From b519b678e8e5857d14616272684fe3154ebf1b73 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Tue, 3 Feb 2015 09:39:02 +0100 Subject: [PATCH] Clean up assets/scripts for Ember CLI --- .../utils/emoji-dictionary.coffee} | 0 assets/scripts/lib/ext/jquery.coffee | 172 - .../spec/integration/build_spec.coffee | 99 - .../spec/integration/builds_spec.coffee | 28 - .../spec/integration/current_spec.coffee | 48 - .../spec/integration/event_spec.coffee | 214 - .../spec/integration/index_spec.coffee | 48 - .../scripts/spec/integration/job_spec.coffee | 81 - .../scripts/spec/integration/log_spec.coffee | 35 - .../spec/integration/my_repos_spec.coffee | 44 - .../spec/integration/routes_spec.coffee | 11 - assets/scripts/spec/integration/sync.coffee | 30 - assets/scripts/spec/spec_helper.coffee | 87 - assets/scripts/spec/support/conditions.coffee | 18 - .../scripts/spec/support/expectations.coffee | 140 - assets/scripts/spec/support/mocks.coffee | 177 - assets/scripts/spec/unit/build_spec.coffee | 26 - assets/scripts/spec/unit/commit_spec.coffee | 39 - assets/scripts/spec/unit/helpers_spec.coffee | 74 - assets/scripts/spec/unit/job_spec.coffee | 82 - .../spec/unit/limited_array_spec.coffee | 48 - .../spec/unit/line_selector_spec.coffee | 108 - .../scripts/spec/unit/log_chunks_spec.coffee | 75 - .../scripts/spec/unit/log_folder_spec.coffee | 54 - assets/scripts/spec/unit/model_spec.coffee | 122 - assets/scripts/spec/unit/tailing_spec.coffee | 89 - assets/scripts/spec/unit/user_spec.coffee | 46 - assets/scripts/spec/vendor/jquery.mockjax.js | 523 - assets/scripts/spec/vendor/qunit.js | 2212 - assets/scripts/spec/vendor/sinon.js | 3555 -- assets/scripts/vendor/ansiparse.js | 186 - assets/scripts/vendor/customerio.js | 14 - assets/scripts/vendor/ember-data.js | 12188 ---- assets/scripts/vendor/ember-data.prod.js | 12073 ---- assets/scripts/vendor/ember.js | 50415 ---------------- assets/scripts/vendor/ember.prod.js | 48510 --------------- assets/scripts/vendor/handlebars.js | 3079 - assets/scripts/vendor/highcharts.js | 239 - assets/scripts/vendor/jquery.min.js | 9597 --- assets/scripts/vendor/jquery.timeago.js | 147 - assets/scripts/vendor/jquery.tipsy.js | 258 - assets/scripts/vendor/md5.min.js | 1 - assets/scripts/vendor/minispade.js | 55 - assets/scripts/vendor/moment.js | 6 - assets/scripts/vendor/pusher.js | 119 - assets/scripts/vendor/setImmediate.js | 218 - assets/scripts/vendor/visibility-0.6.2.min.js | 1 - 47 files changed, 145391 deletions(-) rename assets/scripts/{config/emoij.coffee => app/utils/emoji-dictionary.coffee} (100%) delete mode 100644 assets/scripts/lib/ext/jquery.coffee delete mode 100644 assets/scripts/spec/integration/build_spec.coffee delete mode 100644 assets/scripts/spec/integration/builds_spec.coffee delete mode 100644 assets/scripts/spec/integration/current_spec.coffee delete mode 100644 assets/scripts/spec/integration/event_spec.coffee delete mode 100644 assets/scripts/spec/integration/index_spec.coffee delete mode 100644 assets/scripts/spec/integration/job_spec.coffee delete mode 100644 assets/scripts/spec/integration/log_spec.coffee delete mode 100644 assets/scripts/spec/integration/my_repos_spec.coffee delete mode 100644 assets/scripts/spec/integration/routes_spec.coffee delete mode 100644 assets/scripts/spec/integration/sync.coffee delete mode 100644 assets/scripts/spec/spec_helper.coffee delete mode 100644 assets/scripts/spec/support/conditions.coffee delete mode 100644 assets/scripts/spec/support/expectations.coffee delete mode 100644 assets/scripts/spec/support/mocks.coffee delete mode 100644 assets/scripts/spec/unit/build_spec.coffee delete mode 100644 assets/scripts/spec/unit/commit_spec.coffee delete mode 100644 assets/scripts/spec/unit/helpers_spec.coffee delete mode 100644 assets/scripts/spec/unit/job_spec.coffee delete mode 100644 assets/scripts/spec/unit/limited_array_spec.coffee delete mode 100644 assets/scripts/spec/unit/line_selector_spec.coffee delete mode 100644 assets/scripts/spec/unit/log_chunks_spec.coffee delete mode 100644 assets/scripts/spec/unit/log_folder_spec.coffee delete mode 100644 assets/scripts/spec/unit/model_spec.coffee delete mode 100644 assets/scripts/spec/unit/tailing_spec.coffee delete mode 100644 assets/scripts/spec/unit/user_spec.coffee delete mode 100644 assets/scripts/spec/vendor/jquery.mockjax.js delete mode 100644 assets/scripts/spec/vendor/qunit.js delete mode 100644 assets/scripts/spec/vendor/sinon.js delete mode 100644 assets/scripts/vendor/ansiparse.js delete mode 100644 assets/scripts/vendor/customerio.js delete mode 100644 assets/scripts/vendor/ember-data.js delete mode 100644 assets/scripts/vendor/ember-data.prod.js delete mode 100644 assets/scripts/vendor/ember.js delete mode 100644 assets/scripts/vendor/ember.prod.js delete mode 100644 assets/scripts/vendor/handlebars.js delete mode 100644 assets/scripts/vendor/highcharts.js delete mode 100644 assets/scripts/vendor/jquery.min.js delete mode 100644 assets/scripts/vendor/jquery.timeago.js delete mode 100644 assets/scripts/vendor/jquery.tipsy.js delete mode 100644 assets/scripts/vendor/md5.min.js delete mode 100644 assets/scripts/vendor/minispade.js delete mode 100644 assets/scripts/vendor/moment.js delete mode 100644 assets/scripts/vendor/pusher.js delete mode 100644 assets/scripts/vendor/setImmediate.js delete mode 100644 assets/scripts/vendor/visibility-0.6.2.min.js diff --git a/assets/scripts/config/emoij.coffee b/assets/scripts/app/utils/emoji-dictionary.coffee similarity index 100% rename from assets/scripts/config/emoij.coffee rename to assets/scripts/app/utils/emoji-dictionary.coffee diff --git a/assets/scripts/lib/ext/jquery.coffee b/assets/scripts/lib/ext/jquery.coffee deleted file mode 100644 index 37930a9e..00000000 --- a/assets/scripts/lib/ext/jquery.coffee +++ /dev/null @@ -1,172 +0,0 @@ -$.fn.extend - outerHtml: -> - $(this).wrap('
').parent().html() - - outerElement: -> - $($(this).outerHtml()).empty() - - flash: -> - Utils.flash this - - unflash: -> - Utils.unflash this - - filterLog: -> - @deansi() - @foldLog() - - deansi: -> - @html Utils.deansi(@html()) - - foldLog: -> - @html Utils.foldLog(@html()) - - unfoldLog: -> - @html Utils.unfoldLog(@html()) - - updateTimes: -> - Utils.updateTimes this - - activateTab: (tab) -> - Utils.activateTab this, tab - - timeInWords: -> - $(this).each -> - $(this).text Utils.timeInWords(parseInt($(this).attr('title'))) - - updateGithubStats: (repo) -> - Utils.updateGithubStats repo, $(this) - -$.extend - isEmpty: (obj) -> - if $.isArray(obj) - !obj.length - else if $.isObject(obj) - !$.keys(obj).length - else - !obj - - isObject: (obj) -> - # does this work as expected? - Object.prototype.toString.call(obj) == '[object Object]' - - keys: (obj) -> - keys = [] - $.each obj, (key) -> keys.push key - keys - - values: (obj) -> - values = [] - $.each obj, (key, value) -> values.push value - values - - underscore: (string) -> - string[0].toLowerCase() + string.substring(1).replace /([A-Z])?/g, (match, chr) -> - if chr then "_#{chr.toUpperCase()}" else '' - - titleize: (string) -> - $.capitalize(string).replace /_(.)?/g, (match, chr) -> - if chr then ' ' + chr.toUpperCase() else '' - - camelize: (string, uppercase) -> - string = if uppercase == false then $.underscore(string) else $.capitalize(string) - string.replace /_(.)?/g, (match, chr) -> - if chr then chr.toUpperCase() else '' - - capitalize: (string) -> - string[0].toUpperCase() + string.substring(1) - - compact: (object) -> - $.grep(object, (value) -> !!value) - - all: (array, callback) -> - args = Array::slice.apply(arguments) - callback = args.pop() - array = args.pop() or this - i = 0 - - while i < array.length - return false if callback(array[i]) - i++ - true - - detect: (array, callback) -> - args = Array::slice.apply(arguments) - callback = args.pop() - array = args.pop() or this - i = 0 - - while i < array.length - return array[i] if callback(array[i]) - i++ - - select: (array, callback) -> - args = Array::slice.apply(arguments) - callback = args.pop() - array = args.pop() or this - result = [] - i = 0 - - while i < array.length - result.push array[i] if callback(array[i]) - i++ - result - - slice: (object, key) -> - keys = Array::slice.apply(arguments) - object = (if (typeof keys[0] is 'object') then keys.shift() else this) - result = {} - for key of object - result[key] = object[key] if keys.indexOf(key) > -1 - result - - only: (object) -> - keys = Array::slice.apply(arguments) - object = (if (typeof keys[0] is 'object') then keys.shift() else this) - result = {} - for key of object - result[key] = object[key] unless keys.indexOf(key) is -1 - result - - except: (object) -> - keys = Array::slice.apply(arguments) - object = (if (typeof keys[0] is 'object') then keys.shift() else this) - result = {} - for key of object - result[key] = object[key] if keys.indexOf(key) is -1 - result - - intersect: (array, other) -> - array.filter (element) -> - other.indexOf(element) != -1 - - map: (elems, callback, arg) -> - value = undefined - key = undefined - ret = [] - i = 0 - length = elems.length - isArray = elems instanceof jQuery || length != undefined && typeof length == 'number' && (length > 0 && elems[0] && elems[length - 1]) || length == 0 || jQuery.isArray(elems) - if isArray - while i < length - value = callback(elems[i], i, arg) - ret[ret.length] = value if value? - i++ - else - for key of elems - value = callback(elems[key], key, arg) - ret[ret.length] = value if value? - ret.concat.apply [], ret - - shuffle: (array) -> - array = array.slice() - top = array.length - while top && --top - current = Math.floor(Math.random() * (top + 1)) - tmp = array[current] - array[current] = array[top] - array[top] = tmp - array - - truncate: (string, length) -> - if string.length > length then string.trim().substring(0, length) + '...' else string diff --git a/assets/scripts/spec/integration/build_spec.coffee b/assets/scripts/spec/integration/build_spec.coffee deleted file mode 100644 index 8e9b4f88..00000000 --- a/assets/scripts/spec/integration/build_spec.coffee +++ /dev/null @@ -1,99 +0,0 @@ -module "Build page", - setup: -> - Ember.run -> Travis.advanceReadiness() - teardown: -> - Ember.run -> Travis.reset() - -test "displaying information on build page", -> - visit('/travis-ci/travis-core/builds') - visit('/travis-ci/travis-core/builds/1') - andThen(-> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - { slug: 'travis-ci/travis-assets', build: { number: 3, url: '/travis-ci/travis-assets/builds/3', duration: '30 sec', finishedAt: 'a day ago' } } - ] - - displaysRepository - href: '/travis-ci/travis-core' - - displaysSummary - type: 'build' - id: 1 - repo: 'travis-ci/travis-core' - commit: '1234567' - branch: 'master' - compare: '0123456..1234567' - finishedAt: '3 minutes ago' - duration: '30 sec' - message: 'commit message 1' - - displaysSummaryGravatars - authorEmail: 'author@email.com' - committerEmail: 'committer@email.com' - - - displaysTabs - current: { href: '/travis-ci/travis-core' } - builds: { href: '/travis-ci/travis-core/builds' } - build: { href: '/travis-ci/travis-core/builds/1', active: true } - job: { hidden: true } - - listsJobs - table: '#jobs' - headers: ['Job', 'Duration', 'Finished', 'Ruby'] - jobs: [ - { color: 'green', id: 1, number: '1.1', repo: 'travis-ci/travis-core', finishedAt: '3 minutes ago', duration: '30 sec', rvm: 'rbx' } - { color: 'red', id: 2, number: '1.2', repo: 'travis-ci/travis-core', finishedAt: '2 minutes ago', duration: '40 sec', rvm: '1.9.3' } - ] - - listsJobs - table: '#allowed_failure_jobs' - headers: ['Job', 'Duration', 'Finished', 'Ruby'] - jobs: [ - { color: '', id: 3, number: '1.3', repo: 'travis-ci/travis-core', finishedAt: '-', duration: '-', rvm: 'jruby' } - ] - ) - - -test "updating current build", -> - visit('/travis-ci/travis-core').then -> - payload = - build: - id: 11 - repository_id: 1 - commit_id: 1 - number: '3' - duration: 55 - started_at: '2012-07-02T00:02:00Z' - finished_at: '2012-07-02T00:02:55Z' - event_type: 'push' - result: 1 - message: 'commit message 3' - commit: 'foo1234' - branch: 'master' - state: 'started' - config: {} - pull_request: false - compare_url: 'https://github.com/compare/0123456..1234567' - repository: - id: 1 - last_build_number: '3' - last_build_id: 11 - - Em.run -> - Travis.receive 'build:started', payload - - wait().then -> - displaysSummaryBuildLink '/travis-ci/travis-core/builds/11', '3' - - displaysSummary - type: 'build' - id: 11 - repo: 'travis-ci/travis-core' - commit: 'foo1234' - branch: 'master' - compare: '0123456..1234567' - finishedAt: 'less than a minute ago' - duration: '55 sec' - message: 'commit message 3' diff --git a/assets/scripts/spec/integration/builds_spec.coffee b/assets/scripts/spec/integration/builds_spec.coffee deleted file mode 100644 index 9968f3dc..00000000 --- a/assets/scripts/spec/integration/builds_spec.coffee +++ /dev/null @@ -1,28 +0,0 @@ -module "Builds page", - setup: -> - Ember.run -> Travis.advanceReadiness() - teardown: -> - Ember.run -> Travis.reset() - -test "displaying information on builds page", -> - visit('/travis-ci/travis-core/builds').then -> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - { slug: 'travis-ci/travis-assets', build: { number: 3, url: '/travis-ci/travis-assets/builds/3', duration: '30 sec', finishedAt: 'a day ago' } } - ] - - displaysRepository - href: '/travis-ci/travis-core' - - displaysTabs - current: { href: '/travis-ci/travis-core' } - builds: { href: '/travis-ci/travis-core/builds', active: true } - build: { hidden: true } - job: { hidden: true } - - - listsBuilds [ - { id: 2, slug: 'travis-ci/travis-core', number: '2', sha: '2345678', branch: 'feature', message: 'commit message 2', duration: '-', finishedAt: '-', color: '' } - { id: 1, slug: 'travis-ci/travis-core', number: '1', sha: '1234567', branch: 'master', message: 'commit message 1', duration: '30 sec', finishedAt: '3 minutes ago', color: 'green' } - ] diff --git a/assets/scripts/spec/integration/current_spec.coffee b/assets/scripts/spec/integration/current_spec.coffee deleted file mode 100644 index e602df76..00000000 --- a/assets/scripts/spec/integration/current_spec.coffee +++ /dev/null @@ -1,48 +0,0 @@ -module "Repo page", - setup: -> - Ember.run -> Travis.advanceReadiness() - teardown: -> - Ember.run -> Travis.reset() - -test "displaying information on repo page", -> - visit('/travis-ci/travis-core').then -> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - { slug: 'travis-ci/travis-assets', build: { number: 3, url: '/travis-ci/travis-assets/builds/3', duration: '30 sec', finishedAt: 'a day ago' } } - ] - - displaysRepository - href: '/travis-ci/travis-core' - - displaysSummary - type: 'build' - id: 1 - repo: 'travis-ci/travis-core' - commit: '1234567' - branch: 'master' - compare: '0123456..1234567' - finishedAt: '3 minutes ago' - duration: '30 sec' - message: 'commit message 1' - - displaysTabs - current: { href: '/travis-ci/travis-core', active: true } - builds: { href: '/travis-ci/travis-core/builds' } - build: { hidden: true } - job: { hidden: true } - - listsJobs - table: '#jobs' - headers: ['Job', 'Duration', 'Finished', 'Ruby'] - jobs: [ - { id: 1, color: 'green', number: '1.1', repo: 'travis-ci/travis-core', finishedAt: '3 minutes ago', duration: '30 sec', rvm: 'rbx' } - { id: 2, color: 'red', number: '1.2', repo: 'travis-ci/travis-core', finishedAt: '2 minutes ago', duration: '40 sec', rvm: '1.9.3' } - ] - - listsJobs - table: '#allowed_failure_jobs' - headers: ['Job', 'Duration', 'Finished', 'Ruby'] - jobs: [ - { id: 3, color: '', number: '1.3', repo: 'travis-ci/travis-core', finishedAt: '-', duration: '-', rvm: 'jruby' } - ] diff --git a/assets/scripts/spec/integration/event_spec.coffee b/assets/scripts/spec/integration/event_spec.coffee deleted file mode 100644 index 3cd2f835..00000000 --- a/assets/scripts/spec/integration/event_spec.coffee +++ /dev/null @@ -1,214 +0,0 @@ -module "Events", - setup: -> - Ember.run -> Travis.advanceReadiness() - teardown: -> - Ember.run -> Travis.reset() - -test "event containing a repository, adds repository to repos list", -> - visit('/travis-ci/travis-core').then -> - payload = - repository: - id: 10 - build: - id: 10 - repository_id: 10 - - $.mockjax - url: '/builds/10' - responseTime: 0 - responseText: payload - - Em.run -> - Travis.receive 'build:started', - build: - id: 10 - repository: - id: 10 - slug: 'travis-ci/travis-support' - last_build_id: 10 - last_build_number: 10 - last_build_started_at: '2012-07-02T00:01:00Z' - last_build_finished_at: '2012-07-02T00:02:30Z' - last_build_state: 'passed' - last_build_duration: 90 - - wait().then -> - listsRepo - row: 2 - item: { slug: 'travis-ci/travis-support', build: { number: 4, url: '/travis-ci/travis-support/builds/10', duration: '1 min 30 sec', finishedAt: 'less than a minute ago' } } - - -test "an event containing a created job, clears the job's log", -> - payload = - job: - id: 12 - repository_id: 1 - number: '1.4' - queue: 'build.linux' - - visit('/travis-ci/travis-core/').then -> - Em.run -> - logRendered() - Travis.receive 'build:created', payload - - wait().then -> - displaysLog [] - -test "an event containing a requeued job, clears the job's log", -> - payload = - job: - id: 12 - repository_id: 1 - number: '1.4' - queue: 'build.linux' - - visit('/travis-ci/travis-core').then -> - Em.run -> - logRendered() - Travis.receive 'build:requeued', payload - - wait().then -> - displaysLog [] - - -test "an event with a build adds a build to a builds list", -> - visit('/travis-ci/travis-core/builds').then -> - payload = - build: - id: 11 - repository_id: 1 - commit_id: 1 - number: '3' - duration: 55 - started_at: '2012-07-02T00:02:00Z' - finished_at: '2012-07-02T00:02:55Z' - event_type: 'push' - message: 'commit message 3' - commit: '1234567' - state: 'failed' - pull_request: false - pull_request_number: null - pull_request_title: null - - Em.run -> - Travis.receive 'build:started', payload - - wait().then -> - listsBuild - row: 1 - item: { id: 11, slug: 'travis-ci/travis-core', number: '3', sha: '1234567', branch: 'master', message: 'commit message 3', finishedAt: 'less than a minute ago', duration: '55 sec', color: 'red' } - - -#test "event containing a job, adds job to jobs list", -> -# visit('travis-ci/travis-core').then -> -# payload = -# job: -# id: 12 -# repository_id: 1 -# number: '1.4' -# queue: 'builds.linux' -# -# $.mockjax -# url: '/jobs/12' -# responseTime: 0 -# responseText: payload -# -# Em.run -> -# Travis.receive 'job:started', -# job: -# id: 12 -# repository_id: 1 -# repository_slug: 'travis-ci/travis-core' -# number: '1.4' -# queue: 'builds.linux' -# state: 'created' -# -# wait().then -> -# listsQueuedJob -# name: 'linux' -# row: 3 -# item: { number: '1.4', repo: 'travis-ci/travis-core' } -# -# it 'updates only keys that are available', -> -# Em.run -> -# Travis.receive 'job:started', -# job: -# id: 1 -# build_id: 1 -# -# waits(100) -# runs -> -# listsJob -# table: $('#jobs') -# row: 1 -# item: { id: 1, number: '1.1', repo: 'travis-ci/travis-core', finishedAt: '3 minutes ago', duration: '30 sec', rvm: 'rbx' } -# -# #describe 'an event adding a worker', -> -# # beforeEach -> -# # app '' -# # waitFor sidebarTabsRendered -# # runs -> -# # $('#right #tab_workers a').trigger('click') -# # waitFor workersRendered -# -# # it 'adds a worker to the workers list', -> -# # payload = -# # worker: -# # id: 10 -# # host: 'worker.travis-ci.org' -# # name: 'ruby-3' -# # state: 'ready' -# -# # $.mockjax -# # url: '/workers/10' -# # responseTime: 0 -# # responseText: payload -# -# # Em.run -> -# # Travis.receive 'worker:created', -# # worker: -# # id: 10 -# # name: 'ruby-3' -# # host: 'worker.travis-ci.org' -# # state: 'ready' -# -# # waits(100) -# # runs -> -# # listsWorker -# # group: 'worker.travis-ci.org' -# # row: 3 -# # item: { name: 'ruby-3', state: 'ready' } -# -# -# #describe 'an event updating a worker', -> -# # beforeEach -> -# # app '/travis-ci/travis-core' -# # waitFor sidebarTabsRendered -# # runs -> -# # $('#right #tab_workers a').trigger('click') -# # waitFor workersRendered -# -# # it 'does not update repository if it\'s already in the store', -> -# # payload = -# # worker: -# # id: 1 -# # host: 'worker.travis-ci.org' -# # name: 'ruby-2' -# # state: 'working' -# # payload: -# # repository: -# # id: 1 -# # last_build_id: 999 -# # last_build_number: '999' -# -# # Em.run -> -# # Travis.receive 'worker:updated', payload -# -# # waits(100) -# # runs -> -# # listsRepo -# # row: 2 -# # item: { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } -# -# -# diff --git a/assets/scripts/spec/integration/index_spec.coffee b/assets/scripts/spec/integration/index_spec.coffee deleted file mode 100644 index 8eb426f9..00000000 --- a/assets/scripts/spec/integration/index_spec.coffee +++ /dev/null @@ -1,48 +0,0 @@ -module "Index page", - setup: -> - Ember.run -> Travis.advanceReadiness() - teardown: -> - Ember.run -> Travis.reset() - -test "displaying information on index page", -> - visit('/travis-ci/travis-core').then -> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - { slug: 'travis-ci/travis-assets', build: { number: 3, url: '/travis-ci/travis-assets/builds/3', duration: '30 sec', finishedAt: 'a day ago' } } - ] - - displaysRepository - href: '/travis-ci/travis-core' - - displaysSummary - type: 'build' - id: 1 - repo: 'travis-ci/travis-core' - commit: '1234567' - branch: 'master' - compare: '0123456..1234567' - finishedAt: '3 minutes ago' - duration: '30 sec' - message: 'commit message 1' - - displaysTabs - current: { href: '/travis-ci/travis-core', active: true } - builds: { href: '/travis-ci/travis-core/builds' } - build: { hidden: true } - job: { hidden: true } - - listsJobs - table: '#jobs' - headers: ['Job', 'Duration', 'Finished', 'Ruby'] - jobs: [ - { color: 'green', id: 1, number: '1.1', repo: 'travis-ci/travis-core', finishedAt: '3 minutes ago', duration: '30 sec', rvm: 'rbx' } - { color: 'red', id: 2, number: '1.2', repo: 'travis-ci/travis-core', finishedAt: '2 minutes ago', duration: '40 sec', rvm: '1.9.3' } - ] - - listsJobs - table: '#allowed_failure_jobs' - headers: ['Job', 'Duration', 'Finished', 'Ruby'] - jobs: [ - { color: '', id: 3, number: '1.3', repo: 'travis-ci/travis-core', finishedAt: '-', duration: '-', rvm: 'jruby' } - ] diff --git a/assets/scripts/spec/integration/job_spec.coffee b/assets/scripts/spec/integration/job_spec.coffee deleted file mode 100644 index ccd07b2f..00000000 --- a/assets/scripts/spec/integration/job_spec.coffee +++ /dev/null @@ -1,81 +0,0 @@ -module "Job page", - setup: -> - Ember.run -> Travis.advanceReadiness() - teardown: -> - Ember.run -> Travis.reset() - - -test 'displaying information on job page', -> - $.mockjax - url: '/jobs/1/log?cors_hax=true' - responseTime: 0 - responseText: "First line\ncontent:travis_fold:start:install\r$ Install something\nInstalling something\ncontent:travis_fold:end:install\r$ End" - - visit('/travis-ci/travis-core/jobs/1').then -> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - { slug: 'travis-ci/travis-assets', build: { number: 3, url: '/travis-ci/travis-assets/builds/3', duration: '30 sec', finishedAt: 'a day ago' } } - ] - - displaysRepository - href: '/travis-ci/travis-core' - - displaysSummary - id: 1 - type: 'job' - repo: 'travis-ci/travis-core' - commit: '1234567' - branch: 'master' - compare: '0123456..1234567' - finishedAt: '3 minutes ago' - duration: '30 sec' - message: 'commit message 1' - - displaysTabs - current: { href: '/travis-ci/travis-core' } - builds: { href: '/travis-ci/travis-core/builds' } - build: { href: '/travis-ci/travis-core/builds/1' } - job: { href: '/travis-ci/travis-core/jobs/1', active: true } - - displaysLog [ - 'First line', - '$ Install something', - 'Installing something', - '$ End' - ] - -# it 'allows to expand folds', -> -# waits 100 -# runs -> -# expect($('#fold-start-install').hasClass('open')).toBeFalsy() -# $('#fold-start-install').click() -# waits 20 -# runs -> -# expect($('#fold-start-install').hasClass('open')).toBeTruthy() -# -# -#describe 'too long log', -> -# beforeEach -> -# $.mockjax -# url: '/jobs/2/log?cors_hax=true' -# responseTime: 0 -# responseText: '1\n2\n3\n4\n5\n6\n7\n8\n9\n10' -# -# Log.LIMIT = 5 -# -# app 'travis-ci/travis-core/jobs/2' -# waitFor logRendered -# -# afterEach -> -# Log.LIMIT = 10000 -# -# it 'is cut after given limit', -> -# displaysLog [ -# '12345' -# ] -# -# expect( $('#log-container .warning').text() ).toMatch /This log is too long to be displayed/ -# expect( $('#log-container .warning a').attr('href') ).toEqual '/jobs/2/log.txt?deansi=true' -# -# diff --git a/assets/scripts/spec/integration/log_spec.coffee b/assets/scripts/spec/integration/log_spec.coffee deleted file mode 100644 index 45e52032..00000000 --- a/assets/scripts/spec/integration/log_spec.coffee +++ /dev/null @@ -1,35 +0,0 @@ -module "Logs", - setup: -> - Ember.run -> Travis.advanceReadiness() - @sandbox = sinon.sandbox.create(); - $.mockjax - url: '/jobs/1/log?cors_hax=true' - responseTime: 0 - responseText: "First line\ncontent:travis_fold:start:install\r$ Install something\nInstalling something\ncontent:travis_fold:end:install\r$ End" - - teardown: -> - Ember.run -> Travis.reset() - @sandbox.restore(); - -test 'displaying the logs initializes the line selector', -> - selector_stub = - willDestroy: @sandbox.spy() - lineSelector = @sandbox.stub(Travis, "LinesSelector").returns(selector_stub) - visit('/travis-ci/travis-core/jobs/1').then -> - ok lineSelector.calledWithNew(), 'the lines selector has been initialized' - -test 'displaying the log initializes the logger', -> - log = @sandbox.stub(Log, "create").returns - set: @sandbox.spy() - scroll_stub = - tryScroll: @sandbox.spy() - scroll = @sandbox.stub(Log, "Scroll").returns(scroll_stub) - - visit('/travis-ci/travis-core/jobs/1').then -> - ok log.calledWith({limit: Log.LIMIT, listeners: [scroll_stub]}), 'the logger has been initialized' - -test 'displaying the logs initializes the log folder', -> - folder_stub = {} - logFolder = @sandbox.stub(Travis, "LogFolder").returns(folder_stub) - visit('/travis-ci/travis-core/jobs/1').then -> - ok logFolder.calledWithNew(), 'the logs folder has been initialized' diff --git a/assets/scripts/spec/integration/my_repos_spec.coffee b/assets/scripts/spec/integration/my_repos_spec.coffee deleted file mode 100644 index b43c4a50..00000000 --- a/assets/scripts/spec/integration/my_repos_spec.coffee +++ /dev/null @@ -1,44 +0,0 @@ -module "My repos", - setup: -> - Ember.run -> Travis.advanceReadiness() - teardown: -> - Ember.run -> Travis.reset() - -test "my repos is active by default when user is signed in", -> - Ember.run -> signInUser() - visit('/').then -> - wait().then -> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - ] - - displaysRepository - href: '/travis-ci/travis-hub' - - displaysSummary - type: 'build' - id: 4 - repo: 'travis-ci/travis-hub' - commit: '4567890' - branch: 'master' - compare: '0123456..4567890' - finishedAt: '-' - duration: '-' - message: 'commit message 4' - -test "my repos is activated when user signs in", -> - visit('/').then -> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - { slug: 'travis-ci/travis-assets', build: { number: 3, url: '/travis-ci/travis-assets/builds/3', duration: '30 sec', finishedAt: 'a day ago' } } - ] - - Ember.run -> signInUser() - - wait().then -> - listsRepos [ - { slug: 'travis-ci/travis-hub', build: { number: 4, url: '/travis-ci/travis-hub/builds/4', duration: '1 min', finishedAt: '-' } } - { slug: 'travis-ci/travis-core', build: { number: 1, url: '/travis-ci/travis-core/builds/1', duration: '30 sec', finishedAt: '3 minutes ago' } } - ] diff --git a/assets/scripts/spec/integration/routes_spec.coffee b/assets/scripts/spec/integration/routes_spec.coffee deleted file mode 100644 index 1992cfab..00000000 --- a/assets/scripts/spec/integration/routes_spec.coffee +++ /dev/null @@ -1,11 +0,0 @@ -module "Router", - teardown: -> - Ember.run -> Travis.reset() - -test 'renders notFound template when URL can\t be found', -> - visit('/somehing/something/something/.../dark/side/..../something/something/something/.../complete').then -> - equal($('#main').text().trim(), 'The requested page was not found.') - -test 'renders repo not found information when repo can\'t be found', -> - visit('/what-is-this/i-dont-even').then -> - equal($('#main').text().trim(), 'The repository at what-is-this/i-dont-even was not found.') diff --git a/assets/scripts/spec/integration/sync.coffee b/assets/scripts/spec/integration/sync.coffee deleted file mode 100644 index a28b95b1..00000000 --- a/assets/scripts/spec/integration/sync.coffee +++ /dev/null @@ -1,30 +0,0 @@ -#module "Sync", -# setup: -> -# Ember.run -> Travis.advanceReadiness() -# teardown: -> -# Ember.run -> Travis.reset() -# -#test "first sync page is show when user just signed up and is syncing", -> -# Ember.run -> -# signInUser -# is_syncing: true -# synced_at: null -# -# $.mockjax -# url: '/hooks' -# responseTime: 10 -# responseText: -# hooks: [] -# -# Travis.config.syncingPageRedirectionTime = 100 -# -# wait().then -> -# ok $('#first_sync').text().match(/Just a few more seconds as we talk to GitHub to find out which repositories belong to you./) -# -# stop() -# Travis.__container__.lookup('controller:currentUser').get('content').set('isSyncing', false) -# setTimeout -> -# start() -# visit('/').then -> -# ok $('#getting-started').text().match(/Welcome to Travis CI!/) -# , 120 diff --git a/assets/scripts/spec/spec_helper.coffee b/assets/scripts/spec/spec_helper.coffee deleted file mode 100644 index 320eeee2..00000000 --- a/assets/scripts/spec/spec_helper.coffee +++ /dev/null @@ -1,87 +0,0 @@ -document.write('
') - -Travis.rootElement = '#ember-testing' -Travis.setupForTesting() -Travis.injectTestHelpers() - -oldSetup = Travis.setup -Travis.ready = -> - oldSetup.apply(this, arguments) - # TODO: in the future I would like to create a TestAuth class which - # would have similar interface to Travis.Auth, but with the - # auth logic stubbed out. It will give use ability to do things - # like testAuth.shouldSucceedOnSignIn() - Travis.lookup('auth:main').signOut() - -window.exists = (selector) -> - return !!find(selector).length - -Ember.Container.prototype.stub = (fullName, instance) -> - instance.destroy = instance.destroy || (->) - this.cache.dict[fullName] = instance - -window.signInUser = (data) -> - data ||= {} - userData = { - id: 1 - email: 'tyrion@example.org' - login: 'tyrion' - token: 'abcdef' - created_at: "2011-05-10T15:43:59Z" - gravatar_id: "582034b63279abeaa8e76acf12f5ee30" - is_syncing: false - name: "Tyrion" - synced_at: "2013-12-09T09:41:47Z" - } - userData = Ember.merge(userData, data) - $.mockjax - url: '/users/1' - responseTime: 10 - responseText: - user: userData - $.mockjax - url: '/users' - responseTime: 10 - responseText: - user: userData - $.mockjax - url: '/users/permissions' - responseTime: 10 - responseText: - permissions: [] - admin: [] - push: [] - pull: [] - $.mockjax - url: '/broadcasts' - responseTime: 10 - responseText: - broadcasts: [] - $.mockjax - url: '/accounts' - responseTime: 10 - responseText: - accounts: [] - - # for now let's just use harcoded data to log in the user, - # we may extend it in the future to pass specific user data - Travis.lookup('auth:main').signIn - user: userData - token: 'abcdef' - - #@app = (url, options = {}) -> - # # TODO: this should wait till app is initialized, not some - # # arbitrary amount of time - # waits(50) - # runs -> - # Travis.reset() - # Travis.auth.signOut() - # - # if options.user - # signInUser() - # url = "/#{url}" unless url.match /^\// - # visit(url) - -now = -> new Date('2012-07-02T00:03:00Z') -$.timeago.settings.nowFunction = -> now().getTime() -Travis.currentDate = now diff --git a/assets/scripts/spec/support/conditions.coffee b/assets/scripts/spec/support/conditions.coffee deleted file mode 100644 index 66188ae2..00000000 --- a/assets/scripts/spec/support/conditions.coffee +++ /dev/null @@ -1,18 +0,0 @@ -@notEmpty = (selector) -> - -> $(selector).text().trim() != '' - -@hasText = (selector, text) -> - -> $(selector).text().trim() == text - -@reposRendered = notEmpty('#repos li.selected') -@myReposRendered = -> notEmpty('#repos li.selected')() && $('#left #tab_owned').hasClass('active') -@buildRendered = notEmpty('#summary .number') -@buildsRendered = notEmpty('#builds .number') -@jobRendered = notEmpty('#summary .number') -@jobsRendered = notEmpty('#jobs .number') -@queuesRendered = notEmpty('#queue_linux li') -@workersRendered = notEmpty('.worker') -@logRendered = notEmpty('#log p') -@appRendered = -> $('.ember-view.application').length - -@sidebarTabsRendered = notEmpty('#right #tab_workers a') diff --git a/assets/scripts/spec/support/expectations.coffee b/assets/scripts/spec/support/expectations.coffee deleted file mode 100644 index e6a5335c..00000000 --- a/assets/scripts/spec/support/expectations.coffee +++ /dev/null @@ -1,140 +0,0 @@ -@displaysRepository = (repo) -> - equal($('#repo h3 a').attr('href'), repo.href, 'repository title should link to repo page') - equal($('#repo .github-icon a').attr('href'), "https://github.com#{repo.href}", 'github icon should link to repo on github') - -@displaysTabs = (tabs) -> - for name, tab of tabs - equal($("#tab_#{name} a").attr('href'), tab.href, "#{name} tab should link to #{tab.href}") unless tab.hidden - equal($("#tab_#{name}").hasClass('active'), !!tab.active, "#{name} tab should #{'not' unless tab.active} be active") - equal($("#tab_#{name}").hasClass('display-inline'), !tab.hidden, "#{name} tab should have class display-inline") if name in ['build', 'job'] - -@displaysSummaryBuildLink = (link, number) -> - element = $('#new-summary .build-status a') - equal( element.attr('href') , link) - equal( element.text().trim() , "##{number} started") - -@displaysSummary = (data) -> - element = $('#new-summary .build-status a') - equal(element.attr('href'), "/#{data.repo}/#{data.type}s/#{data.id}") - - element = $('#new-summary .finished') - equal(element.text().trim(), data.finishedAt) - - element = $('#new-summary .runtime') - duration_regexp = new RegExp("(ran|running) for #{data.duration}") - ok(duration_regexp.test(element.text().trim())) - - element = $('#new-summary .commit-changes a.commit') - equal(element.attr('href'), "https://github.com/#{data.repo}/commit/#{data.commit}") - - element = $('#new-summary .commit-changes a.commit') - equal(element.text(), "Commit #{data.commit}") - - element = $('#new-summary .branch') - equal(element.text().trim(), data.branch) - - element = $('#new-summary .commit-changes a.compare') - equal(element.attr('href'), "https://github.com/compare/#{data.compare}") - - element = $('#new-summary .commit-changes a.compare') - equal(element.text(), "Compare #{data.compare}") - - element = $('#new-summary .subject') - equal(element.text().trim(), "- #{data.message}") - -@displaysSummaryGravatars = (data) -> - element = $('#new-summary .author .committed img') - equal(element.attr('src'), Travis.Urls.gravatarImage(data.committerEmail, 40)) - - element = $('#new-summary .author .authored img') - equal(element.attr('src'), Travis.Urls.gravatarImage(data.authorEmail, 40)) - -@displaysLog = (lines) -> - log = lines.join('') - equal($('#log p').text().trim(), log) - -@listsRepos = (items) -> - listsItems('repo', items) - -@listsRepo = (data) -> - row = $('#repos li')[data.row - 1] - repo = data.item - - equal($('a.slug', row).attr('href'), "/#{repo.slug}") - equal($('a.last_build', row).attr('href'), repo.build.url) - equal($('.duration', row).text().trim(), repo.build.duration) - equal($('.finished_at', row).text().trim(), repo.build.finishedAt) - -@listsBuilds = (builds) -> - listsItems('build', builds) - -@listsBuild = (data) -> - row = $('#builds tbody tr')[data.row - 1] - build = data.item - - equal($('.number a', row).attr('href'), "/#{build.slug}/builds/#{build.id}") - equal($('.number a', row).text().trim(), build.number) - equal($('.message', row).text().trim(), build.message) - equal($('.duration', row).text().trim(), build.duration) - equal($('.finished_at', row).text().trim(), build.finishedAt) - ok($(row).attr('class').match(build.color)) - -@listsJobs = (data) -> - table = $(data.table) - headers = ($(element).text() for element in $("thead th", table)) - deepEqual(headers, data.headers) - - $.each data.jobs, (row, job) -> listsJob(table: data.table, row: row + 1, item: job) - -@listsJob = (data) -> - row = $('tbody tr', data.table)[data.row - 1] - job = data.item - - element = $(row) - ok(element.attr('class').match(job.color)) - - element = $("td.number", row) - equal(element.text().trim(), job.number) - - element = $("td.number a", row) - equal(element.attr('href'), "/#{job.repo}/jobs/#{job.id}") - - element = $("td.duration", row) - equal(element.text().trim(), job.duration) - - element = $("td.finished_at", row) - equal(element.text().trim(), job.finishedAt) - - element = $("td:nth-child(4)", row) - equal(element.text().trim(), job.rvm) - -@listsQueuedJobs = (jobs) -> - listsItems('queuedJob', jobs) - -@listsQueuedJob = (data) -> - job = data.item - text = $($("#queue_#{data.name} li")[data.row - 1]).text() - ok(text.match(job.repo), "#{text} should contain #{job.repo}") - ok(text.match(job.repo), "#{text} should contain #{job.number}") - -@listsQueue = (data) -> - name = data.item.name - job = data.item.item - text = $($("#queue_#{name} li")[data.row - 1]).text() - ok(text.match(job.repo), "#{text} should contain #{job.repo}") - ok(text.match(job.repo), "#{text} should contain #{job.number}") - -@listsItems = (type, items) -> - $.each items, (row, item) => - window["lists#{$.camelize(type)}"](item: item, row: row + 1) - -@listsQueues = (queues) -> - listsItems('queue', queues) - -@listsWorker = (data) -> - group = $("#workers li:contains('#{data.group}')") - element = $($('ul li', group)[data.row - 1]) - worker = data.item - - ok(element.text().match(worker.name)) - ok(element.text().match(worker.state)) diff --git a/assets/scripts/spec/support/mocks.coffee b/assets/scripts/spec/support/mocks.coffee deleted file mode 100644 index d4e7b377..00000000 --- a/assets/scripts/spec/support/mocks.coffee +++ /dev/null @@ -1,177 +0,0 @@ -minispade.require 'ext/jquery' - -responseTime = 10 - -repos = [ - { id: '1', owner: 'travis-ci', name: 'travis-core', slug: 'travis-ci/travis-core', build_ids: [1, 2], last_build_id: 1, last_build_number: 1, last_build_state: 'passed', last_build_duration: 30, last_build_started_at: '2012-07-02T00:00:00Z', last_build_finished_at: '2012-07-02T00:00:30Z', description: 'Description of travis-core', github_language: 'ruby' }, - { id: '2', owner: 'travis-ci', name: 'travis-assets', slug: 'travis-ci/travis-assets', build_ids: [3], last_build_id: 3, last_build_number: 3, last_build_state: 'failed', last_build_duration: 30, last_build_started_at: '2012-07-02T00:01:00Z', last_build_finished_at: '2012-07-01T00:01:30Z', description: 'Description of travis-assets', github_language: 'ruby'}, - { id: '3', owner: 'travis-ci', name: 'travis-hub', slug: 'travis-ci/travis-hub', build_ids: [4], last_build_id: 4, last_build_number: 4, last_build_state: null, last_build_duration: null, last_build_started_at: '2012-07-02T00:02:00Z', last_build_finished_at: null, description: 'Description of travis-hub', github_language: 'ruby' }, -] - -reposByName = (name) -> - # this is hardcoded as well as user is hardcoded in app() helper, - # please make it more flexible if needed - if name == 'tyrion' - [repos[0], repos[2]] - else - [] - -builds = [ - { id: '1', repository_id: '1', commit_id: 1, job_ids: [1, 2, 3], number: 1, pull_request: false, config: { rvm: ['rbx', '1.9.3', 'jruby'] }, duration: 30, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:30Z', state: 'passed' }, - { id: '2', repository_id: '1', commit_id: 2, job_ids: [4], number: 2, pull_request: false, config: { rvm: ['rbx'] }, duration: null, state: 'created', finished_at: null }, - { id: '3', repository_id: '2', commit_id: 3, job_ids: [5], number: 3, pull_request: false, config: { rvm: ['rbx'] }, duration: 30, started_at: '2012-07-02T00:01:00Z', finished_at: '2012-07-01T00:01:30Z', state: 'failed' }, - { id: '4', repository_id: '3', commit_id: 4, job_ids: [6], number: 4, pull_request: false, config: { rvm: ['rbx'] }, duration: null, started_at: '2012-07-02T00:02:00Z', state: 'queued', finished_at: null }, -] - -commits = [ - { id: '1', sha: '1234567', branch: 'master', message: 'commit message 1', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'https://github.com/compare/0123456..1234567' }, - { id: '2', sha: '2345678', branch: 'feature', message: 'commit message 2', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'https://github.com/compare/0123456..2345678' }, - { id: '3', sha: '3456789', branch: 'master', message: 'commit message 3', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'https://github.com/compare/0123456..3456789' }, - { id: '4', sha: '4567890', branch: 'master', message: 'commit message 4', author_name: 'author name', author_email: 'author@email.com', committer_name: 'committer name', committer_email: 'committer@email.com', compare_url: 'https://github.com/compare/0123456..4567890' }, -] - -jobs = [ - { id: '1', repository_id: 1, repository_slug: 'travis-ci/travis-core', build_id: 1, commit_id: 1, log_id: 1, number: '1.1', config: { rvm: 'rbx' }, duration: 30, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:30Z', state: 'passed', allow_failure: false } - { id: '2', repository_id: 1, repository_slug: 'travis-ci/travis-core', build_id: 1, commit_id: 1, log_id: 2, number: '1.2', config: { rvm: '1.9.3' }, duration: 40, started_at: '2012-07-02T00:00:00Z', finished_at: '2012-07-02T00:00:40Z', state: 'failed', allow_failure: false } - { id: '3', repository_id: 1, repository_slug: 'travis-ci/travis-core', build_id: 1, commit_id: 1, log_id: 3, number: '1.3', config: { rvm: 'jruby' }, duration: null, started_at: null, finished_at: null, allow_failure: true, state: null } - { id: '4', repository_id: 1, repository_slug: 'travis-ci/travis-core', build_id: 2, commit_id: 2, log_id: 4, number: '2.1', config: { rvm: 'rbx' }, duration: null, started_at: null, finished_at: null, allow_failure: false, state: null } - { id: '5', repository_id: 2, repository_slug: 'travis-ci/travis-assets', build_id: 3, commit_id: 3, log_id: 5, number: '3.1', config: { rvm: 'rbx' }, duration: 30, started_at: '2012-07-02T00:01:00Z', finished_at: '2012-07-02T00:01:30Z', state: 'failed', allow_failure: false } - { id: '6', repository_id: 3, repository_slug: 'travis-ci/travis-hub', build_id: 4, commit_id: 4, log_id: 6, number: '4.1', config: { rvm: 'rbx' }, started_at: '2012-07-02T00:02:00Z', allow_failure: false, state: null } - { id: '7', repository_id: 1, repository_slug: 'travis-ci/travis-core', build_id: 5, commit_id: 5, log_id: 7, number: '5.1', config: { rvm: 'rbx' }, duration: null, started_at: null, finished_at: null, state: 'created', queue: 'builds.linux', allow_failure: false } - { id: '8', repository_id: 1, repository_slug: 'travis-ci/travis-core', build_id: 5, commit_id: 5, log_id: 8, number: '5.2', config: { rvm: 'rbx' }, duration: null, started_at: null, finished_at: null, state: 'created', queue: 'builds.linux', allow_failure: false } -] - -artifacts = [ - { id: '1', body: 'log 1' } - { id: '2', body: 'log 2' } - { id: '3', body: 'log 3' } - { id: '4', body: 'log 4' } - { id: '5', body: 'log 5' } - { id: '6', body: 'log 6' } - { id: '7', body: 'log 7' } - { id: '8', body: 'log 8' } -] - -branches = [ - { branches: [builds[0], builds[1]], commits: [commits[0], commits[1]] }, - { branches: [builds[2]], commits: [commits[2]] }, - { branches: [builds[3]], commits: [commits[3]] }, -] - -workers = [ - { id: '1', name: 'ruby-1', host: 'worker.travis-ci.org', state: 'ready' } - { id: '2', name: 'ruby-2', host: 'worker.travis-ci.org', state: 'ready' } -] - -hooks = [ - { slug: 'travis-ci/travis-core', description: 'description of travis-core', active: true, private: false } - { slug: 'travis-ci/travis-assets', description: 'description of travis-assets', active: false, private: false } - { slug: 'svenfuchs/minimal', description: 'description of minimal', active: true, private: false } -] - - -$.mockjax - url: '/repos' - responseTime: responseTime - response: (settings) -> - if !settings.data - this.responseText = { repos: repos } - else if slug = settings.data.slug - reposForResponse = $.select(repos, (repository) -> repository.slug == slug) - this.responseText = { repos: reposForResponse } - else if search = settings.data.search - this.responseText = { repos: $.select(repos, (repository) -> repository.slug.indexOf(search) > -1).toArray() } - else if settings.data.member - this.responseText = { repos: reposByName(settings.data.member) } - else - console.log settings.data - throw 'unknown params for repos' - -for repository in repos - $.mockjax - url: '/' + repository.slug - responseTime: responseTime - responseText: { repository: repository } - - $.mockjax - url: '/repos' - data: { slug: repository.slug } - responseTime: responseTime - responseText: { repos: [repository] } - - $.mockjax - url: '/builds' - data: { ids: repository.build_ids } - responseTime: responseTime - responseText: { builds: $.select(builds, (build) -> repository.build_ids.indexOf(build.id) != -1) } - - $.mockjax - url: '/builds' - data: { repository_id: repository.id, event_type: 'push' } - responseTime: responseTime - responseText: - builds: (builds[id - 1] for id in repository.build_ids) - commits: (commits[builds[id - 1].commit_id - 1] for id in repository.build_ids) - -for build in builds - $.mockjax - url: '/builds/' + build.id - responseTime: responseTime - responseText: - build: build, - commit: commits[build.commit_id - 1] - jobs: (jobs[id - 1] for id in build.job_ids) - - # $.mockjax - # url: '/jobs' - # data: { ids: build.job_ids.join(',') } - # responseTime: responseTime - # responseText: { jobs: $.select(jobs, (job) -> build.job_ids.indexOf(job.id) != -1) } - -for job in jobs - $.mockjax - url: '/jobs/' + job.id - responseTime: responseTime - responseText: - job: job, - commit: commits[job.commit_id - 1] - -$.mockjax - url: '/jobs' - responseTime: responseTime - responseText: - jobs: $.select(jobs, (job) -> job.state == 'created') - -$.mockjax - url: '/builds*' - responseTime: responseTime - response: (settings) -> - if match = settings.url.match('/builds\\?(ids.*)') - ids = match[1].split(new RegExp('&?ids\\[\\]=')).filter (str) -> str != '' - this.responseText = { builds: $.select(builds, (build) -> ids.contains(build.id) ) } - else - throw "can't handle mocked request" - -for data in branches - $.mockjax - url: '/branches' - data: { repository_id: data.branches[0].repository_id } - responseTime: responseTime - responseText: data - -for artifact in artifacts - $.mockjax - url: '/artifacts/' + artifact.id - responseTime: responseTime - responseText: - artifact: artifact - -$.mockjax - url: '/workers' - responseTime: responseTime - responseText: { workers: workers } - -$.mockjax - url: '/profile/hooks' - responseTime: responseTime - responseText: { hooks: hooks } diff --git a/assets/scripts/spec/unit/build_spec.coffee b/assets/scripts/spec/unit/build_spec.coffee deleted file mode 100644 index c6d3c3fd..00000000 --- a/assets/scripts/spec/unit/build_spec.coffee +++ /dev/null @@ -1,26 +0,0 @@ -record = null - -module "Travis.Build", - setup: -> - teardown: -> - Travis.Build.resetData() - Travis.Job.resetData() - -test 'it takes into account all the jobs when getting config keys', -> - buildConfig = { rvm: ['1.9.3', '2.0.0'] } - Travis.Build.load [{ id: '1', job_ids: ['1', '2', '3'], config: buildConfig }] - - Travis.Job.load [{ id: '1', config: { rvm: '1.9.3', env: 'FOO=foo' } }] - Travis.Job.load [{ id: '2', config: { rvm: '2.0.0', gemfile: 'Gemfile.1' } }] - Travis.Job.load [{ id: '3', config: { rvm: '1.9.3', jdk: 'OpenJDK' } }] - - build = null - rawConfigKeys = null - configKeys = null - Ember.run -> - build = Travis.Build.find '1' - rawConfigKeys = build.get('rawConfigKeys') - configKeys = build.get('configKeys') - - deepEqual(rawConfigKeys, ['rvm', 'env', 'gemfile', 'jdk' ]) - deepEqual(configKeys, [ 'Job', 'Duration', 'Finished', 'Ruby', 'ENV', 'Gemfile', 'JDK' ]) diff --git a/assets/scripts/spec/unit/commit_spec.coffee b/assets/scripts/spec/unit/commit_spec.coffee deleted file mode 100644 index 799b6ca7..00000000 --- a/assets/scripts/spec/unit/commit_spec.coffee +++ /dev/null @@ -1,39 +0,0 @@ -record = null - -module "Travis.Commit", - setup: -> - teardown: -> - Travis.Commit.resetData() - -test 'it recognizes when author is committer', -> - Travis.Commit.load [ - { - id: 1, - committer_name: 'Jimmy', - committer_email: 'jimmy@example.com', - author_name: 'Jimmy', - author_email: 'jimmy@example.com' - } - ] - - Ember.run -> - record = Travis.Commit.find 1 - - console.log(record.get('authorName')) - equal(true, record.get('authorIsCommitter')) - -test 'it recognizes when author is not committer', -> - Travis.Commit.load [ - { - id: 1, - committer_name: 'Jimmy', - committer_email: 'jimmy@example.com', - author_name: 'John', - author_email: 'john@example.com' - } - ] - - Ember.run -> - record = Travis.Commit.find 1 - console.log(record.get('authorName')) - equal(false, record.get('authorIsCommitter')) diff --git a/assets/scripts/spec/unit/helpers_spec.coffee b/assets/scripts/spec/unit/helpers_spec.coffee deleted file mode 100644 index 45781f20..00000000 --- a/assets/scripts/spec/unit/helpers_spec.coffee +++ /dev/null @@ -1,74 +0,0 @@ -module "Travis.Helpers.githubify" - -test 'replaces #Num with github issues link', -> - message = 'Solved #11hey' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'Solved #11hey' - - equal(result, expected, "#num should be converted to a link") - -test 'replaces User#Num with github issues link to forked repo', -> - message = 'Solved test#11hey' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'Solved test#11hey' - - equal(result, expected, "user#num should be converted to a link") - -test 'replaces User/Project#Num with github issues link to another repo', -> - message = 'Solved test_1-a2/test-a_11#11hey' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'Solved test_1-a2/test-a_11#11hey' - - equal(result, expected, "owner/repo#num should be converted to a link") - -test 'replaces gh-Num with github issues link', -> - message = 'Solved gh-22hey' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'Solved gh-22hey' - - equal(result, expected, "gh-Num should be converted to a link") - -test 'replaces multiple references with github issues links', -> - message = 'Try #1 and test#2 and test/testing#3' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'Try #1 and ' - expected += 'test#2 and ' - expected += 'test/testing#3' - - equal(result, expected, "references should be converted to links") - -test 'replaces multiple references with github issues links', -> - message = 'Try #1 and test#2 and test/testing#3' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'Try #1 and ' - expected += 'test#2 and ' - expected += 'test/testing#3' - - equal(result, expected, "references should be converted to links") - -test 'replaces @user with github user link', -> - message = 'It is for you @tender_love1' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'It is for you @tender_love1' - - equal(result, expected, "@user should be converted to a link") - -test 'does not replace @user if it is a sign-off', -> - message = 'Signed-off-by: GitHub User ' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - - equal(result, message, "@user should not be converted to a link if it matches an email") - -test 'replaces one commit reference with github commit link', -> - message = 'See travis-ci/travis-core@732fe00' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'See travis-ci/travis-core@732fe00' - - equal(result, expected, "Commit reference should be converted to a link") - -test 'replaces multiple commit references with github commit links', -> - message = 'See travis-ci/travis-core@732fe00 and travis-ci/travis-web@3b6aa17' - result = Travis.Helpers.githubify(message, 'travis-ci', 'travis-web') - expected = 'See travis-ci/travis-core@732fe00 and travis-ci/travis-web@3b6aa17' - - equal(result, expected, "Commit references should be converted to links") diff --git a/assets/scripts/spec/unit/job_spec.coffee b/assets/scripts/spec/unit/job_spec.coffee deleted file mode 100644 index a42409b6..00000000 --- a/assets/scripts/spec/unit/job_spec.coffee +++ /dev/null @@ -1,82 +0,0 @@ -record = null - -module "Travis.Job", - setup: -> - teardown: -> - Travis.Job.resetData() - Travis.Build.resetData() - -test 'configKeys takes into account the keys of other jobs', -> - buildConfig = { rvm: ['1.9.3', '2.0.0'] } - Travis.Build.load [{ id: '1', job_ids: ['1', '2', '3'], config: buildConfig }] - - Travis.Job.load [{ id: '1', config: { rvm: '1.9.3', env: 'FOO=foo' }, build_id: '1' }] - Travis.Job.load [{ id: '2', config: { rvm: '2.0.0', gemfile: 'Gemfile.1' }, build_id: '1' }] - Travis.Job.load [{ id: '3', config: { rvm: '1.9.3', jdk: 'OpenJDK' }, build_id: '1' }] - - configValues1 = null - configValues2 = null - configValues3 = null - job1 = null - job2 = null - job3 = null - - Ember.run -> - job1 = Travis.Job.find('1') - job2 = Travis.Job.find('2') - job3 = Travis.Job.find('3') - - wait().then -> - Ember.run -> - configValues1 = job1.get('configValues') - configValues2 = job2.get('configValues') - configValues3 = job3.get('configValues') - - deepEqual( configValues1, [ '1.9.3', 'FOO=foo', undefined, undefined ] ) - deepEqual( configValues2, [ '2.0.0', undefined, 'Gemfile.1', undefined ] ) - deepEqual( configValues3, [ '1.9.3', undefined, undefined, 'OpenJDK' ] ) - -test 'returns config values for all keys available on build with different number of config keys in sibling jobs', -> - buildAttrs = - id: 1 - job_ids: [1, 2] - config: - jdk: ['oraclejdk7'] - rvm: ['jruby-head'] - - Travis.Build.load [buildAttrs] - - jobAttrs = - id: 1 - build_id: 1 - config: - jdk: 'oraclejdk7' - rvm: 'jruby-head' - - Travis.Job.load [jobAttrs] - - jobAttrs = - id: 2 - build_id: 1 - config: - jdk: null - rvm: 'jruby-head' - - Travis.Job.load [jobAttrs] - - configValues1 = null - configValues2 = null - job1 = null - job2 = null - - Ember.run -> - job1 = Travis.Job.find(1) - job2 = Travis.Job.find(2) - - wait().then -> - Ember.run -> - configValues1 = job1.get('configValues') - configValues2 = job2.get('configValues') - - deepEqual( configValues1, ['oraclejdk7', 'jruby-head'] ) - deepEqual( configValues2, [undefined, 'jruby-head'] ) diff --git a/assets/scripts/spec/unit/limited_array_spec.coffee b/assets/scripts/spec/unit/limited_array_spec.coffee deleted file mode 100644 index 8c482234..00000000 --- a/assets/scripts/spec/unit/limited_array_spec.coffee +++ /dev/null @@ -1,48 +0,0 @@ -module 'Travis.LimitedArray' - -test 'limits given content', -> - content = [1, 2, 3] - array = Travis.LimitedArray.create content: content, limit: 2 - equal( array.get('length'), 2 ) - deepEqual( array.toArray(), [1, 2] ) - -test 'inserts content at the right place when unshifting', -> - content = [1, 2, 3] - array = Travis.LimitedArray.create content: content, limit: 2 - content.unshiftObject 0 - equal( array.get('length'), 2 ) - deepEqual( array.toArray(), [0, 1] ) - -test 'does not insert content when it\'s inserted not in the limited range', -> - content = [1, 2, 3] - array = Travis.LimitedArray.create content: content, limit: 2 - content.pushObject 0 - equal( array.get('length'), 2 ) - deepEqual( array.toArray(), [1, 2] ) - -test 'properly removes items', -> - content = [1, 2, 3] - array = Travis.LimitedArray.create content: content, limit: 2 - content.shiftObject() - - equal( array.get('length'), 2 ) - deepEqual( array.toArray(), [2, 3] ) - - content.shiftObject() - - equal( array.get('length'), 1 ) - deepEqual( array.toArray(), [3] ) - - content.shiftObject() - - equal( array.get('length'), 0) - -test 'allows to expand array to show all items', -> - content = [1, 2, 3] - array = Travis.LimitedArray.create content: content, limit: 2 - - Ember.run -> - array.showAll() - - equal( array.get('length'), 3) - deepEqual( array.toArray(), [1, 2, 3]) diff --git a/assets/scripts/spec/unit/line_selector_spec.coffee b/assets/scripts/spec/unit/line_selector_spec.coffee deleted file mode 100644 index 93a5a7c3..00000000 --- a/assets/scripts/spec/unit/line_selector_spec.coffee +++ /dev/null @@ -1,108 +0,0 @@ -fakeLocation = { - getHash: -> - @hash || '' - setHash: (hash) -> - @hash = hash -} - -fakeScroll = - tryScroll: sinon.spy() -fakeFolder = {} - -element = jQuery('
-

first line

-

second line

-

third line

-
') - -module "Travis.LinesSelector", - setup: -> - fakeFolder.unfold = sinon.spy() - fakeLocation.hash = '' - jQuery('body').append(element) - - teardown: -> - element.remove() - -test "defaults to no line selected", -> - Ember.run -> - new Travis.LinesSelector(element, fakeScroll, fakeFolder, fakeLocation) - - wait().then -> - equal($('#fakeLog p.highlight').length, 0) - -test "defaults to a single line selected", -> - fakeLocation.hash = '#L2' - Ember.run -> - new Travis.LinesSelector(element, fakeScroll, fakeFolder, fakeLocation) - - wait().then -> - equal($('#fakeLog p.highlight').length, 1) - equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) - -test "defaults to multiple lines selected", -> - fakeLocation.hash = '#L2-L3' - Ember.run -> - new Travis.LinesSelector(element, fakeScroll, fakeFolder, fakeLocation) - - wait().then -> - equal($('#fakeLog p.highlight').length, 2) - equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) - equal($('#fakeLog p:nth-child(3)').hasClass('highlight'), true) - -test "selects a single line", -> - Ember.run -> - new Travis.LinesSelector(element, fakeScroll, fakeFolder, fakeLocation) - - wait().then -> - equal($('#fakeLog p.highlight').length, 0) - $('#fakeLog p:first a').click() - equal($('#fakeLog p.highlight').length, 1) - equal($('#fakeLog p:nth-child(1)').hasClass('highlight'), true) - equal('#L1', fakeLocation.hash) - -test "selects multiple lines", -> - fakeLocation.hash = '#L2' - Ember.run -> - new Travis.LinesSelector(element, fakeScroll, fakeFolder, fakeLocation) - - wait().then -> - equal($('#fakeLog p.highlight').length, 1) - - event = jQuery.Event('click') - event.shiftKey = true - $('#fakeLog p:first a').trigger(event) - - equal($('#fakeLog p.highlight').length, 2) - equal($('#fakeLog p:nth-child(1)').hasClass('highlight'), true) - equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) - equal('#L1-L2', fakeLocation.hash) - -test "uses the last selected line as second selection line", -> - selector = null - Ember.run -> - selector = new Travis.LinesSelector(element, fakeScroll, fakeFolder, fakeLocation) - - wait().then -> - $('#fakeLog p:last a').click() - equal($('#fakeLog p.highlight').length, 1) - equal(3, selector.last_selected_line) - - event = jQuery.Event('click') - event.shiftKey = true - $('#fakeLog p:first a').trigger(event) - - equal($('#fakeLog p.highlight').length, 3) - equal($('#fakeLog p:nth-child(1)').hasClass('highlight'), true) - equal($('#fakeLog p:nth-child(2)').hasClass('highlight'), true) - equal($('#fakeLog p:nth-child(3)').hasClass('highlight'), true) - equal('#L1-L3', fakeLocation.hash) - equal(1, selector.last_selected_line) - -test "unfolds the first and last selected lines", -> - fakeLocation.hash = '#L1-L3' - Ember.run -> - new Travis.LinesSelector(element, fakeScroll, fakeFolder, fakeLocation) - - wait().then -> - ok(fakeFolder.unfold.calledTwice, 'the first and last lines have been unfolded') diff --git a/assets/scripts/spec/unit/log_chunks_spec.coffee b/assets/scripts/spec/unit/log_chunks_spec.coffee deleted file mode 100644 index c643cd69..00000000 --- a/assets/scripts/spec/unit/log_chunks_spec.coffee +++ /dev/null @@ -1,75 +0,0 @@ -module "Travis.LogChunks" - -test "it doesn't trigger downloading missing parts if they come in timely fashion", -> - expect(2) - stop() - - callback = -> ok false, 'callback should not be called' - - chunks = Travis.LogChunks.create(timeout: 20, missingPartsCallback: callback, content: []) - - Ember.run.later (-> chunks.pushObject(number: 1, final: false)), 10 - Ember.run.later (-> chunks.pushObject(number: 2, final: false)), 20 - setTimeout -> - ok true - Ember.run -> - chunks.pushObject(number: 3, final: true) - start() - - equal(chunks.get('finalized'), true, 'log should be finalized') - , 30 - -test "it triggers downloading missing parts if there is a missing part, even though final part arrived", -> - expect(3) - stop() - - callback = (missingNumbers) -> - deepEqual(missingNumbers, [2, 3], 'callback should be called with missing numbers') - - chunks = Travis.LogChunks.create(timeout: 20, missingPartsCallback: callback, content: []) - - Ember.run -> chunks.pushObject(number: 1, final: false) - setTimeout -> - Ember.run -> chunks.pushObject(number: 4, final: true) - - ok(!chunks.get('finalized'), "log shouldn't be finalized") - , 10 - - setTimeout -> - Ember.run -> chunks.destroy() # destroy object to not fire more callbacks - start() - , 60 - -test "it triggers downloading next parts if there is no final part", -> - expect(4) - stop() - - callback = (missingNumbers, after) -> - deepEqual(missingNumbers, [2], 'callback should be called with missing numbers') - equal(after, 3, 'callback should be called with "after" argument') - - chunks = Travis.LogChunks.create(timeout: 15, missingPartsCallback: callback, content: []) - - Ember.run -> - chunks.pushObject(number: 1, final: false) - chunks.pushObject(number: 3, final: false) - - setTimeout -> - Ember.run -> chunks.destroy() # destroy object to not fire more callbacks - start() - , 35 - -test "it triggers downloading all available parts if there is no parts yet", -> - expect(2) - stop() - - callback = (missingNumbers, after) -> - ok(!missingNumbers, 'there should be no missing parts') - ok(!after, 'after should not be specified') - - chunks = Travis.LogChunks.create(timeout: 15, missingPartsCallback: callback, content: []) - - setTimeout -> - Ember.run -> chunks.destroy() # destroy object to not fire more callbacks - start() - , 25 diff --git a/assets/scripts/spec/unit/log_folder_spec.coffee b/assets/scripts/spec/unit/log_folder_spec.coffee deleted file mode 100644 index d683c45b..00000000 --- a/assets/scripts/spec/unit/log_folder_spec.coffee +++ /dev/null @@ -1,54 +0,0 @@ -element = jQuery('
-

first line

-
-

second line

-

third line

-
-

fourth line

-
') -logFolder = null - -module "Travis.LogFolder", - setup: -> - jQuery('body').append(element) - logFolder = new Travis.LogFolder jQuery('#fakeLog') - - teardown: -> - element.remove() - -test "displays the fold", -> - equal($('#fakeLog .fold.open').length, 0) - $('#fakeLog .fold p:first').click() - equal($('#fakeLog .fold.open').length, 1) - -test "hides the fold", -> - $('#fakeLog .fold').addClass('open') - $('#fakeLog .fold p:first').click() - equal($('#fakeLog .fold.open').length, 0) - -test "binds new elements", -> - new_element = jQuery('
-

fifth line

-
') - jQuery('#fakeLog').append new_element - - equal($('#fakeLog .fold.open').length, 0) - $('#fakeLog .fold p:first-child').click() - equal($('#fakeLog .fold.open').length, 2) - -test "fold", -> - fold = jQuery('#fakeLog .fold') - line = fold.find('p:first') - fold.addClass('open') - - equal(fold.hasClass('open'), true) - logFolder.fold(line) - equal(fold.hasClass('open'), false) - -test "unfold", -> - fold = jQuery('#fakeLog .fold') - line = fold.find('p:first') - - equal(fold.hasClass('open'), false) - logFolder.unfold(line) - equal(fold.hasClass('open'), true) diff --git a/assets/scripts/spec/unit/model_spec.coffee b/assets/scripts/spec/unit/model_spec.coffee deleted file mode 100644 index b14b42aa..00000000 --- a/assets/scripts/spec/unit/model_spec.coffee +++ /dev/null @@ -1,122 +0,0 @@ -fullPostHash = null -Post = null -Author = null -Comment = null - -module "Travis.Model", - setup: -> - fullPostHash = { - id: '1', - title: 'foo', - published_at: 'today', - - author_id: '1', - comment_ids: ['1', '2'] - } - - Author = Travis.Model.extend( - name: Ember.attr('string') - ) - Author.toString = -> return 'Author' - - Comment = Travis.Model.extend( - body: Ember.attr('string') - ) - Comment.toString = -> return 'Comment' - - Post = Travis.Model.extend( - title: Ember.attr('string'), - publishedAt: Ember.attr('string'), - - author: Ember.belongsTo(Author, { key: 'author_id' }), - comments: Ember.hasMany(Comment, { key: 'comment_ids' }) - ) - Post.toString = -> return 'Post' - - Comment.adapter = Ember.FixtureAdapter.create() - Author.adapter = Ember.FixtureAdapter.create() - Post.adapter = Ember.FixtureAdapter.create() - - Author.load([ - { id: '1', name: 'drogus' } - ]) - Comment.load([ - { id: '1', body: 'comment 1' }, - { id: '2', body: 'comment 2' } - ]) -test "new data can be merged into the record", -> - delete fullPostHash.title - delete fullPostHash.author_id - delete fullPostHash.comment_ids - post = Post.findFromCacheOrLoad(fullPostHash) - - post.loadTheRest = (->) - - equal(post.get('title'), null, 'title should be null') - equal(post.get('comments.length'), 0, 'comments should be empty') - equal(post.get('author'), null, 'author should be null') - - Ember.run -> post.merge(title: 'teh title', comment_ids: ['1', '2'], author_id: '1') - - author = null - Ember.run -> author = Author.find('1').get('name') - title = null - Ember.run -> title = post.get('title') - console.log('title', title) - - equal(post.get('title'), 'teh title', 'title should be updated') - equal(post.get('comments.length'), 2, 'comments should be updated and have length of 2') - equal(post.get('comments.firstObject.body'), 'comment 1', 'comment should be loaded') - equal(author, 'drogus', 'author should be loaded') - equal(post.get('publishedAt'), 'today', 'existing attributes are not overwritten') - -module "Travis.Model.loadOrMerge", - setup: -> - Post = Travis.Model.extend( - title: Ember.attr('string') - ) - Post.toString = -> return 'Post' - -test "it doesn't update record if skipIfExists is passed and record is already in store", -> - Post.load([{id: '1', title: 'foo'}]) - - post = Post.find('1') - equal(post.get('title'), 'foo', 'precondition - title of the post should be set') - - Ember.run -> - Travis.loadOrMerge(Post, { id: '1', title: 'bar' }, { skipIfExists: true }) - - equal(post.get('title'), 'foo', 'title should stay unchanged') - -test "it updates record if record is already in the store", -> - Post.load([{id: '1', title: 'foo'}]) - - post = Post.find('1') - equal(post.get('title'), 'foo', 'precondition - title of the post should be set') - - Ember.run -> - Travis.loadOrMerge(Post, { id: '1', title: 'bar' }) - - equal(post.get('title'), 'bar', 'title should be updated') - -test "record is not instantiated by default", -> - reference = null - Ember.run -> - reference = Travis.loadOrMerge(Post, { id: '1', title: 'bar' }) - - equal(reference.id, '1', 'reference should be created') - ok(Ember.isNone(reference.record), 'record should not be created') - - post = null - Ember.run -> post = Post.find('1') - equal(post.get('title'), 'bar', 'record should be loaded from cached data') - equal(reference.record, post, 'record should be created') - -test "data is merged to the existing data cache", -> - Post.load([{id: '1', title: 'foo'}]) - - Ember.run -> - Travis.loadOrMerge(Post, { id: '1', title: 'bar' }) - - post = Post.find('1') - equal(post.get('title'), 'bar', 'title should be updated') diff --git a/assets/scripts/spec/unit/tailing_spec.coffee b/assets/scripts/spec/unit/tailing_spec.coffee deleted file mode 100644 index 3ccb613f..00000000 --- a/assets/scripts/spec/unit/tailing_spec.coffee +++ /dev/null @@ -1,89 +0,0 @@ -fakeWindow = - scroll: sinon.spy() - scrollTop: sinon.stub().returns(0) - height: sinon.stub().returns(40) -element = jQuery('
') -log = jQuery('
') -tail = new Travis.Tailing(fakeWindow, '#specTail', '#specLog') -tail.tail = -> element -tail.log = -> log - -module "Travis.Tailing", - setup: -> - jQuery('body').append(element) - jQuery('body').append(log) - - teardown: -> - element.remove() - log.remove() - tail.stop() - -#test "toggle", -> -# equal(element.hasClass('active'), false) -# tail.toggle() -# equal(element.hasClass('active'), true) -# tail.toggle() -# stop() -# -# Ember.run.later -> -# start() -# equal(element.hasClass('active'), false) -# , 300 -# -#test "active", -> -# equal(tail.active(), false) -# element.addClass('active') -# equal(tail.active(), true) -# -#test "autoscroll when inactive", -> -# tail.scrollTo = sinon.spy() -# -# equal(tail.active(), false) -# equal(tail.autoScroll(), false) -# equal(tail.scrollTo.called, false) -# -#test "autoscroll", -> -# element.addClass('active') -# log.offset = -> {top: 1} -# log.outerHeight = -> 1 -# -# equal(tail.active(), true) -# equal(tail.autoScroll(), true) -# equal(fakeWindow.scrollTop.calledWith(2), true) -# -#test "autoscroll when we're at the bottom", -> -# element.addClass('active') -# log.offset = -> {top: 0} -# log.outerHeight = -> 0 -# -# equal(tail.active(), true) -# equal(tail.autoScroll(), false) -# equal(fakeWindow.scrollTop.calledWith(0), false) -# -#test 'should stop scrolling if the position changed', -> -# element.addClass('active') -# tail.position = 100 -# tail.onScroll() -# equal(element.hasClass('active'), false) -# -#test 'positionButton adds the scrolling class', -> -# log.offset = -> {top: -1} -# -# tail.positionButton() -# equal(element.hasClass('scrolling'), true) -# equal(element.hasClass('bottom'), false) -# -#test 'positionButton removes the scrolling class', -> -# log.offset = -> {top: 1} -# tail.positionButton() -# equal(element.hasClass('scrolling'), false) -# equal(element.hasClass('bottom'), false) -# -#test 'positionButton sets the button as bottom', -> -# log.offset = -> {top: -100} -# log.height = -> 50 -# tail.height = -> 1 -# -# tail.positionButton() -# equal(element.hasClass('scrolling'), false) -# equal(element.hasClass('bottom'), true) diff --git a/assets/scripts/spec/unit/user_spec.coffee b/assets/scripts/spec/unit/user_spec.coffee deleted file mode 100644 index 81df96dc..00000000 --- a/assets/scripts/spec/unit/user_spec.coffee +++ /dev/null @@ -1,46 +0,0 @@ -record = null - -module "Travis.User", - setup: -> - teardown: -> - Travis.User.resetData() - -test '', -> - # TODO: we should not need to mock entire user response - # just for user creation. It happens, because whenever - # a user is created we try to get fresh data - userData = { - id: 1 - email: 'tyrion@example.org' - login: 'tyrion' - token: 'abcdef' - created_at: "2011-05-10T15:43:59Z" - gravatar_id: "582034b63279abeaa8e76acf12f5ee30" - is_syncing: false - name: "Tyrion" - synced_at: "2013-12-09T09:41:47Z" - } - $.mockjax - url: '/users/1' - responseTime: 10 - responseText: - user: userData - - - Travis.User.load [{ id: '1', login: 'test@travis-ci.org' }] - user = null - pushPermissions = null - adminPermissions = null - - Ember.run -> - user = Travis.User.find(1) - user.set '_rawPermissions', - then: (func) -> - func(permissions: [1], admin: [1], pull: [2], push: [3]) - - pushPermissions = user.get('pushPermissions') - adminPermissions = user.get('adminPermissions') - - wait().then -> - deepEqual(adminPermissions.toArray(), [1]) - deepEqual(pushPermissions.toArray(), [3]) diff --git a/assets/scripts/spec/vendor/jquery.mockjax.js b/assets/scripts/spec/vendor/jquery.mockjax.js deleted file mode 100644 index e487b2db..00000000 --- a/assets/scripts/spec/vendor/jquery.mockjax.js +++ /dev/null @@ -1,523 +0,0 @@ -/*! - * MockJax - jQuery Plugin to Mock Ajax requests - * - * Version: 1.5.1 - * Released: - * Home: http://github.com/appendto/jquery-mockjax - * Author: Jonathan Sharp (http://jdsharp.com) - * License: MIT,GPL - * - * Copyright (c) 2011 appendTo LLC. - * Dual licensed under the MIT or GPL licenses. - * http://appendto.com/open-source-licenses - */ -(function($) { - var _ajax = $.ajax, - mockHandlers = [], - CALLBACK_REGEX = /=\?(&|$)/, - jsc = (new Date()).getTime(); - - - // Parse the given XML string. - function parseXML(xml) { - if ( window['DOMParser'] == undefined && window.ActiveXObject ) { - DOMParser = function() { }; - DOMParser.prototype.parseFromString = function( xmlString ) { - var doc = new ActiveXObject('Microsoft.XMLDOM'); - doc.async = 'false'; - doc.loadXML( xmlString ); - return doc; - }; - } - - try { - var xmlDoc = ( new DOMParser() ).parseFromString( xml, 'text/xml' ); - if ( $.isXMLDoc( xmlDoc ) ) { - var err = $('parsererror', xmlDoc); - if ( err.length == 1 ) { - throw('Error: ' + $(xmlDoc).text() ); - } - } else { - throw('Unable to parse XML'); - } - } catch( e ) { - var msg = ( e.name == undefined ? e : e.name + ': ' + e.message ); - $(document).trigger('xmlParseError', [ msg ]); - return undefined; - } - return xmlDoc; - } - - // Trigger a jQuery event - function trigger(s, type, args) { - (s.context ? $(s.context) : $.event).trigger(type, args); - } - - // Check if the data field on the mock handler and the request match. This - // can be used to restrict a mock handler to being used only when a certain - // set of data is passed to it. - function isMockDataEqual( mock, live ) { - var identical = false; - // Test for situations where the data is a querystring (not an object) - if (typeof live === 'string') { - // Querystring may be a regex - return $.isFunction( mock.test ) ? mock.test(live) : mock == live; - } - $.each(mock, function(k, v) { - if ( live[k] === undefined ) { - identical = false; - return identical; - } else { - identical = true; - if ( typeof live[k] == 'object' ) { - return isMockDataEqual(mock[k], live[k]); - } else { - if ( $.isFunction( mock[k].test ) ) { - identical = mock[k].test(live[k]); - } else { - identical = ( mock[k] == live[k] ); - } - return identical; - } - } - }); - - return identical; - } - - // Check the given handler should mock the given request - function getMockForRequest( handler, requestSettings ) { - // If the mock was registered with a function, let the function decide if we - // want to mock this request - if ( $.isFunction(handler) ) { - return handler( requestSettings ); - } - - // Inspect the URL of the request and check if the mock handler's url - // matches the url for this ajax request - if ( $.isFunction(handler.url.test) ) { - // The user provided a regex for the url, test it - if ( !handler.url.test( requestSettings.url ) ) { - return null; - } - } else { - // Look for a simple wildcard '*' or a direct URL match - var star = handler.url.indexOf('*'); - if (handler.url !== requestSettings.url && star === -1 || - !new RegExp(handler.url.replace(/[-[\]{}()+?.,\\^$|#\s]/g, "\\$&").replace('*', '.+')).test(requestSettings.url)) { - return null; - } - } - - // Inspect the data submitted in the request (either POST body or GET query string) - if ( handler.data && requestSettings.data ) { - if ( !isMockDataEqual(handler.data, requestSettings.data) ) { - // They're not identical, do not mock this request - return null; - } - } - // Inspect the request type - if ( handler && handler.type && - handler.type.toLowerCase() != requestSettings.type.toLowerCase() ) { - // The request type doesn't match (GET vs. POST) - return null; - } - - return handler; - } - - // If logging is enabled, log the mock to the console - function logMock( mockHandler, requestSettings ) { - var c = $.extend({}, $.mockjaxSettings, mockHandler); - if ( c.log && $.isFunction(c.log) ) { - c.log('MOCK ' + requestSettings.type.toUpperCase() + ': ' + requestSettings.url, $.extend({}, requestSettings)); - } - } - - // Process the xhr objects send operation - function _xhrSend(mockHandler, requestSettings, origSettings) { - - // This is a substitute for < 1.4 which lacks $.proxy - var process = (function(that) { - return function() { - return (function() { - // The request has returned - this.status = mockHandler.status; - this.statusText = mockHandler.statusText; - this.readyState = 4; - - // We have an executable function, call it to give - // the mock handler a chance to update it's data - if ( $.isFunction(mockHandler.response) ) { - mockHandler.response(origSettings); - } - // Copy over our mock to our xhr object before passing control back to - // jQuery's onreadystatechange callback - if ( requestSettings.dataType == 'json' && ( typeof mockHandler.responseText == 'object' ) ) { - this.responseText = JSON.stringify(mockHandler.responseText); - } else if ( requestSettings.dataType == 'xml' ) { - if ( typeof mockHandler.responseXML == 'string' ) { - this.responseXML = parseXML(mockHandler.responseXML); - } else { - this.responseXML = mockHandler.responseXML; - } - } else { - this.responseText = mockHandler.responseText; - } - if( typeof mockHandler.status == 'number' || typeof mockHandler.status == 'string' ) { - this.status = mockHandler.status; - } - if( typeof mockHandler.statusText === "string") { - this.statusText = mockHandler.statusText; - } - // jQuery < 1.4 doesn't have onreadystate change for xhr - if ( $.isFunction(this.onreadystatechange) ) { - if( mockHandler.isTimeout) { - this.status = -1; - } - this.onreadystatechange( mockHandler.isTimeout ? 'timeout' : undefined ); - } else if ( mockHandler.isTimeout ) { - // Fix for 1.3.2 timeout to keep success from firing. - this.status = -1; - } - }).apply(that); - }; - })(this); - - if ( mockHandler.proxy ) { - // We're proxying this request and loading in an external file instead - _ajax({ - global: false, - url: mockHandler.proxy, - type: mockHandler.proxyType, - data: mockHandler.data, - dataType: requestSettings.dataType === "script" ? "text/plain" : requestSettings.dataType, - complete: function(xhr, txt) { - mockHandler.responseXML = xhr.responseXML; - mockHandler.responseText = xhr.responseText; - mockHandler.status = xhr.status; - mockHandler.statusText = xhr.statusText; - this.responseTimer = setTimeout(process, mockHandler.responseTime || 0); - } - }); - } else { - // type == 'POST' || 'GET' || 'DELETE' - if ( requestSettings.async === false ) { - // TODO: Blocking delay - process(); - } else { - this.responseTimer = setTimeout(process, mockHandler.responseTime || 50); - } - } - } - - // Construct a mocked XHR Object - function xhr(mockHandler, requestSettings, origSettings, origHandler) { - // Extend with our default mockjax settings - mockHandler = $.extend({}, $.mockjaxSettings, mockHandler); - - if (typeof mockHandler.headers === 'undefined') { - mockHandler.headers = {}; - } - if ( mockHandler.contentType ) { - mockHandler.headers['content-type'] = mockHandler.contentType; - } - - return { - status: mockHandler.status, - statusText: mockHandler.statusText, - readyState: 1, - open: function() { }, - send: function() { - origHandler.fired = true; - _xhrSend.call(this, mockHandler, requestSettings, origSettings); - }, - abort: function() { - clearTimeout(this.responseTimer); - }, - setRequestHeader: function(header, value) { - mockHandler.headers[header] = value; - }, - getResponseHeader: function(header) { - // 'Last-modified', 'Etag', 'content-type' are all checked by jQuery - if ( mockHandler.headers && mockHandler.headers[header] ) { - // Return arbitrary headers - return mockHandler.headers[header]; - } else if ( header.toLowerCase() == 'last-modified' ) { - return mockHandler.lastModified || (new Date()).toString(); - } else if ( header.toLowerCase() == 'etag' ) { - return mockHandler.etag || ''; - } else if ( header.toLowerCase() == 'content-type' ) { - return mockHandler.contentType || 'text/plain'; - } - }, - getAllResponseHeaders: function() { - var headers = ''; - $.each(mockHandler.headers, function(k, v) { - headers += k + ': ' + v + "\n"; - }); - return headers; - } - }; - } - - // Process a JSONP mock request. - function processJsonpMock( requestSettings, mockHandler, origSettings ) { - // Handle JSONP Parameter Callbacks, we need to replicate some of the jQuery core here - // because there isn't an easy hook for the cross domain script tag of jsonp - - processJsonpUrl( requestSettings ); - - requestSettings.dataType = "json"; - if(requestSettings.data && CALLBACK_REGEX.test(requestSettings.data) || CALLBACK_REGEX.test(requestSettings.url)) { - createJsonpCallback(requestSettings, mockHandler); - - // We need to make sure - // that a JSONP style response is executed properly - - var rurl = /^(\w+:)?\/\/([^\/?#]+)/, - parts = rurl.exec( requestSettings.url ), - remote = parts && (parts[1] && parts[1] !== location.protocol || parts[2] !== location.host); - - requestSettings.dataType = "script"; - if(requestSettings.type.toUpperCase() === "GET" && remote ) { - var newMockReturn = processJsonpRequest( requestSettings, mockHandler, origSettings ); - - // Check if we are supposed to return a Deferred back to the mock call, or just - // signal success - if(newMockReturn) { - return newMockReturn; - } else { - return true; - } - } - } - return null; - } - - // Append the required callback parameter to the end of the request URL, for a JSONP request - function processJsonpUrl( requestSettings ) { - if ( requestSettings.type.toUpperCase() === "GET" ) { - if ( !CALLBACK_REGEX.test( requestSettings.url ) ) { - requestSettings.url += (/\?/.test( requestSettings.url ) ? "&" : "?") + - (requestSettings.jsonp || "callback") + "=?"; - } - } else if ( !requestSettings.data || !CALLBACK_REGEX.test(requestSettings.data) ) { - requestSettings.data = (requestSettings.data ? requestSettings.data + "&" : "") + (requestSettings.jsonp || "callback") + "=?"; - } - } - - // Process a JSONP request by evaluating the mocked response text - function processJsonpRequest( requestSettings, mockHandler, origSettings ) { - // Synthesize the mock request for adding a script tag - var callbackContext = origSettings && origSettings.context || requestSettings, - newMock = null; - - - // If the response handler on the moock is a function, call it - if ( mockHandler.response && $.isFunction(mockHandler.response) ) { - mockHandler.response(origSettings); - } else { - - // Evaluate the responseText javascript in a global context - if( typeof mockHandler.responseText === 'object' ) { - $.globalEval( '(' + JSON.stringify( mockHandler.responseText ) + ')'); - } else { - $.globalEval( '(' + mockHandler.responseText + ')'); - } - } - - // Successful response - jsonpSuccess( requestSettings, mockHandler ); - jsonpComplete( requestSettings, mockHandler ); - - // If we are running under jQuery 1.5+, return a deferred object - if($.Deferred){ - newMock = new $.Deferred(); - if(typeof mockHandler.responseText == "object"){ - newMock.resolveWith( callbackContext, [mockHandler.responseText] ); - } - else{ - newMock.resolveWith( callbackContext, [$.parseJSON( mockHandler.responseText )] ); - } - } - return newMock; - } - - - // Create the required JSONP callback function for the request - function createJsonpCallback( requestSettings, mockHandler ) { - jsonp = requestSettings.jsonpCallback || ("jsonp" + jsc++); - - // Replace the =? sequence both in the query string and the data - if ( requestSettings.data ) { - requestSettings.data = (requestSettings.data + "").replace(CALLBACK_REGEX, "=" + jsonp + "$1"); - } - - requestSettings.url = requestSettings.url.replace(CALLBACK_REGEX, "=" + jsonp + "$1"); - - - // Handle JSONP-style loading - window[ jsonp ] = window[ jsonp ] || function( tmp ) { - data = tmp; - jsonpSuccess( requestSettings, mockHandler ); - jsonpComplete( requestSettings, mockHandler ); - // Garbage collect - window[ jsonp ] = undefined; - - try { - delete window[ jsonp ]; - } catch(e) {} - - if ( head ) { - head.removeChild( script ); - } - }; - } - - // The JSONP request was successful - function jsonpSuccess(requestSettings, mockHandler) { - // If a local callback was specified, fire it and pass it the data - if ( requestSettings.success ) { - requestSettings.success.call( callbackContext, ( mockHandler.response ? mockHandler.response.toString() : mockHandler.responseText || ''), status, {} ); - } - - // Fire the global callback - if ( requestSettings.global ) { - trigger(requestSettings, "ajaxSuccess", [{}, requestSettings] ); - } - } - - // The JSONP request was completed - function jsonpComplete(requestSettings, mockHandler) { - // Process result - if ( requestSettings.complete ) { - requestSettings.complete.call( callbackContext, {} , status ); - } - - // The request was completed - if ( requestSettings.global ) { - trigger( "ajaxComplete", [{}, requestSettings] ); - } - - // Handle the global AJAX counter - if ( requestSettings.global && ! --$.active ) { - $.event.trigger( "ajaxStop" ); - } - } - - - // The core $.ajax replacement. - function handleAjax( url, origSettings ) { - var mockRequest, requestSettings, mockHandler; - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - origSettings = url; - url = undefined; - } else { - // work around to support 1.5 signature - origSettings.url = url; - } - - // Extend the original settings for the request - requestSettings = $.extend(true, {}, $.ajaxSettings, origSettings); - - // Iterate over our mock handlers (in registration order) until we find - // one that is willing to intercept the request - for(var k = 0; k < mockHandlers.length; k++) { - if ( !mockHandlers[k] ) { - continue; - } - - mockHandler = getMockForRequest( mockHandlers[k], requestSettings ); - if(!mockHandler) { - // No valid mock found for this request - continue; - } - - // Handle console logging - logMock( mockHandler, requestSettings ); - - - if ( requestSettings.dataType === "jsonp" ) { - if ((mockRequest = processJsonpMock( requestSettings, mockHandler, origSettings ))) { - // This mock will handle the JSONP request - return mockRequest; - } - } - - - // Removed to fix #54 - keep the mocking data object intact - //mockHandler.data = requestSettings.data; - - mockHandler.cache = requestSettings.cache; - mockHandler.timeout = requestSettings.timeout; - mockHandler.global = requestSettings.global; - - (function(mockHandler, requestSettings, origSettings, origHandler) { - mockRequest = _ajax.call($, $.extend(true, {}, origSettings, { - // Mock the XHR object - xhr: function() { return xhr( mockHandler, requestSettings, origSettings, origHandler ) } - })); - })(mockHandler, requestSettings, origSettings, mockHandlers[k]); - - return mockRequest; - } - - // We don't have a mock request, trigger a normal request - return _ajax.apply($, [origSettings]); - } - - - // Public - - $.extend({ - ajax: handleAjax - }); - - $.mockjaxSettings = { - //url: null, - //type: 'GET', - log: function( msg ) { - if ( window[ 'console' ] && window.console.log ) { - window.console.log.apply( console, arguments ); - } - }, - status: 200, - statusText: "OK", - responseTime: 500, - isTimeout: false, - contentType: 'text/plain', - response: '', - responseText: '', - responseXML: '', - proxy: '', - proxyType: 'GET', - - lastModified: null, - etag: '', - headers: { - etag: 'IJF@H#@923uf8023hFO@I#H#', - 'content-type' : 'text/plain' - } - }; - - $.mockjax = function(settings) { - var i = mockHandlers.length; - mockHandlers[i] = settings; - return i; - }; - $.mockjaxClear = function(i) { - if ( arguments.length == 1 ) { - mockHandlers[i] = null; - } else { - mockHandlers = []; - } - }; - $.mockjax.handler = function(i) { - if ( arguments.length == 1 ) { - return mockHandlers[i]; - } - }; -})(jQuery); diff --git a/assets/scripts/spec/vendor/qunit.js b/assets/scripts/spec/vendor/qunit.js deleted file mode 100644 index e0eddc24..00000000 --- a/assets/scripts/spec/vendor/qunit.js +++ /dev/null @@ -1,2212 +0,0 @@ -/** - * QUnit v1.12.0 - A JavaScript Unit Testing Framework - * - * http://qunitjs.com - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * https://jquery.org/license/ - */ - -(function( window ) { - -var QUnit, - assert, - config, - onErrorFnPrev, - testId = 0, - fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - // Keep a local reference to Date (GH-283) - Date = window.Date, - setTimeout = window.setTimeout, - defined = { - setTimeout: typeof window.setTimeout !== "undefined", - sessionStorage: (function() { - var x = "qunit-test-string"; - try { - sessionStorage.setItem( x, x ); - sessionStorage.removeItem( x ); - return true; - } catch( e ) { - return false; - } - }()) - }, - /** - * Provides a normalized error string, correcting an issue - * with IE 7 (and prior) where Error.prototype.toString is - * not properly implemented - * - * Based on http://es5.github.com/#x15.11.4.4 - * - * @param {String|Error} error - * @return {String} error message - */ - errorString = function( error ) { - var name, message, - errorString = error.toString(); - if ( errorString.substring( 0, 7 ) === "[object" ) { - name = error.name ? error.name.toString() : "Error"; - message = error.message ? error.message.toString() : ""; - if ( name && message ) { - return name + ": " + message; - } else if ( name ) { - return name; - } else if ( message ) { - return message; - } else { - return "Error"; - } - } else { - return errorString; - } - }, - /** - * Makes a clone of an object using only Array or Object as base, - * and copies over the own enumerable properties. - * - * @param {Object} obj - * @return {Object} New object with only the own properties (recursively). - */ - objectValues = function( obj ) { - // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392. - /*jshint newcap: false */ - var key, val, - vals = QUnit.is( "array", obj ) ? [] : {}; - for ( key in obj ) { - if ( hasOwn.call( obj, key ) ) { - val = obj[key]; - vals[key] = val === Object(val) ? objectValues(val) : val; - } - } - return vals; - }; - -function Test( settings ) { - extend( this, settings ); - this.assertions = []; - this.testNumber = ++Test.count; -} - -Test.count = 0; - -Test.prototype = { - init: function() { - var a, b, li, - tests = id( "qunit-tests" ); - - if ( tests ) { - b = document.createElement( "strong" ); - b.innerHTML = this.nameHtml; - - // `a` initialized at top of scope - a = document.createElement( "a" ); - a.innerHTML = "Rerun"; - a.href = QUnit.url({ testNumber: this.testNumber }); - - li = document.createElement( "li" ); - li.appendChild( b ); - li.appendChild( a ); - li.className = "running"; - li.id = this.id = "qunit-test-output" + testId++; - - tests.appendChild( li ); - } - }, - setup: function() { - if ( - // Emit moduleStart when we're switching from one module to another - this.module !== config.previousModule || - // They could be equal (both undefined) but if the previousModule property doesn't - // yet exist it means this is the first test in a suite that isn't wrapped in a - // module, in which case we'll just emit a moduleStart event for 'undefined'. - // Without this, reporters can get testStart before moduleStart which is a problem. - !hasOwn.call( config, "previousModule" ) - ) { - if ( hasOwn.call( config, "previousModule" ) ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.previousModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - config.previousModule = this.module; - config.moduleStats = { all: 0, bad: 0 }; - runLoggingCallbacks( "moduleStart", QUnit, { - name: this.module - }); - } - - config.current = this; - - this.testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, this.moduleTestEnvironment ); - - this.started = +new Date(); - runLoggingCallbacks( "testStart", QUnit, { - name: this.testName, - module: this.module - }); - - /*jshint camelcase:false */ - - - /** - * Expose the current test environment. - * - * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead. - */ - QUnit.current_testEnvironment = this.testEnvironment; - - /*jshint camelcase:true */ - - if ( !config.pollution ) { - saveGlobal(); - } - if ( config.notrycatch ) { - this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); - return; - } - try { - this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert ); - } catch( e ) { - QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); - } - }, - run: function() { - config.current = this; - - var running = id( "qunit-testresult" ); - - if ( running ) { - running.innerHTML = "Running:
" + this.nameHtml; - } - - if ( this.async ) { - QUnit.stop(); - } - - this.callbackStarted = +new Date(); - - if ( config.notrycatch ) { - this.callback.call( this.testEnvironment, QUnit.assert ); - this.callbackRuntime = +new Date() - this.callbackStarted; - return; - } - - try { - this.callback.call( this.testEnvironment, QUnit.assert ); - this.callbackRuntime = +new Date() - this.callbackStarted; - } catch( e ) { - this.callbackRuntime = +new Date() - this.callbackStarted; - - QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); - // else next test will carry the responsibility - saveGlobal(); - - // Restart the tests if they're blocking - if ( config.blocking ) { - QUnit.start(); - } - } - }, - teardown: function() { - config.current = this; - if ( config.notrycatch ) { - if ( typeof this.callbackRuntime === "undefined" ) { - this.callbackRuntime = +new Date() - this.callbackStarted; - } - this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); - return; - } else { - try { - this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert ); - } catch( e ) { - QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) ); - } - } - checkPollution(); - }, - finish: function() { - config.current = this; - if ( config.requireExpects && this.expected === null ) { - QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); - } else if ( this.expected !== null && this.expected !== this.assertions.length ) { - QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); - } else if ( this.expected === null && !this.assertions.length ) { - QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); - } - - var i, assertion, a, b, time, li, ol, - test = this, - good = 0, - bad = 0, - tests = id( "qunit-tests" ); - - this.runtime = +new Date() - this.started; - config.stats.all += this.assertions.length; - config.moduleStats.all += this.assertions.length; - - if ( tests ) { - ol = document.createElement( "ol" ); - ol.className = "qunit-assert-list"; - - for ( i = 0; i < this.assertions.length; i++ ) { - assertion = this.assertions[i]; - - li = document.createElement( "li" ); - li.className = assertion.result ? "pass" : "fail"; - li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); - ol.appendChild( li ); - - if ( assertion.result ) { - good++; - } else { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - - // store result when possible - if ( QUnit.config.reorder && defined.sessionStorage ) { - if ( bad ) { - sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); - } else { - sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); - } - } - - if ( bad === 0 ) { - addClass( ol, "qunit-collapsed" ); - } - - // `b` initialized at top of scope - b = document.createElement( "strong" ); - b.innerHTML = this.nameHtml + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; - - addEvent(b, "click", function() { - var next = b.parentNode.lastChild, - collapsed = hasClass( next, "qunit-collapsed" ); - ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" ); - }); - - addEvent(b, "dblclick", function( e ) { - var target = e && e.target ? e.target : window.event.srcElement; - if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) { - target = target.parentNode; - } - if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location = QUnit.url({ testNumber: test.testNumber }); - } - }); - - // `time` initialized at top of scope - time = document.createElement( "span" ); - time.className = "runtime"; - time.innerHTML = this.runtime + " ms"; - - // `li` initialized at top of scope - li = id( this.id ); - li.className = bad ? "fail" : "pass"; - li.removeChild( li.firstChild ); - a = li.firstChild; - li.appendChild( b ); - li.appendChild( a ); - li.appendChild( time ); - li.appendChild( ol ); - - } else { - for ( i = 0; i < this.assertions.length; i++ ) { - if ( !this.assertions[i].result ) { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - } - - runLoggingCallbacks( "testDone", QUnit, { - name: this.testName, - module: this.module, - failed: bad, - passed: this.assertions.length - bad, - total: this.assertions.length, - duration: this.runtime - }); - - QUnit.reset(); - - config.current = undefined; - }, - - queue: function() { - var bad, - test = this; - - synchronize(function() { - test.init(); - }); - function run() { - // each of these can by async - synchronize(function() { - test.setup(); - }); - synchronize(function() { - test.run(); - }); - synchronize(function() { - test.teardown(); - }); - synchronize(function() { - test.finish(); - }); - } - - // `bad` initialized at top of scope - // defer when previous test run passed, if storage is available - bad = QUnit.config.reorder && defined.sessionStorage && - +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); - - if ( bad ) { - run(); - } else { - synchronize( run, true ); - } - } -}; - -// Root QUnit object. -// `QUnit` initialized at top of scope -QUnit = { - - // call on start of module test to prepend name to all tests - module: function( name, testEnvironment ) { - config.currentModule = name; - config.currentModuleTestEnvironment = testEnvironment; - config.modules[name] = true; - }, - - asyncTest: function( testName, expected, callback ) { - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - QUnit.test( testName, expected, callback, true ); - }, - - test: function( testName, expected, callback, async ) { - var test, - nameHtml = "" + escapeText( testName ) + ""; - - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - if ( config.currentModule ) { - nameHtml = "" + escapeText( config.currentModule ) + ": " + nameHtml; - } - - test = new Test({ - nameHtml: nameHtml, - testName: testName, - expected: expected, - async: async, - callback: callback, - module: config.currentModule, - moduleTestEnvironment: config.currentModuleTestEnvironment, - stack: sourceFromStacktrace( 2 ) - }); - - if ( !validTest( test ) ) { - return; - } - - test.queue(); - }, - - // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through. - expect: function( asserts ) { - if (arguments.length === 1) { - config.current.expected = asserts; - } else { - return config.current.expected; - } - }, - - start: function( count ) { - // QUnit hasn't been initialized yet. - // Note: RequireJS (et al) may delay onLoad - if ( config.semaphore === undefined ) { - QUnit.begin(function() { - // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first - setTimeout(function() { - QUnit.start( count ); - }); - }); - return; - } - - config.semaphore -= count || 1; - // don't start until equal number of stop-calls - if ( config.semaphore > 0 ) { - return; - } - // ignore if start is called more often then stop - if ( config.semaphore < 0 ) { - config.semaphore = 0; - QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) ); - return; - } - // A slight delay, to avoid any current callbacks - if ( defined.setTimeout ) { - setTimeout(function() { - if ( config.semaphore > 0 ) { - return; - } - if ( config.timeout ) { - clearTimeout( config.timeout ); - } - - config.blocking = false; - process( true ); - }, 13); - } else { - config.blocking = false; - process( true ); - } - }, - - stop: function( count ) { - config.semaphore += count || 1; - config.blocking = true; - - if ( config.testTimeout && defined.setTimeout ) { - clearTimeout( config.timeout ); - config.timeout = setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - config.semaphore = 1; - QUnit.start(); - }, config.testTimeout ); - } - } -}; - -// `assert` initialized at top of scope -// Assert helpers -// All of these must either call QUnit.push() or manually do: -// - runLoggingCallbacks( "log", .. ); -// - config.current.assertions.push({ .. }); -// We attach it to the QUnit object *after* we expose the public API, -// otherwise `assert` will become a global variable in browsers (#341). -assert = { - /** - * Asserts rough true-ish result. - * @name ok - * @function - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ - ok: function( result, msg ) { - if ( !config.current ) { - throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); - } - result = !!result; - msg = msg || (result ? "okay" : "failed" ); - - var source, - details = { - module: config.current.module, - name: config.current.testName, - result: result, - message: msg - }; - - msg = "" + escapeText( msg ) + ""; - - if ( !result ) { - source = sourceFromStacktrace( 2 ); - if ( source ) { - details.source = source; - msg += "
Source:
" + escapeText( source ) + "
"; - } - } - runLoggingCallbacks( "log", QUnit, details ); - config.current.assertions.push({ - result: result, - message: msg - }); - }, - - /** - * Assert that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * @name equal - * @function - * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); - */ - equal: function( actual, expected, message ) { - /*jshint eqeqeq:false */ - QUnit.push( expected == actual, actual, expected, message ); - }, - - /** - * @name notEqual - * @function - */ - notEqual: function( actual, expected, message ) { - /*jshint eqeqeq:false */ - QUnit.push( expected != actual, actual, expected, message ); - }, - - /** - * @name propEqual - * @function - */ - propEqual: function( actual, expected, message ) { - actual = objectValues(actual); - expected = objectValues(expected); - QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name notPropEqual - * @function - */ - notPropEqual: function( actual, expected, message ) { - actual = objectValues(actual); - expected = objectValues(expected); - QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name deepEqual - * @function - */ - deepEqual: function( actual, expected, message ) { - QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name notDeepEqual - * @function - */ - notDeepEqual: function( actual, expected, message ) { - QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name strictEqual - * @function - */ - strictEqual: function( actual, expected, message ) { - QUnit.push( expected === actual, actual, expected, message ); - }, - - /** - * @name notStrictEqual - * @function - */ - notStrictEqual: function( actual, expected, message ) { - QUnit.push( expected !== actual, actual, expected, message ); - }, - - "throws": function( block, expected, message ) { - var actual, - expectedOutput = expected, - ok = false; - - // 'expected' is optional - if ( typeof expected === "string" ) { - message = expected; - expected = null; - } - - config.current.ignoreGlobalErrors = true; - try { - block.call( config.current.testEnvironment ); - } catch (e) { - actual = e; - } - config.current.ignoreGlobalErrors = false; - - if ( actual ) { - // we don't want to validate thrown error - if ( !expected ) { - ok = true; - expectedOutput = null; - // expected is a regexp - } else if ( QUnit.objectType( expected ) === "regexp" ) { - ok = expected.test( errorString( actual ) ); - // expected is a constructor - } else if ( actual instanceof expected ) { - ok = true; - // expected is a validation function which returns true is validation passed - } else if ( expected.call( {}, actual ) === true ) { - expectedOutput = null; - ok = true; - } - - QUnit.push( ok, actual, expectedOutput, message ); - } else { - QUnit.pushFailure( message, null, "No exception was thrown." ); - } - } -}; - -/** - * @deprecated since 1.8.0 - * Kept assertion helpers in root for backwards compatibility. - */ -extend( QUnit, assert ); - -/** - * @deprecated since 1.9.0 - * Kept root "raises()" for backwards compatibility. - * (Note that we don't introduce assert.raises). - */ -QUnit.raises = assert[ "throws" ]; - -/** - * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 - * Kept to avoid TypeErrors for undefined methods. - */ -QUnit.equals = function() { - QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); -}; -QUnit.same = function() { - QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); -}; - -// We want access to the constructor's prototype -(function() { - function F() {} - F.prototype = QUnit; - QUnit = new F(); - // Make F QUnit's constructor so that we can add to the prototype later - QUnit.constructor = F; -}()); - -/** - * Config object: Maintain internal state - * Later exposed as QUnit.config - * `config` initialized at top of scope - */ -config = { - // The queue of tests to run - queue: [], - - // block until document ready - blocking: true, - - // when enabled, show only failing tests - // gets persisted through sessionStorage and can be changed in UI via checkbox - hidepassed: false, - - // by default, run previously failed tests first - // very useful in combination with "Hide passed tests" checked - reorder: true, - - // by default, modify document.title when suite is done - altertitle: true, - - // when enabled, all tests must call expect() - requireExpects: false, - - // add checkboxes that are persisted in the query-string - // when enabled, the id is set to `true` as a `QUnit.config` property - urlConfig: [ - { - id: "noglobals", - label: "Check for Globals", - tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." - }, - { - id: "notrycatch", - label: "No try-catch", - tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." - } - ], - - // Set of all modules. - modules: {}, - - // logging callback queues - begin: [], - done: [], - log: [], - testStart: [], - testDone: [], - moduleStart: [], - moduleDone: [] -}; - -// Export global variables, unless an 'exports' object exists, -// in that case we assume we're in CommonJS (dealt with on the bottom of the script) -if ( typeof exports === "undefined" ) { - extend( window, QUnit.constructor.prototype ); - - // Expose QUnit object - window.QUnit = QUnit; -} - -// Initialize more QUnit.config and QUnit.urlParams -(function() { - var i, - location = window.location || { search: "", protocol: "file:" }, - params = location.search.slice( 1 ).split( "&" ), - length = params.length, - urlParams = {}, - current; - - if ( params[ 0 ] ) { - for ( i = 0; i < length; i++ ) { - current = params[ i ].split( "=" ); - current[ 0 ] = decodeURIComponent( current[ 0 ] ); - // allow just a key to turn on a flag, e.g., test.html?noglobals - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; - urlParams[ current[ 0 ] ] = current[ 1 ]; - } - } - - QUnit.urlParams = urlParams; - - // String search anywhere in moduleName+testName - config.filter = urlParams.filter; - - // Exact match of the module name - config.module = urlParams.module; - - config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; - - // Figure out if we're running the tests from a server or not - QUnit.isLocal = location.protocol === "file:"; -}()); - -// Extend QUnit object, -// these after set here because they should not be exposed as global functions -extend( QUnit, { - assert: assert, - - config: config, - - // Initialize the configuration options - init: function() { - extend( config, { - stats: { all: 0, bad: 0 }, - moduleStats: { all: 0, bad: 0 }, - started: +new Date(), - updateRate: 1000, - blocking: false, - autostart: true, - autorun: false, - filter: "", - queue: [], - semaphore: 1 - }); - - var tests, banner, result, - qunit = id( "qunit" ); - - if ( qunit ) { - qunit.innerHTML = - "

" + escapeText( document.title ) + "

" + - "

" + - "
" + - "

" + - "
    "; - } - - tests = id( "qunit-tests" ); - banner = id( "qunit-banner" ); - result = id( "qunit-testresult" ); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = "Running...
     "; - } - }, - - // Resets the test setup. Useful for tests that modify the DOM. - /* - DEPRECATED: Use multiple tests instead of resetting inside a test. - Use testStart or testDone for custom cleanup. - This method will throw an error in 2.0, and will be removed in 2.1 - */ - reset: function() { - var fixture = id( "qunit-fixture" ); - if ( fixture ) { - fixture.innerHTML = config.fixture; - } - }, - - // Trigger an event on an element. - // @example triggerEvent( document.body, "click" ); - triggerEvent: function( elem, type, event ) { - if ( document.createEvent ) { - event = document.createEvent( "MouseEvents" ); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - - elem.dispatchEvent( event ); - } else if ( elem.fireEvent ) { - elem.fireEvent( "on" + type ); - } - }, - - // Safe object type checking - is: function( type, obj ) { - return QUnit.objectType( obj ) === type; - }, - - objectType: function( obj ) { - if ( typeof obj === "undefined" ) { - return "undefined"; - // consider: typeof null === object - } - if ( obj === null ) { - return "null"; - } - - var match = toString.call( obj ).match(/^\[object\s(.*)\]$/), - type = match && match[1] || ""; - - switch ( type ) { - case "Number": - if ( isNaN(obj) ) { - return "nan"; - } - return "number"; - case "String": - case "Boolean": - case "Array": - case "Date": - case "RegExp": - case "Function": - return type.toLowerCase(); - } - if ( typeof obj === "object" ) { - return "object"; - } - return undefined; - }, - - push: function( result, actual, expected, message ) { - if ( !config.current ) { - throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); - } - - var output, source, - details = { - module: config.current.module, - name: config.current.testName, - result: result, - message: message, - actual: actual, - expected: expected - }; - - message = escapeText( message ) || ( result ? "okay" : "failed" ); - message = "" + message + ""; - output = message; - - if ( !result ) { - expected = escapeText( QUnit.jsDump.parse(expected) ); - actual = escapeText( QUnit.jsDump.parse(actual) ); - output += ""; - - if ( actual !== expected ) { - output += ""; - output += ""; - } - - source = sourceFromStacktrace(); - - if ( source ) { - details.source = source; - output += ""; - } - - output += "
    Expected:
    " + expected + "
    Result:
    " + actual + "
    Diff:
    " + QUnit.diff( expected, actual ) + "
    Source:
    " + escapeText( source ) + "
    "; - } - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: !!result, - message: output - }); - }, - - pushFailure: function( message, source, actual ) { - if ( !config.current ) { - throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); - } - - var output, - details = { - module: config.current.module, - name: config.current.testName, - result: false, - message: message - }; - - message = escapeText( message ) || "error"; - message = "" + message + ""; - output = message; - - output += ""; - - if ( actual ) { - output += ""; - } - - if ( source ) { - details.source = source; - output += ""; - } - - output += "
    Result:
    " + escapeText( actual ) + "
    Source:
    " + escapeText( source ) + "
    "; - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: false, - message: output - }); - }, - - url: function( params ) { - params = extend( extend( {}, QUnit.urlParams ), params ); - var key, - querystring = "?"; - - for ( key in params ) { - if ( hasOwn.call( params, key ) ) { - querystring += encodeURIComponent( key ) + "=" + - encodeURIComponent( params[ key ] ) + "&"; - } - } - return window.location.protocol + "//" + window.location.host + - window.location.pathname + querystring.slice( 0, -1 ); - }, - - extend: extend, - id: id, - addEvent: addEvent, - addClass: addClass, - hasClass: hasClass, - removeClass: removeClass - // load, equiv, jsDump, diff: Attached later -}); - -/** - * @deprecated: Created for backwards compatibility with test runner that set the hook function - * into QUnit.{hook}, instead of invoking it and passing the hook function. - * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. - * Doing this allows us to tell if the following methods have been overwritten on the actual - * QUnit object. - */ -extend( QUnit.constructor.prototype, { - - // Logging callbacks; all receive a single argument with the listed properties - // run test/logs.html for any related changes - begin: registerLoggingCallback( "begin" ), - - // done: { failed, passed, total, runtime } - done: registerLoggingCallback( "done" ), - - // log: { result, actual, expected, message } - log: registerLoggingCallback( "log" ), - - // testStart: { name } - testStart: registerLoggingCallback( "testStart" ), - - // testDone: { name, failed, passed, total, duration } - testDone: registerLoggingCallback( "testDone" ), - - // moduleStart: { name } - moduleStart: registerLoggingCallback( "moduleStart" ), - - // moduleDone: { name, failed, passed, total } - moduleDone: registerLoggingCallback( "moduleDone" ) -}); - -if ( typeof document === "undefined" || document.readyState === "complete" ) { - config.autorun = true; -} - -QUnit.load = function() { - runLoggingCallbacks( "begin", QUnit, {} ); - - // Initialize the config, saving the execution queue - var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, - urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter, - numModules = 0, - moduleNames = [], - moduleFilterHtml = "", - urlConfigHtml = "", - oldconfig = extend( {}, config ); - - QUnit.init(); - extend(config, oldconfig); - - config.blocking = false; - - len = config.urlConfig.length; - - for ( i = 0; i < len; i++ ) { - val = config.urlConfig[i]; - if ( typeof val === "string" ) { - val = { - id: val, - label: val, - tooltip: "[no tooltip available]" - }; - } - config[ val.id ] = QUnit.urlParams[ val.id ]; - urlConfigHtml += ""; - } - for ( i in config.modules ) { - if ( config.modules.hasOwnProperty( i ) ) { - moduleNames.push(i); - } - } - numModules = moduleNames.length; - moduleNames.sort( function( a, b ) { - return a.localeCompare( b ); - }); - moduleFilterHtml += ""; - - // `userAgent` initialized at top of scope - userAgent = id( "qunit-userAgent" ); - if ( userAgent ) { - userAgent.innerHTML = navigator.userAgent; - } - - // `banner` initialized at top of scope - banner = id( "qunit-header" ); - if ( banner ) { - banner.innerHTML = "" + banner.innerHTML + " "; - } - - // `toolbar` initialized at top of scope - toolbar = id( "qunit-testrunner-toolbar" ); - if ( toolbar ) { - // `filter` initialized at top of scope - filter = document.createElement( "input" ); - filter.type = "checkbox"; - filter.id = "qunit-filter-pass"; - - addEvent( filter, "click", function() { - var tmp, - ol = document.getElementById( "qunit-tests" ); - - if ( filter.checked ) { - ol.className = ol.className + " hidepass"; - } else { - tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; - ol.className = tmp.replace( / hidepass /, " " ); - } - if ( defined.sessionStorage ) { - if (filter.checked) { - sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); - } else { - sessionStorage.removeItem( "qunit-filter-passed-tests" ); - } - } - }); - - if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { - filter.checked = true; - // `ol` initialized at top of scope - ol = document.getElementById( "qunit-tests" ); - ol.className = ol.className + " hidepass"; - } - toolbar.appendChild( filter ); - - // `label` initialized at top of scope - label = document.createElement( "label" ); - label.setAttribute( "for", "qunit-filter-pass" ); - label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." ); - label.innerHTML = "Hide passed tests"; - toolbar.appendChild( label ); - - urlConfigCheckboxesContainer = document.createElement("span"); - urlConfigCheckboxesContainer.innerHTML = urlConfigHtml; - urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input"); - // For oldIE support: - // * Add handlers to the individual elements instead of the container - // * Use "click" instead of "change" - // * Fallback from event.target to event.srcElement - addEvents( urlConfigCheckboxes, "click", function( event ) { - var params = {}, - target = event.target || event.srcElement; - params[ target.name ] = target.checked ? true : undefined; - window.location = QUnit.url( params ); - }); - toolbar.appendChild( urlConfigCheckboxesContainer ); - - if (numModules > 1) { - moduleFilter = document.createElement( "span" ); - moduleFilter.setAttribute( "id", "qunit-modulefilter-container" ); - moduleFilter.innerHTML = moduleFilterHtml; - addEvent( moduleFilter.lastChild, "change", function() { - var selectBox = moduleFilter.getElementsByTagName("select")[0], - selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value); - - window.location = QUnit.url({ - module: ( selectedModule === "" ) ? undefined : selectedModule, - // Remove any existing filters - filter: undefined, - testNumber: undefined - }); - }); - toolbar.appendChild(moduleFilter); - } - } - - // `main` initialized at top of scope - main = id( "qunit-fixture" ); - if ( main ) { - config.fixture = main.innerHTML; - } - - if ( config.autostart ) { - QUnit.start(); - } -}; - -addEvent( window, "load", QUnit.load ); - -// `onErrorFnPrev` initialized at top of scope -// Preserve other handlers -onErrorFnPrev = window.onerror; - -// Cover uncaught exceptions -// Returning true will suppress the default browser handler, -// returning false will let it run. -window.onerror = function ( error, filePath, linerNr ) { - var ret = false; - if ( onErrorFnPrev ) { - ret = onErrorFnPrev( error, filePath, linerNr ); - } - - // Treat return value as window.onerror itself does, - // Only do our handling if not suppressed. - if ( ret !== true ) { - if ( QUnit.config.current ) { - if ( QUnit.config.current.ignoreGlobalErrors ) { - return true; - } - QUnit.pushFailure( error, filePath + ":" + linerNr ); - } else { - QUnit.test( "global failure", extend( function() { - QUnit.pushFailure( error, filePath + ":" + linerNr ); - }, { validTest: validTest } ) ); - } - return false; - } - - return ret; -}; - -function done() { - config.autorun = true; - - // Log the last module results - if ( config.currentModule ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.currentModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - delete config.previousModule; - - var i, key, - banner = id( "qunit-banner" ), - tests = id( "qunit-tests" ), - runtime = +new Date() - config.started, - passed = config.stats.all - config.stats.bad, - html = [ - "Tests completed in ", - runtime, - " milliseconds.
    ", - "", - passed, - " assertions of ", - config.stats.all, - " passed, ", - config.stats.bad, - " failed." - ].join( "" ); - - if ( banner ) { - banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); - } - - if ( tests ) { - id( "qunit-testresult" ).innerHTML = html; - } - - if ( config.altertitle && typeof document !== "undefined" && document.title ) { - // show ✖ for good, ✔ for bad suite result in title - // use escape sequences in case file gets loaded with non-utf-8-charset - document.title = [ - ( config.stats.bad ? "\u2716" : "\u2714" ), - document.title.replace( /^[\u2714\u2716] /i, "" ) - ].join( " " ); - } - - // clear own sessionStorage items if all tests passed - if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { - // `key` & `i` initialized at top of scope - for ( i = 0; i < sessionStorage.length; i++ ) { - key = sessionStorage.key( i++ ); - if ( key.indexOf( "qunit-test-" ) === 0 ) { - sessionStorage.removeItem( key ); - } - } - } - - // scroll back to top to show results - if ( window.scrollTo ) { - window.scrollTo(0, 0); - } - - runLoggingCallbacks( "done", QUnit, { - failed: config.stats.bad, - passed: passed, - total: config.stats.all, - runtime: runtime - }); -} - -/** @return Boolean: true if this test should be ran */ -function validTest( test ) { - var include, - filter = config.filter && config.filter.toLowerCase(), - module = config.module && config.module.toLowerCase(), - fullName = (test.module + ": " + test.testName).toLowerCase(); - - // Internally-generated tests are always valid - if ( test.callback && test.callback.validTest === validTest ) { - delete test.callback.validTest; - return true; - } - - if ( config.testNumber ) { - return test.testNumber === config.testNumber; - } - - if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { - return false; - } - - if ( !filter ) { - return true; - } - - include = filter.charAt( 0 ) !== "!"; - if ( !include ) { - filter = filter.slice( 1 ); - } - - // If the filter matches, we need to honour include - if ( fullName.indexOf( filter ) !== -1 ) { - return include; - } - - // Otherwise, do the opposite - return !include; -} - -// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) -// Later Safari and IE10 are supposed to support error.stack as well -// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack -function extractStacktrace( e, offset ) { - offset = offset === undefined ? 3 : offset; - - var stack, include, i; - - if ( e.stacktrace ) { - // Opera - return e.stacktrace.split( "\n" )[ offset + 3 ]; - } else if ( e.stack ) { - // Firefox, Chrome - stack = e.stack.split( "\n" ); - if (/^error$/i.test( stack[0] ) ) { - stack.shift(); - } - if ( fileName ) { - include = []; - for ( i = offset; i < stack.length; i++ ) { - if ( stack[ i ].indexOf( fileName ) !== -1 ) { - break; - } - include.push( stack[ i ] ); - } - if ( include.length ) { - return include.join( "\n" ); - } - } - return stack[ offset ]; - } else if ( e.sourceURL ) { - // Safari, PhantomJS - // hopefully one day Safari provides actual stacktraces - // exclude useless self-reference for generated Error objects - if ( /qunit.js$/.test( e.sourceURL ) ) { - return; - } - // for actual exceptions, this is useful - return e.sourceURL + ":" + e.line; - } -} -function sourceFromStacktrace( offset ) { - try { - throw new Error(); - } catch ( e ) { - return extractStacktrace( e, offset ); - } -} - -/** - * Escape text for attribute or text content. - */ -function escapeText( s ) { - if ( !s ) { - return ""; - } - s = s + ""; - // Both single quotes and double quotes (for attributes) - return s.replace( /['"<>&]/g, function( s ) { - switch( s ) { - case "'": - return "'"; - case "\"": - return """; - case "<": - return "<"; - case ">": - return ">"; - case "&": - return "&"; - } - }); -} - -function synchronize( callback, last ) { - config.queue.push( callback ); - - if ( config.autorun && !config.blocking ) { - process( last ); - } -} - -function process( last ) { - function next() { - process( last ); - } - var start = new Date().getTime(); - config.depth = config.depth ? config.depth + 1 : 1; - - while ( config.queue.length && !config.blocking ) { - if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { - config.queue.shift()(); - } else { - setTimeout( next, 13 ); - break; - } - } - config.depth--; - if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { - done(); - } -} - -function saveGlobal() { - config.pollution = []; - - if ( config.noglobals ) { - for ( var key in window ) { - if ( hasOwn.call( window, key ) ) { - // in Opera sometimes DOM element ids show up here, ignore them - if ( /^qunit-test-output/.test( key ) ) { - continue; - } - config.pollution.push( key ); - } - } - } -} - -function checkPollution() { - var newGlobals, - deletedGlobals, - old = config.pollution; - - saveGlobal(); - - newGlobals = diff( config.pollution, old ); - if ( newGlobals.length > 0 ) { - QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); - } - - deletedGlobals = diff( old, config.pollution ); - if ( deletedGlobals.length > 0 ) { - QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); - } -} - -// returns a new Array with the elements that are in a but not in b -function diff( a, b ) { - var i, j, - result = a.slice(); - - for ( i = 0; i < result.length; i++ ) { - for ( j = 0; j < b.length; j++ ) { - if ( result[i] === b[j] ) { - result.splice( i, 1 ); - i--; - break; - } - } - } - return result; -} - -function extend( a, b ) { - for ( var prop in b ) { - if ( hasOwn.call( b, prop ) ) { - // Avoid "Member not found" error in IE8 caused by messing with window.constructor - if ( !( prop === "constructor" && a === window ) ) { - if ( b[ prop ] === undefined ) { - delete a[ prop ]; - } else { - a[ prop ] = b[ prop ]; - } - } - } - } - - return a; -} - -/** - * @param {HTMLElement} elem - * @param {string} type - * @param {Function} fn - */ -function addEvent( elem, type, fn ) { - // Standards-based browsers - if ( elem.addEventListener ) { - elem.addEventListener( type, fn, false ); - // IE - } else { - elem.attachEvent( "on" + type, fn ); - } -} - -/** - * @param {Array|NodeList} elems - * @param {string} type - * @param {Function} fn - */ -function addEvents( elems, type, fn ) { - var i = elems.length; - while ( i-- ) { - addEvent( elems[i], type, fn ); - } -} - -function hasClass( elem, name ) { - return (" " + elem.className + " ").indexOf(" " + name + " ") > -1; -} - -function addClass( elem, name ) { - if ( !hasClass( elem, name ) ) { - elem.className += (elem.className ? " " : "") + name; - } -} - -function removeClass( elem, name ) { - var set = " " + elem.className + " "; - // Class name may appear multiple times - while ( set.indexOf(" " + name + " ") > -1 ) { - set = set.replace(" " + name + " " , " "); - } - // If possible, trim it for prettiness, but not necessarily - elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, ""); -} - -function id( name ) { - return !!( typeof document !== "undefined" && document && document.getElementById ) && - document.getElementById( name ); -} - -function registerLoggingCallback( key ) { - return function( callback ) { - config[key].push( callback ); - }; -} - -// Supports deprecated method of completely overwriting logging callbacks -function runLoggingCallbacks( key, scope, args ) { - var i, callbacks; - if ( QUnit.hasOwnProperty( key ) ) { - QUnit[ key ].call(scope, args ); - } else { - callbacks = config[ key ]; - for ( i = 0; i < callbacks.length; i++ ) { - callbacks[ i ].call( scope, args ); - } - } -} - -// Test for equality any JavaScript type. -// Author: Philippe Rathé -QUnit.equiv = (function() { - - // Call the o related callback with the given arguments. - function bindCallbacks( o, callbacks, args ) { - var prop = QUnit.objectType( o ); - if ( prop ) { - if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { - return callbacks[ prop ].apply( callbacks, args ); - } else { - return callbacks[ prop ]; // or undefined - } - } - } - - // the real equiv function - var innerEquiv, - // stack to decide between skip/abort functions - callers = [], - // stack to avoiding loops from circular referencing - parents = [], - parentsB = [], - - getProto = Object.getPrototypeOf || function ( obj ) { - /*jshint camelcase:false */ - return obj.__proto__; - }, - callbacks = (function () { - - // for string, boolean, number and null - function useStrictEquality( b, a ) { - /*jshint eqeqeq:false */ - if ( b instanceof a.constructor || a instanceof b.constructor ) { - // to catch short annotation VS 'new' annotation of a - // declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function( b ) { - return isNaN( b ); - }, - - "date": function( b, a ) { - return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function( b, a ) { - return QUnit.objectType( b ) === "regexp" && - // the regex itself - a.source === b.source && - // and its modifiers - a.global === b.global && - // (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline && - a.sticky === b.sticky; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function() { - var caller = callers[callers.length - 1]; - return caller !== Object && typeof caller !== "undefined"; - }, - - "array": function( b, a ) { - var i, j, len, loop, aCircular, bCircular; - - // b could be an object literal here - if ( QUnit.objectType( b ) !== "array" ) { - return false; - } - - len = a.length; - if ( len !== b.length ) { - // safe and faster - return false; - } - - // track reference to avoid circular references - parents.push( a ); - parentsB.push( b ); - for ( i = 0; i < len; i++ ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - aCircular = parents[j] === a[i]; - bCircular = parentsB[j] === b[i]; - if ( aCircular || bCircular ) { - if ( a[i] === b[i] || aCircular && bCircular ) { - loop = true; - } else { - parents.pop(); - parentsB.pop(); - return false; - } - } - } - if ( !loop && !innerEquiv(a[i], b[i]) ) { - parents.pop(); - parentsB.pop(); - return false; - } - } - parents.pop(); - parentsB.pop(); - return true; - }, - - "object": function( b, a ) { - /*jshint forin:false */ - var i, j, loop, aCircular, bCircular, - // Default to true - eq = true, - aProperties = [], - bProperties = []; - - // comparing constructors is more strict than using - // instanceof - if ( a.constructor !== b.constructor ) { - // Allow objects with no prototype to be equivalent to - // objects with Object as their constructor. - if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || - ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { - return false; - } - } - - // stack constructor before traversing properties - callers.push( a.constructor ); - - // track reference to avoid circular references - parents.push( a ); - parentsB.push( b ); - - // be strict: don't ensure hasOwnProperty and go deep - for ( i in a ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - aCircular = parents[j] === a[i]; - bCircular = parentsB[j] === b[i]; - if ( aCircular || bCircular ) { - if ( a[i] === b[i] || aCircular && bCircular ) { - loop = true; - } else { - eq = false; - break; - } - } - } - aProperties.push(i); - if ( !loop && !innerEquiv(a[i], b[i]) ) { - eq = false; - break; - } - } - - parents.pop(); - parentsB.pop(); - callers.pop(); // unstack, we are done - - for ( i in b ) { - bProperties.push( i ); // collect b's properties - } - - // Ensures identical properties name - return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); - } - }; - }()); - - innerEquiv = function() { // can take multiple arguments - var args = [].slice.apply( arguments ); - if ( args.length < 2 ) { - return true; // end transition - } - - return (function( a, b ) { - if ( a === b ) { - return true; // catch the most you can - } else if ( a === null || b === null || typeof a === "undefined" || - typeof b === "undefined" || - QUnit.objectType(a) !== QUnit.objectType(b) ) { - return false; // don't lose time with error prone cases - } else { - return bindCallbacks(a, callbacks, [ b, a ]); - } - - // apply transition with (1..n) arguments - }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) ); - }; - - return innerEquiv; -}()); - -/** - * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | - * http://flesler.blogspot.com Licensed under BSD - * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 - * - * @projectDescription Advanced and extensible data dumping for Javascript. - * @version 1.0.0 - * @author Ariel Flesler - * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} - */ -QUnit.jsDump = (function() { - function quote( str ) { - return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; - } - function literal( o ) { - return o + ""; - } - function join( pre, arr, post ) { - var s = jsDump.separator(), - base = jsDump.indent(), - inner = jsDump.indent(1); - if ( arr.join ) { - arr = arr.join( "," + s + inner ); - } - if ( !arr ) { - return pre + post; - } - return [ pre, inner + arr, base + post ].join(s); - } - function array( arr, stack ) { - var i = arr.length, ret = new Array(i); - this.up(); - while ( i-- ) { - ret[i] = this.parse( arr[i] , undefined , stack); - } - this.down(); - return join( "[", ret, "]" ); - } - - var reName = /^function (\w+)/, - jsDump = { - // type is used mostly internally, you can fix a (custom)type in advance - parse: function( obj, type, stack ) { - stack = stack || [ ]; - var inStack, res, - parser = this.parsers[ type || this.typeOf(obj) ]; - - type = typeof parser; - inStack = inArray( obj, stack ); - - if ( inStack !== -1 ) { - return "recursion(" + (inStack - stack.length) + ")"; - } - if ( type === "function" ) { - stack.push( obj ); - res = parser.call( this, obj, stack ); - stack.pop(); - return res; - } - return ( type === "string" ) ? parser : this.parsers.error; - }, - typeOf: function( obj ) { - var type; - if ( obj === null ) { - type = "null"; - } else if ( typeof obj === "undefined" ) { - type = "undefined"; - } else if ( QUnit.is( "regexp", obj) ) { - type = "regexp"; - } else if ( QUnit.is( "date", obj) ) { - type = "date"; - } else if ( QUnit.is( "function", obj) ) { - type = "function"; - } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { - type = "window"; - } else if ( obj.nodeType === 9 ) { - type = "document"; - } else if ( obj.nodeType ) { - type = "node"; - } else if ( - // native arrays - toString.call( obj ) === "[object Array]" || - // NodeList objects - ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) - ) { - type = "array"; - } else if ( obj.constructor === Error.prototype.constructor ) { - type = "error"; - } else { - type = typeof obj; - } - return type; - }, - separator: function() { - return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; - }, - // extra can be a number, shortcut for increasing-calling-decreasing - indent: function( extra ) { - if ( !this.multiline ) { - return ""; - } - var chr = this.indentChar; - if ( this.HTML ) { - chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); - } - return new Array( this.depth + ( extra || 0 ) ).join(chr); - }, - up: function( a ) { - this.depth += a || 1; - }, - down: function( a ) { - this.depth -= a || 1; - }, - setParser: function( name, parser ) { - this.parsers[name] = parser; - }, - // The next 3 are exposed so you can use them - quote: quote, - literal: literal, - join: join, - // - depth: 1, - // This is the list of parsers, to modify them, use jsDump.setParser - parsers: { - window: "[Window]", - document: "[Document]", - error: function(error) { - return "Error(\"" + error.message + "\")"; - }, - unknown: "[Unknown]", - "null": "null", - "undefined": "undefined", - "function": function( fn ) { - var ret = "function", - // functions never have name in IE - name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1]; - - if ( name ) { - ret += " " + name; - } - ret += "( "; - - ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); - return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); - }, - array: array, - nodelist: array, - "arguments": array, - object: function( map, stack ) { - /*jshint forin:false */ - var ret = [ ], keys, key, val, i; - QUnit.jsDump.up(); - keys = []; - for ( key in map ) { - keys.push( key ); - } - keys.sort(); - for ( i = 0; i < keys.length; i++ ) { - key = keys[ i ]; - val = map[ key ]; - ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); - } - QUnit.jsDump.down(); - return join( "{", ret, "}" ); - }, - node: function( node ) { - var len, i, val, - open = QUnit.jsDump.HTML ? "<" : "<", - close = QUnit.jsDump.HTML ? ">" : ">", - tag = node.nodeName.toLowerCase(), - ret = open + tag, - attrs = node.attributes; - - if ( attrs ) { - for ( i = 0, len = attrs.length; i < len; i++ ) { - val = attrs[i].nodeValue; - // IE6 includes all attributes in .attributes, even ones not explicitly set. - // Those have values like undefined, null, 0, false, "" or "inherit". - if ( val && val !== "inherit" ) { - ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" ); - } - } - } - ret += close; - - // Show content of TextNode or CDATASection - if ( node.nodeType === 3 || node.nodeType === 4 ) { - ret += node.nodeValue; - } - - return ret + open + "/" + tag + close; - }, - // function calls it internally, it's the arguments part of the function - functionArgs: function( fn ) { - var args, - l = fn.length; - - if ( !l ) { - return ""; - } - - args = new Array(l); - while ( l-- ) { - // 97 is 'a' - args[l] = String.fromCharCode(97+l); - } - return " " + args.join( ", " ) + " "; - }, - // object calls it internally, the key part of an item in a map - key: quote, - // function calls it internally, it's the content of the function - functionCode: "[code]", - // node calls it internally, it's an html attribute value - attribute: quote, - string: quote, - date: quote, - regexp: literal, - number: literal, - "boolean": literal - }, - // if true, entities are escaped ( <, >, \t, space and \n ) - HTML: false, - // indentation unit - indentChar: " ", - // if true, items in a collection, are separated by a \n, else just a space. - multiline: true - }; - - return jsDump; -}()); - -// from jquery.js -function inArray( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; -} - -/* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" - * - * Released under the MIT license. - * - * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ - * - * Usage: QUnit.diff(expected, actual) - * - * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" - */ -QUnit.diff = (function() { - /*jshint eqeqeq:false, eqnull:true */ - function diff( o, n ) { - var i, - ns = {}, - os = {}; - - for ( i = 0; i < n.length; i++ ) { - if ( !hasOwn.call( ns, n[i] ) ) { - ns[ n[i] ] = { - rows: [], - o: null - }; - } - ns[ n[i] ].rows.push( i ); - } - - for ( i = 0; i < o.length; i++ ) { - if ( !hasOwn.call( os, o[i] ) ) { - os[ o[i] ] = { - rows: [], - n: null - }; - } - os[ o[i] ].rows.push( i ); - } - - for ( i in ns ) { - if ( hasOwn.call( ns, i ) ) { - if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) { - n[ ns[i].rows[0] ] = { - text: n[ ns[i].rows[0] ], - row: os[i].rows[0] - }; - o[ os[i].rows[0] ] = { - text: o[ os[i].rows[0] ], - row: ns[i].rows[0] - }; - } - } - } - - for ( i = 0; i < n.length - 1; i++ ) { - if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && - n[ i + 1 ] == o[ n[i].row + 1 ] ) { - - n[ i + 1 ] = { - text: n[ i + 1 ], - row: n[i].row + 1 - }; - o[ n[i].row + 1 ] = { - text: o[ n[i].row + 1 ], - row: i + 1 - }; - } - } - - for ( i = n.length - 1; i > 0; i-- ) { - if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && - n[ i - 1 ] == o[ n[i].row - 1 ]) { - - n[ i - 1 ] = { - text: n[ i - 1 ], - row: n[i].row - 1 - }; - o[ n[i].row - 1 ] = { - text: o[ n[i].row - 1 ], - row: i - 1 - }; - } - } - - return { - o: o, - n: n - }; - } - - return function( o, n ) { - o = o.replace( /\s+$/, "" ); - n = n.replace( /\s+$/, "" ); - - var i, pre, - str = "", - out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), - oSpace = o.match(/\s+/g), - nSpace = n.match(/\s+/g); - - if ( oSpace == null ) { - oSpace = [ " " ]; - } - else { - oSpace.push( " " ); - } - - if ( nSpace == null ) { - nSpace = [ " " ]; - } - else { - nSpace.push( " " ); - } - - if ( out.n.length === 0 ) { - for ( i = 0; i < out.o.length; i++ ) { - str += "" + out.o[i] + oSpace[i] + ""; - } - } - else { - if ( out.n[0].text == null ) { - for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { - str += "" + out.o[n] + oSpace[n] + ""; - } - } - - for ( i = 0; i < out.n.length; i++ ) { - if (out.n[i].text == null) { - str += "" + out.n[i] + nSpace[i] + ""; - } - else { - // `pre` initialized at top of scope - pre = ""; - - for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { - pre += "" + out.o[n] + oSpace[n] + ""; - } - str += " " + out.n[i].text + nSpace[i] + pre; - } - } - } - - return str; - }; -}()); - -// for CommonJS environments, export everything -if ( typeof exports !== "undefined" ) { - extend( exports, QUnit.constructor.prototype ); -} - -// get at whatever the global object is, like window in browsers -}( window )); diff --git a/assets/scripts/spec/vendor/sinon.js b/assets/scripts/spec/vendor/sinon.js deleted file mode 100644 index d50830c4..00000000 --- a/assets/scripts/spec/vendor/sinon.js +++ /dev/null @@ -1,3555 +0,0 @@ -/** - * Sinon.JS 1.3.4, 2012/04/16 - * - * @author Christian Johansen (christian@cjohansen.no) - * - * (The BSD License) - * - * Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Christian Johansen nor the names of his contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -"use strict"; -var sinon = (function () { -var buster = (function (buster, setTimeout) { - function extend(target) { - if (!target) { - return; - } - - for (var i = 1, l = arguments.length, prop; i < l; ++i) { - for (prop in arguments[i]) { - target[prop] = arguments[i][prop]; - } - } - - return target; - } - - var div = typeof document != "undefined" && document.createElement("div"); - - return extend(buster, { - bind: function (obj, methOrProp) { - var method = typeof methOrProp == "string" ? obj[methOrProp] : methOrProp; - var args = Array.prototype.slice.call(arguments, 2); - - return function () { - var allArgs = args.concat(Array.prototype.slice.call(arguments)); - return method.apply(obj, allArgs); - }; - }, - - create: (function () { - function F() {} - - return function create(object) { - F.prototype = object; - return new F(); - } - }()), - - extend: extend, - - nextTick: function (callback) { - if (typeof process != "undefined" && process.nextTick) { - return process.nextTick(callback); - } - - setTimeout(callback, 0); - }, - - functionName: function (func) { - if (!func) return ""; - if (func.displayName) return func.displayName; - if (func.name) return func.name; - - var matches = func.toString().match(/function\s+([^\(]+)/m); - return matches && matches[1] || ""; - }, - - isNode: function (obj) { - if (!div) return false; - - try { - obj.appendChild(div); - obj.removeChild(div); - } catch (e) { - return false; - } - - return true; - }, - - isElement: function (obj) { - return obj && buster.isNode(obj) && obj.nodeType === 1; - } - }); -}(buster || {}, setTimeout)); - -if (typeof module == "object" && typeof require == "function") { - module.exports = buster; - buster.eventEmitter = require("./buster-event-emitter"); - - Object.defineProperty(buster, "defineVersionGetter", { - get: function () { - return require("./define-version-getter"); - } - }); -} -if (typeof buster === "undefined") { - var buster = {}; -} - -if (typeof module === "object" && typeof require === "function") { - buster = require("buster-core"); -} - -buster.format = buster.format || {}; -buster.format.excludeConstructors = ["Object", /^.$/]; -buster.format.quoteStrings = true; - -buster.format.ascii = (function () { - - function keys(object) { - var k = Object.keys && Object.keys(object) || []; - - if (k.length == 0) { - for (var prop in object) { - if (object.hasOwnProperty(prop)) { - k.push(prop); - } - } - } - - return k.sort(); - } - - function isCircular(object, objects) { - if (typeof object != "object") { - return false; - } - - for (var i = 0, l = objects.length; i < l; ++i) { - if (objects[i] === object) { - return true; - } - } - - return false; - } - - function ascii(object, processed, indent) { - if (typeof object == "string") { - var quote = typeof this.quoteStrings != "boolean" || this.quoteStrings; - return processed || quote ? '"' + object + '"' : object; - } - - if (typeof object == "function" && !(object instanceof RegExp)) { - return ascii.func(object); - } - - processed = processed || []; - - if (isCircular(object, processed)) { - return "[Circular]"; - } - - if (Object.prototype.toString.call(object) == "[object Array]") { - return ascii.array.call(this, object); - } - - if (!object) { - return "" + object; - } - - if (buster.isElement(object)) { - return ascii.element(object); - } - - if (typeof object.toString == "function" && - object.toString !== Object.prototype.toString) { - return object.toString(); - } - - return ascii.object.call(this, object, processed, indent); - } - - ascii.func = function (func) { - return "function " + buster.functionName(func) + "() {}"; - }; - - ascii.array = function (array, processed) { - processed = processed || []; - processed.push(array); - var pieces = []; - - for (var i = 0, l = array.length; i < l; ++i) { - pieces.push(ascii.call(this, array[i], processed)); - } - - return "[" + pieces.join(", ") + "]"; - }; - - ascii.object = function (object, processed, indent) { - processed = processed || []; - processed.push(object); - indent = indent || 0; - var pieces = [], properties = keys(object), prop, str, obj; - var is = ""; - var length = 3; - - for (var i = 0, l = indent; i < l; ++i) { - is += " "; - } - - for (i = 0, l = properties.length; i < l; ++i) { - prop = properties[i]; - obj = object[prop]; - - if (isCircular(obj, processed)) { - str = "[Circular]"; - } else { - str = ascii.call(this, obj, processed, indent + 2); - } - - str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str; - length += str.length; - pieces.push(str); - } - - var cons = ascii.constructorName.call(this, object); - var prefix = cons ? "[" + cons + "] " : "" - - return (length + indent) > 80 ? - prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + is + "}" : - prefix + "{ " + pieces.join(", ") + " }"; - }; - - ascii.element = function (element) { - var tagName = element.tagName.toLowerCase(); - var attrs = element.attributes, attribute, pairs = [], attrName; - - for (var i = 0, l = attrs.length; i < l; ++i) { - attribute = attrs.item(i); - attrName = attribute.nodeName.toLowerCase().replace("html:", ""); - - if (attrName == "contenteditable" && attribute.nodeValue == "inherit") { - continue; - } - - if (!!attribute.nodeValue) { - pairs.push(attrName + "=\"" + attribute.nodeValue + "\""); - } - } - - var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); - var content = element.innerHTML; - - if (content.length > 20) { - content = content.substr(0, 20) + "[...]"; - } - - var res = formatted + pairs.join(" ") + ">" + content + ""; - - return res.replace(/ contentEditable="inherit"/, ""); - }; - - ascii.constructorName = function (object) { - var name = buster.functionName(object && object.constructor); - var excludes = this.excludeConstructors || buster.format.excludeConstructors || []; - - for (var i = 0, l = excludes.length; i < l; ++i) { - if (typeof excludes[i] == "string" && excludes[i] == name) { - return ""; - } else if (excludes[i].test && excludes[i].test(name)) { - return ""; - } - } - - return name; - }; - - return ascii; -}()); - -if (typeof module != "undefined") { - module.exports = buster.format; -} -/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/ -/*global module, require, __dirname, document*/ -/** - * Sinon core utilities. For internal use only. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -var sinon = (function (buster) { - var div = typeof document != "undefined" && document.createElement("div"); - var hasOwn = Object.prototype.hasOwnProperty; - - function isDOMNode(obj) { - var success = false; - - try { - obj.appendChild(div); - success = div.parentNode == obj; - } catch (e) { - return false; - } finally { - try { - obj.removeChild(div); - } catch (e) { - // Remove failed, not much we can do about that - } - } - - return success; - } - - function isElement(obj) { - return div && obj && obj.nodeType === 1 && isDOMNode(obj); - } - - function isFunction(obj) { - return !!(obj && obj.constructor && obj.call && obj.apply); - } - - function mirrorProperties(target, source) { - for (var prop in source) { - if (!hasOwn.call(target, prop)) { - target[prop] = source[prop]; - } - } - } - - var sinon = { - wrapMethod: function wrapMethod(object, property, method) { - if (!object) { - throw new TypeError("Should wrap property of object"); - } - - if (typeof method != "function") { - throw new TypeError("Method wrapper should be function"); - } - - var wrappedMethod = object[property]; - - if (!isFunction(wrappedMethod)) { - throw new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + - property + " as function"); - } - - if (wrappedMethod.restore && wrappedMethod.restore.sinon) { - throw new TypeError("Attempted to wrap " + property + " which is already wrapped"); - } - - if (wrappedMethod.calledBefore) { - var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; - throw new TypeError("Attempted to wrap " + property + " which is already " + verb); - } - - // IE 8 does not support hasOwnProperty on the window object. - var owned = hasOwn.call(object, property); - object[property] = method; - method.displayName = property; - - method.restore = function () { - if(owned) { - object[property] = wrappedMethod; - } else { - delete object[property]; - } - }; - - method.restore.sinon = true; - mirrorProperties(method, wrappedMethod); - - return method; - }, - - extend: function extend(target) { - for (var i = 1, l = arguments.length; i < l; i += 1) { - for (var prop in arguments[i]) { - if (arguments[i].hasOwnProperty(prop)) { - target[prop] = arguments[i][prop]; - } - - // DONT ENUM bug, only care about toString - if (arguments[i].hasOwnProperty("toString") && - arguments[i].toString != target.toString) { - target.toString = arguments[i].toString; - } - } - } - - return target; - }, - - create: function create(proto) { - var F = function () {}; - F.prototype = proto; - return new F(); - }, - - deepEqual: function deepEqual(a, b) { - if (typeof a != "object" || typeof b != "object") { - return a === b; - } - - if (isElement(a) || isElement(b)) { - return a === b; - } - - if (a === b) { - return true; - } - - var aString = Object.prototype.toString.call(a); - if (aString != Object.prototype.toString.call(b)) { - return false; - } - - if (aString == "[object Array]") { - if (a.length !== b.length) { - return false; - } - - for (var i = 0, l = a.length; i < l; i += 1) { - if (!deepEqual(a[i], b[i])) { - return false; - } - } - - return true; - } - - var prop, aLength = 0, bLength = 0; - - for (prop in a) { - aLength += 1; - - if (!deepEqual(a[prop], b[prop])) { - return false; - } - } - - for (prop in b) { - bLength += 1; - } - - if (aLength != bLength) { - return false; - } - - return true; - }, - - functionName: function functionName(func) { - var name = func.displayName || func.name; - - // Use function decomposition as a last resort to get function - // name. Does not rely on function decomposition to work - if it - // doesn't debugging will be slightly less informative - // (i.e. toString will say 'spy' rather than 'myFunc'). - if (!name) { - var matches = func.toString().match(/function ([^\s\(]+)/); - name = matches && matches[1]; - } - - return name; - }, - - functionToString: function toString() { - if (this.getCall && this.callCount) { - var thisValue, prop, i = this.callCount; - - while (i--) { - thisValue = this.getCall(i).thisValue; - - for (prop in thisValue) { - if (thisValue[prop] === this) { - return prop; - } - } - } - } - - return this.displayName || "sinon fake"; - }, - - getConfig: function (custom) { - var config = {}; - custom = custom || {}; - var defaults = sinon.defaultConfig; - - for (var prop in defaults) { - if (defaults.hasOwnProperty(prop)) { - config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; - } - } - - return config; - }, - - format: function (val) { - return "" + val; - }, - - defaultConfig: { - injectIntoThis: true, - injectInto: null, - properties: ["spy", "stub", "mock", "clock", "server", "requests"], - useFakeTimers: true, - useFakeServer: true - }, - - timesInWords: function timesInWords(count) { - return count == 1 && "once" || - count == 2 && "twice" || - count == 3 && "thrice" || - (count || 0) + " times"; - }, - - calledInOrder: function (spies) { - for (var i = 1, l = spies.length; i < l; i++) { - if (!spies[i - 1].calledBefore(spies[i])) { - return false; - } - } - - return true; - }, - - orderByFirstCall: function (spies) { - return spies.sort(function (a, b) { - // uuid, won't ever be equal - var aCall = a.getCall(0); - var bCall = b.getCall(0); - var aId = aCall && aCall.callId || -1; - var bId = bCall && bCall.callId || -1; - - return aId < bId ? -1 : 1; - }); - }, - - log: function () {}, - - logError: function (label, err) { - var msg = label + " threw exception: " - sinon.log(msg + "[" + err.name + "] " + err.message); - if (err.stack) { sinon.log(err.stack); } - - setTimeout(function () { - err.message = msg + err.message; - throw err; - }, 0); - } - }; - - var isNode = typeof module == "object" && typeof require == "function"; - - if (isNode) { - try { - buster = { format: require("buster-format") }; - } catch (e) {} - module.exports = sinon; - module.exports.spy = require("./sinon/spy"); - module.exports.stub = require("./sinon/stub"); - module.exports.mock = require("./sinon/mock"); - module.exports.collection = require("./sinon/collection"); - module.exports.assert = require("./sinon/assert"); - module.exports.sandbox = require("./sinon/sandbox"); - module.exports.test = require("./sinon/test"); - module.exports.testCase = require("./sinon/test_case"); - module.exports.assert = require("./sinon/assert"); - } - - if (buster) { - var formatter = sinon.create(buster.format); - formatter.quoteStrings = false; - sinon.format = function () { - return formatter.ascii.apply(formatter, arguments); - }; - } else if (isNode) { - try { - var util = require("util"); - sinon.format = function (value) { - return typeof value == "object" ? util.inspect(value) : value; - }; - } catch (e) { - /* Node, but no util module - would be very old, but better safe than - sorry */ - } - } - - return sinon; -}(typeof buster == "object" && buster)); - -/* @depend ../sinon.js */ -/*jslint eqeqeq: false, onevar: false, plusplus: false*/ -/*global module, require, sinon*/ -/** - * Spy functions - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function (sinon) { - var commonJSModule = typeof module == "object" && typeof require == "function"; - var spyCall; - var callId = 0; - var push = [].push; - var slice = Array.prototype.slice; - - if (!sinon && commonJSModule) { - sinon = require("../sinon"); - } - - if (!sinon) { - return; - } - - function spy(object, property) { - if (!property && typeof object == "function") { - return spy.create(object); - } - - if (!object || !property) { - return spy.create(function () {}); - } - - var method = object[property]; - return sinon.wrapMethod(object, property, spy.create(method)); - } - - sinon.extend(spy, (function () { - - function delegateToCalls(api, method, matchAny, actual, notCalled) { - api[method] = function () { - if (!this.called) { - if (notCalled) { - return notCalled.apply(this, arguments); - } - return false; - } - - var currentCall; - var matches = 0; - - for (var i = 0, l = this.callCount; i < l; i += 1) { - currentCall = this.getCall(i); - - if (currentCall[actual || method].apply(currentCall, arguments)) { - matches += 1; - - if (matchAny) { - return true; - } - } - } - - return matches === this.callCount; - }; - } - - function matchingFake(fakes, args, strict) { - if (!fakes) { - return; - } - - var alen = args.length; - - for (var i = 0, l = fakes.length; i < l; i++) { - if (fakes[i].matches(args, strict)) { - return fakes[i]; - } - } - } - - function incrementCallCount() { - this.called = true; - this.callCount += 1; - this.calledOnce = this.callCount == 1; - this.calledTwice = this.callCount == 2; - this.calledThrice = this.callCount == 3; - } - - function createCallProperties() { - this.firstCall = this.getCall(0); - this.secondCall = this.getCall(1); - this.thirdCall = this.getCall(2); - this.lastCall = this.getCall(this.callCount - 1); - } - - var uuid = 0; - - // Public API - var spyApi = { - reset: function () { - this.called = false; - this.calledOnce = false; - this.calledTwice = false; - this.calledThrice = false; - this.callCount = 0; - this.firstCall = null; - this.secondCall = null; - this.thirdCall = null; - this.lastCall = null; - this.args = []; - this.returnValues = []; - this.thisValues = []; - this.exceptions = []; - this.callIds = []; - }, - - create: function create(func) { - var name; - - if (typeof func != "function") { - func = function () {}; - } else { - name = sinon.functionName(func); - } - - function proxy() { - return proxy.invoke(func, this, slice.call(arguments)); - } - - sinon.extend(proxy, spy); - delete proxy.create; - sinon.extend(proxy, func); - - proxy.reset(); - proxy.prototype = func.prototype; - proxy.displayName = name || "spy"; - proxy.toString = sinon.functionToString; - proxy._create = sinon.spy.create; - proxy.id = "spy#" + uuid++; - - return proxy; - }, - - invoke: function invoke(func, thisValue, args) { - var matching = matchingFake(this.fakes, args); - var exception, returnValue; - - incrementCallCount.call(this); - push.call(this.thisValues, thisValue); - push.call(this.args, args); - push.call(this.callIds, callId++); - - try { - if (matching) { - returnValue = matching.invoke(func, thisValue, args); - } else { - returnValue = (this.func || func).apply(thisValue, args); - } - } catch (e) { - push.call(this.returnValues, undefined); - exception = e; - throw e; - } finally { - push.call(this.exceptions, exception); - } - - push.call(this.returnValues, returnValue); - - createCallProperties.call(this); - - return returnValue; - }, - - getCall: function getCall(i) { - if (i < 0 || i >= this.callCount) { - return null; - } - - return spyCall.create(this, this.thisValues[i], this.args[i], - this.returnValues[i], this.exceptions[i], - this.callIds[i]); - }, - - calledBefore: function calledBefore(spyFn) { - if (!this.called) { - return false; - } - - if (!spyFn.called) { - return true; - } - - return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; - }, - - calledAfter: function calledAfter(spyFn) { - if (!this.called || !spyFn.called) { - return false; - } - - return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; - }, - - withArgs: function () { - var args = slice.call(arguments); - - if (this.fakes) { - var match = matchingFake(this.fakes, args, true); - - if (match) { - return match; - } - } else { - this.fakes = []; - } - - var original = this; - var fake = this._create(); - fake.matchingAguments = args; - push.call(this.fakes, fake); - - fake.withArgs = function () { - return original.withArgs.apply(original, arguments); - }; - - for (var i = 0; i < this.args.length; i++) { - if (fake.matches(this.args[i])) { - incrementCallCount.call(fake); - push.call(fake.thisValues, this.thisValues[i]); - push.call(fake.args, this.args[i]); - push.call(fake.returnValues, this.returnValues[i]); - push.call(fake.exceptions, this.exceptions[i]); - push.call(fake.callIds, this.callIds[i]); - } - } - createCallProperties.call(fake); - - return fake; - }, - - matches: function (args, strict) { - var margs = this.matchingAguments; - - if (margs.length <= args.length && - sinon.deepEqual(margs, args.slice(0, margs.length))) { - return !strict || margs.length == args.length; - } - }, - - printf: function (format) { - var spy = this; - var args = slice.call(arguments, 1); - var formatter; - - return (format || "").replace(/%(.)/g, function (match, specifyer) { - formatter = spyApi.formatters[specifyer]; - - if (typeof formatter == "function") { - return formatter.call(null, spy, args); - } else if (!isNaN(parseInt(specifyer), 10)) { - return sinon.format(args[specifyer - 1]); - } - - return "%" + specifyer; - }); - } - }; - - delegateToCalls(spyApi, "calledOn", true); - delegateToCalls(spyApi, "alwaysCalledOn", false, "calledOn"); - delegateToCalls(spyApi, "calledWith", true); - delegateToCalls(spyApi, "alwaysCalledWith", false, "calledWith"); - delegateToCalls(spyApi, "calledWithExactly", true); - delegateToCalls(spyApi, "alwaysCalledWithExactly", false, "calledWithExactly"); - delegateToCalls(spyApi, "neverCalledWith", false, "notCalledWith", - function () { return true; }); - delegateToCalls(spyApi, "threw", true); - delegateToCalls(spyApi, "alwaysThrew", false, "threw"); - delegateToCalls(spyApi, "returned", true); - delegateToCalls(spyApi, "alwaysReturned", false, "returned"); - delegateToCalls(spyApi, "calledWithNew", true); - delegateToCalls(spyApi, "alwaysCalledWithNew", false, "calledWithNew"); - delegateToCalls(spyApi, "callArg", false, "callArgWith", function () { - throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); - }); - spyApi.callArgWith = spyApi.callArg; - delegateToCalls(spyApi, "yield", false, "yield", function () { - throw new Error(this.toString() + " cannot yield since it was not yet invoked."); - }); - // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. - spyApi.invokeCallback = spyApi.yield; - delegateToCalls(spyApi, "yieldTo", false, "yieldTo", function (property) { - throw new Error(this.toString() + " cannot yield to '" + property + - "' since it was not yet invoked."); - }); - - spyApi.formatters = { - "c": function (spy) { - return sinon.timesInWords(spy.callCount); - }, - - "n": function (spy) { - return spy.toString(); - }, - - "C": function (spy) { - var calls = []; - - for (var i = 0, l = spy.callCount; i < l; ++i) { - push.call(calls, " " + spy.getCall(i).toString()); - } - - return calls.length > 0 ? "\n" + calls.join("\n") : ""; - }, - - "t": function (spy) { - var objects = []; - - for (var i = 0, l = spy.callCount; i < l; ++i) { - push.call(objects, sinon.format(spy.thisValues[i])); - } - - return objects.join(", "); - }, - - "*": function (spy, args) { - return args.join(", "); - } - }; - - return spyApi; - }())); - - spyCall = (function () { - - function throwYieldError(proxy, text, args) { - var msg = sinon.functionName(proxy) + text; - if (args.length) { - msg += " Received [" + slice.call(args).join(", ") + "]"; - } - throw new Error(msg); - } - - return { - create: function create(spy, thisValue, args, returnValue, exception, id) { - var proxyCall = sinon.create(spyCall); - delete proxyCall.create; - proxyCall.proxy = spy; - proxyCall.thisValue = thisValue; - proxyCall.args = args; - proxyCall.returnValue = returnValue; - proxyCall.exception = exception; - proxyCall.callId = typeof id == "number" && id || callId++; - - return proxyCall; - }, - - calledOn: function calledOn(thisValue) { - return this.thisValue === thisValue; - }, - - calledWith: function calledWith() { - for (var i = 0, l = arguments.length; i < l; i += 1) { - if (!sinon.deepEqual(arguments[i], this.args[i])) { - return false; - } - } - - return true; - }, - - calledWithExactly: function calledWithExactly() { - return arguments.length == this.args.length && - this.calledWith.apply(this, arguments); - }, - - notCalledWith: function notCalledWith() { - for (var i = 0, l = arguments.length; i < l; i += 1) { - if (!sinon.deepEqual(arguments[i], this.args[i])) { - return true; - } - } - return false; - }, - - returned: function returned(value) { - return this.returnValue === value; - }, - - threw: function threw(error) { - if (typeof error == "undefined" || !this.exception) { - return !!this.exception; - } - - if (typeof error == "string") { - return this.exception.name == error; - } - - return this.exception === error; - }, - - calledWithNew: function calledWithNew(thisValue) { - return this.thisValue instanceof this.proxy; - }, - - calledBefore: function (other) { - return this.callId < other.callId; - }, - - calledAfter: function (other) { - return this.callId > other.callId; - }, - - callArg: function (pos) { - this.args[pos](); - }, - - callArgWith: function (pos) { - var args = slice.call(arguments, 1); - this.args[pos].apply(null, args); - }, - - "yield": function () { - var args = this.args; - for (var i = 0, l = args.length; i < l; ++i) { - if (typeof args[i] === "function") { - args[i].apply(null, slice.call(arguments)); - return; - } - } - throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); - }, - - yieldTo: function (prop) { - var args = this.args; - for (var i = 0, l = args.length; i < l; ++i) { - if (args[i] && typeof args[i][prop] === "function") { - args[i][prop].apply(null, slice.call(arguments, 1)); - return; - } - } - throwYieldError(this.proxy, " cannot yield to '" + prop + - "' since no callback was passed.", args); - }, - - toString: function () { - var callStr = this.proxy.toString() + "("; - var args = []; - - for (var i = 0, l = this.args.length; i < l; ++i) { - push.call(args, sinon.format(this.args[i])); - } - - callStr = callStr + args.join(", ") + ")"; - - if (typeof this.returnValue != "undefined") { - callStr += " => " + sinon.format(this.returnValue); - } - - if (this.exception) { - callStr += " !" + this.exception.name; - - if (this.exception.message) { - callStr += "(" + this.exception.message + ")"; - } - } - - return callStr; - } - }; - }()); - - spy.spyCall = spyCall; - - // This steps outside the module sandbox and will be removed - sinon.spyCall = spyCall; - - if (commonJSModule) { - module.exports = spy; - } else { - sinon.spy = spy; - } -}(typeof sinon == "object" && sinon || null)); - -/** - * @depend ../sinon.js - * @depend spy.js - */ -/*jslint eqeqeq: false, onevar: false*/ -/*global module, require, sinon*/ -/** - * Stub functions - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function (sinon) { - var commonJSModule = typeof module == "object" && typeof require == "function"; - - if (!sinon && commonJSModule) { - sinon = require("../sinon"); - } - - if (!sinon) { - return; - } - - function stub(object, property, func) { - if (!!func && typeof func != "function") { - throw new TypeError("Custom stub should be function"); - } - - var wrapper; - - if (func) { - wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; - } else { - wrapper = stub.create(); - } - - if (!object && !property) { - return sinon.stub.create(); - } - - if (!property && !!object && typeof object == "object") { - for (var prop in object) { - if (typeof object[prop] === "function") { - stub(object, prop); - } - } - - return object; - } - - return sinon.wrapMethod(object, property, wrapper); - } - - function getCallback(stub, args) { - if (stub.callArgAt < 0) { - for (var i = 0, l = args.length; i < l; ++i) { - if (!stub.callArgProp && typeof args[i] == "function") { - return args[i]; - } - - if (stub.callArgProp && args[i] && - typeof args[i][stub.callArgProp] == "function") { - return args[i][stub.callArgProp]; - } - } - - return null; - } - - return args[stub.callArgAt]; - } - - var join = Array.prototype.join; - - function getCallbackError(stub, func, args) { - if (stub.callArgAt < 0) { - var msg; - - if (stub.callArgProp) { - msg = sinon.functionName(stub) + - " expected to yield to '" + stub.callArgProp + - "', but no object with such a property was passed." - } else { - msg = sinon.functionName(stub) + - " expected to yield, but no callback was passed." - } - - if (args.length > 0) { - msg += " Received [" + join.call(args, ", ") + "]"; - } - - return msg; - } - - return "argument at index " + stub.callArgAt + " is not a function: " + func; - } - - function callCallback(stub, args) { - if (typeof stub.callArgAt == "number") { - var func = getCallback(stub, args); - - if (typeof func != "function") { - throw new TypeError(getCallbackError(stub, func, args)); - } - - func.apply(stub.callbackContext, stub.callbackArguments); - } - } - - var uuid = 0; - - sinon.extend(stub, (function () { - var slice = Array.prototype.slice; - - function throwsException(error, message) { - if (typeof error == "string") { - this.exception = new Error(message || ""); - this.exception.name = error; - } else if (!error) { - this.exception = new Error("Error"); - } else { - this.exception = error; - } - - return this; - } - - return { - create: function create() { - var functionStub = function () { - if (functionStub.exception) { - throw functionStub.exception; - } else if (typeof functionStub.returnArgAt == 'number') { - return arguments[functionStub.returnArgAt]; - } - - callCallback(functionStub, arguments); - - return functionStub.returnValue; - }; - - functionStub.id = "stub#" + uuid++; - var orig = functionStub; - functionStub = sinon.spy.create(functionStub); - functionStub.func = orig; - - sinon.extend(functionStub, stub); - functionStub._create = sinon.stub.create; - functionStub.displayName = "stub"; - functionStub.toString = sinon.functionToString; - - return functionStub; - }, - - returns: function returns(value) { - this.returnValue = value; - - return this; - }, - - returnsArg: function returnsArg(pos) { - if (typeof pos != "number") { - throw new TypeError("argument index is not number"); - } - - this.returnArgAt = pos; - - return this; - }, - - "throws": throwsException, - throwsException: throwsException, - - callsArg: function callsArg(pos) { - if (typeof pos != "number") { - throw new TypeError("argument index is not number"); - } - - this.callArgAt = pos; - this.callbackArguments = []; - - return this; - }, - - callsArgOn: function callsArgOn(pos, context) { - if (typeof pos != "number") { - throw new TypeError("argument index is not number"); - } - if (typeof context != "object") { - throw new TypeError("argument context is not an object"); - } - - this.callArgAt = pos; - this.callbackArguments = []; - this.callbackContext = context; - - return this; - }, - - callsArgWith: function callsArgWith(pos) { - if (typeof pos != "number") { - throw new TypeError("argument index is not number"); - } - - this.callArgAt = pos; - this.callbackArguments = slice.call(arguments, 1); - - return this; - }, - - callsArgOnWith: function callsArgWith(pos, context) { - if (typeof pos != "number") { - throw new TypeError("argument index is not number"); - } - if (typeof context != "object") { - throw new TypeError("argument context is not an object"); - } - - this.callArgAt = pos; - this.callbackArguments = slice.call(arguments, 2); - this.callbackContext = context; - - return this; - }, - - yields: function () { - this.callArgAt = -1; - this.callbackArguments = slice.call(arguments, 0); - - return this; - }, - - yieldsOn: function (context) { - if (typeof context != "object") { - throw new TypeError("argument context is not an object"); - } - - this.callArgAt = -1; - this.callbackArguments = slice.call(arguments, 1); - this.callbackContext = context; - - return this; - }, - - yieldsTo: function (prop) { - this.callArgAt = -1; - this.callArgProp = prop; - this.callbackArguments = slice.call(arguments, 1); - - return this; - }, - - yieldsToOn: function (prop, context) { - if (typeof context != "object") { - throw new TypeError("argument context is not an object"); - } - - this.callArgAt = -1; - this.callArgProp = prop; - this.callbackArguments = slice.call(arguments, 2); - this.callbackContext = context; - - return this; - } - }; - }())); - - if (commonJSModule) { - module.exports = stub; - } else { - sinon.stub = stub; - } -}(typeof sinon == "object" && sinon || null)); - -/** - * @depend ../sinon.js - * @depend stub.js - */ -/*jslint eqeqeq: false, onevar: false, nomen: false*/ -/*global module, require, sinon*/ -/** - * Mock functions. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function (sinon) { - var commonJSModule = typeof module == "object" && typeof require == "function"; - var push = [].push; - - if (!sinon && commonJSModule) { - sinon = require("../sinon"); - } - - if (!sinon) { - return; - } - - function mock(object) { - if (!object) { - return sinon.expectation.create("Anonymous mock"); - } - - return mock.create(object); - } - - sinon.mock = mock; - - sinon.extend(mock, (function () { - function each(collection, callback) { - if (!collection) { - return; - } - - for (var i = 0, l = collection.length; i < l; i += 1) { - callback(collection[i]); - } - } - - return { - create: function create(object) { - if (!object) { - throw new TypeError("object is null"); - } - - var mockObject = sinon.extend({}, mock); - mockObject.object = object; - delete mockObject.create; - - return mockObject; - }, - - expects: function expects(method) { - if (!method) { - throw new TypeError("method is falsy"); - } - - if (!this.expectations) { - this.expectations = {}; - this.proxies = []; - } - - if (!this.expectations[method]) { - this.expectations[method] = []; - var mockObject = this; - - sinon.wrapMethod(this.object, method, function () { - return mockObject.invokeMethod(method, this, arguments); - }); - - push.call(this.proxies, method); - } - - var expectation = sinon.expectation.create(method); - push.call(this.expectations[method], expectation); - - return expectation; - }, - - restore: function restore() { - var object = this.object; - - each(this.proxies, function (proxy) { - if (typeof object[proxy].restore == "function") { - object[proxy].restore(); - } - }); - }, - - verify: function verify() { - var expectations = this.expectations || {}; - var messages = [], met = []; - - each(this.proxies, function (proxy) { - each(expectations[proxy], function (expectation) { - if (!expectation.met()) { - push.call(messages, expectation.toString()); - } else { - push.call(met, expectation.toString()); - } - }); - }); - - this.restore(); - - if (messages.length > 0) { - sinon.expectation.fail(messages.concat(met).join("\n")); - } - - return true; - }, - - invokeMethod: function invokeMethod(method, thisValue, args) { - var expectations = this.expectations && this.expectations[method]; - var length = expectations && expectations.length || 0; - - for (var i = 0; i < length; i += 1) { - if (!expectations[i].met() && - expectations[i].allowsCall(thisValue, args)) { - return expectations[i].apply(thisValue, args); - } - } - - var messages = []; - - for (i = 0; i < length; i += 1) { - push.call(messages, " " + expectations[i].toString()); - } - - messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ - proxy: method, - args: args - })); - - sinon.expectation.fail(messages.join("\n")); - } - }; - }())); - - var times = sinon.timesInWords; - - sinon.expectation = (function () { - var slice = Array.prototype.slice; - var _invoke = sinon.spy.invoke; - - function callCountInWords(callCount) { - if (callCount == 0) { - return "never called"; - } else { - return "called " + times(callCount); - } - } - - function expectedCallCountInWords(expectation) { - var min = expectation.minCalls; - var max = expectation.maxCalls; - - if (typeof min == "number" && typeof max == "number") { - var str = times(min); - - if (min != max) { - str = "at least " + str + " and at most " + times(max); - } - - return str; - } - - if (typeof min == "number") { - return "at least " + times(min); - } - - return "at most " + times(max); - } - - function receivedMinCalls(expectation) { - var hasMinLimit = typeof expectation.minCalls == "number"; - return !hasMinLimit || expectation.callCount >= expectation.minCalls; - } - - function receivedMaxCalls(expectation) { - if (typeof expectation.maxCalls != "number") { - return false; - } - - return expectation.callCount == expectation.maxCalls; - } - - return { - minCalls: 1, - maxCalls: 1, - - create: function create(methodName) { - var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); - delete expectation.create; - expectation.method = methodName; - - return expectation; - }, - - invoke: function invoke(func, thisValue, args) { - this.verifyCallAllowed(thisValue, args); - - return _invoke.apply(this, arguments); - }, - - atLeast: function atLeast(num) { - if (typeof num != "number") { - throw new TypeError("'" + num + "' is not number"); - } - - if (!this.limitsSet) { - this.maxCalls = null; - this.limitsSet = true; - } - - this.minCalls = num; - - return this; - }, - - atMost: function atMost(num) { - if (typeof num != "number") { - throw new TypeError("'" + num + "' is not number"); - } - - if (!this.limitsSet) { - this.minCalls = null; - this.limitsSet = true; - } - - this.maxCalls = num; - - return this; - }, - - never: function never() { - return this.exactly(0); - }, - - once: function once() { - return this.exactly(1); - }, - - twice: function twice() { - return this.exactly(2); - }, - - thrice: function thrice() { - return this.exactly(3); - }, - - exactly: function exactly(num) { - if (typeof num != "number") { - throw new TypeError("'" + num + "' is not a number"); - } - - this.atLeast(num); - return this.atMost(num); - }, - - met: function met() { - return !this.failed && receivedMinCalls(this); - }, - - verifyCallAllowed: function verifyCallAllowed(thisValue, args) { - if (receivedMaxCalls(this)) { - this.failed = true; - sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); - } - - if ("expectedThis" in this && this.expectedThis !== thisValue) { - sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + - this.expectedThis); - } - - if (!("expectedArguments" in this)) { - return; - } - - if (!args || args.length === 0) { - sinon.expectation.fail(this.method + " received no arguments, expected " + - this.expectedArguments.join()); - } - - if (args.length < this.expectedArguments.length) { - sinon.expectation.fail(this.method + " received too few arguments (" + args.join() + - "), expected " + this.expectedArguments.join()); - } - - if (this.expectsExactArgCount && - args.length != this.expectedArguments.length) { - sinon.expectation.fail(this.method + " received too many arguments (" + args.join() + - "), expected " + this.expectedArguments.join()); - } - - for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { - if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { - sinon.expectation.fail(this.method + " received wrong arguments (" + args.join() + - "), expected " + this.expectedArguments.join()); - } - } - }, - - allowsCall: function allowsCall(thisValue, args) { - if (this.met()) { - return false; - } - - if ("expectedThis" in this && this.expectedThis !== thisValue) { - return false; - } - - if (!("expectedArguments" in this)) { - return true; - } - - args = args || []; - - if (args.length < this.expectedArguments.length) { - return false; - } - - if (this.expectsExactArgCount && - args.length != this.expectedArguments.length) { - return false; - } - - for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { - if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { - return false; - } - } - - return true; - }, - - withArgs: function withArgs() { - this.expectedArguments = slice.call(arguments); - return this; - }, - - withExactArgs: function withExactArgs() { - this.withArgs.apply(this, arguments); - this.expectsExactArgCount = true; - return this; - }, - - on: function on(thisValue) { - this.expectedThis = thisValue; - return this; - }, - - toString: function () { - var args = (this.expectedArguments || []).slice(); - - if (!this.expectsExactArgCount) { - push.call(args, "[...]"); - } - - var callStr = sinon.spyCall.toString.call({ - proxy: this.method, args: args - }); - - var message = callStr.replace(", [...", "[, ...") + " " + - expectedCallCountInWords(this); - - if (this.met()) { - return "Expectation met: " + message; - } - - return "Expected " + message + " (" + - callCountInWords(this.callCount) + ")"; - }, - - verify: function verify() { - if (!this.met()) { - sinon.expectation.fail(this.toString()); - } - - return true; - }, - - fail: function (message) { - var exception = new Error(message); - exception.name = "ExpectationError"; - - throw exception; - } - }; - }()); - - if (commonJSModule) { - module.exports = mock; - } else { - sinon.mock = mock; - } -}(typeof sinon == "object" && sinon || null)); - -/** - * @depend ../sinon.js - * @depend stub.js - * @depend mock.js - */ -/*jslint eqeqeq: false, onevar: false, forin: true*/ -/*global module, require, sinon*/ -/** - * Collections of stubs, spies and mocks. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function (sinon) { - var commonJSModule = typeof module == "object" && typeof require == "function"; - var push = [].push; - - if (!sinon && commonJSModule) { - sinon = require("../sinon"); - } - - if (!sinon) { - return; - } - - function getFakes(fakeCollection) { - if (!fakeCollection.fakes) { - fakeCollection.fakes = []; - } - - return fakeCollection.fakes; - } - - function each(fakeCollection, method) { - var fakes = getFakes(fakeCollection); - - for (var i = 0, l = fakes.length; i < l; i += 1) { - if (typeof fakes[i][method] == "function") { - fakes[i][method](); - } - } - } - - function compact(fakeCollection) { - var fakes = getFakes(fakeCollection); - var i = 0; - while (i < fakes.length) { - fakes.splice(i, 1); - } - } - - var collection = { - verify: function resolve() { - each(this, "verify"); - }, - - restore: function restore() { - each(this, "restore"); - compact(this); - }, - - verifyAndRestore: function verifyAndRestore() { - var exception; - - try { - this.verify(); - } catch (e) { - exception = e; - } - - this.restore(); - - if (exception) { - throw exception; - } - }, - - add: function add(fake) { - push.call(getFakes(this), fake); - return fake; - }, - - spy: function spy() { - return this.add(sinon.spy.apply(sinon, arguments)); - }, - - stub: function stub(object, property, value) { - if (property) { - var original = object[property]; - - if (typeof original != "function") { - if (!object.hasOwnProperty(property)) { - throw new TypeError("Cannot stub non-existent own property " + property); - } - - object[property] = value; - - return this.add({ - restore: function () { - object[property] = original; - } - }); - } - } - - return this.add(sinon.stub.apply(sinon, arguments)); - }, - - mock: function mock() { - return this.add(sinon.mock.apply(sinon, arguments)); - }, - - inject: function inject(obj) { - var col = this; - - obj.spy = function () { - return col.spy.apply(col, arguments); - }; - - obj.stub = function () { - return col.stub.apply(col, arguments); - }; - - obj.mock = function () { - return col.mock.apply(col, arguments); - }; - - return obj; - } - }; - - if (commonJSModule) { - module.exports = collection; - } else { - sinon.collection = collection; - } -}(typeof sinon == "object" && sinon || null)); - -/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ -/*global module, require, window*/ -/** - * Fake timer API - * setTimeout - * setInterval - * clearTimeout - * clearInterval - * tick - * reset - * Date - * - * Inspired by jsUnitMockTimeOut from JsUnit - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -if (typeof sinon == "undefined") { - var sinon = {}; -} - -(function (global) { - var id = 1; - - function addTimer(args, recurring) { - if (args.length === 0) { - throw new Error("Function requires at least 1 parameter"); - } - - var toId = id++; - var delay = args[1] || 0; - - if (!this.timeouts) { - this.timeouts = {}; - } - - this.timeouts[toId] = { - id: toId, - func: args[0], - callAt: this.now + delay - }; - - if (recurring === true) { - this.timeouts[toId].interval = delay; - } - - return toId; - } - - function parseTime(str) { - if (!str) { - return 0; - } - - var strings = str.split(":"); - var l = strings.length, i = l; - var ms = 0, parsed; - - if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { - throw new Error("tick only understands numbers and 'h:m:s'"); - } - - while (i--) { - parsed = parseInt(strings[i], 10); - - if (parsed >= 60) { - throw new Error("Invalid time " + str); - } - - ms += parsed * Math.pow(60, (l - i - 1)); - } - - return ms * 1000; - } - - function createObject(object) { - var newObject; - - if (Object.create) { - newObject = Object.create(object); - } else { - var F = function () {}; - F.prototype = object; - newObject = new F(); - } - - newObject.Date.clock = newObject; - return newObject; - } - - sinon.clock = { - now: 0, - - create: function create(now) { - var clock = createObject(this); - - if (typeof now == "number") { - clock.now = now; - } - - if (!!now && typeof now == "object") { - throw new TypeError("now should be milliseconds since UNIX epoch"); - } - - return clock; - }, - - setTimeout: function setTimeout(callback, timeout) { - return addTimer.call(this, arguments, false); - }, - - clearTimeout: function clearTimeout(timerId) { - if (!this.timeouts) { - this.timeouts = []; - } - - if (timerId in this.timeouts) { - delete this.timeouts[timerId]; - } - }, - - setInterval: function setInterval(callback, timeout) { - return addTimer.call(this, arguments, true); - }, - - clearInterval: function clearInterval(timerId) { - this.clearTimeout(timerId); - }, - - tick: function tick(ms) { - ms = typeof ms == "number" ? ms : parseTime(ms); - var tickFrom = this.now, tickTo = this.now + ms, previous = this.now; - var timer = this.firstTimerInRange(tickFrom, tickTo); - - var firstException; - while (timer && tickFrom <= tickTo) { - if (this.timeouts[timer.id]) { - tickFrom = this.now = timer.callAt; - try { - this.callTimer(timer); - } catch (e) { - firstException = firstException || e; - } - } - - timer = this.firstTimerInRange(previous, tickTo); - previous = tickFrom; - } - - this.now = tickTo; - - if (firstException) { - throw firstException; - } - }, - - firstTimerInRange: function (from, to) { - var timer, smallest, originalTimer; - - for (var id in this.timeouts) { - if (this.timeouts.hasOwnProperty(id)) { - if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) { - continue; - } - - if (!smallest || this.timeouts[id].callAt < smallest) { - originalTimer = this.timeouts[id]; - smallest = this.timeouts[id].callAt; - - timer = { - func: this.timeouts[id].func, - callAt: this.timeouts[id].callAt, - interval: this.timeouts[id].interval, - id: this.timeouts[id].id - }; - } - } - } - - return timer || null; - }, - - callTimer: function (timer) { - try { - if (typeof timer.func == "function") { - timer.func.call(null); - } else { - eval(timer.func); - } - } catch (e) { - var exception = e; - } - - if (!this.timeouts[timer.id]) { - if (exception) { - throw exception; - } - return; - } - - if (typeof timer.interval == "number") { - this.timeouts[timer.id].callAt += timer.interval; - } else { - delete this.timeouts[timer.id]; - } - - if (exception) { - throw exception; - } - }, - - reset: function reset() { - this.timeouts = {}; - }, - - Date: (function () { - var NativeDate = Date; - - function ClockDate(year, month, date, hour, minute, second, ms) { - // Defensive and verbose to avoid potential harm in passing - // explicit undefined when user does not pass argument - switch (arguments.length) { - case 0: - return new NativeDate(ClockDate.clock.now); - case 1: - return new NativeDate(year); - case 2: - return new NativeDate(year, month); - case 3: - return new NativeDate(year, month, date); - case 4: - return new NativeDate(year, month, date, hour); - case 5: - return new NativeDate(year, month, date, hour, minute); - case 6: - return new NativeDate(year, month, date, hour, minute, second); - default: - return new NativeDate(year, month, date, hour, minute, second, ms); - } - } - - return mirrorDateProperties(ClockDate, NativeDate); - }()) - }; - - function mirrorDateProperties(target, source) { - if (source.now) { - target.now = function now() { - return target.clock.now; - }; - } else { - delete target.now; - } - - if (source.toSource) { - target.toSource = function toSource() { - return source.toSource(); - }; - } else { - delete target.toSource; - } - - target.toString = function toString() { - return source.toString(); - }; - - target.prototype = source.prototype; - target.parse = source.parse; - target.UTC = source.UTC; - target.prototype.toUTCString = source.prototype.toUTCString; - return target; - } - - var methods = ["Date", "setTimeout", "setInterval", - "clearTimeout", "clearInterval"]; - - function restore() { - var method; - - for (var i = 0, l = this.methods.length; i < l; i++) { - method = this.methods[i]; - global[method] = this["_" + method]; - } - } - - function stubGlobal(method, clock) { - clock["_" + method] = global[method]; - - if (method == "Date") { - var date = mirrorDateProperties(clock[method], global[method]); - global[method] = date; - } else { - global[method] = function () { - return clock[method].apply(clock, arguments); - }; - - for (var prop in clock[method]) { - if (clock[method].hasOwnProperty(prop)) { - global[method][prop] = clock[method][prop]; - } - } - } - - global[method].clock = clock; - } - - sinon.useFakeTimers = function useFakeTimers(now) { - var clock = sinon.clock.create(now); - clock.restore = restore; - clock.methods = Array.prototype.slice.call(arguments, - typeof now == "number" ? 1 : 0); - - if (clock.methods.length === 0) { - clock.methods = methods; - } - - for (var i = 0, l = clock.methods.length; i < l; i++) { - stubGlobal(clock.methods[i], clock); - } - - return clock; - }; -}(typeof global != "undefined" && typeof global !== "function" ? global : this)); - -sinon.timers = { - setTimeout: setTimeout, - clearTimeout: clearTimeout, - setInterval: setInterval, - clearInterval: clearInterval, - Date: Date -}; - -if (typeof module == "object" && typeof require == "function") { - module.exports = sinon; -} - -/*jslint eqeqeq: false, onevar: false*/ -/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ -/** - * Minimal Event interface implementation - * - * Original implementation by Sven Fuchs: https://gist.github.com/995028 - * Modifications and tests by Christian Johansen. - * - * @author Sven Fuchs (svenfuchs@artweb-design.de) - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2011 Sven Fuchs, Christian Johansen - */ - -if (typeof sinon == "undefined") { - this.sinon = {}; -} - -(function () { - var push = [].push; - - sinon.Event = function Event(type, bubbles, cancelable) { - this.initEvent(type, bubbles, cancelable); - }; - - sinon.Event.prototype = { - initEvent: function(type, bubbles, cancelable) { - this.type = type; - this.bubbles = bubbles; - this.cancelable = cancelable; - }, - - stopPropagation: function () {}, - - preventDefault: function () { - this.defaultPrevented = true; - } - }; - - sinon.EventTarget = { - addEventListener: function addEventListener(event, listener, useCapture) { - this.eventListeners = this.eventListeners || {}; - this.eventListeners[event] = this.eventListeners[event] || []; - push.call(this.eventListeners[event], listener); - }, - - removeEventListener: function removeEventListener(event, listener, useCapture) { - var listeners = this.eventListeners && this.eventListeners[event] || []; - - for (var i = 0, l = listeners.length; i < l; ++i) { - if (listeners[i] == listener) { - return listeners.splice(i, 1); - } - } - }, - - dispatchEvent: function dispatchEvent(event) { - var type = event.type; - var listeners = this.eventListeners && this.eventListeners[type] || []; - - for (var i = 0; i < listeners.length; i++) { - if (typeof listeners[i] == "function") { - listeners[i].call(this, event); - } else { - listeners[i].handleEvent(event); - } - } - - return !!event.defaultPrevented; - } - }; -}()); - -/** - * @depend event.js - */ -/*jslint eqeqeq: false, onevar: false*/ -/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/ -/** - * Fake XMLHttpRequest object - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -if (typeof sinon == "undefined") { - this.sinon = {}; -} -sinon.xhr = { XMLHttpRequest: this.XMLHttpRequest }; - -// wrapper for global -(function(global) { - var xhr = sinon.xhr; - xhr.GlobalXMLHttpRequest = global.XMLHttpRequest; - xhr.GlobalActiveXObject = global.ActiveXObject; - xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined"; - xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined"; - xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX - ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; - - /*jsl:ignore*/ - var unsafeHeaders = { - "Accept-Charset": true, - "Accept-Encoding": true, - "Connection": true, - "Content-Length": true, - "Cookie": true, - "Cookie2": true, - "Content-Transfer-Encoding": true, - "Date": true, - "Expect": true, - "Host": true, - "Keep-Alive": true, - "Referer": true, - "TE": true, - "Trailer": true, - "Transfer-Encoding": true, - "Upgrade": true, - "User-Agent": true, - "Via": true - }; - /*jsl:end*/ - - function FakeXMLHttpRequest() { - this.readyState = FakeXMLHttpRequest.UNSENT; - this.requestHeaders = {}; - this.requestBody = null; - this.status = 0; - this.statusText = ""; - - if (typeof FakeXMLHttpRequest.onCreate == "function") { - FakeXMLHttpRequest.onCreate(this); - } - } - - function verifyState(xhr) { - if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { - throw new Error("INVALID_STATE_ERR"); - } - - if (xhr.sendFlag) { - throw new Error("INVALID_STATE_ERR"); - } - } - - // filtering to enable a white-list version of Sinon FakeXhr, - // where whitelisted requests are passed through to real XHR - function each(collection, callback) { - if (!collection) return; - for (var i = 0, l = collection.length; i < l; i += 1) { - callback(collection[i]); - } - } - function some(collection, callback) { - for (var index = 0; index < collection.length; index++) { - if(callback(collection[index]) === true) return true; - }; - return false; - } - // largest arity in XHR is 5 - XHR#open - var apply = function(obj,method,args) { - switch(args.length) { - case 0: return obj[method](); - case 1: return obj[method](args[0]); - case 2: return obj[method](args[0],args[1]); - case 3: return obj[method](args[0],args[1],args[2]); - case 4: return obj[method](args[0],args[1],args[2],args[3]); - case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]); - }; - }; - - FakeXMLHttpRequest.filters = []; - FakeXMLHttpRequest.addFilter = function(fn) { - this.filters.push(fn) - }; - var IE6Re = /MSIE 6/; - FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) { - var xhr = new sinon.xhr.workingXHR(); - each(["open","setRequestHeader","send","abort","getResponseHeader", - "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"], - function(method) { - fakeXhr[method] = function() { - return apply(xhr,method,arguments); - }; - }); - - var copyAttrs = function(args) { - each(args, function(attr) { - try { - fakeXhr[attr] = xhr[attr] - } catch(e) { - if(!IE6Re.test(navigator.userAgent)) throw e; - } - }); - }; - - var stateChange = function() { - fakeXhr.readyState = xhr.readyState; - if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { - copyAttrs(["status","statusText"]); - } - if(xhr.readyState >= FakeXMLHttpRequest.LOADING) { - copyAttrs(["responseText"]); - } - if(xhr.readyState === FakeXMLHttpRequest.DONE) { - copyAttrs(["responseXML"]); - } - if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr); - }; - if(xhr.addEventListener) { - for(var event in fakeXhr.eventListeners) { - if(fakeXhr.eventListeners.hasOwnProperty(event)) { - each(fakeXhr.eventListeners[event],function(handler) { - xhr.addEventListener(event, handler); - }); - } - } - xhr.addEventListener("readystatechange",stateChange); - } else { - xhr.onreadystatechange = stateChange; - } - apply(xhr,"open",xhrArgs); - }; - FakeXMLHttpRequest.useFilters = false; - - function verifyRequestSent(xhr) { - if (xhr.readyState == FakeXMLHttpRequest.DONE) { - throw new Error("Request done"); - } - } - - function verifyHeadersReceived(xhr) { - if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { - throw new Error("No headers received"); - } - } - - function verifyResponseBodyType(body) { - if (typeof body != "string") { - var error = new Error("Attempted to respond to fake XMLHttpRequest with " + - body + ", which is not a string."); - error.name = "InvalidBodyException"; - throw error; - } - } - - sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { - async: true, - - open: function open(method, url, async, username, password) { - this.method = method; - this.url = url; - this.async = typeof async == "boolean" ? async : true; - this.username = username; - this.password = password; - this.responseText = null; - this.responseXML = null; - this.requestHeaders = {}; - this.sendFlag = false; - if(sinon.FakeXMLHttpRequest.useFilters === true) { - var xhrArgs = arguments; - var defake = some(FakeXMLHttpRequest.filters,function(filter) { - return filter.apply(this,xhrArgs) - }); - if (defake) { - return sinon.FakeXMLHttpRequest.defake(this,arguments); - } - } - this.readyStateChange(FakeXMLHttpRequest.OPENED); - }, - - readyStateChange: function readyStateChange(state) { - this.readyState = state; - - if (typeof this.onreadystatechange == "function") { - try { - this.onreadystatechange(); - } catch (e) { - sinon.logError("Fake XHR onreadystatechange handler", e); - } - } - - this.dispatchEvent(new sinon.Event("readystatechange")); - }, - - setRequestHeader: function setRequestHeader(header, value) { - verifyState(this); - - if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { - throw new Error("Refused to set unsafe header \"" + header + "\""); - } - - if (this.requestHeaders[header]) { - this.requestHeaders[header] += "," + value; - } else { - this.requestHeaders[header] = value; - } - }, - - // Helps testing - setResponseHeaders: function setResponseHeaders(headers) { - this.responseHeaders = {}; - - for (var header in headers) { - if (headers.hasOwnProperty(header)) { - this.responseHeaders[header] = headers[header]; - } - } - - if (this.async) { - this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); - } - }, - - // Currently treats ALL data as a DOMString (i.e. no Document) - send: function send(data) { - verifyState(this); - - if (!/^(get|head)$/i.test(this.method)) { - if (this.requestHeaders["Content-Type"]) { - var value = this.requestHeaders["Content-Type"].split(";"); - this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8"; - } else { - this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; - } - - this.requestBody = data; - } - - this.errorFlag = false; - this.sendFlag = this.async; - this.readyStateChange(FakeXMLHttpRequest.OPENED); - - if (typeof this.onSend == "function") { - this.onSend(this); - } - }, - - abort: function abort() { - this.aborted = true; - this.responseText = null; - this.errorFlag = true; - this.requestHeaders = {}; - - if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) { - this.readyStateChange(sinon.FakeXMLHttpRequest.DONE); - this.sendFlag = false; - } - - this.readyState = sinon.FakeXMLHttpRequest.UNSENT; - }, - - getResponseHeader: function getResponseHeader(header) { - if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { - return null; - } - - if (/^Set-Cookie2?$/i.test(header)) { - return null; - } - - header = header.toLowerCase(); - - for (var h in this.responseHeaders) { - if (h.toLowerCase() == header) { - return this.responseHeaders[h]; - } - } - - return null; - }, - - getAllResponseHeaders: function getAllResponseHeaders() { - if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { - return ""; - } - - var headers = ""; - - for (var header in this.responseHeaders) { - if (this.responseHeaders.hasOwnProperty(header) && - !/^Set-Cookie2?$/i.test(header)) { - headers += header + ": " + this.responseHeaders[header] + "\r\n"; - } - } - - return headers; - }, - - setResponseBody: function setResponseBody(body) { - verifyRequestSent(this); - verifyHeadersReceived(this); - verifyResponseBodyType(body); - - var chunkSize = this.chunkSize || 10; - var index = 0; - this.responseText = ""; - - do { - if (this.async) { - this.readyStateChange(FakeXMLHttpRequest.LOADING); - } - - this.responseText += body.substring(index, index + chunkSize); - index += chunkSize; - } while (index < body.length); - - var type = this.getResponseHeader("Content-Type"); - - if (this.responseText && - (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { - try { - this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); - } catch (e) { - // Unable to parse XML - no biggie - } - } - - if (this.async) { - this.readyStateChange(FakeXMLHttpRequest.DONE); - } else { - this.readyState = FakeXMLHttpRequest.DONE; - } - }, - - respond: function respond(status, headers, body) { - this.setResponseHeaders(headers || {}); - this.status = typeof status == "number" ? status : 200; - this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; - this.setResponseBody(body || ""); - } - }); - - sinon.extend(FakeXMLHttpRequest, { - UNSENT: 0, - OPENED: 1, - HEADERS_RECEIVED: 2, - LOADING: 3, - DONE: 4 - }); - - // Borrowed from JSpec - FakeXMLHttpRequest.parseXML = function parseXML(text) { - var xmlDoc; - - if (typeof DOMParser != "undefined") { - var parser = new DOMParser(); - xmlDoc = parser.parseFromString(text, "text/xml"); - } else { - xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); - xmlDoc.async = "false"; - xmlDoc.loadXML(text); - } - - return xmlDoc; - }; - - FakeXMLHttpRequest.statusCodes = { - 100: "Continue", - 101: "Switching Protocols", - 200: "OK", - 201: "Created", - 202: "Accepted", - 203: "Non-Authoritative Information", - 204: "No Content", - 205: "Reset Content", - 206: "Partial Content", - 300: "Multiple Choice", - 301: "Moved Permanently", - 302: "Found", - 303: "See Other", - 304: "Not Modified", - 305: "Use Proxy", - 307: "Temporary Redirect", - 400: "Bad Request", - 401: "Unauthorized", - 402: "Payment Required", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 406: "Not Acceptable", - 407: "Proxy Authentication Required", - 408: "Request Timeout", - 409: "Conflict", - 410: "Gone", - 411: "Length Required", - 412: "Precondition Failed", - 413: "Request Entity Too Large", - 414: "Request-URI Too Long", - 415: "Unsupported Media Type", - 416: "Requested Range Not Satisfiable", - 417: "Expectation Failed", - 422: "Unprocessable Entity", - 500: "Internal Server Error", - 501: "Not Implemented", - 502: "Bad Gateway", - 503: "Service Unavailable", - 504: "Gateway Timeout", - 505: "HTTP Version Not Supported" - }; - - sinon.useFakeXMLHttpRequest = function () { - sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) { - if (xhr.supportsXHR) { - global.XMLHttpRequest = xhr.GlobalXMLHttpRequest; - } - - if (xhr.supportsActiveX) { - global.ActiveXObject = xhr.GlobalActiveXObject; - } - - delete sinon.FakeXMLHttpRequest.restore; - - if (keepOnCreate !== true) { - delete sinon.FakeXMLHttpRequest.onCreate; - } - }; - if (xhr.supportsXHR) { - global.XMLHttpRequest = sinon.FakeXMLHttpRequest; - } - - if (xhr.supportsActiveX) { - global.ActiveXObject = function ActiveXObject(objId) { - if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { - - return new sinon.FakeXMLHttpRequest(); - } - - return new xhr.GlobalActiveXObject(objId); - }; - } - - return sinon.FakeXMLHttpRequest; - }; - - sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; -})(this); - -if (typeof module == "object" && typeof require == "function") { - module.exports = sinon; -} - -/** - * @depend fake_xml_http_request.js - */ -/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/ -/*global module, require, window*/ -/** - * The Sinon "server" mimics a web server that receives requests from - * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, - * both synchronously and asynchronously. To respond synchronuously, canned - * answers have to be provided upfront. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -if (typeof sinon == "undefined") { - var sinon = {}; -} - -sinon.fakeServer = (function () { - var push = [].push; - function F() {} - - function create(proto) { - F.prototype = proto; - return new F(); - } - - function responseArray(handler) { - var response = handler; - - if (Object.prototype.toString.call(handler) != "[object Array]") { - response = [200, {}, handler]; - } - - if (typeof response[2] != "string") { - throw new TypeError("Fake server response body should be string, but was " + - typeof response[2]); - } - - return response; - } - - var wloc = window.location; - var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); - - function matchOne(response, reqMethod, reqUrl) { - var rmeth = response.method; - var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); - var url = response.url; - var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); - - return matchMethod && matchUrl; - } - - function match(response, request) { - var requestMethod = this.getHTTPMethod(request); - var requestUrl = request.url; - - if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { - requestUrl = requestUrl.replace(rCurrLoc, ""); - } - - if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { - if (typeof response.response == "function") { - var ru = response.url; - var args = [request].concat(!ru ? [] : requestUrl.match(ru).slice(1)); - return response.response.apply(response, args); - } - - return true; - } - - return false; - } - - return { - create: function () { - var server = create(this); - this.xhr = sinon.useFakeXMLHttpRequest(); - server.requests = []; - - this.xhr.onCreate = function (xhrObj) { - server.addRequest(xhrObj); - }; - - return server; - }, - - addRequest: function addRequest(xhrObj) { - var server = this; - push.call(this.requests, xhrObj); - - xhrObj.onSend = function () { - server.handleRequest(this); - }; - - if (this.autoRespond && !this.responding) { - setTimeout(function () { - server.responding = false; - server.respond(); - }, this.autoRespondAfter || 10); - - this.responding = true; - } - }, - - getHTTPMethod: function getHTTPMethod(request) { - if (this.fakeHTTPMethods && /post/i.test(request.method)) { - var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); - return !!matches ? matches[1] : request.method; - } - - return request.method; - }, - - handleRequest: function handleRequest(xhr) { - if (xhr.async) { - if (!this.queue) { - this.queue = []; - } - - push.call(this.queue, xhr); - } else { - this.processRequest(xhr); - } - }, - - respondWith: function respondWith(method, url, body) { - if (arguments.length == 1 && typeof method != "function") { - this.response = responseArray(method); - return; - } - - if (!this.responses) { this.responses = []; } - - if (arguments.length == 1) { - body = method; - url = method = null; - } - - if (arguments.length == 2) { - body = url; - url = method; - method = null; - } - - push.call(this.responses, { - method: method, - url: url, - response: typeof body == "function" ? body : responseArray(body) - }); - }, - - respond: function respond() { - if (arguments.length > 0) this.respondWith.apply(this, arguments); - var queue = this.queue || []; - var request; - - while(request = queue.shift()) { - this.processRequest(request); - } - }, - - processRequest: function processRequest(request) { - try { - if (request.aborted) { - return; - } - - var response = this.response || [404, {}, ""]; - - if (this.responses) { - for (var i = 0, l = this.responses.length; i < l; i++) { - if (match.call(this, this.responses[i], request)) { - response = this.responses[i].response; - break; - } - } - } - - if (request.readyState != 4) { - request.respond(response[0], response[1], response[2]); - } - } catch (e) { - sinon.logError("Fake server request processing", e); - } - }, - - restore: function restore() { - return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); - } - }; -}()); - -if (typeof module == "object" && typeof require == "function") { - module.exports = sinon; -} - -/** - * @depend fake_server.js - * @depend fake_timers.js - */ -/*jslint browser: true, eqeqeq: false, onevar: false*/ -/*global sinon*/ -/** - * Add-on for sinon.fakeServer that automatically handles a fake timer along with - * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery - * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, - * it polls the object for completion with setInterval. Dispite the direct - * motivation, there is nothing jQuery-specific in this file, so it can be used - * in any environment where the ajax implementation depends on setInterval or - * setTimeout. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function () { - function Server() {} - Server.prototype = sinon.fakeServer; - - sinon.fakeServerWithClock = new Server(); - - sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { - if (xhr.async) { - if (typeof setTimeout.clock == "object") { - this.clock = setTimeout.clock; - } else { - this.clock = sinon.useFakeTimers(); - this.resetClock = true; - } - - if (!this.longestTimeout) { - var clockSetTimeout = this.clock.setTimeout; - var clockSetInterval = this.clock.setInterval; - var server = this; - - this.clock.setTimeout = function (fn, timeout) { - server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); - - return clockSetTimeout.apply(this, arguments); - }; - - this.clock.setInterval = function (fn, timeout) { - server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); - - return clockSetInterval.apply(this, arguments); - }; - } - } - - return sinon.fakeServer.addRequest.call(this, xhr); - }; - - sinon.fakeServerWithClock.respond = function respond() { - var returnVal = sinon.fakeServer.respond.apply(this, arguments); - - if (this.clock) { - this.clock.tick(this.longestTimeout || 0); - this.longestTimeout = 0; - - if (this.resetClock) { - this.clock.restore(); - this.resetClock = false; - } - } - - return returnVal; - }; - - sinon.fakeServerWithClock.restore = function restore() { - if (this.clock) { - this.clock.restore(); - } - - return sinon.fakeServer.restore.apply(this, arguments); - }; -}()); - -/** - * @depend ../sinon.js - * @depend collection.js - * @depend util/fake_timers.js - * @depend util/fake_server_with_clock.js - */ -/*jslint eqeqeq: false, onevar: false, plusplus: false*/ -/*global require, module*/ -/** - * Manages fake collections as well as fake utilities such as Sinon's - * timers and fake XHR implementation in one convenient object. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -if (typeof module == "object" && typeof require == "function") { - var sinon = require("../sinon"); - sinon.extend(sinon, require("./util/fake_timers")); -} - -(function () { - var push = [].push; - - function exposeValue(sandbox, config, key, value) { - if (!value) { - return; - } - - if (config.injectInto) { - config.injectInto[key] = value; - } else { - push.call(sandbox.args, value); - } - } - - function prepareSandboxFromConfig(config) { - var sandbox = sinon.create(sinon.sandbox); - - if (config.useFakeServer) { - if (typeof config.useFakeServer == "object") { - sandbox.serverPrototype = config.useFakeServer; - } - - sandbox.useFakeServer(); - } - - if (config.useFakeTimers) { - if (typeof config.useFakeTimers == "object") { - sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); - } else { - sandbox.useFakeTimers(); - } - } - - return sandbox; - } - - sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { - useFakeTimers: function useFakeTimers() { - this.clock = sinon.useFakeTimers.apply(sinon, arguments); - - return this.add(this.clock); - }, - - serverPrototype: sinon.fakeServer, - - useFakeServer: function useFakeServer() { - var proto = this.serverPrototype || sinon.fakeServer; - - if (!proto || !proto.create) { - return null; - } - - this.server = proto.create(); - return this.add(this.server); - }, - - inject: function (obj) { - sinon.collection.inject.call(this, obj); - - if (this.clock) { - obj.clock = this.clock; - } - - if (this.server) { - obj.server = this.server; - obj.requests = this.server.requests; - } - - return obj; - }, - - create: function (config) { - if (!config) { - return sinon.create(sinon.sandbox); - } - - var sandbox = prepareSandboxFromConfig(config); - sandbox.args = sandbox.args || []; - var prop, value, exposed = sandbox.inject({}); - - if (config.properties) { - for (var i = 0, l = config.properties.length; i < l; i++) { - prop = config.properties[i]; - value = exposed[prop] || prop == "sandbox" && sandbox; - exposeValue(sandbox, config, prop, value); - } - } else { - exposeValue(sandbox, config, "sandbox", value); - } - - return sandbox; - } - }); - - sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; - - if (typeof module == "object" && typeof require == "function") { - module.exports = sinon.sandbox; - } -}()); - -/** - * @depend ../sinon.js - * @depend stub.js - * @depend mock.js - * @depend sandbox.js - */ -/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/ -/*global module, require, sinon*/ -/** - * Test function, sandboxes fakes - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function (sinon) { - var commonJSModule = typeof module == "object" && typeof require == "function"; - - if (!sinon && commonJSModule) { - sinon = require("../sinon"); - } - - if (!sinon) { - return; - } - - function test(callback) { - var type = typeof callback; - - if (type != "function") { - throw new TypeError("sinon.test needs to wrap a test function, got " + type); - } - - return function () { - var config = sinon.getConfig(sinon.config); - config.injectInto = config.injectIntoThis && this || config.injectInto; - var sandbox = sinon.sandbox.create(config); - var exception, result; - var args = Array.prototype.slice.call(arguments).concat(sandbox.args); - - try { - result = callback.apply(this, args); - } finally { - sandbox.verifyAndRestore(); - } - - return result; - }; - } - - test.config = { - injectIntoThis: true, - injectInto: null, - properties: ["spy", "stub", "mock", "clock", "server", "requests"], - useFakeTimers: true, - useFakeServer: true - }; - - if (commonJSModule) { - module.exports = test; - } else { - sinon.test = test; - } -}(typeof sinon == "object" && sinon || null)); - -/** - * @depend ../sinon.js - * @depend test.js - */ -/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/ -/*global module, require, sinon*/ -/** - * Test case, sandboxes all test functions - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function (sinon) { - var commonJSModule = typeof module == "object" && typeof require == "function"; - - if (!sinon && commonJSModule) { - sinon = require("../sinon"); - } - - if (!sinon || !Object.prototype.hasOwnProperty) { - return; - } - - function createTest(property, setUp, tearDown) { - return function () { - if (setUp) { - setUp.apply(this, arguments); - } - - var exception, result; - - try { - result = property.apply(this, arguments); - } catch (e) { - exception = e; - } - - if (tearDown) { - tearDown.apply(this, arguments); - } - - if (exception) { - throw exception; - } - - return result; - }; - } - - function testCase(tests, prefix) { - /*jsl:ignore*/ - if (!tests || typeof tests != "object") { - throw new TypeError("sinon.testCase needs an object with test functions"); - } - /*jsl:end*/ - - prefix = prefix || "test"; - var rPrefix = new RegExp("^" + prefix); - var methods = {}, testName, property, method; - var setUp = tests.setUp; - var tearDown = tests.tearDown; - - for (testName in tests) { - if (tests.hasOwnProperty(testName)) { - property = tests[testName]; - - if (/^(setUp|tearDown)$/.test(testName)) { - continue; - } - - if (typeof property == "function" && rPrefix.test(testName)) { - method = property; - - if (setUp || tearDown) { - method = createTest(property, setUp, tearDown); - } - - methods[testName] = sinon.test(method); - } else { - methods[testName] = tests[testName]; - } - } - } - - return methods; - } - - if (commonJSModule) { - module.exports = testCase; - } else { - sinon.testCase = testCase; - } -}(typeof sinon == "object" && sinon || null)); - -/** - * @depend ../sinon.js - * @depend stub.js - */ -/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/ -/*global module, require, sinon*/ -/** - * Assertions matching the test spy retrieval interface. - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2011 Christian Johansen - */ - -(function (sinon, global) { - var commonJSModule = typeof module == "object" && typeof require == "function"; - var slice = Array.prototype.slice; - var assert; - - if (!sinon && commonJSModule) { - sinon = require("../sinon"); - } - - if (!sinon) { - return; - } - - function verifyIsStub() { - var method; - - for (var i = 0, l = arguments.length; i < l; ++i) { - method = arguments[i]; - - if (!method) { - assert.fail("fake is not a spy"); - } - - if (typeof method != "function") { - assert.fail(method + " is not a function"); - } - - if (typeof method.getCall != "function") { - assert.fail(method + " is not stubbed"); - } - } - } - - function failAssertion(object, msg) { - object = object || global; - var failMethod = object.fail || assert.fail; - failMethod.call(object, msg); - } - - function mirrorPropAsAssertion(name, method, message) { - if (arguments.length == 2) { - message = method; - method = name; - } - - assert[name] = function (fake) { - verifyIsStub(fake); - - var args = slice.call(arguments, 1); - var failed = false; - - if (typeof method == "function") { - failed = !method(fake); - } else { - failed = typeof fake[method] == "function" ? - !fake[method].apply(fake, args) : !fake[method]; - } - - if (failed) { - failAssertion(this, fake.printf.apply(fake, [message].concat(args))); - } else { - assert.pass(name); - } - }; - } - - function exposedName(prefix, prop) { - return !prefix || /^fail/.test(prop) ? prop : - prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); - }; - - assert = { - failException: "AssertError", - - fail: function fail(message) { - var error = new Error(message); - error.name = this.failException || assert.failException; - - throw error; - }, - - pass: function pass(assertion) {}, - - callOrder: function assertCallOrder() { - verifyIsStub.apply(null, arguments); - var expected = "", actual = ""; - - if (!sinon.calledInOrder(arguments)) { - try { - expected = [].join.call(arguments, ", "); - actual = sinon.orderByFirstCall(slice.call(arguments)).join(", "); - } catch (e) { - // If this fails, we'll just fall back to the blank string - } - - failAssertion(this, "expected " + expected + " to be " + - "called in order but were called as " + actual); - } else { - assert.pass("callOrder"); - } - }, - - callCount: function assertCallCount(method, count) { - verifyIsStub(method); - - if (method.callCount != count) { - var msg = "expected %n to be called " + sinon.timesInWords(count) + - " but was called %c%C"; - failAssertion(this, method.printf(msg)); - } else { - assert.pass("callCount"); - } - }, - - expose: function expose(target, options) { - if (!target) { - throw new TypeError("target is null or undefined"); - } - - var o = options || {}; - var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; - var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; - - for (var method in this) { - if (method != "export" && (includeFail || !/^(fail)/.test(method))) { - target[exposedName(prefix, method)] = this[method]; - } - } - - return target; - } - }; - - mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); - mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, - "expected %n to not have been called but was called %c%C"); - mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); - mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); - mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); - mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); - mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); - mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); - mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); - mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); - mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); - mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); - mirrorPropAsAssertion("threw", "%n did not throw exception%C"); - mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); - - if (commonJSModule) { - module.exports = assert; - } else { - sinon.assert = assert; - } -}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : global)); - -return sinon;}.call(typeof window != 'undefined' && window || {})); diff --git a/assets/scripts/vendor/ansiparse.js b/assets/scripts/vendor/ansiparse.js deleted file mode 100644 index 692247d7..00000000 --- a/assets/scripts/vendor/ansiparse.js +++ /dev/null @@ -1,186 +0,0 @@ -ansiparse = function (str) { - // - // I'm terrible at writing parsers. - // - var matchingControl = null, - matchingData = null, - matchingText = '', - ansiState = [], - result = [], - state = {}, - eraseChar; - - // - // General workflow for this thing is: - // \033\[33mText - // | | | - // | | matchingText - // | matchingData - // matchingControl - // - // In further steps we hope it's all going to be fine. It usually is. - // - - // - // Erases a char from the output - // - eraseChar = function () { - var index, text; - if (matchingText.length) { - matchingText = matchingText.substr(0, matchingText.length - 1); - } - else if (result.length) { - index = result.length - 1; - text = result[index].text; - if (text.length === 1) { - // - // A result bit was fully deleted, pop it out to simplify the final output - // - result.pop(); - } - else { - result[index].text = text.substr(0, text.length - 1); - } - } - }; - - for (var i = 0; i < str.length; i++) { - if (matchingControl != null) { - if (matchingControl == '\033' && str[i] == '\[') { - // - // We've matched full control code. Lets start matching formating data. - // - - // - // "emit" matched text with correct state - // - if (matchingText) { - state.text = matchingText; - result.push(state); - state = {}; - matchingText = ""; - } - - matchingControl = null; - matchingData = ''; - } - else { - // - // We failed to match anything - most likely a bad control code. We - // go back to matching regular strings. - // - matchingText += matchingControl + str[i]; - matchingControl = null; - } - continue; - } - else if (matchingData != null) { - if (str[i] == ';') { - // - // `;` separates many formatting codes, for example: `\033[33;43m` - // means that both `33` and `43` should be applied. - // - // TODO: this can be simplified by modifying state here. - // - ansiState.push(matchingData); - matchingData = ''; - } - else if (str[i] == 'm') { - // - // `m` finished whole formatting code. We can proceed to matching - // formatted text. - // - ansiState.push(matchingData); - matchingData = null; - matchingText = ''; - - // - // Convert matched formatting data into user-friendly state object. - // - // TODO: DRY. - // - ansiState.forEach(function (ansiCode) { - if (ansiparse.foregroundColors[ansiCode]) { - state.foreground = ansiparse.foregroundColors[ansiCode]; - } - else if (ansiparse.backgroundColors[ansiCode]) { - state.background = ansiparse.backgroundColors[ansiCode]; - } - else if (ansiCode == 39) { - delete state.foreground; - } - else if (ansiCode == 49) { - delete state.background; - } - else if (ansiparse.styles[ansiCode]) { - state[ansiparse.styles[ansiCode]] = true; - } - else if (ansiCode == 22) { - state.bold = false; - } - else if (ansiCode == 23) { - state.italic = false; - } - else if (ansiCode == 24) { - state.underline = false; - } - }); - ansiState = []; - } - else { - matchingData += str[i]; - } - continue; - } - - if (str[i] == '\033') { - matchingControl = str[i]; - } - else if (str[i] == '\u0008') { - eraseChar(); - } - else { - matchingText += str[i]; - } - } - - if (matchingText) { - state.text = matchingText + (matchingControl ? matchingControl : ''); - result.push(state); - } - return result; -} - -ansiparse.foregroundColors = { - '30': 'black', - '31': 'red', - '32': 'green', - '33': 'yellow', - '34': 'blue', - '35': 'magenta', - '36': 'cyan', - '37': 'white', - '90': 'grey' -}; - -ansiparse.backgroundColors = { - '40': 'black', - '41': 'red', - '42': 'green', - '43': 'yellow', - '44': 'blue', - '45': 'magenta', - '46': 'cyan', - '47': 'white' -}; - -ansiparse.styles = { - '1': 'bold', - '3': 'italic', - '4': 'underline' -}; - -if (typeof module == "object" && typeof window == "undefined") { - module.exports = ansiparse; -} - diff --git a/assets/scripts/vendor/customerio.js b/assets/scripts/vendor/customerio.js deleted file mode 100644 index 10522d01..00000000 --- a/assets/scripts/vendor/customerio.js +++ /dev/null @@ -1,14 +0,0 @@ -var _cio = _cio || []; - -function setupCustomerio(siteId) { - var a,b,c;a=function(f){return function(){_cio.push([f]. - concat(Array.prototype.slice.call(arguments,0)))}};b=["load","identify", - "sidentify","track","page"];for(c=0;c= 1.8 forEach is called with the order value, key as per - * the ES6 spec. - */ - function ember$data$lib$system$map$$translate(valueKeyOrderedCallback){ - return function(key, value){ - valueKeyOrderedCallback.call(this, value, key); - }; - } - - // old, non ES6 compliant behavior - if (ember$data$lib$system$map$$usesOldBehavior){ - ember$data$lib$system$map$$mapForEach = function(callback, thisArg){ - this.__super$forEach(ember$data$lib$system$map$$translate(callback), thisArg); - }; - - /* alias to remove */ - ember$data$lib$system$map$$deleteFn = function(thing){ - this.remove(thing); - }; - - ember$data$lib$system$map$$Map.prototype.__super$forEach = Ember.Map.prototype.forEach; - ember$data$lib$system$map$$Map.prototype.forEach = ember$data$lib$system$map$$mapForEach; - ember$data$lib$system$map$$Map.prototype["delete"] = ember$data$lib$system$map$$deleteFn; - - ember$data$lib$system$map$$MapWithDefault.prototype.forEach = ember$data$lib$system$map$$mapForEach; - ember$data$lib$system$map$$MapWithDefault.prototype.__super$forEach = Ember.MapWithDefault.prototype.forEach; - ember$data$lib$system$map$$MapWithDefault.prototype["delete"] = ember$data$lib$system$map$$deleteFn; - - ember$data$lib$system$map$$OrderedSet.prototype["delete"] = ember$data$lib$system$map$$deleteFn; - } - - ember$data$lib$system$map$$MapWithDefault.constructor = ember$data$lib$system$map$$MapWithDefault; - ember$data$lib$system$map$$Map.constructor = ember$data$lib$system$map$$Map; - - ember$data$lib$system$map$$MapWithDefault.create = function(options){ - if (options) { - return new ember$data$lib$system$map$$MapWithDefault(options); - } else { - return new ember$data$lib$system$map$$Map(); - } - }; - - ember$data$lib$system$map$$Map.create = function(){ - return new this.constructor(); - }; - - var ember$data$lib$system$map$$default = ember$data$lib$system$map$$Map; - var ember$data$lib$adapters$rest_adapter$$get = Ember.get; - var ember$data$lib$adapters$rest_adapter$$forEach = Ember.ArrayPolyfills.forEach; - - var ember$data$lib$adapters$rest_adapter$$default = ember$data$lib$system$adapter$$Adapter.extend({ - defaultSerializer: '-rest', - - /** - By default the RESTAdapter will send each find request coming from a `store.find` - or from accessing a relationship separately to the server. If your server supports passing - ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests - within a single runloop. - - For example, if you have an initial payload of - ```javascript - post: { - id:1, - comments: [1,2] - } - ``` - - By default calling `post.get('comments')` will trigger the following requests(assuming the - comments haven't been loaded before): - - ``` - GET /comments/1 - GET /comments/2 - ``` - - If you set coalesceFindRequests to `true` it will instead trigger the following request: - - ``` - GET /comments?ids[]=1&ids[]=2 - ``` - - Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` - relationships accessed within the same runloop. If you set `coalesceFindRequests: true` - - ```javascript - store.find('comment', 1); - store.find('comment', 2); - ``` - - will also send a request to: `GET /comments?ids[]=1&ids[]=2` - - Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app - `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. - - @property coalesceFindRequests - @type {boolean} - */ - coalesceFindRequests: false, - - /** - Endpoint paths can be prefixed with a `namespace` by setting the namespace - property on the adapter: - - ```javascript - DS.RESTAdapter.reopen({ - namespace: 'api/1' - }); - ``` - - Requests for `App.Post` would now target `/api/1/post/`. - - @property namespace - @type {String} - */ - - /** - An adapter can target other hosts by setting the `host` property. - - ```javascript - DS.RESTAdapter.reopen({ - host: 'https://api.example.com' - }); - ``` - - Requests for `App.Post` would now target `https://api.example.com/post/`. - - @property host - @type {String} - */ - - /** - Some APIs require HTTP headers, e.g. to provide an API - key. Arbitrary headers can be set as key/value pairs on the - `RESTAdapter`'s `headers` object and Ember Data will send them - along with each ajax request. For dynamic headers see [headers - customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). - - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ - headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" - } - }); - ``` - - @property headers - @type {Object} - */ - - /** - Called by the store in order to fetch the JSON for a given - type and ID. - - The `find` method makes an Ajax request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - This method performs an HTTP `GET` request with the id provided as part of the query string. - - @method find - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {String} id - @param {DS.Model} record - @return {Promise} promise - */ - find: function(store, type, id, record) { - return this.ajax(this.buildURL(type.typeKey, id, record), 'GET'); - }, - - /** - Called by the store in order to fetch a JSON array for all - of the records for a given type. - - The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - @private - @method findAll - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {String} sinceToken - @return {Promise} promise - */ - findAll: function(store, type, sinceToken) { - var query; - - if (sinceToken) { - query = { since: sinceToken }; - } - - return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch a JSON array for - the records that match a particular query. - - The `findQuery` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - The `query` argument is a simple JavaScript object that will be passed directly - to the server as parameters. - - @private - @method findQuery - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} query - @return {Promise} promise - */ - findQuery: function(store, type, query) { - return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch several records together if `coalesceFindRequests` is true - - For example, if the original payload looks like: - - ```js - { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2, 3 ] - } - ``` - - The IDs will be passed as a URL-encoded Array of IDs, in this form: - - ``` - ids[]=1&ids[]=2&ids[]=3 - ``` - - Many servers, such as Rails and PHP, will automatically convert this URL-encoded array - into an Array for you on the server-side. If you want to encode the - IDs, differently, just override this (one-line) method. - - The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - @method findMany - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Array} ids - @param {Array} records - @return {Promise} promise - */ - findMany: function(store, type, ids, records) { - return this.ajax(this.buildURL(type.typeKey, ids, records), 'GET', { data: { ids: ids } }); - }, - - /** - Called by the store in order to fetch a JSON array for - the unloaded records in a has-many relationship that were originally - specified as a URL (inside of `links`). - - For example, if your original payload looks like this: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "links": { "comments": "/posts/1/comments" } - } - } - ``` - - This method will be called with the parent record and `/posts/1/comments`. - - The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL. - If the URL is host-relative (starting with a single slash), the - request will use the host specified on the adapter (if any). - - @method findHasMany - @param {DS.Store} store - @param {DS.Model} record - @param {String} url - @return {Promise} promise - */ - findHasMany: function(store, record, url, relationship) { - var host = ember$data$lib$adapters$rest_adapter$$get(this, 'host'); - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - var type = record.constructor.typeKey; - - if (host && url.charAt(0) === '/' && url.charAt(1) !== '/') { - url = host + url; - } - - return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET'); - }, - - /** - Called by the store in order to fetch a JSON array for - the unloaded records in a belongs-to relationship that were originally - specified as a URL (inside of `links`). - - For example, if your original payload looks like this: - - ```js - { - "person": { - "id": 1, - "name": "Tom Dale", - "links": { "group": "/people/1/group" } - } - } - ``` - - This method will be called with the parent record and `/people/1/group`. - - The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL. - - @method findBelongsTo - @param {DS.Store} store - @param {DS.Model} record - @param {String} url - @return {Promise} promise - */ - findBelongsTo: function(store, record, url, relationship) { - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - var type = record.constructor.typeKey; - - return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET'); - }, - - /** - Called by the store when a newly created record is - saved via the `save` method on a model record instance. - - The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request - to a URL computed by `buildURL`. - - See `serialize` for information on how to customize the serialized form - of a record. - - @method createRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {DS.Model} record - @return {Promise} promise - */ - createRecord: function(store, type, record) { - var data = {}; - var serializer = store.serializerFor(type.typeKey); - - serializer.serializeIntoHash(data, type, record, { includeId: true }); - - return this.ajax(this.buildURL(type.typeKey, null, record), "POST", { data: data }); - }, - - /** - Called by the store when an existing record is saved - via the `save` method on a model record instance. - - The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request - to a URL computed by `buildURL`. - - See `serialize` for information on how to customize the serialized form - of a record. - - @method updateRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {DS.Model} record - @return {Promise} promise - */ - updateRecord: function(store, type, record) { - var data = {}; - var serializer = store.serializerFor(type.typeKey); - - serializer.serializeIntoHash(data, type, record); - - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - - return this.ajax(this.buildURL(type.typeKey, id, record), "PUT", { data: data }); - }, - - /** - Called by the store when a record is deleted. - - The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`. - - @method deleteRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {DS.Model} record - @return {Promise} promise - */ - deleteRecord: function(store, type, record) { - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - - return this.ajax(this.buildURL(type.typeKey, id, record), "DELETE"); - }, - - /** - Builds a URL for a given type and optional ID. - - By default, it pluralizes the type's name (for example, 'post' - becomes 'posts' and 'person' becomes 'people'). To override the - pluralization see [pathForType](#method_pathForType). - - If an ID is specified, it adds the ID to the path generated - for the type, separated by a `/`. - - @method buildURL - @param {String} type - @param {String} id - @param {DS.Model} record - @return {String} url - */ - buildURL: function(type, id, record) { - var url = [], - host = ember$data$lib$adapters$rest_adapter$$get(this, 'host'), - prefix = this.urlPrefix(); - - if (type) { url.push(this.pathForType(type)); } - - //We might get passed in an array of ids from findMany - //in which case we don't want to modify the url, as the - //ids will be passed in through a query param - if (id && !Ember.isArray(id)) { url.push(encodeURIComponent(id)); } - - if (prefix) { url.unshift(prefix); } - - url = url.join('/'); - if (!host && url) { url = '/' + url; } - - return url; - }, - - /** - @method urlPrefix - @private - @param {String} path - @param {String} parentUrl - @return {String} urlPrefix - */ - urlPrefix: function(path, parentURL) { - var host = ember$data$lib$adapters$rest_adapter$$get(this, 'host'); - var namespace = ember$data$lib$adapters$rest_adapter$$get(this, 'namespace'); - var url = []; - - if (path) { - // Absolute path - if (path.charAt(0) === '/') { - if (host) { - path = path.slice(1); - url.push(host); - } - // Relative path - } else if (!/^http(s)?:\/\//.test(path)) { - url.push(parentURL); - } - } else { - if (host) { url.push(host); } - if (namespace) { url.push(namespace); } - } - - if (path) { - url.push(path); - } - - return url.join('/'); - }, - - _stripIDFromURL: function(store, record) { - var type = record.constructor; - var url = this.buildURL(type.typeKey, record.get('id'), record); - - var expandedURL = url.split('/'); - //Case when the url is of the format ...something/:id - var lastSegment = expandedURL[ expandedURL.length - 1 ]; - var id = record.get('id'); - if (lastSegment === id) { - expandedURL[expandedURL.length - 1] = ""; - } else if(ember$data$lib$adapters$rest_adapter$$endsWith(lastSegment, '?id=' + id)) { - //Case when the url is of the format ...something?id=:id - expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); - } - - return expandedURL.join('/'); - }, - - /** - http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers - */ - maxUrlLength: 2048, - - /** - Organize records into groups, each of which is to be passed to separate - calls to `findMany`. - - This implementation groups together records that have the same base URL but - differing ids. For example `/comments/1` and `/comments/2` will be grouped together - because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2` - - It also supports urls where ids are passed as a query param, such as `/comments?id=1` - but not those where there is more than 1 query param such as `/comments?id=2&name=David` - Currently only the query param of `id` is supported. If you need to support others, please - override this or the `_stripIDFromURL` method. - - It does not group records that have differing base urls, such as for example: `/posts/1/comments/2` - and `/posts/2/comments/3` - - @method groupRecordsForFindMany - @param {DS.Store} store - @param {Array} records - @return {Array} an array of arrays of records, each of which is to be - loaded separately by `findMany`. - */ - groupRecordsForFindMany: function (store, records) { - var groups = ember$data$lib$system$map$$MapWithDefault.create({defaultValue: function(){return [];}}); - var adapter = this; - var maxUrlLength = this.maxUrlLength; - - ember$data$lib$adapters$rest_adapter$$forEach.call(records, function(record){ - var baseUrl = adapter._stripIDFromURL(store, record); - groups.get(baseUrl).push(record); - }); - - function splitGroupToFitInUrl(group, maxUrlLength, paramNameLength) { - var baseUrl = adapter._stripIDFromURL(store, group[0]); - var idsSize = 0; - var splitGroups = [[]]; - - ember$data$lib$adapters$rest_adapter$$forEach.call(group, function(record) { - var additionalLength = encodeURIComponent(record.get('id')).length + paramNameLength; - if (baseUrl.length + idsSize + additionalLength >= maxUrlLength) { - idsSize = 0; - splitGroups.push([]); - } - - idsSize += additionalLength; - - var lastGroupIndex = splitGroups.length - 1; - splitGroups[lastGroupIndex].push(record); - }); - - return splitGroups; - } - - var groupsArray = []; - groups.forEach(function(group, key){ - var paramNameLength = '&ids%5B%5D='.length; - var splitGroups = splitGroupToFitInUrl(group, maxUrlLength, paramNameLength); - - ember$data$lib$adapters$rest_adapter$$forEach.call(splitGroups, function(splitGroup) { - groupsArray.push(splitGroup); - }); - }); - - return groupsArray; - }, - - /** - Determines the pathname for a given type. - - By default, it pluralizes the type's name (for example, - 'post' becomes 'posts' and 'person' becomes 'people'). - - ### Pathname customization - - For example if you have an object LineItem with an - endpoint of "/line_items/". - - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ - pathForType: function(type) { - var decamelized = Ember.String.decamelize(type); - return Ember.String.pluralize(decamelized); - } - }); - ``` - - @method pathForType - @param {String} type - @return {String} path - **/ - pathForType: function(type) { - var camelized = Ember.String.camelize(type); - return Ember.String.pluralize(camelized); - }, - - /** - Takes an ajax response, and returns an error payload. - - Returning a `DS.InvalidError` from this method will cause the - record to transition into the `invalid` state and make the - `errors` object available on the record. - - This function should return the entire payload as received from the - server. Error object extraction and normalization of model errors - should be performed by `extractErrors` on the serializer. - - Example - - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ - ajaxError: function(jqXHR) { - var error = this._super(jqXHR); - - if (jqXHR && jqXHR.status === 422) { - var jsonErrors = Ember.$.parseJSON(jqXHR.responseText); - - return new DS.InvalidError(jsonErrors); - } else { - return error; - } - } - }); - ``` - - Note: As a correctness optimization, the default implementation of - the `ajaxError` method strips out the `then` method from jquery's - ajax response (jqXHR). This is important because the jqXHR's - `then` method fulfills the promise with itself resulting in a - circular "thenable" chain which may cause problems for some - promise libraries. - - @method ajaxError - @param {Object} jqXHR - @param {Object} responseText - @return {Object} jqXHR - */ - ajaxError: function(jqXHR, responseText, errorThrown) { - var isObject = jqXHR !== null && typeof jqXHR === 'object'; - - if (isObject) { - jqXHR.then = null; - if (!jqXHR.errorThrown) { - jqXHR.errorThrown = errorThrown; - } - } - - return jqXHR; - }, - - /** - Takes an ajax response, and returns the json payload. - - By default this hook just returns the jsonPayload passed to it. - You might want to override it in two cases: - - 1. Your API might return useful results in the request headers. - If you need to access these, you can override this hook to copy them - from jqXHR to the payload object so they can be processed in you serializer. - - - 2. Your API might return errors as successful responses with status code - 200 and an Errors text or object. You can return a DS.InvalidError from - this hook and it will automatically reject the promise and put your record - into the invalid state. - - @method ajaxSuccess - @param {Object} jqXHR - @param {Object} jsonPayload - @return {Object} jsonPayload - */ - - ajaxSuccess: function(jqXHR, jsonPayload) { - return jsonPayload; - }, - - /** - Takes a URL, an HTTP method and a hash of data, and makes an - HTTP request. - - When the server responds with a payload, Ember Data will call into `extractSingle` - or `extractArray` (depending on whether the original query was for one record or - many records). - - By default, `ajax` method has the following behavior: - - * It sets the response `dataType` to `"json"` - * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be - `application/json; charset=utf-8` - * If the HTTP method is not `"GET"`, it stringifies the data passed in. The - data is the serialized record in the case of a save. - * Registers success and failure handlers. - - @method ajax - @private - @param {String} url - @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} hash - @return {Promise} promise - */ - ajax: function(url, type, options) { - var adapter = this; - - return new Ember.RSVP.Promise(function(resolve, reject) { - var hash = adapter.ajaxOptions(url, type, options); - - hash.success = function(json, textStatus, jqXHR) { - json = adapter.ajaxSuccess(jqXHR, json); - if (json instanceof ember$data$lib$system$adapter$$InvalidError) { - Ember.run(null, reject, json); - } else { - Ember.run(null, resolve, json); - } - }; - - hash.error = function(jqXHR, textStatus, errorThrown) { - Ember.run(null, reject, adapter.ajaxError(jqXHR, jqXHR.responseText, errorThrown)); - }; - - Ember.$.ajax(hash); - }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); - }, - - /** - @method ajaxOptions - @private - @param {String} url - @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} hash - @return {Object} hash - */ - ajaxOptions: function(url, type, options) { - var hash = options || {}; - hash.url = url; - hash.type = type; - hash.dataType = 'json'; - hash.context = this; - - if (hash.data && type !== 'GET') { - hash.contentType = 'application/json; charset=utf-8'; - hash.data = JSON.stringify(hash.data); - } - - var headers = ember$data$lib$adapters$rest_adapter$$get(this, 'headers'); - if (headers !== undefined) { - hash.beforeSend = function (xhr) { - ember$data$lib$adapters$rest_adapter$$forEach.call(Ember.keys(headers), function(key) { - xhr.setRequestHeader(key, headers[key]); - }); - }; - } - - return hash; - } - }); - - //From http://stackoverflow.com/questions/280634/endswith-in-javascript - function ember$data$lib$adapters$rest_adapter$$endsWith(string, suffix){ - if (typeof String.prototype.endsWith !== 'function') { - return string.indexOf(suffix, string.length - suffix.length) !== -1; - } else { - return string.endsWith(suffix); - } - } - - var ember$inflector$lib$system$inflector$$capitalize = Ember.String.capitalize; - - var ember$inflector$lib$system$inflector$$BLANK_REGEX = /^\s*$/; - var ember$inflector$lib$system$inflector$$LAST_WORD_DASHED_REGEX = /(\w+[_-])([a-z\d]+$)/; - var ember$inflector$lib$system$inflector$$LAST_WORD_CAMELIZED_REGEX = /(\w+)([A-Z][a-z\d]*$)/; - var ember$inflector$lib$system$inflector$$CAMELIZED_REGEX = /[A-Z][a-z\d]*$/; - - function ember$inflector$lib$system$inflector$$loadUncountable(rules, uncountable) { - for (var i = 0, length = uncountable.length; i < length; i++) { - rules.uncountable[uncountable[i].toLowerCase()] = true; - } - } - - function ember$inflector$lib$system$inflector$$loadIrregular(rules, irregularPairs) { - var pair; - - for (var i = 0, length = irregularPairs.length; i < length; i++) { - pair = irregularPairs[i]; - - //pluralizing - rules.irregular[pair[0].toLowerCase()] = pair[1]; - rules.irregular[pair[1].toLowerCase()] = pair[1]; - - //singularizing - rules.irregularInverse[pair[1].toLowerCase()] = pair[0]; - rules.irregularInverse[pair[0].toLowerCase()] = pair[0]; - } - } - - /** - Inflector.Ember provides a mechanism for supplying inflection rules for your - application. Ember includes a default set of inflection rules, and provides an - API for providing additional rules. - - Examples: - - Creating an inflector with no rules. - - ```js - var inflector = new Ember.Inflector(); - ``` - - Creating an inflector with the default ember ruleset. - - ```js - var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); - - inflector.pluralize('cow'); //=> 'kine' - inflector.singularize('kine'); //=> 'cow' - ``` - - Creating an inflector and adding rules later. - - ```javascript - var inflector = Ember.Inflector.inflector; - - inflector.pluralize('advice'); // => 'advices' - inflector.uncountable('advice'); - inflector.pluralize('advice'); // => 'advice' - - inflector.pluralize('formula'); // => 'formulas' - inflector.irregular('formula', 'formulae'); - inflector.pluralize('formula'); // => 'formulae' - - // you would not need to add these as they are the default rules - inflector.plural(/$/, 's'); - inflector.singular(/s$/i, ''); - ``` - - Creating an inflector with a nondefault ruleset. - - ```javascript - var rules = { - plurals: [ /$/, 's' ], - singular: [ /\s$/, '' ], - irregularPairs: [ - [ 'cow', 'kine' ] - ], - uncountable: [ 'fish' ] - }; - - var inflector = new Ember.Inflector(rules); - ``` - - @class Inflector - @namespace Ember - */ - function ember$inflector$lib$system$inflector$$Inflector(ruleSet) { - ruleSet = ruleSet || {}; - ruleSet.uncountable = ruleSet.uncountable || ember$inflector$lib$system$inflector$$makeDictionary(); - ruleSet.irregularPairs = ruleSet.irregularPairs || ember$inflector$lib$system$inflector$$makeDictionary(); - - var rules = this.rules = { - plurals: ruleSet.plurals || [], - singular: ruleSet.singular || [], - irregular: ember$inflector$lib$system$inflector$$makeDictionary(), - irregularInverse: ember$inflector$lib$system$inflector$$makeDictionary(), - uncountable: ember$inflector$lib$system$inflector$$makeDictionary() - }; - - ember$inflector$lib$system$inflector$$loadUncountable(rules, ruleSet.uncountable); - ember$inflector$lib$system$inflector$$loadIrregular(rules, ruleSet.irregularPairs); - - this.enableCache(); - } - - if (!Object.create && !Object.create(null).hasOwnProperty) { - throw new Error("This browser does not support Object.create(null), please polyfil with es5-sham: http://git.io/yBU2rg"); - } - - function ember$inflector$lib$system$inflector$$makeDictionary() { - var cache = Object.create(null); - cache['_dict'] = null; - delete cache['_dict']; - return cache; - } - - ember$inflector$lib$system$inflector$$Inflector.prototype = { - /** - @public - - As inflections can be costly, and commonly the same subset of words are repeatedly - inflected an optional cache is provided. - - @method enableCache - */ - enableCache: function() { - this.purgeCache(); - - this.singularize = function(word) { - this._cacheUsed = true; - return this._sCache[word] || (this._sCache[word] = this._singularize(word)); - }; - - this.pluralize = function(word) { - this._cacheUsed = true; - return this._pCache[word] || (this._pCache[word] = this._pluralize(word)); - }; - }, - - /** - @public - - @method purgedCache - */ - purgeCache: function() { - this._cacheUsed = false; - this._sCache = ember$inflector$lib$system$inflector$$makeDictionary(); - this._pCache = ember$inflector$lib$system$inflector$$makeDictionary(); - }, - - /** - @public - disable caching - - @method disableCache; - */ - disableCache: function() { - this._sCache = null; - this._pCache = null; - this.singularize = function(word) { - return this._singularize(word); - }; - - this.pluralize = function(word) { - return this._pluralize(word); - }; - }, - - /** - @method plural - @param {RegExp} regex - @param {String} string - */ - plural: function(regex, string) { - if (this._cacheUsed) { this.purgeCache(); } - this.rules.plurals.push([regex, string.toLowerCase()]); - }, - - /** - @method singular - @param {RegExp} regex - @param {String} string - */ - singular: function(regex, string) { - if (this._cacheUsed) { this.purgeCache(); } - this.rules.singular.push([regex, string.toLowerCase()]); - }, - - /** - @method uncountable - @param {String} regex - */ - uncountable: function(string) { - if (this._cacheUsed) { this.purgeCache(); } - ember$inflector$lib$system$inflector$$loadUncountable(this.rules, [string.toLowerCase()]); - }, - - /** - @method irregular - @param {String} singular - @param {String} plural - */ - irregular: function (singular, plural) { - if (this._cacheUsed) { this.purgeCache(); } - ember$inflector$lib$system$inflector$$loadIrregular(this.rules, [[singular, plural]]); - }, - - /** - @method pluralize - @param {String} word - */ - pluralize: function(word) { - return this._pluralize(word); - }, - - _pluralize: function(word) { - return this.inflect(word, this.rules.plurals, this.rules.irregular); - }, - /** - @method singularize - @param {String} word - */ - singularize: function(word) { - return this._singularize(word); - }, - - _singularize: function(word) { - return this.inflect(word, this.rules.singular, this.rules.irregularInverse); - }, - - /** - @protected - - @method inflect - @param {String} word - @param {Object} typeRules - @param {Object} irregular - */ - inflect: function(word, typeRules, irregular) { - var inflection, substitution, result, lowercase, wordSplit, - firstPhrase, lastWord, isBlank, isCamelized, isUncountable, - isIrregular, isIrregularInverse, rule; - - isBlank = ember$inflector$lib$system$inflector$$BLANK_REGEX.test(word); - isCamelized = ember$inflector$lib$system$inflector$$CAMELIZED_REGEX.test(word); - firstPhrase = ""; - - if (isBlank) { - return word; - } - - lowercase = word.toLowerCase(); - wordSplit = ember$inflector$lib$system$inflector$$LAST_WORD_DASHED_REGEX.exec(word) || ember$inflector$lib$system$inflector$$LAST_WORD_CAMELIZED_REGEX.exec(word); - if (wordSplit){ - firstPhrase = wordSplit[1]; - lastWord = wordSplit[2].toLowerCase(); - } - - isUncountable = this.rules.uncountable[lowercase] || this.rules.uncountable[lastWord]; - - if (isUncountable) { - return word; - } - - isIrregular = irregular && (irregular[lowercase] || irregular[lastWord]); - - if (isIrregular) { - if (irregular[lowercase]){ - return isIrregular; - } - else { - isIrregular = (isCamelized) ? ember$inflector$lib$system$inflector$$capitalize(isIrregular) : isIrregular; - return firstPhrase + isIrregular; - } - } - - for (var i = typeRules.length, min = 0; i > min; i--) { - inflection = typeRules[i-1]; - rule = inflection[0]; - - if (rule.test(word)) { - break; - } - } - - inflection = inflection || []; - - rule = inflection[0]; - substitution = inflection[1]; - - result = word.replace(rule, substitution); - - return result; - } - }; - - var ember$inflector$lib$system$inflector$$default = ember$inflector$lib$system$inflector$$Inflector; - - function ember$inflector$lib$system$string$$pluralize(word) { - return ember$inflector$lib$system$inflector$$default.inflector.pluralize(word); - } - - function ember$inflector$lib$system$string$$singularize(word) { - return ember$inflector$lib$system$inflector$$default.inflector.singularize(word); - } - - var ember$inflector$lib$system$inflections$$default = { - plurals: [ - [/$/, 's'], - [/s$/i, 's'], - [/^(ax|test)is$/i, '$1es'], - [/(octop|vir)us$/i, '$1i'], - [/(octop|vir)i$/i, '$1i'], - [/(alias|status)$/i, '$1es'], - [/(bu)s$/i, '$1ses'], - [/(buffal|tomat)o$/i, '$1oes'], - [/([ti])um$/i, '$1a'], - [/([ti])a$/i, '$1a'], - [/sis$/i, 'ses'], - [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'], - [/(hive)$/i, '$1s'], - [/([^aeiouy]|qu)y$/i, '$1ies'], - [/(x|ch|ss|sh)$/i, '$1es'], - [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'], - [/^(m|l)ouse$/i, '$1ice'], - [/^(m|l)ice$/i, '$1ice'], - [/^(ox)$/i, '$1en'], - [/^(oxen)$/i, '$1'], - [/(quiz)$/i, '$1zes'] - ], - - singular: [ - [/s$/i, ''], - [/(ss)$/i, '$1'], - [/(n)ews$/i, '$1ews'], - [/([ti])a$/i, '$1um'], - [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'], - [/(^analy)(sis|ses)$/i, '$1sis'], - [/([^f])ves$/i, '$1fe'], - [/(hive)s$/i, '$1'], - [/(tive)s$/i, '$1'], - [/([lr])ves$/i, '$1f'], - [/([^aeiouy]|qu)ies$/i, '$1y'], - [/(s)eries$/i, '$1eries'], - [/(m)ovies$/i, '$1ovie'], - [/(x|ch|ss|sh)es$/i, '$1'], - [/^(m|l)ice$/i, '$1ouse'], - [/(bus)(es)?$/i, '$1'], - [/(o)es$/i, '$1'], - [/(shoe)s$/i, '$1'], - [/(cris|test)(is|es)$/i, '$1is'], - [/^(a)x[ie]s$/i, '$1xis'], - [/(octop|vir)(us|i)$/i, '$1us'], - [/(alias|status)(es)?$/i, '$1'], - [/^(ox)en/i, '$1'], - [/(vert|ind)ices$/i, '$1ex'], - [/(matr)ices$/i, '$1ix'], - [/(quiz)zes$/i, '$1'], - [/(database)s$/i, '$1'] - ], - - irregularPairs: [ - ['person', 'people'], - ['man', 'men'], - ['child', 'children'], - ['sex', 'sexes'], - ['move', 'moves'], - ['cow', 'kine'], - ['zombie', 'zombies'] - ], - - uncountable: [ - 'equipment', - 'information', - 'rice', - 'money', - 'species', - 'series', - 'fish', - 'sheep', - 'jeans', - 'police' - ] - }; - - ember$inflector$lib$system$inflector$$default.inflector = new ember$inflector$lib$system$inflector$$default(ember$inflector$lib$system$inflections$$default); - - /** - * - * If you have Ember Inflector (such as if Ember Data is present), - * singularize a word. For example, turn "oxen" into "ox". - * - * Example: - * - * {{singularize myProperty}} - * {{singularize "oxen"}} - * - * @for Ember.Handlebars.helpers - * @method singularize - * @param {String|Property} word word to singularize - */ - Ember.Handlebars.helper('singularize', ember$inflector$lib$system$string$$singularize); - - /** - * - * If you have Ember Inflector (such as if Ember Data is present), - * pluralize a word. For example, turn "ox" into "oxen". - * - * Example: - * - * {{pluralize count myProperty}} - * {{pluralize 1 "oxen"}} - * {{pluralize myProperty}} - * {{pluralize "ox"}} - * - * @for Ember.Handlebars.helpers - * @method pluralize - * @param {Number|Property} [count] count of objects - * @param {String|Property} word word to pluralize - */ - Ember.Handlebars.helper('pluralize', function(count, word, options) { - if(arguments.length < 3) { - return ember$inflector$lib$system$string$$pluralize(count); - } else { - /* jshint eqeqeq: false */ - if(count != 1) { - /* jshint eqeqeq: true */ - word = ember$inflector$lib$system$string$$pluralize(word); - } - return count + " " + word; - } - }); - - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { - /** - See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}} - - @method pluralize - @for String - */ - String.prototype.pluralize = function() { - return ember$inflector$lib$system$string$$pluralize(this); - }; - - /** - See {{#crossLink "Ember.String/singularize"}}{{/crossLink}} - - @method singularize - @for String - */ - String.prototype.singularize = function() { - return ember$inflector$lib$system$string$$singularize(this); - }; - } - - ember$inflector$lib$system$inflector$$default.defaultRules = ember$inflector$lib$system$inflections$$default; - Ember.Inflector = ember$inflector$lib$system$inflector$$default; - - Ember.String.pluralize = ember$inflector$lib$system$string$$pluralize; - Ember.String.singularize = ember$inflector$lib$system$string$$singularize; - - var ember$inflector$lib$main$$default = ember$inflector$lib$system$inflector$$default; - - /** - @module ember-data - */ - - var activemodel$adapter$lib$system$active_model_adapter$$decamelize = Ember.String.decamelize, - activemodel$adapter$lib$system$active_model_adapter$$underscore = Ember.String.underscore; - - /** - The ActiveModelAdapter is a subclass of the RESTAdapter designed to integrate - with a JSON API that uses an underscored naming convention instead of camelCasing. - It has been designed to work out of the box with the - [active\_model\_serializers](http://github.com/rails-api/active_model_serializers) - Ruby gem. This Adapter expects specific settings using ActiveModel::Serializers, - `embed :ids, embed_in_root: true` which sideloads the records. - - This adapter extends the DS.RESTAdapter by making consistent use of the camelization, - decamelization and pluralization methods to normalize the serialized JSON into a - format that is compatible with a conventional Rails backend and Ember Data. - - ## JSON Structure - - The ActiveModelAdapter expects the JSON returned from your server to follow - the REST adapter conventions substituting underscored keys for camelcased ones. - - Unlike the DS.RESTAdapter, async relationship keys must be the singular form - of the relationship name, followed by "_id" for DS.belongsTo relationships, - or "_ids" for DS.hasMany relationships. - - ### Conventional Names - - Attribute names in your JSON payload should be the underscored versions of - the attributes in your Ember.js models. - - For example, if you have a `Person` model: - - ```js - App.FamousPerson = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string') - }); - ``` - - The JSON returned should look like this: - - ```js - { - "famous_person": { - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation": "President" - } - } - ``` - - Let's imagine that `Occupation` is just another model: - - ```js - App.Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.belongsTo('occupation') - }); - - App.Occupation = DS.Model.extend({ - name: DS.attr('string'), - salary: DS.attr('number'), - people: DS.hasMany('person') - }); - ``` - - The JSON needed to avoid extra server calls, should look like this: - - ```js - { - "people": [{ - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation_id": 1 - }], - - "occupations": [{ - "id": 1, - "name": "President", - "salary": 100000, - "person_ids": [1] - }] - } - ``` - - @class ActiveModelAdapter - @constructor - @namespace DS - @extends DS.RESTAdapter - **/ - - var activemodel$adapter$lib$system$active_model_adapter$$ActiveModelAdapter = ember$data$lib$adapters$rest_adapter$$default.extend({ - defaultSerializer: '-active-model', - /** - The ActiveModelAdapter overrides the `pathForType` method to build - underscored URLs by decamelizing and pluralizing the object type name. - - ```js - this.pathForType("famousPerson"); - //=> "famous_people" - ``` - - @method pathForType - @param {String} type - @return String - */ - pathForType: function(type) { - var decamelized = activemodel$adapter$lib$system$active_model_adapter$$decamelize(type); - var underscored = activemodel$adapter$lib$system$active_model_adapter$$underscore(decamelized); - return ember$inflector$lib$system$string$$pluralize(underscored); - }, - - /** - The ActiveModelAdapter overrides the `ajaxError` method - to return a DS.InvalidError for all 422 Unprocessable Entity - responses. - - A 422 HTTP response from the server generally implies that the request - was well formed but the API was unable to process it because the - content was not semantically correct or meaningful per the API. - - For more information on 422 HTTP Error code see 11.2 WebDAV RFC 4918 - https://tools.ietf.org/html/rfc4918#section-11.2 - - @method ajaxError - @param {Object} jqXHR - @return error - */ - ajaxError: function(jqXHR) { - var error = this._super.apply(this, arguments); - - if (jqXHR && jqXHR.status === 422) { - return new ember$data$lib$system$adapter$$InvalidError(Ember.$.parseJSON(jqXHR.responseText)); - } else { - return error; - } - } - }); - - var activemodel$adapter$lib$system$active_model_adapter$$default = activemodel$adapter$lib$system$active_model_adapter$$ActiveModelAdapter; - var ember$data$lib$serializers$json_serializer$$get = Ember.get; - var ember$data$lib$serializers$json_serializer$$isNone = Ember.isNone; - var ember$data$lib$serializers$json_serializer$$map = Ember.ArrayPolyfills.map; - var ember$data$lib$serializers$json_serializer$$merge = Ember.merge; - - var ember$data$lib$serializers$json_serializer$$default = Ember.Object.extend({ - /** - The primaryKey is used when serializing and deserializing - data. Ember Data always uses the `id` property to store the id of - the record. The external source may not always follow this - convention. In these cases it is useful to override the - primaryKey property to match the primaryKey of your external - store. - - Example - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - primaryKey: '_id' - }); - ``` - - @property primaryKey - @type {String} - @default 'id' - */ - primaryKey: 'id', - - /** - The `attrs` object can be used to declare a simple mapping between - property names on `DS.Model` records and payload keys in the - serialized JSON object representing the record. An object with the - property `key` can also be used to designate the attribute's key on - the response payload. - - Example - - ```javascript - App.Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string'), - admin: DS.attr('boolean') - }); - - App.PersonSerializer = DS.JSONSerializer.extend({ - attrs: { - admin: 'is_admin', - occupation: {key: 'career'} - } - }); - ``` - - You can also remove attributes by setting the `serialize` key to - false in your mapping object. - - Example - - ```javascript - App.PersonSerializer = DS.JSONSerializer.extend({ - attrs: { - admin: {serialize: false}, - occupation: {key: 'career'} - } - }); - ``` - - When serialized: - - ```javascript - { - "career": "magician" - } - ``` - - Note that the `admin` is now not included in the payload. - - @property attrs - @type {Object} - */ - - /** - Given a subclass of `DS.Model` and a JSON object this method will - iterate through each attribute of the `DS.Model` and invoke the - `DS.Transform#deserialize` method on the matching property of the - JSON object. This method is typically called after the - serializer's `normalize` method. - - @method applyTransforms - @private - @param {subclass of DS.Model} type - @param {Object} data The data to transform - @return {Object} data The transformed data object - */ - applyTransforms: function(type, data) { - type.eachTransformedAttribute(function applyTransform(key, type) { - if (!data.hasOwnProperty(key)) { return; } - - var transform = this.transformFor(type); - data[key] = transform.deserialize(data[key]); - }, this); - - return data; - }, - - /** - Normalizes a part of the JSON payload returned by - the server. You should override this method, munge the hash - and call super if you have generic normalization to do. - - It takes the type of the record that is being normalized - (as a DS.Model class), the property where the hash was - originally found, and the hash to normalize. - - You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. - - Example - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - normalize: function(type, hash) { - var fields = Ember.get(type, 'fields'); - fields.forEach(function(field) { - var payloadField = Ember.String.underscore(field); - if (field === payloadField) { return; } - - hash[field] = hash[payloadField]; - delete hash[payloadField]; - }); - return this._super.apply(this, arguments); - } - }); - ``` - - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash - @return {Object} - */ - normalize: function(type, hash) { - if (!hash) { return hash; } - - this.normalizeId(hash); - this.normalizeAttributes(type, hash); - this.normalizeRelationships(type, hash); - - this.normalizeUsingDeclaredMapping(type, hash); - this.applyTransforms(type, hash); - return hash; - }, - - /** - You can use this method to normalize all payloads, regardless of whether they - represent single records or an array. - - For example, you might want to remove some extraneous data from the payload: - - ```js - App.ApplicationSerializer = DS.JSONSerializer.extend({ - normalizePayload: function(payload) { - delete payload.version; - delete payload.status; - return payload; - } - }); - ``` - - @method normalizePayload - @param {Object} payload - @return {Object} the normalized payload - */ - normalizePayload: function(payload) { - return payload; - }, - - /** - @method normalizeAttributes - @private - */ - normalizeAttributes: function(type, hash) { - var payloadKey; - - if (this.keyForAttribute) { - type.eachAttribute(function(key) { - payloadKey = this.keyForAttribute(key); - if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }, this); - } - }, - - /** - @method normalizeRelationships - @private - */ - normalizeRelationships: function(type, hash) { - var payloadKey; - - if (this.keyForRelationship) { - type.eachRelationship(function(key, relationship) { - payloadKey = this.keyForRelationship(key, relationship.kind); - if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }, this); - } - }, - - /** - @method normalizeUsingDeclaredMapping - @private - */ - normalizeUsingDeclaredMapping: function(type, hash) { - var attrs = ember$data$lib$serializers$json_serializer$$get(this, 'attrs'), payloadKey, key; - - if (attrs) { - for (key in attrs) { - payloadKey = this._getMappedKey(key); - if (!hash.hasOwnProperty(payloadKey)) { continue; } - - if (payloadKey !== key) { - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - } - } - } - }, - - /** - @method normalizeId - @private - */ - normalizeId: function(hash) { - var primaryKey = ember$data$lib$serializers$json_serializer$$get(this, 'primaryKey'); - - if (primaryKey === 'id') { return; } - - hash.id = hash[primaryKey]; - delete hash[primaryKey]; - }, - - /** - @method normalizeErrors - @private - */ - normalizeErrors: function(type, hash) { - this.normalizeId(hash); - this.normalizeAttributes(type, hash); - this.normalizeRelationships(type, hash); - }, - - /** - Looks up the property key that was set by the custom `attr` mapping - passed to the serializer. - - @method _getMappedKey - @private - @param {String} key - @return {String} key - */ - _getMappedKey: function(key) { - var attrs = ember$data$lib$serializers$json_serializer$$get(this, 'attrs'); - var mappedKey; - if (attrs && attrs[key]) { - mappedKey = attrs[key]; - //We need to account for both the {title: 'post_title'} and - //{title: {key: 'post_title'}} forms - if (mappedKey.key){ - mappedKey = mappedKey.key; - } - if (typeof mappedKey === 'string'){ - key = mappedKey; - } - } - - return key; - }, - - /** - Check attrs.key.serialize property to inform if the `key` - can be serialized - - @method _canSerialize - @private - @param {String} key - @return {boolean} true if the key can be serialized - */ - _canSerialize: function(key) { - var attrs = ember$data$lib$serializers$json_serializer$$get(this, 'attrs'); - - return !attrs || !attrs[key] || attrs[key].serialize !== false; - }, - - // SERIALIZE - /** - Called when a record is saved in order to convert the - record into JSON. - - By default, it creates a JSON object with a key for - each attribute and belongsTo relationship. - - For example, consider this model: - - ```javascript - App.Comment = DS.Model.extend({ - title: DS.attr(), - body: DS.attr(), - - author: DS.belongsTo('user') - }); - ``` - - The default serialization would create a JSON object like: - - ```javascript - { - "title": "Rails is unagi", - "body": "Rails? Omakase? O_O", - "author": 12 - } - ``` - - By default, attributes are passed through as-is, unless - you specified an attribute type (`DS.attr('date')`). If - you specify a transform, the JavaScript value will be - serialized when inserted into the JSON hash. - - By default, belongs-to relationships are converted into - IDs when inserted into the JSON hash. - - ## IDs - - `serialize` takes an options hash with a single option: - `includeId`. If this option is `true`, `serialize` will, - by default include the ID in the JSON object it builds. - - The adapter passes in `includeId: true` when serializing - a record for `createRecord`, but not for `updateRecord`. - - ## Customization - - Your server may expect a different JSON format than the - built-in serialization format. - - In that case, you can implement `serialize` yourself and - return a JSON hash of your choosing. - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serialize: function(post, options) { - var json = { - POST_TTL: post.get('title'), - POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapBy('id') - } - - if (options.includeId) { - json.POST_ID_ = post.get('id'); - } - - return json; - } - }); - ``` - - ## Customizing an App-Wide Serializer - - If you want to define a serializer for your entire - application, you'll probably want to use `eachAttribute` - and `eachRelationship` on the record. - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - serialize: function(record, options) { - var json = {}; - - record.eachAttribute(function(name) { - json[serverAttributeName(name)] = record.get(name); - }) - - record.eachRelationship(function(name, relationship) { - if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = record.get(name).mapBy('id'); - } - }); - - if (options.includeId) { - json.ID_ = record.get('id'); - } - - return json; - } - }); - - function serverAttributeName(attribute) { - return attribute.underscore().toUpperCase(); - } - - function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; - } - ``` - - This serializer will generate JSON that looks like this: - - ```javascript - { - "TITLE": "Rails is omakase", - "BODY": "Yep. Omakase.", - "COMMENT_IDS": [ 1, 2, 3 ] - } - ``` - - ## Tweaking the Default JSON - - If you just want to do some small tweaks on the default JSON, - you can call super first and make the tweaks on the returned - JSON. - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serialize: function(record, options) { - var json = this._super.apply(this, arguments); - - json.subject = json.title; - delete json.title; - - return json; - } - }); - ``` - - @method serialize - @param {subclass of DS.Model} record - @param {Object} options - @return {Object} json - */ - serialize: function(record, options) { - var json = {}; - - if (options && options.includeId) { - var id = ember$data$lib$serializers$json_serializer$$get(record, 'id'); - - if (id) { - json[ember$data$lib$serializers$json_serializer$$get(this, 'primaryKey')] = id; - } - } - - record.eachAttribute(function(key, attribute) { - this.serializeAttribute(record, json, key, attribute); - }, this); - - record.eachRelationship(function(key, relationship) { - if (relationship.kind === 'belongsTo') { - this.serializeBelongsTo(record, json, relationship); - } else if (relationship.kind === 'hasMany') { - this.serializeHasMany(record, json, relationship); - } - }, this); - - return json; - }, - - /** - You can use this method to customize how a serialized record is added to the complete - JSON hash to be sent to the server. By default the JSON Serializer does not namespace - the payload and just sends the raw serialized JSON object. - If your server expects namespaced keys, you should consider using the RESTSerializer. - Otherwise you can override this method to customize how the record is added to the hash. - - For example, your server may expect underscored root objects. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { - var root = Ember.String.decamelize(type.typeKey); - data[root] = this.serialize(record, options); - } - }); - ``` - - @method serializeIntoHash - @param {Object} hash - @param {subclass of DS.Model} type - @param {DS.Model} record - @param {Object} options - */ - serializeIntoHash: function(hash, type, record, options) { - ember$data$lib$serializers$json_serializer$$merge(hash, this.serialize(record, options)); - }, - - /** - `serializeAttribute` can be used to customize how `DS.attr` - properties are serialized - - For example if you wanted to ensure all your attributes were always - serialized as properties on an `attributes` object you could - write: - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - serializeAttribute: function(record, json, key, attributes) { - json.attributes = json.attributes || {}; - this._super(record, json.attributes, key, attributes); - } - }); - ``` - - @method serializeAttribute - @param {DS.Model} record - @param {Object} json - @param {String} key - @param {Object} attribute - */ - serializeAttribute: function(record, json, key, attribute) { - var type = attribute.type; - - if (this._canSerialize(key)) { - var value = ember$data$lib$serializers$json_serializer$$get(record, key); - if (type) { - var transform = this.transformFor(type); - value = transform.serialize(value); - } - - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key); - - if (payloadKey === key && this.keyForAttribute) { - payloadKey = this.keyForAttribute(key); - } - - json[payloadKey] = value; - } - }, - - /** - `serializeBelongsTo` can be used to customize how `DS.belongsTo` - properties are serialized. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serializeBelongsTo: function(record, json, relationship) { - var key = relationship.key; - - var belongsTo = get(record, key); - - key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key; - - json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.toJSON(); - } - }); - ``` - - @method serializeBelongsTo - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeBelongsTo: function(record, json, relationship) { - var key = relationship.key; - - if (this._canSerialize(key)) { - var belongsTo = ember$data$lib$serializers$json_serializer$$get(record, key); - - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "belongsTo"); - } - - //Need to check whether the id is there for new&async records - if (ember$data$lib$serializers$json_serializer$$isNone(belongsTo) || ember$data$lib$serializers$json_serializer$$isNone(ember$data$lib$serializers$json_serializer$$get(belongsTo, 'id'))) { - json[payloadKey] = null; - } else { - json[payloadKey] = ember$data$lib$serializers$json_serializer$$get(belongsTo, 'id'); - } - - if (relationship.options.polymorphic) { - this.serializePolymorphicType(record, json, relationship); - } - } - }, - - /** - `serializeHasMany` can be used to customize how `DS.hasMany` - properties are serialized. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serializeHasMany: function(record, json, relationship) { - var key = relationship.key; - if (key === 'comments') { - return; - } else { - this._super.apply(this, arguments); - } - } - }); - ``` - - @method serializeHasMany - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeHasMany: function(record, json, relationship) { - var key = relationship.key; - - if (this._canSerialize(key)) { - var payloadKey; - - // if provided, use the mapping provided by `attrs` in - // the serializer - payloadKey = this._getMappedKey(key); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "hasMany"); - } - - var relationshipType = record.constructor.determineRelationshipType(relationship); - - if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { - json[payloadKey] = ember$data$lib$serializers$json_serializer$$get(record, key).mapBy('id'); - // TODO support for polymorphic manyToNone and manyToMany relationships - } - } - }, - - /** - You can use this method to customize how polymorphic objects are - serialized. Objects are considered to be polymorphic if - `{polymorphic: true}` is pass as the second argument to the - `DS.belongsTo` function. - - Example - - ```javascript - App.CommentSerializer = DS.JSONSerializer.extend({ - serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key, - belongsTo = get(record, key); - key = this.keyForAttribute ? this.keyForAttribute(key) : key; - - if (Ember.isNone(belongsTo)) { - json[key + "_type"] = null; - } else { - json[key + "_type"] = belongsTo.constructor.typeKey; - } - } - }); - ``` - - @method serializePolymorphicType - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType: Ember.K, - - // EXTRACT - - /** - The `extract` method is used to deserialize payload data from the - server. By default the `JSONSerializer` does not push the records - into the store. However records that subclass `JSONSerializer` - such as the `RESTSerializer` may push records into the store as - part of the extract call. - - This method delegates to a more specific extract method based on - the `requestType`. - - Example - - ```javascript - var get = Ember.get; - socket.on('message', function(message) { - var modelName = message.model; - var data = message.data; - var type = store.modelFor(modelName); - var serializer = store.serializerFor(type.typeKey); - var record = serializer.extract(store, type, data, get(data, 'id'), 'single'); - store.push(modelName, record); - }); - ``` - - @method extract - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extract: function(store, type, payload, id, requestType) { - this.extractMeta(store, type, payload); - - var specificExtract = "extract" + requestType.charAt(0).toUpperCase() + requestType.substr(1); - return this[specificExtract](store, type, payload, id, requestType); - }, - - /** - `extractFindAll` is a hook into the extract method used when a - call is made to `DS.Store#findAll`. By default this method is an - alias for [extractArray](#method_extractArray). - - @method extractFindAll - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindAll: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - /** - `extractFindQuery` is a hook into the extract method used when a - call is made to `DS.Store#findQuery`. By default this method is an - alias for [extractArray](#method_extractArray). - - @method extractFindQuery - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindQuery: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - /** - `extractFindMany` is a hook into the extract method used when a - call is made to `DS.Store#findMany`. By default this method is - alias for [extractArray](#method_extractArray). - - @method extractFindMany - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindMany: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - /** - `extractFindHasMany` is a hook into the extract method used when a - call is made to `DS.Store#findHasMany`. By default this method is - alias for [extractArray](#method_extractArray). - - @method extractFindHasMany - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindHasMany: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - - /** - `extractCreateRecord` is a hook into the extract method used when a - call is made to `DS.Model#save` and the record is new. By default - this method is alias for [extractSave](#method_extractSave). - - @method extractCreateRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractCreateRecord: function(store, type, payload, id, requestType) { - return this.extractSave(store, type, payload, id, requestType); - }, - /** - `extractUpdateRecord` is a hook into the extract method used when - a call is made to `DS.Model#save` and the record has been updated. - By default this method is alias for [extractSave](#method_extractSave). - - @method extractUpdateRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractUpdateRecord: function(store, type, payload, id, requestType) { - return this.extractSave(store, type, payload, id, requestType); - }, - /** - `extractDeleteRecord` is a hook into the extract method used when - a call is made to `DS.Model#save` and the record has been deleted. - By default this method is alias for [extractSave](#method_extractSave). - - @method extractDeleteRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractDeleteRecord: function(store, type, payload, id, requestType) { - return this.extractSave(store, type, payload, id, requestType); - }, - - /** - `extractFind` is a hook into the extract method used when - a call is made to `DS.Store#find`. By default this method is - alias for [extractSingle](#method_extractSingle). - - @method extractFind - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractFind: function(store, type, payload, id, requestType) { - return this.extractSingle(store, type, payload, id, requestType); - }, - /** - `extractFindBelongsTo` is a hook into the extract method used when - a call is made to `DS.Store#findBelongsTo`. By default this method is - alias for [extractSingle](#method_extractSingle). - - @method extractFindBelongsTo - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractFindBelongsTo: function(store, type, payload, id, requestType) { - return this.extractSingle(store, type, payload, id, requestType); - }, - /** - `extractSave` is a hook into the extract method used when a call - is made to `DS.Model#save`. By default this method is alias - for [extractSingle](#method_extractSingle). - - @method extractSave - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractSave: function(store, type, payload, id, requestType) { - return this.extractSingle(store, type, payload, id, requestType); - }, - - /** - `extractSingle` is used to deserialize a single record returned - from the adapter. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractSingle: function(store, type, payload) { - payload.comments = payload._embedded.comment; - delete payload._embedded; - - return this._super(store, type, payload); - }, - }); - ``` - - @method extractSingle - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractSingle: function(store, type, payload, id, requestType) { - payload = this.normalizePayload(payload); - return this.normalize(type, payload); - }, - - /** - `extractArray` is used to deserialize an array of records - returned from the adapter. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractArray: function(store, type, payload) { - return payload.map(function(json) { - return this.extractSingle(store, type, json); - }, this); - } - }); - ``` - - @method extractArray - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractArray: function(store, type, arrayPayload, id, requestType) { - var normalizedPayload = this.normalizePayload(arrayPayload); - var serializer = this; - - return ember$data$lib$serializers$json_serializer$$map.call(normalizedPayload, function(singlePayload) { - return serializer.normalize(type, singlePayload); - }); - }, - - /** - `extractMeta` is used to deserialize any meta information in the - adapter payload. By default Ember Data expects meta information to - be located on the `meta` property of the payload object. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractMeta: function(store, type, payload) { - if (payload && payload._pagination) { - store.setMetadataFor(type, payload._pagination); - delete payload._pagination; - } - } - }); - ``` - - @method extractMeta - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - */ - extractMeta: function(store, type, payload) { - if (payload && payload.meta) { - store.setMetadataFor(type, payload.meta); - delete payload.meta; - } - }, - - /** - `extractErrors` is used to extract model errors when a call is made - to `DS.Model#save` which fails with an InvalidError`. By default - Ember Data expects error information to be located on the `errors` - property of the payload object. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractErrors: function(store, type, payload, id) { - if (payload && typeof payload === 'object' && payload._problems) { - payload = payload._problems; - this.normalizeErrors(type, payload); - } - return payload; - } - }); - ``` - - @method extractErrors - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @return {Object} json The deserialized errors - */ - extractErrors: function(store, type, payload, id) { - if (payload && typeof payload === 'object' && payload.errors) { - payload = payload.errors; - this.normalizeErrors(type, payload); - } - return payload; - }, - - /** - `keyForAttribute` can be used to define rules for how to convert an - attribute name in your model to a key in your JSON. - - Example - - ```javascript - App.ApplicationSerializer = DS.RESTSerializer.extend({ - keyForAttribute: function(attr) { - return Ember.String.underscore(attr).toUpperCase(); - } - }); - ``` - - @method keyForAttribute - @param {String} key - @return {String} normalized key - */ - keyForAttribute: function(key){ - return key; - }, - - /** - `keyForRelationship` can be used to define a custom key when - serializing relationship properties. By default `JSONSerializer` - does not provide an implementation of this method. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - keyForRelationship: function(key, relationship) { - return 'rel_' + Ember.String.underscore(key); - } - }); - ``` - - @method keyForRelationship - @param {String} key - @param {String} relationship type - @return {String} normalized key - */ - - keyForRelationship: function(key, type){ - return key; - }, - - // HELPERS - - /** - @method transformFor - @private - @param {String} attributeType - @param {Boolean} skipAssertion - @return {DS.Transform} transform - */ - transformFor: function(attributeType, skipAssertion) { - var transform = this.container.lookup('transform:' + attributeType); - Ember.assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform); - return transform; - } - }); - - var ember$data$lib$serializers$rest_serializer$$get = Ember.get; - var ember$data$lib$serializers$rest_serializer$$forEach = Ember.ArrayPolyfills.forEach; - var ember$data$lib$serializers$rest_serializer$$map = Ember.ArrayPolyfills.map; - var ember$data$lib$serializers$rest_serializer$$camelize = Ember.String.camelize; - - function ember$data$lib$serializers$rest_serializer$$coerceId(id) { - return id == null ? null : id + ''; - } - - /** - Normally, applications will use the `RESTSerializer` by implementing - the `normalize` method and individual normalizations under - `normalizeHash`. - - This allows you to do whatever kind of munging you need, and is - especially useful if your server is inconsistent and you need to - do munging differently for many different kinds of responses. - - See the `normalize` documentation for more information. - - ## Across the Board Normalization - - There are also a number of hooks that you might find useful to define - across-the-board rules for your payload. These rules will be useful - if your server is consistent, or if you're building an adapter for - an infrastructure service, like Parse, and want to encode service - conventions. - - For example, if all of your keys are underscored and all-caps, but - otherwise consistent with the names you use in your models, you - can implement across-the-board rules for how to convert an attribute - name in your model to a key in your JSON. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - keyForAttribute: function(attr) { - return Ember.String.underscore(attr).toUpperCase(); - } - }); - ``` - - You can also implement `keyForRelationship`, which takes the name - of the relationship as the first parameter, and the kind of - relationship (`hasMany` or `belongsTo`) as the second parameter. - - @class RESTSerializer - @namespace DS - @extends DS.JSONSerializer - */ - var ember$data$lib$serializers$rest_serializer$$RESTSerializer = ember$data$lib$serializers$json_serializer$$default.extend({ - /** - If you want to do normalizations specific to some part of the payload, you - can specify those under `normalizeHash`. - - For example, given the following json where the the `IDs` under - `"comments"` are provided as `_id` instead of `id`. - - ```javascript - { - "post": { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2 ] - }, - "comments": [{ - "_id": 1, - "body": "FIRST" - }, { - "_id": 2, - "body": "Rails is unagi" - }] - } - ``` - - You use `normalizeHash` to normalize just the comments: - - ```javascript - App.PostSerializer = DS.RESTSerializer.extend({ - normalizeHash: { - comments: function(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - }); - ``` - - The key under `normalizeHash` is usually just the original key - that was in the original payload. However, key names will be - impacted by any modifications done in the `normalizePayload` - method. The `DS.RESTSerializer`'s default implementation makes no - changes to the payload keys. - - @property normalizeHash - @type {Object} - @default undefined - */ - - /** - Normalizes a part of the JSON payload returned by - the server. You should override this method, munge the hash - and call super if you have generic normalization to do. - - It takes the type of the record that is being normalized - (as a DS.Model class), the property where the hash was - originally found, and the hash to normalize. - - For example, if you have a payload that looks like this: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2 ] - }, - "comments": [{ - "id": 1, - "body": "FIRST" - }, { - "id": 2, - "body": "Rails is unagi" - }] - } - ``` - - The `normalize` method will be called three times: - - * With `App.Post`, `"posts"` and `{ id: 1, title: "Rails is omakase", ... }` - * With `App.Comment`, `"comments"` and `{ id: 1, body: "FIRST" }` - * With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }` - - You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. - - If you want to do normalizations specific to some part of the payload, you - can specify those under `normalizeHash`. - - For example, if the `IDs` under `"comments"` are provided as `_id` instead of - `id`, you can specify how to normalize just the comments: - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - normalizeHash: { - comments: function(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - }); - ``` - - The key under `normalizeHash` is just the original key that was in the original - payload. - - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash - @param {String} prop - @return {Object} - */ - normalize: function(type, hash, prop) { - this.normalizeId(hash); - this.normalizeAttributes(type, hash); - this.normalizeRelationships(type, hash); - - this.normalizeUsingDeclaredMapping(type, hash); - - if (this.normalizeHash && this.normalizeHash[prop]) { - this.normalizeHash[prop](hash); - } - - this.applyTransforms(type, hash); - return hash; - }, - - - /** - Called when the server has returned a payload representing - a single record, such as in response to a `find` or `save`. - - It is your opportunity to clean up the server's response into the normalized - form expected by Ember Data. - - If you want, you can just restructure the top-level of your payload, and - do more fine-grained normalization in the `normalize` method. - - For example, if you have a payload like this in response to a request for - post 1: - - ```js - { - "id": 1, - "title": "Rails is omakase", - - "_embedded": { - "comment": [{ - "_id": 1, - "comment_title": "FIRST" - }, { - "_id": 2, - "comment_title": "Rails is unagi" - }] - } - } - ``` - - You could implement a serializer that looks like this to get your payload - into shape: - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - // First, restructure the top-level so it's organized by type - extractSingle: function(store, type, payload, id) { - var comments = payload._embedded.comment; - delete payload._embedded; - - payload = { comments: comments, post: payload }; - return this._super(store, type, payload, id); - }, - - normalizeHash: { - // Next, normalize individual comments, which (after `extract`) - // are now located under `comments` - comments: function(hash) { - hash.id = hash._id; - hash.title = hash.comment_title; - delete hash._id; - delete hash.comment_title; - return hash; - } - } - }) - ``` - - When you call super from your own implementation of `extractSingle`, the - built-in implementation will find the primary record in your normalized - payload and push the remaining records into the store. - - The primary record is the single hash found under `post` or the first - element of the `posts` array. - - The primary record has special meaning when the record is being created - for the first time or updated (`createRecord` or `updateRecord`). In - particular, it will update the properties of the record that was saved. - - @method extractSingle - @param {DS.Store} store - @param {subclass of DS.Model} primaryType - @param {Object} payload - @param {String} recordId - @return {Object} the primary response to the original request - */ - extractSingle: function(store, primaryType, rawPayload, recordId) { - var payload = this.normalizePayload(rawPayload); - var primaryTypeName = primaryType.typeKey; - var primaryRecord; - - for (var prop in payload) { - var typeName = this.typeForRoot(prop); - - if (!store.modelFactoryFor(typeName)){ - Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); - continue; - } - var type = store.modelFor(typeName); - var isPrimary = type.typeKey === primaryTypeName; - var value = payload[prop]; - - if (value === null) { - continue; - } - - // legacy support for singular resources - if (isPrimary && Ember.typeOf(value) !== "array" ) { - primaryRecord = this.normalize(primaryType, value, prop); - continue; - } - - /*jshint loopfunc:true*/ - ember$data$lib$serializers$rest_serializer$$forEach.call(value, function(hash) { - var typeName = this.typeForRoot(prop); - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - - hash = typeSerializer.normalize(type, hash, prop); - - var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord; - var isUpdatedRecord = isPrimary && ember$data$lib$serializers$rest_serializer$$coerceId(hash.id) === recordId; - - // find the primary record. - // - // It's either: - // * the record with the same ID as the original request - // * in the case of a newly created record that didn't have an ID, the first - // record in the Array - if (isFirstCreatedRecord || isUpdatedRecord) { - primaryRecord = hash; - } else { - store.push(typeName, hash); - } - }, this); - } - - return primaryRecord; - }, - - /** - Called when the server has returned a payload representing - multiple records, such as in response to a `findAll` or `findQuery`. - - It is your opportunity to clean up the server's response into the normalized - form expected by Ember Data. - - If you want, you can just restructure the top-level of your payload, and - do more fine-grained normalization in the `normalize` method. - - For example, if you have a payload like this in response to a request for - all posts: - - ```js - { - "_embedded": { - "post": [{ - "id": 1, - "title": "Rails is omakase" - }, { - "id": 2, - "title": "The Parley Letter" - }], - "comment": [{ - "_id": 1, - "comment_title": "Rails is unagi" - "post_id": 1 - }, { - "_id": 2, - "comment_title": "Don't tread on me", - "post_id": 2 - }] - } - } - ``` - - You could implement a serializer that looks like this to get your payload - into shape: - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - // First, restructure the top-level so it's organized by type - // and the comments are listed under a post's `comments` key. - extractArray: function(store, type, payload) { - var posts = payload._embedded.post; - var comments = []; - var postCache = {}; - - posts.forEach(function(post) { - post.comments = []; - postCache[post.id] = post; - }); - - payload._embedded.comment.forEach(function(comment) { - comments.push(comment); - postCache[comment.post_id].comments.push(comment); - delete comment.post_id; - }); - - payload = { comments: comments, posts: payload }; - - return this._super(store, type, payload); - }, - - normalizeHash: { - // Next, normalize individual comments, which (after `extract`) - // are now located under `comments` - comments: function(hash) { - hash.id = hash._id; - hash.title = hash.comment_title; - delete hash._id; - delete hash.comment_title; - return hash; - } - } - }) - ``` - - When you call super from your own implementation of `extractArray`, the - built-in implementation will find the primary array in your normalized - payload and push the remaining records into the store. - - The primary array is the array found under `posts`. - - The primary record has special meaning when responding to `findQuery` - or `findHasMany`. In particular, the primary array will become the - list of records in the record array that kicked off the request. - - If your primary array contains secondary (embedded) records of the same type, - you cannot place these into the primary array `posts`. Instead, place the - secondary items into an underscore prefixed property `_posts`, which will - push these items into the store and will not affect the resulting query. - - @method extractArray - @param {DS.Store} store - @param {subclass of DS.Model} primaryType - @param {Object} payload - @return {Array} The primary array that was returned in response - to the original query. - */ - extractArray: function(store, primaryType, rawPayload) { - var payload = this.normalizePayload(rawPayload); - var primaryTypeName = primaryType.typeKey; - var primaryArray; - - for (var prop in payload) { - var typeKey = prop; - var forcedSecondary = false; - - if (prop.charAt(0) === '_') { - forcedSecondary = true; - typeKey = prop.substr(1); - } - - var typeName = this.typeForRoot(typeKey); - if (!store.modelFactoryFor(typeName)) { - Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); - continue; - } - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - var isPrimary = (!forcedSecondary && (type.typeKey === primaryTypeName)); - - /*jshint loopfunc:true*/ - var normalizedArray = ember$data$lib$serializers$rest_serializer$$map.call(payload[prop], function(hash) { - return typeSerializer.normalize(type, hash, prop); - }, this); - - if (isPrimary) { - primaryArray = normalizedArray; - } else { - store.pushMany(typeName, normalizedArray); - } - } - - return primaryArray; - }, - - /** - This method allows you to push a payload containing top-level - collections of records organized per type. - - ```js - { - "posts": [{ - "id": "1", - "title": "Rails is omakase", - "author", "1", - "comments": [ "1" ] - }], - "comments": [{ - "id": "1", - "body": "FIRST" - }], - "users": [{ - "id": "1", - "name": "@d2h" - }] - } - ``` - - It will first normalize the payload, so you can use this to push - in data streaming in from your server structured the same way - that fetches and saves are structured. - - @method pushPayload - @param {DS.Store} store - @param {Object} payload - */ - pushPayload: function(store, rawPayload) { - var payload = this.normalizePayload(rawPayload); - - for (var prop in payload) { - var typeName = this.typeForRoot(prop); - if (!store.modelFactoryFor(typeName, prop)){ - Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false); - continue; - } - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - - /*jshint loopfunc:true*/ - var normalizedArray = ember$data$lib$serializers$rest_serializer$$map.call(Ember.makeArray(payload[prop]), function(hash) { - return typeSerializer.normalize(type, hash, prop); - }, this); - - store.pushMany(typeName, normalizedArray); - } - }, - - /** - This method is used to convert each JSON root key in the payload - into a typeKey that it can use to look up the appropriate model for - that part of the payload. By default the typeKey for a model is its - name in camelCase, so if your JSON root key is 'fast-car' you would - use typeForRoot to convert it to 'fastCar' so that Ember Data finds - the `FastCar` model. - - If you diverge from this norm you should also consider changes to - store._normalizeTypeKey as well. - - For example, your server may return prefixed root keys like so: - - ```js - { - "response-fast-car": { - "id": "1", - "name": "corvette" - } - } - ``` - - In order for Ember Data to know that the model corresponding to - the 'response-fast-car' hash is `FastCar` (typeKey: 'fastCar'), - you can override typeForRoot to convert 'response-fast-car' to - 'fastCar' like so: - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - typeForRoot: function(root) { - // 'response-fast-car' should become 'fast-car' - var subRoot = root.substring(9); - - // _super normalizes 'fast-car' to 'fastCar' - return this._super(subRoot); - } - }); - ``` - - @method typeForRoot - @param {String} key - @return {String} the model's typeKey - */ - typeForRoot: function(key) { - return ember$data$lib$serializers$rest_serializer$$camelize(ember$inflector$lib$system$string$$singularize(key)); - }, - - // SERIALIZE - - /** - Called when a record is saved in order to convert the - record into JSON. - - By default, it creates a JSON object with a key for - each attribute and belongsTo relationship. - - For example, consider this model: - - ```js - App.Comment = DS.Model.extend({ - title: DS.attr(), - body: DS.attr(), - - author: DS.belongsTo('user') - }); - ``` - - The default serialization would create a JSON object like: - - ```js - { - "title": "Rails is unagi", - "body": "Rails? Omakase? O_O", - "author": 12 - } - ``` - - By default, attributes are passed through as-is, unless - you specified an attribute type (`DS.attr('date')`). If - you specify a transform, the JavaScript value will be - serialized when inserted into the JSON hash. - - By default, belongs-to relationships are converted into - IDs when inserted into the JSON hash. - - ## IDs - - `serialize` takes an options hash with a single option: - `includeId`. If this option is `true`, `serialize` will, - by default include the ID in the JSON object it builds. - - The adapter passes in `includeId: true` when serializing - a record for `createRecord`, but not for `updateRecord`. - - ## Customization - - Your server may expect a different JSON format than the - built-in serialization format. - - In that case, you can implement `serialize` yourself and - return a JSON hash of your choosing. - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - serialize: function(post, options) { - var json = { - POST_TTL: post.get('title'), - POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapBy('id') - } - - if (options.includeId) { - json.POST_ID_ = post.get('id'); - } - - return json; - } - }); - ``` - - ## Customizing an App-Wide Serializer - - If you want to define a serializer for your entire - application, you'll probably want to use `eachAttribute` - and `eachRelationship` on the record. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - serialize: function(record, options) { - var json = {}; - - record.eachAttribute(function(name) { - json[serverAttributeName(name)] = record.get(name); - }) - - record.eachRelationship(function(name, relationship) { - if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = record.get(name).mapBy('id'); - } - }); - - if (options.includeId) { - json.ID_ = record.get('id'); - } - - return json; - } - }); - - function serverAttributeName(attribute) { - return attribute.underscore().toUpperCase(); - } - - function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; - } - ``` - - This serializer will generate JSON that looks like this: - - ```js - { - "TITLE": "Rails is omakase", - "BODY": "Yep. Omakase.", - "COMMENT_IDS": [ 1, 2, 3 ] - } - ``` - - ## Tweaking the Default JSON - - If you just want to do some small tweaks on the default JSON, - you can call super first and make the tweaks on the returned - JSON. - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - serialize: function(record, options) { - var json = this._super(record, options); - - json.subject = json.title; - delete json.title; - - return json; - } - }); - ``` - - @method serialize - @param {subclass of DS.Model} record - @param {Object} options - @return {Object} json - */ - serialize: function(record, options) { - return this._super.apply(this, arguments); - }, - - /** - You can use this method to customize the root keys serialized into the JSON. - By default the REST Serializer sends the typeKey of a model, which is a camelized - version of the name. - - For example, your server may expect underscored root objects. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { - var root = Ember.String.decamelize(type.typeKey); - data[root] = this.serialize(record, options); - } - }); - ``` - - @method serializeIntoHash - @param {Object} hash - @param {subclass of DS.Model} type - @param {DS.Model} record - @param {Object} options - */ - serializeIntoHash: function(hash, type, record, options) { - hash[type.typeKey] = this.serialize(record, options); - }, - - /** - You can use this method to customize how polymorphic objects are serialized. - By default the JSON Serializer creates the key by appending `Type` to - the attribute and value from the model's camelcased model name. - - @method serializePolymorphicType - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key; - var belongsTo = ember$data$lib$serializers$rest_serializer$$get(record, key); - key = this.keyForAttribute ? this.keyForAttribute(key) : key; - if (Ember.isNone(belongsTo)) { - json[key + "Type"] = null; - } else { - json[key + "Type"] = Ember.String.camelize(belongsTo.constructor.typeKey); - } - } - }); - - Ember.runInDebug(function(){ - ember$data$lib$serializers$rest_serializer$$RESTSerializer.reopen({ - warnMessageNoModelForKey: function(prop, typeKey){ - return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.typeForRoot("' + prop + '"))'; - } - }); - }); - - var ember$data$lib$serializers$rest_serializer$$default = ember$data$lib$serializers$rest_serializer$$RESTSerializer; - /** - @module ember-data - */ - - var activemodel$adapter$lib$system$active_model_serializer$$get = Ember.get, - activemodel$adapter$lib$system$active_model_serializer$$forEach = Ember.EnumerableUtils.forEach, - activemodel$adapter$lib$system$active_model_serializer$$camelize = Ember.String.camelize, - activemodel$adapter$lib$system$active_model_serializer$$capitalize = Ember.String.capitalize, - activemodel$adapter$lib$system$active_model_serializer$$decamelize = Ember.String.decamelize, - activemodel$adapter$lib$system$active_model_serializer$$underscore = Ember.String.underscore; - /** - The ActiveModelSerializer is a subclass of the RESTSerializer designed to integrate - with a JSON API that uses an underscored naming convention instead of camelCasing. - It has been designed to work out of the box with the - [active\_model\_serializers](http://github.com/rails-api/active_model_serializers) - Ruby gem. This Serializer expects specific settings using ActiveModel::Serializers, - `embed :ids, embed_in_root: true` which sideloads the records. - - This serializer extends the DS.RESTSerializer by making consistent - use of the camelization, decamelization and pluralization methods to - normalize the serialized JSON into a format that is compatible with - a conventional Rails backend and Ember Data. - - ## JSON Structure - - The ActiveModelSerializer expects the JSON returned from your server - to follow the REST adapter conventions substituting underscored keys - for camelcased ones. - - ### Conventional Names - - Attribute names in your JSON payload should be the underscored versions of - the attributes in your Ember.js models. - - For example, if you have a `Person` model: - - ```js - App.FamousPerson = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string') - }); - ``` - - The JSON returned should look like this: - - ```js - { - "famous_person": { - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation": "President" - } - } - ``` - - Let's imagine that `Occupation` is just another model: - - ```js - App.Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.belongsTo('occupation') - }); - - App.Occupation = DS.Model.extend({ - name: DS.attr('string'), - salary: DS.attr('number'), - people: DS.hasMany('person') - }); - ``` - - The JSON needed to avoid extra server calls, should look like this: - - ```js - { - "people": [{ - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation_id": 1 - }], - - "occupations": [{ - "id": 1, - "name": "President", - "salary": 100000, - "person_ids": [1] - }] - } - ``` - - @class ActiveModelSerializer - @namespace DS - @extends DS.RESTSerializer - */ - var activemodel$adapter$lib$system$active_model_serializer$$ActiveModelSerializer = ember$data$lib$serializers$rest_serializer$$default.extend({ - // SERIALIZE - - /** - Converts camelCased attributes to underscored when serializing. - - @method keyForAttribute - @param {String} attribute - @return String - */ - keyForAttribute: function(attr) { - return activemodel$adapter$lib$system$active_model_serializer$$decamelize(attr); - }, - - /** - Underscores relationship names and appends "_id" or "_ids" when serializing - relationship keys. - - @method keyForRelationship - @param {String} key - @param {String} kind - @return String - */ - keyForRelationship: function(rawKey, kind) { - var key = activemodel$adapter$lib$system$active_model_serializer$$decamelize(rawKey); - if (kind === "belongsTo") { - return key + "_id"; - } else if (kind === "hasMany") { - return ember$inflector$lib$system$string$$singularize(key) + "_ids"; - } else { - return key; - } - }, - - /* - Does not serialize hasMany relationships by default. - */ - serializeHasMany: Ember.K, - - /** - Underscores the JSON root keys when serializing. - - @method serializeIntoHash - @param {Object} hash - @param {subclass of DS.Model} type - @param {DS.Model} record - @param {Object} options - */ - serializeIntoHash: function(data, type, record, options) { - var root = activemodel$adapter$lib$system$active_model_serializer$$underscore(activemodel$adapter$lib$system$active_model_serializer$$decamelize(type.typeKey)); - data[root] = this.serialize(record, options); - }, - - /** - Serializes a polymorphic type as a fully capitalized model name. - - @method serializePolymorphicType - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key; - var belongsTo = activemodel$adapter$lib$system$active_model_serializer$$get(record, key); - var jsonKey = activemodel$adapter$lib$system$active_model_serializer$$underscore(key + "_type"); - - if (Ember.isNone(belongsTo)) { - json[jsonKey] = null; - } else { - json[jsonKey] = activemodel$adapter$lib$system$active_model_serializer$$capitalize(activemodel$adapter$lib$system$active_model_serializer$$camelize(belongsTo.constructor.typeKey)); - } - }, - - // EXTRACT - - /** - Add extra step to `DS.RESTSerializer.normalize` so links are normalized. - - If your payload looks like: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "links": { "flagged_comments": "api/comments/flagged" } - } - } - ``` - - The normalized version would look like this - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "links": { "flaggedComments": "api/comments/flagged" } - } - } - ``` - - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash - @param {String} prop - @return Object - */ - - normalize: function(type, hash, prop) { - this.normalizeLinks(hash); - - return this._super(type, hash, prop); - }, - - /** - Convert `snake_cased` links to `camelCase` - - @method normalizeLinks - @param {Object} data - */ - - normalizeLinks: function(data){ - if (data.links) { - var links = data.links; - - for (var link in links) { - var camelizedLink = activemodel$adapter$lib$system$active_model_serializer$$camelize(link); - - if (camelizedLink !== link) { - links[camelizedLink] = links[link]; - delete links[link]; - } - } - } - }, - - /** - Normalize the polymorphic type from the JSON. - - Normalize: - ```js - { - id: "1" - minion: { type: "evil_minion", id: "12"} - } - ``` - - To: - ```js - { - id: "1" - minion: { type: "evilMinion", id: "12"} - } - ``` - - @method normalizeRelationships - @private - */ - normalizeRelationships: function(type, hash) { - - if (this.keyForRelationship) { - type.eachRelationship(function(key, relationship) { - var payloadKey, payload; - if (relationship.options.polymorphic) { - payloadKey = this.keyForAttribute(key); - payload = hash[payloadKey]; - if (payload && payload.type) { - payload.type = this.typeForRoot(payload.type); - } else if (payload && relationship.kind === "hasMany") { - var self = this; - activemodel$adapter$lib$system$active_model_serializer$$forEach(payload, function(single) { - single.type = self.typeForRoot(single.type); - }); - } - } else { - payloadKey = this.keyForRelationship(key, relationship.kind); - if (!hash.hasOwnProperty(payloadKey)) { return; } - payload = hash[payloadKey]; - } - - hash[key] = payload; - - if (key !== payloadKey) { - delete hash[payloadKey]; - } - }, this); - } - } - }); - - var activemodel$adapter$lib$system$active_model_serializer$$default = activemodel$adapter$lib$system$active_model_serializer$$ActiveModelSerializer; - /** - This is used internally to enable deprecation of container paths and provide - a decent message to the user indicating how to fix the issue. - - @class ContainerProxy - @namespace DS - @private - */ - function ember$data$lib$system$container_proxy$$ContainerProxy(container){ - this.container = container; - } - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.aliasedFactory = function(path, preLookup) { - var _this = this; - - return {create: function(){ - if (preLookup) { preLookup(); } - - return _this.container.lookup(path); - }}; - }; - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.registerAlias = function(source, dest, preLookup) { - var factory = this.aliasedFactory(dest, preLookup); - - return this.container.register(source, factory); - }; - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) { - var preLookupCallback = function(){ - Ember.deprecate("You tried to look up '" + deprecated + "', " + - "but this has been deprecated in favor of '" + valid + "'.", false); - }; - - return this.registerAlias(deprecated, valid, preLookupCallback); - }; - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.registerDeprecations = function(proxyPairs) { - var i, proxyPair, deprecated, valid; - - for (i = proxyPairs.length; i > 0; i--) { - proxyPair = proxyPairs[i - 1]; - deprecated = proxyPair['deprecated']; - valid = proxyPair['valid']; - - this.registerDeprecation(deprecated, valid); - } - }; - - var ember$data$lib$system$container_proxy$$default = ember$data$lib$system$container_proxy$$ContainerProxy; - function activemodel$adapter$lib$setup$container$$setupActiveModelAdapter(container, application){ - var proxy = new ember$data$lib$system$container_proxy$$default(container); - proxy.registerDeprecations([ - { deprecated: 'serializer:_ams', valid: 'serializer:-active-model' }, - { deprecated: 'adapter:_ams', valid: 'adapter:-active-model' } - ]); - - container.register('serializer:-active-model', activemodel$adapter$lib$system$active_model_serializer$$default); - container.register('adapter:-active-model', activemodel$adapter$lib$system$active_model_adapter$$default); - } - var activemodel$adapter$lib$setup$container$$default = activemodel$adapter$lib$setup$container$$setupActiveModelAdapter; - /** - @module ember-data - */ - - /** - All Ember Data methods and functions are defined inside of this namespace. - - @class DS - @static - */ - - /** - @property VERSION - @type String - @default '1.0.0-beta.14.1' - @static - */ - /*jshint -W079 */ - var ember$data$lib$core$$DS = Ember.Namespace.create({ - VERSION: '1.0.0-beta.14.1' - }); - - if (Ember.libraries) { - Ember.libraries.registerCoreLibrary('Ember Data', ember$data$lib$core$$DS.VERSION); - } - - var ember$data$lib$core$$default = ember$data$lib$core$$DS; - var ember$data$lib$system$promise_proxies$$Promise = Ember.RSVP.Promise; - var ember$data$lib$system$promise_proxies$$get = Ember.get; - - /** - A `PromiseArray` is an object that acts like both an `Ember.Array` - and a promise. When the promise is resolved the resulting value - will be set to the `PromiseArray`'s `content` property. This makes - it easy to create data bindings with the `PromiseArray` that will be - updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - var promiseArray = DS.PromiseArray.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseArray.get('length'); // 0 - - promiseArray.then(function() { - promiseArray.get('length'); // 100 - }); - ``` - - @class PromiseArray - @namespace DS - @extends Ember.ArrayProxy - @uses Ember.PromiseProxyMixin - */ - var ember$data$lib$system$promise_proxies$$PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); - - /** - A `PromiseObject` is an object that acts like both an `Ember.Object` - and a promise. When the promise is resolved, then the resulting value - will be set to the `PromiseObject`'s `content` property. This makes - it easy to create data bindings with the `PromiseObject` that will - be updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - var promiseObject = DS.PromiseObject.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseObject.get('name'); // null - - promiseObject.then(function() { - promiseObject.get('name'); // 'Tomster' - }); - ``` - - @class PromiseObject - @namespace DS - @extends Ember.ObjectProxy - @uses Ember.PromiseProxyMixin - */ - var ember$data$lib$system$promise_proxies$$PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); - - var ember$data$lib$system$promise_proxies$$promiseObject = function(promise, label) { - return ember$data$lib$system$promise_proxies$$PromiseObject.create({ - promise: ember$data$lib$system$promise_proxies$$Promise.resolve(promise, label) - }); - }; - - var ember$data$lib$system$promise_proxies$$promiseArray = function(promise, label) { - return ember$data$lib$system$promise_proxies$$PromiseArray.create({ - promise: ember$data$lib$system$promise_proxies$$Promise.resolve(promise, label) - }); - }; - - /** - A PromiseManyArray is a PromiseArray that also proxies certain method calls - to the underlying manyArray. - Right now we proxy: - - * `reload()` - * `createRecord()` - * `on()` - * `one()` - * `trigger()` - * `off()` - * `has()` - - @class PromiseManyArray - @namespace DS - @extends Ember.ArrayProxy - */ - - function ember$data$lib$system$promise_proxies$$proxyToContent(method) { - return function() { - var content = ember$data$lib$system$promise_proxies$$get(this, 'content'); - return content[method].apply(content, arguments); - }; - } - - var ember$data$lib$system$promise_proxies$$PromiseManyArray = ember$data$lib$system$promise_proxies$$PromiseArray.extend({ - reload: function() { - //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships - Ember.assert('You are trying to reload an async manyArray before it has been created', ember$data$lib$system$promise_proxies$$get(this, 'content')); - return ember$data$lib$system$promise_proxies$$PromiseManyArray.create({ - promise: ember$data$lib$system$promise_proxies$$get(this, 'content').reload() - }); - }, - - createRecord: ember$data$lib$system$promise_proxies$$proxyToContent('createRecord'), - - on: ember$data$lib$system$promise_proxies$$proxyToContent('on'), - - one: ember$data$lib$system$promise_proxies$$proxyToContent('one'), - - trigger: ember$data$lib$system$promise_proxies$$proxyToContent('trigger'), - - off: ember$data$lib$system$promise_proxies$$proxyToContent('off'), - - has: ember$data$lib$system$promise_proxies$$proxyToContent('has') - }); - - var ember$data$lib$system$promise_proxies$$promiseManyArray = function(promise, label) { - return ember$data$lib$system$promise_proxies$$PromiseManyArray.create({ - promise: ember$data$lib$system$promise_proxies$$Promise.resolve(promise, label) - }); - }; - - - var ember$data$lib$system$record_arrays$record_array$$get = Ember.get; - var ember$data$lib$system$record_arrays$record_array$$set = Ember.set; - - var ember$data$lib$system$record_arrays$record_array$$default = Ember.ArrayProxy.extend(Ember.Evented, { - /** - The model type contained by this record array. - - @property type - @type DS.Model - */ - type: null, - - /** - The array of client ids backing the record array. When a - record is requested from the record array, the record - for the client id at the same index is materialized, if - necessary, by the store. - - @property content - @private - @type Ember.Array - */ - content: null, - - /** - The flag to signal a `RecordArray` is currently loading data. - - Example - - ```javascript - var people = store.all('person'); - people.get('isLoaded'); // true - ``` - - @property isLoaded - @type Boolean - */ - isLoaded: false, - /** - The flag to signal a `RecordArray` is currently loading data. - - Example - - ```javascript - var people = store.all('person'); - people.get('isUpdating'); // false - people.update(); - people.get('isUpdating'); // true - ``` - - @property isUpdating - @type Boolean - */ - isUpdating: false, - - /** - The store that created this record array. - - @property store - @private - @type DS.Store - */ - store: null, - - /** - Retrieves an object from the content by index. - - @method objectAtContent - @private - @param {Number} index - @return {DS.Model} record - */ - objectAtContent: function(index) { - var content = ember$data$lib$system$record_arrays$record_array$$get(this, 'content'); - - return content.objectAt(index); - }, - - /** - Used to get the latest version of all of the records in this array - from the adapter. - - Example - - ```javascript - var people = store.all('person'); - people.get('isUpdating'); // false - people.update(); - people.get('isUpdating'); // true - ``` - - @method update - */ - update: function() { - if (ember$data$lib$system$record_arrays$record_array$$get(this, 'isUpdating')) { return; } - - var store = ember$data$lib$system$record_arrays$record_array$$get(this, 'store'); - var type = ember$data$lib$system$record_arrays$record_array$$get(this, 'type'); - - return store.fetchAll(type, this); - }, - - /** - Adds a record to the `RecordArray` without duplicates - - @method addRecord - @private - @param {DS.Model} record - @param {DS.Model} an optional index to insert at - */ - addRecord: function(record, idx) { - var content = ember$data$lib$system$record_arrays$record_array$$get(this, 'content'); - if (idx === undefined) { - content.addObject(record); - } else { - if (!content.contains(record)) { - content.insertAt(idx, record); - } - } - }, - - /** - Adds a record to the `RecordArray`, but allows duplicates - - @method pushRecord - @private - @param {DS.Model} record - */ - pushRecord: function(record) { - ember$data$lib$system$record_arrays$record_array$$get(this, 'content').pushObject(record); - }, - /** - Removes a record to the `RecordArray`. - - @method removeRecord - @private - @param {DS.Model} record - */ - removeRecord: function(record) { - ember$data$lib$system$record_arrays$record_array$$get(this, 'content').removeObject(record); - }, - - /** - Saves all of the records in the `RecordArray`. - - Example - - ```javascript - var messages = store.all('message'); - messages.forEach(function(message) { - message.set('hasBeenSeen', true); - }); - messages.save(); - ``` - - @method save - @return {DS.PromiseArray} promise - */ - save: function() { - var promiseLabel = "DS: RecordArray#save " + ember$data$lib$system$record_arrays$record_array$$get(this, 'type'); - var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { - return Ember.A(array); - }, null, "DS: RecordArray#save apply Ember.NativeArray"); - - return ember$data$lib$system$promise_proxies$$PromiseArray.create({ promise: promise }); - }, - - _dissociateFromOwnRecords: function() { - var array = this; - - this.forEach(function(record){ - var recordArrays = record._recordArrays; - - if (recordArrays) { - recordArrays["delete"](array); - } - }); - }, - - /** - @method _unregisterFromManager - @private - */ - _unregisterFromManager: function(){ - var manager = ember$data$lib$system$record_arrays$record_array$$get(this, 'manager'); - //We will stop needing this stupid if statement soon, once manyArray are refactored to not be RecordArrays - if (manager) { - manager.unregisterFilteredRecordArray(this); - } - }, - - willDestroy: function(){ - this._unregisterFromManager(); - this._dissociateFromOwnRecords(); - ember$data$lib$system$record_arrays$record_array$$set(this, 'content', undefined); - this._super(); - } - }); - - /** - @module ember-data - */ - - var ember$data$lib$system$record_arrays$filtered_record_array$$get = Ember.get; - - var ember$data$lib$system$record_arrays$filtered_record_array$$default = ember$data$lib$system$record_arrays$record_array$$default.extend({ - /** - The filterFunction is a function used to test records from the store to - determine if they should be part of the record array. - - Example - - ```javascript - var allPeople = store.all('person'); - allPeople.mapBy('name'); // ["Tom Dale", "Yehuda Katz", "Trek Glowacki"] - - var people = store.filter('person', function(person) { - if (person.get('name').match(/Katz$/)) { return true; } - }); - people.mapBy('name'); // ["Yehuda Katz"] - - var notKatzFilter = function(person) { - return !person.get('name').match(/Katz$/); - }; - people.set('filterFunction', notKatzFilter); - people.mapBy('name'); // ["Tom Dale", "Trek Glowacki"] - ``` - - @method filterFunction - @param {DS.Model} record - @return {Boolean} `true` if the record should be in the array - */ - filterFunction: null, - isLoaded: true, - - replace: function() { - var type = ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'type').toString(); - throw new Error("The result of a client-side filter (on " + type + ") is immutable."); - }, - - /** - @method updateFilter - @private - */ - _updateFilter: function() { - var manager = ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'manager'); - manager.updateFilter(this, ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'type'), ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'filterFunction')); - }, - - updateFilter: Ember.observer(function() { - Ember.run.once(this, this._updateFilter); - }, 'filterFunction'), - - }); - - /** - @module ember-data - */ - - var ember$data$lib$system$record_arrays$adapter_populated_record_array$$get = Ember.get; - - function ember$data$lib$system$record_arrays$adapter_populated_record_array$$cloneNull(source) { - var clone = Ember.create(null); - for (var key in source) { - clone[key] = source[key]; - } - return clone; - } - - var ember$data$lib$system$record_arrays$adapter_populated_record_array$$default = ember$data$lib$system$record_arrays$record_array$$default.extend({ - query: null, - - replace: function() { - var type = ember$data$lib$system$record_arrays$adapter_populated_record_array$$get(this, 'type').toString(); - throw new Error("The result of a server query (on " + type + ") is immutable."); - }, - - /** - @method load - @private - @param {Array} data - */ - load: function(data) { - var store = ember$data$lib$system$record_arrays$adapter_populated_record_array$$get(this, 'store'); - var type = ember$data$lib$system$record_arrays$adapter_populated_record_array$$get(this, 'type'); - var records = store.pushMany(type, data); - var meta = store.metadataFor(type); - - this.setProperties({ - content: Ember.A(records), - isLoaded: true, - meta: ember$data$lib$system$record_arrays$adapter_populated_record_array$$cloneNull(meta) - }); - - records.forEach(function(record) { - this.manager.recordArraysForRecord(record).add(this); - }, this); - - // TODO: should triggering didLoad event be the last action of the runLoop? - Ember.run.once(this, 'trigger', 'didLoad'); - } - }); - - /** - @module ember-data - */ - - var ember$data$lib$system$record_arrays$many_array$$get = Ember.get, ember$data$lib$system$record_arrays$many_array$$set = Ember.set; - - var ember$data$lib$system$record_arrays$many_array$$default = Ember.Object.extend(Ember.MutableArray, Ember.Evented, { - init: function() { - this.currentState = Ember.A([]); - this.diff = []; - }, - - record: null, - - canonicalState: null, - currentState: null, - - diff: null, - - length: 0, - - objectAt: function(index) { - if (this.currentState[index]) { - return this.currentState[index]; - } else { - return this.canonicalState[index]; - } - }, - - flushCanonical: function() { - //TODO make this smarter, currently its plenty stupid - var toSet = this.canonicalState.slice(0); - //a hack for not removing new records - //TODO remove once we have proper diffing - var newRecords = this.currentState.filter(function(record) { - return record.get('isNew'); - }); - toSet = toSet.concat(newRecords); - this.arrayContentWillChange(0, this.length, this.length); - this.set('length', toSet.length); - this.currentState = toSet; - this.arrayContentDidChange(0, this.length, this.length); - //TODO Figure out to notify only on additions and maybe only if unloaded - this.relationship.notifyHasManyChanged(); - this.record.updateRecordArrays(); - }, - /** - `true` if the relationship is polymorphic, `false` otherwise. - - @property {Boolean} isPolymorphic - @private - */ - isPolymorphic: false, - - /** - The loading state of this array - - @property {Boolean} isLoaded - */ - isLoaded: false, - - /** - The relationship which manages this array. - - @property {ManyRelationship} relationship - @private - */ - relationship: null, - - internalReplace: function(idx, amt, objects) { - if (!objects) { - objects = []; - } - this.arrayContentWillChange(idx, amt, objects.length); - this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); - this.set('length', this.currentState.length); - this.arrayContentDidChange(idx, amt, objects.length); - if (objects){ - //TODO(Igor) probably needed only for unloaded records - this.relationship.notifyHasManyChanged(); - } - this.record.updateRecordArrays(); - }, - - //TODO(Igor) optimize - internalRemoveRecords: function(records) { - var index; - for(var i=0; i < records.length; i++) { - index = this.currentState.indexOf(records[i]); - this.internalReplace(index, 1); - } - }, - - //TODO(Igor) optimize - internalAddRecords: function(records, idx) { - if (idx === undefined) { - idx = this.currentState.length; - } - this.internalReplace(idx, 0, records); - }, - - replace: function(idx, amt, objects) { - var records; - if (amt > 0){ - records = this.currentState.slice(idx, idx+amt); - this.get('relationship').removeRecords(records); - } - if (objects){ - this.get('relationship').addRecords(objects, idx); - } - }, - /** - Used for async `hasMany` arrays - to keep track of when they will resolve. - - @property {Ember.RSVP.Promise} promise - @private - */ - promise: null, - - /** - @method loadingRecordsCount - @param {Number} count - @private - */ - loadingRecordsCount: function(count) { - this.loadingRecordsCount = count; - }, - - /** - @method loadedRecord - @private - */ - loadedRecord: function() { - this.loadingRecordsCount--; - if (this.loadingRecordsCount === 0) { - ember$data$lib$system$record_arrays$many_array$$set(this, 'isLoaded', true); - this.trigger('didLoad'); - } - }, - - /** - @method reload - @public - */ - reload: function() { - return this.relationship.reload(); - }, - - /** - Create a child record within the owner - - @method createRecord - @private - @param {Object} hash - @return {DS.Model} record - */ - createRecord: function(hash) { - var store = ember$data$lib$system$record_arrays$many_array$$get(this, 'store'); - var type = ember$data$lib$system$record_arrays$many_array$$get(this, 'type'); - var record; - - Ember.assert("You cannot add '" + type.typeKey + "' records to this polymorphic relationship.", !ember$data$lib$system$record_arrays$many_array$$get(this, 'isPolymorphic')); - - record = store.createRecord(type, hash); - this.pushObject(record); - - return record; - } - }); - - var ember$data$lib$system$record_array_manager$$get = Ember.get; - var ember$data$lib$system$record_array_manager$$forEach = Ember.EnumerableUtils.forEach; - var ember$data$lib$system$record_array_manager$$indexOf = Ember.EnumerableUtils.indexOf; - - var ember$data$lib$system$record_array_manager$$default = Ember.Object.extend({ - init: function() { - this.filteredRecordArrays = ember$data$lib$system$map$$MapWithDefault.create({ - defaultValue: function() { return []; } - }); - - this.changedRecords = []; - this._adapterPopulatedRecordArrays = []; - }, - - recordDidChange: function(record) { - if (this.changedRecords.push(record) !== 1) { return; } - - Ember.run.schedule('actions', this, this.updateRecordArrays); - }, - - recordArraysForRecord: function(record) { - record._recordArrays = record._recordArrays || ember$data$lib$system$map$$OrderedSet.create(); - return record._recordArrays; - }, - - /** - This method is invoked whenever data is loaded into the store by the - adapter or updated by the adapter, or when a record has changed. - - It updates all record arrays that a record belongs to. - - To avoid thrashing, it only runs at most once per run loop. - - @method updateRecordArrays - @param {Class} type - @param {Number|String} clientId - */ - updateRecordArrays: function() { - ember$data$lib$system$record_array_manager$$forEach(this.changedRecords, function(record) { - if (ember$data$lib$system$record_array_manager$$get(record, 'isDeleted')) { - this._recordWasDeleted(record); - } else { - this._recordWasChanged(record); - } - }, this); - - this.changedRecords.length = 0; - }, - - _recordWasDeleted: function (record) { - var recordArrays = record._recordArrays; - - if (!recordArrays) { return; } - - recordArrays.forEach(function(array){ - array.removeRecord(record); - }); - - record._recordArrays = null; - }, - - _recordWasChanged: function (record) { - var type = record.constructor; - var recordArrays = this.filteredRecordArrays.get(type); - var filter; - - ember$data$lib$system$record_array_manager$$forEach(recordArrays, function(array) { - filter = ember$data$lib$system$record_array_manager$$get(array, 'filterFunction'); - this.updateRecordArray(array, filter, type, record); - }, this); - - // loop through all manyArrays containing an unloaded copy of this - // clientId and notify them that the record was loaded. - var manyArrays = record._loadingRecordArrays; - - if (manyArrays) { - for (var i=0, l=manyArrays.length; i "root.created.uncommitted" - ``` - - The hierarchy of valid states that ship with ember data looks like - this: - - ```text - * root - * deleted - * saved - * uncommitted - * inFlight - * empty - * loaded - * created - * uncommitted - * inFlight - * saved - * updated - * uncommitted - * inFlight - * loading - ``` - - The `DS.Model` states are themselves stateless. What that means is - that, the hierarchical states that each of *those* points to is a - shared data structure. For performance reasons, instead of each - record getting its own copy of the hierarchy of states, each record - points to this global, immutable shared instance. How does a state - know which record it should be acting on? We pass the record - instance into the state's event handlers as the first argument. - - The record passed as the first parameter is where you should stash - state about the record if needed; you should never store data on the state - object itself. - - ### Events and Flags - - A state may implement zero or more events and flags. - - #### Events - - Events are named functions that are invoked when sent to a record. The - record will first look for a method with the given name on the - current state. If no method is found, it will search the current - state's parent, and then its grandparent, and so on until reaching - the top of the hierarchy. If the root is reached without an event - handler being found, an exception will be raised. This can be very - helpful when debugging new features. - - Here's an example implementation of a state with a `myEvent` event handler: - - ```javascript - aState: DS.State.create({ - myEvent: function(manager, param) { - console.log("Received myEvent with", param); - } - }) - ``` - - To trigger this event: - - ```javascript - record.send('myEvent', 'foo'); - //=> "Received myEvent with foo" - ``` - - Note that an optional parameter can be sent to a record's `send()` method, - which will be passed as the second parameter to the event handler. - - Events should transition to a different state if appropriate. This can be - done by calling the record's `transitionTo()` method with a path to the - desired state. The state manager will attempt to resolve the state path - relative to the current state. If no state is found at that path, it will - attempt to resolve it relative to the current state's parent, and then its - parent, and so on until the root is reached. For example, imagine a hierarchy - like this: - - * created - * uncommitted <-- currentState - * inFlight - * updated - * inFlight - - If we are currently in the `uncommitted` state, calling - `transitionTo('inFlight')` would transition to the `created.inFlight` state, - while calling `transitionTo('updated.inFlight')` would transition to - the `updated.inFlight` state. - - Remember that *only events* should ever cause a state transition. You should - never call `transitionTo()` from outside a state's event handler. If you are - tempted to do so, create a new event and send that to the state manager. - - #### Flags - - Flags are Boolean values that can be used to introspect a record's current - state in a more user-friendly way than examining its state path. For example, - instead of doing this: - - ```javascript - var statePath = record.get('stateManager.currentPath'); - if (statePath === 'created.inFlight') { - doSomething(); - } - ``` - - You can say: - - ```javascript - if (record.get('isNew') && record.get('isSaving')) { - doSomething(); - } - ``` - - If your state does not set a value for a given flag, the value will - be inherited from its parent (or the first place in the state hierarchy - where it is defined). - - The current set of flags are defined below. If you want to add a new flag, - in addition to the area below, you will also need to declare it in the - `DS.Model` class. - - - * [isEmpty](DS.Model.html#property_isEmpty) - * [isLoading](DS.Model.html#property_isLoading) - * [isLoaded](DS.Model.html#property_isLoaded) - * [isDirty](DS.Model.html#property_isDirty) - * [isSaving](DS.Model.html#property_isSaving) - * [isDeleted](DS.Model.html#property_isDeleted) - * [isNew](DS.Model.html#property_isNew) - * [isValid](DS.Model.html#property_isValid) - - @namespace DS - @class RootState - */ - - function ember$data$lib$system$model$states$$didSetProperty(record, context) { - if (context.value === context.originalValue) { - delete record._attributes[context.name]; - record.send('propertyWasReset', context.name); - } else if (context.value !== context.oldValue) { - record.send('becomeDirty'); - } - - record.updateRecordArraysLater(); - } - - // Implementation notes: - // - // Each state has a boolean value for all of the following flags: - // - // * isLoaded: The record has a populated `data` property. When a - // record is loaded via `store.find`, `isLoaded` is false - // until the adapter sets it. When a record is created locally, - // its `isLoaded` property is always true. - // * isDirty: The record has local changes that have not yet been - // saved by the adapter. This includes records that have been - // created (but not yet saved) or deleted. - // * isSaving: The record has been committed, but - // the adapter has not yet acknowledged that the changes have - // been persisted to the backend. - // * isDeleted: The record was marked for deletion. When `isDeleted` - // is true and `isDirty` is true, the record is deleted locally - // but the deletion was not yet persisted. When `isSaving` is - // true, the change is in-flight. When both `isDirty` and - // `isSaving` are false, the change has persisted. - // * isError: The adapter reported that it was unable to save - // local changes to the backend. This may also result in the - // record having its `isValid` property become false if the - // adapter reported that server-side validations failed. - // * isNew: The record was created on the client and the adapter - // did not yet report that it was successfully saved. - // * isValid: The adapter did not report any server-side validation - // failures. - - // The dirty state is a abstract state whose functionality is - // shared between the `created` and `updated` states. - // - // The deleted state shares the `isDirty` flag with the - // subclasses of `DirtyState`, but with a very different - // implementation. - // - // Dirty states have three child states: - // - // `uncommitted`: the store has not yet handed off the record - // to be saved. - // `inFlight`: the store has handed off the record to be saved, - // but the adapter has not yet acknowledged success. - // `invalid`: the record has invalid information and cannot be - // send to the adapter yet. - var ember$data$lib$system$model$states$$DirtyState = { - initialState: 'uncommitted', - - // FLAGS - isDirty: true, - - // SUBSTATES - - // When a record first becomes dirty, it is `uncommitted`. - // This means that there are local pending changes, but they - // have not yet begun to be saved, and are not invalid. - uncommitted: { - // EVENTS - didSetProperty: ember$data$lib$system$model$states$$didSetProperty, - - //TODO(Igor) reloading now triggers a - //loadingData event, though it seems fine? - loadingData: Ember.K, - - propertyWasReset: function(record, name) { - var length = Ember.keys(record._attributes).length; - var stillDirty = length > 0; - - if (!stillDirty) { record.send('rolledBack'); } - }, - - pushedData: Ember.K, - - becomeDirty: Ember.K, - - willCommit: function(record) { - record.transitionTo('inFlight'); - }, - - reloadRecord: function(record, resolve) { - resolve(ember$data$lib$system$model$states$$get(record, 'store').reloadRecord(record)); - }, - - rolledBack: function(record) { - record.transitionTo('loaded.saved'); - }, - - becameInvalid: function(record) { - record.transitionTo('invalid'); - }, - - rollback: function(record) { - record.rollback(); - } - }, - - // Once a record has been handed off to the adapter to be - // saved, it is in the 'in flight' state. Changes to the - // record cannot be made during this window. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - didSetProperty: ember$data$lib$system$model$states$$didSetProperty, - becomeDirty: Ember.K, - pushedData: Ember.K, - - unloadRecord: function(record) { - Ember.assert("You can only unload a record which is not inFlight. `" + Ember.inspect(record) + " `", false); - }, - - // TODO: More robust semantics around save-while-in-flight - willCommit: Ember.K, - - didCommit: function(record) { - var dirtyType = ember$data$lib$system$model$states$$get(this, 'dirtyType'); - - record.transitionTo('saved'); - record.send('invokeLifecycleCallbacks', dirtyType); - }, - - becameInvalid: function(record) { - record.transitionTo('invalid'); - record.send('invokeLifecycleCallbacks'); - }, - - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); - } - }, - - // A record is in the `invalid` if the adapter has indicated - // the the record failed server-side invalidations. - invalid: { - // FLAGS - isValid: false, - - // EVENTS - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); - }, - - didSetProperty: function(record, context) { - ember$data$lib$system$model$states$$get(record, 'errors').remove(context.name); - - ember$data$lib$system$model$states$$didSetProperty(record, context); - }, - - becomeDirty: Ember.K, - - willCommit: function(record) { - ember$data$lib$system$model$states$$get(record, 'errors').clear(); - record.transitionTo('inFlight'); - }, - - rolledBack: function(record) { - ember$data$lib$system$model$states$$get(record, 'errors').clear(); - }, - - becameValid: function(record) { - record.transitionTo('uncommitted'); - }, - - invokeLifecycleCallbacks: function(record) { - record.triggerLater('becameInvalid', record); - }, - - exit: function(record) { - record._inFlightAttributes = {}; - } - } - }; - - // The created and updated states are created outside the state - // chart so we can reopen their substates and add mixins as - // necessary. - - function ember$data$lib$system$model$states$$deepClone(object) { - var clone = {}, value; - - for (var prop in object) { - value = object[prop]; - if (value && typeof value === 'object') { - clone[prop] = ember$data$lib$system$model$states$$deepClone(value); - } else { - clone[prop] = value; - } - } - - return clone; - } - - function ember$data$lib$system$model$states$$mixin(original, hash) { - for (var prop in hash) { - original[prop] = hash[prop]; - } - - return original; - } - - function ember$data$lib$system$model$states$$dirtyState(options) { - var newState = ember$data$lib$system$model$states$$deepClone(ember$data$lib$system$model$states$$DirtyState); - return ember$data$lib$system$model$states$$mixin(newState, options); - } - - var ember$data$lib$system$model$states$$createdState = ember$data$lib$system$model$states$$dirtyState({ - dirtyType: 'created', - // FLAGS - isNew: true - }); - - ember$data$lib$system$model$states$$createdState.uncommitted.rolledBack = function(record) { - record.transitionTo('deleted.saved'); - }; - - var ember$data$lib$system$model$states$$updatedState = ember$data$lib$system$model$states$$dirtyState({ - dirtyType: 'updated' - }); - - ember$data$lib$system$model$states$$createdState.uncommitted.deleteRecord = function(record) { - record.disconnectRelationships(); - record.transitionTo('deleted.saved'); - }; - - ember$data$lib$system$model$states$$createdState.uncommitted.rollback = function(record) { - ember$data$lib$system$model$states$$DirtyState.uncommitted.rollback.apply(this, arguments); - record.transitionTo('deleted.saved'); - }; - - ember$data$lib$system$model$states$$createdState.uncommitted.propertyWasReset = Ember.K; - - function ember$data$lib$system$model$states$$assertAgainstUnloadRecord(record) { - Ember.assert("You can only unload a record which is not inFlight. `" + Ember.inspect(record) + "`", false); - } - - ember$data$lib$system$model$states$$updatedState.inFlight.unloadRecord = ember$data$lib$system$model$states$$assertAgainstUnloadRecord; - - ember$data$lib$system$model$states$$updatedState.uncommitted.deleteRecord = function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); - }; - - var ember$data$lib$system$model$states$$RootState = { - // FLAGS - isEmpty: false, - isLoading: false, - isLoaded: false, - isDirty: false, - isSaving: false, - isDeleted: false, - isNew: false, - isValid: true, - - // DEFAULT EVENTS - - // Trying to roll back if you're not in the dirty state - // doesn't change your state. For example, if you're in the - // in-flight state, rolling back the record doesn't move - // you out of the in-flight state. - rolledBack: Ember.K, - unloadRecord: function(record) { - // clear relationships before moving to deleted state - // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); - }, - - - propertyWasReset: Ember.K, - - // SUBSTATES - - // A record begins its lifecycle in the `empty` state. - // If its data will come from the adapter, it will - // transition into the `loading` state. Otherwise, if - // the record is being created on the client, it will - // transition into the `created` state. - empty: { - isEmpty: true, - - // EVENTS - loadingData: function(record, promise) { - record._loadingPromise = promise; - record.transitionTo('loading'); - }, - - loadedData: function(record) { - record.transitionTo('loaded.created.uncommitted'); - }, - - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - } - }, - - // A record enters this state when the store asks - // the adapter for its data. It remains in this state - // until the adapter provides the requested data. - // - // Usually, this process is asynchronous, using an - // XHR to retrieve the data. - loading: { - // FLAGS - isLoading: true, - - exit: function(record) { - record._loadingPromise = null; - }, - - // EVENTS - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - ember$data$lib$system$model$states$$set(record, 'isError', false); - }, - - becameError: function(record) { - record.triggerLater('becameError', record); - }, - - notFound: function(record) { - record.transitionTo('empty'); - } - }, - - // A record enters this state when its data is populated. - // Most of a record's lifecycle is spent inside substates - // of the `loaded` state. - loaded: { - initialState: 'saved', - - // FLAGS - isLoaded: true, - - //TODO(Igor) Reloading now triggers a loadingData event, - //but it should be ok? - loadingData: Ember.K, - - // SUBSTATES - - // If there are no local changes to a record, it remains - // in the `saved` state. - saved: { - setup: function(record) { - var attrs = record._attributes; - var isDirty = Ember.keys(attrs).length > 0; - - if (isDirty) { - record.adapterDidDirty(); - } - }, - - // EVENTS - didSetProperty: ember$data$lib$system$model$states$$didSetProperty, - - pushedData: Ember.K, - - becomeDirty: function(record) { - record.transitionTo('updated.uncommitted'); - }, - - willCommit: function(record) { - record.transitionTo('updated.inFlight'); - }, - - reloadRecord: function(record, resolve) { - resolve(ember$data$lib$system$model$states$$get(record, 'store').reloadRecord(record)); - }, - - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); - }, - - unloadRecord: function(record) { - // clear relationships before moving to deleted state - // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); - }, - - didCommit: function(record) { - record.send('invokeLifecycleCallbacks', ember$data$lib$system$model$states$$get(record, 'lastDirtyType')); - }, - - // loaded.saved.notFound would be triggered by a failed - // `reload()` on an unchanged record - notFound: Ember.K - - }, - - // A record is in this state after it has been locally - // created but before the adapter has indicated that - // it has been saved. - created: ember$data$lib$system$model$states$$createdState, - - // A record is in this state if it has already been - // saved to the server, but there are new local changes - // that have not yet been saved. - updated: ember$data$lib$system$model$states$$updatedState - }, - - // A record is in this state if it was deleted from the store. - deleted: { - initialState: 'uncommitted', - dirtyType: 'deleted', - - // FLAGS - isDeleted: true, - isLoaded: true, - isDirty: true, - - // TRANSITIONS - setup: function(record) { - record.updateRecordArrays(); - }, - - // SUBSTATES - - // When a record is deleted, it enters the `start` - // state. It will exit this state when the record - // starts to commit. - uncommitted: { - - // EVENTS - - willCommit: function(record) { - record.transitionTo('inFlight'); - }, - - rollback: function(record) { - record.rollback(); - }, - - becomeDirty: Ember.K, - deleteRecord: Ember.K, - - rolledBack: function(record) { - record.transitionTo('loaded.saved'); - } - }, - - // After a record starts committing, but - // before the adapter indicates that the deletion - // has saved to the server, a record is in the - // `inFlight` substate of `deleted`. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - - unloadRecord: ember$data$lib$system$model$states$$assertAgainstUnloadRecord, - - // TODO: More robust semantics around save-while-in-flight - willCommit: Ember.K, - didCommit: function(record) { - record.transitionTo('saved'); - - record.send('invokeLifecycleCallbacks'); - }, - - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); - } - }, - - // Once the adapter indicates that the deletion has - // been saved, the record enters the `saved` substate - // of `deleted`. - saved: { - // FLAGS - isDirty: false, - - setup: function(record) { - var store = ember$data$lib$system$model$states$$get(record, 'store'); - store.dematerializeRecord(record); - }, - - invokeLifecycleCallbacks: function(record) { - record.triggerLater('didDelete', record); - record.triggerLater('didCommit', record); - }, - - willCommit: Ember.K, - - didCommit: Ember.K - } - }, - - invokeLifecycleCallbacks: function(record, dirtyType) { - if (dirtyType === 'created') { - record.triggerLater('didCreate', record); - } else { - record.triggerLater('didUpdate', record); - } - - record.triggerLater('didCommit', record); - } - }; - - function ember$data$lib$system$model$states$$wireState(object, parent, name) { - /*jshint proto:true*/ - // TODO: Use Object.create and copy instead - object = ember$data$lib$system$model$states$$mixin(parent ? Ember.create(parent) : {}, object); - object.parentState = parent; - object.stateName = name; - - for (var prop in object) { - if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } - if (typeof object[prop] === 'object') { - object[prop] = ember$data$lib$system$model$states$$wireState(object[prop], object, name + "." + prop); - } - } - - return object; - } - - ember$data$lib$system$model$states$$RootState = ember$data$lib$system$model$states$$wireState(ember$data$lib$system$model$states$$RootState, null, "root"); - - var ember$data$lib$system$model$states$$default = ember$data$lib$system$model$states$$RootState; - var ember$data$lib$system$model$errors$$get = Ember.get; - var ember$data$lib$system$model$errors$$isEmpty = Ember.isEmpty; - var ember$data$lib$system$model$errors$$map = Ember.EnumerableUtils.map; - - var ember$data$lib$system$model$errors$$default = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { - /** - Register with target handler - - @method registerHandlers - @param {Object} target - @param {Function} becameInvalid - @param {Function} becameValid - */ - registerHandlers: function(target, becameInvalid, becameValid) { - this.on('becameInvalid', target, becameInvalid); - this.on('becameValid', target, becameValid); - }, - - /** - @property errorsByAttributeName - @type {Ember.MapWithDefault} - @private - */ - errorsByAttributeName: Ember.reduceComputed("content", { - initialValue: function() { - return ember$data$lib$system$map$$MapWithDefault.create({ - defaultValue: function() { - return Ember.A(); - } - }); - }, - - addedItem: function(errors, error) { - errors.get(error.attribute).pushObject(error); - - return errors; - }, - - removedItem: function(errors, error) { - errors.get(error.attribute).removeObject(error); - - return errors; - } - }), - - /** - Returns errors for a given attribute - - ```javascript - var user = store.createRecord('user', { - username: 'tomster', - email: 'invalidEmail' - }); - user.save().catch(function(){ - user.get('errors').errorsFor('email'); // returns: - // [{attribute: "email", message: "Doesn't look like a valid email."}] - }); - ``` - - @method errorsFor - @param {String} attribute - @return {Array} - */ - errorsFor: function(attribute) { - return ember$data$lib$system$model$errors$$get(this, 'errorsByAttributeName').get(attribute); - }, - - /** - An array containing all of the error messages for this - record. This is useful for displaying all errors to the user. - - ```handlebars - {{#each message in errors.messages}} -
    - {{message}} -
    - {{/each}} - ``` - - @property messages - @type {Array} - */ - messages: Ember.computed.mapBy('content', 'message'), - - /** - @property content - @type {Array} - @private - */ - content: Ember.computed(function() { - return Ember.A(); - }), - - /** - @method unknownProperty - @private - */ - unknownProperty: function(attribute) { - var errors = this.errorsFor(attribute); - if (ember$data$lib$system$model$errors$$isEmpty(errors)) { return null; } - return errors; - }, - - /** - @method nextObject - @private - */ - nextObject: function(index, previousObject, context) { - return ember$data$lib$system$model$errors$$get(this, 'content').objectAt(index); - }, - - /** - Total number of errors. - - @property length - @type {Number} - @readOnly - */ - length: Ember.computed.oneWay('content.length').readOnly(), - - /** - @property isEmpty - @type {Boolean} - @readOnly - */ - isEmpty: Ember.computed.not('length').readOnly(), - - /** - Adds error messages to a given attribute and sends - `becameInvalid` event to the record. - - Example: - - ```javascript - if (!user.get('username') { - user.get('errors').add('username', 'This field is required'); - } - ``` - - @method add - @param {String} attribute - @param {Array|String} messages - */ - add: function(attribute, messages) { - var wasEmpty = ember$data$lib$system$model$errors$$get(this, 'isEmpty'); - - messages = this._findOrCreateMessages(attribute, messages); - ember$data$lib$system$model$errors$$get(this, 'content').addObjects(messages); - - this.notifyPropertyChange(attribute); - this.enumerableContentDidChange(); - - if (wasEmpty && !ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { - this.trigger('becameInvalid'); - } - }, - - /** - @method _findOrCreateMessages - @private - */ - _findOrCreateMessages: function(attribute, messages) { - var errors = this.errorsFor(attribute); - - return ember$data$lib$system$model$errors$$map(Ember.makeArray(messages), function(message) { - return errors.findBy('message', message) || { - attribute: attribute, - message: message - }; - }); - }, - - /** - Removes all error messages from the given attribute and sends - `becameValid` event to the record if there no more errors left. - - Example: - - ```javascript - App.User = DS.Model.extend({ - email: DS.attr('string'), - twoFactorAuth: DS.attr('boolean'), - phone: DS.attr('string') - }); - - App.UserEditRoute = Ember.Route.extend({ - actions: { - save: function(user) { - if (!user.get('twoFactorAuth')) { - user.get('errors').remove('phone'); - } - user.save(); - } - } - }); - ``` - - @method remove - @param {String} attribute - */ - remove: function(attribute) { - if (ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { return; } - - var content = ember$data$lib$system$model$errors$$get(this, 'content').rejectBy('attribute', attribute); - ember$data$lib$system$model$errors$$get(this, 'content').setObjects(content); - - this.notifyPropertyChange(attribute); - this.enumerableContentDidChange(); - - if (ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { - this.trigger('becameValid'); - } - }, - - /** - Removes all error messages and sends `becameValid` event - to the record. - - Example: - - ```javascript - App.UserEditRoute = Ember.Route.extend({ - actions: { - retrySave: function(user) { - user.get('errors').clear(); - user.save(); - } - } - }); - ``` - - @method clear - */ - clear: function() { - if (ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { return; } - - ember$data$lib$system$model$errors$$get(this, 'content').clear(); - this.enumerableContentDidChange(); - - this.trigger('becameValid'); - }, - - /** - Checks if there is error messages for the given attribute. - - ```javascript - App.UserEditRoute = Ember.Route.extend({ - actions: { - save: function(user) { - if (user.get('errors').has('email')) { - return alert('Please update your email before attempting to save.'); - } - user.save(); - } - } - }); - ``` - - @method has - @param {String} attribute - @return {Boolean} true if there some errors on given attribute - */ - has: function(attribute) { - return !ember$data$lib$system$model$errors$$isEmpty(this.errorsFor(attribute)); - } - }); - - function ember$data$lib$system$merge$$merge(original, updates) { - if (!updates || typeof updates !== 'object') { - return original; - } - - var props = Ember.keys(updates); - var prop; - var length = props.length; - - for (var i = 0; i < length; i++) { - prop = props[i]; - original[prop] = updates[prop]; - } - - return original; - } - - var ember$data$lib$system$merge$$default = ember$data$lib$system$merge$$merge; - - var ember$data$lib$system$relationships$state$relationship$$forEach = Ember.EnumerableUtils.forEach; - - var ember$data$lib$system$relationships$state$relationship$$Relationship = function(store, record, inverseKey, relationshipMeta) { - this.members = new ember$data$lib$system$map$$OrderedSet(); - this.canonicalMembers = new ember$data$lib$system$map$$OrderedSet(); - this.store = store; - this.key = relationshipMeta.key; - this.inverseKey = inverseKey; - this.record = record; - this.isAsync = relationshipMeta.options.async; - this.relationshipMeta = relationshipMeta; - //This probably breaks for polymorphic relationship in complex scenarios, due to - //multiple possible typeKeys - this.inverseKeyForImplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; - this.linkPromise = null; - }; - - ember$data$lib$system$relationships$state$relationship$$Relationship.prototype = { - constructor: ember$data$lib$system$relationships$state$relationship$$Relationship, - - destroy: Ember.K, - - clear: function() { - var members = this.members.list; - var member; - - while (members.length > 0){ - member = members[0]; - this.removeRecord(member); - } - }, - - disconnect: function(){ - this.members.forEach(function(member) { - this.removeRecordFromInverse(member); - }, this); - }, - - reconnect: function(){ - this.members.forEach(function(member) { - this.addRecordToInverse(member); - }, this); - }, - - removeRecords: function(records){ - var self = this; - ember$data$lib$system$relationships$state$relationship$$forEach(records, function(record){ - self.removeRecord(record); - }); - }, - - addRecords: function(records, idx){ - var self = this; - ember$data$lib$system$relationships$state$relationship$$forEach(records, function(record){ - self.addRecord(record, idx); - if (idx !== undefined) { - idx++; - } - }); - }, - - addCanonicalRecords: function(records, idx) { - for (var i=0; i -1) { - this.canonicalState.splice(i, 1); - } - this._super$removeCanonicalRecordFromOwn(record, idx); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype._super$flushCanonical = ember$data$lib$system$relationships$state$relationship$$default.prototype.flushCanonical; - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.flushCanonical = function() { - this.manyArray.flushCanonical(); - this._super$flushCanonical(); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype._super$removeRecordFromOwn = ember$data$lib$system$relationships$state$relationship$$default.prototype.removeRecordFromOwn; - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { - if (!this.members.has(record)) { - return; - } - this._super$removeRecordFromOwn(record, idx); - if (idx !== undefined) { - //TODO(Igor) not used currently, fix - this.manyArray.currentState.removeAt(idx); - } else { - this.manyArray.internalRemoveRecords([record]); - } - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - var type = this.relationshipMeta.type; - Ember.assert("You cannot add '" + record.constructor.typeKey + "' records to the " + this.record.constructor.typeKey + "." + this.key + " relationship (only '" + this.belongsToType.typeKey + "' allowed)", (function () { - if (record instanceof type) { - return true; - } else if (Ember.MODEL_FACTORY_INJECTIONS) { - return record instanceof type.superclass; - } - - return false; - })()); - - this.record.notifyHasManyAdded(this.key, record, idx); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.reload = function() { - var self = this; - if (this.link) { - return this.fetchLink(); - } else { - return this.store.scheduleFetchMany(this.manyArray.toArray()).then(function() { - //Goes away after the manyArray refactor - self.manyArray.set('isLoaded', true); - return self.manyArray; - }); - } - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.computeChanges = function(records) { - var members = this.canonicalMembers; - var recordsToRemove = []; - var length; - var record; - var i; - - records = ember$data$lib$system$relationships$state$has_many$$setForArray(records); - - members.forEach(function(member) { - if (records.has(member)) return; - - recordsToRemove.push(member); - }); - - this.removeCanonicalRecords(recordsToRemove); - - var hasManyArray = this.manyArray; - - // Using records.toArray() since currently using - // removeRecord can modify length, messing stuff up - // forEach since it directly looks at "length" each - // iteration - records = records.toArray(); - length = records.length; - for (i = 0; i < length; i++){ - record = records[i]; - //Need to preserve the order of incoming records - if (hasManyArray.objectAt(i) === record ) { - continue; - } - this.removeCanonicalRecord(record); - this.addCanonicalRecord(record, i); - } - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.fetchLink = function() { - var self = this; - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ - self.updateRecordsFromAdapter(records); - return self.manyArray; - }); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.findRecords = function() { - var manyArray = this.manyArray; - return this.store.findMany(manyArray.toArray()).then(function(){ - //Goes away after the manyArray refactor - manyArray.set('isLoaded', true); - return manyArray; - }); - }; - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.notifyHasManyChanged = function() { - this.record.notifyHasManyAdded(this.key); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.getRecords = function() { - //TODO(Igor) sync server here, once our syncing is not stupid - if (this.isAsync) { - var self = this; - var promise; - if (this.link) { - promise = this.findLink().then(function() { - return self.findRecords(); - }); - } else { - promise = this.findRecords(); - } - return ember$data$lib$system$promise_proxies$$PromiseManyArray.create({ - content: this.manyArray, - promise: promise - }); - } else { - Ember.assert("You looked up the '" + this.key + "' relationship on a '" + this.record.constructor.typeKey + "' with id " + this.record.get('id') + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", this.manyArray.isEvery('isEmpty', false)); - - //TODO(Igor) WTF DO I DO HERE? - if (!this.manyArray.get('isDestroyed')) { - this.manyArray.set('isLoaded', true); - } - return this.manyArray; - } - }; - - function ember$data$lib$system$relationships$state$has_many$$setForArray(array) { - var set = new ember$data$lib$system$map$$OrderedSet(); - - if (array) { - for (var i=0, l=array.length; i')` from " + this.toString(), name !== 'id'); - - meta.name = name; - map.set(name, meta); - } - }); - - return map; - }).readOnly(), - - /** - A map whose keys are the attributes of the model (properties - described by DS.attr) and whose values are type of transformation - applied to each attribute. This map does not include any - attributes that do not have an transformation type. - - Example - - ```javascript - App.Person = DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - - var transformedAttributes = Ember.get(App.Person, 'transformedAttributes') - - transformedAttributes.forEach(function(field, type) { - console.log(field, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @property transformedAttributes - @static - @type {Ember.Map} - @readOnly - */ - transformedAttributes: Ember.computed(function() { - var map = ember$data$lib$system$map$$Map.create(); - - this.eachAttribute(function(key, meta) { - if (meta.type) { - map.set(key, meta.type); - } - }); - - return map; - }).readOnly(), - - /** - Iterates through the attributes of the model, calling the passed function on each - attribute. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, meta); - ``` - - - `name` the name of the current property in the iteration - - `meta` the meta object for the attribute property in the iteration - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - App.Person = DS.Model.extend({ - firstName: attr('string'), - lastName: attr('string'), - birthday: attr('date') - }); - - App.Person.eachAttribute(function(name, meta) { - console.log(name, meta); - }); - - // prints: - // firstName {type: "string", isAttribute: true, options: Object, parentType: function, name: "firstName"} - // lastName {type: "string", isAttribute: true, options: Object, parentType: function, name: "lastName"} - // birthday {type: "date", isAttribute: true, options: Object, parentType: function, name: "birthday"} - ``` - - @method eachAttribute - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @static - */ - eachAttribute: function(callback, binding) { - ember$data$lib$system$model$attributes$$get(this, 'attributes').forEach(function(meta, name) { - callback.call(binding, name, meta); - }, binding); - }, - - /** - Iterates through the transformedAttributes of the model, calling - the passed function on each attribute. Note the callback will not be - called for any attributes that do not have an transformation type. - - The callback method you provide should have the following signature (all - parameters are optional): - - ```javascript - function(name, type); - ``` - - - `name` the name of the current property in the iteration - - `type` a string containing the name of the type of transformed - applied to the attribute - - Note that in addition to a callback, you can also pass an optional target - object that will be set as `this` on the context. - - Example - - ```javascript - App.Person = DS.Model.extend({ - firstName: attr(), - lastName: attr('string'), - birthday: attr('date') - }); - - App.Person.eachTransformedAttribute(function(name, type) { - console.log(name, type); - }); - - // prints: - // lastName string - // birthday date - ``` - - @method eachTransformedAttribute - @param {Function} callback The callback to execute - @param {Object} [target] The target object to use - @static - */ - eachTransformedAttribute: function(callback, binding) { - ember$data$lib$system$model$attributes$$get(this, 'transformedAttributes').forEach(function(type, name) { - callback.call(binding, name, type); - }); - } - }); - - - ember$data$lib$system$model$model$$default.reopen({ - eachAttribute: function(callback, binding) { - this.constructor.eachAttribute(callback, binding); - } - }); - - function ember$data$lib$system$model$attributes$$getDefaultValue(record, options, key) { - if (typeof options.defaultValue === "function") { - return options.defaultValue.apply(null, arguments); - } else { - return options.defaultValue; - } - } - - function ember$data$lib$system$model$attributes$$hasValue(record, key) { - return key in record._attributes || - key in record._inFlightAttributes || - record._data.hasOwnProperty(key); - } - - function ember$data$lib$system$model$attributes$$getValue(record, key) { - if (key in record._attributes) { - return record._attributes[key]; - } else if (key in record._inFlightAttributes) { - return record._inFlightAttributes[key]; - } else { - return record._data[key]; - } - } - - function ember$data$lib$system$model$attributes$$attr(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } else { - options = options || {}; - } - - var meta = { - type: type, - isAttribute: true, - options: options - }; - - return Ember.computed(function(key, value) { - if (arguments.length > 1) { - Ember.assert("You may not set `id` as an attribute on your model. Please remove any lines that look like: `id: DS.attr('')` from " + this.constructor.toString(), key !== 'id'); - var oldValue = ember$data$lib$system$model$attributes$$getValue(this, key); - - if (value !== oldValue) { - // Add the new value to the changed attributes hash; it will get deleted by - // the 'didSetProperty' handler if it is no different from the original value - this._attributes[key] = value; - - this.send('didSetProperty', { - name: key, - oldValue: oldValue, - originalValue: this._data[key], - value: value - }); - } - - return value; - } else if (ember$data$lib$system$model$attributes$$hasValue(this, key)) { - return ember$data$lib$system$model$attributes$$getValue(this, key); - } else { - return ember$data$lib$system$model$attributes$$getDefaultValue(this, options, key); - } - - // `data` is never set directly. However, it may be - // invalidated from the state manager's setData - // event. - }).meta(meta); - } - var ember$data$lib$system$model$attributes$$default = ember$data$lib$system$model$attributes$$attr; - //Stanley told me to do this - var ember$data$lib$system$store$$Backburner = Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; - - //Shim Backburner.join - if (!ember$data$lib$system$store$$Backburner.prototype.join) { - var ember$data$lib$system$store$$isString = function(suspect) { - return typeof suspect === 'string'; - }; - - ember$data$lib$system$store$$Backburner.prototype.join = function(/*target, method, args */) { - var method, target; - - if (this.currentInstance) { - var length = arguments.length; - if (length === 1) { - method = arguments[0]; - target = null; - } else { - target = arguments[0]; - method = arguments[1]; - } - - if (ember$data$lib$system$store$$isString(method)) { - method = target[method]; - } - - if (length === 1) { - return method(); - } else if (length === 2) { - return method.call(target); - } else { - var args = new Array(length - 2); - for (var i =0, l = length - 2; i < l; i++) { - args[i] = arguments[i + 2]; - } - return method.apply(target, args); - } - } else { - return this.run.apply(this, arguments); - } - }; - } - - - var ember$data$lib$system$store$$get = Ember.get; - var ember$data$lib$system$store$$set = Ember.set; - var ember$data$lib$system$store$$once = Ember.run.once; - var ember$data$lib$system$store$$isNone = Ember.isNone; - var ember$data$lib$system$store$$forEach = Ember.EnumerableUtils.forEach; - var ember$data$lib$system$store$$indexOf = Ember.EnumerableUtils.indexOf; - var ember$data$lib$system$store$$map = Ember.EnumerableUtils.map; - var ember$data$lib$system$store$$Promise = Ember.RSVP.Promise; - var ember$data$lib$system$store$$copy = Ember.copy; - var ember$data$lib$system$store$$Store; - - var ember$data$lib$system$store$$camelize = Ember.String.camelize; - - // Implementors Note: - // - // The variables in this file are consistently named according to the following - // scheme: - // - // * +id+ means an identifier managed by an external source, provided inside - // the data provided by that source. These are always coerced to be strings - // before being used internally. - // * +clientId+ means a transient numerical identifier generated at runtime by - // the data store. It is important primarily because newly created objects may - // not yet have an externally generated id. - // * +reference+ means a record reference object, which holds metadata about a - // record, even if it has not yet been fully materialized. - // * +type+ means a subclass of DS.Model. - - // Used by the store to normalize IDs entering the store. Despite the fact - // that developers may provide IDs as numbers (e.g., `store.find(Person, 1)`), - // it is important that internally we use strings, since IDs may be serialized - // and lose type information. For example, Ember's router may put a record's - // ID into the URL, and if we later try to deserialize that URL and find the - // corresponding record, we will not know if it is a string or a number. - function ember$data$lib$system$store$$coerceId(id) { - return id == null ? null : id+''; - } - - /** - The store contains all of the data for records loaded from the server. - It is also responsible for creating instances of `DS.Model` that wrap - the individual data for a record, so that they can be bound to in your - Handlebars templates. - - Define your application's store like this: - - ```javascript - MyApp.Store = DS.Store.extend(); - ``` - - Most Ember.js applications will only have a single `DS.Store` that is - automatically created by their `Ember.Application`. - - You can retrieve models from the store in several ways. To retrieve a record - for a specific id, use `DS.Store`'s `find()` method: - - ```javascript - store.find('person', 123).then(function (person) { - }); - ``` - - By default, the store will talk to your backend using a standard - REST mechanism. You can customize how the store talks to your - backend by specifying a custom adapter: - - ```javascript - MyApp.ApplicationAdapter = MyApp.CustomAdapter - ``` - - You can learn more about writing a custom adapter by reading the `DS.Adapter` - documentation. - - ### Store createRecord() vs. push() vs. pushPayload() - - The store provides multiple ways to create new record objects. They have - some subtle differences in their use which are detailed below: - - [createRecord](#method_createRecord) is used for creating new - records on the client side. This will return a new record in the - `created.uncommitted` state. In order to persist this record to the - backend you will need to call `record.save()`. - - [push](#method_push) is used to notify Ember Data's store of new or - updated records that exist in the backend. This will return a record - in the `loaded.saved` state. The primary use-case for `store#push` is - to notify Ember Data about record updates (full or partial) that happen - outside of the normal adapter methods (for example - [SSE](http://dev.w3.org/html5/eventsource/) or [Web - Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). - - [pushPayload](#method_pushPayload) is a convenience wrapper for - `store#push` that will deserialize payloads if the - Serializer implements a `pushPayload` method. - - Note: When creating a new record using any of the above methods - Ember Data will update `DS.RecordArray`s such as those returned by - `store#all()`, `store#findAll()` or `store#filter()`. This means any - data bindings or computed properties that depend on the RecordArray - will automatically be synced to include the new or updated record - values. - - @class Store - @namespace DS - @extends Ember.Object - */ - ember$data$lib$system$store$$Store = Ember.Object.extend({ - - /** - @method init - @private - */ - init: function() { - this._backburner = new ember$data$lib$system$store$$Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); - // internal bookkeeping; not observable - this.typeMaps = {}; - this.recordArrayManager = ember$data$lib$system$record_array_manager$$default.create({ - store: this - }); - this._pendingSave = []; - //Used to keep track of all the find requests that need to be coalesced - this._pendingFetch = ember$data$lib$system$map$$Map.create(); - }, - - /** - The adapter to use to communicate to a backend server or other persistence layer. - - This can be specified as an instance, class, or string. - - If you want to specify `App.CustomAdapter` as a string, do: - - ```js - adapter: 'custom' - ``` - - @property adapter - @default DS.RESTAdapter - @type {DS.Adapter|String} - */ - adapter: '-rest', - - /** - Returns a JSON representation of the record using a custom - type-specific serializer, if one exists. - - The available options are: - - * `includeId`: `true` if the record's ID should be included in - the JSON representation - - @method serialize - @private - @param {DS.Model} record the record to serialize - @param {Object} options an options hash - */ - serialize: function(record, options) { - return this.serializerFor(record.constructor.typeKey).serialize(record, options); - }, - - /** - This property returns the adapter, after resolving a possible - string key. - - If the supplied `adapter` was a class, or a String property - path resolved to a class, this property will instantiate the - class. - - This property is cacheable, so the same instance of a specified - adapter class should be used for the lifetime of the store. - - @property defaultAdapter - @private - @return DS.Adapter - */ - defaultAdapter: Ember.computed('adapter', function() { - var adapter = ember$data$lib$system$store$$get(this, 'adapter'); - - Ember.assert('You tried to set `adapter` property to an instance of `DS.Adapter`, where it should be a name or a factory', !(adapter instanceof ember$data$lib$system$adapter$$Adapter)); - - if (typeof adapter === 'string') { - adapter = this.container.lookup('adapter:' + adapter) || this.container.lookup('adapter:application') || this.container.lookup('adapter:-rest'); - } - - if (DS.Adapter.detect(adapter)) { - adapter = adapter.create({ - container: this.container - }); - } - - return adapter; - }), - - // ..................... - // . CREATE NEW RECORD . - // ..................... - - /** - Create a new record in the current store. The properties passed - to this method are set on the newly created record. - - To create a new instance of `App.Post`: - - ```js - store.createRecord('post', { - title: "Rails is omakase" - }); - ``` - - @method createRecord - @param {String} type - @param {Object} properties a hash of properties to set on the - newly created record. - @return {DS.Model} record - */ - createRecord: function(typeName, inputProperties) { - var type = this.modelFor(typeName); - var properties = ember$data$lib$system$store$$copy(inputProperties) || {}; - - // If the passed properties do not include a primary key, - // give the adapter an opportunity to generate one. Typically, - // client-side ID generators will use something like uuid.js - // to avoid conflicts. - - if (ember$data$lib$system$store$$isNone(properties.id)) { - properties.id = this._generateId(type); - } - - // Coerce ID to a string - properties.id = ember$data$lib$system$store$$coerceId(properties.id); - - var record = this.buildRecord(type, properties.id); - - // Move the record out of its initial `empty` state into - // the `loaded` state. - record.loadedData(); - - // Set the properties specified on the record. - record.setProperties(properties); - - return record; - }, - - /** - If possible, this method asks the adapter to generate an ID for - a newly created record. - - @method _generateId - @private - @param {String} type - @return {String} if the adapter can generate one, an ID - */ - _generateId: function(type) { - var adapter = this.adapterFor(type); - - if (adapter && adapter.generateIdForRecord) { - return adapter.generateIdForRecord(this); - } - - return null; - }, - - // ................. - // . DELETE RECORD . - // ................. - - /** - For symmetry, a record can be deleted via the store. - - Example - - ```javascript - var post = store.createRecord('post', { - title: "Rails is omakase" - }); - - store.deleteRecord(post); - ``` - - @method deleteRecord - @param {DS.Model} record - */ - deleteRecord: function(record) { - record.deleteRecord(); - }, - - /** - For symmetry, a record can be unloaded via the store. Only - non-dirty records can be unloaded. - - Example - - ```javascript - store.find('post', 1).then(function(post) { - store.unloadRecord(post); - }); - ``` - - @method unloadRecord - @param {DS.Model} record - */ - unloadRecord: function(record) { - record.unloadRecord(); - }, - - // ................ - // . FIND RECORDS . - // ................ - - /** - This is the main entry point into finding records. The first parameter to - this method is the model's name as a string. - - --- - - To find a record by ID, pass the `id` as the second parameter: - - ```javascript - store.find('person', 1); - ``` - - The `find` method will always return a **promise** that will be resolved - with the record. If the record was already in the store, the promise will - be resolved immediately. Otherwise, the store will ask the adapter's `find` - method to find the necessary data. - - The `find` method will always resolve its promise with the same object for - a given type and `id`. - - --- - - You can optionally `preload` specific attributes and relationships that you know of - by passing them as the third argument to find. - - For example, if your Ember route looks like `/posts/1/comments/2` and your API route - for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment - without fetching the post you can pass in the post to the `find` call: - - ```javascript - store.find('comment', 2, {post: 1}); - ``` - - If you have access to the post model you can also pass the model itself: - - ```javascript - store.find('post', 1).then(function (myPostModel) { - store.find('comment', 2, {post: myPostModel}); - }); - ``` - - This way, your adapter's `find` or `buildURL` method will be able to look up the - relationship on the record and construct the nested URL without having to first - fetch the post. - - --- - - To find all records for a type, call `find` with no additional parameters: - - ```javascript - store.find('person'); - ``` - - This will ask the adapter's `findAll` method to find the records for the - given type, and return a promise that will be resolved once the server - returns the values. - - --- - - To find a record by a query, call `find` with a hash as the second - parameter: - - ```javascript - store.find('person', { page: 1 }); - ``` - - This will ask the adapter's `findQuery` method to find the records for - the query, and return a promise that will be resolved once the server - responds. - - @method find - @param {String or subclass of DS.Model} type - @param {Object|String|Integer|null} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models - @return {Promise} promise - */ - find: function(type, id, preload) { - Ember.assert("You need to pass a type to the store's find method", arguments.length >= 1); - Ember.assert("You may not pass `" + id + "` as id to the store's find method", arguments.length === 1 || !Ember.isNone(id)); - - if (arguments.length === 1) { - return this.findAll(type); - } - - // We are passed a query instead of an id. - if (Ember.typeOf(id) === 'object') { - return this.findQuery(type, id); - } - - return this.findById(type, ember$data$lib$system$store$$coerceId(id), preload); - }, - - /** - This method returns a fresh record for a given type and id combination. - - If a record is available for the given type/id combination, then - it will fetch this record from the store and call `reload()` on it. - That will fire a request to server and return a promise that will - resolve once the record has been reloaded. - If there's no record corresponding in the store it will simply call - `store.find`. - - Example - - ```javascript - App.PostRoute = Ember.Route.extend({ - model: function(params) { - return this.store.fetch('post', params.post_id); - } - }); - ``` - - @method fetch - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models - @return {Promise} promise - */ - fetch: function(type, id, preload) { - if (this.hasRecordForId(type, id)) { - return this.getById(type, id).reload(); - } else { - return this.find(type, id, preload); - } - }, - - /** - This method returns a record for a given type and id combination. - - @method findById - @private - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models - @return {Promise} promise - */ - findById: function(typeName, id, preload) { - - var type = this.modelFor(typeName); - var record = this.recordForId(type, id); - - return this._findByRecord(record, preload); - }, - - _findByRecord: function(record, preload) { - var fetchedRecord; - - if (preload) { - record._preloadData(preload); - } - - if (ember$data$lib$system$store$$get(record, 'isEmpty')) { - fetchedRecord = this.scheduleFetch(record); - //TODO double check about reloading - } else if (ember$data$lib$system$store$$get(record, 'isLoading')){ - fetchedRecord = record._loadingPromise; - } - - return ember$data$lib$system$promise_proxies$$promiseObject(fetchedRecord || record, "DS: Store#findByRecord " + record.typeKey + " with id: " + ember$data$lib$system$store$$get(record, 'id')); - }, - - /** - This method makes a series of requests to the adapter's `find` method - and returns a promise that resolves once they are all loaded. - - @private - @method findByIds - @param {String} type - @param {Array} ids - @return {Promise} promise - */ - findByIds: function(type, ids) { - var store = this; - - return ember$data$lib$system$promise_proxies$$promiseArray(Ember.RSVP.all(ember$data$lib$system$store$$map(ids, function(id) { - return store.findById(type, id); - })).then(Ember.A, null, "DS: Store#findByIds of " + type + " complete")); - }, - - /** - This method is called by `findById` if it discovers that a particular - type/id pair hasn't been loaded yet to kick off a request to the - adapter. - - @method fetchRecord - @private - @param {DS.Model} record - @return {Promise} promise - */ - fetchRecord: function(record) { - var type = record.constructor; - var id = ember$data$lib$system$store$$get(record, 'id'); - var adapter = this.adapterFor(type); - - Ember.assert("You tried to find a record but you have no adapter (for " + type + ")", adapter); - Ember.assert("You tried to find a record but your adapter (for " + type + ") does not implement 'find'", typeof adapter.find === 'function'); - - var promise = ember$data$lib$system$store$$_find(adapter, this, type, id, record); - return promise; - }, - - scheduleFetchMany: function(records) { - return ember$data$lib$system$store$$Promise.all(ember$data$lib$system$store$$map(records, this.scheduleFetch, this)); - }, - - scheduleFetch: function(record) { - var type = record.constructor; - if (ember$data$lib$system$store$$isNone(record)) { return null; } - if (record._loadingPromise) { return record._loadingPromise; } - - var resolver = Ember.RSVP.defer('Fetching ' + type + 'with id: ' + record.get('id')); - var recordResolverPair = { - record: record, - resolver: resolver - }; - var promise = resolver.promise; - - record.loadingData(promise); - - if (!this._pendingFetch.get(type)){ - this._pendingFetch.set(type, [recordResolverPair]); - } else { - this._pendingFetch.get(type).push(recordResolverPair); - } - Ember.run.scheduleOnce('afterRender', this, this.flushAllPendingFetches); - - return promise; - }, - - flushAllPendingFetches: function(){ - if (this.isDestroyed || this.isDestroying) { - return; - } - - this._pendingFetch.forEach(this._flushPendingFetchForType, this); - this._pendingFetch = ember$data$lib$system$map$$Map.create(); - }, - - _flushPendingFetchForType: function (recordResolverPairs, type) { - var store = this; - var adapter = store.adapterFor(type); - var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; - var records = Ember.A(recordResolverPairs).mapBy('record'); - - function _fetchRecord(recordResolverPair) { - recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record)); - } - - function resolveFoundRecords(records) { - ember$data$lib$system$store$$forEach(records, function(record){ - var pair = Ember.A(recordResolverPairs).findBy('record', record); - if (pair){ - var resolver = pair.resolver; - resolver.resolve(record); - } - }); - } - - function makeMissingRecordsRejector(requestedRecords) { - return function rejectMissingRecords(resolvedRecords) { - var missingRecords = requestedRecords.without(resolvedRecords); - rejectRecords(missingRecords); - }; - } - - function makeRecordsRejector(records) { - return function (error) { - rejectRecords(records, error); - }; - } - - function rejectRecords(records, error) { - ember$data$lib$system$store$$forEach(records, function(record){ - var pair = Ember.A(recordResolverPairs).findBy('record', record); - if (pair){ - var resolver = pair.resolver; - resolver.reject(error); - } - }); - } - - if (recordResolverPairs.length === 1) { - _fetchRecord(recordResolverPairs[0]); - } else if (shouldCoalesce) { - var groups = adapter.groupRecordsForFindMany(this, records); - ember$data$lib$system$store$$forEach(groups, function (groupOfRecords) { - var requestedRecords = Ember.A(groupOfRecords); - var ids = requestedRecords.mapBy('id'); - if (ids.length > 1) { - ember$data$lib$system$store$$_findMany(adapter, store, type, ids, requestedRecords). - then(resolveFoundRecords). - then(makeMissingRecordsRejector(requestedRecords)). - then(null, makeRecordsRejector(requestedRecords)); - } else if (ids.length === 1) { - var pair = Ember.A(recordResolverPairs).findBy('record', groupOfRecords[0]); - _fetchRecord(pair); - } else { - Ember.assert("You cannot return an empty array from adapter's method groupRecordsForFindMany", false); - } - }); - } else { - ember$data$lib$system$store$$forEach(recordResolverPairs, _fetchRecord); - } - }, - - /** - Get a record by a given type and ID without triggering a fetch. - - This method will synchronously return the record if it is available in the store, - otherwise it will return `null`. A record is available if it has been fetched earlier, or - pushed manually into the store. - - _Note: This is an synchronous method and does not return a promise._ - - ```js - var post = store.getById('post', 1); - - post.get('id'); // 1 - ``` - - @method getById - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @return {DS.Model|null} record - */ - getById: function(type, id) { - if (this.hasRecordForId(type, id)) { - return this.recordForId(type, id); - } else { - return null; - } - }, - - /** - This method is called by the record's `reload` method. - - This method calls the adapter's `find` method, which returns a promise. When - **that** promise resolves, `reloadRecord` will resolve the promise returned - by the record's `reload`. - - @method reloadRecord - @private - @param {DS.Model} record - @return {Promise} promise - */ - reloadRecord: function(record) { - var type = record.constructor; - var adapter = this.adapterFor(type); - var id = ember$data$lib$system$store$$get(record, 'id'); - - Ember.assert("You cannot reload a record without an ID", id); - Ember.assert("You tried to reload a record but you have no adapter (for " + type + ")", adapter); - Ember.assert("You tried to reload a record but your adapter does not implement `find`", typeof adapter.find === 'function'); - - return this.scheduleFetch(record); - }, - - /** - Returns true if a record for a given type and ID is already loaded. - - @method hasRecordForId - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @return {Boolean} - */ - hasRecordForId: function(typeName, inputId) { - var type = this.modelFor(typeName); - var id = ember$data$lib$system$store$$coerceId(inputId); - return !!this.typeMapFor(type).idToRecord[id]; - }, - - /** - Returns id record for a given type and ID. If one isn't already loaded, - it builds a new record and leaves it in the `empty` state. - - @method recordForId - @private - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @return {DS.Model} record - */ - recordForId: function(typeName, inputId) { - var type = this.modelFor(typeName); - var id = ember$data$lib$system$store$$coerceId(inputId); - var idToRecord = this.typeMapFor(type).idToRecord; - var record = idToRecord[id]; - - if (!record || !idToRecord[id]) { - record = this.buildRecord(type, id); - } - - return record; - }, - - /** - @method findMany - @private - @param {DS.Model} owner - @param {Array} records - @param {String or subclass of DS.Model} type - @param {Resolver} resolver - @return {DS.ManyArray} records - */ - findMany: function(records) { - var store = this; - return ember$data$lib$system$store$$Promise.all(ember$data$lib$system$store$$map(records, function(record) { - return store._findByRecord(record); - })); - }, - - - /** - If a relationship was originally populated by the adapter as a link - (as opposed to a list of IDs), this method is called when the - relationship is fetched. - - The link (which is usually a URL) is passed through unchanged, so the - adapter can make whatever request it wants. - - The usual use-case is for the server to register a URL as a link, and - then use that URL in the future to make a request for the relationship. - - @method findHasMany - @private - @param {DS.Model} owner - @param {any} link - @param {String or subclass of DS.Model} type - @return {Promise} promise - */ - findHasMany: function(owner, link, type) { - var adapter = this.adapterFor(owner.constructor); - - Ember.assert("You tried to load a hasMany relationship but you have no adapter (for " + owner.constructor + ")", adapter); - Ember.assert("You tried to load a hasMany relationship from a specified `link` in the original payload but your adapter does not implement `findHasMany`", typeof adapter.findHasMany === 'function'); - - return ember$data$lib$system$store$$_findHasMany(adapter, this, owner, link, type); - }, - - /** - @method findBelongsTo - @private - @param {DS.Model} owner - @param {any} link - @param {Relationship} relationship - @return {Promise} promise - */ - findBelongsTo: function(owner, link, relationship) { - var adapter = this.adapterFor(owner.constructor); - - Ember.assert("You tried to load a belongsTo relationship but you have no adapter (for " + owner.constructor + ")", adapter); - Ember.assert("You tried to load a belongsTo relationship from a specified `link` in the original payload but your adapter does not implement `findBelongsTo`", typeof adapter.findBelongsTo === 'function'); - - return ember$data$lib$system$store$$_findBelongsTo(adapter, this, owner, link, relationship); - }, - - /** - This method delegates a query to the adapter. This is the one place where - adapter-level semantics are exposed to the application. - - Exposing queries this way seems preferable to creating an abstract query - language for all server-side queries, and then require all adapters to - implement them. - - This method returns a promise, which is resolved with a `RecordArray` - once the server returns. - - @method findQuery - @private - @param {String or subclass of DS.Model} type - @param {any} query an opaque query to be used by the adapter - @return {Promise} promise - */ - findQuery: function(typeName, query) { - var type = this.modelFor(typeName); - var array = this.recordArrayManager - .createAdapterPopulatedRecordArray(type, query); - - var adapter = this.adapterFor(type); - - Ember.assert("You tried to load a query but you have no adapter (for " + type + ")", adapter); - Ember.assert("You tried to load a query but your adapter does not implement `findQuery`", typeof adapter.findQuery === 'function'); - - return ember$data$lib$system$promise_proxies$$promiseArray(ember$data$lib$system$store$$_findQuery(adapter, this, type, query, array)); - }, - - /** - This method returns an array of all records adapter can find. - It triggers the adapter's `findAll` method to give it an opportunity to populate - the array with records of that type. - - @method findAll - @private - @param {String or subclass of DS.Model} type - @return {DS.AdapterPopulatedRecordArray} - */ - findAll: function(typeName) { - var type = this.modelFor(typeName); - - return this.fetchAll(type, this.all(type)); - }, - - /** - @method fetchAll - @private - @param {DS.Model} type - @param {DS.RecordArray} array - @return {Promise} promise - */ - fetchAll: function(type, array) { - var adapter = this.adapterFor(type); - var sinceToken = this.typeMapFor(type).metadata.since; - - ember$data$lib$system$store$$set(array, 'isUpdating', true); - - Ember.assert("You tried to load all records but you have no adapter (for " + type + ")", adapter); - Ember.assert("You tried to load all records but your adapter does not implement `findAll`", typeof adapter.findAll === 'function'); - - return ember$data$lib$system$promise_proxies$$promiseArray(ember$data$lib$system$store$$_findAll(adapter, this, type, sinceToken)); - }, - - /** - @method didUpdateAll - @param {DS.Model} type - */ - didUpdateAll: function(type) { - var findAllCache = this.typeMapFor(type).findAllCache; - ember$data$lib$system$store$$set(findAllCache, 'isUpdating', false); - }, - - /** - This method returns a filtered array that contains all of the - known records for a given type in the store. - - Note that because it's just a filter, the result will contain any - locally created records of the type, however, it will not make a - request to the backend to retrieve additional records. If you - would like to request all the records from the backend please use - [store.find](#method_find). - - Also note that multiple calls to `all` for a given type will always - return the same `RecordArray`. - - Example - - ```javascript - var localPosts = store.all('post'); - ``` - - @method all - @param {String or subclass of DS.Model} type - @return {DS.RecordArray} - */ - all: function(typeName) { - var type = this.modelFor(typeName); - var typeMap = this.typeMapFor(type); - var findAllCache = typeMap.findAllCache; - - if (findAllCache) { - this.recordArrayManager.updateFilter(findAllCache, type); - return findAllCache; - } - - var array = this.recordArrayManager.createRecordArray(type); - - typeMap.findAllCache = array; - return array; - }, - - - /** - This method unloads all of the known records for a given type. - - ```javascript - store.unloadAll('post'); - ``` - - @method unloadAll - @param {String or subclass of DS.Model} type - */ - unloadAll: function(type) { - var modelType = this.modelFor(type); - var typeMap = this.typeMapFor(modelType); - var records = typeMap.records.slice(); - var record; - - for (var i = 0; i < records.length; i++) { - record = records[i]; - record.unloadRecord(); - record.destroy(); // maybe within unloadRecord - } - - typeMap.findAllCache = null; - }, - - /** - Takes a type and filter function, and returns a live RecordArray that - remains up to date as new records are loaded into the store or created - locally. - - The filter function takes a materialized record, and returns true - if the record should be included in the filter and false if it should - not. - - Example - - ```javascript - store.filter('post', function(post) { - return post.get('unread'); - }); - ``` - - The filter function is called once on all records for the type when - it is created, and then once on each newly loaded or created record. - - If any of a record's properties change, or if it changes state, the - filter function will be invoked again to determine whether it should - still be in the array. - - Optionally you can pass a query, which is the equivalent of calling - [find](#method_find) with that same query, to fetch additional records - from the server. The results returned by the server could then appear - in the filter if they match the filter function. - - The query itself is not used to filter records, it's only sent to your - server for you to be able to do server-side filtering. The filter - function will be applied on the returned results regardless. - - Example - - ```javascript - store.filter('post', { unread: true }, function(post) { - return post.get('unread'); - }).then(function(unreadPosts) { - unreadPosts.get('length'); // 5 - var unreadPost = unreadPosts.objectAt(0); - unreadPost.set('unread', false); - unreadPosts.get('length'); // 4 - }); - ``` - - @method filter - @param {String or subclass of DS.Model} type - @param {Object} query optional query - @param {Function} filter - @return {DS.PromiseArray} - */ - filter: function(type, query, filter) { - var promise; - var length = arguments.length; - var array; - var hasQuery = length === 3; - - // allow an optional server query - if (hasQuery) { - promise = this.findQuery(type, query); - } else if (arguments.length === 2) { - filter = query; - } - - type = this.modelFor(type); - - if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(type, filter, query); - } else { - array = this.recordArrayManager.createFilteredRecordArray(type, filter); - } - - promise = promise || ember$data$lib$system$store$$Promise.cast(array); - - return ember$data$lib$system$promise_proxies$$promiseArray(promise.then(function() { - return array; - }, null, "DS: Store#filter of " + type)); - }, - - /** - This method returns if a certain record is already loaded - in the store. Use this function to know beforehand if a find() - will result in a request or that it will be a cache hit. - - Example - - ```javascript - store.recordIsLoaded('post', 1); // false - store.find('post', 1).then(function() { - store.recordIsLoaded('post', 1); // true - }); - ``` - - @method recordIsLoaded - @param {String or subclass of DS.Model} type - @param {string} id - @return {boolean} - */ - recordIsLoaded: function(type, id) { - if (!this.hasRecordForId(type, id)) { return false; } - return !ember$data$lib$system$store$$get(this.recordForId(type, id), 'isEmpty'); - }, - - /** - This method returns the metadata for a specific type. - - @method metadataFor - @param {String or subclass of DS.Model} typeName - @return {object} - */ - metadataFor: function(typeName) { - var type = this.modelFor(typeName); - return this.typeMapFor(type).metadata; - }, - - /** - This method sets the metadata for a specific type. - - @method setMetadataFor - @param {String or subclass of DS.Model} typeName - @param {Object} metadata metadata to set - @return {object} - */ - setMetadataFor: function(typeName, metadata) { - var type = this.modelFor(typeName); - Ember.merge(this.typeMapFor(type).metadata, metadata); - }, - - // ............ - // . UPDATING . - // ............ - - /** - If the adapter updates attributes or acknowledges creation - or deletion, the record will notify the store to update its - membership in any filters. - To avoid thrashing, this method is invoked only once per - - run loop per record. - - @method dataWasUpdated - @private - @param {Class} type - @param {DS.Model} record - */ - dataWasUpdated: function(type, record) { - this.recordArrayManager.recordDidChange(record); - }, - - // .............. - // . PERSISTING . - // .............. - - /** - This method is called by `record.save`, and gets passed a - resolver for the promise that `record.save` returns. - - It schedules saving to happen at the end of the run loop. - - @method scheduleSave - @private - @param {DS.Model} record - @param {Resolver} resolver - */ - scheduleSave: function(record, resolver) { - record.adapterWillCommit(); - this._pendingSave.push([record, resolver]); - ember$data$lib$system$store$$once(this, 'flushPendingSave'); - }, - - /** - This method is called at the end of the run loop, and - flushes any records passed into `scheduleSave` - - @method flushPendingSave - @private - */ - flushPendingSave: function() { - var pending = this._pendingSave.slice(); - this._pendingSave = []; - - ember$data$lib$system$store$$forEach(pending, function(tuple) { - var record = tuple[0], resolver = tuple[1]; - var adapter = this.adapterFor(record.constructor); - var operation; - - if (ember$data$lib$system$store$$get(record, 'currentState.stateName') === 'root.deleted.saved') { - return resolver.resolve(record); - } else if (ember$data$lib$system$store$$get(record, 'isNew')) { - operation = 'createRecord'; - } else if (ember$data$lib$system$store$$get(record, 'isDeleted')) { - operation = 'deleteRecord'; - } else { - operation = 'updateRecord'; - } - - resolver.resolve(ember$data$lib$system$store$$_commit(adapter, this, operation, record)); - }, this); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is resolved. - - If the data provides a server-generated ID, it will - update the record and the store's indexes. - - @method didSaveRecord - @private - @param {DS.Model} record the in-flight record - @param {Object} data optional data (see above) - */ - didSaveRecord: function(record, data) { - if (data) { - // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', record, record.constructor, data); - this.updateId(record, data); - } - - //We first make sure the primary data has been updated - //TODO try to move notification to the user to the end of the runloop - record.adapterDidCommit(data); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected with a `DS.InvalidError`. - - @method recordWasInvalid - @private - @param {DS.Model} record - @param {Object} errors - */ - recordWasInvalid: function(record, errors) { - record.adapterDidInvalidate(errors); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected (with anything other than a `DS.InvalidError`). - - @method recordWasError - @private - @param {DS.Model} record - */ - recordWasError: function(record) { - record.adapterDidError(); - }, - - /** - When an adapter's `createRecord`, `updateRecord` or `deleteRecord` - resolves with data, this method extracts the ID from the supplied - data. - - @method updateId - @private - @param {DS.Model} record - @param {Object} data - */ - updateId: function(record, data) { - var oldId = ember$data$lib$system$store$$get(record, 'id'); - var id = ember$data$lib$system$store$$coerceId(data.id); - - Ember.assert("An adapter cannot assign a new id to a record that already has an id. " + record + " had id: " + oldId + " and you tried to update it with " + id + ". This likely happened because your server returned data in response to a find or update that had a different id than the one you sent.", oldId === null || id === oldId); - - this.typeMapFor(record.constructor).idToRecord[id] = record; - - ember$data$lib$system$store$$set(record, 'id', id); - }, - - /** - Returns a map of IDs to client IDs for a given type. - - @method typeMapFor - @private - @param {subclass of DS.Model} type - @return {Object} typeMap - */ - typeMapFor: function(type) { - var typeMaps = ember$data$lib$system$store$$get(this, 'typeMaps'); - var guid = Ember.guidFor(type); - var typeMap; - - typeMap = typeMaps[guid]; - - if (typeMap) { return typeMap; } - - typeMap = { - idToRecord: Ember.create(null), - records: [], - metadata: Ember.create(null), - type: type - }; - - typeMaps[guid] = typeMap; - - return typeMap; - }, - - // ................ - // . LOADING DATA . - // ................ - - /** - This internal method is used by `push`. - - @method _load - @private - @param {String or subclass of DS.Model} type - @param {Object} data - */ - _load: function(type, data) { - var id = ember$data$lib$system$store$$coerceId(data.id); - var record = this.recordForId(type, id); - - record.setupData(data); - this.recordArrayManager.recordDidChange(record); - - return record; - }, - - /** - Returns a model class for a particular key. Used by - methods that take a type key (like `find`, `createRecord`, - etc.) - - @method modelFor - @param {String or subclass of DS.Model} key - @return {subclass of DS.Model} - */ - modelFor: function(key) { - var factory; - - if (typeof key === 'string') { - factory = this.modelFactoryFor(key); - if (!factory) { - throw new Ember.Error("No model was found for '" + key + "'"); - } - factory.typeKey = factory.typeKey || this._normalizeTypeKey(key); - } else { - // A factory already supplied. Ensure it has a normalized key. - factory = key; - if (factory.typeKey) { - factory.typeKey = this._normalizeTypeKey(factory.typeKey); - } - } - - factory.store = this; - return factory; - }, - - modelFactoryFor: function(key){ - return this.container.lookupFactory('model:' + key); - }, - - /** - Push some data for a given type into the store. - - This method expects normalized data: - - * The ID is a key named `id` (an ID is mandatory) - * The names of attributes are the ones you used in - your model's `DS.attr`s. - * Your relationships must be: - * represented as IDs or Arrays of IDs - * represented as model instances - * represented as URLs, under the `links` key - - For this model: - - ```js - App.Person = DS.Model.extend({ - firstName: DS.attr(), - lastName: DS.attr(), - - children: DS.hasMany('person') - }); - ``` - - To represent the children as IDs: - - ```js - { - id: 1, - firstName: "Tom", - lastName: "Dale", - children: [1, 2, 3] - } - ``` - - To represent the children relationship as a URL: - - ```js - { - id: 1, - firstName: "Tom", - lastName: "Dale", - links: { - children: "/people/1/children" - } - } - ``` - - If you're streaming data or implementing an adapter, make sure - that you have converted the incoming data into this form. The - store's [normalize](#method_normalize) method is a convenience - helper for converting a json payload into the form Ember Data - expects. - - ```js - store.push('person', store.normalize('person', data)); - ``` - - This method can be used both to push in brand new - records, as well as to update existing records. - - @method push - @param {String or subclass of DS.Model} type - @param {Object} data - @return {DS.Model} the record that was created or - updated. - */ - push: function(typeName, data) { - Ember.assert("Expected an object as `data` in a call to `push` for " + typeName + " , but was " + data, Ember.typeOf(data) === 'object'); - Ember.assert("You must include an `id` for " + typeName + " in an object passed to `push`", data.id != null && data.id !== ''); - - var type = this.modelFor(typeName); - var filter = Ember.EnumerableUtils.filter; - - // If the payload contains unused keys log a warning. - // Adding `Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = true` will suppress the warning. - if (!Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS) { - Ember.warn("The payload for '" + type.typeKey + "' contains these unknown keys: " + - Ember.inspect(filter(Ember.keys(data), function(key) { - return !ember$data$lib$system$store$$get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; - })) + ". Make sure they've been defined in your model.", - filter(Ember.keys(data), function(key) { - return !ember$data$lib$system$store$$get(type, 'fields').has(key) && key !== 'id' && key !== 'links'; - }).length === 0 - ); - } - - // Actually load the record into the store. - - this._load(type, data); - - var record = this.recordForId(type, data.id); - var store = this; - - this._backburner.join(function() { - store._backburner.schedule('normalizeRelationships', store, '_setupRelationships', record, type, data); - }); - - return record; - }, - - _setupRelationships: function(record, type, data) { - // If the payload contains relationships that are specified as - // IDs, normalizeRelationships will convert them into DS.Model instances - // (possibly unloaded) before we push the payload into the - // store. - - data = ember$data$lib$system$store$$normalizeRelationships(this, type, data); - - - // Now that the pushed record as well as any related records - // are in the store, create the data structures used to track - // relationships. - ember$data$lib$system$store$$setupRelationships(this, record, data); - }, - - /** - Push some raw data into the store. - - This method can be used both to push in brand new - records, as well as to update existing records. You - can push in more than one type of object at once. - All objects should be in the format expected by the - serializer. - - ```js - App.ApplicationSerializer = DS.ActiveModelSerializer; - - var pushData = { - posts: [ - {id: 1, post_title: "Great post", comment_ids: [2]} - ], - comments: [ - {id: 2, comment_body: "Insightful comment"} - ] - } - - store.pushPayload(pushData); - ``` - - By default, the data will be deserialized using a default - serializer (the application serializer if it exists). - - Alternatively, `pushPayload` will accept a model type which - will determine which serializer will process the payload. - However, the serializer itself (processing this data via - `normalizePayload`) will not know which model it is - deserializing. - - ```js - App.ApplicationSerializer = DS.ActiveModelSerializer; - App.PostSerializer = DS.JSONSerializer; - store.pushPayload('comment', pushData); // Will use the ApplicationSerializer - store.pushPayload('post', pushData); // Will use the PostSerializer - ``` - - @method pushPayload - @param {String} type Optionally, a model used to determine which serializer will be used - @param {Object} payload - */ - pushPayload: function (type, inputPayload) { - var serializer; - var payload; - if (!inputPayload) { - payload = type; - serializer = ember$data$lib$system$store$$defaultSerializer(this.container); - Ember.assert("You cannot use `store#pushPayload` without a type unless your default serializer defines `pushPayload`", typeof serializer.pushPayload === 'function'); - } else { - payload = inputPayload; - serializer = this.serializerFor(type); - } - var store = this; - ember$data$lib$system$store$$_adapterRun(this, function() { - serializer.pushPayload(store, payload); - }); - }, - - /** - `normalize` converts a json payload into the normalized form that - [push](#method_push) expects. - - Example - - ```js - socket.on('message', function(message) { - var modelName = message.model; - var data = message.data; - store.push(modelName, store.normalize(modelName, data)); - }); - ``` - - @method normalize - @param {String} type The name of the model type for this payload - @param {Object} payload - @return {Object} The normalized payload - */ - normalize: function (type, payload) { - var serializer = this.serializerFor(type); - var model = this.modelFor(type); - return serializer.normalize(model, payload); - }, - - /** - @method update - @param {String} type - @param {Object} data - @return {DS.Model} the record that was updated. - @deprecated Use [push](#method_push) instead - */ - update: function(type, data) { - Ember.deprecate('Using store.update() has been deprecated since store.push() now handles partial updates. You should use store.push() instead.'); - return this.push(type, data); - }, - - /** - If you have an Array of normalized data to push, - you can call `pushMany` with the Array, and it will - call `push` repeatedly for you. - - @method pushMany - @param {String or subclass of DS.Model} type - @param {Array} datas - @return {Array} - */ - pushMany: function(type, datas) { - var length = datas.length; - var result = new Array(length); - - for (var i = 0; i < length; i++) { - result[i] = this.push(type, datas[i]); - } - - return result; - }, - - /** - @method metaForType - @param {String or subclass of DS.Model} typeName - @param {Object} metadata - @deprecated Use [setMetadataFor](#method_setMetadataFor) instead - */ - metaForType: function(typeName, metadata) { - Ember.deprecate('Using store.metaForType() has been deprecated. Use store.setMetadataFor() to set metadata for a specific type.'); - this.setMetadataFor(typeName, metadata); - }, - - /** - Build a brand new record for a given type, ID, and - initial data. - - @method buildRecord - @private - @param {subclass of DS.Model} type - @param {String} id - @param {Object} data - @return {DS.Model} record - */ - buildRecord: function(type, id, data) { - var typeMap = this.typeMapFor(type); - var idToRecord = typeMap.idToRecord; - - Ember.assert('The id ' + id + ' has already been used with another record of type ' + type.toString() + '.', !id || !idToRecord[id]); - Ember.assert("`" + Ember.inspect(type)+ "` does not appear to be an ember-data model", (typeof type._create === 'function') ); - - // lookupFactory should really return an object that creates - // instances with the injections applied - var record = type._create({ - id: id, - store: this, - container: this.container - }); - - if (data) { - record.setupData(data); - } - - // if we're creating an item, this process will be done - // later, once the object has been persisted. - if (id) { - idToRecord[id] = record; - } - - typeMap.records.push(record); - - return record; - }, - - // ............... - // . DESTRUCTION . - // ............... - - /** - When a record is destroyed, this un-indexes it and - removes it from any record arrays so it can be GCed. - - @method dematerializeRecord - @private - @param {DS.Model} record - */ - dematerializeRecord: function(record) { - var type = record.constructor; - var typeMap = this.typeMapFor(type); - var id = ember$data$lib$system$store$$get(record, 'id'); - - record.updateRecordArrays(); - - if (id) { - delete typeMap.idToRecord[id]; - } - - var loc = ember$data$lib$system$store$$indexOf(typeMap.records, record); - typeMap.records.splice(loc, 1); - }, - - // ...................... - // . PER-TYPE ADAPTERS - // ...................... - - /** - Returns the adapter for a given type. - - @method adapterFor - @private - @param {subclass of DS.Model} type - @return DS.Adapter - */ - adapterFor: function(type) { - var container = this.container, adapter; - - if (container) { - adapter = container.lookup('adapter:' + type.typeKey) || container.lookup('adapter:application'); - } - - return adapter || ember$data$lib$system$store$$get(this, 'defaultAdapter'); - }, - - // .............................. - // . RECORD CHANGE NOTIFICATION . - // .............................. - - /** - Returns an instance of the serializer for a given type. For - example, `serializerFor('person')` will return an instance of - `App.PersonSerializer`. - - If no `App.PersonSerializer` is found, this method will look - for an `App.ApplicationSerializer` (the default serializer for - your entire application). - - If no `App.ApplicationSerializer` is found, it will fall back - to an instance of `DS.JSONSerializer`. - - @method serializerFor - @private - @param {String} type the record to serialize - @return {DS.Serializer} - */ - serializerFor: function(type) { - type = this.modelFor(type); - var adapter = this.adapterFor(type); - - return ember$data$lib$system$store$$serializerFor(this.container, type.typeKey, adapter && adapter.defaultSerializer); - }, - - willDestroy: function() { - var typeMaps = this.typeMaps; - var keys = Ember.keys(typeMaps); - - var types = ember$data$lib$system$store$$map(keys, byType); - - this.recordArrayManager.destroy(); - - ember$data$lib$system$store$$forEach(types, this.unloadAll, this); - - function byType(entry) { - return typeMaps[entry]['type']; - } - - }, - - /** - All typeKeys are camelCase internally. Changing this function may - require changes to other normalization hooks (such as typeForRoot). - - @method _normalizeTypeKey - @private - @param {String} type - @return {String} if the adapter can generate one, an ID - */ - _normalizeTypeKey: function(key) { - return ember$data$lib$system$store$$camelize(ember$inflector$lib$system$string$$singularize(key)); - } - }); - - - function ember$data$lib$system$store$$normalizeRelationships(store, type, data, record) { - type.eachRelationship(function(key, relationship) { - var kind = relationship.kind; - var value = data[key]; - if (kind === 'belongsTo') { - ember$data$lib$system$store$$deserializeRecordId(store, data, key, relationship, value); - } else if (kind === 'hasMany') { - ember$data$lib$system$store$$deserializeRecordIds(store, data, key, relationship, value); - } - }); - - return data; - } - - function ember$data$lib$system$store$$deserializeRecordId(store, data, key, relationship, id) { - if (ember$data$lib$system$store$$isNone(id) || id instanceof ember$data$lib$system$model$model$$default) { - return; - } - Ember.assert("A " + relationship.parentType + " record was pushed into the store with the value of " + key + " being " + Ember.inspect(id) + ", but " + key + " is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.", !Ember.isArray(id)); - - var type; - - if (typeof id === 'number' || typeof id === 'string') { - type = ember$data$lib$system$store$$typeFor(relationship, key, data); - data[key] = store.recordForId(type, id); - } else if (typeof id === 'object') { - // polymorphic - Ember.assert('Ember Data expected a number or string to represent the record(s) in the `' + relationship.key + '` relationship instead it found an object. If this is a polymorphic relationship please specify a `type` key. If this is an embedded relationship please include the `DS.EmbeddedRecordsMixin` and specify the `' + relationship.key +'` property in your serializer\'s attrs hash.', id.type); - data[key] = store.recordForId(id.type, id.id); - } - } - - function ember$data$lib$system$store$$typeFor(relationship, key, data) { - if (relationship.options.polymorphic) { - return data[key + "Type"]; - } else { - return relationship.type; - } - } - - function ember$data$lib$system$store$$deserializeRecordIds(store, data, key, relationship, ids) { - if (ember$data$lib$system$store$$isNone(ids)) { - return; - } - - Ember.assert("A " + relationship.parentType + " record was pushed into the store with the value of " + key + " being '" + Ember.inspect(ids) + "', but " + key + " is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.", Ember.isArray(ids)); - for (var i=0, l=ids.length; i self.attributeLimit) { return false; } - var desc = ember$data$lib$system$debug$debug_adapter$$capitalize(ember$data$lib$system$debug$debug_adapter$$underscore(name).replace('_', ' ')); - columns.push({ name: name, desc: desc }); - }); - return columns; - }, - - getRecords: function(type) { - return this.get('store').all(type); - }, - - getRecordColumnValues: function(record) { - var self = this, count = 0; - var columnValues = { id: ember$data$lib$system$debug$debug_adapter$$get(record, 'id') }; - - record.eachAttribute(function(key) { - if (count++ > self.attributeLimit) { - return false; - } - var value = ember$data$lib$system$debug$debug_adapter$$get(record, key); - columnValues[key] = value; - }); - return columnValues; - }, - - getRecordKeywords: function(record) { - var keywords = []; - var keys = Ember.A(['id']); - record.eachAttribute(function(key) { - keys.push(key); - }); - keys.forEach(function(key) { - keywords.push(ember$data$lib$system$debug$debug_adapter$$get(record, key)); - }); - return keywords; - }, - - getRecordFilterValues: function(record) { - return { - isNew: record.get('isNew'), - isModified: record.get('isDirty') && !record.get('isNew'), - isClean: !record.get('isDirty') - }; - }, - - getRecordColor: function(record) { - var color = 'black'; - if (record.get('isNew')) { - color = 'green'; - } else if (record.get('isDirty')) { - color = 'blue'; - } - return color; - }, - - observeRecord: function(record, recordUpdated) { - var releaseMethods = Ember.A(), self = this; - var keysToObserve = Ember.A(['id', 'isNew', 'isDirty']); - - record.eachAttribute(function(key) { - keysToObserve.push(key); - }); - - keysToObserve.forEach(function(key) { - var handler = function() { - recordUpdated(self.wrapRecord(record)); - }; - Ember.addObserver(record, key, handler); - releaseMethods.push(function() { - Ember.removeObserver(record, key, handler); - }); - }); - - var release = function() { - releaseMethods.forEach(function(fn) { fn(); } ); - }; - - return release; - } - - }); - - function ember$data$lib$initializers$data_adapter$$initializeDebugAdapter(container){ - container.register('data-adapter:main', ember$data$lib$system$debug$debug_adapter$$default); - } - var ember$data$lib$initializers$data_adapter$$default = ember$data$lib$initializers$data_adapter$$initializeDebugAdapter; - function ember$data$lib$setup$container$$setupContainer(container, application){ - // application is not a required argument. This ensures - // testing setups can setup a container without booting an - // entire ember application. - - ember$data$lib$initializers$data_adapter$$default(container, application); - ember$data$lib$initializers$transforms$$default(container, application); - ember$data$lib$initializers$store_injections$$default(container, application); - ember$data$lib$initializers$store$$default(container, application); - activemodel$adapter$lib$setup$container$$default(container, application); - } - var ember$data$lib$setup$container$$default = ember$data$lib$setup$container$$setupContainer; - - var ember$data$lib$ember$initializer$$K = Ember.K; - - /** - @module ember-data - */ - - /* - - This code initializes Ember-Data onto an Ember application. - - If an Ember.js developer defines a subclass of DS.Store on their application, - as `App.ApplicationStore` (or via a module system that resolves to `store:application`) - this code will automatically instantiate it and make it available on the - router. - - Additionally, after an application's controllers have been injected, they will - each have the store made available to them. - - For example, imagine an Ember.js application with the following classes: - - App.ApplicationStore = DS.Store.extend({ - adapter: 'custom' - }); - - App.PostsController = Ember.ArrayController.extend({ - // ... - }); - - When the application is initialized, `App.ApplicationStore` will automatically be - instantiated, and the instance of `App.PostsController` will have its `store` - property set to that instance. - - Note that this code will only be run if the `ember-application` package is - loaded. If Ember Data is being used in an environment other than a - typical application (e.g., node.js where only `ember-runtime` is available), - this code will be ignored. - */ - - Ember.onLoad('Ember.Application', function(Application) { - - Application.initializer({ - name: "ember-data", - initialize: ember$data$lib$setup$container$$default - }); - - // Deprecated initializers to satisfy old code that depended on them - - Application.initializer({ - name: "store", - after: "ember-data", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "activeModelAdapter", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "transforms", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "data-adapter", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "injectStore", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - }); - /** - @module ember-data - */ - - /** - Date.parse with progressive enhancement for ISO 8601 - - © 2011 Colin Snover - - Released under MIT license. - - @class Date - @namespace Ember - @static - */ - Ember.Date = Ember.Date || {}; - - var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ]; - - /** - @method parse - @param {Date} date - @return {Number} timestamp - */ - Ember.Date.parse = function (date) { - var timestamp, struct, minutesOffset = 0; - - // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string - // before falling back to any implementation-specific date parsing, so that’s what we do, even if native - // implementations could be faster - // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) { - // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC - for (var i = 0, k; (k = numericKeys[i]); ++i) { - struct[k] = +struct[k] || 0; - } - - // allow undefined days and months - struct[2] = (+struct[2] || 1) - 1; - struct[3] = +struct[3] || 1; - - if (struct[8] !== 'Z' && struct[9] !== undefined) { - minutesOffset = struct[10] * 60 + struct[11]; - - if (struct[9] === '+') { - minutesOffset = 0 - minutesOffset; - } - } - - timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); - } - else { - timestamp = origParse ? origParse(date) : NaN; - } - - return timestamp; - }; - - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) { - Date.parse = Ember.Date.parse; - } - /* - Detect if the user has a correct Object.create shim. - Ember has provided this for a long time but has had an incorrect shim before 1.8 - TODO: Remove for Ember Data 1.0. - */ - var object = Ember.create(null); - if (object.toString !== undefined && Ember.keys(Ember.create({}))[0] === '__proto__'){ - throw new Error("Ember Data requires a correct Object.create shim. You should upgrade to Ember >= 1.8 which provides one for you. If you are using ES5-shim, you should try removing that after upgrading Ember."); - } - - ember$data$lib$system$model$model$$default.reopen({ - - /** - Provides info about the model for debugging purposes - by grouping the properties into more semantic groups. - - Meant to be used by debugging tools such as the Chrome Ember Extension. - - - Groups all attributes in "Attributes" group. - - Groups all belongsTo relationships in "Belongs To" group. - - Groups all hasMany relationships in "Has Many" group. - - Groups all flags in "Flags" group. - - Flags relationship CPs as expensive properties. - - @method _debugInfo - @for DS.Model - @private - */ - _debugInfo: function() { - var attributes = ['id'], - relationships = { belongsTo: [], hasMany: [] }, - expensiveProperties = []; - - this.eachAttribute(function(name, meta) { - attributes.push(name); - }, this); - - this.eachRelationship(function(name, relationship) { - relationships[relationship.kind].push(name); - expensiveProperties.push(name); - }); - - var groups = [ - { - name: 'Attributes', - properties: attributes, - expand: true - }, - { - name: 'Belongs To', - properties: relationships.belongsTo, - expand: true - }, - { - name: 'Has Many', - properties: relationships.hasMany, - expand: true - }, - { - name: 'Flags', - properties: ['isLoaded', 'isDirty', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] - } - ]; - - return { - propertyInfo: { - // include all other mixins / properties (not just the grouped ones) - includeOtherProperties: true, - groups: groups, - // don't pre-calculate unless cached - expensiveProperties: expensiveProperties - } - }; - } - }); - - var ember$data$lib$system$debug$debug_info$$default = ember$data$lib$system$model$model$$default; - var ember$data$lib$system$debug$$default = ember$data$lib$system$debug$debug_adapter$$default; - var ember$data$lib$serializers$embedded_records_mixin$$get = Ember.get; - var ember$data$lib$serializers$embedded_records_mixin$$forEach = Ember.EnumerableUtils.forEach; - var ember$data$lib$serializers$embedded_records_mixin$$camelize = Ember.String.camelize; - - /** - ## Using Embedded Records - - `DS.EmbeddedRecordsMixin` supports serializing embedded records. - - To set up embedded records, include the mixin when extending a serializer - then define and configure embedded (model) relationships. - - Below is an example of a per-type serializer ('post' type). - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - author: { embedded: 'always' }, - comments: { serialize: 'ids' } - } - }); - ``` - Note that this use of `{ embedded: 'always' }` is unrelated to - the `{ embedded: 'always' }` that is defined as an option on `DS.attr` as part of - defining a model while working with the ActiveModelSerializer. Nevertheless, - using `{ embedded: 'always' }` as an option to DS.attr is not a valid way to setup - embedded records. - - The `attrs` option for a resource `{ embedded: 'always' }` is shorthand for: - - ```js - { - serialize: 'records', - deserialize: 'records' - } - ``` - - ### Configuring Attrs - - A resource's `attrs` option may be set to use `ids`, `records` or false for the - `serialize` and `deserialize` settings. - - The `attrs` property can be set on the ApplicationSerializer or a per-type - serializer. - - In the case where embedded JSON is expected while extracting a payload (reading) - the setting is `deserialize: 'records'`, there is no need to use `ids` when - extracting as that is the default behavior without this mixin if you are using - the vanilla EmbeddedRecordsMixin. Likewise, to embed JSON in the payload while - serializing `serialize: 'records'` is the setting to use. There is an option of - not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you - do not want the relationship sent at all, you can use `serialize: false`. - - - ### EmbeddedRecordsMixin defaults - If you do not overwrite `attrs` for a specific relationship, the `EmbeddedRecordsMixin` - will behave in the following way: - - BelongsTo: `{ serialize: 'id', deserialize: 'id' }` - HasMany: `{ serialize: false, deserialize: 'ids' }` - - ### Model Relationships - - Embedded records must have a model defined to be extracted and serialized. Note that - when defining any relationships on your model such as `belongsTo` and `hasMany`, you - should not both specify `async:true` and also indicate through the serializer's - `attrs` attribute that the related model should be embedded. If a model is - declared embedded, then do not use `async:true`. - - To successfully extract and serialize embedded records the model relationships - must be setup correcty See the - [defining relationships](/guides/models/defining-models/#toc_defining-relationships) - section of the **Defining Models** guide page. - - Records without an `id` property are not considered embedded records, model - instances must have an `id` property to be used with Ember Data. - - ### Example JSON payloads, Models and Serializers - - **When customizing a serializer it is important to grok what the customizations - are. Please read the docs for the methods this mixin provides, in case you need - to modify it to fit your specific needs.** - - For example review the docs for each method of this mixin: - * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) - * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) - * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) - - @class EmbeddedRecordsMixin - @namespace DS - */ - var ember$data$lib$serializers$embedded_records_mixin$$EmbeddedRecordsMixin = Ember.Mixin.create({ - - /** - Normalize the record and recursively normalize/extract all the embedded records - while pushing them into the store as they are encountered - - A payload with an attr configured for embedded records needs to be extracted: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "comments": [{ - "id": "1", - "body": "Rails is unagi" - }, { - "id": "2", - "body": "Omakase O_o" - }] - } - } - ``` - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash to be normalized - @param {String} key the hash has been referenced by - @return {Object} the normalized hash - **/ - normalize: function(type, hash, prop) { - var normalizedHash = this._super(type, hash, prop); - return ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedRecords(this, this.store, type, normalizedHash); - }, - - keyForRelationship: function(key, type){ - if (this.hasDeserializeRecordsOption(key)) { - return this.keyForAttribute(key); - } else { - return this._super(key, type) || key; - } - }, - - /** - Serialize `belongsTo` relationship when it is configured as an embedded object. - - This example of an author model belongs to a post model: - - ```js - Post = DS.Model.extend({ - title: DS.attr('string'), - body: DS.attr('string'), - author: DS.belongsTo('author') - }); - - Author = DS.Model.extend({ - name: DS.attr('string'), - post: DS.belongsTo('post') - }); - ``` - - Use a custom (type) serializer for the post model to configure embedded author - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - author: {embedded: 'always'} - } - }) - ``` - - A payload with an attribute configured for embedded records can serialize - the records together under the root attribute's payload: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "author": { - "id": "2" - "name": "dhh" - } - } - } - ``` - - @method serializeBelongsTo - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeBelongsTo: function(record, json, relationship) { - var attr = relationship.key; - if (this.noSerializeOptionSpecified(attr)) { - this._super(record, json, relationship); - return; - } - var includeIds = this.hasSerializeIdsOption(attr); - var includeRecords = this.hasSerializeRecordsOption(attr); - var embeddedRecord = record.get(attr); - var key; - if (includeIds) { - key = this.keyForRelationship(attr, relationship.kind); - if (!embeddedRecord) { - json[key] = null; - } else { - json[key] = ember$data$lib$serializers$embedded_records_mixin$$get(embeddedRecord, 'id'); - } - } else if (includeRecords) { - key = this.keyForAttribute(attr); - if (!embeddedRecord) { - json[key] = null; - } else { - json[key] = embeddedRecord.serialize({includeId: true}); - this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, json[key]); - } - } - }, - - /** - Serialize `hasMany` relationship when it is configured as embedded objects. - - This example of a post model has many comments: - - ```js - Post = DS.Model.extend({ - title: DS.attr('string'), - body: DS.attr('string'), - comments: DS.hasMany('comment') - }); - - Comment = DS.Model.extend({ - body: DS.attr('string'), - post: DS.belongsTo('post') - }); - ``` - - Use a custom (type) serializer for the post model to configure embedded comments - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - comments: {embedded: 'always'} - } - }) - ``` - - A payload with an attribute configured for embedded records can serialize - the records together under the root attribute's payload: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "body": "I want this for my ORM, I want that for my template language..." - "comments": [{ - "id": "1", - "body": "Rails is unagi" - }, { - "id": "2", - "body": "Omakase O_o" - }] - } - } - ``` - - The attrs options object can use more specific instruction for extracting and - serializing. When serializing, an option to embed `ids` or `records` can be set. - When extracting the only option is `records`. - - So `{embedded: 'always'}` is shorthand for: - `{serialize: 'records', deserialize: 'records'}` - - To embed the `ids` for a related object (using a hasMany relationship): - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - comments: {serialize: 'ids', deserialize: 'records'} - } - }) - ``` - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "body": "I want this for my ORM, I want that for my template language..." - "comments": ["1", "2"] - } - } - ``` - - @method serializeHasMany - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeHasMany: function(record, json, relationship) { - var attr = relationship.key; - if (this.noSerializeOptionSpecified(attr)) { - this._super(record, json, relationship); - return; - } - var includeIds = this.hasSerializeIdsOption(attr); - var includeRecords = this.hasSerializeRecordsOption(attr); - var key; - if (includeIds) { - key = this.keyForRelationship(attr, relationship.kind); - json[key] = ember$data$lib$serializers$embedded_records_mixin$$get(record, attr).mapBy('id'); - } else if (includeRecords) { - key = this.keyForAttribute(attr); - json[key] = ember$data$lib$serializers$embedded_records_mixin$$get(record, attr).map(function(embeddedRecord) { - var serializedEmbeddedRecord = embeddedRecord.serialize({includeId: true}); - this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord); - return serializedEmbeddedRecord; - }, this); - } - }, - - /** - When serializing an embedded record, modify the property (in the json payload) - that refers to the parent record (foreign key for relationship). - - Serializing a `belongsTo` relationship removes the property that refers to the - parent record - - Serializing a `hasMany` relationship does not remove the property that refers to - the parent record. - - @method removeEmbeddedForeignKey - @param {DS.Model} record - @param {DS.Model} embeddedRecord - @param {Object} relationship - @param {Object} json - */ - removeEmbeddedForeignKey: function (record, embeddedRecord, relationship, json) { - if (relationship.kind === 'hasMany') { - return; - } else if (relationship.kind === 'belongsTo') { - var parentRecord = record.constructor.inverseFor(relationship.key); - if (parentRecord) { - var name = parentRecord.name; - var embeddedSerializer = this.store.serializerFor(embeddedRecord.constructor); - var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind); - if (parentKey) { - delete json[parentKey]; - } - } - } - }, - - // checks config for attrs option to embedded (always) - serialize and deserialize - hasEmbeddedAlwaysOption: function (attr) { - var option = this.attrsOption(attr); - return option && option.embedded === 'always'; - }, - - // checks config for attrs option to serialize ids - hasSerializeRecordsOption: function(attr) { - var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); - var option = this.attrsOption(attr); - return alwaysEmbed || (option && (option.serialize === 'records')); - }, - - // checks config for attrs option to serialize records - hasSerializeIdsOption: function(attr) { - var option = this.attrsOption(attr); - return option && (option.serialize === 'ids' || option.serialize === 'id'); - }, - - // checks config for attrs option to serialize records - noSerializeOptionSpecified: function(attr) { - var option = this.attrsOption(attr); - return !(option && (option.serialize || option.embedded)); - }, - - // checks config for attrs option to deserialize records - // a defined option object for a resource is treated the same as - // `deserialize: 'records'` - hasDeserializeRecordsOption: function(attr) { - var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); - var option = this.attrsOption(attr); - return alwaysEmbed || (option && option.deserialize === 'records'); - }, - - attrsOption: function(attr) { - var attrs = this.get('attrs'); - return attrs && (attrs[ember$data$lib$serializers$embedded_records_mixin$$camelize(attr)] || attrs[attr]); - } - }); - - // chooses a relationship kind to branch which function is used to update payload - // does not change payload if attr is not embedded - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedRecords(serializer, store, type, partial) { - - type.eachRelationship(function(key, relationship) { - if (serializer.hasDeserializeRecordsOption(key)) { - var embeddedType = store.modelFor(relationship.type.typeKey); - if (relationship.kind === "hasMany") { - if (relationship.options.polymorphic) { - ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasManyPolymorphic(store, key, partial); - } - else { - ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasMany(store, key, embeddedType, partial); - } - } - if (relationship.kind === "belongsTo") { - ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedBelongsTo(store, key, embeddedType, partial); - } - } - }); - - return partial; - } - - // handles embedding for `hasMany` relationship - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasMany(store, key, embeddedType, hash) { - if (!hash[key]) { - return hash; - } - - var ids = []; - - var embeddedSerializer = store.serializerFor(embeddedType.typeKey); - ember$data$lib$serializers$embedded_records_mixin$$forEach(hash[key], function(data) { - var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null); - store.push(embeddedType, embeddedRecord); - ids.push(embeddedRecord.id); - }); - - hash[key] = ids; - return hash; - } - - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasManyPolymorphic(store, key, hash) { - if (!hash[key]) { - return hash; - } - - var ids = []; - - ember$data$lib$serializers$embedded_records_mixin$$forEach(hash[key], function(data) { - var typeKey = data.type; - var embeddedSerializer = store.serializerFor(typeKey); - var embeddedType = store.modelFor(typeKey); - var primaryKey = ember$data$lib$serializers$embedded_records_mixin$$get(embeddedSerializer, 'primaryKey'); - - var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null); - store.push(embeddedType, embeddedRecord); - ids.push({ id: embeddedRecord[primaryKey], type: typeKey }); - }); - - hash[key] = ids; - return hash; - } - - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedBelongsTo(store, key, embeddedType, hash) { - if (!hash[key]) { - return hash; - } - - var embeddedSerializer = store.serializerFor(embeddedType.typeKey); - var embeddedRecord = embeddedSerializer.normalize(embeddedType, hash[key], null); - store.push(embeddedType, embeddedRecord); - - hash[key] = embeddedRecord.id; - //TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records - return hash; - } - - var ember$data$lib$serializers$embedded_records_mixin$$default = ember$data$lib$serializers$embedded_records_mixin$$EmbeddedRecordsMixin; - - - /** - `DS.belongsTo` is used to define One-To-One and One-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - - `DS.belongsTo` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a - related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) - - #### One-To-One - To declare a one-to-one relationship between two models, use - `DS.belongsTo`: - - ```javascript - App.User = DS.Model.extend({ - profile: DS.belongsTo('profile') - }); - - App.Profile = DS.Model.extend({ - user: DS.belongsTo('user') - }); - ``` - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('comment') - }); - - App.Comment = DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the key name. - - ```javascript - App.Comment = DS.Model.extend({ - post: DS.belongsTo() - }); - ``` - - will lookup for a Post type. - - @namespace - @method belongsTo - @for DS - @param {String} type (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship - */ - function ember$data$lib$system$relationships$belongs_to$$belongsTo(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } - - Ember.assert("The first argument to DS.belongsTo must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Person model, use DS.belongsTo('person')", typeof type === 'string' || typeof type === 'undefined'); - - options = options || {}; - - var meta = { - type: type, - isRelationship: true, - options: options, - kind: 'belongsTo', - key: null - }; - - return Ember.computed(function(key, value) { - if (arguments.length>1) { - if ( value === undefined ) { - value = null; - } - if (value && value.then) { - this._relationships[key].setRecordPromise(value); - } else { - this._relationships[key].setRecord(value); - } - } - - return this._relationships[key].getRecord(); - }).meta(meta); - } - - /** - These observers observe all `belongsTo` relationships on the record. See - `relationships/ext` to see how these observers get their dependencies. - - @class Model - @namespace DS - */ - ember$data$lib$system$model$model$$default.reopen({ - notifyBelongsToChanged: function(key) { - this.notifyPropertyChange(key); - } - }); - - var ember$data$lib$system$relationships$belongs_to$$default = ember$data$lib$system$relationships$belongs_to$$belongsTo; - - /** - `DS.hasMany` is used to define One-To-Many and Many-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - `DS.hasMany` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a related model. - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('comment') - }); - - App.Comment = DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - #### Many-To-Many - To declare a many-to-many relationship between two models, use - `DS.hasMany`: - - ```javascript - App.Post = DS.Model.extend({ - tags: DS.hasMany('tag') - }); - - App.Tag = DS.Model.extend({ - posts: DS.hasMany('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the singularized key name. - - ```javascript - App.Post = DS.Model.extend({ - tags: DS.hasMany() - }); - ``` - - will lookup for a Tag type. - - #### Explicit Inverses - - Ember Data will do its best to discover which relationships map to - one another. In the one-to-many code above, for example, Ember Data - can figure out that changing the `comments` relationship should update - the `post` relationship on the inverse because post is the only - relationship to that model. - - However, sometimes you may have multiple `belongsTo`/`hasManys` for the - same type. You can specify which property on the related model is - the inverse using `DS.hasMany`'s `inverse` option: - - ```javascript - var belongsTo = DS.belongsTo, - hasMany = DS.hasMany; - - App.Comment = DS.Model.extend({ - onePost: belongsTo('post'), - twoPost: belongsTo('post'), - redPost: belongsTo('post'), - bluePost: belongsTo('post') - }); - - App.Post = DS.Model.extend({ - comments: hasMany('comment', { - inverse: 'redPost' - }) - }); - ``` - - You can also specify an inverse on a `belongsTo`, which works how - you'd expect. - - @namespace - @method hasMany - @for DS - @param {String} type (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship - */ - function ember$data$lib$system$relationships$has_many$$hasMany(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } - - Ember.assert("The first argument to DS.hasMany must be a string representing a model type key, not an instance of " + Ember.inspect(type) + ". E.g., to define a relation to the Comment model, use DS.hasMany('comment')", typeof type === 'string' || typeof type === 'undefined'); - - options = options || {}; - - // Metadata about relationships is stored on the meta of - // the relationship. This is used for introspection and - // serialization. Note that `key` is populated lazily - // the first time the CP is called. - var meta = { - type: type, - isRelationship: true, - options: options, - kind: 'hasMany', - key: null - }; - - return Ember.computed(function(key) { - var relationship = this._relationships[key]; - return relationship.getRecords(); - }).meta(meta).readOnly(); - } - - ember$data$lib$system$model$model$$default.reopen({ - notifyHasManyAdded: function(key) { - //We need to notifyPropertyChange in the adding case because we need to make sure - //we fetch the newly added record in case it is unloaded - //TODO(Igor): Consider whether we could do this only if the record state is unloaded - - //Goes away once hasMany is double promisified - this.notifyPropertyChange(key); - }, - }); - - - var ember$data$lib$system$relationships$has_many$$default = ember$data$lib$system$relationships$has_many$$hasMany; - function ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(store, meta) { - var typeKey, type; - - typeKey = meta.type || meta.key; - if (typeof typeKey === 'string') { - if (meta.kind === 'hasMany') { - typeKey = ember$inflector$lib$system$string$$singularize(typeKey); - } - type = store.modelFor(typeKey); - } else { - type = meta.type; - } - - return type; - } - - function ember$data$lib$system$relationship$meta$$relationshipFromMeta(store, meta) { - return { - key: meta.key, - kind: meta.kind, - type: ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(store, meta), - options: meta.options, - parentType: meta.parentType, - isRelationship: true - }; - } - - var ember$data$lib$system$relationships$ext$$get = Ember.get; - var ember$data$lib$system$relationships$ext$$filter = Ember.ArrayPolyfills.filter; - - var ember$data$lib$system$relationships$ext$$relationshipsDescriptor = Ember.computed(function() { - if (Ember.testing === true && ember$data$lib$system$relationships$ext$$relationshipsDescriptor._cacheable === true) { - ember$data$lib$system$relationships$ext$$relationshipsDescriptor._cacheable = false; - } - - var map = new ember$data$lib$system$map$$MapWithDefault({ - defaultValue: function() { return []; } - }); - - // Loop through each computed property on the class - this.eachComputedProperty(function(name, meta) { - // If the computed property is a relationship, add - // it to the map. - if (meta.isRelationship) { - meta.key = name; - var relationshipsForType = map.get(ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(this.store, meta)); - - relationshipsForType.push({ - name: name, - kind: meta.kind - }); - } - }); - - return map; - }).readOnly(); - - var ember$data$lib$system$relationships$ext$$relatedTypesDescriptor = Ember.computed(function() { - if (Ember.testing === true && ember$data$lib$system$relationships$ext$$relatedTypesDescriptor._cacheable === true) { - ember$data$lib$system$relationships$ext$$relatedTypesDescriptor._cacheable = false; - } - - var type; - var types = Ember.A(); - - // Loop through each computed property on the class, - // and create an array of the unique types involved - // in relationships - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - meta.key = name; - type = ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(this.store, meta); - - Ember.assert("You specified a hasMany (" + meta.type + ") on " + meta.parentType + " but " + meta.type + " was not found.", type); - - if (!types.contains(type)) { - Ember.assert("Trying to sideload " + name + " on " + this.toString() + " but the type doesn't exist.", !!type); - types.push(type); - } - } - }); - - return types; - }).readOnly(); - - var ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor = Ember.computed(function() { - if (Ember.testing === true && ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor._cacheable === true) { - ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor._cacheable = false; - } - - var map = ember$data$lib$system$map$$Map.create(); - - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - meta.key = name; - var relationship = ember$data$lib$system$relationship$meta$$relationshipFromMeta(this.store, meta); - relationship.type = ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(this.store, meta); - map.set(name, relationship); - } - }); - - return map; - }).readOnly(); - - /** - @module ember-data - */ - - /* - This file defines several extensions to the base `DS.Model` class that - add support for one-to-many relationships. - */ - - /** - @class Model - @namespace DS - */ - ember$data$lib$system$model$model$$default.reopen({ - - /** - This Ember.js hook allows an object to be notified when a property - is defined. - - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. - - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: - - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` - - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. - - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ - didDefineProperty: function(proto, key, value) { - // Check if the value being set is a computed property. - if (value instanceof Ember.ComputedProperty) { - - // If it is, get the metadata for the relationship. This is - // populated by the `DS.belongsTo` helper when it is creating - // the computed property. - var meta = value.meta(); - - meta.parentType = proto.constructor; - } - } - }); - - /* - These DS.Model extensions add class methods that provide relationship - introspection abilities about relationships. - - A note about the computed properties contained here: - - **These properties are effectively sealed once called for the first time.** - To avoid repeatedly doing expensive iteration over a model's fields, these - values are computed once and then cached for the remainder of the runtime of - your application. - - If your application needs to modify a class after its initial definition - (for example, using `reopen()` to add additional attributes), make sure you - do it before using your model with the store, which uses these properties - extensively. - */ - - ember$data$lib$system$model$model$$default.reopenClass({ - - /** - For a given relationship name, returns the model type of the relationship. - - For example, if you define a model like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - Calling `App.Post.typeForRelationship('comments')` will return `App.Comment`. - - @method typeForRelationship - @static - @param {String} name the name of the relationship - @return {subclass of DS.Model} the type of the relationship, or undefined - */ - typeForRelationship: function(name) { - var relationship = ember$data$lib$system$relationships$ext$$get(this, 'relationshipsByName').get(name); - return relationship && relationship.type; - }, - - inverseMap: Ember.computed(function() { - return Ember.create(null); - }), - - /** - Find the relationship which is the inverse of the one asked for. - - For example, if you define models like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('message') - }); - - App.Message = DS.Model.extend({ - owner: DS.belongsTo('post') - }); - ``` - - App.Post.inverseFor('comments') -> {type: App.Message, name:'owner', kind:'belongsTo'} - App.Message.inverseFor('owner') -> {type: App.Post, name:'comments', kind:'hasMany'} - - @method inverseFor - @static - @param {String} name the name of the relationship - @return {Object} the inverse relationship, or null - */ - inverseFor: function(name) { - var inverseMap = ember$data$lib$system$relationships$ext$$get(this, 'inverseMap'); - if (inverseMap[name]) { - return inverseMap[name]; - } else { - var inverse = this._findInverseFor(name); - inverseMap[name] = inverse; - return inverse; - } - }, - - //Calculate the inverse, ignoring the cache - _findInverseFor: function(name) { - - var inverseType = this.typeForRelationship(name); - if (!inverseType) { - return null; - } - - //If inverse is manually specified to be null, like `comments: DS.hasMany('message', {inverse: null})` - var options = this.metaForProperty(name).options; - if (options.inverse === null) { return null; } - - var inverseName, inverseKind, inverse; - - //If inverse is specified manually, return the inverse - if (options.inverse) { - inverseName = options.inverse; - inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); - - Ember.assert("We found no inverse relationships by the name of '" + inverseName + "' on the '" + inverseType.typeKey + - "' model. This is most likely due to a missing attribute on your model definition.", !Ember.isNone(inverse)); - - inverseKind = inverse.kind; - } else { - //No inverse was specified manually, we need to use a heuristic to guess one - var possibleRelationships = findPossibleInverses(this, inverseType); - - if (possibleRelationships.length === 0) { return null; } - - var filteredRelationships = ember$data$lib$system$relationships$ext$$filter.call(possibleRelationships, function(possibleRelationship) { - var optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; - return name === optionsForRelationship.inverse; - }); - - Ember.assert("You defined the '" + name + "' relationship on " + this + ", but you defined the inverse relationships of type " + - inverseType.toString() + " multiple times. Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", - filteredRelationships.length < 2); - - if (filteredRelationships.length === 1 ) { - possibleRelationships = filteredRelationships; - } - - Ember.assert("You defined the '" + name + "' relationship on " + this + ", but multiple possible inverse relationships of type " + - this + " were found on " + inverseType + ". Look at http://emberjs.com/guides/models/defining-models/#toc_explicit-inverses for how to explicitly specify inverses", - possibleRelationships.length === 1); - - inverseName = possibleRelationships[0].name; - inverseKind = possibleRelationships[0].kind; - } - - function findPossibleInverses(type, inverseType, relationshipsSoFar) { - var possibleRelationships = relationshipsSoFar || []; - - var relationshipMap = ember$data$lib$system$relationships$ext$$get(inverseType, 'relationships'); - if (!relationshipMap) { return; } - - var relationships = relationshipMap.get(type); - - relationships = ember$data$lib$system$relationships$ext$$filter.call(relationships, function(relationship) { - var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - - if (!optionsForRelationship.inverse){ - return true; - } - - return name === optionsForRelationship.inverse; - }); - - if (relationships) { - possibleRelationships.push.apply(possibleRelationships, relationships); - } - - //Recurse to support polymorphism - if (type.superclass) { - findPossibleInverses(type.superclass, inverseType, possibleRelationships); - } - - return possibleRelationships; - } - - return { - type: inverseType, - name: inverseName, - kind: inverseKind - }; - }, - - /** - The model's relationships as a map, keyed on the type of the - relationship. The value of each entry is an array containing a descriptor - for each relationship with that type, describing the name of the relationship - as well as the type. - - For example, given the following model definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); - ``` - - This computed property would return a map describing these - relationships, like this: - - ```javascript - var relationships = Ember.get(App.Blog, 'relationships'); - relationships.get(App.User); - //=> [ { name: 'users', kind: 'hasMany' }, - // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(App.Post); - //=> [ { name: 'posts', kind: 'hasMany' } ] - ``` - - @property relationships - @static - @type Ember.Map - @readOnly - */ - - relationships: ember$data$lib$system$relationships$ext$$relationshipsDescriptor, - - /** - A hash containing lists of the model's relationships, grouped - by the relationship kind. For example, given a model with this - definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - var relationshipNames = Ember.get(App.Blog, 'relationshipNames'); - relationshipNames.hasMany; - //=> ['users', 'posts'] - relationshipNames.belongsTo; - //=> ['owner'] - ``` - - @property relationshipNames - @static - @type Object - @readOnly - */ - relationshipNames: Ember.computed(function() { - var names = { - hasMany: [], - belongsTo: [] - }; - - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - names[meta.kind].push(name); - } - }); - - return names; - }), - - /** - An array of types directly related to a model. Each type will be - included once, regardless of the number of relationships it has with - the model. - - For example, given a model with this definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - var relatedTypes = Ember.get(App.Blog, 'relatedTypes'); - //=> [ App.User, App.Post ] - ``` - - @property relatedTypes - @static - @type Ember.Array - @readOnly - */ - relatedTypes: ember$data$lib$system$relationships$ext$$relatedTypesDescriptor, - - /** - A map whose keys are the relationships of a model and whose values are - relationship descriptors. - - For example, given a model with this - definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - var relationshipsByName = Ember.get(App.Blog, 'relationshipsByName'); - relationshipsByName.get('users'); - //=> { key: 'users', kind: 'hasMany', type: App.User } - relationshipsByName.get('owner'); - //=> { key: 'owner', kind: 'belongsTo', type: App.User } - ``` - - @property relationshipsByName - @static - @type Ember.Map - @readOnly - */ - relationshipsByName: ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor, - - /** - A map whose keys are the fields of the model and whose values are strings - describing the kind of the field. A model's fields are the union of all of its - attributes and relationships. - - For example: - - ```javascript - - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post'), - - title: DS.attr('string') - }); - - var fields = Ember.get(App.Blog, 'fields'); - fields.forEach(function(kind, field) { - console.log(field, kind); - }); - - // prints: - // users, hasMany - // owner, belongsTo - // posts, hasMany - // title, attribute - ``` - - @property fields - @static - @type Ember.Map - @readOnly - */ - fields: Ember.computed(function() { - var map = ember$data$lib$system$map$$Map.create(); - - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - map.set(name, meta.kind); - } else if (meta.isAttribute) { - map.set(name, 'attribute'); - } - }); - - return map; - }).readOnly(), - - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - @method eachRelationship - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship: function(callback, binding) { - ember$data$lib$system$relationships$ext$$get(this, 'relationshipsByName').forEach(function(relationship, name) { - callback.call(binding, name, relationship); - }); - }, - - /** - Given a callback, iterates over each of the types related to a model, - invoking the callback with the related type's class. Each type will be - returned just once, regardless of how many different relationships it has - with a model. - - @method eachRelatedType - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelatedType: function(callback, binding) { - ember$data$lib$system$relationships$ext$$get(this, 'relatedTypes').forEach(function(type) { - callback.call(binding, type); - }); - }, - - determineRelationshipType: function(knownSide) { - var knownKey = knownSide.key; - var knownKind = knownSide.kind; - var inverse = this.inverseFor(knownKey); - var key, otherKind; - - if (!inverse) { - return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; - } - - key = inverse.name; - otherKind = inverse.kind; - - if (otherKind === 'belongsTo') { - return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; - } else { - return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; - } - } - - }); - - ember$data$lib$system$model$model$$default.reopen({ - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - @method eachRelationship - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship: function(callback, binding) { - this.constructor.eachRelationship(callback, binding); - }, - - relationshipFor: function(name) { - return ember$data$lib$system$relationships$ext$$get(this.constructor, 'relationshipsByName').get(name); - }, - - inverseFor: function(key) { - return this.constructor.inverseFor(key); - } - - }); - /** - Ember Data - @module ember-data - @main ember-data - */ - - // support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast - Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; - - Ember.runInDebug(function(){ - if (Ember.VERSION.match(/1\.[0-7]\./)){ - throw new Ember.Error("Ember Data requires at least Ember 1.8.0, but you have " + - Ember.VERSION + - ". Please upgrade your version of Ember, then upgrade Ember Data"); - } - }); - - ember$data$lib$core$$default.Store = ember$data$lib$system$store$$Store; - ember$data$lib$core$$default.PromiseArray = ember$data$lib$system$promise_proxies$$PromiseArray; - ember$data$lib$core$$default.PromiseObject = ember$data$lib$system$promise_proxies$$PromiseObject; - - ember$data$lib$core$$default.PromiseManyArray = ember$data$lib$system$promise_proxies$$PromiseManyArray; - - ember$data$lib$core$$default.Model = ember$data$lib$system$model$model$$default; - ember$data$lib$core$$default.RootState = ember$data$lib$system$model$states$$default; - ember$data$lib$core$$default.attr = ember$data$lib$system$model$attributes$$default; - ember$data$lib$core$$default.Errors = ember$data$lib$system$model$errors$$default; - - ember$data$lib$core$$default.Adapter = ember$data$lib$system$adapter$$Adapter; - ember$data$lib$core$$default.InvalidError = ember$data$lib$system$adapter$$InvalidError; - - ember$data$lib$core$$default.DebugAdapter = ember$data$lib$system$debug$$default; - - ember$data$lib$core$$default.RecordArray = ember$data$lib$system$record_arrays$record_array$$default; - ember$data$lib$core$$default.FilteredRecordArray = ember$data$lib$system$record_arrays$filtered_record_array$$default; - ember$data$lib$core$$default.AdapterPopulatedRecordArray = ember$data$lib$system$record_arrays$adapter_populated_record_array$$default; - ember$data$lib$core$$default.ManyArray = ember$data$lib$system$record_arrays$many_array$$default; - - ember$data$lib$core$$default.RecordArrayManager = ember$data$lib$system$record_array_manager$$default; - - ember$data$lib$core$$default.RESTAdapter = ember$data$lib$adapters$rest_adapter$$default; - ember$data$lib$core$$default.FixtureAdapter = ember$data$lib$adapters$fixture_adapter$$default; - - ember$data$lib$core$$default.RESTSerializer = ember$data$lib$serializers$rest_serializer$$default; - ember$data$lib$core$$default.JSONSerializer = ember$data$lib$serializers$json_serializer$$default; - - ember$data$lib$core$$default.Transform = ember$data$lib$transforms$base$$default; - ember$data$lib$core$$default.DateTransform = ember$data$lib$transforms$date$$default; - ember$data$lib$core$$default.StringTransform = ember$data$lib$transforms$string$$default; - ember$data$lib$core$$default.NumberTransform = ember$data$lib$transforms$number$$default; - ember$data$lib$core$$default.BooleanTransform = ember$data$lib$transforms$boolean$$default; - - ember$data$lib$core$$default.ActiveModelAdapter = activemodel$adapter$lib$system$active_model_adapter$$default; - ember$data$lib$core$$default.ActiveModelSerializer = activemodel$adapter$lib$system$active_model_serializer$$default; - ember$data$lib$core$$default.EmbeddedRecordsMixin = ember$data$lib$serializers$embedded_records_mixin$$default; - - ember$data$lib$core$$default.belongsTo = ember$data$lib$system$relationships$belongs_to$$default; - ember$data$lib$core$$default.hasMany = ember$data$lib$system$relationships$has_many$$default; - - ember$data$lib$core$$default.Relationship = ember$data$lib$system$relationships$state$relationship$$default; - - ember$data$lib$core$$default.ContainerProxy = ember$data$lib$system$container_proxy$$default; - - ember$data$lib$core$$default._setupContainer = ember$data$lib$setup$container$$default; - - Ember.lookup.DS = ember$data$lib$core$$default; - - var ember$data$lib$main$$default = ember$data$lib$core$$default; -}).call(this); - -//# sourceMappingURL=ember-data.js.map - diff --git a/assets/scripts/vendor/ember-data.prod.js b/assets/scripts/vendor/ember-data.prod.js deleted file mode 100644 index 1584d750..00000000 --- a/assets/scripts/vendor/ember-data.prod.js +++ /dev/null @@ -1,12073 +0,0 @@ -(function() { - "use strict"; - /** - @module ember-data - */ - - var ember$data$lib$system$adapter$$get = Ember.get; - - var ember$data$lib$system$adapter$$errorProps = [ - 'description', - 'fileName', - 'lineNumber', - 'message', - 'name', - 'number', - 'stack' - ]; - - /** - A `DS.InvalidError` is used by an adapter to signal the external API - was unable to process a request because the content was not - semantically correct or meaningful per the API. Usually this means a - record failed some form of server side validation. When a promise - from an adapter is rejected with a `DS.InvalidError` the record will - transition to the `invalid` state and the errors will be set to the - `errors` property on the record. - - This function should return the entire payload as received from the - server. Error object extraction and normalization of model errors - should be performed by `extractErrors` on the serializer. - - Example - - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ - ajaxError: function(jqXHR) { - var error = this._super(jqXHR); - - if (jqXHR && jqXHR.status === 422) { - var jsonErrors = Ember.$.parseJSON(jqXHR.responseText); - return new DS.InvalidError(jsonErrors); - } else { - return error; - } - } - }); - ``` - - The `DS.InvalidError` must be constructed with a single object whose - keys are the invalid model properties, and whose values are the - corresponding error messages. For example: - - ```javascript - return new DS.InvalidError({ - length: 'Must be less than 15', - name: 'Must not be blank' - }); - ``` - - @class InvalidError - @namespace DS - */ - function ember$data$lib$system$adapter$$InvalidError(errors) { - var tmp = Error.prototype.constructor.call(this, "The backend rejected the commit because it was invalid: " + Ember.inspect(errors)); - this.errors = errors; - - for (var i=0, l=ember$data$lib$system$adapter$$errorProps.length; i= 1.8 forEach is called with the order value, key as per - * the ES6 spec. - */ - function ember$data$lib$system$map$$translate(valueKeyOrderedCallback){ - return function(key, value){ - valueKeyOrderedCallback.call(this, value, key); - }; - } - - // old, non ES6 compliant behavior - if (ember$data$lib$system$map$$usesOldBehavior){ - ember$data$lib$system$map$$mapForEach = function(callback, thisArg){ - this.__super$forEach(ember$data$lib$system$map$$translate(callback), thisArg); - }; - - /* alias to remove */ - ember$data$lib$system$map$$deleteFn = function(thing){ - this.remove(thing); - }; - - ember$data$lib$system$map$$Map.prototype.__super$forEach = Ember.Map.prototype.forEach; - ember$data$lib$system$map$$Map.prototype.forEach = ember$data$lib$system$map$$mapForEach; - ember$data$lib$system$map$$Map.prototype["delete"] = ember$data$lib$system$map$$deleteFn; - - ember$data$lib$system$map$$MapWithDefault.prototype.forEach = ember$data$lib$system$map$$mapForEach; - ember$data$lib$system$map$$MapWithDefault.prototype.__super$forEach = Ember.MapWithDefault.prototype.forEach; - ember$data$lib$system$map$$MapWithDefault.prototype["delete"] = ember$data$lib$system$map$$deleteFn; - - ember$data$lib$system$map$$OrderedSet.prototype["delete"] = ember$data$lib$system$map$$deleteFn; - } - - ember$data$lib$system$map$$MapWithDefault.constructor = ember$data$lib$system$map$$MapWithDefault; - ember$data$lib$system$map$$Map.constructor = ember$data$lib$system$map$$Map; - - ember$data$lib$system$map$$MapWithDefault.create = function(options){ - if (options) { - return new ember$data$lib$system$map$$MapWithDefault(options); - } else { - return new ember$data$lib$system$map$$Map(); - } - }; - - ember$data$lib$system$map$$Map.create = function(){ - return new this.constructor(); - }; - - var ember$data$lib$system$map$$default = ember$data$lib$system$map$$Map; - var ember$data$lib$adapters$rest_adapter$$get = Ember.get; - var ember$data$lib$adapters$rest_adapter$$forEach = Ember.ArrayPolyfills.forEach; - - var ember$data$lib$adapters$rest_adapter$$default = ember$data$lib$system$adapter$$Adapter.extend({ - defaultSerializer: '-rest', - - /** - By default the RESTAdapter will send each find request coming from a `store.find` - or from accessing a relationship separately to the server. If your server supports passing - ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests - within a single runloop. - - For example, if you have an initial payload of - ```javascript - post: { - id:1, - comments: [1,2] - } - ``` - - By default calling `post.get('comments')` will trigger the following requests(assuming the - comments haven't been loaded before): - - ``` - GET /comments/1 - GET /comments/2 - ``` - - If you set coalesceFindRequests to `true` it will instead trigger the following request: - - ``` - GET /comments?ids[]=1&ids[]=2 - ``` - - Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo` - relationships accessed within the same runloop. If you set `coalesceFindRequests: true` - - ```javascript - store.find('comment', 1); - store.find('comment', 2); - ``` - - will also send a request to: `GET /comments?ids[]=1&ids[]=2` - - Note: Requests coalescing rely on URL building strategy. So if you override `buildURL` in your app - `groupRecordsForFindMany` more likely should be overridden as well in order for coalescing to work. - - @property coalesceFindRequests - @type {boolean} - */ - coalesceFindRequests: false, - - /** - Endpoint paths can be prefixed with a `namespace` by setting the namespace - property on the adapter: - - ```javascript - DS.RESTAdapter.reopen({ - namespace: 'api/1' - }); - ``` - - Requests for `App.Post` would now target `/api/1/post/`. - - @property namespace - @type {String} - */ - - /** - An adapter can target other hosts by setting the `host` property. - - ```javascript - DS.RESTAdapter.reopen({ - host: 'https://api.example.com' - }); - ``` - - Requests for `App.Post` would now target `https://api.example.com/post/`. - - @property host - @type {String} - */ - - /** - Some APIs require HTTP headers, e.g. to provide an API - key. Arbitrary headers can be set as key/value pairs on the - `RESTAdapter`'s `headers` object and Ember Data will send them - along with each ajax request. For dynamic headers see [headers - customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization). - - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ - headers: { - "API_KEY": "secret key", - "ANOTHER_HEADER": "Some header value" - } - }); - ``` - - @property headers - @type {Object} - */ - - /** - Called by the store in order to fetch the JSON for a given - type and ID. - - The `find` method makes an Ajax request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - This method performs an HTTP `GET` request with the id provided as part of the query string. - - @method find - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {String} id - @param {DS.Model} record - @return {Promise} promise - */ - find: function(store, type, id, record) { - return this.ajax(this.buildURL(type.typeKey, id, record), 'GET'); - }, - - /** - Called by the store in order to fetch a JSON array for all - of the records for a given type. - - The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - @private - @method findAll - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {String} sinceToken - @return {Promise} promise - */ - findAll: function(store, type, sinceToken) { - var query; - - if (sinceToken) { - query = { since: sinceToken }; - } - - return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch a JSON array for - the records that match a particular query. - - The `findQuery` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - The `query` argument is a simple JavaScript object that will be passed directly - to the server as parameters. - - @private - @method findQuery - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} query - @return {Promise} promise - */ - findQuery: function(store, type, query) { - return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query }); - }, - - /** - Called by the store in order to fetch several records together if `coalesceFindRequests` is true - - For example, if the original payload looks like: - - ```js - { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2, 3 ] - } - ``` - - The IDs will be passed as a URL-encoded Array of IDs, in this form: - - ``` - ids[]=1&ids[]=2&ids[]=3 - ``` - - Many servers, such as Rails and PHP, will automatically convert this URL-encoded array - into an Array for you on the server-side. If you want to encode the - IDs, differently, just override this (one-line) method. - - The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a - promise for the resulting payload. - - @method findMany - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Array} ids - @param {Array} records - @return {Promise} promise - */ - findMany: function(store, type, ids, records) { - return this.ajax(this.buildURL(type.typeKey, ids, records), 'GET', { data: { ids: ids } }); - }, - - /** - Called by the store in order to fetch a JSON array for - the unloaded records in a has-many relationship that were originally - specified as a URL (inside of `links`). - - For example, if your original payload looks like this: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "links": { "comments": "/posts/1/comments" } - } - } - ``` - - This method will be called with the parent record and `/posts/1/comments`. - - The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL. - If the URL is host-relative (starting with a single slash), the - request will use the host specified on the adapter (if any). - - @method findHasMany - @param {DS.Store} store - @param {DS.Model} record - @param {String} url - @return {Promise} promise - */ - findHasMany: function(store, record, url, relationship) { - var host = ember$data$lib$adapters$rest_adapter$$get(this, 'host'); - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - var type = record.constructor.typeKey; - - if (host && url.charAt(0) === '/' && url.charAt(1) !== '/') { - url = host + url; - } - - return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET'); - }, - - /** - Called by the store in order to fetch a JSON array for - the unloaded records in a belongs-to relationship that were originally - specified as a URL (inside of `links`). - - For example, if your original payload looks like this: - - ```js - { - "person": { - "id": 1, - "name": "Tom Dale", - "links": { "group": "/people/1/group" } - } - } - ``` - - This method will be called with the parent record and `/people/1/group`. - - The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL. - - @method findBelongsTo - @param {DS.Store} store - @param {DS.Model} record - @param {String} url - @return {Promise} promise - */ - findBelongsTo: function(store, record, url, relationship) { - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - var type = record.constructor.typeKey; - - return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET'); - }, - - /** - Called by the store when a newly created record is - saved via the `save` method on a model record instance. - - The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request - to a URL computed by `buildURL`. - - See `serialize` for information on how to customize the serialized form - of a record. - - @method createRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {DS.Model} record - @return {Promise} promise - */ - createRecord: function(store, type, record) { - var data = {}; - var serializer = store.serializerFor(type.typeKey); - - serializer.serializeIntoHash(data, type, record, { includeId: true }); - - return this.ajax(this.buildURL(type.typeKey, null, record), "POST", { data: data }); - }, - - /** - Called by the store when an existing record is saved - via the `save` method on a model record instance. - - The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request - to a URL computed by `buildURL`. - - See `serialize` for information on how to customize the serialized form - of a record. - - @method updateRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {DS.Model} record - @return {Promise} promise - */ - updateRecord: function(store, type, record) { - var data = {}; - var serializer = store.serializerFor(type.typeKey); - - serializer.serializeIntoHash(data, type, record); - - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - - return this.ajax(this.buildURL(type.typeKey, id, record), "PUT", { data: data }); - }, - - /** - Called by the store when a record is deleted. - - The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`. - - @method deleteRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {DS.Model} record - @return {Promise} promise - */ - deleteRecord: function(store, type, record) { - var id = ember$data$lib$adapters$rest_adapter$$get(record, 'id'); - - return this.ajax(this.buildURL(type.typeKey, id, record), "DELETE"); - }, - - /** - Builds a URL for a given type and optional ID. - - By default, it pluralizes the type's name (for example, 'post' - becomes 'posts' and 'person' becomes 'people'). To override the - pluralization see [pathForType](#method_pathForType). - - If an ID is specified, it adds the ID to the path generated - for the type, separated by a `/`. - - @method buildURL - @param {String} type - @param {String} id - @param {DS.Model} record - @return {String} url - */ - buildURL: function(type, id, record) { - var url = [], - host = ember$data$lib$adapters$rest_adapter$$get(this, 'host'), - prefix = this.urlPrefix(); - - if (type) { url.push(this.pathForType(type)); } - - //We might get passed in an array of ids from findMany - //in which case we don't want to modify the url, as the - //ids will be passed in through a query param - if (id && !Ember.isArray(id)) { url.push(encodeURIComponent(id)); } - - if (prefix) { url.unshift(prefix); } - - url = url.join('/'); - if (!host && url) { url = '/' + url; } - - return url; - }, - - /** - @method urlPrefix - @private - @param {String} path - @param {String} parentUrl - @return {String} urlPrefix - */ - urlPrefix: function(path, parentURL) { - var host = ember$data$lib$adapters$rest_adapter$$get(this, 'host'); - var namespace = ember$data$lib$adapters$rest_adapter$$get(this, 'namespace'); - var url = []; - - if (path) { - // Absolute path - if (path.charAt(0) === '/') { - if (host) { - path = path.slice(1); - url.push(host); - } - // Relative path - } else if (!/^http(s)?:\/\//.test(path)) { - url.push(parentURL); - } - } else { - if (host) { url.push(host); } - if (namespace) { url.push(namespace); } - } - - if (path) { - url.push(path); - } - - return url.join('/'); - }, - - _stripIDFromURL: function(store, record) { - var type = record.constructor; - var url = this.buildURL(type.typeKey, record.get('id'), record); - - var expandedURL = url.split('/'); - //Case when the url is of the format ...something/:id - var lastSegment = expandedURL[ expandedURL.length - 1 ]; - var id = record.get('id'); - if (lastSegment === id) { - expandedURL[expandedURL.length - 1] = ""; - } else if(ember$data$lib$adapters$rest_adapter$$endsWith(lastSegment, '?id=' + id)) { - //Case when the url is of the format ...something?id=:id - expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1); - } - - return expandedURL.join('/'); - }, - - /** - http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers - */ - maxUrlLength: 2048, - - /** - Organize records into groups, each of which is to be passed to separate - calls to `findMany`. - - This implementation groups together records that have the same base URL but - differing ids. For example `/comments/1` and `/comments/2` will be grouped together - because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2` - - It also supports urls where ids are passed as a query param, such as `/comments?id=1` - but not those where there is more than 1 query param such as `/comments?id=2&name=David` - Currently only the query param of `id` is supported. If you need to support others, please - override this or the `_stripIDFromURL` method. - - It does not group records that have differing base urls, such as for example: `/posts/1/comments/2` - and `/posts/2/comments/3` - - @method groupRecordsForFindMany - @param {DS.Store} store - @param {Array} records - @return {Array} an array of arrays of records, each of which is to be - loaded separately by `findMany`. - */ - groupRecordsForFindMany: function (store, records) { - var groups = ember$data$lib$system$map$$MapWithDefault.create({defaultValue: function(){return [];}}); - var adapter = this; - var maxUrlLength = this.maxUrlLength; - - ember$data$lib$adapters$rest_adapter$$forEach.call(records, function(record){ - var baseUrl = adapter._stripIDFromURL(store, record); - groups.get(baseUrl).push(record); - }); - - function splitGroupToFitInUrl(group, maxUrlLength, paramNameLength) { - var baseUrl = adapter._stripIDFromURL(store, group[0]); - var idsSize = 0; - var splitGroups = [[]]; - - ember$data$lib$adapters$rest_adapter$$forEach.call(group, function(record) { - var additionalLength = encodeURIComponent(record.get('id')).length + paramNameLength; - if (baseUrl.length + idsSize + additionalLength >= maxUrlLength) { - idsSize = 0; - splitGroups.push([]); - } - - idsSize += additionalLength; - - var lastGroupIndex = splitGroups.length - 1; - splitGroups[lastGroupIndex].push(record); - }); - - return splitGroups; - } - - var groupsArray = []; - groups.forEach(function(group, key){ - var paramNameLength = '&ids%5B%5D='.length; - var splitGroups = splitGroupToFitInUrl(group, maxUrlLength, paramNameLength); - - ember$data$lib$adapters$rest_adapter$$forEach.call(splitGroups, function(splitGroup) { - groupsArray.push(splitGroup); - }); - }); - - return groupsArray; - }, - - /** - Determines the pathname for a given type. - - By default, it pluralizes the type's name (for example, - 'post' becomes 'posts' and 'person' becomes 'people'). - - ### Pathname customization - - For example if you have an object LineItem with an - endpoint of "/line_items/". - - ```js - App.ApplicationAdapter = DS.RESTAdapter.extend({ - pathForType: function(type) { - var decamelized = Ember.String.decamelize(type); - return Ember.String.pluralize(decamelized); - } - }); - ``` - - @method pathForType - @param {String} type - @return {String} path - **/ - pathForType: function(type) { - var camelized = Ember.String.camelize(type); - return Ember.String.pluralize(camelized); - }, - - /** - Takes an ajax response, and returns an error payload. - - Returning a `DS.InvalidError` from this method will cause the - record to transition into the `invalid` state and make the - `errors` object available on the record. - - This function should return the entire payload as received from the - server. Error object extraction and normalization of model errors - should be performed by `extractErrors` on the serializer. - - Example - - ```javascript - App.ApplicationAdapter = DS.RESTAdapter.extend({ - ajaxError: function(jqXHR) { - var error = this._super(jqXHR); - - if (jqXHR && jqXHR.status === 422) { - var jsonErrors = Ember.$.parseJSON(jqXHR.responseText); - - return new DS.InvalidError(jsonErrors); - } else { - return error; - } - } - }); - ``` - - Note: As a correctness optimization, the default implementation of - the `ajaxError` method strips out the `then` method from jquery's - ajax response (jqXHR). This is important because the jqXHR's - `then` method fulfills the promise with itself resulting in a - circular "thenable" chain which may cause problems for some - promise libraries. - - @method ajaxError - @param {Object} jqXHR - @param {Object} responseText - @return {Object} jqXHR - */ - ajaxError: function(jqXHR, responseText, errorThrown) { - var isObject = jqXHR !== null && typeof jqXHR === 'object'; - - if (isObject) { - jqXHR.then = null; - if (!jqXHR.errorThrown) { - jqXHR.errorThrown = errorThrown; - } - } - - return jqXHR; - }, - - /** - Takes an ajax response, and returns the json payload. - - By default this hook just returns the jsonPayload passed to it. - You might want to override it in two cases: - - 1. Your API might return useful results in the request headers. - If you need to access these, you can override this hook to copy them - from jqXHR to the payload object so they can be processed in you serializer. - - - 2. Your API might return errors as successful responses with status code - 200 and an Errors text or object. You can return a DS.InvalidError from - this hook and it will automatically reject the promise and put your record - into the invalid state. - - @method ajaxSuccess - @param {Object} jqXHR - @param {Object} jsonPayload - @return {Object} jsonPayload - */ - - ajaxSuccess: function(jqXHR, jsonPayload) { - return jsonPayload; - }, - - /** - Takes a URL, an HTTP method and a hash of data, and makes an - HTTP request. - - When the server responds with a payload, Ember Data will call into `extractSingle` - or `extractArray` (depending on whether the original query was for one record or - many records). - - By default, `ajax` method has the following behavior: - - * It sets the response `dataType` to `"json"` - * If the HTTP method is not `"GET"`, it sets the `Content-Type` to be - `application/json; charset=utf-8` - * If the HTTP method is not `"GET"`, it stringifies the data passed in. The - data is the serialized record in the case of a save. - * Registers success and failure handlers. - - @method ajax - @private - @param {String} url - @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} hash - @return {Promise} promise - */ - ajax: function(url, type, options) { - var adapter = this; - - return new Ember.RSVP.Promise(function(resolve, reject) { - var hash = adapter.ajaxOptions(url, type, options); - - hash.success = function(json, textStatus, jqXHR) { - json = adapter.ajaxSuccess(jqXHR, json); - if (json instanceof ember$data$lib$system$adapter$$InvalidError) { - Ember.run(null, reject, json); - } else { - Ember.run(null, resolve, json); - } - }; - - hash.error = function(jqXHR, textStatus, errorThrown) { - Ember.run(null, reject, adapter.ajaxError(jqXHR, jqXHR.responseText, errorThrown)); - }; - - Ember.$.ajax(hash); - }, 'DS: RESTAdapter#ajax ' + type + ' to ' + url); - }, - - /** - @method ajaxOptions - @private - @param {String} url - @param {String} type The request type GET, POST, PUT, DELETE etc. - @param {Object} hash - @return {Object} hash - */ - ajaxOptions: function(url, type, options) { - var hash = options || {}; - hash.url = url; - hash.type = type; - hash.dataType = 'json'; - hash.context = this; - - if (hash.data && type !== 'GET') { - hash.contentType = 'application/json; charset=utf-8'; - hash.data = JSON.stringify(hash.data); - } - - var headers = ember$data$lib$adapters$rest_adapter$$get(this, 'headers'); - if (headers !== undefined) { - hash.beforeSend = function (xhr) { - ember$data$lib$adapters$rest_adapter$$forEach.call(Ember.keys(headers), function(key) { - xhr.setRequestHeader(key, headers[key]); - }); - }; - } - - return hash; - } - }); - - //From http://stackoverflow.com/questions/280634/endswith-in-javascript - function ember$data$lib$adapters$rest_adapter$$endsWith(string, suffix){ - if (typeof String.prototype.endsWith !== 'function') { - return string.indexOf(suffix, string.length - suffix.length) !== -1; - } else { - return string.endsWith(suffix); - } - } - - var ember$inflector$lib$system$inflector$$capitalize = Ember.String.capitalize; - - var ember$inflector$lib$system$inflector$$BLANK_REGEX = /^\s*$/; - var ember$inflector$lib$system$inflector$$LAST_WORD_DASHED_REGEX = /(\w+[_-])([a-z\d]+$)/; - var ember$inflector$lib$system$inflector$$LAST_WORD_CAMELIZED_REGEX = /(\w+)([A-Z][a-z\d]*$)/; - var ember$inflector$lib$system$inflector$$CAMELIZED_REGEX = /[A-Z][a-z\d]*$/; - - function ember$inflector$lib$system$inflector$$loadUncountable(rules, uncountable) { - for (var i = 0, length = uncountable.length; i < length; i++) { - rules.uncountable[uncountable[i].toLowerCase()] = true; - } - } - - function ember$inflector$lib$system$inflector$$loadIrregular(rules, irregularPairs) { - var pair; - - for (var i = 0, length = irregularPairs.length; i < length; i++) { - pair = irregularPairs[i]; - - //pluralizing - rules.irregular[pair[0].toLowerCase()] = pair[1]; - rules.irregular[pair[1].toLowerCase()] = pair[1]; - - //singularizing - rules.irregularInverse[pair[1].toLowerCase()] = pair[0]; - rules.irregularInverse[pair[0].toLowerCase()] = pair[0]; - } - } - - /** - Inflector.Ember provides a mechanism for supplying inflection rules for your - application. Ember includes a default set of inflection rules, and provides an - API for providing additional rules. - - Examples: - - Creating an inflector with no rules. - - ```js - var inflector = new Ember.Inflector(); - ``` - - Creating an inflector with the default ember ruleset. - - ```js - var inflector = new Ember.Inflector(Ember.Inflector.defaultRules); - - inflector.pluralize('cow'); //=> 'kine' - inflector.singularize('kine'); //=> 'cow' - ``` - - Creating an inflector and adding rules later. - - ```javascript - var inflector = Ember.Inflector.inflector; - - inflector.pluralize('advice'); // => 'advices' - inflector.uncountable('advice'); - inflector.pluralize('advice'); // => 'advice' - - inflector.pluralize('formula'); // => 'formulas' - inflector.irregular('formula', 'formulae'); - inflector.pluralize('formula'); // => 'formulae' - - // you would not need to add these as they are the default rules - inflector.plural(/$/, 's'); - inflector.singular(/s$/i, ''); - ``` - - Creating an inflector with a nondefault ruleset. - - ```javascript - var rules = { - plurals: [ /$/, 's' ], - singular: [ /\s$/, '' ], - irregularPairs: [ - [ 'cow', 'kine' ] - ], - uncountable: [ 'fish' ] - }; - - var inflector = new Ember.Inflector(rules); - ``` - - @class Inflector - @namespace Ember - */ - function ember$inflector$lib$system$inflector$$Inflector(ruleSet) { - ruleSet = ruleSet || {}; - ruleSet.uncountable = ruleSet.uncountable || ember$inflector$lib$system$inflector$$makeDictionary(); - ruleSet.irregularPairs = ruleSet.irregularPairs || ember$inflector$lib$system$inflector$$makeDictionary(); - - var rules = this.rules = { - plurals: ruleSet.plurals || [], - singular: ruleSet.singular || [], - irregular: ember$inflector$lib$system$inflector$$makeDictionary(), - irregularInverse: ember$inflector$lib$system$inflector$$makeDictionary(), - uncountable: ember$inflector$lib$system$inflector$$makeDictionary() - }; - - ember$inflector$lib$system$inflector$$loadUncountable(rules, ruleSet.uncountable); - ember$inflector$lib$system$inflector$$loadIrregular(rules, ruleSet.irregularPairs); - - this.enableCache(); - } - - if (!Object.create && !Object.create(null).hasOwnProperty) { - throw new Error("This browser does not support Object.create(null), please polyfil with es5-sham: http://git.io/yBU2rg"); - } - - function ember$inflector$lib$system$inflector$$makeDictionary() { - var cache = Object.create(null); - cache['_dict'] = null; - delete cache['_dict']; - return cache; - } - - ember$inflector$lib$system$inflector$$Inflector.prototype = { - /** - @public - - As inflections can be costly, and commonly the same subset of words are repeatedly - inflected an optional cache is provided. - - @method enableCache - */ - enableCache: function() { - this.purgeCache(); - - this.singularize = function(word) { - this._cacheUsed = true; - return this._sCache[word] || (this._sCache[word] = this._singularize(word)); - }; - - this.pluralize = function(word) { - this._cacheUsed = true; - return this._pCache[word] || (this._pCache[word] = this._pluralize(word)); - }; - }, - - /** - @public - - @method purgedCache - */ - purgeCache: function() { - this._cacheUsed = false; - this._sCache = ember$inflector$lib$system$inflector$$makeDictionary(); - this._pCache = ember$inflector$lib$system$inflector$$makeDictionary(); - }, - - /** - @public - disable caching - - @method disableCache; - */ - disableCache: function() { - this._sCache = null; - this._pCache = null; - this.singularize = function(word) { - return this._singularize(word); - }; - - this.pluralize = function(word) { - return this._pluralize(word); - }; - }, - - /** - @method plural - @param {RegExp} regex - @param {String} string - */ - plural: function(regex, string) { - if (this._cacheUsed) { this.purgeCache(); } - this.rules.plurals.push([regex, string.toLowerCase()]); - }, - - /** - @method singular - @param {RegExp} regex - @param {String} string - */ - singular: function(regex, string) { - if (this._cacheUsed) { this.purgeCache(); } - this.rules.singular.push([regex, string.toLowerCase()]); - }, - - /** - @method uncountable - @param {String} regex - */ - uncountable: function(string) { - if (this._cacheUsed) { this.purgeCache(); } - ember$inflector$lib$system$inflector$$loadUncountable(this.rules, [string.toLowerCase()]); - }, - - /** - @method irregular - @param {String} singular - @param {String} plural - */ - irregular: function (singular, plural) { - if (this._cacheUsed) { this.purgeCache(); } - ember$inflector$lib$system$inflector$$loadIrregular(this.rules, [[singular, plural]]); - }, - - /** - @method pluralize - @param {String} word - */ - pluralize: function(word) { - return this._pluralize(word); - }, - - _pluralize: function(word) { - return this.inflect(word, this.rules.plurals, this.rules.irregular); - }, - /** - @method singularize - @param {String} word - */ - singularize: function(word) { - return this._singularize(word); - }, - - _singularize: function(word) { - return this.inflect(word, this.rules.singular, this.rules.irregularInverse); - }, - - /** - @protected - - @method inflect - @param {String} word - @param {Object} typeRules - @param {Object} irregular - */ - inflect: function(word, typeRules, irregular) { - var inflection, substitution, result, lowercase, wordSplit, - firstPhrase, lastWord, isBlank, isCamelized, isUncountable, - isIrregular, isIrregularInverse, rule; - - isBlank = ember$inflector$lib$system$inflector$$BLANK_REGEX.test(word); - isCamelized = ember$inflector$lib$system$inflector$$CAMELIZED_REGEX.test(word); - firstPhrase = ""; - - if (isBlank) { - return word; - } - - lowercase = word.toLowerCase(); - wordSplit = ember$inflector$lib$system$inflector$$LAST_WORD_DASHED_REGEX.exec(word) || ember$inflector$lib$system$inflector$$LAST_WORD_CAMELIZED_REGEX.exec(word); - if (wordSplit){ - firstPhrase = wordSplit[1]; - lastWord = wordSplit[2].toLowerCase(); - } - - isUncountable = this.rules.uncountable[lowercase] || this.rules.uncountable[lastWord]; - - if (isUncountable) { - return word; - } - - isIrregular = irregular && (irregular[lowercase] || irregular[lastWord]); - - if (isIrregular) { - if (irregular[lowercase]){ - return isIrregular; - } - else { - isIrregular = (isCamelized) ? ember$inflector$lib$system$inflector$$capitalize(isIrregular) : isIrregular; - return firstPhrase + isIrregular; - } - } - - for (var i = typeRules.length, min = 0; i > min; i--) { - inflection = typeRules[i-1]; - rule = inflection[0]; - - if (rule.test(word)) { - break; - } - } - - inflection = inflection || []; - - rule = inflection[0]; - substitution = inflection[1]; - - result = word.replace(rule, substitution); - - return result; - } - }; - - var ember$inflector$lib$system$inflector$$default = ember$inflector$lib$system$inflector$$Inflector; - - function ember$inflector$lib$system$string$$pluralize(word) { - return ember$inflector$lib$system$inflector$$default.inflector.pluralize(word); - } - - function ember$inflector$lib$system$string$$singularize(word) { - return ember$inflector$lib$system$inflector$$default.inflector.singularize(word); - } - - var ember$inflector$lib$system$inflections$$default = { - plurals: [ - [/$/, 's'], - [/s$/i, 's'], - [/^(ax|test)is$/i, '$1es'], - [/(octop|vir)us$/i, '$1i'], - [/(octop|vir)i$/i, '$1i'], - [/(alias|status)$/i, '$1es'], - [/(bu)s$/i, '$1ses'], - [/(buffal|tomat)o$/i, '$1oes'], - [/([ti])um$/i, '$1a'], - [/([ti])a$/i, '$1a'], - [/sis$/i, 'ses'], - [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'], - [/(hive)$/i, '$1s'], - [/([^aeiouy]|qu)y$/i, '$1ies'], - [/(x|ch|ss|sh)$/i, '$1es'], - [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'], - [/^(m|l)ouse$/i, '$1ice'], - [/^(m|l)ice$/i, '$1ice'], - [/^(ox)$/i, '$1en'], - [/^(oxen)$/i, '$1'], - [/(quiz)$/i, '$1zes'] - ], - - singular: [ - [/s$/i, ''], - [/(ss)$/i, '$1'], - [/(n)ews$/i, '$1ews'], - [/([ti])a$/i, '$1um'], - [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '$1sis'], - [/(^analy)(sis|ses)$/i, '$1sis'], - [/([^f])ves$/i, '$1fe'], - [/(hive)s$/i, '$1'], - [/(tive)s$/i, '$1'], - [/([lr])ves$/i, '$1f'], - [/([^aeiouy]|qu)ies$/i, '$1y'], - [/(s)eries$/i, '$1eries'], - [/(m)ovies$/i, '$1ovie'], - [/(x|ch|ss|sh)es$/i, '$1'], - [/^(m|l)ice$/i, '$1ouse'], - [/(bus)(es)?$/i, '$1'], - [/(o)es$/i, '$1'], - [/(shoe)s$/i, '$1'], - [/(cris|test)(is|es)$/i, '$1is'], - [/^(a)x[ie]s$/i, '$1xis'], - [/(octop|vir)(us|i)$/i, '$1us'], - [/(alias|status)(es)?$/i, '$1'], - [/^(ox)en/i, '$1'], - [/(vert|ind)ices$/i, '$1ex'], - [/(matr)ices$/i, '$1ix'], - [/(quiz)zes$/i, '$1'], - [/(database)s$/i, '$1'] - ], - - irregularPairs: [ - ['person', 'people'], - ['man', 'men'], - ['child', 'children'], - ['sex', 'sexes'], - ['move', 'moves'], - ['cow', 'kine'], - ['zombie', 'zombies'] - ], - - uncountable: [ - 'equipment', - 'information', - 'rice', - 'money', - 'species', - 'series', - 'fish', - 'sheep', - 'jeans', - 'police' - ] - }; - - ember$inflector$lib$system$inflector$$default.inflector = new ember$inflector$lib$system$inflector$$default(ember$inflector$lib$system$inflections$$default); - - /** - * - * If you have Ember Inflector (such as if Ember Data is present), - * singularize a word. For example, turn "oxen" into "ox". - * - * Example: - * - * {{singularize myProperty}} - * {{singularize "oxen"}} - * - * @for Ember.Handlebars.helpers - * @method singularize - * @param {String|Property} word word to singularize - */ - Ember.Handlebars.helper('singularize', ember$inflector$lib$system$string$$singularize); - - /** - * - * If you have Ember Inflector (such as if Ember Data is present), - * pluralize a word. For example, turn "ox" into "oxen". - * - * Example: - * - * {{pluralize count myProperty}} - * {{pluralize 1 "oxen"}} - * {{pluralize myProperty}} - * {{pluralize "ox"}} - * - * @for Ember.Handlebars.helpers - * @method pluralize - * @param {Number|Property} [count] count of objects - * @param {String|Property} word word to pluralize - */ - Ember.Handlebars.helper('pluralize', function(count, word, options) { - if(arguments.length < 3) { - return ember$inflector$lib$system$string$$pluralize(count); - } else { - /* jshint eqeqeq: false */ - if(count != 1) { - /* jshint eqeqeq: true */ - word = ember$inflector$lib$system$string$$pluralize(word); - } - return count + " " + word; - } - }); - - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.String) { - /** - See {{#crossLink "Ember.String/pluralize"}}{{/crossLink}} - - @method pluralize - @for String - */ - String.prototype.pluralize = function() { - return ember$inflector$lib$system$string$$pluralize(this); - }; - - /** - See {{#crossLink "Ember.String/singularize"}}{{/crossLink}} - - @method singularize - @for String - */ - String.prototype.singularize = function() { - return ember$inflector$lib$system$string$$singularize(this); - }; - } - - ember$inflector$lib$system$inflector$$default.defaultRules = ember$inflector$lib$system$inflections$$default; - Ember.Inflector = ember$inflector$lib$system$inflector$$default; - - Ember.String.pluralize = ember$inflector$lib$system$string$$pluralize; - Ember.String.singularize = ember$inflector$lib$system$string$$singularize; - - var ember$inflector$lib$main$$default = ember$inflector$lib$system$inflector$$default; - - /** - @module ember-data - */ - - var activemodel$adapter$lib$system$active_model_adapter$$decamelize = Ember.String.decamelize, - activemodel$adapter$lib$system$active_model_adapter$$underscore = Ember.String.underscore; - - /** - The ActiveModelAdapter is a subclass of the RESTAdapter designed to integrate - with a JSON API that uses an underscored naming convention instead of camelCasing. - It has been designed to work out of the box with the - [active\_model\_serializers](http://github.com/rails-api/active_model_serializers) - Ruby gem. This Adapter expects specific settings using ActiveModel::Serializers, - `embed :ids, embed_in_root: true` which sideloads the records. - - This adapter extends the DS.RESTAdapter by making consistent use of the camelization, - decamelization and pluralization methods to normalize the serialized JSON into a - format that is compatible with a conventional Rails backend and Ember Data. - - ## JSON Structure - - The ActiveModelAdapter expects the JSON returned from your server to follow - the REST adapter conventions substituting underscored keys for camelcased ones. - - Unlike the DS.RESTAdapter, async relationship keys must be the singular form - of the relationship name, followed by "_id" for DS.belongsTo relationships, - or "_ids" for DS.hasMany relationships. - - ### Conventional Names - - Attribute names in your JSON payload should be the underscored versions of - the attributes in your Ember.js models. - - For example, if you have a `Person` model: - - ```js - App.FamousPerson = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string') - }); - ``` - - The JSON returned should look like this: - - ```js - { - "famous_person": { - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation": "President" - } - } - ``` - - Let's imagine that `Occupation` is just another model: - - ```js - App.Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.belongsTo('occupation') - }); - - App.Occupation = DS.Model.extend({ - name: DS.attr('string'), - salary: DS.attr('number'), - people: DS.hasMany('person') - }); - ``` - - The JSON needed to avoid extra server calls, should look like this: - - ```js - { - "people": [{ - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation_id": 1 - }], - - "occupations": [{ - "id": 1, - "name": "President", - "salary": 100000, - "person_ids": [1] - }] - } - ``` - - @class ActiveModelAdapter - @constructor - @namespace DS - @extends DS.RESTAdapter - **/ - - var activemodel$adapter$lib$system$active_model_adapter$$ActiveModelAdapter = ember$data$lib$adapters$rest_adapter$$default.extend({ - defaultSerializer: '-active-model', - /** - The ActiveModelAdapter overrides the `pathForType` method to build - underscored URLs by decamelizing and pluralizing the object type name. - - ```js - this.pathForType("famousPerson"); - //=> "famous_people" - ``` - - @method pathForType - @param {String} type - @return String - */ - pathForType: function(type) { - var decamelized = activemodel$adapter$lib$system$active_model_adapter$$decamelize(type); - var underscored = activemodel$adapter$lib$system$active_model_adapter$$underscore(decamelized); - return ember$inflector$lib$system$string$$pluralize(underscored); - }, - - /** - The ActiveModelAdapter overrides the `ajaxError` method - to return a DS.InvalidError for all 422 Unprocessable Entity - responses. - - A 422 HTTP response from the server generally implies that the request - was well formed but the API was unable to process it because the - content was not semantically correct or meaningful per the API. - - For more information on 422 HTTP Error code see 11.2 WebDAV RFC 4918 - https://tools.ietf.org/html/rfc4918#section-11.2 - - @method ajaxError - @param {Object} jqXHR - @return error - */ - ajaxError: function(jqXHR) { - var error = this._super.apply(this, arguments); - - if (jqXHR && jqXHR.status === 422) { - return new ember$data$lib$system$adapter$$InvalidError(Ember.$.parseJSON(jqXHR.responseText)); - } else { - return error; - } - } - }); - - var activemodel$adapter$lib$system$active_model_adapter$$default = activemodel$adapter$lib$system$active_model_adapter$$ActiveModelAdapter; - var ember$data$lib$serializers$json_serializer$$get = Ember.get; - var ember$data$lib$serializers$json_serializer$$isNone = Ember.isNone; - var ember$data$lib$serializers$json_serializer$$map = Ember.ArrayPolyfills.map; - var ember$data$lib$serializers$json_serializer$$merge = Ember.merge; - - var ember$data$lib$serializers$json_serializer$$default = Ember.Object.extend({ - /** - The primaryKey is used when serializing and deserializing - data. Ember Data always uses the `id` property to store the id of - the record. The external source may not always follow this - convention. In these cases it is useful to override the - primaryKey property to match the primaryKey of your external - store. - - Example - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - primaryKey: '_id' - }); - ``` - - @property primaryKey - @type {String} - @default 'id' - */ - primaryKey: 'id', - - /** - The `attrs` object can be used to declare a simple mapping between - property names on `DS.Model` records and payload keys in the - serialized JSON object representing the record. An object with the - property `key` can also be used to designate the attribute's key on - the response payload. - - Example - - ```javascript - App.Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string'), - admin: DS.attr('boolean') - }); - - App.PersonSerializer = DS.JSONSerializer.extend({ - attrs: { - admin: 'is_admin', - occupation: {key: 'career'} - } - }); - ``` - - You can also remove attributes by setting the `serialize` key to - false in your mapping object. - - Example - - ```javascript - App.PersonSerializer = DS.JSONSerializer.extend({ - attrs: { - admin: {serialize: false}, - occupation: {key: 'career'} - } - }); - ``` - - When serialized: - - ```javascript - { - "career": "magician" - } - ``` - - Note that the `admin` is now not included in the payload. - - @property attrs - @type {Object} - */ - - /** - Given a subclass of `DS.Model` and a JSON object this method will - iterate through each attribute of the `DS.Model` and invoke the - `DS.Transform#deserialize` method on the matching property of the - JSON object. This method is typically called after the - serializer's `normalize` method. - - @method applyTransforms - @private - @param {subclass of DS.Model} type - @param {Object} data The data to transform - @return {Object} data The transformed data object - */ - applyTransforms: function(type, data) { - type.eachTransformedAttribute(function applyTransform(key, type) { - if (!data.hasOwnProperty(key)) { return; } - - var transform = this.transformFor(type); - data[key] = transform.deserialize(data[key]); - }, this); - - return data; - }, - - /** - Normalizes a part of the JSON payload returned by - the server. You should override this method, munge the hash - and call super if you have generic normalization to do. - - It takes the type of the record that is being normalized - (as a DS.Model class), the property where the hash was - originally found, and the hash to normalize. - - You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. - - Example - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - normalize: function(type, hash) { - var fields = Ember.get(type, 'fields'); - fields.forEach(function(field) { - var payloadField = Ember.String.underscore(field); - if (field === payloadField) { return; } - - hash[field] = hash[payloadField]; - delete hash[payloadField]; - }); - return this._super.apply(this, arguments); - } - }); - ``` - - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash - @return {Object} - */ - normalize: function(type, hash) { - if (!hash) { return hash; } - - this.normalizeId(hash); - this.normalizeAttributes(type, hash); - this.normalizeRelationships(type, hash); - - this.normalizeUsingDeclaredMapping(type, hash); - this.applyTransforms(type, hash); - return hash; - }, - - /** - You can use this method to normalize all payloads, regardless of whether they - represent single records or an array. - - For example, you might want to remove some extraneous data from the payload: - - ```js - App.ApplicationSerializer = DS.JSONSerializer.extend({ - normalizePayload: function(payload) { - delete payload.version; - delete payload.status; - return payload; - } - }); - ``` - - @method normalizePayload - @param {Object} payload - @return {Object} the normalized payload - */ - normalizePayload: function(payload) { - return payload; - }, - - /** - @method normalizeAttributes - @private - */ - normalizeAttributes: function(type, hash) { - var payloadKey; - - if (this.keyForAttribute) { - type.eachAttribute(function(key) { - payloadKey = this.keyForAttribute(key); - if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }, this); - } - }, - - /** - @method normalizeRelationships - @private - */ - normalizeRelationships: function(type, hash) { - var payloadKey; - - if (this.keyForRelationship) { - type.eachRelationship(function(key, relationship) { - payloadKey = this.keyForRelationship(key, relationship.kind); - if (key === payloadKey) { return; } - if (!hash.hasOwnProperty(payloadKey)) { return; } - - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - }, this); - } - }, - - /** - @method normalizeUsingDeclaredMapping - @private - */ - normalizeUsingDeclaredMapping: function(type, hash) { - var attrs = ember$data$lib$serializers$json_serializer$$get(this, 'attrs'), payloadKey, key; - - if (attrs) { - for (key in attrs) { - payloadKey = this._getMappedKey(key); - if (!hash.hasOwnProperty(payloadKey)) { continue; } - - if (payloadKey !== key) { - hash[key] = hash[payloadKey]; - delete hash[payloadKey]; - } - } - } - }, - - /** - @method normalizeId - @private - */ - normalizeId: function(hash) { - var primaryKey = ember$data$lib$serializers$json_serializer$$get(this, 'primaryKey'); - - if (primaryKey === 'id') { return; } - - hash.id = hash[primaryKey]; - delete hash[primaryKey]; - }, - - /** - @method normalizeErrors - @private - */ - normalizeErrors: function(type, hash) { - this.normalizeId(hash); - this.normalizeAttributes(type, hash); - this.normalizeRelationships(type, hash); - }, - - /** - Looks up the property key that was set by the custom `attr` mapping - passed to the serializer. - - @method _getMappedKey - @private - @param {String} key - @return {String} key - */ - _getMappedKey: function(key) { - var attrs = ember$data$lib$serializers$json_serializer$$get(this, 'attrs'); - var mappedKey; - if (attrs && attrs[key]) { - mappedKey = attrs[key]; - //We need to account for both the {title: 'post_title'} and - //{title: {key: 'post_title'}} forms - if (mappedKey.key){ - mappedKey = mappedKey.key; - } - if (typeof mappedKey === 'string'){ - key = mappedKey; - } - } - - return key; - }, - - /** - Check attrs.key.serialize property to inform if the `key` - can be serialized - - @method _canSerialize - @private - @param {String} key - @return {boolean} true if the key can be serialized - */ - _canSerialize: function(key) { - var attrs = ember$data$lib$serializers$json_serializer$$get(this, 'attrs'); - - return !attrs || !attrs[key] || attrs[key].serialize !== false; - }, - - // SERIALIZE - /** - Called when a record is saved in order to convert the - record into JSON. - - By default, it creates a JSON object with a key for - each attribute and belongsTo relationship. - - For example, consider this model: - - ```javascript - App.Comment = DS.Model.extend({ - title: DS.attr(), - body: DS.attr(), - - author: DS.belongsTo('user') - }); - ``` - - The default serialization would create a JSON object like: - - ```javascript - { - "title": "Rails is unagi", - "body": "Rails? Omakase? O_O", - "author": 12 - } - ``` - - By default, attributes are passed through as-is, unless - you specified an attribute type (`DS.attr('date')`). If - you specify a transform, the JavaScript value will be - serialized when inserted into the JSON hash. - - By default, belongs-to relationships are converted into - IDs when inserted into the JSON hash. - - ## IDs - - `serialize` takes an options hash with a single option: - `includeId`. If this option is `true`, `serialize` will, - by default include the ID in the JSON object it builds. - - The adapter passes in `includeId: true` when serializing - a record for `createRecord`, but not for `updateRecord`. - - ## Customization - - Your server may expect a different JSON format than the - built-in serialization format. - - In that case, you can implement `serialize` yourself and - return a JSON hash of your choosing. - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serialize: function(post, options) { - var json = { - POST_TTL: post.get('title'), - POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapBy('id') - } - - if (options.includeId) { - json.POST_ID_ = post.get('id'); - } - - return json; - } - }); - ``` - - ## Customizing an App-Wide Serializer - - If you want to define a serializer for your entire - application, you'll probably want to use `eachAttribute` - and `eachRelationship` on the record. - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - serialize: function(record, options) { - var json = {}; - - record.eachAttribute(function(name) { - json[serverAttributeName(name)] = record.get(name); - }) - - record.eachRelationship(function(name, relationship) { - if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = record.get(name).mapBy('id'); - } - }); - - if (options.includeId) { - json.ID_ = record.get('id'); - } - - return json; - } - }); - - function serverAttributeName(attribute) { - return attribute.underscore().toUpperCase(); - } - - function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; - } - ``` - - This serializer will generate JSON that looks like this: - - ```javascript - { - "TITLE": "Rails is omakase", - "BODY": "Yep. Omakase.", - "COMMENT_IDS": [ 1, 2, 3 ] - } - ``` - - ## Tweaking the Default JSON - - If you just want to do some small tweaks on the default JSON, - you can call super first and make the tweaks on the returned - JSON. - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serialize: function(record, options) { - var json = this._super.apply(this, arguments); - - json.subject = json.title; - delete json.title; - - return json; - } - }); - ``` - - @method serialize - @param {subclass of DS.Model} record - @param {Object} options - @return {Object} json - */ - serialize: function(record, options) { - var json = {}; - - if (options && options.includeId) { - var id = ember$data$lib$serializers$json_serializer$$get(record, 'id'); - - if (id) { - json[ember$data$lib$serializers$json_serializer$$get(this, 'primaryKey')] = id; - } - } - - record.eachAttribute(function(key, attribute) { - this.serializeAttribute(record, json, key, attribute); - }, this); - - record.eachRelationship(function(key, relationship) { - if (relationship.kind === 'belongsTo') { - this.serializeBelongsTo(record, json, relationship); - } else if (relationship.kind === 'hasMany') { - this.serializeHasMany(record, json, relationship); - } - }, this); - - return json; - }, - - /** - You can use this method to customize how a serialized record is added to the complete - JSON hash to be sent to the server. By default the JSON Serializer does not namespace - the payload and just sends the raw serialized JSON object. - If your server expects namespaced keys, you should consider using the RESTSerializer. - Otherwise you can override this method to customize how the record is added to the hash. - - For example, your server may expect underscored root objects. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { - var root = Ember.String.decamelize(type.typeKey); - data[root] = this.serialize(record, options); - } - }); - ``` - - @method serializeIntoHash - @param {Object} hash - @param {subclass of DS.Model} type - @param {DS.Model} record - @param {Object} options - */ - serializeIntoHash: function(hash, type, record, options) { - ember$data$lib$serializers$json_serializer$$merge(hash, this.serialize(record, options)); - }, - - /** - `serializeAttribute` can be used to customize how `DS.attr` - properties are serialized - - For example if you wanted to ensure all your attributes were always - serialized as properties on an `attributes` object you could - write: - - ```javascript - App.ApplicationSerializer = DS.JSONSerializer.extend({ - serializeAttribute: function(record, json, key, attributes) { - json.attributes = json.attributes || {}; - this._super(record, json.attributes, key, attributes); - } - }); - ``` - - @method serializeAttribute - @param {DS.Model} record - @param {Object} json - @param {String} key - @param {Object} attribute - */ - serializeAttribute: function(record, json, key, attribute) { - var type = attribute.type; - - if (this._canSerialize(key)) { - var value = ember$data$lib$serializers$json_serializer$$get(record, key); - if (type) { - var transform = this.transformFor(type); - value = transform.serialize(value); - } - - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key); - - if (payloadKey === key && this.keyForAttribute) { - payloadKey = this.keyForAttribute(key); - } - - json[payloadKey] = value; - } - }, - - /** - `serializeBelongsTo` can be used to customize how `DS.belongsTo` - properties are serialized. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serializeBelongsTo: function(record, json, relationship) { - var key = relationship.key; - - var belongsTo = get(record, key); - - key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key; - - json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.toJSON(); - } - }); - ``` - - @method serializeBelongsTo - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeBelongsTo: function(record, json, relationship) { - var key = relationship.key; - - if (this._canSerialize(key)) { - var belongsTo = ember$data$lib$serializers$json_serializer$$get(record, key); - - // if provided, use the mapping provided by `attrs` in - // the serializer - var payloadKey = this._getMappedKey(key); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "belongsTo"); - } - - //Need to check whether the id is there for new&async records - if (ember$data$lib$serializers$json_serializer$$isNone(belongsTo) || ember$data$lib$serializers$json_serializer$$isNone(ember$data$lib$serializers$json_serializer$$get(belongsTo, 'id'))) { - json[payloadKey] = null; - } else { - json[payloadKey] = ember$data$lib$serializers$json_serializer$$get(belongsTo, 'id'); - } - - if (relationship.options.polymorphic) { - this.serializePolymorphicType(record, json, relationship); - } - } - }, - - /** - `serializeHasMany` can be used to customize how `DS.hasMany` - properties are serialized. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - serializeHasMany: function(record, json, relationship) { - var key = relationship.key; - if (key === 'comments') { - return; - } else { - this._super.apply(this, arguments); - } - } - }); - ``` - - @method serializeHasMany - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeHasMany: function(record, json, relationship) { - var key = relationship.key; - - if (this._canSerialize(key)) { - var payloadKey; - - // if provided, use the mapping provided by `attrs` in - // the serializer - payloadKey = this._getMappedKey(key); - if (payloadKey === key && this.keyForRelationship) { - payloadKey = this.keyForRelationship(key, "hasMany"); - } - - var relationshipType = record.constructor.determineRelationshipType(relationship); - - if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') { - json[payloadKey] = ember$data$lib$serializers$json_serializer$$get(record, key).mapBy('id'); - // TODO support for polymorphic manyToNone and manyToMany relationships - } - } - }, - - /** - You can use this method to customize how polymorphic objects are - serialized. Objects are considered to be polymorphic if - `{polymorphic: true}` is pass as the second argument to the - `DS.belongsTo` function. - - Example - - ```javascript - App.CommentSerializer = DS.JSONSerializer.extend({ - serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key, - belongsTo = get(record, key); - key = this.keyForAttribute ? this.keyForAttribute(key) : key; - - if (Ember.isNone(belongsTo)) { - json[key + "_type"] = null; - } else { - json[key + "_type"] = belongsTo.constructor.typeKey; - } - } - }); - ``` - - @method serializePolymorphicType - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType: Ember.K, - - // EXTRACT - - /** - The `extract` method is used to deserialize payload data from the - server. By default the `JSONSerializer` does not push the records - into the store. However records that subclass `JSONSerializer` - such as the `RESTSerializer` may push records into the store as - part of the extract call. - - This method delegates to a more specific extract method based on - the `requestType`. - - Example - - ```javascript - var get = Ember.get; - socket.on('message', function(message) { - var modelName = message.model; - var data = message.data; - var type = store.modelFor(modelName); - var serializer = store.serializerFor(type.typeKey); - var record = serializer.extract(store, type, data, get(data, 'id'), 'single'); - store.push(modelName, record); - }); - ``` - - @method extract - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extract: function(store, type, payload, id, requestType) { - this.extractMeta(store, type, payload); - - var specificExtract = "extract" + requestType.charAt(0).toUpperCase() + requestType.substr(1); - return this[specificExtract](store, type, payload, id, requestType); - }, - - /** - `extractFindAll` is a hook into the extract method used when a - call is made to `DS.Store#findAll`. By default this method is an - alias for [extractArray](#method_extractArray). - - @method extractFindAll - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindAll: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - /** - `extractFindQuery` is a hook into the extract method used when a - call is made to `DS.Store#findQuery`. By default this method is an - alias for [extractArray](#method_extractArray). - - @method extractFindQuery - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindQuery: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - /** - `extractFindMany` is a hook into the extract method used when a - call is made to `DS.Store#findMany`. By default this method is - alias for [extractArray](#method_extractArray). - - @method extractFindMany - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindMany: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - /** - `extractFindHasMany` is a hook into the extract method used when a - call is made to `DS.Store#findHasMany`. By default this method is - alias for [extractArray](#method_extractArray). - - @method extractFindHasMany - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractFindHasMany: function(store, type, payload, id, requestType){ - return this.extractArray(store, type, payload, id, requestType); - }, - - /** - `extractCreateRecord` is a hook into the extract method used when a - call is made to `DS.Model#save` and the record is new. By default - this method is alias for [extractSave](#method_extractSave). - - @method extractCreateRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractCreateRecord: function(store, type, payload, id, requestType) { - return this.extractSave(store, type, payload, id, requestType); - }, - /** - `extractUpdateRecord` is a hook into the extract method used when - a call is made to `DS.Model#save` and the record has been updated. - By default this method is alias for [extractSave](#method_extractSave). - - @method extractUpdateRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractUpdateRecord: function(store, type, payload, id, requestType) { - return this.extractSave(store, type, payload, id, requestType); - }, - /** - `extractDeleteRecord` is a hook into the extract method used when - a call is made to `DS.Model#save` and the record has been deleted. - By default this method is alias for [extractSave](#method_extractSave). - - @method extractDeleteRecord - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractDeleteRecord: function(store, type, payload, id, requestType) { - return this.extractSave(store, type, payload, id, requestType); - }, - - /** - `extractFind` is a hook into the extract method used when - a call is made to `DS.Store#find`. By default this method is - alias for [extractSingle](#method_extractSingle). - - @method extractFind - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractFind: function(store, type, payload, id, requestType) { - return this.extractSingle(store, type, payload, id, requestType); - }, - /** - `extractFindBelongsTo` is a hook into the extract method used when - a call is made to `DS.Store#findBelongsTo`. By default this method is - alias for [extractSingle](#method_extractSingle). - - @method extractFindBelongsTo - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractFindBelongsTo: function(store, type, payload, id, requestType) { - return this.extractSingle(store, type, payload, id, requestType); - }, - /** - `extractSave` is a hook into the extract method used when a call - is made to `DS.Model#save`. By default this method is alias - for [extractSingle](#method_extractSingle). - - @method extractSave - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractSave: function(store, type, payload, id, requestType) { - return this.extractSingle(store, type, payload, id, requestType); - }, - - /** - `extractSingle` is used to deserialize a single record returned - from the adapter. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractSingle: function(store, type, payload) { - payload.comments = payload._embedded.comment; - delete payload._embedded; - - return this._super(store, type, payload); - }, - }); - ``` - - @method extractSingle - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Object} json The deserialized payload - */ - extractSingle: function(store, type, payload, id, requestType) { - payload = this.normalizePayload(payload); - return this.normalize(type, payload); - }, - - /** - `extractArray` is used to deserialize an array of records - returned from the adapter. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractArray: function(store, type, payload) { - return payload.map(function(json) { - return this.extractSingle(store, type, json); - }, this); - } - }); - ``` - - @method extractArray - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @param {String} requestType - @return {Array} array An array of deserialized objects - */ - extractArray: function(store, type, arrayPayload, id, requestType) { - var normalizedPayload = this.normalizePayload(arrayPayload); - var serializer = this; - - return ember$data$lib$serializers$json_serializer$$map.call(normalizedPayload, function(singlePayload) { - return serializer.normalize(type, singlePayload); - }); - }, - - /** - `extractMeta` is used to deserialize any meta information in the - adapter payload. By default Ember Data expects meta information to - be located on the `meta` property of the payload object. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractMeta: function(store, type, payload) { - if (payload && payload._pagination) { - store.setMetadataFor(type, payload._pagination); - delete payload._pagination; - } - } - }); - ``` - - @method extractMeta - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - */ - extractMeta: function(store, type, payload) { - if (payload && payload.meta) { - store.setMetadataFor(type, payload.meta); - delete payload.meta; - } - }, - - /** - `extractErrors` is used to extract model errors when a call is made - to `DS.Model#save` which fails with an InvalidError`. By default - Ember Data expects error information to be located on the `errors` - property of the payload object. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - extractErrors: function(store, type, payload, id) { - if (payload && typeof payload === 'object' && payload._problems) { - payload = payload._problems; - this.normalizeErrors(type, payload); - } - return payload; - } - }); - ``` - - @method extractErrors - @param {DS.Store} store - @param {subclass of DS.Model} type - @param {Object} payload - @param {String or Number} id - @return {Object} json The deserialized errors - */ - extractErrors: function(store, type, payload, id) { - if (payload && typeof payload === 'object' && payload.errors) { - payload = payload.errors; - this.normalizeErrors(type, payload); - } - return payload; - }, - - /** - `keyForAttribute` can be used to define rules for how to convert an - attribute name in your model to a key in your JSON. - - Example - - ```javascript - App.ApplicationSerializer = DS.RESTSerializer.extend({ - keyForAttribute: function(attr) { - return Ember.String.underscore(attr).toUpperCase(); - } - }); - ``` - - @method keyForAttribute - @param {String} key - @return {String} normalized key - */ - keyForAttribute: function(key){ - return key; - }, - - /** - `keyForRelationship` can be used to define a custom key when - serializing relationship properties. By default `JSONSerializer` - does not provide an implementation of this method. - - Example - - ```javascript - App.PostSerializer = DS.JSONSerializer.extend({ - keyForRelationship: function(key, relationship) { - return 'rel_' + Ember.String.underscore(key); - } - }); - ``` - - @method keyForRelationship - @param {String} key - @param {String} relationship type - @return {String} normalized key - */ - - keyForRelationship: function(key, type){ - return key; - }, - - // HELPERS - - /** - @method transformFor - @private - @param {String} attributeType - @param {Boolean} skipAssertion - @return {DS.Transform} transform - */ - transformFor: function(attributeType, skipAssertion) { - var transform = this.container.lookup('transform:' + attributeType); - return transform; - } - }); - - var ember$data$lib$serializers$rest_serializer$$get = Ember.get; - var ember$data$lib$serializers$rest_serializer$$forEach = Ember.ArrayPolyfills.forEach; - var ember$data$lib$serializers$rest_serializer$$map = Ember.ArrayPolyfills.map; - var ember$data$lib$serializers$rest_serializer$$camelize = Ember.String.camelize; - - function ember$data$lib$serializers$rest_serializer$$coerceId(id) { - return id == null ? null : id + ''; - } - - /** - Normally, applications will use the `RESTSerializer` by implementing - the `normalize` method and individual normalizations under - `normalizeHash`. - - This allows you to do whatever kind of munging you need, and is - especially useful if your server is inconsistent and you need to - do munging differently for many different kinds of responses. - - See the `normalize` documentation for more information. - - ## Across the Board Normalization - - There are also a number of hooks that you might find useful to define - across-the-board rules for your payload. These rules will be useful - if your server is consistent, or if you're building an adapter for - an infrastructure service, like Parse, and want to encode service - conventions. - - For example, if all of your keys are underscored and all-caps, but - otherwise consistent with the names you use in your models, you - can implement across-the-board rules for how to convert an attribute - name in your model to a key in your JSON. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - keyForAttribute: function(attr) { - return Ember.String.underscore(attr).toUpperCase(); - } - }); - ``` - - You can also implement `keyForRelationship`, which takes the name - of the relationship as the first parameter, and the kind of - relationship (`hasMany` or `belongsTo`) as the second parameter. - - @class RESTSerializer - @namespace DS - @extends DS.JSONSerializer - */ - var ember$data$lib$serializers$rest_serializer$$RESTSerializer = ember$data$lib$serializers$json_serializer$$default.extend({ - /** - If you want to do normalizations specific to some part of the payload, you - can specify those under `normalizeHash`. - - For example, given the following json where the the `IDs` under - `"comments"` are provided as `_id` instead of `id`. - - ```javascript - { - "post": { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2 ] - }, - "comments": [{ - "_id": 1, - "body": "FIRST" - }, { - "_id": 2, - "body": "Rails is unagi" - }] - } - ``` - - You use `normalizeHash` to normalize just the comments: - - ```javascript - App.PostSerializer = DS.RESTSerializer.extend({ - normalizeHash: { - comments: function(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - }); - ``` - - The key under `normalizeHash` is usually just the original key - that was in the original payload. However, key names will be - impacted by any modifications done in the `normalizePayload` - method. The `DS.RESTSerializer`'s default implementation makes no - changes to the payload keys. - - @property normalizeHash - @type {Object} - @default undefined - */ - - /** - Normalizes a part of the JSON payload returned by - the server. You should override this method, munge the hash - and call super if you have generic normalization to do. - - It takes the type of the record that is being normalized - (as a DS.Model class), the property where the hash was - originally found, and the hash to normalize. - - For example, if you have a payload that looks like this: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "comments": [ 1, 2 ] - }, - "comments": [{ - "id": 1, - "body": "FIRST" - }, { - "id": 2, - "body": "Rails is unagi" - }] - } - ``` - - The `normalize` method will be called three times: - - * With `App.Post`, `"posts"` and `{ id: 1, title: "Rails is omakase", ... }` - * With `App.Comment`, `"comments"` and `{ id: 1, body: "FIRST" }` - * With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }` - - You can use this method, for example, to normalize underscored keys to camelized - or other general-purpose normalizations. - - If you want to do normalizations specific to some part of the payload, you - can specify those under `normalizeHash`. - - For example, if the `IDs` under `"comments"` are provided as `_id` instead of - `id`, you can specify how to normalize just the comments: - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - normalizeHash: { - comments: function(hash) { - hash.id = hash._id; - delete hash._id; - return hash; - } - } - }); - ``` - - The key under `normalizeHash` is just the original key that was in the original - payload. - - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash - @param {String} prop - @return {Object} - */ - normalize: function(type, hash, prop) { - this.normalizeId(hash); - this.normalizeAttributes(type, hash); - this.normalizeRelationships(type, hash); - - this.normalizeUsingDeclaredMapping(type, hash); - - if (this.normalizeHash && this.normalizeHash[prop]) { - this.normalizeHash[prop](hash); - } - - this.applyTransforms(type, hash); - return hash; - }, - - - /** - Called when the server has returned a payload representing - a single record, such as in response to a `find` or `save`. - - It is your opportunity to clean up the server's response into the normalized - form expected by Ember Data. - - If you want, you can just restructure the top-level of your payload, and - do more fine-grained normalization in the `normalize` method. - - For example, if you have a payload like this in response to a request for - post 1: - - ```js - { - "id": 1, - "title": "Rails is omakase", - - "_embedded": { - "comment": [{ - "_id": 1, - "comment_title": "FIRST" - }, { - "_id": 2, - "comment_title": "Rails is unagi" - }] - } - } - ``` - - You could implement a serializer that looks like this to get your payload - into shape: - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - // First, restructure the top-level so it's organized by type - extractSingle: function(store, type, payload, id) { - var comments = payload._embedded.comment; - delete payload._embedded; - - payload = { comments: comments, post: payload }; - return this._super(store, type, payload, id); - }, - - normalizeHash: { - // Next, normalize individual comments, which (after `extract`) - // are now located under `comments` - comments: function(hash) { - hash.id = hash._id; - hash.title = hash.comment_title; - delete hash._id; - delete hash.comment_title; - return hash; - } - } - }) - ``` - - When you call super from your own implementation of `extractSingle`, the - built-in implementation will find the primary record in your normalized - payload and push the remaining records into the store. - - The primary record is the single hash found under `post` or the first - element of the `posts` array. - - The primary record has special meaning when the record is being created - for the first time or updated (`createRecord` or `updateRecord`). In - particular, it will update the properties of the record that was saved. - - @method extractSingle - @param {DS.Store} store - @param {subclass of DS.Model} primaryType - @param {Object} payload - @param {String} recordId - @return {Object} the primary response to the original request - */ - extractSingle: function(store, primaryType, rawPayload, recordId) { - var payload = this.normalizePayload(rawPayload); - var primaryTypeName = primaryType.typeKey; - var primaryRecord; - - for (var prop in payload) { - var typeName = this.typeForRoot(prop); - - if (!store.modelFactoryFor(typeName)){ - continue; - } - var type = store.modelFor(typeName); - var isPrimary = type.typeKey === primaryTypeName; - var value = payload[prop]; - - if (value === null) { - continue; - } - - // legacy support for singular resources - if (isPrimary && Ember.typeOf(value) !== "array" ) { - primaryRecord = this.normalize(primaryType, value, prop); - continue; - } - - /*jshint loopfunc:true*/ - ember$data$lib$serializers$rest_serializer$$forEach.call(value, function(hash) { - var typeName = this.typeForRoot(prop); - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - - hash = typeSerializer.normalize(type, hash, prop); - - var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord; - var isUpdatedRecord = isPrimary && ember$data$lib$serializers$rest_serializer$$coerceId(hash.id) === recordId; - - // find the primary record. - // - // It's either: - // * the record with the same ID as the original request - // * in the case of a newly created record that didn't have an ID, the first - // record in the Array - if (isFirstCreatedRecord || isUpdatedRecord) { - primaryRecord = hash; - } else { - store.push(typeName, hash); - } - }, this); - } - - return primaryRecord; - }, - - /** - Called when the server has returned a payload representing - multiple records, such as in response to a `findAll` or `findQuery`. - - It is your opportunity to clean up the server's response into the normalized - form expected by Ember Data. - - If you want, you can just restructure the top-level of your payload, and - do more fine-grained normalization in the `normalize` method. - - For example, if you have a payload like this in response to a request for - all posts: - - ```js - { - "_embedded": { - "post": [{ - "id": 1, - "title": "Rails is omakase" - }, { - "id": 2, - "title": "The Parley Letter" - }], - "comment": [{ - "_id": 1, - "comment_title": "Rails is unagi" - "post_id": 1 - }, { - "_id": 2, - "comment_title": "Don't tread on me", - "post_id": 2 - }] - } - } - ``` - - You could implement a serializer that looks like this to get your payload - into shape: - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - // First, restructure the top-level so it's organized by type - // and the comments are listed under a post's `comments` key. - extractArray: function(store, type, payload) { - var posts = payload._embedded.post; - var comments = []; - var postCache = {}; - - posts.forEach(function(post) { - post.comments = []; - postCache[post.id] = post; - }); - - payload._embedded.comment.forEach(function(comment) { - comments.push(comment); - postCache[comment.post_id].comments.push(comment); - delete comment.post_id; - }); - - payload = { comments: comments, posts: payload }; - - return this._super(store, type, payload); - }, - - normalizeHash: { - // Next, normalize individual comments, which (after `extract`) - // are now located under `comments` - comments: function(hash) { - hash.id = hash._id; - hash.title = hash.comment_title; - delete hash._id; - delete hash.comment_title; - return hash; - } - } - }) - ``` - - When you call super from your own implementation of `extractArray`, the - built-in implementation will find the primary array in your normalized - payload and push the remaining records into the store. - - The primary array is the array found under `posts`. - - The primary record has special meaning when responding to `findQuery` - or `findHasMany`. In particular, the primary array will become the - list of records in the record array that kicked off the request. - - If your primary array contains secondary (embedded) records of the same type, - you cannot place these into the primary array `posts`. Instead, place the - secondary items into an underscore prefixed property `_posts`, which will - push these items into the store and will not affect the resulting query. - - @method extractArray - @param {DS.Store} store - @param {subclass of DS.Model} primaryType - @param {Object} payload - @return {Array} The primary array that was returned in response - to the original query. - */ - extractArray: function(store, primaryType, rawPayload) { - var payload = this.normalizePayload(rawPayload); - var primaryTypeName = primaryType.typeKey; - var primaryArray; - - for (var prop in payload) { - var typeKey = prop; - var forcedSecondary = false; - - if (prop.charAt(0) === '_') { - forcedSecondary = true; - typeKey = prop.substr(1); - } - - var typeName = this.typeForRoot(typeKey); - if (!store.modelFactoryFor(typeName)) { - continue; - } - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - var isPrimary = (!forcedSecondary && (type.typeKey === primaryTypeName)); - - /*jshint loopfunc:true*/ - var normalizedArray = ember$data$lib$serializers$rest_serializer$$map.call(payload[prop], function(hash) { - return typeSerializer.normalize(type, hash, prop); - }, this); - - if (isPrimary) { - primaryArray = normalizedArray; - } else { - store.pushMany(typeName, normalizedArray); - } - } - - return primaryArray; - }, - - /** - This method allows you to push a payload containing top-level - collections of records organized per type. - - ```js - { - "posts": [{ - "id": "1", - "title": "Rails is omakase", - "author", "1", - "comments": [ "1" ] - }], - "comments": [{ - "id": "1", - "body": "FIRST" - }], - "users": [{ - "id": "1", - "name": "@d2h" - }] - } - ``` - - It will first normalize the payload, so you can use this to push - in data streaming in from your server structured the same way - that fetches and saves are structured. - - @method pushPayload - @param {DS.Store} store - @param {Object} payload - */ - pushPayload: function(store, rawPayload) { - var payload = this.normalizePayload(rawPayload); - - for (var prop in payload) { - var typeName = this.typeForRoot(prop); - if (!store.modelFactoryFor(typeName, prop)){ - continue; - } - var type = store.modelFor(typeName); - var typeSerializer = store.serializerFor(type); - - /*jshint loopfunc:true*/ - var normalizedArray = ember$data$lib$serializers$rest_serializer$$map.call(Ember.makeArray(payload[prop]), function(hash) { - return typeSerializer.normalize(type, hash, prop); - }, this); - - store.pushMany(typeName, normalizedArray); - } - }, - - /** - This method is used to convert each JSON root key in the payload - into a typeKey that it can use to look up the appropriate model for - that part of the payload. By default the typeKey for a model is its - name in camelCase, so if your JSON root key is 'fast-car' you would - use typeForRoot to convert it to 'fastCar' so that Ember Data finds - the `FastCar` model. - - If you diverge from this norm you should also consider changes to - store._normalizeTypeKey as well. - - For example, your server may return prefixed root keys like so: - - ```js - { - "response-fast-car": { - "id": "1", - "name": "corvette" - } - } - ``` - - In order for Ember Data to know that the model corresponding to - the 'response-fast-car' hash is `FastCar` (typeKey: 'fastCar'), - you can override typeForRoot to convert 'response-fast-car' to - 'fastCar' like so: - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - typeForRoot: function(root) { - // 'response-fast-car' should become 'fast-car' - var subRoot = root.substring(9); - - // _super normalizes 'fast-car' to 'fastCar' - return this._super(subRoot); - } - }); - ``` - - @method typeForRoot - @param {String} key - @return {String} the model's typeKey - */ - typeForRoot: function(key) { - return ember$data$lib$serializers$rest_serializer$$camelize(ember$inflector$lib$system$string$$singularize(key)); - }, - - // SERIALIZE - - /** - Called when a record is saved in order to convert the - record into JSON. - - By default, it creates a JSON object with a key for - each attribute and belongsTo relationship. - - For example, consider this model: - - ```js - App.Comment = DS.Model.extend({ - title: DS.attr(), - body: DS.attr(), - - author: DS.belongsTo('user') - }); - ``` - - The default serialization would create a JSON object like: - - ```js - { - "title": "Rails is unagi", - "body": "Rails? Omakase? O_O", - "author": 12 - } - ``` - - By default, attributes are passed through as-is, unless - you specified an attribute type (`DS.attr('date')`). If - you specify a transform, the JavaScript value will be - serialized when inserted into the JSON hash. - - By default, belongs-to relationships are converted into - IDs when inserted into the JSON hash. - - ## IDs - - `serialize` takes an options hash with a single option: - `includeId`. If this option is `true`, `serialize` will, - by default include the ID in the JSON object it builds. - - The adapter passes in `includeId: true` when serializing - a record for `createRecord`, but not for `updateRecord`. - - ## Customization - - Your server may expect a different JSON format than the - built-in serialization format. - - In that case, you can implement `serialize` yourself and - return a JSON hash of your choosing. - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - serialize: function(post, options) { - var json = { - POST_TTL: post.get('title'), - POST_BDY: post.get('body'), - POST_CMS: post.get('comments').mapBy('id') - } - - if (options.includeId) { - json.POST_ID_ = post.get('id'); - } - - return json; - } - }); - ``` - - ## Customizing an App-Wide Serializer - - If you want to define a serializer for your entire - application, you'll probably want to use `eachAttribute` - and `eachRelationship` on the record. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - serialize: function(record, options) { - var json = {}; - - record.eachAttribute(function(name) { - json[serverAttributeName(name)] = record.get(name); - }) - - record.eachRelationship(function(name, relationship) { - if (relationship.kind === 'hasMany') { - json[serverHasManyName(name)] = record.get(name).mapBy('id'); - } - }); - - if (options.includeId) { - json.ID_ = record.get('id'); - } - - return json; - } - }); - - function serverAttributeName(attribute) { - return attribute.underscore().toUpperCase(); - } - - function serverHasManyName(name) { - return serverAttributeName(name.singularize()) + "_IDS"; - } - ``` - - This serializer will generate JSON that looks like this: - - ```js - { - "TITLE": "Rails is omakase", - "BODY": "Yep. Omakase.", - "COMMENT_IDS": [ 1, 2, 3 ] - } - ``` - - ## Tweaking the Default JSON - - If you just want to do some small tweaks on the default JSON, - you can call super first and make the tweaks on the returned - JSON. - - ```js - App.PostSerializer = DS.RESTSerializer.extend({ - serialize: function(record, options) { - var json = this._super(record, options); - - json.subject = json.title; - delete json.title; - - return json; - } - }); - ``` - - @method serialize - @param {subclass of DS.Model} record - @param {Object} options - @return {Object} json - */ - serialize: function(record, options) { - return this._super.apply(this, arguments); - }, - - /** - You can use this method to customize the root keys serialized into the JSON. - By default the REST Serializer sends the typeKey of a model, which is a camelized - version of the name. - - For example, your server may expect underscored root objects. - - ```js - App.ApplicationSerializer = DS.RESTSerializer.extend({ - serializeIntoHash: function(data, type, record, options) { - var root = Ember.String.decamelize(type.typeKey); - data[root] = this.serialize(record, options); - } - }); - ``` - - @method serializeIntoHash - @param {Object} hash - @param {subclass of DS.Model} type - @param {DS.Model} record - @param {Object} options - */ - serializeIntoHash: function(hash, type, record, options) { - hash[type.typeKey] = this.serialize(record, options); - }, - - /** - You can use this method to customize how polymorphic objects are serialized. - By default the JSON Serializer creates the key by appending `Type` to - the attribute and value from the model's camelcased model name. - - @method serializePolymorphicType - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key; - var belongsTo = ember$data$lib$serializers$rest_serializer$$get(record, key); - key = this.keyForAttribute ? this.keyForAttribute(key) : key; - if (Ember.isNone(belongsTo)) { - json[key + "Type"] = null; - } else { - json[key + "Type"] = Ember.String.camelize(belongsTo.constructor.typeKey); - } - } - }); - - - var ember$data$lib$serializers$rest_serializer$$default = ember$data$lib$serializers$rest_serializer$$RESTSerializer; - /** - @module ember-data - */ - - var activemodel$adapter$lib$system$active_model_serializer$$get = Ember.get, - activemodel$adapter$lib$system$active_model_serializer$$forEach = Ember.EnumerableUtils.forEach, - activemodel$adapter$lib$system$active_model_serializer$$camelize = Ember.String.camelize, - activemodel$adapter$lib$system$active_model_serializer$$capitalize = Ember.String.capitalize, - activemodel$adapter$lib$system$active_model_serializer$$decamelize = Ember.String.decamelize, - activemodel$adapter$lib$system$active_model_serializer$$underscore = Ember.String.underscore; - /** - The ActiveModelSerializer is a subclass of the RESTSerializer designed to integrate - with a JSON API that uses an underscored naming convention instead of camelCasing. - It has been designed to work out of the box with the - [active\_model\_serializers](http://github.com/rails-api/active_model_serializers) - Ruby gem. This Serializer expects specific settings using ActiveModel::Serializers, - `embed :ids, embed_in_root: true` which sideloads the records. - - This serializer extends the DS.RESTSerializer by making consistent - use of the camelization, decamelization and pluralization methods to - normalize the serialized JSON into a format that is compatible with - a conventional Rails backend and Ember Data. - - ## JSON Structure - - The ActiveModelSerializer expects the JSON returned from your server - to follow the REST adapter conventions substituting underscored keys - for camelcased ones. - - ### Conventional Names - - Attribute names in your JSON payload should be the underscored versions of - the attributes in your Ember.js models. - - For example, if you have a `Person` model: - - ```js - App.FamousPerson = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.attr('string') - }); - ``` - - The JSON returned should look like this: - - ```js - { - "famous_person": { - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation": "President" - } - } - ``` - - Let's imagine that `Occupation` is just another model: - - ```js - App.Person = DS.Model.extend({ - firstName: DS.attr('string'), - lastName: DS.attr('string'), - occupation: DS.belongsTo('occupation') - }); - - App.Occupation = DS.Model.extend({ - name: DS.attr('string'), - salary: DS.attr('number'), - people: DS.hasMany('person') - }); - ``` - - The JSON needed to avoid extra server calls, should look like this: - - ```js - { - "people": [{ - "id": 1, - "first_name": "Barack", - "last_name": "Obama", - "occupation_id": 1 - }], - - "occupations": [{ - "id": 1, - "name": "President", - "salary": 100000, - "person_ids": [1] - }] - } - ``` - - @class ActiveModelSerializer - @namespace DS - @extends DS.RESTSerializer - */ - var activemodel$adapter$lib$system$active_model_serializer$$ActiveModelSerializer = ember$data$lib$serializers$rest_serializer$$default.extend({ - // SERIALIZE - - /** - Converts camelCased attributes to underscored when serializing. - - @method keyForAttribute - @param {String} attribute - @return String - */ - keyForAttribute: function(attr) { - return activemodel$adapter$lib$system$active_model_serializer$$decamelize(attr); - }, - - /** - Underscores relationship names and appends "_id" or "_ids" when serializing - relationship keys. - - @method keyForRelationship - @param {String} key - @param {String} kind - @return String - */ - keyForRelationship: function(rawKey, kind) { - var key = activemodel$adapter$lib$system$active_model_serializer$$decamelize(rawKey); - if (kind === "belongsTo") { - return key + "_id"; - } else if (kind === "hasMany") { - return ember$inflector$lib$system$string$$singularize(key) + "_ids"; - } else { - return key; - } - }, - - /* - Does not serialize hasMany relationships by default. - */ - serializeHasMany: Ember.K, - - /** - Underscores the JSON root keys when serializing. - - @method serializeIntoHash - @param {Object} hash - @param {subclass of DS.Model} type - @param {DS.Model} record - @param {Object} options - */ - serializeIntoHash: function(data, type, record, options) { - var root = activemodel$adapter$lib$system$active_model_serializer$$underscore(activemodel$adapter$lib$system$active_model_serializer$$decamelize(type.typeKey)); - data[root] = this.serialize(record, options); - }, - - /** - Serializes a polymorphic type as a fully capitalized model name. - - @method serializePolymorphicType - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializePolymorphicType: function(record, json, relationship) { - var key = relationship.key; - var belongsTo = activemodel$adapter$lib$system$active_model_serializer$$get(record, key); - var jsonKey = activemodel$adapter$lib$system$active_model_serializer$$underscore(key + "_type"); - - if (Ember.isNone(belongsTo)) { - json[jsonKey] = null; - } else { - json[jsonKey] = activemodel$adapter$lib$system$active_model_serializer$$capitalize(activemodel$adapter$lib$system$active_model_serializer$$camelize(belongsTo.constructor.typeKey)); - } - }, - - // EXTRACT - - /** - Add extra step to `DS.RESTSerializer.normalize` so links are normalized. - - If your payload looks like: - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "links": { "flagged_comments": "api/comments/flagged" } - } - } - ``` - - The normalized version would look like this - - ```js - { - "post": { - "id": 1, - "title": "Rails is omakase", - "links": { "flaggedComments": "api/comments/flagged" } - } - } - ``` - - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash - @param {String} prop - @return Object - */ - - normalize: function(type, hash, prop) { - this.normalizeLinks(hash); - - return this._super(type, hash, prop); - }, - - /** - Convert `snake_cased` links to `camelCase` - - @method normalizeLinks - @param {Object} data - */ - - normalizeLinks: function(data){ - if (data.links) { - var links = data.links; - - for (var link in links) { - var camelizedLink = activemodel$adapter$lib$system$active_model_serializer$$camelize(link); - - if (camelizedLink !== link) { - links[camelizedLink] = links[link]; - delete links[link]; - } - } - } - }, - - /** - Normalize the polymorphic type from the JSON. - - Normalize: - ```js - { - id: "1" - minion: { type: "evil_minion", id: "12"} - } - ``` - - To: - ```js - { - id: "1" - minion: { type: "evilMinion", id: "12"} - } - ``` - - @method normalizeRelationships - @private - */ - normalizeRelationships: function(type, hash) { - - if (this.keyForRelationship) { - type.eachRelationship(function(key, relationship) { - var payloadKey, payload; - if (relationship.options.polymorphic) { - payloadKey = this.keyForAttribute(key); - payload = hash[payloadKey]; - if (payload && payload.type) { - payload.type = this.typeForRoot(payload.type); - } else if (payload && relationship.kind === "hasMany") { - var self = this; - activemodel$adapter$lib$system$active_model_serializer$$forEach(payload, function(single) { - single.type = self.typeForRoot(single.type); - }); - } - } else { - payloadKey = this.keyForRelationship(key, relationship.kind); - if (!hash.hasOwnProperty(payloadKey)) { return; } - payload = hash[payloadKey]; - } - - hash[key] = payload; - - if (key !== payloadKey) { - delete hash[payloadKey]; - } - }, this); - } - } - }); - - var activemodel$adapter$lib$system$active_model_serializer$$default = activemodel$adapter$lib$system$active_model_serializer$$ActiveModelSerializer; - /** - This is used internally to enable deprecation of container paths and provide - a decent message to the user indicating how to fix the issue. - - @class ContainerProxy - @namespace DS - @private - */ - function ember$data$lib$system$container_proxy$$ContainerProxy(container){ - this.container = container; - } - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.aliasedFactory = function(path, preLookup) { - var _this = this; - - return {create: function(){ - if (preLookup) { preLookup(); } - - return _this.container.lookup(path); - }}; - }; - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.registerAlias = function(source, dest, preLookup) { - var factory = this.aliasedFactory(dest, preLookup); - - return this.container.register(source, factory); - }; - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) { - var preLookupCallback = function(){ - }; - - return this.registerAlias(deprecated, valid, preLookupCallback); - }; - - ember$data$lib$system$container_proxy$$ContainerProxy.prototype.registerDeprecations = function(proxyPairs) { - var i, proxyPair, deprecated, valid; - - for (i = proxyPairs.length; i > 0; i--) { - proxyPair = proxyPairs[i - 1]; - deprecated = proxyPair['deprecated']; - valid = proxyPair['valid']; - - this.registerDeprecation(deprecated, valid); - } - }; - - var ember$data$lib$system$container_proxy$$default = ember$data$lib$system$container_proxy$$ContainerProxy; - function activemodel$adapter$lib$setup$container$$setupActiveModelAdapter(container, application){ - var proxy = new ember$data$lib$system$container_proxy$$default(container); - proxy.registerDeprecations([ - { deprecated: 'serializer:_ams', valid: 'serializer:-active-model' }, - { deprecated: 'adapter:_ams', valid: 'adapter:-active-model' } - ]); - - container.register('serializer:-active-model', activemodel$adapter$lib$system$active_model_serializer$$default); - container.register('adapter:-active-model', activemodel$adapter$lib$system$active_model_adapter$$default); - } - var activemodel$adapter$lib$setup$container$$default = activemodel$adapter$lib$setup$container$$setupActiveModelAdapter; - /** - @module ember-data - */ - - /** - All Ember Data methods and functions are defined inside of this namespace. - - @class DS - @static - */ - - /** - @property VERSION - @type String - @default '1.0.0-beta.14.1' - @static - */ - /*jshint -W079 */ - var ember$data$lib$core$$DS = Ember.Namespace.create({ - VERSION: '1.0.0-beta.14.1' - }); - - if (Ember.libraries) { - Ember.libraries.registerCoreLibrary('Ember Data', ember$data$lib$core$$DS.VERSION); - } - - var ember$data$lib$core$$default = ember$data$lib$core$$DS; - var ember$data$lib$system$promise_proxies$$Promise = Ember.RSVP.Promise; - var ember$data$lib$system$promise_proxies$$get = Ember.get; - - /** - A `PromiseArray` is an object that acts like both an `Ember.Array` - and a promise. When the promise is resolved the resulting value - will be set to the `PromiseArray`'s `content` property. This makes - it easy to create data bindings with the `PromiseArray` that will be - updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - var promiseArray = DS.PromiseArray.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseArray.get('length'); // 0 - - promiseArray.then(function() { - promiseArray.get('length'); // 100 - }); - ``` - - @class PromiseArray - @namespace DS - @extends Ember.ArrayProxy - @uses Ember.PromiseProxyMixin - */ - var ember$data$lib$system$promise_proxies$$PromiseArray = Ember.ArrayProxy.extend(Ember.PromiseProxyMixin); - - /** - A `PromiseObject` is an object that acts like both an `Ember.Object` - and a promise. When the promise is resolved, then the resulting value - will be set to the `PromiseObject`'s `content` property. This makes - it easy to create data bindings with the `PromiseObject` that will - be updated when the promise resolves. - - For more information see the [Ember.PromiseProxyMixin - documentation](/api/classes/Ember.PromiseProxyMixin.html). - - Example - - ```javascript - var promiseObject = DS.PromiseObject.create({ - promise: $.getJSON('/some/remote/data.json') - }); - - promiseObject.get('name'); // null - - promiseObject.then(function() { - promiseObject.get('name'); // 'Tomster' - }); - ``` - - @class PromiseObject - @namespace DS - @extends Ember.ObjectProxy - @uses Ember.PromiseProxyMixin - */ - var ember$data$lib$system$promise_proxies$$PromiseObject = Ember.ObjectProxy.extend(Ember.PromiseProxyMixin); - - var ember$data$lib$system$promise_proxies$$promiseObject = function(promise, label) { - return ember$data$lib$system$promise_proxies$$PromiseObject.create({ - promise: ember$data$lib$system$promise_proxies$$Promise.resolve(promise, label) - }); - }; - - var ember$data$lib$system$promise_proxies$$promiseArray = function(promise, label) { - return ember$data$lib$system$promise_proxies$$PromiseArray.create({ - promise: ember$data$lib$system$promise_proxies$$Promise.resolve(promise, label) - }); - }; - - /** - A PromiseManyArray is a PromiseArray that also proxies certain method calls - to the underlying manyArray. - Right now we proxy: - - * `reload()` - * `createRecord()` - * `on()` - * `one()` - * `trigger()` - * `off()` - * `has()` - - @class PromiseManyArray - @namespace DS - @extends Ember.ArrayProxy - */ - - function ember$data$lib$system$promise_proxies$$proxyToContent(method) { - return function() { - var content = ember$data$lib$system$promise_proxies$$get(this, 'content'); - return content[method].apply(content, arguments); - }; - } - - var ember$data$lib$system$promise_proxies$$PromiseManyArray = ember$data$lib$system$promise_proxies$$PromiseArray.extend({ - reload: function() { - //I don't think this should ever happen right now, but worth guarding if we refactor the async relationships - return ember$data$lib$system$promise_proxies$$PromiseManyArray.create({ - promise: ember$data$lib$system$promise_proxies$$get(this, 'content').reload() - }); - }, - - createRecord: ember$data$lib$system$promise_proxies$$proxyToContent('createRecord'), - - on: ember$data$lib$system$promise_proxies$$proxyToContent('on'), - - one: ember$data$lib$system$promise_proxies$$proxyToContent('one'), - - trigger: ember$data$lib$system$promise_proxies$$proxyToContent('trigger'), - - off: ember$data$lib$system$promise_proxies$$proxyToContent('off'), - - has: ember$data$lib$system$promise_proxies$$proxyToContent('has') - }); - - var ember$data$lib$system$promise_proxies$$promiseManyArray = function(promise, label) { - return ember$data$lib$system$promise_proxies$$PromiseManyArray.create({ - promise: ember$data$lib$system$promise_proxies$$Promise.resolve(promise, label) - }); - }; - - - var ember$data$lib$system$record_arrays$record_array$$get = Ember.get; - var ember$data$lib$system$record_arrays$record_array$$set = Ember.set; - - var ember$data$lib$system$record_arrays$record_array$$default = Ember.ArrayProxy.extend(Ember.Evented, { - /** - The model type contained by this record array. - - @property type - @type DS.Model - */ - type: null, - - /** - The array of client ids backing the record array. When a - record is requested from the record array, the record - for the client id at the same index is materialized, if - necessary, by the store. - - @property content - @private - @type Ember.Array - */ - content: null, - - /** - The flag to signal a `RecordArray` is currently loading data. - - Example - - ```javascript - var people = store.all('person'); - people.get('isLoaded'); // true - ``` - - @property isLoaded - @type Boolean - */ - isLoaded: false, - /** - The flag to signal a `RecordArray` is currently loading data. - - Example - - ```javascript - var people = store.all('person'); - people.get('isUpdating'); // false - people.update(); - people.get('isUpdating'); // true - ``` - - @property isUpdating - @type Boolean - */ - isUpdating: false, - - /** - The store that created this record array. - - @property store - @private - @type DS.Store - */ - store: null, - - /** - Retrieves an object from the content by index. - - @method objectAtContent - @private - @param {Number} index - @return {DS.Model} record - */ - objectAtContent: function(index) { - var content = ember$data$lib$system$record_arrays$record_array$$get(this, 'content'); - - return content.objectAt(index); - }, - - /** - Used to get the latest version of all of the records in this array - from the adapter. - - Example - - ```javascript - var people = store.all('person'); - people.get('isUpdating'); // false - people.update(); - people.get('isUpdating'); // true - ``` - - @method update - */ - update: function() { - if (ember$data$lib$system$record_arrays$record_array$$get(this, 'isUpdating')) { return; } - - var store = ember$data$lib$system$record_arrays$record_array$$get(this, 'store'); - var type = ember$data$lib$system$record_arrays$record_array$$get(this, 'type'); - - return store.fetchAll(type, this); - }, - - /** - Adds a record to the `RecordArray` without duplicates - - @method addRecord - @private - @param {DS.Model} record - @param {DS.Model} an optional index to insert at - */ - addRecord: function(record, idx) { - var content = ember$data$lib$system$record_arrays$record_array$$get(this, 'content'); - if (idx === undefined) { - content.addObject(record); - } else { - if (!content.contains(record)) { - content.insertAt(idx, record); - } - } - }, - - /** - Adds a record to the `RecordArray`, but allows duplicates - - @method pushRecord - @private - @param {DS.Model} record - */ - pushRecord: function(record) { - ember$data$lib$system$record_arrays$record_array$$get(this, 'content').pushObject(record); - }, - /** - Removes a record to the `RecordArray`. - - @method removeRecord - @private - @param {DS.Model} record - */ - removeRecord: function(record) { - ember$data$lib$system$record_arrays$record_array$$get(this, 'content').removeObject(record); - }, - - /** - Saves all of the records in the `RecordArray`. - - Example - - ```javascript - var messages = store.all('message'); - messages.forEach(function(message) { - message.set('hasBeenSeen', true); - }); - messages.save(); - ``` - - @method save - @return {DS.PromiseArray} promise - */ - save: function() { - var promiseLabel = "DS: RecordArray#save " + ember$data$lib$system$record_arrays$record_array$$get(this, 'type'); - var promise = Ember.RSVP.all(this.invoke("save"), promiseLabel).then(function(array) { - return Ember.A(array); - }, null, "DS: RecordArray#save apply Ember.NativeArray"); - - return ember$data$lib$system$promise_proxies$$PromiseArray.create({ promise: promise }); - }, - - _dissociateFromOwnRecords: function() { - var array = this; - - this.forEach(function(record){ - var recordArrays = record._recordArrays; - - if (recordArrays) { - recordArrays["delete"](array); - } - }); - }, - - /** - @method _unregisterFromManager - @private - */ - _unregisterFromManager: function(){ - var manager = ember$data$lib$system$record_arrays$record_array$$get(this, 'manager'); - //We will stop needing this stupid if statement soon, once manyArray are refactored to not be RecordArrays - if (manager) { - manager.unregisterFilteredRecordArray(this); - } - }, - - willDestroy: function(){ - this._unregisterFromManager(); - this._dissociateFromOwnRecords(); - ember$data$lib$system$record_arrays$record_array$$set(this, 'content', undefined); - this._super(); - } - }); - - /** - @module ember-data - */ - - var ember$data$lib$system$record_arrays$filtered_record_array$$get = Ember.get; - - var ember$data$lib$system$record_arrays$filtered_record_array$$default = ember$data$lib$system$record_arrays$record_array$$default.extend({ - /** - The filterFunction is a function used to test records from the store to - determine if they should be part of the record array. - - Example - - ```javascript - var allPeople = store.all('person'); - allPeople.mapBy('name'); // ["Tom Dale", "Yehuda Katz", "Trek Glowacki"] - - var people = store.filter('person', function(person) { - if (person.get('name').match(/Katz$/)) { return true; } - }); - people.mapBy('name'); // ["Yehuda Katz"] - - var notKatzFilter = function(person) { - return !person.get('name').match(/Katz$/); - }; - people.set('filterFunction', notKatzFilter); - people.mapBy('name'); // ["Tom Dale", "Trek Glowacki"] - ``` - - @method filterFunction - @param {DS.Model} record - @return {Boolean} `true` if the record should be in the array - */ - filterFunction: null, - isLoaded: true, - - replace: function() { - var type = ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'type').toString(); - throw new Error("The result of a client-side filter (on " + type + ") is immutable."); - }, - - /** - @method updateFilter - @private - */ - _updateFilter: function() { - var manager = ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'manager'); - manager.updateFilter(this, ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'type'), ember$data$lib$system$record_arrays$filtered_record_array$$get(this, 'filterFunction')); - }, - - updateFilter: Ember.observer(function() { - Ember.run.once(this, this._updateFilter); - }, 'filterFunction'), - - }); - - /** - @module ember-data - */ - - var ember$data$lib$system$record_arrays$adapter_populated_record_array$$get = Ember.get; - - function ember$data$lib$system$record_arrays$adapter_populated_record_array$$cloneNull(source) { - var clone = Ember.create(null); - for (var key in source) { - clone[key] = source[key]; - } - return clone; - } - - var ember$data$lib$system$record_arrays$adapter_populated_record_array$$default = ember$data$lib$system$record_arrays$record_array$$default.extend({ - query: null, - - replace: function() { - var type = ember$data$lib$system$record_arrays$adapter_populated_record_array$$get(this, 'type').toString(); - throw new Error("The result of a server query (on " + type + ") is immutable."); - }, - - /** - @method load - @private - @param {Array} data - */ - load: function(data) { - var store = ember$data$lib$system$record_arrays$adapter_populated_record_array$$get(this, 'store'); - var type = ember$data$lib$system$record_arrays$adapter_populated_record_array$$get(this, 'type'); - var records = store.pushMany(type, data); - var meta = store.metadataFor(type); - - this.setProperties({ - content: Ember.A(records), - isLoaded: true, - meta: ember$data$lib$system$record_arrays$adapter_populated_record_array$$cloneNull(meta) - }); - - records.forEach(function(record) { - this.manager.recordArraysForRecord(record).add(this); - }, this); - - // TODO: should triggering didLoad event be the last action of the runLoop? - Ember.run.once(this, 'trigger', 'didLoad'); - } - }); - - /** - @module ember-data - */ - - var ember$data$lib$system$record_arrays$many_array$$get = Ember.get, ember$data$lib$system$record_arrays$many_array$$set = Ember.set; - - var ember$data$lib$system$record_arrays$many_array$$default = Ember.Object.extend(Ember.MutableArray, Ember.Evented, { - init: function() { - this.currentState = Ember.A([]); - this.diff = []; - }, - - record: null, - - canonicalState: null, - currentState: null, - - diff: null, - - length: 0, - - objectAt: function(index) { - if (this.currentState[index]) { - return this.currentState[index]; - } else { - return this.canonicalState[index]; - } - }, - - flushCanonical: function() { - //TODO make this smarter, currently its plenty stupid - var toSet = this.canonicalState.slice(0); - //a hack for not removing new records - //TODO remove once we have proper diffing - var newRecords = this.currentState.filter(function(record) { - return record.get('isNew'); - }); - toSet = toSet.concat(newRecords); - this.arrayContentWillChange(0, this.length, this.length); - this.set('length', toSet.length); - this.currentState = toSet; - this.arrayContentDidChange(0, this.length, this.length); - //TODO Figure out to notify only on additions and maybe only if unloaded - this.relationship.notifyHasManyChanged(); - this.record.updateRecordArrays(); - }, - /** - `true` if the relationship is polymorphic, `false` otherwise. - - @property {Boolean} isPolymorphic - @private - */ - isPolymorphic: false, - - /** - The loading state of this array - - @property {Boolean} isLoaded - */ - isLoaded: false, - - /** - The relationship which manages this array. - - @property {ManyRelationship} relationship - @private - */ - relationship: null, - - internalReplace: function(idx, amt, objects) { - if (!objects) { - objects = []; - } - this.arrayContentWillChange(idx, amt, objects.length); - this.currentState.splice.apply(this.currentState, [idx, amt].concat(objects)); - this.set('length', this.currentState.length); - this.arrayContentDidChange(idx, amt, objects.length); - if (objects){ - //TODO(Igor) probably needed only for unloaded records - this.relationship.notifyHasManyChanged(); - } - this.record.updateRecordArrays(); - }, - - //TODO(Igor) optimize - internalRemoveRecords: function(records) { - var index; - for(var i=0; i < records.length; i++) { - index = this.currentState.indexOf(records[i]); - this.internalReplace(index, 1); - } - }, - - //TODO(Igor) optimize - internalAddRecords: function(records, idx) { - if (idx === undefined) { - idx = this.currentState.length; - } - this.internalReplace(idx, 0, records); - }, - - replace: function(idx, amt, objects) { - var records; - if (amt > 0){ - records = this.currentState.slice(idx, idx+amt); - this.get('relationship').removeRecords(records); - } - if (objects){ - this.get('relationship').addRecords(objects, idx); - } - }, - /** - Used for async `hasMany` arrays - to keep track of when they will resolve. - - @property {Ember.RSVP.Promise} promise - @private - */ - promise: null, - - /** - @method loadingRecordsCount - @param {Number} count - @private - */ - loadingRecordsCount: function(count) { - this.loadingRecordsCount = count; - }, - - /** - @method loadedRecord - @private - */ - loadedRecord: function() { - this.loadingRecordsCount--; - if (this.loadingRecordsCount === 0) { - ember$data$lib$system$record_arrays$many_array$$set(this, 'isLoaded', true); - this.trigger('didLoad'); - } - }, - - /** - @method reload - @public - */ - reload: function() { - return this.relationship.reload(); - }, - - /** - Create a child record within the owner - - @method createRecord - @private - @param {Object} hash - @return {DS.Model} record - */ - createRecord: function(hash) { - var store = ember$data$lib$system$record_arrays$many_array$$get(this, 'store'); - var type = ember$data$lib$system$record_arrays$many_array$$get(this, 'type'); - var record; - - - record = store.createRecord(type, hash); - this.pushObject(record); - - return record; - } - }); - - var ember$data$lib$system$record_array_manager$$get = Ember.get; - var ember$data$lib$system$record_array_manager$$forEach = Ember.EnumerableUtils.forEach; - var ember$data$lib$system$record_array_manager$$indexOf = Ember.EnumerableUtils.indexOf; - - var ember$data$lib$system$record_array_manager$$default = Ember.Object.extend({ - init: function() { - this.filteredRecordArrays = ember$data$lib$system$map$$MapWithDefault.create({ - defaultValue: function() { return []; } - }); - - this.changedRecords = []; - this._adapterPopulatedRecordArrays = []; - }, - - recordDidChange: function(record) { - if (this.changedRecords.push(record) !== 1) { return; } - - Ember.run.schedule('actions', this, this.updateRecordArrays); - }, - - recordArraysForRecord: function(record) { - record._recordArrays = record._recordArrays || ember$data$lib$system$map$$OrderedSet.create(); - return record._recordArrays; - }, - - /** - This method is invoked whenever data is loaded into the store by the - adapter or updated by the adapter, or when a record has changed. - - It updates all record arrays that a record belongs to. - - To avoid thrashing, it only runs at most once per run loop. - - @method updateRecordArrays - @param {Class} type - @param {Number|String} clientId - */ - updateRecordArrays: function() { - ember$data$lib$system$record_array_manager$$forEach(this.changedRecords, function(record) { - if (ember$data$lib$system$record_array_manager$$get(record, 'isDeleted')) { - this._recordWasDeleted(record); - } else { - this._recordWasChanged(record); - } - }, this); - - this.changedRecords.length = 0; - }, - - _recordWasDeleted: function (record) { - var recordArrays = record._recordArrays; - - if (!recordArrays) { return; } - - recordArrays.forEach(function(array){ - array.removeRecord(record); - }); - - record._recordArrays = null; - }, - - _recordWasChanged: function (record) { - var type = record.constructor; - var recordArrays = this.filteredRecordArrays.get(type); - var filter; - - ember$data$lib$system$record_array_manager$$forEach(recordArrays, function(array) { - filter = ember$data$lib$system$record_array_manager$$get(array, 'filterFunction'); - this.updateRecordArray(array, filter, type, record); - }, this); - - // loop through all manyArrays containing an unloaded copy of this - // clientId and notify them that the record was loaded. - var manyArrays = record._loadingRecordArrays; - - if (manyArrays) { - for (var i=0, l=manyArrays.length; i "root.created.uncommitted" - ``` - - The hierarchy of valid states that ship with ember data looks like - this: - - ```text - * root - * deleted - * saved - * uncommitted - * inFlight - * empty - * loaded - * created - * uncommitted - * inFlight - * saved - * updated - * uncommitted - * inFlight - * loading - ``` - - The `DS.Model` states are themselves stateless. What that means is - that, the hierarchical states that each of *those* points to is a - shared data structure. For performance reasons, instead of each - record getting its own copy of the hierarchy of states, each record - points to this global, immutable shared instance. How does a state - know which record it should be acting on? We pass the record - instance into the state's event handlers as the first argument. - - The record passed as the first parameter is where you should stash - state about the record if needed; you should never store data on the state - object itself. - - ### Events and Flags - - A state may implement zero or more events and flags. - - #### Events - - Events are named functions that are invoked when sent to a record. The - record will first look for a method with the given name on the - current state. If no method is found, it will search the current - state's parent, and then its grandparent, and so on until reaching - the top of the hierarchy. If the root is reached without an event - handler being found, an exception will be raised. This can be very - helpful when debugging new features. - - Here's an example implementation of a state with a `myEvent` event handler: - - ```javascript - aState: DS.State.create({ - myEvent: function(manager, param) { - console.log("Received myEvent with", param); - } - }) - ``` - - To trigger this event: - - ```javascript - record.send('myEvent', 'foo'); - //=> "Received myEvent with foo" - ``` - - Note that an optional parameter can be sent to a record's `send()` method, - which will be passed as the second parameter to the event handler. - - Events should transition to a different state if appropriate. This can be - done by calling the record's `transitionTo()` method with a path to the - desired state. The state manager will attempt to resolve the state path - relative to the current state. If no state is found at that path, it will - attempt to resolve it relative to the current state's parent, and then its - parent, and so on until the root is reached. For example, imagine a hierarchy - like this: - - * created - * uncommitted <-- currentState - * inFlight - * updated - * inFlight - - If we are currently in the `uncommitted` state, calling - `transitionTo('inFlight')` would transition to the `created.inFlight` state, - while calling `transitionTo('updated.inFlight')` would transition to - the `updated.inFlight` state. - - Remember that *only events* should ever cause a state transition. You should - never call `transitionTo()` from outside a state's event handler. If you are - tempted to do so, create a new event and send that to the state manager. - - #### Flags - - Flags are Boolean values that can be used to introspect a record's current - state in a more user-friendly way than examining its state path. For example, - instead of doing this: - - ```javascript - var statePath = record.get('stateManager.currentPath'); - if (statePath === 'created.inFlight') { - doSomething(); - } - ``` - - You can say: - - ```javascript - if (record.get('isNew') && record.get('isSaving')) { - doSomething(); - } - ``` - - If your state does not set a value for a given flag, the value will - be inherited from its parent (or the first place in the state hierarchy - where it is defined). - - The current set of flags are defined below. If you want to add a new flag, - in addition to the area below, you will also need to declare it in the - `DS.Model` class. - - - * [isEmpty](DS.Model.html#property_isEmpty) - * [isLoading](DS.Model.html#property_isLoading) - * [isLoaded](DS.Model.html#property_isLoaded) - * [isDirty](DS.Model.html#property_isDirty) - * [isSaving](DS.Model.html#property_isSaving) - * [isDeleted](DS.Model.html#property_isDeleted) - * [isNew](DS.Model.html#property_isNew) - * [isValid](DS.Model.html#property_isValid) - - @namespace DS - @class RootState - */ - - function ember$data$lib$system$model$states$$didSetProperty(record, context) { - if (context.value === context.originalValue) { - delete record._attributes[context.name]; - record.send('propertyWasReset', context.name); - } else if (context.value !== context.oldValue) { - record.send('becomeDirty'); - } - - record.updateRecordArraysLater(); - } - - // Implementation notes: - // - // Each state has a boolean value for all of the following flags: - // - // * isLoaded: The record has a populated `data` property. When a - // record is loaded via `store.find`, `isLoaded` is false - // until the adapter sets it. When a record is created locally, - // its `isLoaded` property is always true. - // * isDirty: The record has local changes that have not yet been - // saved by the adapter. This includes records that have been - // created (but not yet saved) or deleted. - // * isSaving: The record has been committed, but - // the adapter has not yet acknowledged that the changes have - // been persisted to the backend. - // * isDeleted: The record was marked for deletion. When `isDeleted` - // is true and `isDirty` is true, the record is deleted locally - // but the deletion was not yet persisted. When `isSaving` is - // true, the change is in-flight. When both `isDirty` and - // `isSaving` are false, the change has persisted. - // * isError: The adapter reported that it was unable to save - // local changes to the backend. This may also result in the - // record having its `isValid` property become false if the - // adapter reported that server-side validations failed. - // * isNew: The record was created on the client and the adapter - // did not yet report that it was successfully saved. - // * isValid: The adapter did not report any server-side validation - // failures. - - // The dirty state is a abstract state whose functionality is - // shared between the `created` and `updated` states. - // - // The deleted state shares the `isDirty` flag with the - // subclasses of `DirtyState`, but with a very different - // implementation. - // - // Dirty states have three child states: - // - // `uncommitted`: the store has not yet handed off the record - // to be saved. - // `inFlight`: the store has handed off the record to be saved, - // but the adapter has not yet acknowledged success. - // `invalid`: the record has invalid information and cannot be - // send to the adapter yet. - var ember$data$lib$system$model$states$$DirtyState = { - initialState: 'uncommitted', - - // FLAGS - isDirty: true, - - // SUBSTATES - - // When a record first becomes dirty, it is `uncommitted`. - // This means that there are local pending changes, but they - // have not yet begun to be saved, and are not invalid. - uncommitted: { - // EVENTS - didSetProperty: ember$data$lib$system$model$states$$didSetProperty, - - //TODO(Igor) reloading now triggers a - //loadingData event, though it seems fine? - loadingData: Ember.K, - - propertyWasReset: function(record, name) { - var length = Ember.keys(record._attributes).length; - var stillDirty = length > 0; - - if (!stillDirty) { record.send('rolledBack'); } - }, - - pushedData: Ember.K, - - becomeDirty: Ember.K, - - willCommit: function(record) { - record.transitionTo('inFlight'); - }, - - reloadRecord: function(record, resolve) { - resolve(ember$data$lib$system$model$states$$get(record, 'store').reloadRecord(record)); - }, - - rolledBack: function(record) { - record.transitionTo('loaded.saved'); - }, - - becameInvalid: function(record) { - record.transitionTo('invalid'); - }, - - rollback: function(record) { - record.rollback(); - } - }, - - // Once a record has been handed off to the adapter to be - // saved, it is in the 'in flight' state. Changes to the - // record cannot be made during this window. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - didSetProperty: ember$data$lib$system$model$states$$didSetProperty, - becomeDirty: Ember.K, - pushedData: Ember.K, - - unloadRecord: function(record) { - }, - - // TODO: More robust semantics around save-while-in-flight - willCommit: Ember.K, - - didCommit: function(record) { - var dirtyType = ember$data$lib$system$model$states$$get(this, 'dirtyType'); - - record.transitionTo('saved'); - record.send('invokeLifecycleCallbacks', dirtyType); - }, - - becameInvalid: function(record) { - record.transitionTo('invalid'); - record.send('invokeLifecycleCallbacks'); - }, - - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); - } - }, - - // A record is in the `invalid` if the adapter has indicated - // the the record failed server-side invalidations. - invalid: { - // FLAGS - isValid: false, - - // EVENTS - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); - }, - - didSetProperty: function(record, context) { - ember$data$lib$system$model$states$$get(record, 'errors').remove(context.name); - - ember$data$lib$system$model$states$$didSetProperty(record, context); - }, - - becomeDirty: Ember.K, - - willCommit: function(record) { - ember$data$lib$system$model$states$$get(record, 'errors').clear(); - record.transitionTo('inFlight'); - }, - - rolledBack: function(record) { - ember$data$lib$system$model$states$$get(record, 'errors').clear(); - }, - - becameValid: function(record) { - record.transitionTo('uncommitted'); - }, - - invokeLifecycleCallbacks: function(record) { - record.triggerLater('becameInvalid', record); - }, - - exit: function(record) { - record._inFlightAttributes = {}; - } - } - }; - - // The created and updated states are created outside the state - // chart so we can reopen their substates and add mixins as - // necessary. - - function ember$data$lib$system$model$states$$deepClone(object) { - var clone = {}, value; - - for (var prop in object) { - value = object[prop]; - if (value && typeof value === 'object') { - clone[prop] = ember$data$lib$system$model$states$$deepClone(value); - } else { - clone[prop] = value; - } - } - - return clone; - } - - function ember$data$lib$system$model$states$$mixin(original, hash) { - for (var prop in hash) { - original[prop] = hash[prop]; - } - - return original; - } - - function ember$data$lib$system$model$states$$dirtyState(options) { - var newState = ember$data$lib$system$model$states$$deepClone(ember$data$lib$system$model$states$$DirtyState); - return ember$data$lib$system$model$states$$mixin(newState, options); - } - - var ember$data$lib$system$model$states$$createdState = ember$data$lib$system$model$states$$dirtyState({ - dirtyType: 'created', - // FLAGS - isNew: true - }); - - ember$data$lib$system$model$states$$createdState.uncommitted.rolledBack = function(record) { - record.transitionTo('deleted.saved'); - }; - - var ember$data$lib$system$model$states$$updatedState = ember$data$lib$system$model$states$$dirtyState({ - dirtyType: 'updated' - }); - - ember$data$lib$system$model$states$$createdState.uncommitted.deleteRecord = function(record) { - record.disconnectRelationships(); - record.transitionTo('deleted.saved'); - }; - - ember$data$lib$system$model$states$$createdState.uncommitted.rollback = function(record) { - ember$data$lib$system$model$states$$DirtyState.uncommitted.rollback.apply(this, arguments); - record.transitionTo('deleted.saved'); - }; - - ember$data$lib$system$model$states$$createdState.uncommitted.propertyWasReset = Ember.K; - - function ember$data$lib$system$model$states$$assertAgainstUnloadRecord(record) { - } - - ember$data$lib$system$model$states$$updatedState.inFlight.unloadRecord = ember$data$lib$system$model$states$$assertAgainstUnloadRecord; - - ember$data$lib$system$model$states$$updatedState.uncommitted.deleteRecord = function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); - }; - - var ember$data$lib$system$model$states$$RootState = { - // FLAGS - isEmpty: false, - isLoading: false, - isLoaded: false, - isDirty: false, - isSaving: false, - isDeleted: false, - isNew: false, - isValid: true, - - // DEFAULT EVENTS - - // Trying to roll back if you're not in the dirty state - // doesn't change your state. For example, if you're in the - // in-flight state, rolling back the record doesn't move - // you out of the in-flight state. - rolledBack: Ember.K, - unloadRecord: function(record) { - // clear relationships before moving to deleted state - // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); - }, - - - propertyWasReset: Ember.K, - - // SUBSTATES - - // A record begins its lifecycle in the `empty` state. - // If its data will come from the adapter, it will - // transition into the `loading` state. Otherwise, if - // the record is being created on the client, it will - // transition into the `created` state. - empty: { - isEmpty: true, - - // EVENTS - loadingData: function(record, promise) { - record._loadingPromise = promise; - record.transitionTo('loading'); - }, - - loadedData: function(record) { - record.transitionTo('loaded.created.uncommitted'); - }, - - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - } - }, - - // A record enters this state when the store asks - // the adapter for its data. It remains in this state - // until the adapter provides the requested data. - // - // Usually, this process is asynchronous, using an - // XHR to retrieve the data. - loading: { - // FLAGS - isLoading: true, - - exit: function(record) { - record._loadingPromise = null; - }, - - // EVENTS - pushedData: function(record) { - record.transitionTo('loaded.saved'); - record.triggerLater('didLoad'); - ember$data$lib$system$model$states$$set(record, 'isError', false); - }, - - becameError: function(record) { - record.triggerLater('becameError', record); - }, - - notFound: function(record) { - record.transitionTo('empty'); - } - }, - - // A record enters this state when its data is populated. - // Most of a record's lifecycle is spent inside substates - // of the `loaded` state. - loaded: { - initialState: 'saved', - - // FLAGS - isLoaded: true, - - //TODO(Igor) Reloading now triggers a loadingData event, - //but it should be ok? - loadingData: Ember.K, - - // SUBSTATES - - // If there are no local changes to a record, it remains - // in the `saved` state. - saved: { - setup: function(record) { - var attrs = record._attributes; - var isDirty = Ember.keys(attrs).length > 0; - - if (isDirty) { - record.adapterDidDirty(); - } - }, - - // EVENTS - didSetProperty: ember$data$lib$system$model$states$$didSetProperty, - - pushedData: Ember.K, - - becomeDirty: function(record) { - record.transitionTo('updated.uncommitted'); - }, - - willCommit: function(record) { - record.transitionTo('updated.inFlight'); - }, - - reloadRecord: function(record, resolve) { - resolve(ember$data$lib$system$model$states$$get(record, 'store').reloadRecord(record)); - }, - - deleteRecord: function(record) { - record.transitionTo('deleted.uncommitted'); - record.disconnectRelationships(); - }, - - unloadRecord: function(record) { - // clear relationships before moving to deleted state - // otherwise it fails - record.clearRelationships(); - record.transitionTo('deleted.saved'); - }, - - didCommit: function(record) { - record.send('invokeLifecycleCallbacks', ember$data$lib$system$model$states$$get(record, 'lastDirtyType')); - }, - - // loaded.saved.notFound would be triggered by a failed - // `reload()` on an unchanged record - notFound: Ember.K - - }, - - // A record is in this state after it has been locally - // created but before the adapter has indicated that - // it has been saved. - created: ember$data$lib$system$model$states$$createdState, - - // A record is in this state if it has already been - // saved to the server, but there are new local changes - // that have not yet been saved. - updated: ember$data$lib$system$model$states$$updatedState - }, - - // A record is in this state if it was deleted from the store. - deleted: { - initialState: 'uncommitted', - dirtyType: 'deleted', - - // FLAGS - isDeleted: true, - isLoaded: true, - isDirty: true, - - // TRANSITIONS - setup: function(record) { - record.updateRecordArrays(); - }, - - // SUBSTATES - - // When a record is deleted, it enters the `start` - // state. It will exit this state when the record - // starts to commit. - uncommitted: { - - // EVENTS - - willCommit: function(record) { - record.transitionTo('inFlight'); - }, - - rollback: function(record) { - record.rollback(); - }, - - becomeDirty: Ember.K, - deleteRecord: Ember.K, - - rolledBack: function(record) { - record.transitionTo('loaded.saved'); - } - }, - - // After a record starts committing, but - // before the adapter indicates that the deletion - // has saved to the server, a record is in the - // `inFlight` substate of `deleted`. - inFlight: { - // FLAGS - isSaving: true, - - // EVENTS - - unloadRecord: ember$data$lib$system$model$states$$assertAgainstUnloadRecord, - - // TODO: More robust semantics around save-while-in-flight - willCommit: Ember.K, - didCommit: function(record) { - record.transitionTo('saved'); - - record.send('invokeLifecycleCallbacks'); - }, - - becameError: function(record) { - record.transitionTo('uncommitted'); - record.triggerLater('becameError', record); - } - }, - - // Once the adapter indicates that the deletion has - // been saved, the record enters the `saved` substate - // of `deleted`. - saved: { - // FLAGS - isDirty: false, - - setup: function(record) { - var store = ember$data$lib$system$model$states$$get(record, 'store'); - store.dematerializeRecord(record); - }, - - invokeLifecycleCallbacks: function(record) { - record.triggerLater('didDelete', record); - record.triggerLater('didCommit', record); - }, - - willCommit: Ember.K, - - didCommit: Ember.K - } - }, - - invokeLifecycleCallbacks: function(record, dirtyType) { - if (dirtyType === 'created') { - record.triggerLater('didCreate', record); - } else { - record.triggerLater('didUpdate', record); - } - - record.triggerLater('didCommit', record); - } - }; - - function ember$data$lib$system$model$states$$wireState(object, parent, name) { - /*jshint proto:true*/ - // TODO: Use Object.create and copy instead - object = ember$data$lib$system$model$states$$mixin(parent ? Ember.create(parent) : {}, object); - object.parentState = parent; - object.stateName = name; - - for (var prop in object) { - if (!object.hasOwnProperty(prop) || prop === 'parentState' || prop === 'stateName') { continue; } - if (typeof object[prop] === 'object') { - object[prop] = ember$data$lib$system$model$states$$wireState(object[prop], object, name + "." + prop); - } - } - - return object; - } - - ember$data$lib$system$model$states$$RootState = ember$data$lib$system$model$states$$wireState(ember$data$lib$system$model$states$$RootState, null, "root"); - - var ember$data$lib$system$model$states$$default = ember$data$lib$system$model$states$$RootState; - var ember$data$lib$system$model$errors$$get = Ember.get; - var ember$data$lib$system$model$errors$$isEmpty = Ember.isEmpty; - var ember$data$lib$system$model$errors$$map = Ember.EnumerableUtils.map; - - var ember$data$lib$system$model$errors$$default = Ember.Object.extend(Ember.Enumerable, Ember.Evented, { - /** - Register with target handler - - @method registerHandlers - @param {Object} target - @param {Function} becameInvalid - @param {Function} becameValid - */ - registerHandlers: function(target, becameInvalid, becameValid) { - this.on('becameInvalid', target, becameInvalid); - this.on('becameValid', target, becameValid); - }, - - /** - @property errorsByAttributeName - @type {Ember.MapWithDefault} - @private - */ - errorsByAttributeName: Ember.reduceComputed("content", { - initialValue: function() { - return ember$data$lib$system$map$$MapWithDefault.create({ - defaultValue: function() { - return Ember.A(); - } - }); - }, - - addedItem: function(errors, error) { - errors.get(error.attribute).pushObject(error); - - return errors; - }, - - removedItem: function(errors, error) { - errors.get(error.attribute).removeObject(error); - - return errors; - } - }), - - /** - Returns errors for a given attribute - - ```javascript - var user = store.createRecord('user', { - username: 'tomster', - email: 'invalidEmail' - }); - user.save().catch(function(){ - user.get('errors').errorsFor('email'); // returns: - // [{attribute: "email", message: "Doesn't look like a valid email."}] - }); - ``` - - @method errorsFor - @param {String} attribute - @return {Array} - */ - errorsFor: function(attribute) { - return ember$data$lib$system$model$errors$$get(this, 'errorsByAttributeName').get(attribute); - }, - - /** - An array containing all of the error messages for this - record. This is useful for displaying all errors to the user. - - ```handlebars - {{#each message in errors.messages}} -
    - {{message}} -
    - {{/each}} - ``` - - @property messages - @type {Array} - */ - messages: Ember.computed.mapBy('content', 'message'), - - /** - @property content - @type {Array} - @private - */ - content: Ember.computed(function() { - return Ember.A(); - }), - - /** - @method unknownProperty - @private - */ - unknownProperty: function(attribute) { - var errors = this.errorsFor(attribute); - if (ember$data$lib$system$model$errors$$isEmpty(errors)) { return null; } - return errors; - }, - - /** - @method nextObject - @private - */ - nextObject: function(index, previousObject, context) { - return ember$data$lib$system$model$errors$$get(this, 'content').objectAt(index); - }, - - /** - Total number of errors. - - @property length - @type {Number} - @readOnly - */ - length: Ember.computed.oneWay('content.length').readOnly(), - - /** - @property isEmpty - @type {Boolean} - @readOnly - */ - isEmpty: Ember.computed.not('length').readOnly(), - - /** - Adds error messages to a given attribute and sends - `becameInvalid` event to the record. - - Example: - - ```javascript - if (!user.get('username') { - user.get('errors').add('username', 'This field is required'); - } - ``` - - @method add - @param {String} attribute - @param {Array|String} messages - */ - add: function(attribute, messages) { - var wasEmpty = ember$data$lib$system$model$errors$$get(this, 'isEmpty'); - - messages = this._findOrCreateMessages(attribute, messages); - ember$data$lib$system$model$errors$$get(this, 'content').addObjects(messages); - - this.notifyPropertyChange(attribute); - this.enumerableContentDidChange(); - - if (wasEmpty && !ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { - this.trigger('becameInvalid'); - } - }, - - /** - @method _findOrCreateMessages - @private - */ - _findOrCreateMessages: function(attribute, messages) { - var errors = this.errorsFor(attribute); - - return ember$data$lib$system$model$errors$$map(Ember.makeArray(messages), function(message) { - return errors.findBy('message', message) || { - attribute: attribute, - message: message - }; - }); - }, - - /** - Removes all error messages from the given attribute and sends - `becameValid` event to the record if there no more errors left. - - Example: - - ```javascript - App.User = DS.Model.extend({ - email: DS.attr('string'), - twoFactorAuth: DS.attr('boolean'), - phone: DS.attr('string') - }); - - App.UserEditRoute = Ember.Route.extend({ - actions: { - save: function(user) { - if (!user.get('twoFactorAuth')) { - user.get('errors').remove('phone'); - } - user.save(); - } - } - }); - ``` - - @method remove - @param {String} attribute - */ - remove: function(attribute) { - if (ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { return; } - - var content = ember$data$lib$system$model$errors$$get(this, 'content').rejectBy('attribute', attribute); - ember$data$lib$system$model$errors$$get(this, 'content').setObjects(content); - - this.notifyPropertyChange(attribute); - this.enumerableContentDidChange(); - - if (ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { - this.trigger('becameValid'); - } - }, - - /** - Removes all error messages and sends `becameValid` event - to the record. - - Example: - - ```javascript - App.UserEditRoute = Ember.Route.extend({ - actions: { - retrySave: function(user) { - user.get('errors').clear(); - user.save(); - } - } - }); - ``` - - @method clear - */ - clear: function() { - if (ember$data$lib$system$model$errors$$get(this, 'isEmpty')) { return; } - - ember$data$lib$system$model$errors$$get(this, 'content').clear(); - this.enumerableContentDidChange(); - - this.trigger('becameValid'); - }, - - /** - Checks if there is error messages for the given attribute. - - ```javascript - App.UserEditRoute = Ember.Route.extend({ - actions: { - save: function(user) { - if (user.get('errors').has('email')) { - return alert('Please update your email before attempting to save.'); - } - user.save(); - } - } - }); - ``` - - @method has - @param {String} attribute - @return {Boolean} true if there some errors on given attribute - */ - has: function(attribute) { - return !ember$data$lib$system$model$errors$$isEmpty(this.errorsFor(attribute)); - } - }); - - function ember$data$lib$system$merge$$merge(original, updates) { - if (!updates || typeof updates !== 'object') { - return original; - } - - var props = Ember.keys(updates); - var prop; - var length = props.length; - - for (var i = 0; i < length; i++) { - prop = props[i]; - original[prop] = updates[prop]; - } - - return original; - } - - var ember$data$lib$system$merge$$default = ember$data$lib$system$merge$$merge; - - var ember$data$lib$system$relationships$state$relationship$$forEach = Ember.EnumerableUtils.forEach; - - var ember$data$lib$system$relationships$state$relationship$$Relationship = function(store, record, inverseKey, relationshipMeta) { - this.members = new ember$data$lib$system$map$$OrderedSet(); - this.canonicalMembers = new ember$data$lib$system$map$$OrderedSet(); - this.store = store; - this.key = relationshipMeta.key; - this.inverseKey = inverseKey; - this.record = record; - this.isAsync = relationshipMeta.options.async; - this.relationshipMeta = relationshipMeta; - //This probably breaks for polymorphic relationship in complex scenarios, due to - //multiple possible typeKeys - this.inverseKeyForImplicit = this.store.modelFor(this.record.constructor).typeKey + this.key; - this.linkPromise = null; - }; - - ember$data$lib$system$relationships$state$relationship$$Relationship.prototype = { - constructor: ember$data$lib$system$relationships$state$relationship$$Relationship, - - destroy: Ember.K, - - clear: function() { - var members = this.members.list; - var member; - - while (members.length > 0){ - member = members[0]; - this.removeRecord(member); - } - }, - - disconnect: function(){ - this.members.forEach(function(member) { - this.removeRecordFromInverse(member); - }, this); - }, - - reconnect: function(){ - this.members.forEach(function(member) { - this.addRecordToInverse(member); - }, this); - }, - - removeRecords: function(records){ - var self = this; - ember$data$lib$system$relationships$state$relationship$$forEach(records, function(record){ - self.removeRecord(record); - }); - }, - - addRecords: function(records, idx){ - var self = this; - ember$data$lib$system$relationships$state$relationship$$forEach(records, function(record){ - self.addRecord(record, idx); - if (idx !== undefined) { - idx++; - } - }); - }, - - addCanonicalRecords: function(records, idx) { - for (var i=0; i -1) { - this.canonicalState.splice(i, 1); - } - this._super$removeCanonicalRecordFromOwn(record, idx); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype._super$flushCanonical = ember$data$lib$system$relationships$state$relationship$$default.prototype.flushCanonical; - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.flushCanonical = function() { - this.manyArray.flushCanonical(); - this._super$flushCanonical(); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype._super$removeRecordFromOwn = ember$data$lib$system$relationships$state$relationship$$default.prototype.removeRecordFromOwn; - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { - if (!this.members.has(record)) { - return; - } - this._super$removeRecordFromOwn(record, idx); - if (idx !== undefined) { - //TODO(Igor) not used currently, fix - this.manyArray.currentState.removeAt(idx); - } else { - this.manyArray.internalRemoveRecords([record]); - } - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - var type = this.relationshipMeta.type; - - this.record.notifyHasManyAdded(this.key, record, idx); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.reload = function() { - var self = this; - if (this.link) { - return this.fetchLink(); - } else { - return this.store.scheduleFetchMany(this.manyArray.toArray()).then(function() { - //Goes away after the manyArray refactor - self.manyArray.set('isLoaded', true); - return self.manyArray; - }); - } - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.computeChanges = function(records) { - var members = this.canonicalMembers; - var recordsToRemove = []; - var length; - var record; - var i; - - records = ember$data$lib$system$relationships$state$has_many$$setForArray(records); - - members.forEach(function(member) { - if (records.has(member)) return; - - recordsToRemove.push(member); - }); - - this.removeCanonicalRecords(recordsToRemove); - - var hasManyArray = this.manyArray; - - // Using records.toArray() since currently using - // removeRecord can modify length, messing stuff up - // forEach since it directly looks at "length" each - // iteration - records = records.toArray(); - length = records.length; - for (i = 0; i < length; i++){ - record = records[i]; - //Need to preserve the order of incoming records - if (hasManyArray.objectAt(i) === record ) { - continue; - } - this.removeCanonicalRecord(record); - this.addCanonicalRecord(record, i); - } - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.fetchLink = function() { - var self = this; - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then(function(records){ - self.updateRecordsFromAdapter(records); - return self.manyArray; - }); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.findRecords = function() { - var manyArray = this.manyArray; - return this.store.findMany(manyArray.toArray()).then(function(){ - //Goes away after the manyArray refactor - manyArray.set('isLoaded', true); - return manyArray; - }); - }; - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.notifyHasManyChanged = function() { - this.record.notifyHasManyAdded(this.key); - }; - - ember$data$lib$system$relationships$state$has_many$$ManyRelationship.prototype.getRecords = function() { - //TODO(Igor) sync server here, once our syncing is not stupid - if (this.isAsync) { - var self = this; - var promise; - if (this.link) { - promise = this.findLink().then(function() { - return self.findRecords(); - }); - } else { - promise = this.findRecords(); - } - return ember$data$lib$system$promise_proxies$$PromiseManyArray.create({ - content: this.manyArray, - promise: promise - }); - } else { - - //TODO(Igor) WTF DO I DO HERE? - if (!this.manyArray.get('isDestroyed')) { - this.manyArray.set('isLoaded', true); - } - return this.manyArray; - } - }; - - function ember$data$lib$system$relationships$state$has_many$$setForArray(array) { - var set = new ember$data$lib$system$map$$OrderedSet(); - - if (array) { - for (var i=0, l=array.length; i 1) { - var oldValue = ember$data$lib$system$model$attributes$$getValue(this, key); - - if (value !== oldValue) { - // Add the new value to the changed attributes hash; it will get deleted by - // the 'didSetProperty' handler if it is no different from the original value - this._attributes[key] = value; - - this.send('didSetProperty', { - name: key, - oldValue: oldValue, - originalValue: this._data[key], - value: value - }); - } - - return value; - } else if (ember$data$lib$system$model$attributes$$hasValue(this, key)) { - return ember$data$lib$system$model$attributes$$getValue(this, key); - } else { - return ember$data$lib$system$model$attributes$$getDefaultValue(this, options, key); - } - - // `data` is never set directly. However, it may be - // invalidated from the state manager's setData - // event. - }).meta(meta); - } - var ember$data$lib$system$model$attributes$$default = ember$data$lib$system$model$attributes$$attr; - //Stanley told me to do this - var ember$data$lib$system$store$$Backburner = Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner']; - - //Shim Backburner.join - if (!ember$data$lib$system$store$$Backburner.prototype.join) { - var ember$data$lib$system$store$$isString = function(suspect) { - return typeof suspect === 'string'; - }; - - ember$data$lib$system$store$$Backburner.prototype.join = function(/*target, method, args */) { - var method, target; - - if (this.currentInstance) { - var length = arguments.length; - if (length === 1) { - method = arguments[0]; - target = null; - } else { - target = arguments[0]; - method = arguments[1]; - } - - if (ember$data$lib$system$store$$isString(method)) { - method = target[method]; - } - - if (length === 1) { - return method(); - } else if (length === 2) { - return method.call(target); - } else { - var args = new Array(length - 2); - for (var i =0, l = length - 2; i < l; i++) { - args[i] = arguments[i + 2]; - } - return method.apply(target, args); - } - } else { - return this.run.apply(this, arguments); - } - }; - } - - - var ember$data$lib$system$store$$get = Ember.get; - var ember$data$lib$system$store$$set = Ember.set; - var ember$data$lib$system$store$$once = Ember.run.once; - var ember$data$lib$system$store$$isNone = Ember.isNone; - var ember$data$lib$system$store$$forEach = Ember.EnumerableUtils.forEach; - var ember$data$lib$system$store$$indexOf = Ember.EnumerableUtils.indexOf; - var ember$data$lib$system$store$$map = Ember.EnumerableUtils.map; - var ember$data$lib$system$store$$Promise = Ember.RSVP.Promise; - var ember$data$lib$system$store$$copy = Ember.copy; - var ember$data$lib$system$store$$Store; - - var ember$data$lib$system$store$$camelize = Ember.String.camelize; - - // Implementors Note: - // - // The variables in this file are consistently named according to the following - // scheme: - // - // * +id+ means an identifier managed by an external source, provided inside - // the data provided by that source. These are always coerced to be strings - // before being used internally. - // * +clientId+ means a transient numerical identifier generated at runtime by - // the data store. It is important primarily because newly created objects may - // not yet have an externally generated id. - // * +reference+ means a record reference object, which holds metadata about a - // record, even if it has not yet been fully materialized. - // * +type+ means a subclass of DS.Model. - - // Used by the store to normalize IDs entering the store. Despite the fact - // that developers may provide IDs as numbers (e.g., `store.find(Person, 1)`), - // it is important that internally we use strings, since IDs may be serialized - // and lose type information. For example, Ember's router may put a record's - // ID into the URL, and if we later try to deserialize that URL and find the - // corresponding record, we will not know if it is a string or a number. - function ember$data$lib$system$store$$coerceId(id) { - return id == null ? null : id+''; - } - - /** - The store contains all of the data for records loaded from the server. - It is also responsible for creating instances of `DS.Model` that wrap - the individual data for a record, so that they can be bound to in your - Handlebars templates. - - Define your application's store like this: - - ```javascript - MyApp.Store = DS.Store.extend(); - ``` - - Most Ember.js applications will only have a single `DS.Store` that is - automatically created by their `Ember.Application`. - - You can retrieve models from the store in several ways. To retrieve a record - for a specific id, use `DS.Store`'s `find()` method: - - ```javascript - store.find('person', 123).then(function (person) { - }); - ``` - - By default, the store will talk to your backend using a standard - REST mechanism. You can customize how the store talks to your - backend by specifying a custom adapter: - - ```javascript - MyApp.ApplicationAdapter = MyApp.CustomAdapter - ``` - - You can learn more about writing a custom adapter by reading the `DS.Adapter` - documentation. - - ### Store createRecord() vs. push() vs. pushPayload() - - The store provides multiple ways to create new record objects. They have - some subtle differences in their use which are detailed below: - - [createRecord](#method_createRecord) is used for creating new - records on the client side. This will return a new record in the - `created.uncommitted` state. In order to persist this record to the - backend you will need to call `record.save()`. - - [push](#method_push) is used to notify Ember Data's store of new or - updated records that exist in the backend. This will return a record - in the `loaded.saved` state. The primary use-case for `store#push` is - to notify Ember Data about record updates (full or partial) that happen - outside of the normal adapter methods (for example - [SSE](http://dev.w3.org/html5/eventsource/) or [Web - Sockets](http://www.w3.org/TR/2009/WD-websockets-20091222/)). - - [pushPayload](#method_pushPayload) is a convenience wrapper for - `store#push` that will deserialize payloads if the - Serializer implements a `pushPayload` method. - - Note: When creating a new record using any of the above methods - Ember Data will update `DS.RecordArray`s such as those returned by - `store#all()`, `store#findAll()` or `store#filter()`. This means any - data bindings or computed properties that depend on the RecordArray - will automatically be synced to include the new or updated record - values. - - @class Store - @namespace DS - @extends Ember.Object - */ - ember$data$lib$system$store$$Store = Ember.Object.extend({ - - /** - @method init - @private - */ - init: function() { - this._backburner = new ember$data$lib$system$store$$Backburner(['normalizeRelationships', 'syncRelationships', 'finished']); - // internal bookkeeping; not observable - this.typeMaps = {}; - this.recordArrayManager = ember$data$lib$system$record_array_manager$$default.create({ - store: this - }); - this._pendingSave = []; - //Used to keep track of all the find requests that need to be coalesced - this._pendingFetch = ember$data$lib$system$map$$Map.create(); - }, - - /** - The adapter to use to communicate to a backend server or other persistence layer. - - This can be specified as an instance, class, or string. - - If you want to specify `App.CustomAdapter` as a string, do: - - ```js - adapter: 'custom' - ``` - - @property adapter - @default DS.RESTAdapter - @type {DS.Adapter|String} - */ - adapter: '-rest', - - /** - Returns a JSON representation of the record using a custom - type-specific serializer, if one exists. - - The available options are: - - * `includeId`: `true` if the record's ID should be included in - the JSON representation - - @method serialize - @private - @param {DS.Model} record the record to serialize - @param {Object} options an options hash - */ - serialize: function(record, options) { - return this.serializerFor(record.constructor.typeKey).serialize(record, options); - }, - - /** - This property returns the adapter, after resolving a possible - string key. - - If the supplied `adapter` was a class, or a String property - path resolved to a class, this property will instantiate the - class. - - This property is cacheable, so the same instance of a specified - adapter class should be used for the lifetime of the store. - - @property defaultAdapter - @private - @return DS.Adapter - */ - defaultAdapter: Ember.computed('adapter', function() { - var adapter = ember$data$lib$system$store$$get(this, 'adapter'); - - - if (typeof adapter === 'string') { - adapter = this.container.lookup('adapter:' + adapter) || this.container.lookup('adapter:application') || this.container.lookup('adapter:-rest'); - } - - if (DS.Adapter.detect(adapter)) { - adapter = adapter.create({ - container: this.container - }); - } - - return adapter; - }), - - // ..................... - // . CREATE NEW RECORD . - // ..................... - - /** - Create a new record in the current store. The properties passed - to this method are set on the newly created record. - - To create a new instance of `App.Post`: - - ```js - store.createRecord('post', { - title: "Rails is omakase" - }); - ``` - - @method createRecord - @param {String} type - @param {Object} properties a hash of properties to set on the - newly created record. - @return {DS.Model} record - */ - createRecord: function(typeName, inputProperties) { - var type = this.modelFor(typeName); - var properties = ember$data$lib$system$store$$copy(inputProperties) || {}; - - // If the passed properties do not include a primary key, - // give the adapter an opportunity to generate one. Typically, - // client-side ID generators will use something like uuid.js - // to avoid conflicts. - - if (ember$data$lib$system$store$$isNone(properties.id)) { - properties.id = this._generateId(type); - } - - // Coerce ID to a string - properties.id = ember$data$lib$system$store$$coerceId(properties.id); - - var record = this.buildRecord(type, properties.id); - - // Move the record out of its initial `empty` state into - // the `loaded` state. - record.loadedData(); - - // Set the properties specified on the record. - record.setProperties(properties); - - return record; - }, - - /** - If possible, this method asks the adapter to generate an ID for - a newly created record. - - @method _generateId - @private - @param {String} type - @return {String} if the adapter can generate one, an ID - */ - _generateId: function(type) { - var adapter = this.adapterFor(type); - - if (adapter && adapter.generateIdForRecord) { - return adapter.generateIdForRecord(this); - } - - return null; - }, - - // ................. - // . DELETE RECORD . - // ................. - - /** - For symmetry, a record can be deleted via the store. - - Example - - ```javascript - var post = store.createRecord('post', { - title: "Rails is omakase" - }); - - store.deleteRecord(post); - ``` - - @method deleteRecord - @param {DS.Model} record - */ - deleteRecord: function(record) { - record.deleteRecord(); - }, - - /** - For symmetry, a record can be unloaded via the store. Only - non-dirty records can be unloaded. - - Example - - ```javascript - store.find('post', 1).then(function(post) { - store.unloadRecord(post); - }); - ``` - - @method unloadRecord - @param {DS.Model} record - */ - unloadRecord: function(record) { - record.unloadRecord(); - }, - - // ................ - // . FIND RECORDS . - // ................ - - /** - This is the main entry point into finding records. The first parameter to - this method is the model's name as a string. - - --- - - To find a record by ID, pass the `id` as the second parameter: - - ```javascript - store.find('person', 1); - ``` - - The `find` method will always return a **promise** that will be resolved - with the record. If the record was already in the store, the promise will - be resolved immediately. Otherwise, the store will ask the adapter's `find` - method to find the necessary data. - - The `find` method will always resolve its promise with the same object for - a given type and `id`. - - --- - - You can optionally `preload` specific attributes and relationships that you know of - by passing them as the third argument to find. - - For example, if your Ember route looks like `/posts/1/comments/2` and your API route - for the comment also looks like `/posts/1/comments/2` if you want to fetch the comment - without fetching the post you can pass in the post to the `find` call: - - ```javascript - store.find('comment', 2, {post: 1}); - ``` - - If you have access to the post model you can also pass the model itself: - - ```javascript - store.find('post', 1).then(function (myPostModel) { - store.find('comment', 2, {post: myPostModel}); - }); - ``` - - This way, your adapter's `find` or `buildURL` method will be able to look up the - relationship on the record and construct the nested URL without having to first - fetch the post. - - --- - - To find all records for a type, call `find` with no additional parameters: - - ```javascript - store.find('person'); - ``` - - This will ask the adapter's `findAll` method to find the records for the - given type, and return a promise that will be resolved once the server - returns the values. - - --- - - To find a record by a query, call `find` with a hash as the second - parameter: - - ```javascript - store.find('person', { page: 1 }); - ``` - - This will ask the adapter's `findQuery` method to find the records for - the query, and return a promise that will be resolved once the server - responds. - - @method find - @param {String or subclass of DS.Model} type - @param {Object|String|Integer|null} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models - @return {Promise} promise - */ - find: function(type, id, preload) { - - if (arguments.length === 1) { - return this.findAll(type); - } - - // We are passed a query instead of an id. - if (Ember.typeOf(id) === 'object') { - return this.findQuery(type, id); - } - - return this.findById(type, ember$data$lib$system$store$$coerceId(id), preload); - }, - - /** - This method returns a fresh record for a given type and id combination. - - If a record is available for the given type/id combination, then - it will fetch this record from the store and call `reload()` on it. - That will fire a request to server and return a promise that will - resolve once the record has been reloaded. - If there's no record corresponding in the store it will simply call - `store.find`. - - Example - - ```javascript - App.PostRoute = Ember.Route.extend({ - model: function(params) { - return this.store.fetch('post', params.post_id); - } - }); - ``` - - @method fetch - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models - @return {Promise} promise - */ - fetch: function(type, id, preload) { - if (this.hasRecordForId(type, id)) { - return this.getById(type, id).reload(); - } else { - return this.find(type, id, preload); - } - }, - - /** - This method returns a record for a given type and id combination. - - @method findById - @private - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @param {Object} preload - optional set of attributes and relationships passed in either as IDs or as actual models - @return {Promise} promise - */ - findById: function(typeName, id, preload) { - - var type = this.modelFor(typeName); - var record = this.recordForId(type, id); - - return this._findByRecord(record, preload); - }, - - _findByRecord: function(record, preload) { - var fetchedRecord; - - if (preload) { - record._preloadData(preload); - } - - if (ember$data$lib$system$store$$get(record, 'isEmpty')) { - fetchedRecord = this.scheduleFetch(record); - //TODO double check about reloading - } else if (ember$data$lib$system$store$$get(record, 'isLoading')){ - fetchedRecord = record._loadingPromise; - } - - return ember$data$lib$system$promise_proxies$$promiseObject(fetchedRecord || record, "DS: Store#findByRecord " + record.typeKey + " with id: " + ember$data$lib$system$store$$get(record, 'id')); - }, - - /** - This method makes a series of requests to the adapter's `find` method - and returns a promise that resolves once they are all loaded. - - @private - @method findByIds - @param {String} type - @param {Array} ids - @return {Promise} promise - */ - findByIds: function(type, ids) { - var store = this; - - return ember$data$lib$system$promise_proxies$$promiseArray(Ember.RSVP.all(ember$data$lib$system$store$$map(ids, function(id) { - return store.findById(type, id); - })).then(Ember.A, null, "DS: Store#findByIds of " + type + " complete")); - }, - - /** - This method is called by `findById` if it discovers that a particular - type/id pair hasn't been loaded yet to kick off a request to the - adapter. - - @method fetchRecord - @private - @param {DS.Model} record - @return {Promise} promise - */ - fetchRecord: function(record) { - var type = record.constructor; - var id = ember$data$lib$system$store$$get(record, 'id'); - var adapter = this.adapterFor(type); - - - var promise = ember$data$lib$system$store$$_find(adapter, this, type, id, record); - return promise; - }, - - scheduleFetchMany: function(records) { - return ember$data$lib$system$store$$Promise.all(ember$data$lib$system$store$$map(records, this.scheduleFetch, this)); - }, - - scheduleFetch: function(record) { - var type = record.constructor; - if (ember$data$lib$system$store$$isNone(record)) { return null; } - if (record._loadingPromise) { return record._loadingPromise; } - - var resolver = Ember.RSVP.defer('Fetching ' + type + 'with id: ' + record.get('id')); - var recordResolverPair = { - record: record, - resolver: resolver - }; - var promise = resolver.promise; - - record.loadingData(promise); - - if (!this._pendingFetch.get(type)){ - this._pendingFetch.set(type, [recordResolverPair]); - } else { - this._pendingFetch.get(type).push(recordResolverPair); - } - Ember.run.scheduleOnce('afterRender', this, this.flushAllPendingFetches); - - return promise; - }, - - flushAllPendingFetches: function(){ - if (this.isDestroyed || this.isDestroying) { - return; - } - - this._pendingFetch.forEach(this._flushPendingFetchForType, this); - this._pendingFetch = ember$data$lib$system$map$$Map.create(); - }, - - _flushPendingFetchForType: function (recordResolverPairs, type) { - var store = this; - var adapter = store.adapterFor(type); - var shouldCoalesce = !!adapter.findMany && adapter.coalesceFindRequests; - var records = Ember.A(recordResolverPairs).mapBy('record'); - - function _fetchRecord(recordResolverPair) { - recordResolverPair.resolver.resolve(store.fetchRecord(recordResolverPair.record)); - } - - function resolveFoundRecords(records) { - ember$data$lib$system$store$$forEach(records, function(record){ - var pair = Ember.A(recordResolverPairs).findBy('record', record); - if (pair){ - var resolver = pair.resolver; - resolver.resolve(record); - } - }); - } - - function makeMissingRecordsRejector(requestedRecords) { - return function rejectMissingRecords(resolvedRecords) { - var missingRecords = requestedRecords.without(resolvedRecords); - rejectRecords(missingRecords); - }; - } - - function makeRecordsRejector(records) { - return function (error) { - rejectRecords(records, error); - }; - } - - function rejectRecords(records, error) { - ember$data$lib$system$store$$forEach(records, function(record){ - var pair = Ember.A(recordResolverPairs).findBy('record', record); - if (pair){ - var resolver = pair.resolver; - resolver.reject(error); - } - }); - } - - if (recordResolverPairs.length === 1) { - _fetchRecord(recordResolverPairs[0]); - } else if (shouldCoalesce) { - var groups = adapter.groupRecordsForFindMany(this, records); - ember$data$lib$system$store$$forEach(groups, function (groupOfRecords) { - var requestedRecords = Ember.A(groupOfRecords); - var ids = requestedRecords.mapBy('id'); - if (ids.length > 1) { - ember$data$lib$system$store$$_findMany(adapter, store, type, ids, requestedRecords). - then(resolveFoundRecords). - then(makeMissingRecordsRejector(requestedRecords)). - then(null, makeRecordsRejector(requestedRecords)); - } else if (ids.length === 1) { - var pair = Ember.A(recordResolverPairs).findBy('record', groupOfRecords[0]); - _fetchRecord(pair); - } else { - } - }); - } else { - ember$data$lib$system$store$$forEach(recordResolverPairs, _fetchRecord); - } - }, - - /** - Get a record by a given type and ID without triggering a fetch. - - This method will synchronously return the record if it is available in the store, - otherwise it will return `null`. A record is available if it has been fetched earlier, or - pushed manually into the store. - - _Note: This is an synchronous method and does not return a promise._ - - ```js - var post = store.getById('post', 1); - - post.get('id'); // 1 - ``` - - @method getById - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @return {DS.Model|null} record - */ - getById: function(type, id) { - if (this.hasRecordForId(type, id)) { - return this.recordForId(type, id); - } else { - return null; - } - }, - - /** - This method is called by the record's `reload` method. - - This method calls the adapter's `find` method, which returns a promise. When - **that** promise resolves, `reloadRecord` will resolve the promise returned - by the record's `reload`. - - @method reloadRecord - @private - @param {DS.Model} record - @return {Promise} promise - */ - reloadRecord: function(record) { - var type = record.constructor; - var adapter = this.adapterFor(type); - var id = ember$data$lib$system$store$$get(record, 'id'); - - - return this.scheduleFetch(record); - }, - - /** - Returns true if a record for a given type and ID is already loaded. - - @method hasRecordForId - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @return {Boolean} - */ - hasRecordForId: function(typeName, inputId) { - var type = this.modelFor(typeName); - var id = ember$data$lib$system$store$$coerceId(inputId); - return !!this.typeMapFor(type).idToRecord[id]; - }, - - /** - Returns id record for a given type and ID. If one isn't already loaded, - it builds a new record and leaves it in the `empty` state. - - @method recordForId - @private - @param {String or subclass of DS.Model} type - @param {String|Integer} id - @return {DS.Model} record - */ - recordForId: function(typeName, inputId) { - var type = this.modelFor(typeName); - var id = ember$data$lib$system$store$$coerceId(inputId); - var idToRecord = this.typeMapFor(type).idToRecord; - var record = idToRecord[id]; - - if (!record || !idToRecord[id]) { - record = this.buildRecord(type, id); - } - - return record; - }, - - /** - @method findMany - @private - @param {DS.Model} owner - @param {Array} records - @param {String or subclass of DS.Model} type - @param {Resolver} resolver - @return {DS.ManyArray} records - */ - findMany: function(records) { - var store = this; - return ember$data$lib$system$store$$Promise.all(ember$data$lib$system$store$$map(records, function(record) { - return store._findByRecord(record); - })); - }, - - - /** - If a relationship was originally populated by the adapter as a link - (as opposed to a list of IDs), this method is called when the - relationship is fetched. - - The link (which is usually a URL) is passed through unchanged, so the - adapter can make whatever request it wants. - - The usual use-case is for the server to register a URL as a link, and - then use that URL in the future to make a request for the relationship. - - @method findHasMany - @private - @param {DS.Model} owner - @param {any} link - @param {String or subclass of DS.Model} type - @return {Promise} promise - */ - findHasMany: function(owner, link, type) { - var adapter = this.adapterFor(owner.constructor); - - - return ember$data$lib$system$store$$_findHasMany(adapter, this, owner, link, type); - }, - - /** - @method findBelongsTo - @private - @param {DS.Model} owner - @param {any} link - @param {Relationship} relationship - @return {Promise} promise - */ - findBelongsTo: function(owner, link, relationship) { - var adapter = this.adapterFor(owner.constructor); - - - return ember$data$lib$system$store$$_findBelongsTo(adapter, this, owner, link, relationship); - }, - - /** - This method delegates a query to the adapter. This is the one place where - adapter-level semantics are exposed to the application. - - Exposing queries this way seems preferable to creating an abstract query - language for all server-side queries, and then require all adapters to - implement them. - - This method returns a promise, which is resolved with a `RecordArray` - once the server returns. - - @method findQuery - @private - @param {String or subclass of DS.Model} type - @param {any} query an opaque query to be used by the adapter - @return {Promise} promise - */ - findQuery: function(typeName, query) { - var type = this.modelFor(typeName); - var array = this.recordArrayManager - .createAdapterPopulatedRecordArray(type, query); - - var adapter = this.adapterFor(type); - - - return ember$data$lib$system$promise_proxies$$promiseArray(ember$data$lib$system$store$$_findQuery(adapter, this, type, query, array)); - }, - - /** - This method returns an array of all records adapter can find. - It triggers the adapter's `findAll` method to give it an opportunity to populate - the array with records of that type. - - @method findAll - @private - @param {String or subclass of DS.Model} type - @return {DS.AdapterPopulatedRecordArray} - */ - findAll: function(typeName) { - var type = this.modelFor(typeName); - - return this.fetchAll(type, this.all(type)); - }, - - /** - @method fetchAll - @private - @param {DS.Model} type - @param {DS.RecordArray} array - @return {Promise} promise - */ - fetchAll: function(type, array) { - var adapter = this.adapterFor(type); - var sinceToken = this.typeMapFor(type).metadata.since; - - ember$data$lib$system$store$$set(array, 'isUpdating', true); - - - return ember$data$lib$system$promise_proxies$$promiseArray(ember$data$lib$system$store$$_findAll(adapter, this, type, sinceToken)); - }, - - /** - @method didUpdateAll - @param {DS.Model} type - */ - didUpdateAll: function(type) { - var findAllCache = this.typeMapFor(type).findAllCache; - ember$data$lib$system$store$$set(findAllCache, 'isUpdating', false); - }, - - /** - This method returns a filtered array that contains all of the - known records for a given type in the store. - - Note that because it's just a filter, the result will contain any - locally created records of the type, however, it will not make a - request to the backend to retrieve additional records. If you - would like to request all the records from the backend please use - [store.find](#method_find). - - Also note that multiple calls to `all` for a given type will always - return the same `RecordArray`. - - Example - - ```javascript - var localPosts = store.all('post'); - ``` - - @method all - @param {String or subclass of DS.Model} type - @return {DS.RecordArray} - */ - all: function(typeName) { - var type = this.modelFor(typeName); - var typeMap = this.typeMapFor(type); - var findAllCache = typeMap.findAllCache; - - if (findAllCache) { - this.recordArrayManager.updateFilter(findAllCache, type); - return findAllCache; - } - - var array = this.recordArrayManager.createRecordArray(type); - - typeMap.findAllCache = array; - return array; - }, - - - /** - This method unloads all of the known records for a given type. - - ```javascript - store.unloadAll('post'); - ``` - - @method unloadAll - @param {String or subclass of DS.Model} type - */ - unloadAll: function(type) { - var modelType = this.modelFor(type); - var typeMap = this.typeMapFor(modelType); - var records = typeMap.records.slice(); - var record; - - for (var i = 0; i < records.length; i++) { - record = records[i]; - record.unloadRecord(); - record.destroy(); // maybe within unloadRecord - } - - typeMap.findAllCache = null; - }, - - /** - Takes a type and filter function, and returns a live RecordArray that - remains up to date as new records are loaded into the store or created - locally. - - The filter function takes a materialized record, and returns true - if the record should be included in the filter and false if it should - not. - - Example - - ```javascript - store.filter('post', function(post) { - return post.get('unread'); - }); - ``` - - The filter function is called once on all records for the type when - it is created, and then once on each newly loaded or created record. - - If any of a record's properties change, or if it changes state, the - filter function will be invoked again to determine whether it should - still be in the array. - - Optionally you can pass a query, which is the equivalent of calling - [find](#method_find) with that same query, to fetch additional records - from the server. The results returned by the server could then appear - in the filter if they match the filter function. - - The query itself is not used to filter records, it's only sent to your - server for you to be able to do server-side filtering. The filter - function will be applied on the returned results regardless. - - Example - - ```javascript - store.filter('post', { unread: true }, function(post) { - return post.get('unread'); - }).then(function(unreadPosts) { - unreadPosts.get('length'); // 5 - var unreadPost = unreadPosts.objectAt(0); - unreadPost.set('unread', false); - unreadPosts.get('length'); // 4 - }); - ``` - - @method filter - @param {String or subclass of DS.Model} type - @param {Object} query optional query - @param {Function} filter - @return {DS.PromiseArray} - */ - filter: function(type, query, filter) { - var promise; - var length = arguments.length; - var array; - var hasQuery = length === 3; - - // allow an optional server query - if (hasQuery) { - promise = this.findQuery(type, query); - } else if (arguments.length === 2) { - filter = query; - } - - type = this.modelFor(type); - - if (hasQuery) { - array = this.recordArrayManager.createFilteredRecordArray(type, filter, query); - } else { - array = this.recordArrayManager.createFilteredRecordArray(type, filter); - } - - promise = promise || ember$data$lib$system$store$$Promise.cast(array); - - return ember$data$lib$system$promise_proxies$$promiseArray(promise.then(function() { - return array; - }, null, "DS: Store#filter of " + type)); - }, - - /** - This method returns if a certain record is already loaded - in the store. Use this function to know beforehand if a find() - will result in a request or that it will be a cache hit. - - Example - - ```javascript - store.recordIsLoaded('post', 1); // false - store.find('post', 1).then(function() { - store.recordIsLoaded('post', 1); // true - }); - ``` - - @method recordIsLoaded - @param {String or subclass of DS.Model} type - @param {string} id - @return {boolean} - */ - recordIsLoaded: function(type, id) { - if (!this.hasRecordForId(type, id)) { return false; } - return !ember$data$lib$system$store$$get(this.recordForId(type, id), 'isEmpty'); - }, - - /** - This method returns the metadata for a specific type. - - @method metadataFor - @param {String or subclass of DS.Model} typeName - @return {object} - */ - metadataFor: function(typeName) { - var type = this.modelFor(typeName); - return this.typeMapFor(type).metadata; - }, - - /** - This method sets the metadata for a specific type. - - @method setMetadataFor - @param {String or subclass of DS.Model} typeName - @param {Object} metadata metadata to set - @return {object} - */ - setMetadataFor: function(typeName, metadata) { - var type = this.modelFor(typeName); - Ember.merge(this.typeMapFor(type).metadata, metadata); - }, - - // ............ - // . UPDATING . - // ............ - - /** - If the adapter updates attributes or acknowledges creation - or deletion, the record will notify the store to update its - membership in any filters. - To avoid thrashing, this method is invoked only once per - - run loop per record. - - @method dataWasUpdated - @private - @param {Class} type - @param {DS.Model} record - */ - dataWasUpdated: function(type, record) { - this.recordArrayManager.recordDidChange(record); - }, - - // .............. - // . PERSISTING . - // .............. - - /** - This method is called by `record.save`, and gets passed a - resolver for the promise that `record.save` returns. - - It schedules saving to happen at the end of the run loop. - - @method scheduleSave - @private - @param {DS.Model} record - @param {Resolver} resolver - */ - scheduleSave: function(record, resolver) { - record.adapterWillCommit(); - this._pendingSave.push([record, resolver]); - ember$data$lib$system$store$$once(this, 'flushPendingSave'); - }, - - /** - This method is called at the end of the run loop, and - flushes any records passed into `scheduleSave` - - @method flushPendingSave - @private - */ - flushPendingSave: function() { - var pending = this._pendingSave.slice(); - this._pendingSave = []; - - ember$data$lib$system$store$$forEach(pending, function(tuple) { - var record = tuple[0], resolver = tuple[1]; - var adapter = this.adapterFor(record.constructor); - var operation; - - if (ember$data$lib$system$store$$get(record, 'currentState.stateName') === 'root.deleted.saved') { - return resolver.resolve(record); - } else if (ember$data$lib$system$store$$get(record, 'isNew')) { - operation = 'createRecord'; - } else if (ember$data$lib$system$store$$get(record, 'isDeleted')) { - operation = 'deleteRecord'; - } else { - operation = 'updateRecord'; - } - - resolver.resolve(ember$data$lib$system$store$$_commit(adapter, this, operation, record)); - }, this); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is resolved. - - If the data provides a server-generated ID, it will - update the record and the store's indexes. - - @method didSaveRecord - @private - @param {DS.Model} record the in-flight record - @param {Object} data optional data (see above) - */ - didSaveRecord: function(record, data) { - if (data) { - // normalize relationship IDs into records - this._backburner.schedule('normalizeRelationships', this, '_setupRelationships', record, record.constructor, data); - this.updateId(record, data); - } - - //We first make sure the primary data has been updated - //TODO try to move notification to the user to the end of the runloop - record.adapterDidCommit(data); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected with a `DS.InvalidError`. - - @method recordWasInvalid - @private - @param {DS.Model} record - @param {Object} errors - */ - recordWasInvalid: function(record, errors) { - record.adapterDidInvalidate(errors); - }, - - /** - This method is called once the promise returned by an - adapter's `createRecord`, `updateRecord` or `deleteRecord` - is rejected (with anything other than a `DS.InvalidError`). - - @method recordWasError - @private - @param {DS.Model} record - */ - recordWasError: function(record) { - record.adapterDidError(); - }, - - /** - When an adapter's `createRecord`, `updateRecord` or `deleteRecord` - resolves with data, this method extracts the ID from the supplied - data. - - @method updateId - @private - @param {DS.Model} record - @param {Object} data - */ - updateId: function(record, data) { - var oldId = ember$data$lib$system$store$$get(record, 'id'); - var id = ember$data$lib$system$store$$coerceId(data.id); - - - this.typeMapFor(record.constructor).idToRecord[id] = record; - - ember$data$lib$system$store$$set(record, 'id', id); - }, - - /** - Returns a map of IDs to client IDs for a given type. - - @method typeMapFor - @private - @param {subclass of DS.Model} type - @return {Object} typeMap - */ - typeMapFor: function(type) { - var typeMaps = ember$data$lib$system$store$$get(this, 'typeMaps'); - var guid = Ember.guidFor(type); - var typeMap; - - typeMap = typeMaps[guid]; - - if (typeMap) { return typeMap; } - - typeMap = { - idToRecord: Ember.create(null), - records: [], - metadata: Ember.create(null), - type: type - }; - - typeMaps[guid] = typeMap; - - return typeMap; - }, - - // ................ - // . LOADING DATA . - // ................ - - /** - This internal method is used by `push`. - - @method _load - @private - @param {String or subclass of DS.Model} type - @param {Object} data - */ - _load: function(type, data) { - var id = ember$data$lib$system$store$$coerceId(data.id); - var record = this.recordForId(type, id); - - record.setupData(data); - this.recordArrayManager.recordDidChange(record); - - return record; - }, - - /** - Returns a model class for a particular key. Used by - methods that take a type key (like `find`, `createRecord`, - etc.) - - @method modelFor - @param {String or subclass of DS.Model} key - @return {subclass of DS.Model} - */ - modelFor: function(key) { - var factory; - - if (typeof key === 'string') { - factory = this.modelFactoryFor(key); - if (!factory) { - throw new Ember.Error("No model was found for '" + key + "'"); - } - factory.typeKey = factory.typeKey || this._normalizeTypeKey(key); - } else { - // A factory already supplied. Ensure it has a normalized key. - factory = key; - if (factory.typeKey) { - factory.typeKey = this._normalizeTypeKey(factory.typeKey); - } - } - - factory.store = this; - return factory; - }, - - modelFactoryFor: function(key){ - return this.container.lookupFactory('model:' + key); - }, - - /** - Push some data for a given type into the store. - - This method expects normalized data: - - * The ID is a key named `id` (an ID is mandatory) - * The names of attributes are the ones you used in - your model's `DS.attr`s. - * Your relationships must be: - * represented as IDs or Arrays of IDs - * represented as model instances - * represented as URLs, under the `links` key - - For this model: - - ```js - App.Person = DS.Model.extend({ - firstName: DS.attr(), - lastName: DS.attr(), - - children: DS.hasMany('person') - }); - ``` - - To represent the children as IDs: - - ```js - { - id: 1, - firstName: "Tom", - lastName: "Dale", - children: [1, 2, 3] - } - ``` - - To represent the children relationship as a URL: - - ```js - { - id: 1, - firstName: "Tom", - lastName: "Dale", - links: { - children: "/people/1/children" - } - } - ``` - - If you're streaming data or implementing an adapter, make sure - that you have converted the incoming data into this form. The - store's [normalize](#method_normalize) method is a convenience - helper for converting a json payload into the form Ember Data - expects. - - ```js - store.push('person', store.normalize('person', data)); - ``` - - This method can be used both to push in brand new - records, as well as to update existing records. - - @method push - @param {String or subclass of DS.Model} type - @param {Object} data - @return {DS.Model} the record that was created or - updated. - */ - push: function(typeName, data) { - - var type = this.modelFor(typeName); - var filter = Ember.EnumerableUtils.filter; - - // If the payload contains unused keys log a warning. - // Adding `Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS = true` will suppress the warning. - if (!Ember.ENV.DS_NO_WARN_ON_UNUSED_KEYS) { - } - - // Actually load the record into the store. - - this._load(type, data); - - var record = this.recordForId(type, data.id); - var store = this; - - this._backburner.join(function() { - store._backburner.schedule('normalizeRelationships', store, '_setupRelationships', record, type, data); - }); - - return record; - }, - - _setupRelationships: function(record, type, data) { - // If the payload contains relationships that are specified as - // IDs, normalizeRelationships will convert them into DS.Model instances - // (possibly unloaded) before we push the payload into the - // store. - - data = ember$data$lib$system$store$$normalizeRelationships(this, type, data); - - - // Now that the pushed record as well as any related records - // are in the store, create the data structures used to track - // relationships. - ember$data$lib$system$store$$setupRelationships(this, record, data); - }, - - /** - Push some raw data into the store. - - This method can be used both to push in brand new - records, as well as to update existing records. You - can push in more than one type of object at once. - All objects should be in the format expected by the - serializer. - - ```js - App.ApplicationSerializer = DS.ActiveModelSerializer; - - var pushData = { - posts: [ - {id: 1, post_title: "Great post", comment_ids: [2]} - ], - comments: [ - {id: 2, comment_body: "Insightful comment"} - ] - } - - store.pushPayload(pushData); - ``` - - By default, the data will be deserialized using a default - serializer (the application serializer if it exists). - - Alternatively, `pushPayload` will accept a model type which - will determine which serializer will process the payload. - However, the serializer itself (processing this data via - `normalizePayload`) will not know which model it is - deserializing. - - ```js - App.ApplicationSerializer = DS.ActiveModelSerializer; - App.PostSerializer = DS.JSONSerializer; - store.pushPayload('comment', pushData); // Will use the ApplicationSerializer - store.pushPayload('post', pushData); // Will use the PostSerializer - ``` - - @method pushPayload - @param {String} type Optionally, a model used to determine which serializer will be used - @param {Object} payload - */ - pushPayload: function (type, inputPayload) { - var serializer; - var payload; - if (!inputPayload) { - payload = type; - serializer = ember$data$lib$system$store$$defaultSerializer(this.container); - } else { - payload = inputPayload; - serializer = this.serializerFor(type); - } - var store = this; - ember$data$lib$system$store$$_adapterRun(this, function() { - serializer.pushPayload(store, payload); - }); - }, - - /** - `normalize` converts a json payload into the normalized form that - [push](#method_push) expects. - - Example - - ```js - socket.on('message', function(message) { - var modelName = message.model; - var data = message.data; - store.push(modelName, store.normalize(modelName, data)); - }); - ``` - - @method normalize - @param {String} type The name of the model type for this payload - @param {Object} payload - @return {Object} The normalized payload - */ - normalize: function (type, payload) { - var serializer = this.serializerFor(type); - var model = this.modelFor(type); - return serializer.normalize(model, payload); - }, - - /** - @method update - @param {String} type - @param {Object} data - @return {DS.Model} the record that was updated. - @deprecated Use [push](#method_push) instead - */ - update: function(type, data) { - return this.push(type, data); - }, - - /** - If you have an Array of normalized data to push, - you can call `pushMany` with the Array, and it will - call `push` repeatedly for you. - - @method pushMany - @param {String or subclass of DS.Model} type - @param {Array} datas - @return {Array} - */ - pushMany: function(type, datas) { - var length = datas.length; - var result = new Array(length); - - for (var i = 0; i < length; i++) { - result[i] = this.push(type, datas[i]); - } - - return result; - }, - - /** - @method metaForType - @param {String or subclass of DS.Model} typeName - @param {Object} metadata - @deprecated Use [setMetadataFor](#method_setMetadataFor) instead - */ - metaForType: function(typeName, metadata) { - this.setMetadataFor(typeName, metadata); - }, - - /** - Build a brand new record for a given type, ID, and - initial data. - - @method buildRecord - @private - @param {subclass of DS.Model} type - @param {String} id - @param {Object} data - @return {DS.Model} record - */ - buildRecord: function(type, id, data) { - var typeMap = this.typeMapFor(type); - var idToRecord = typeMap.idToRecord; - - - // lookupFactory should really return an object that creates - // instances with the injections applied - var record = type._create({ - id: id, - store: this, - container: this.container - }); - - if (data) { - record.setupData(data); - } - - // if we're creating an item, this process will be done - // later, once the object has been persisted. - if (id) { - idToRecord[id] = record; - } - - typeMap.records.push(record); - - return record; - }, - - // ............... - // . DESTRUCTION . - // ............... - - /** - When a record is destroyed, this un-indexes it and - removes it from any record arrays so it can be GCed. - - @method dematerializeRecord - @private - @param {DS.Model} record - */ - dematerializeRecord: function(record) { - var type = record.constructor; - var typeMap = this.typeMapFor(type); - var id = ember$data$lib$system$store$$get(record, 'id'); - - record.updateRecordArrays(); - - if (id) { - delete typeMap.idToRecord[id]; - } - - var loc = ember$data$lib$system$store$$indexOf(typeMap.records, record); - typeMap.records.splice(loc, 1); - }, - - // ...................... - // . PER-TYPE ADAPTERS - // ...................... - - /** - Returns the adapter for a given type. - - @method adapterFor - @private - @param {subclass of DS.Model} type - @return DS.Adapter - */ - adapterFor: function(type) { - var container = this.container, adapter; - - if (container) { - adapter = container.lookup('adapter:' + type.typeKey) || container.lookup('adapter:application'); - } - - return adapter || ember$data$lib$system$store$$get(this, 'defaultAdapter'); - }, - - // .............................. - // . RECORD CHANGE NOTIFICATION . - // .............................. - - /** - Returns an instance of the serializer for a given type. For - example, `serializerFor('person')` will return an instance of - `App.PersonSerializer`. - - If no `App.PersonSerializer` is found, this method will look - for an `App.ApplicationSerializer` (the default serializer for - your entire application). - - If no `App.ApplicationSerializer` is found, it will fall back - to an instance of `DS.JSONSerializer`. - - @method serializerFor - @private - @param {String} type the record to serialize - @return {DS.Serializer} - */ - serializerFor: function(type) { - type = this.modelFor(type); - var adapter = this.adapterFor(type); - - return ember$data$lib$system$store$$serializerFor(this.container, type.typeKey, adapter && adapter.defaultSerializer); - }, - - willDestroy: function() { - var typeMaps = this.typeMaps; - var keys = Ember.keys(typeMaps); - - var types = ember$data$lib$system$store$$map(keys, byType); - - this.recordArrayManager.destroy(); - - ember$data$lib$system$store$$forEach(types, this.unloadAll, this); - - function byType(entry) { - return typeMaps[entry]['type']; - } - - }, - - /** - All typeKeys are camelCase internally. Changing this function may - require changes to other normalization hooks (such as typeForRoot). - - @method _normalizeTypeKey - @private - @param {String} type - @return {String} if the adapter can generate one, an ID - */ - _normalizeTypeKey: function(key) { - return ember$data$lib$system$store$$camelize(ember$inflector$lib$system$string$$singularize(key)); - } - }); - - - function ember$data$lib$system$store$$normalizeRelationships(store, type, data, record) { - type.eachRelationship(function(key, relationship) { - var kind = relationship.kind; - var value = data[key]; - if (kind === 'belongsTo') { - ember$data$lib$system$store$$deserializeRecordId(store, data, key, relationship, value); - } else if (kind === 'hasMany') { - ember$data$lib$system$store$$deserializeRecordIds(store, data, key, relationship, value); - } - }); - - return data; - } - - function ember$data$lib$system$store$$deserializeRecordId(store, data, key, relationship, id) { - if (ember$data$lib$system$store$$isNone(id) || id instanceof ember$data$lib$system$model$model$$default) { - return; - } - - var type; - - if (typeof id === 'number' || typeof id === 'string') { - type = ember$data$lib$system$store$$typeFor(relationship, key, data); - data[key] = store.recordForId(type, id); - } else if (typeof id === 'object') { - // polymorphic - data[key] = store.recordForId(id.type, id.id); - } - } - - function ember$data$lib$system$store$$typeFor(relationship, key, data) { - if (relationship.options.polymorphic) { - return data[key + "Type"]; - } else { - return relationship.type; - } - } - - function ember$data$lib$system$store$$deserializeRecordIds(store, data, key, relationship, ids) { - if (ember$data$lib$system$store$$isNone(ids)) { - return; - } - - for (var i=0, l=ids.length; i self.attributeLimit) { return false; } - var desc = ember$data$lib$system$debug$debug_adapter$$capitalize(ember$data$lib$system$debug$debug_adapter$$underscore(name).replace('_', ' ')); - columns.push({ name: name, desc: desc }); - }); - return columns; - }, - - getRecords: function(type) { - return this.get('store').all(type); - }, - - getRecordColumnValues: function(record) { - var self = this, count = 0; - var columnValues = { id: ember$data$lib$system$debug$debug_adapter$$get(record, 'id') }; - - record.eachAttribute(function(key) { - if (count++ > self.attributeLimit) { - return false; - } - var value = ember$data$lib$system$debug$debug_adapter$$get(record, key); - columnValues[key] = value; - }); - return columnValues; - }, - - getRecordKeywords: function(record) { - var keywords = []; - var keys = Ember.A(['id']); - record.eachAttribute(function(key) { - keys.push(key); - }); - keys.forEach(function(key) { - keywords.push(ember$data$lib$system$debug$debug_adapter$$get(record, key)); - }); - return keywords; - }, - - getRecordFilterValues: function(record) { - return { - isNew: record.get('isNew'), - isModified: record.get('isDirty') && !record.get('isNew'), - isClean: !record.get('isDirty') - }; - }, - - getRecordColor: function(record) { - var color = 'black'; - if (record.get('isNew')) { - color = 'green'; - } else if (record.get('isDirty')) { - color = 'blue'; - } - return color; - }, - - observeRecord: function(record, recordUpdated) { - var releaseMethods = Ember.A(), self = this; - var keysToObserve = Ember.A(['id', 'isNew', 'isDirty']); - - record.eachAttribute(function(key) { - keysToObserve.push(key); - }); - - keysToObserve.forEach(function(key) { - var handler = function() { - recordUpdated(self.wrapRecord(record)); - }; - Ember.addObserver(record, key, handler); - releaseMethods.push(function() { - Ember.removeObserver(record, key, handler); - }); - }); - - var release = function() { - releaseMethods.forEach(function(fn) { fn(); } ); - }; - - return release; - } - - }); - - function ember$data$lib$initializers$data_adapter$$initializeDebugAdapter(container){ - container.register('data-adapter:main', ember$data$lib$system$debug$debug_adapter$$default); - } - var ember$data$lib$initializers$data_adapter$$default = ember$data$lib$initializers$data_adapter$$initializeDebugAdapter; - function ember$data$lib$setup$container$$setupContainer(container, application){ - // application is not a required argument. This ensures - // testing setups can setup a container without booting an - // entire ember application. - - ember$data$lib$initializers$data_adapter$$default(container, application); - ember$data$lib$initializers$transforms$$default(container, application); - ember$data$lib$initializers$store_injections$$default(container, application); - ember$data$lib$initializers$store$$default(container, application); - activemodel$adapter$lib$setup$container$$default(container, application); - } - var ember$data$lib$setup$container$$default = ember$data$lib$setup$container$$setupContainer; - - var ember$data$lib$ember$initializer$$K = Ember.K; - - /** - @module ember-data - */ - - /* - - This code initializes Ember-Data onto an Ember application. - - If an Ember.js developer defines a subclass of DS.Store on their application, - as `App.ApplicationStore` (or via a module system that resolves to `store:application`) - this code will automatically instantiate it and make it available on the - router. - - Additionally, after an application's controllers have been injected, they will - each have the store made available to them. - - For example, imagine an Ember.js application with the following classes: - - App.ApplicationStore = DS.Store.extend({ - adapter: 'custom' - }); - - App.PostsController = Ember.ArrayController.extend({ - // ... - }); - - When the application is initialized, `App.ApplicationStore` will automatically be - instantiated, and the instance of `App.PostsController` will have its `store` - property set to that instance. - - Note that this code will only be run if the `ember-application` package is - loaded. If Ember Data is being used in an environment other than a - typical application (e.g., node.js where only `ember-runtime` is available), - this code will be ignored. - */ - - Ember.onLoad('Ember.Application', function(Application) { - - Application.initializer({ - name: "ember-data", - initialize: ember$data$lib$setup$container$$default - }); - - // Deprecated initializers to satisfy old code that depended on them - - Application.initializer({ - name: "store", - after: "ember-data", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "activeModelAdapter", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "transforms", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "data-adapter", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - - Application.initializer({ - name: "injectStore", - before: "store", - initialize: ember$data$lib$ember$initializer$$K - }); - }); - /** - @module ember-data - */ - - /** - Date.parse with progressive enhancement for ISO 8601 - - © 2011 Colin Snover - - Released under MIT license. - - @class Date - @namespace Ember - @static - */ - Ember.Date = Ember.Date || {}; - - var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ]; - - /** - @method parse - @param {Date} date - @return {Number} timestamp - */ - Ember.Date.parse = function (date) { - var timestamp, struct, minutesOffset = 0; - - // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string - // before falling back to any implementation-specific date parsing, so that’s what we do, even if native - // implementations could be faster - // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm - if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) { - // avoid NaN timestamps caused by “undefined” values being passed to Date.UTC - for (var i = 0, k; (k = numericKeys[i]); ++i) { - struct[k] = +struct[k] || 0; - } - - // allow undefined days and months - struct[2] = (+struct[2] || 1) - 1; - struct[3] = +struct[3] || 1; - - if (struct[8] !== 'Z' && struct[9] !== undefined) { - minutesOffset = struct[10] * 60 + struct[11]; - - if (struct[9] === '+') { - minutesOffset = 0 - minutesOffset; - } - } - - timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]); - } - else { - timestamp = origParse ? origParse(date) : NaN; - } - - return timestamp; - }; - - if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) { - Date.parse = Ember.Date.parse; - } - /* - Detect if the user has a correct Object.create shim. - Ember has provided this for a long time but has had an incorrect shim before 1.8 - TODO: Remove for Ember Data 1.0. - */ - var object = Ember.create(null); - if (object.toString !== undefined && Ember.keys(Ember.create({}))[0] === '__proto__'){ - throw new Error("Ember Data requires a correct Object.create shim. You should upgrade to Ember >= 1.8 which provides one for you. If you are using ES5-shim, you should try removing that after upgrading Ember."); - } - - ember$data$lib$system$model$model$$default.reopen({ - - /** - Provides info about the model for debugging purposes - by grouping the properties into more semantic groups. - - Meant to be used by debugging tools such as the Chrome Ember Extension. - - - Groups all attributes in "Attributes" group. - - Groups all belongsTo relationships in "Belongs To" group. - - Groups all hasMany relationships in "Has Many" group. - - Groups all flags in "Flags" group. - - Flags relationship CPs as expensive properties. - - @method _debugInfo - @for DS.Model - @private - */ - _debugInfo: function() { - var attributes = ['id'], - relationships = { belongsTo: [], hasMany: [] }, - expensiveProperties = []; - - this.eachAttribute(function(name, meta) { - attributes.push(name); - }, this); - - this.eachRelationship(function(name, relationship) { - relationships[relationship.kind].push(name); - expensiveProperties.push(name); - }); - - var groups = [ - { - name: 'Attributes', - properties: attributes, - expand: true - }, - { - name: 'Belongs To', - properties: relationships.belongsTo, - expand: true - }, - { - name: 'Has Many', - properties: relationships.hasMany, - expand: true - }, - { - name: 'Flags', - properties: ['isLoaded', 'isDirty', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'] - } - ]; - - return { - propertyInfo: { - // include all other mixins / properties (not just the grouped ones) - includeOtherProperties: true, - groups: groups, - // don't pre-calculate unless cached - expensiveProperties: expensiveProperties - } - }; - } - }); - - var ember$data$lib$system$debug$debug_info$$default = ember$data$lib$system$model$model$$default; - var ember$data$lib$system$debug$$default = ember$data$lib$system$debug$debug_adapter$$default; - var ember$data$lib$serializers$embedded_records_mixin$$get = Ember.get; - var ember$data$lib$serializers$embedded_records_mixin$$forEach = Ember.EnumerableUtils.forEach; - var ember$data$lib$serializers$embedded_records_mixin$$camelize = Ember.String.camelize; - - /** - ## Using Embedded Records - - `DS.EmbeddedRecordsMixin` supports serializing embedded records. - - To set up embedded records, include the mixin when extending a serializer - then define and configure embedded (model) relationships. - - Below is an example of a per-type serializer ('post' type). - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - author: { embedded: 'always' }, - comments: { serialize: 'ids' } - } - }); - ``` - Note that this use of `{ embedded: 'always' }` is unrelated to - the `{ embedded: 'always' }` that is defined as an option on `DS.attr` as part of - defining a model while working with the ActiveModelSerializer. Nevertheless, - using `{ embedded: 'always' }` as an option to DS.attr is not a valid way to setup - embedded records. - - The `attrs` option for a resource `{ embedded: 'always' }` is shorthand for: - - ```js - { - serialize: 'records', - deserialize: 'records' - } - ``` - - ### Configuring Attrs - - A resource's `attrs` option may be set to use `ids`, `records` or false for the - `serialize` and `deserialize` settings. - - The `attrs` property can be set on the ApplicationSerializer or a per-type - serializer. - - In the case where embedded JSON is expected while extracting a payload (reading) - the setting is `deserialize: 'records'`, there is no need to use `ids` when - extracting as that is the default behavior without this mixin if you are using - the vanilla EmbeddedRecordsMixin. Likewise, to embed JSON in the payload while - serializing `serialize: 'records'` is the setting to use. There is an option of - not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you - do not want the relationship sent at all, you can use `serialize: false`. - - - ### EmbeddedRecordsMixin defaults - If you do not overwrite `attrs` for a specific relationship, the `EmbeddedRecordsMixin` - will behave in the following way: - - BelongsTo: `{ serialize: 'id', deserialize: 'id' }` - HasMany: `{ serialize: false, deserialize: 'ids' }` - - ### Model Relationships - - Embedded records must have a model defined to be extracted and serialized. Note that - when defining any relationships on your model such as `belongsTo` and `hasMany`, you - should not both specify `async:true` and also indicate through the serializer's - `attrs` attribute that the related model should be embedded. If a model is - declared embedded, then do not use `async:true`. - - To successfully extract and serialize embedded records the model relationships - must be setup correcty See the - [defining relationships](/guides/models/defining-models/#toc_defining-relationships) - section of the **Defining Models** guide page. - - Records without an `id` property are not considered embedded records, model - instances must have an `id` property to be used with Ember Data. - - ### Example JSON payloads, Models and Serializers - - **When customizing a serializer it is important to grok what the customizations - are. Please read the docs for the methods this mixin provides, in case you need - to modify it to fit your specific needs.** - - For example review the docs for each method of this mixin: - * [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize) - * [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo) - * [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany) - - @class EmbeddedRecordsMixin - @namespace DS - */ - var ember$data$lib$serializers$embedded_records_mixin$$EmbeddedRecordsMixin = Ember.Mixin.create({ - - /** - Normalize the record and recursively normalize/extract all the embedded records - while pushing them into the store as they are encountered - - A payload with an attr configured for embedded records needs to be extracted: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "comments": [{ - "id": "1", - "body": "Rails is unagi" - }, { - "id": "2", - "body": "Omakase O_o" - }] - } - } - ``` - @method normalize - @param {subclass of DS.Model} type - @param {Object} hash to be normalized - @param {String} key the hash has been referenced by - @return {Object} the normalized hash - **/ - normalize: function(type, hash, prop) { - var normalizedHash = this._super(type, hash, prop); - return ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedRecords(this, this.store, type, normalizedHash); - }, - - keyForRelationship: function(key, type){ - if (this.hasDeserializeRecordsOption(key)) { - return this.keyForAttribute(key); - } else { - return this._super(key, type) || key; - } - }, - - /** - Serialize `belongsTo` relationship when it is configured as an embedded object. - - This example of an author model belongs to a post model: - - ```js - Post = DS.Model.extend({ - title: DS.attr('string'), - body: DS.attr('string'), - author: DS.belongsTo('author') - }); - - Author = DS.Model.extend({ - name: DS.attr('string'), - post: DS.belongsTo('post') - }); - ``` - - Use a custom (type) serializer for the post model to configure embedded author - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - author: {embedded: 'always'} - } - }) - ``` - - A payload with an attribute configured for embedded records can serialize - the records together under the root attribute's payload: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "author": { - "id": "2" - "name": "dhh" - } - } - } - ``` - - @method serializeBelongsTo - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeBelongsTo: function(record, json, relationship) { - var attr = relationship.key; - if (this.noSerializeOptionSpecified(attr)) { - this._super(record, json, relationship); - return; - } - var includeIds = this.hasSerializeIdsOption(attr); - var includeRecords = this.hasSerializeRecordsOption(attr); - var embeddedRecord = record.get(attr); - var key; - if (includeIds) { - key = this.keyForRelationship(attr, relationship.kind); - if (!embeddedRecord) { - json[key] = null; - } else { - json[key] = ember$data$lib$serializers$embedded_records_mixin$$get(embeddedRecord, 'id'); - } - } else if (includeRecords) { - key = this.keyForAttribute(attr); - if (!embeddedRecord) { - json[key] = null; - } else { - json[key] = embeddedRecord.serialize({includeId: true}); - this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, json[key]); - } - } - }, - - /** - Serialize `hasMany` relationship when it is configured as embedded objects. - - This example of a post model has many comments: - - ```js - Post = DS.Model.extend({ - title: DS.attr('string'), - body: DS.attr('string'), - comments: DS.hasMany('comment') - }); - - Comment = DS.Model.extend({ - body: DS.attr('string'), - post: DS.belongsTo('post') - }); - ``` - - Use a custom (type) serializer for the post model to configure embedded comments - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - comments: {embedded: 'always'} - } - }) - ``` - - A payload with an attribute configured for embedded records can serialize - the records together under the root attribute's payload: - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "body": "I want this for my ORM, I want that for my template language..." - "comments": [{ - "id": "1", - "body": "Rails is unagi" - }, { - "id": "2", - "body": "Omakase O_o" - }] - } - } - ``` - - The attrs options object can use more specific instruction for extracting and - serializing. When serializing, an option to embed `ids` or `records` can be set. - When extracting the only option is `records`. - - So `{embedded: 'always'}` is shorthand for: - `{serialize: 'records', deserialize: 'records'}` - - To embed the `ids` for a related object (using a hasMany relationship): - - ```js - App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, { - attrs: { - comments: {serialize: 'ids', deserialize: 'records'} - } - }) - ``` - - ```js - { - "post": { - "id": "1" - "title": "Rails is omakase", - "body": "I want this for my ORM, I want that for my template language..." - "comments": ["1", "2"] - } - } - ``` - - @method serializeHasMany - @param {DS.Model} record - @param {Object} json - @param {Object} relationship - */ - serializeHasMany: function(record, json, relationship) { - var attr = relationship.key; - if (this.noSerializeOptionSpecified(attr)) { - this._super(record, json, relationship); - return; - } - var includeIds = this.hasSerializeIdsOption(attr); - var includeRecords = this.hasSerializeRecordsOption(attr); - var key; - if (includeIds) { - key = this.keyForRelationship(attr, relationship.kind); - json[key] = ember$data$lib$serializers$embedded_records_mixin$$get(record, attr).mapBy('id'); - } else if (includeRecords) { - key = this.keyForAttribute(attr); - json[key] = ember$data$lib$serializers$embedded_records_mixin$$get(record, attr).map(function(embeddedRecord) { - var serializedEmbeddedRecord = embeddedRecord.serialize({includeId: true}); - this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord); - return serializedEmbeddedRecord; - }, this); - } - }, - - /** - When serializing an embedded record, modify the property (in the json payload) - that refers to the parent record (foreign key for relationship). - - Serializing a `belongsTo` relationship removes the property that refers to the - parent record - - Serializing a `hasMany` relationship does not remove the property that refers to - the parent record. - - @method removeEmbeddedForeignKey - @param {DS.Model} record - @param {DS.Model} embeddedRecord - @param {Object} relationship - @param {Object} json - */ - removeEmbeddedForeignKey: function (record, embeddedRecord, relationship, json) { - if (relationship.kind === 'hasMany') { - return; - } else if (relationship.kind === 'belongsTo') { - var parentRecord = record.constructor.inverseFor(relationship.key); - if (parentRecord) { - var name = parentRecord.name; - var embeddedSerializer = this.store.serializerFor(embeddedRecord.constructor); - var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind); - if (parentKey) { - delete json[parentKey]; - } - } - } - }, - - // checks config for attrs option to embedded (always) - serialize and deserialize - hasEmbeddedAlwaysOption: function (attr) { - var option = this.attrsOption(attr); - return option && option.embedded === 'always'; - }, - - // checks config for attrs option to serialize ids - hasSerializeRecordsOption: function(attr) { - var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); - var option = this.attrsOption(attr); - return alwaysEmbed || (option && (option.serialize === 'records')); - }, - - // checks config for attrs option to serialize records - hasSerializeIdsOption: function(attr) { - var option = this.attrsOption(attr); - return option && (option.serialize === 'ids' || option.serialize === 'id'); - }, - - // checks config for attrs option to serialize records - noSerializeOptionSpecified: function(attr) { - var option = this.attrsOption(attr); - return !(option && (option.serialize || option.embedded)); - }, - - // checks config for attrs option to deserialize records - // a defined option object for a resource is treated the same as - // `deserialize: 'records'` - hasDeserializeRecordsOption: function(attr) { - var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr); - var option = this.attrsOption(attr); - return alwaysEmbed || (option && option.deserialize === 'records'); - }, - - attrsOption: function(attr) { - var attrs = this.get('attrs'); - return attrs && (attrs[ember$data$lib$serializers$embedded_records_mixin$$camelize(attr)] || attrs[attr]); - } - }); - - // chooses a relationship kind to branch which function is used to update payload - // does not change payload if attr is not embedded - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedRecords(serializer, store, type, partial) { - - type.eachRelationship(function(key, relationship) { - if (serializer.hasDeserializeRecordsOption(key)) { - var embeddedType = store.modelFor(relationship.type.typeKey); - if (relationship.kind === "hasMany") { - if (relationship.options.polymorphic) { - ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasManyPolymorphic(store, key, partial); - } - else { - ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasMany(store, key, embeddedType, partial); - } - } - if (relationship.kind === "belongsTo") { - ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedBelongsTo(store, key, embeddedType, partial); - } - } - }); - - return partial; - } - - // handles embedding for `hasMany` relationship - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasMany(store, key, embeddedType, hash) { - if (!hash[key]) { - return hash; - } - - var ids = []; - - var embeddedSerializer = store.serializerFor(embeddedType.typeKey); - ember$data$lib$serializers$embedded_records_mixin$$forEach(hash[key], function(data) { - var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null); - store.push(embeddedType, embeddedRecord); - ids.push(embeddedRecord.id); - }); - - hash[key] = ids; - return hash; - } - - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedHasManyPolymorphic(store, key, hash) { - if (!hash[key]) { - return hash; - } - - var ids = []; - - ember$data$lib$serializers$embedded_records_mixin$$forEach(hash[key], function(data) { - var typeKey = data.type; - var embeddedSerializer = store.serializerFor(typeKey); - var embeddedType = store.modelFor(typeKey); - var primaryKey = ember$data$lib$serializers$embedded_records_mixin$$get(embeddedSerializer, 'primaryKey'); - - var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null); - store.push(embeddedType, embeddedRecord); - ids.push({ id: embeddedRecord[primaryKey], type: typeKey }); - }); - - hash[key] = ids; - return hash; - } - - function ember$data$lib$serializers$embedded_records_mixin$$extractEmbeddedBelongsTo(store, key, embeddedType, hash) { - if (!hash[key]) { - return hash; - } - - var embeddedSerializer = store.serializerFor(embeddedType.typeKey); - var embeddedRecord = embeddedSerializer.normalize(embeddedType, hash[key], null); - store.push(embeddedType, embeddedRecord); - - hash[key] = embeddedRecord.id; - //TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records - return hash; - } - - var ember$data$lib$serializers$embedded_records_mixin$$default = ember$data$lib$serializers$embedded_records_mixin$$EmbeddedRecordsMixin; - - - /** - `DS.belongsTo` is used to define One-To-One and One-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - - `DS.belongsTo` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a - related model in a One-To-Many relationship. See [Explicit Inverses](#toc_explicit-inverses) - - #### One-To-One - To declare a one-to-one relationship between two models, use - `DS.belongsTo`: - - ```javascript - App.User = DS.Model.extend({ - profile: DS.belongsTo('profile') - }); - - App.Profile = DS.Model.extend({ - user: DS.belongsTo('user') - }); - ``` - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('comment') - }); - - App.Comment = DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the key name. - - ```javascript - App.Comment = DS.Model.extend({ - post: DS.belongsTo() - }); - ``` - - will lookup for a Post type. - - @namespace - @method belongsTo - @for DS - @param {String} type (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship - */ - function ember$data$lib$system$relationships$belongs_to$$belongsTo(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } - - - options = options || {}; - - var meta = { - type: type, - isRelationship: true, - options: options, - kind: 'belongsTo', - key: null - }; - - return Ember.computed(function(key, value) { - if (arguments.length>1) { - if ( value === undefined ) { - value = null; - } - if (value && value.then) { - this._relationships[key].setRecordPromise(value); - } else { - this._relationships[key].setRecord(value); - } - } - - return this._relationships[key].getRecord(); - }).meta(meta); - } - - /** - These observers observe all `belongsTo` relationships on the record. See - `relationships/ext` to see how these observers get their dependencies. - - @class Model - @namespace DS - */ - ember$data$lib$system$model$model$$default.reopen({ - notifyBelongsToChanged: function(key) { - this.notifyPropertyChange(key); - } - }); - - var ember$data$lib$system$relationships$belongs_to$$default = ember$data$lib$system$relationships$belongs_to$$belongsTo; - - /** - `DS.hasMany` is used to define One-To-Many and Many-To-Many - relationships on a [DS.Model](/api/data/classes/DS.Model.html). - - `DS.hasMany` takes an optional hash as a second parameter, currently - supported options are: - - - `async`: A boolean value used to explicitly declare this to be an async relationship. - - `inverse`: A string used to identify the inverse property on a related model. - - #### One-To-Many - To declare a one-to-many relationship between two models, use - `DS.belongsTo` in combination with `DS.hasMany`, like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('comment') - }); - - App.Comment = DS.Model.extend({ - post: DS.belongsTo('post') - }); - ``` - - #### Many-To-Many - To declare a many-to-many relationship between two models, use - `DS.hasMany`: - - ```javascript - App.Post = DS.Model.extend({ - tags: DS.hasMany('tag') - }); - - App.Tag = DS.Model.extend({ - posts: DS.hasMany('post') - }); - ``` - - You can avoid passing a string as the first parameter. In that case Ember Data - will infer the type from the singularized key name. - - ```javascript - App.Post = DS.Model.extend({ - tags: DS.hasMany() - }); - ``` - - will lookup for a Tag type. - - #### Explicit Inverses - - Ember Data will do its best to discover which relationships map to - one another. In the one-to-many code above, for example, Ember Data - can figure out that changing the `comments` relationship should update - the `post` relationship on the inverse because post is the only - relationship to that model. - - However, sometimes you may have multiple `belongsTo`/`hasManys` for the - same type. You can specify which property on the related model is - the inverse using `DS.hasMany`'s `inverse` option: - - ```javascript - var belongsTo = DS.belongsTo, - hasMany = DS.hasMany; - - App.Comment = DS.Model.extend({ - onePost: belongsTo('post'), - twoPost: belongsTo('post'), - redPost: belongsTo('post'), - bluePost: belongsTo('post') - }); - - App.Post = DS.Model.extend({ - comments: hasMany('comment', { - inverse: 'redPost' - }) - }); - ``` - - You can also specify an inverse on a `belongsTo`, which works how - you'd expect. - - @namespace - @method hasMany - @for DS - @param {String} type (optional) type of the relationship - @param {Object} options (optional) a hash of options - @return {Ember.computed} relationship - */ - function ember$data$lib$system$relationships$has_many$$hasMany(type, options) { - if (typeof type === 'object') { - options = type; - type = undefined; - } - - - options = options || {}; - - // Metadata about relationships is stored on the meta of - // the relationship. This is used for introspection and - // serialization. Note that `key` is populated lazily - // the first time the CP is called. - var meta = { - type: type, - isRelationship: true, - options: options, - kind: 'hasMany', - key: null - }; - - return Ember.computed(function(key) { - var relationship = this._relationships[key]; - return relationship.getRecords(); - }).meta(meta).readOnly(); - } - - ember$data$lib$system$model$model$$default.reopen({ - notifyHasManyAdded: function(key) { - //We need to notifyPropertyChange in the adding case because we need to make sure - //we fetch the newly added record in case it is unloaded - //TODO(Igor): Consider whether we could do this only if the record state is unloaded - - //Goes away once hasMany is double promisified - this.notifyPropertyChange(key); - }, - }); - - - var ember$data$lib$system$relationships$has_many$$default = ember$data$lib$system$relationships$has_many$$hasMany; - function ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(store, meta) { - var typeKey, type; - - typeKey = meta.type || meta.key; - if (typeof typeKey === 'string') { - if (meta.kind === 'hasMany') { - typeKey = ember$inflector$lib$system$string$$singularize(typeKey); - } - type = store.modelFor(typeKey); - } else { - type = meta.type; - } - - return type; - } - - function ember$data$lib$system$relationship$meta$$relationshipFromMeta(store, meta) { - return { - key: meta.key, - kind: meta.kind, - type: ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(store, meta), - options: meta.options, - parentType: meta.parentType, - isRelationship: true - }; - } - - var ember$data$lib$system$relationships$ext$$get = Ember.get; - var ember$data$lib$system$relationships$ext$$filter = Ember.ArrayPolyfills.filter; - - var ember$data$lib$system$relationships$ext$$relationshipsDescriptor = Ember.computed(function() { - if (Ember.testing === true && ember$data$lib$system$relationships$ext$$relationshipsDescriptor._cacheable === true) { - ember$data$lib$system$relationships$ext$$relationshipsDescriptor._cacheable = false; - } - - var map = new ember$data$lib$system$map$$MapWithDefault({ - defaultValue: function() { return []; } - }); - - // Loop through each computed property on the class - this.eachComputedProperty(function(name, meta) { - // If the computed property is a relationship, add - // it to the map. - if (meta.isRelationship) { - meta.key = name; - var relationshipsForType = map.get(ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(this.store, meta)); - - relationshipsForType.push({ - name: name, - kind: meta.kind - }); - } - }); - - return map; - }).readOnly(); - - var ember$data$lib$system$relationships$ext$$relatedTypesDescriptor = Ember.computed(function() { - if (Ember.testing === true && ember$data$lib$system$relationships$ext$$relatedTypesDescriptor._cacheable === true) { - ember$data$lib$system$relationships$ext$$relatedTypesDescriptor._cacheable = false; - } - - var type; - var types = Ember.A(); - - // Loop through each computed property on the class, - // and create an array of the unique types involved - // in relationships - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - meta.key = name; - type = ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(this.store, meta); - - - if (!types.contains(type)) { - types.push(type); - } - } - }); - - return types; - }).readOnly(); - - var ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor = Ember.computed(function() { - if (Ember.testing === true && ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor._cacheable === true) { - ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor._cacheable = false; - } - - var map = ember$data$lib$system$map$$Map.create(); - - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - meta.key = name; - var relationship = ember$data$lib$system$relationship$meta$$relationshipFromMeta(this.store, meta); - relationship.type = ember$data$lib$system$relationship$meta$$typeForRelationshipMeta(this.store, meta); - map.set(name, relationship); - } - }); - - return map; - }).readOnly(); - - /** - @module ember-data - */ - - /* - This file defines several extensions to the base `DS.Model` class that - add support for one-to-many relationships. - */ - - /** - @class Model - @namespace DS - */ - ember$data$lib$system$model$model$$default.reopen({ - - /** - This Ember.js hook allows an object to be notified when a property - is defined. - - In this case, we use it to be notified when an Ember Data user defines a - belongs-to relationship. In that case, we need to set up observers for - each one, allowing us to track relationship changes and automatically - reflect changes in the inverse has-many array. - - This hook passes the class being set up, as well as the key and value - being defined. So, for example, when the user does this: - - ```javascript - DS.Model.extend({ - parent: DS.belongsTo('user') - }); - ``` - - This hook would be called with "parent" as the key and the computed - property returned by `DS.belongsTo` as the value. - - @method didDefineProperty - @param {Object} proto - @param {String} key - @param {Ember.ComputedProperty} value - */ - didDefineProperty: function(proto, key, value) { - // Check if the value being set is a computed property. - if (value instanceof Ember.ComputedProperty) { - - // If it is, get the metadata for the relationship. This is - // populated by the `DS.belongsTo` helper when it is creating - // the computed property. - var meta = value.meta(); - - meta.parentType = proto.constructor; - } - } - }); - - /* - These DS.Model extensions add class methods that provide relationship - introspection abilities about relationships. - - A note about the computed properties contained here: - - **These properties are effectively sealed once called for the first time.** - To avoid repeatedly doing expensive iteration over a model's fields, these - values are computed once and then cached for the remainder of the runtime of - your application. - - If your application needs to modify a class after its initial definition - (for example, using `reopen()` to add additional attributes), make sure you - do it before using your model with the store, which uses these properties - extensively. - */ - - ember$data$lib$system$model$model$$default.reopenClass({ - - /** - For a given relationship name, returns the model type of the relationship. - - For example, if you define a model like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('comment') - }); - ``` - - Calling `App.Post.typeForRelationship('comments')` will return `App.Comment`. - - @method typeForRelationship - @static - @param {String} name the name of the relationship - @return {subclass of DS.Model} the type of the relationship, or undefined - */ - typeForRelationship: function(name) { - var relationship = ember$data$lib$system$relationships$ext$$get(this, 'relationshipsByName').get(name); - return relationship && relationship.type; - }, - - inverseMap: Ember.computed(function() { - return Ember.create(null); - }), - - /** - Find the relationship which is the inverse of the one asked for. - - For example, if you define models like this: - - ```javascript - App.Post = DS.Model.extend({ - comments: DS.hasMany('message') - }); - - App.Message = DS.Model.extend({ - owner: DS.belongsTo('post') - }); - ``` - - App.Post.inverseFor('comments') -> {type: App.Message, name:'owner', kind:'belongsTo'} - App.Message.inverseFor('owner') -> {type: App.Post, name:'comments', kind:'hasMany'} - - @method inverseFor - @static - @param {String} name the name of the relationship - @return {Object} the inverse relationship, or null - */ - inverseFor: function(name) { - var inverseMap = ember$data$lib$system$relationships$ext$$get(this, 'inverseMap'); - if (inverseMap[name]) { - return inverseMap[name]; - } else { - var inverse = this._findInverseFor(name); - inverseMap[name] = inverse; - return inverse; - } - }, - - //Calculate the inverse, ignoring the cache - _findInverseFor: function(name) { - - var inverseType = this.typeForRelationship(name); - if (!inverseType) { - return null; - } - - //If inverse is manually specified to be null, like `comments: DS.hasMany('message', {inverse: null})` - var options = this.metaForProperty(name).options; - if (options.inverse === null) { return null; } - - var inverseName, inverseKind, inverse; - - //If inverse is specified manually, return the inverse - if (options.inverse) { - inverseName = options.inverse; - inverse = Ember.get(inverseType, 'relationshipsByName').get(inverseName); - - - inverseKind = inverse.kind; - } else { - //No inverse was specified manually, we need to use a heuristic to guess one - var possibleRelationships = findPossibleInverses(this, inverseType); - - if (possibleRelationships.length === 0) { return null; } - - var filteredRelationships = ember$data$lib$system$relationships$ext$$filter.call(possibleRelationships, function(possibleRelationship) { - var optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options; - return name === optionsForRelationship.inverse; - }); - - - if (filteredRelationships.length === 1 ) { - possibleRelationships = filteredRelationships; - } - - - inverseName = possibleRelationships[0].name; - inverseKind = possibleRelationships[0].kind; - } - - function findPossibleInverses(type, inverseType, relationshipsSoFar) { - var possibleRelationships = relationshipsSoFar || []; - - var relationshipMap = ember$data$lib$system$relationships$ext$$get(inverseType, 'relationships'); - if (!relationshipMap) { return; } - - var relationships = relationshipMap.get(type); - - relationships = ember$data$lib$system$relationships$ext$$filter.call(relationships, function(relationship) { - var optionsForRelationship = inverseType.metaForProperty(relationship.name).options; - - if (!optionsForRelationship.inverse){ - return true; - } - - return name === optionsForRelationship.inverse; - }); - - if (relationships) { - possibleRelationships.push.apply(possibleRelationships, relationships); - } - - //Recurse to support polymorphism - if (type.superclass) { - findPossibleInverses(type.superclass, inverseType, possibleRelationships); - } - - return possibleRelationships; - } - - return { - type: inverseType, - name: inverseName, - kind: inverseKind - }; - }, - - /** - The model's relationships as a map, keyed on the type of the - relationship. The value of each entry is an array containing a descriptor - for each relationship with that type, describing the name of the relationship - as well as the type. - - For example, given the following model definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - posts: DS.hasMany('post') - }); - ``` - - This computed property would return a map describing these - relationships, like this: - - ```javascript - var relationships = Ember.get(App.Blog, 'relationships'); - relationships.get(App.User); - //=> [ { name: 'users', kind: 'hasMany' }, - // { name: 'owner', kind: 'belongsTo' } ] - relationships.get(App.Post); - //=> [ { name: 'posts', kind: 'hasMany' } ] - ``` - - @property relationships - @static - @type Ember.Map - @readOnly - */ - - relationships: ember$data$lib$system$relationships$ext$$relationshipsDescriptor, - - /** - A hash containing lists of the model's relationships, grouped - by the relationship kind. For example, given a model with this - definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - var relationshipNames = Ember.get(App.Blog, 'relationshipNames'); - relationshipNames.hasMany; - //=> ['users', 'posts'] - relationshipNames.belongsTo; - //=> ['owner'] - ``` - - @property relationshipNames - @static - @type Object - @readOnly - */ - relationshipNames: Ember.computed(function() { - var names = { - hasMany: [], - belongsTo: [] - }; - - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - names[meta.kind].push(name); - } - }); - - return names; - }), - - /** - An array of types directly related to a model. Each type will be - included once, regardless of the number of relationships it has with - the model. - - For example, given a model with this definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - var relatedTypes = Ember.get(App.Blog, 'relatedTypes'); - //=> [ App.User, App.Post ] - ``` - - @property relatedTypes - @static - @type Ember.Array - @readOnly - */ - relatedTypes: ember$data$lib$system$relationships$ext$$relatedTypesDescriptor, - - /** - A map whose keys are the relationships of a model and whose values are - relationship descriptors. - - For example, given a model with this - definition: - - ```javascript - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post') - }); - ``` - - This property would contain the following: - - ```javascript - var relationshipsByName = Ember.get(App.Blog, 'relationshipsByName'); - relationshipsByName.get('users'); - //=> { key: 'users', kind: 'hasMany', type: App.User } - relationshipsByName.get('owner'); - //=> { key: 'owner', kind: 'belongsTo', type: App.User } - ``` - - @property relationshipsByName - @static - @type Ember.Map - @readOnly - */ - relationshipsByName: ember$data$lib$system$relationships$ext$$relationshipsByNameDescriptor, - - /** - A map whose keys are the fields of the model and whose values are strings - describing the kind of the field. A model's fields are the union of all of its - attributes and relationships. - - For example: - - ```javascript - - App.Blog = DS.Model.extend({ - users: DS.hasMany('user'), - owner: DS.belongsTo('user'), - - posts: DS.hasMany('post'), - - title: DS.attr('string') - }); - - var fields = Ember.get(App.Blog, 'fields'); - fields.forEach(function(kind, field) { - console.log(field, kind); - }); - - // prints: - // users, hasMany - // owner, belongsTo - // posts, hasMany - // title, attribute - ``` - - @property fields - @static - @type Ember.Map - @readOnly - */ - fields: Ember.computed(function() { - var map = ember$data$lib$system$map$$Map.create(); - - this.eachComputedProperty(function(name, meta) { - if (meta.isRelationship) { - map.set(name, meta.kind); - } else if (meta.isAttribute) { - map.set(name, 'attribute'); - } - }); - - return map; - }).readOnly(), - - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - @method eachRelationship - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship: function(callback, binding) { - ember$data$lib$system$relationships$ext$$get(this, 'relationshipsByName').forEach(function(relationship, name) { - callback.call(binding, name, relationship); - }); - }, - - /** - Given a callback, iterates over each of the types related to a model, - invoking the callback with the related type's class. Each type will be - returned just once, regardless of how many different relationships it has - with a model. - - @method eachRelatedType - @static - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelatedType: function(callback, binding) { - ember$data$lib$system$relationships$ext$$get(this, 'relatedTypes').forEach(function(type) { - callback.call(binding, type); - }); - }, - - determineRelationshipType: function(knownSide) { - var knownKey = knownSide.key; - var knownKind = knownSide.kind; - var inverse = this.inverseFor(knownKey); - var key, otherKind; - - if (!inverse) { - return knownKind === 'belongsTo' ? 'oneToNone' : 'manyToNone'; - } - - key = inverse.name; - otherKind = inverse.kind; - - if (otherKind === 'belongsTo') { - return knownKind === 'belongsTo' ? 'oneToOne' : 'manyToOne'; - } else { - return knownKind === 'belongsTo' ? 'oneToMany' : 'manyToMany'; - } - } - - }); - - ember$data$lib$system$model$model$$default.reopen({ - /** - Given a callback, iterates over each of the relationships in the model, - invoking the callback with the name of each relationship and its relationship - descriptor. - - @method eachRelationship - @param {Function} callback the callback to invoke - @param {any} binding the value to which the callback's `this` should be bound - */ - eachRelationship: function(callback, binding) { - this.constructor.eachRelationship(callback, binding); - }, - - relationshipFor: function(name) { - return ember$data$lib$system$relationships$ext$$get(this.constructor, 'relationshipsByName').get(name); - }, - - inverseFor: function(key) { - return this.constructor.inverseFor(key); - } - - }); - /** - Ember Data - @module ember-data - @main ember-data - */ - - // support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast - Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve; - - - ember$data$lib$core$$default.Store = ember$data$lib$system$store$$Store; - ember$data$lib$core$$default.PromiseArray = ember$data$lib$system$promise_proxies$$PromiseArray; - ember$data$lib$core$$default.PromiseObject = ember$data$lib$system$promise_proxies$$PromiseObject; - - ember$data$lib$core$$default.PromiseManyArray = ember$data$lib$system$promise_proxies$$PromiseManyArray; - - ember$data$lib$core$$default.Model = ember$data$lib$system$model$model$$default; - ember$data$lib$core$$default.RootState = ember$data$lib$system$model$states$$default; - ember$data$lib$core$$default.attr = ember$data$lib$system$model$attributes$$default; - ember$data$lib$core$$default.Errors = ember$data$lib$system$model$errors$$default; - - ember$data$lib$core$$default.Adapter = ember$data$lib$system$adapter$$Adapter; - ember$data$lib$core$$default.InvalidError = ember$data$lib$system$adapter$$InvalidError; - - ember$data$lib$core$$default.DebugAdapter = ember$data$lib$system$debug$$default; - - ember$data$lib$core$$default.RecordArray = ember$data$lib$system$record_arrays$record_array$$default; - ember$data$lib$core$$default.FilteredRecordArray = ember$data$lib$system$record_arrays$filtered_record_array$$default; - ember$data$lib$core$$default.AdapterPopulatedRecordArray = ember$data$lib$system$record_arrays$adapter_populated_record_array$$default; - ember$data$lib$core$$default.ManyArray = ember$data$lib$system$record_arrays$many_array$$default; - - ember$data$lib$core$$default.RecordArrayManager = ember$data$lib$system$record_array_manager$$default; - - ember$data$lib$core$$default.RESTAdapter = ember$data$lib$adapters$rest_adapter$$default; - ember$data$lib$core$$default.FixtureAdapter = ember$data$lib$adapters$fixture_adapter$$default; - - ember$data$lib$core$$default.RESTSerializer = ember$data$lib$serializers$rest_serializer$$default; - ember$data$lib$core$$default.JSONSerializer = ember$data$lib$serializers$json_serializer$$default; - - ember$data$lib$core$$default.Transform = ember$data$lib$transforms$base$$default; - ember$data$lib$core$$default.DateTransform = ember$data$lib$transforms$date$$default; - ember$data$lib$core$$default.StringTransform = ember$data$lib$transforms$string$$default; - ember$data$lib$core$$default.NumberTransform = ember$data$lib$transforms$number$$default; - ember$data$lib$core$$default.BooleanTransform = ember$data$lib$transforms$boolean$$default; - - ember$data$lib$core$$default.ActiveModelAdapter = activemodel$adapter$lib$system$active_model_adapter$$default; - ember$data$lib$core$$default.ActiveModelSerializer = activemodel$adapter$lib$system$active_model_serializer$$default; - ember$data$lib$core$$default.EmbeddedRecordsMixin = ember$data$lib$serializers$embedded_records_mixin$$default; - - ember$data$lib$core$$default.belongsTo = ember$data$lib$system$relationships$belongs_to$$default; - ember$data$lib$core$$default.hasMany = ember$data$lib$system$relationships$has_many$$default; - - ember$data$lib$core$$default.Relationship = ember$data$lib$system$relationships$state$relationship$$default; - - ember$data$lib$core$$default.ContainerProxy = ember$data$lib$system$container_proxy$$default; - - ember$data$lib$core$$default._setupContainer = ember$data$lib$setup$container$$default; - - Ember.lookup.DS = ember$data$lib$core$$default; - - var ember$data$lib$main$$default = ember$data$lib$core$$default; -}).call(this); - -//# sourceMappingURL=ember-data.js.map - diff --git a/assets/scripts/vendor/ember.js b/assets/scripts/vendor/ember.js deleted file mode 100644 index e57aab16..00000000 --- a/assets/scripts/vendor/ember.js +++ /dev/null @@ -1,50415 +0,0 @@ -/*! - * @overview Ember - JavaScript Application Framework - * @copyright Copyright 2011-2014 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.9.1 - */ - -(function() { -var enifed, requireModule, eriuqer, requirejs, Ember; - -(function() { - Ember = this.Ember = this.Ember || {}; - if (typeof Ember === 'undefined') { Ember = {}; }; - function UNDEFINED() { } - - if (typeof Ember.__loader === 'undefined') { - var registry = {}, seen = {}; - - enifed = function(name, deps, callback) { - registry[name] = { deps: deps, callback: callback }; - }; - - 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", - ["container/container","exports"], - function(__dependency1__, __exports__) { - "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; - } - - - var Container = __dependency1__["default"]; - - __exports__["default"] = Container; - }); -enifed("container/container", - ["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var emberKeys = __dependency2__["default"]; - var dictionary = __dependency3__["default"]; - - // A lightweight container that helps to assemble and decouple components. - // Public api for the container is still in flux. - // The public api, specified on the application namespace should be considered the stable api. - function Container(parent) { - this.parent = parent; - this.children = []; - - this.resolver = parent && parent.resolver || function() {}; - - this.registry = dictionary(parent ? parent.registry : null); - this.cache = dictionary(parent ? parent.cache : null); - this.factoryCache = dictionary(parent ? parent.factoryCache : null); - this.resolveCache = dictionary(parent ? parent.resolveCache : null); - this.typeInjections = dictionary(parent ? parent.typeInjections : null); - this.injections = dictionary(null); - this.normalizeCache = dictionary(null); - - this.factoryTypeInjections = dictionary(parent ? parent.factoryTypeInjections : null); - this.factoryInjections = dictionary(null); - - this._options = dictionary(parent ? parent._options : null); - this._typeOptions = dictionary(parent ? parent._typeOptions : null); - } - - Container.prototype = { - - /** - @property parent - @type Container - @default null - */ - parent: null, - - /** - @property children - @type Array - @default [] - */ - children: null, - - /** - @property resolver - @type function - */ - resolver: null, - - /** - @property registry - @type InheritingDict - */ - registry: null, - - /** - @property cache - @type InheritingDict - */ - cache: null, - - /** - @property typeInjections - @type InheritingDict - */ - typeInjections: null, - - /** - @property injections - @type Object - @default {} - */ - injections: null, - - /** - @private - - @property _options - @type InheritingDict - @default null - */ - _options: null, - - /** - @private - - @property _typeOptions - @type InheritingDict - */ - _typeOptions: null, - - /** - Returns a new child of the current container. These children are configured - to correctly inherit from the current container. - - @method child - @return {Container} - */ - child: function() { - var container = new Container(this); - this.children.push(container); - return container; - }, - - /** - Registers a factory for later injection. - - Example: - - ```javascript - var container = new Container(); - - container.register('model:user', Person, {singleton: false }); - container.register('fruit:favorite', Orange); - container.register('communication:main', Email, {singleton: false}); - ``` - - @method register - @param {String} fullName - @param {Function} factory - @param {Object} options - */ - register: function(fullName, factory, options) { - Ember.assert('fullName must be a proper full name', validateFullName(fullName)); - - if (factory === undefined) { - throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); - } - - var normalizedName = this.normalize(fullName); - - if (normalizedName in this.cache) { - throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); - } - - this.registry[normalizedName] = factory; - this._options[normalizedName] = (options || {}); - }, - - /** - Unregister a fullName - - ```javascript - var container = new Container(); - container.register('model:user', User); - - container.lookup('model:user') instanceof User //=> true - - container.unregister('model:user') - container.lookup('model:user') === undefined //=> true - ``` - - @method unregister - @param {String} fullName - */ - unregister: function(fullName) { - Ember.assert('fullName must be a proper full name', validateFullName(fullName)); - - var normalizedName = this.normalize(fullName); - - delete this.registry[normalizedName]; - delete this.cache[normalizedName]; - delete this.factoryCache[normalizedName]; - delete this.resolveCache[normalizedName]; - delete this._options[normalizedName]; - }, - - /** - Given a fullName return the corresponding factory. - - By default `resolve` will retrieve the factory from - its container's registry. - - ```javascript - var container = new Container(); - container.register('api:twitter', Twitter); - - container.resolve('api:twitter') // => Twitter - ``` - - Optionally the container 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 container = new Container(); - container.resolver = function(fullName) { - // lookup via the module system of choice - }; - - // the twitter factory is added to the module system - container.resolve('api:twitter') // => Twitter - ``` - - @method resolve - @param {String} fullName - @return {Function} fullName's factory - */ - resolve: function(fullName) { - Ember.assert('fullName must be a proper full name', validateFullName(fullName)); - return resolve(this, this.normalize(fullName)); - }, - - /** - 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 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 container = new Container(); - container.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 container = new Container(); - container.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.assert('fullName must be a proper full name', validateFullName(fullName)); - return lookup(this, this.normalize(fullName), options); - }, - - /** - Given a fullName return the corresponding factory. - - @method lookupFactory - @param {String} fullName - @return {any} - */ - lookupFactory: function(fullName) { - Ember.assert('fullName must be a proper full name', validateFullName(fullName)); - return factoryFor(this, this.normalize(fullName)); - }, - - /** - 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.assert('fullName must be a proper full name', validateFullName(fullName)); - return has(this, this.normalize(fullName)); - }, - - /** - Allow registering options for all factories of a type. - - ```javascript - var container = new Container(); - - // if all of type `connection` must not be singletons - container.optionsForType('connection', { singleton: false }); - - container.register('connection:twitter', TwitterConnection); - container.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) { - if (this.parent) { illegalChildOperation('optionsForType'); } - - this._typeOptions[type] = options; - }, - - /** - @method options - @param {String} fullName - @param {Object} options - */ - options: function(fullName, options) { - options = options || {}; - var normalizedName = this.normalize(fullName); - this._options[normalizedName] = options; - }, - - /** - 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 container = new Container(); - - container.register('router:main', Router); - container.register('controller:user', UserController); - container.register('controller:post', PostController); - - container.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.assert('fullName must be a proper full name', validateFullName(fullName)); - - if (this.parent) { illegalChildOperation('typeInjection'); } - - var fullNameType = fullName.split(':')[0]; - if (fullNameType === type) { - throw new Error('Cannot inject a `' + fullName + - '` on other ' + type + - '(s). Register the `' + fullName + - '` as a different type and perform the typeInjection.'); - } - - addTypeInjection(this.typeInjections, type, property, 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 container = new Container(); - - container.register('source:main', Source); - container.register('model:user', User); - container.register('model:post', Post); - - // injecting one fullName on another fullName - // eg. each user model gets a post model - container.injection('model:user', 'post', 'model:post'); - - // injecting one fullName on another type - container.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) { - if (this.parent) { illegalChildOperation('injection'); } - - validateFullName(injectionName); - var normalizedInjectionName = this.normalize(injectionName); - - if (fullName.indexOf(':') === -1) { - return this.typeInjection(fullName, property, normalizedInjectionName); - } - - Ember.assert('fullName must be a proper full name', validateFullName(fullName)); - var normalizedName = this.normalize(fullName); - - if (this.cache[normalizedName]) { - throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + - normalizedName + "', '" + - property + "', '" + - injectionName + "')"); - } - - addInjection(initRules(this.injections, normalizedName), property, 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 container = new Container(); - - container.register('store:main', SomeStore); - - container.factoryTypeInjection('model', 'store', 'store:main'); - - var store = container.lookup('store:main'); - var UserFactory = container.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) { - if (this.parent) { illegalChildOperation('factoryTypeInjection'); } - - addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); - }, - - /** - Defines factory injection rules. - - Similar to regular injection rules, but are run against factories, via - `Container#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 container = new Container(); - - container.register('store:main', Store); - container.register('store:secondary', OtherStore); - container.register('model:user', User); - container.register('model:post', Post); - - // injecting one fullName on another type - container.factoryInjection('model', 'store', 'store:main'); - - // injecting one fullName on another fullName - container.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) { - if (this.parent) { illegalChildOperation('injection'); } - - var normalizedName = this.normalize(fullName); - var normalizedInjectionName = this.normalize(injectionName); - - validateFullName(injectionName); - - if (fullName.indexOf(':') === -1) { - return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); - } - - Ember.assert('fullName must be a proper full name', validateFullName(fullName)); - - if (this.factoryCache[normalizedName]) { - throw new Error('Attempted to register a factoryInjection for a type that has already ' + - 'been looked up. (\'' + normalizedName + '\', \'' + property + '\', \'' + injectionName + '\')'); - } - - addInjection(initRules(this.factoryInjections, normalizedName), property, normalizedInjectionName); - }, - - /** - A depth first traversal, destroying the container, its descendant containers and all - their managed objects. - - @method destroy - */ - destroy: function() { - for (var i = 0, length = this.children.length; i < length; i++) { - this.children[i].destroy(); - } - - this.children = []; - - eachDestroyable(this, function(item) { - item.destroy(); - }); - - this.parent = undefined; - this.isDestroyed = true; - }, - - /** - @method reset - */ - reset: function() { - for (var i = 0, length = this.children.length; i < length; i++) { - resetCache(this.children[i]); - } - - resetCache(this); - } - }; - - function resolve(container, normalizedName) { - var cached = container.resolveCache[normalizedName]; - if (cached) { return cached; } - - var resolved = container.resolver(normalizedName) || container.registry[normalizedName]; - container.resolveCache[normalizedName] = resolved; - - return resolved; - } - - function has(container, fullName){ - if (container.cache[fullName]) { - return true; - } - - return container.resolve(fullName) !== undefined; - } - - 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 (isSingleton(container, fullName) && options.singleton !== false) { - container.cache[fullName] = value; - } - - return value; - } - - function illegalChildOperation(operation) { - throw new Error(operation + ' is not currently supported on child containers'); - } - - function isSingleton(container, fullName) { - var singleton = option(container, fullName, 'singleton'); - - return singleton !== false; - } - - function buildInjections(container, injections) { - var hash = {}; - - if (!injections) { return hash; } - - validateInjections(container, injections); - - var injection; - - for (var i = 0, length = injections.length; i < length; i++) { - injection = injections[i]; - hash[injection.property] = lookup(container, injection.fullName); - } - - return hash; - } - - function validateInjections(container, injections) { - if (!injections) { return; } - - var fullName; - - for (var i = 0, length = injections.length; i < length; i++) { - fullName = injections[i].fullName; - - if (!container.has(fullName)) { - throw new Error('Attempting to inject an unknown injection: `' + fullName + '`'); - } - } - } - - function option(container, fullName, optionName) { - var options = container._options[fullName]; - - if (options && options[optionName] !== undefined) { - return options[optionName]; - } - - var type = fullName.split(':')[0]; - options = container._typeOptions[type]; - - if (options) { - return options[optionName]; - } - } - - function factoryFor(container, fullName) { - var cache = container.factoryCache; - if (cache[fullName]) { - return cache[fullName]; - } - var factory = container.resolve(fullName); - if (factory === undefined) { return; } - - var type = fullName.split(':')[0]; - if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) { - // 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 = container.makeToString(factory, fullName); - - var injectedFactory = factory.extend(injections); - injectedFactory.reopenClass(factoryInjections); - - cache[fullName] = injectedFactory; - - return injectedFactory; - } - } - - function injectionsFor(container, fullName) { - var splitName = fullName.split(':'); - var type = splitName[0]; - var injections = []; - - injections = injections.concat(container.typeInjections[type] || []); - injections = injections.concat(container.injections[fullName] || []); - - injections = buildInjections(container, injections); - injections._debugContainerKey = fullName; - injections.container = container; - - return injections; - } - - function factoryInjectionsFor(container, fullName) { - var splitName = fullName.split(':'); - var type = splitName[0]; - var factoryInjections = []; - - factoryInjections = factoryInjections.concat(container.factoryTypeInjections[type] || []); - factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []); - - factoryInjections = buildInjections(container, factoryInjections); - factoryInjections._debugContainerKey = fullName; - - return factoryInjections; - } - - function normalizeInjectionsHash(hash) { - var injections = []; - - for (var key in hash) { - if (hash.hasOwnProperty(key)) { - Ember.assert("Expected a proper full name, given '" + hash[key] + "'", validateFullName(hash[key])); - - addInjection(injections, key, hash[key]); - } - } - - return injections; - } - - function instantiate(container, fullName) { - var factory = factoryFor(container, fullName); - var lazyInjections; - - if (option(container, 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.'); - } - - - 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(cache); - var key, value; - - for (var i = 0, l = keys.length; i < l; i++) { - key = keys[i]; - value = cache[key]; - - if (option(container, key, 'instantiate') !== false) { - callback(value); - } - } - } - - function resetCache(container) { - eachDestroyable(container, function(value) { - value.destroy(); - }); - - container.cache.dict = dictionary(null); - } - - function addTypeInjection(rules, type, property, fullName) { - var injections = rules[type]; - - if (!injections) { - injections = []; - rules[type] = injections; - } - - injections.push({ - property: property, - fullName: fullName - }); - } - - var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; - function validateFullName(fullName) { - if (!VALID_FULL_NAME_REGEXP.test(fullName)) { - throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); - } - return true; - } - - function initRules(rules, factoryName) { - return rules[factoryName] || (rules[factoryName] = []); - } - - function addInjection(injections, property, injectionName) { - injections.push({ - property: property, - fullName: injectionName - }); - } - - __exports__["default"] = Container; - }); -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("ember-application", - ["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { - "use strict"; - var Ember = __dependency1__["default"]; - var runLoadHooks = __dependency2__.runLoadHooks; - - /** - Ember Application - - @module ember - @submodule ember-application - @requires ember-views, ember-routing - */ - - var Resolver = __dependency3__.Resolver; - var DefaultResolver = __dependency3__["default"]; - var Application = __dependency4__["default"]; - // side effect of extending ControllerMixin - - Ember.Application = Application; - Ember.Resolver = Resolver; - Ember.DefaultResolver = DefaultResolver; - - runLoadHooks('Ember.Application', Application); - }); -enifed("ember-application/ext/controller", - ["ember-metal/core","ember-metal/property_get","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-application - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var get = __dependency2__.get; - var EmberError = __dependency3__["default"]; - var inspect = __dependency4__.inspect; - var computed = __dependency5__.computed; - var ControllerMixin = __dependency6__["default"]; - var meta = __dependency4__.meta; - var controllerFor = __dependency7__["default"]; - - function verifyNeedsDependencies(controller, container, needs) { - var dependency, i, l; - var missing = []; - - for (i=0, l=needs.length; i 1 ? 'they' : 'it') + " could not be found"); - } - } - - var defaultControllersComputedProperty = computed(function() { - var controller = this; - - return { - needs: get(controller, 'needs'), - container: get(controller, 'container'), - unknownProperty: function(controllerName) { - var needs = this.needs; - var dependency, i, l; - - for (i=0, l=needs.length; i 0) { - Ember.assert(' `' + inspect(this) + ' specifies `needs`, but does ' + - "not have a container. Please ensure this controller was " + - "instantiated with a container.", - this.container || meta(this, false).descs.controllers !== defaultControllersComputedProperty); - - if (this.container) { - verifyNeedsDependencies(this, this.container, needs); - } - - // if needs then initialize controllers proxy - get(this, 'controllers'); - } - - this._super.apply(this, arguments); - }, - - /** - @method controllerFor - @see {Ember.Route#controllerFor} - @deprecated Use `needs` instead - */ - controllerFor: function(controllerName) { - Ember.deprecate("Controller#controllerFor is deprecated, please use Controller#needs instead"); - return controllerFor(get(this, 'container'), controllerName); - }, - - /** - Stores the instances of other controllers available from within - this controller. Any controller listed by name in the `needs` - property will be accessible by name through this property. - - ```javascript - App.CommentsController = Ember.ArrayController.extend({ - needs: ['post'], - postTitle: function(){ - var currentPost = this.get('controllers.post'); // instance of App.PostController - return currentPost.get('title'); - }.property('controllers.post.title') - }); - ``` - - @see {Ember.ControllerMixin#needs} - @property {Object} controllers - @default null - */ - controllers: defaultControllersComputedProperty - }); - - __exports__["default"] = ControllerMixin; - }); -enifed("ember-application/system/application", - ["dag-map","container/container","ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-extension-support/container_debug_adapter","ember-metal/core","ember-handlebars-compiler","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__, __dependency29__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-application - */ - var DAG = __dependency1__["default"]; - var Container = __dependency2__["default"]; - - - var Ember = __dependency3__["default"]; - // Ember.FEATURES, Ember.deprecate, Ember.assert, Ember.libraries, LOG_VERSION, Namespace, BOOTED - var get = __dependency4__.get; - var set = __dependency5__.set; - var runLoadHooks = __dependency6__.runLoadHooks; - var Namespace = __dependency7__["default"]; - var DeferredMixin = __dependency8__["default"]; - var DefaultResolver = __dependency9__["default"]; - var create = __dependency10__.create; - var run = __dependency11__["default"]; - var canInvoke = __dependency12__.canInvoke; - var Controller = __dependency13__["default"]; - var EnumerableUtils = __dependency14__["default"]; - var ObjectController = __dependency15__["default"]; - var ArrayController = __dependency16__["default"]; - var SelectView = __dependency17__["default"]; - var EventDispatcher = __dependency18__["default"]; - var jQuery = __dependency19__["default"]; - var Route = __dependency20__["default"]; - var Router = __dependency21__["default"]; - var HashLocation = __dependency22__["default"]; - var HistoryLocation = __dependency23__["default"]; - var AutoLocation = __dependency24__["default"]; - var NoneLocation = __dependency25__["default"]; - var BucketCache = __dependency26__["default"]; - - // this is technically incorrect (per @wycats) - // it should work properly with: - // `import ContainerDebugAdapter from 'ember-extension-support/container_debug_adapter';` but - // es6-module-transpiler 0.4.0 eagerly grabs the module (which is undefined) - - var ContainerDebugAdapter = __dependency27__["default"]; - - var K = __dependency28__.K; - var EmberHandlebars = __dependency29__["default"]; - - function props(obj) { - var properties = []; - - for (var key in obj) { - properties.push(key); - } - - return properties; - } - - /** - An instance of `Ember.Application` is the starting point for every Ember - application. It helps to instantiate, initialize and coordinate the many - objects that make up your app. - - Each Ember app has one and only one `Ember.Application` object. In fact, the - very first thing you should do in your application is create the instance: - - ```javascript - window.App = Ember.Application.create(); - ``` - - Typically, the application object is the only global variable. All other - classes in your app should be properties on the `Ember.Application` instance, - which highlights its first role: a global namespace. - - For example, if you define a view class, it might look like this: - - ```javascript - App.MyView = Ember.View.extend(); - ``` - - By default, calling `Ember.Application.create()` will automatically initialize - your application by calling the `Ember.Application.initialize()` method. If - you need to delay initialization, you can call your app's `deferReadiness()` - method. When you are ready for your app to be initialized, call its - `advanceReadiness()` method. - - You can define a `ready` method on the `Ember.Application` instance, which - will be run by Ember when the application is initialized. - - Because `Ember.Application` inherits from `Ember.Namespace`, any classes - you create will have useful string representations when calling `toString()`. - See the `Ember.Namespace` documentation for more information. - - While you can think of your `Ember.Application` as a container that holds the - other classes in your application, there are several other responsibilities - going on under-the-hood that you may want to understand. - - ### Event Delegation - - Ember uses a technique called _event delegation_. This allows the framework - to set up a global, shared event listener instead of requiring each view to - do it manually. For example, instead of each view registering its own - `mousedown` listener on its associated element, Ember sets up a `mousedown` - listener on the `body`. - - If a `mousedown` event occurs, Ember will look at the target of the event and - start walking up the DOM node tree, finding corresponding views and invoking - their `mouseDown` method as it goes. - - `Ember.Application` has a number of default events that it listens for, as - well as a mapping from lowercase events to camel-cased view method names. For - example, the `keypress` event causes the `keyPress` method on the view to be - called, the `dblclick` event causes `doubleClick` to be called, and so on. - - If there is a bubbling browser event that Ember does not listen for by - default, you can specify custom events and their corresponding view method - names by setting the application's `customEvents` property: - - ```javascript - var App = Ember.Application.create({ - customEvents: { - // add support for the paste event - paste: 'paste' - } - }); - ``` - - By default, the application sets up these event listeners on the document - body. However, in cases where you are embedding an Ember application inside - an existing page, you may want it to set up the listeners on an element - inside the body. - - For example, if only events inside a DOM element with the ID of `ember-app` - should be delegated, set your application's `rootElement` property: - - ```javascript - var App = Ember.Application.create({ - rootElement: '#ember-app' - }); - ``` - - The `rootElement` can be either a DOM element or a jQuery-compatible selector - string. Note that *views appended to the DOM outside the root element will - not receive events.* If you specify a custom root element, make sure you only - append views inside it! - - To learn more about the advantages of event delegation and the Ember view - layer, and a list of the event listeners that are setup by default, visit the - [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). - - ### Initializers - - Libraries on top of Ember can add initializers, like so: - - ```javascript - Ember.Application.initializer({ - name: 'api-adapter', - - initialize: function(container, application) { - application.register('api-adapter:main', ApiAdapter); - } - }); - ``` - - Initializers provide an opportunity to access the container, which - organizes the different components of an Ember application. Additionally - they provide a chance to access the instantiated application. Beyond - being used for libraries, initializers are also a great way to organize - dependency injection or setup in your own application. - - ### Routing - - In addition to creating your application's router, `Ember.Application` is - also responsible for telling the router when to start routing. Transitions - between routes can be logged with the `LOG_TRANSITIONS` flag, and more - detailed intra-transition logging can be logged with - the `LOG_TRANSITIONS_INTERNAL` flag: - - ```javascript - var App = Ember.Application.create({ - LOG_TRANSITIONS: true, // basic logging of successful transitions - LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps - }); - ``` - - By default, the router will begin trying to translate the current URL into - application state once the browser emits the `DOMContentReady` event. If you - need to defer routing, you can call the application's `deferReadiness()` - method. Once routing can begin, call the `advanceReadiness()` method. - - If there is any setup required before routing begins, you can implement a - `ready()` method on your app that will be invoked immediately before routing - begins. - ``` - - @class Application - @namespace Ember - @extends Ember.Namespace - */ - - var Application = Namespace.extend(DeferredMixin, { - _suppressDeferredDeprecation: true, - - /** - The root DOM element of the Application. This can be specified as an - element or a - [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). - - This is the element that will be passed to the Application's, - `eventDispatcher`, which sets up the listeners for event delegation. Every - view in your application should be a child of the element you specify here. - - @property rootElement - @type DOMElement - @default 'body' - */ - rootElement: 'body', - - /** - The `Ember.EventDispatcher` responsible for delegating events to this - application's views. - - The event dispatcher is created by the application at initialization time - and sets up event listeners on the DOM element described by the - application's `rootElement` property. - - See the documentation for `Ember.EventDispatcher` for more information. - - @property eventDispatcher - @type Ember.EventDispatcher - @default null - */ - eventDispatcher: null, - - /** - The DOM events for which the event dispatcher should listen. - - By default, the application's `Ember.EventDispatcher` listens - for a set of standard DOM events, such as `mousedown` and - `keyup`, and delegates them to your application's `Ember.View` - instances. - - If you would like additional bubbling events to be delegated to your - views, set your `Ember.Application`'s `customEvents` property - to a hash containing the DOM event name as the key and the - corresponding view method name as the value. For example: - - ```javascript - var App = Ember.Application.create({ - customEvents: { - // add support for the paste event - paste: 'paste' - } - }); - ``` - - @property customEvents - @type Object - @default null - */ - customEvents: null, - - // Start off the number of deferrals at 1. This will be - // decremented by the Application's own `initialize` method. - _readinessDeferrals: 1, - - init: function() { - if (!this.$) { - this.$ = jQuery; - } - this.__container__ = this.buildContainer(); - - this.Router = this.defaultRouter(); - - this._super(); - - this.scheduleInitialize(); - - Ember.libraries.registerCoreLibrary('Handlebars' + (EmberHandlebars.compile ? '' : '-runtime'), EmberHandlebars.VERSION); - Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); - - if ( Ember.LOG_VERSION ) { - Ember.LOG_VERSION = false; // we only need to see this once per Application#init - - var nameLengths = EnumerableUtils.map(Ember.libraries, function(item) { - return get(item, "name.length"); - }); - - var maxNameLength = Math.max.apply(this, nameLengths); - - Ember.debug('-------------------------------'); - Ember.libraries.each(function(name, version) { - var spaces = new Array(maxNameLength - name.length + 1).join(" "); - Ember.debug([name, spaces, ' : ', version].join("")); - }); - Ember.debug('-------------------------------'); - } - }, - - /** - Build the container for the current application. - - Also register a default application view in case the application - itself does not. - - @private - @method buildContainer - @return {Ember.Container} the configured container - */ - buildContainer: function() { - var container = this.__container__ = Application.buildContainer(this); - - return container; - }, - - /** - If the application has not opted out of routing and has not explicitly - defined a router, supply a default router for the application author - to configure. - - This allows application developers to do: - - ```javascript - var App = Ember.Application.create(); - - App.Router.map(function() { - this.resource('posts'); - }); - ``` - - @private - @method defaultRouter - @return {Ember.Router} the default router - */ - - defaultRouter: function() { - if (this.Router === false) { return; } - var container = this.__container__; - - if (this.Router) { - container.unregister('router:main'); - container.register('router:main', this.Router); - } - - return container.lookupFactory('router:main'); - }, - - /** - Automatically initialize the application once the DOM has - become ready. - - The initialization itself is scheduled on the actions queue - which ensures that application loading finishes before - booting. - - If you are asynchronously loading code, you should call - `deferReadiness()` to defer booting, and then call - `advanceReadiness()` once all of your code has finished - loading. - - @private - @method scheduleInitialize - */ - scheduleInitialize: function() { - var self = this; - - if (!this.$ || this.$.isReady) { - run.schedule('actions', self, '_initialize'); - } else { - this.$().ready(function runInitialize() { - run(self, '_initialize'); - }); - } - }, - - /** - Use this to defer readiness until some condition is true. - - Example: - - ```javascript - var App = Ember.Application.create(); - - App.deferReadiness(); - // Ember.$ is a reference to the jQuery object/function - Ember.$.getJSON('/auth-token', function(token) { - App.token = token; - App.advanceReadiness(); - }); - ``` - - This allows you to perform asynchronous setup logic and defer - booting your application until the setup has finished. - - However, if the setup requires a loading UI, it might be better - to use the router for this purpose. - - @method deferReadiness - */ - deferReadiness: function() { - Ember.assert("You must call deferReadiness on an instance of Ember.Application", this instanceof Application); - Ember.assert("You cannot defer readiness since the `ready()` hook has already been called.", this._readinessDeferrals > 0); - this._readinessDeferrals++; - }, - - /** - Call `advanceReadiness` after any asynchronous setup logic has completed. - Each call to `deferReadiness` must be matched by a call to `advanceReadiness` - or the application will never become ready and routing will not begin. - - @method advanceReadiness - @see {Ember.Application#deferReadiness} - */ - advanceReadiness: function() { - Ember.assert("You must call advanceReadiness on an instance of Ember.Application", this instanceof Application); - this._readinessDeferrals--; - - if (this._readinessDeferrals === 0) { - run.once(this, this.didBecomeReady); - } - }, - - /** - Registers a factory that can be used for dependency injection (with - `App.inject`) or for service lookup. Each factory is registered with - a full name including two parts: `type:name`. - - A simple example: - - ```javascript - var App = Ember.Application.create(); - - App.Orange = Ember.Object.extend(); - App.register('fruit:favorite', App.Orange); - ``` - - Ember will resolve factories from the `App` namespace automatically. - For example `App.CarsController` will be discovered and returned if - an application requests `controller:cars`. - - An example of registering a controller with a non-standard name: - - ```javascript - var App = Ember.Application.create(); - var Session = Ember.Controller.extend(); - - App.register('controller:session', Session); - - // The Session controller can now be treated like a normal controller, - // despite its non-standard name. - App.ApplicationController = Ember.Controller.extend({ - needs: ['session'] - }); - ``` - - Registered factories are **instantiated** by having `create` - called on them. Additionally they are **singletons**, each time - they are looked up they return the same instance. - - Some examples modifying that default behavior: - - ```javascript - var App = Ember.Application.create(); - - App.Person = Ember.Object.extend(); - App.Orange = Ember.Object.extend(); - App.Email = Ember.Object.extend(); - App.session = Ember.Object.create(); - - App.register('model:user', App.Person, { singleton: false }); - App.register('fruit:favorite', App.Orange); - App.register('communication:main', App.Email, { singleton: false }); - App.register('session', App.session, { instantiate: false }); - ``` - - @method register - @param fullName {String} type:name (e.g., 'model:user') - @param factory {Function} (e.g., App.Person) - @param options {Object} (optional) disable instantiation or singleton usage - **/ - register: function() { - var container = this.__container__; - container.register.apply(container, arguments); - }, - - /** - Define a dependency injection onto a specific factory or all factories - of a type. - - When Ember instantiates a controller, view, or other framework component - it can attach a dependency to that component. This is often used to - provide services to a set of framework components. - - An example of providing a session object to all controllers: - - ```javascript - var App = Ember.Application.create(); - var Session = Ember.Object.extend({ isAuthenticated: false }); - - // A factory must be registered before it can be injected - App.register('session:main', Session); - - // Inject 'session:main' onto all factories of the type 'controller' - // with the name 'session' - App.inject('controller', 'session', 'session:main'); - - App.IndexController = Ember.Controller.extend({ - isLoggedIn: Ember.computed.alias('session.isAuthenticated') - }); - ``` - - Injections can also be performed on specific factories. - - ```javascript - App.inject(, , ) - App.inject('route', 'source', 'source:main') - App.inject('route:application', 'email', 'model:email') - ``` - - It is important to note that injections can only be performed on - classes that are instantiated by Ember itself. Instantiating a class - directly (via `create` or `new`) bypasses the dependency injection - system. - - **Note:** Ember-Data instantiates its models in a unique manner, and consequently - injections onto models (or all models) will not work as expected. Injections - on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` - to `true`. - - @method inject - @param factoryNameOrType {String} - @param property {String} - @param injectionName {String} - **/ - inject: function() { - var container = this.__container__; - container.injection.apply(container, arguments); - }, - - /** - Calling initialize manually is not supported. - - Please see Ember.Application#advanceReadiness and - Ember.Application#deferReadiness. - - @private - @deprecated - @method initialize - **/ - initialize: function() { - Ember.deprecate('Calling initialize manually is not supported. Please see Ember.Application#advanceReadiness and Ember.Application#deferReadiness'); - }, - - /** - Initialize the application. This happens automatically. - - Run any initializers and run the application load hook. These hooks may - choose to defer readiness. For example, an authentication hook might want - to defer readiness until the auth token has been retrieved. - - @private - @method _initialize - */ - _initialize: function() { - if (this.isDestroyed) { return; } - - // At this point, the App.Router must already be assigned - if (this.Router) { - var container = this.__container__; - container.unregister('router:main'); - container.register('router:main', this.Router); - } - - this.runInitializers(); - runLoadHooks('application', this); - - // At this point, any initializers or load hooks that would have wanted - // to defer readiness have fired. In general, advancing readiness here - // will proceed to didBecomeReady. - this.advanceReadiness(); - - return this; - }, - - /** - Reset the application. This is typically used only in tests. It cleans up - the application in the following order: - - 1. Deactivate existing routes - 2. Destroy all objects in the container - 3. Create a new application container - 4. Re-route to the existing url - - Typical Example: - - ```javascript - var App; - - run(function() { - App = Ember.Application.create(); - }); - - module('acceptance test', { - setup: function() { - App.reset(); - } - }); - - test('first test', function() { - // App is freshly reset - }); - - test('second test', function() { - // App is again freshly reset - }); - ``` - - Advanced Example: - - Occasionally you may want to prevent the app from initializing during - setup. This could enable extra configuration, or enable asserting prior - to the app becoming ready. - - ```javascript - var App; - - run(function() { - App = Ember.Application.create(); - }); - - module('acceptance test', { - setup: function() { - run(function() { - App.reset(); - App.deferReadiness(); - }); - } - }); - - test('first test', function() { - ok(true, 'something before app is initialized'); - - run(function() { - App.advanceReadiness(); - }); - - ok(true, 'something after app is initialized'); - }); - ``` - - @method reset - **/ - reset: function() { - this._readinessDeferrals = 1; - - function handleReset() { - var router = this.__container__.lookup('router:main'); - router.reset(); - - run(this.__container__, 'destroy'); - - this.buildContainer(); - - run.schedule('actions', this, function() { - this._initialize(); - }); - } - - run.join(this, handleReset); - }, - - /** - @private - @method runInitializers - */ - runInitializers: function() { - var initializersByName = get(this.constructor, 'initializers'); - var initializers = props(initializersByName); - var container = this.__container__; - var graph = new DAG(); - var namespace = this; - var initializer; - - for (var i = 0; i < initializers.length; i++) { - initializer = initializersByName[initializers[i]]; - graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); - } - - graph.topsort(function (vertex) { - var initializer = vertex.value; - Ember.assert("No application initializer named '" + vertex.name + "'", initializer); - initializer(container, namespace); - }); - }, - - /** - @private - @method didBecomeReady - */ - didBecomeReady: function() { - this.setupEventDispatcher(); - this.ready(); // user hook - this.startRouting(); - - if (!Ember.testing) { - // Eagerly name all classes that are already loaded - Ember.Namespace.processAll(); - Ember.BOOTED = true; - } - - this.resolve(this); - }, - - /** - Setup up the event dispatcher to receive events on the - application's `rootElement` with any registered - `customEvents`. - - @private - @method setupEventDispatcher - */ - setupEventDispatcher: function() { - var customEvents = get(this, 'customEvents'); - var rootElement = get(this, 'rootElement'); - var dispatcher = this.__container__.lookup('event_dispatcher:main'); - - set(this, 'eventDispatcher', dispatcher); - dispatcher.setup(customEvents, rootElement); - }, - - /** - If the application has a router, use it to route to the current URL, and - trigger a new call to `route` whenever the URL changes. - - @private - @method startRouting - @property router {Ember.Router} - */ - startRouting: function() { - var router = this.__container__.lookup('router:main'); - if (!router) { return; } - - router.startRouting(); - }, - - handleURL: function(url) { - var router = this.__container__.lookup('router:main'); - - router.handleURL(url); - }, - - /** - Called when the Application has become ready. - The call will be delayed until the DOM has become ready. - - @event ready - */ - ready: K, - - /** - @deprecated Use 'Resolver' instead - Set this to provide an alternate class to `Ember.DefaultResolver` - - - @property resolver - */ - resolver: null, - - /** - Set this to provide an alternate class to `Ember.DefaultResolver` - - @property resolver - */ - Resolver: null, - - willDestroy: function() { - Ember.BOOTED = false; - // Ensure deactivation of routes before objects are destroyed - this.__container__.lookup('router:main').reset(); - - this.__container__.destroy(); - }, - - initializer: function(options) { - this.constructor.initializer(options); - }, - - /** - @method then - @private - @deprecated - */ - then: function() { - Ember.deprecate('Do not use `.then` on an instance of Ember.Application. Please use the `.ready` hook instead.'); - - this._super.apply(this, arguments); - } - }); - - Application.reopenClass({ - initializers: create(null), - - /** - Initializer receives an object which has the following attributes: - `name`, `before`, `after`, `initialize`. The only required attribute is - `initialize, all others are optional. - - * `name` allows you to specify under which name the initializer is registered. - This must be a unique name, as trying to register two initializers with the - same name will result in an error. - - ```javascript - Ember.Application.initializer({ - name: 'namedInitializer', - - initialize: function(container, application) { - Ember.debug('Running namedInitializer!'); - } - }); - ``` - - * `before` and `after` are used to ensure that this initializer is ran prior - or after the one identified by the value. This value can be a single string - or an array of strings, referencing the `name` of other initializers. - - An example of ordering initializers, we create an initializer named `first`: - - ```javascript - Ember.Application.initializer({ - name: 'first', - - initialize: function(container, application) { - Ember.debug('First initializer!'); - } - }); - - // DEBUG: First initializer! - ``` - - We add another initializer named `second`, specifying that it should run - after the initializer named `first`: - - ```javascript - Ember.Application.initializer({ - name: 'second', - after: 'first', - - initialize: function(container, application) { - Ember.debug('Second initializer!'); - } - }); - - // DEBUG: First initializer! - // DEBUG: Second initializer! - ``` - - Afterwards we add a further initializer named `pre`, this time specifying - that it should run before the initializer named `first`: - - ```javascript - Ember.Application.initializer({ - name: 'pre', - before: 'first', - - initialize: function(container, application) { - Ember.debug('Pre initializer!'); - } - }); - - // DEBUG: Pre initializer! - // DEBUG: First initializer! - // DEBUG: Second initializer! - ``` - - Finally we add an initializer named `post`, specifying it should run after - both the `first` and the `second` initializers: - - ```javascript - Ember.Application.initializer({ - name: 'post', - after: ['first', 'second'], - - initialize: function(container, application) { - Ember.debug('Post initializer!'); - } - }); - - // DEBUG: Pre initializer! - // DEBUG: First initializer! - // DEBUG: Second initializer! - // DEBUG: Post initializer! - ``` - - * `initialize` is a callback function that receives two arguments, `container` - and `application` on which you can operate. - - Example of using `container` to preload data into the store: - - ```javascript - Ember.Application.initializer({ - name: 'preload-data', - - initialize: function(container, application) { - var store = container.lookup('store:main'); - - store.pushPayload(preloadedData); - } - }); - ``` - - Example of using `application` to register an adapter: - - ```javascript - Ember.Application.initializer({ - name: 'api-adapter', - - initialize: function(container, application) { - application.register('api-adapter:main', ApiAdapter); - } - }); - ``` - - @method initializer - @param initializer {Object} - */ - initializer: function(initializer) { - // If this is the first initializer being added to a subclass, we are going to reopen the class - // to make sure we have a new `initializers` object, which extends from the parent class' using - // prototypal inheritance. Without this, attempting to add initializers to the subclass would - // pollute the parent class as well as other subclasses. - if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { - this.reopenClass({ - initializers: create(this.initializers) - }); - } - - Ember.assert("The initializer '" + initializer.name + "' has already been registered", !this.initializers[initializer.name]); - Ember.assert("An initializer cannot be registered without an initialize function", canInvoke(initializer, 'initialize')); - Ember.assert("An initializer cannot be registered without a name property", initializer.name !== undefined); - - this.initializers[initializer.name] = initializer; - }, - - /** - This creates a container with the default Ember naming conventions. - - It also configures the container: - - * registered views are created every time they are looked up (they are - not singletons) - * registered templates are not factories; the registered value is - returned directly. - * the router receives the application as its `namespace` property - * all controllers receive the router as their `target` and `controllers` - properties - * all controllers receive the application as their `namespace` property - * the application view receives the application controller as its - `controller` property - * the application view receives the application template as its - `defaultTemplate` property - - @private - @method buildContainer - @static - @param {Ember.Application} namespace the application to build the - container for. - @return {Ember.Container} the built container - */ - buildContainer: function(namespace) { - var container = new Container(); - - container.set = set; - container.resolver = resolverFor(namespace); - container.normalizeFullName = container.resolver.normalize; - container.describe = container.resolver.describe; - container.makeToString = container.resolver.makeToString; - - container.optionsForType('component', { singleton: false }); - container.optionsForType('view', { singleton: false }); - container.optionsForType('template', { instantiate: false }); - container.optionsForType('helper', { instantiate: false }); - - container.register('application:main', namespace, { instantiate: false }); - - container.register('controller:basic', Controller, { instantiate: false }); - container.register('controller:object', ObjectController, { instantiate: false }); - container.register('controller:array', ArrayController, { instantiate: false }); - - container.register('view:select', SelectView); - - container.register('route:basic', Route, { instantiate: false }); - container.register('event_dispatcher:main', EventDispatcher); - - container.register('router:main', Router); - container.injection('router:main', 'namespace', 'application:main'); - - container.register('location:auto', AutoLocation); - container.register('location:hash', HashLocation); - container.register('location:history', HistoryLocation); - container.register('location:none', NoneLocation); - - container.injection('controller', 'target', 'router:main'); - container.injection('controller', 'namespace', 'application:main'); - - container.register('-bucket-cache:main', BucketCache); - container.injection('router', '_bucketCache', '-bucket-cache:main'); - container.injection('route', '_bucketCache', '-bucket-cache:main'); - container.injection('controller', '_bucketCache', '-bucket-cache:main'); - - container.injection('route', 'router', 'router:main'); - container.injection('location', 'rootURL', '-location-setting:root-url'); - - // DEBUGGING - container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); - container.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); - container.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); - // Custom resolver authors may want to register their own ContainerDebugAdapter with this key - - container.register('container-debug-adapter:main', ContainerDebugAdapter); - - return container; - } - }); - - /** - This function defines the default lookup rules for container lookups: - - * templates are looked up on `Ember.TEMPLATES` - * other names are looked up on the application after classifying the name. - For example, `controller:post` looks up `App.PostController` by default. - * if the default lookup fails, look for registered classes on the container - - This allows the application to register default injections in the container - that could be overridden by the normal naming convention. - - @private - @method resolverFor - @param {Ember.Namespace} namespace the namespace to look for classes - @return {*} the resolved value for a given lookup - */ - function resolverFor(namespace) { - if (namespace.get('resolver')) { - Ember.deprecate('Application.resolver is deprecated in favor of Application.Resolver', false); - } - - var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || DefaultResolver; - var resolver = ResolverClass.create({ - namespace: namespace - }); - - function resolve(fullName) { - return resolver.resolve(fullName); - } - - resolve.describe = function(fullName) { - return resolver.lookupDescription(fullName); - }; - - resolve.makeToString = function(factory, fullName) { - return resolver.makeToString(factory, fullName); - }; - - resolve.normalize = function(fullName) { - if (resolver.normalize) { - return resolver.normalize(fullName); - } else { - Ember.deprecate('The Resolver should now provide a \'normalize\' function', false); - return fullName; - } - }; - - resolve.__resolver__ = resolver; - - return resolve; - } - - __exports__["default"] = Application; - }); -enifed("ember-application/system/resolver", - ["ember-metal/core","ember-metal/property_get","ember-metal/logger","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/system/namespace","ember-handlebars","ember-metal/dictionary","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-application - */ - - var Ember = __dependency1__["default"]; - // Ember.TEMPLATES, Ember.assert - var get = __dependency2__.get; - var Logger = __dependency3__["default"]; - var classify = __dependency4__.classify; - var capitalize = __dependency4__.capitalize; - var decamelize = __dependency4__.decamelize; - var EmberObject = __dependency5__["default"]; - var Namespace = __dependency6__["default"]; - var EmberHandlebars = __dependency7__["default"]; - - var Resolver = EmberObject.extend({ - /** - This will be set to the Application instance when it is - created. - - @property namespace - */ - namespace: null, - normalize: Ember.required(Function), - resolve: Ember.required(Function), - parseName: Ember.required(Function), - lookupDescription: Ember.required(Function), - makeToString: Ember.required(Function), - resolveOther: Ember.required(Function), - _logLookup: Ember.required(Function) - }); - __exports__.Resolver = Resolver; - /** - The DefaultResolver defines the default lookup rules to resolve - container lookups before consulting the container for registered - items: - - * templates are looked up on `Ember.TEMPLATES` - * other names are looked up on the application after converting - the name. For example, `controller:post` looks up - `App.PostController` by default. - * there are some nuances (see examples below) - - ### How Resolving Works - - The container calls this object's `resolve` method with the - `fullName` argument. - - It first parses the fullName into an object using `parseName`. - - Then it checks for the presence of a type-specific instance - method of the form `resolve[Type]` and calls it if it exists. - For example if it was resolving 'template:post', it would call - the `resolveTemplate` method. - - Its last resort is to call the `resolveOther` method. - - The methods of this object are designed to be easy to override - in a subclass. For example, you could enhance how a template - is resolved like so: - - ```javascript - App = Ember.Application.create({ - Resolver: Ember.DefaultResolver.extend({ - resolveTemplate: function(parsedName) { - var resolvedTemplate = this._super(parsedName); - if (resolvedTemplate) { return resolvedTemplate; } - return Ember.TEMPLATES['not_found']; - } - }) - }); - ``` - - Some examples of how names are resolved: - - ``` - 'template:post' //=> Ember.TEMPLATES['post'] - 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] - 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] - 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] - // OR - // Ember.TEMPLATES['blog_post'] - 'controller:post' //=> App.PostController - 'controller:posts.index' //=> App.PostsIndexController - 'controller:blog/post' //=> Blog.PostController - 'controller:basic' //=> Ember.Controller - 'route:post' //=> App.PostRoute - 'route:posts.index' //=> App.PostsIndexRoute - 'route:blog/post' //=> Blog.PostRoute - 'route:basic' //=> Ember.Route - 'view:post' //=> App.PostView - 'view:posts.index' //=> App.PostsIndexView - 'view:blog/post' //=> Blog.PostView - 'view:basic' //=> Ember.View - 'foo:post' //=> App.PostFoo - 'model:post' //=> App.Post - ``` - - @class DefaultResolver - @namespace Ember - @extends Ember.Object - */ - var dictionary = __dependency8__["default"]; - - __exports__["default"] = EmberObject.extend({ - /** - This will be set to the Application instance when it is - created. - - @property namespace - */ - namespace: null, - - init: function() { - this._parseNameCache = dictionary(null); - }, - normalize: function(fullName) { - var split = fullName.split(':', 2); - var type = split[0]; - var name = split[1]; - - Ember.assert("Tried to normalize a container name without a colon (:) in it." + - " You probably tried to lookup a name that did not contain a type," + - " a colon, and a name. A proper lookup name would be `view:post`.", split.length === 2); - - if (type !== 'template') { - var result = name; - - if (result.indexOf('.') > -1) { - result = result.replace(/\.(.)/g, function(m) { - return m.charAt(1).toUpperCase(); - }); - } - - if (name.indexOf('_') > -1) { - result = result.replace(/_(.)/g, function(m) { - return m.charAt(1).toUpperCase(); - }); - } - - return type + ':' + result; - } else { - return fullName; - } - }, - - - /** - This method is called via the container's resolver method. - It parses the provided `fullName` and then looks up and - returns the appropriate template or class. - - @method resolve - @param {String} fullName the lookup string - @return {Object} the resolved factory - */ - resolve: function(fullName) { - var parsedName = this.parseName(fullName); - var resolveMethodName = parsedName.resolveMethodName; - var resolved; - - if (!(parsedName.name && parsedName.type)) { - throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); - } - - if (this[resolveMethodName]) { - resolved = this[resolveMethodName](parsedName); - } - - if (!resolved) { - resolved = this.resolveOther(parsedName); - } - - if (parsedName.root && parsedName.root.LOG_RESOLVER) { - this._logLookup(resolved, parsedName); - } - - return resolved; - }, - /** - Convert the string name of the form 'type:name' to - a Javascript object with the parsed aspects of the name - broken out. - - @protected - @param {String} fullName the lookup string - @method parseName - */ - - parseName: function(fullName) { - return this._parseNameCache[fullName] || ( - this._parseNameCache[fullName] = this._parseName(fullName) - ); - }, - - _parseName: function(fullName) { - var nameParts = fullName.split(':'); - var type = nameParts[0], fullNameWithoutType = nameParts[1]; - var name = fullNameWithoutType; - var namespace = get(this, 'namespace'); - var root = namespace; - - if (type !== 'template' && name.indexOf('/') !== -1) { - var parts = name.split('/'); - name = parts[parts.length - 1]; - var namespaceName = capitalize(parts.slice(0, -1).join('.')); - root = Namespace.byName(namespaceName); - - Ember.assert('You are looking for a ' + name + ' ' + type + - ' in the ' + namespaceName + - ' namespace, but the namespace could not be found', root); - } - - return { - fullName: fullName, - type: type, - fullNameWithoutType: fullNameWithoutType, - name: name, - root: root, - resolveMethodName: 'resolve' + classify(type) - }; - }, - - /** - Returns a human-readable description for a fullName. Used by the - Application namespace in assertions to describe the - precise name of the class that Ember is looking for, rather than - container keys. - - @protected - @param {String} fullName the lookup string - @method lookupDescription - */ - lookupDescription: function(fullName) { - var parsedName = this.parseName(fullName); - - if (parsedName.type === 'template') { - return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); - } - - var description = parsedName.root + '.' + classify(parsedName.name); - - if (parsedName.type !== 'model') { - description += classify(parsedName.type); - } - - return description; - }, - - makeToString: function(factory, fullName) { - return factory.toString(); - }, - /** - Given a parseName object (output from `parseName`), apply - the conventions expected by `Ember.Router` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method useRouterNaming - */ - useRouterNaming: function(parsedName) { - parsedName.name = parsedName.name.replace(/\./g, '_'); - if (parsedName.name === 'basic') { - parsedName.name = ''; - } - }, - /** - Look up the template in Ember.TEMPLATES - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveTemplate - */ - resolveTemplate: function(parsedName) { - var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); - - if (Ember.TEMPLATES[templateName]) { - return Ember.TEMPLATES[templateName]; - } - - templateName = decamelize(templateName); - if (Ember.TEMPLATES[templateName]) { - return Ember.TEMPLATES[templateName]; - } - }, - - /** - Lookup the view using `resolveOther` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveView - */ - resolveView: function(parsedName) { - this.useRouterNaming(parsedName); - return this.resolveOther(parsedName); - }, - - /** - Lookup the controller using `resolveOther` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveController - */ - resolveController: function(parsedName) { - this.useRouterNaming(parsedName); - return this.resolveOther(parsedName); - }, - /** - Lookup the route using `resolveOther` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveRoute - */ - resolveRoute: function(parsedName) { - this.useRouterNaming(parsedName); - return this.resolveOther(parsedName); - }, - - /** - Lookup the model on the Application namespace - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveModel - */ - resolveModel: function(parsedName) { - var className = classify(parsedName.name); - var factory = get(parsedName.root, className); - - if (factory) { return factory; } - }, - /** - Look up the specified object (from parsedName) on the appropriate - namespace (usually on the Application) - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveHelper - */ - resolveHelper: function(parsedName) { - return this.resolveOther(parsedName) || EmberHandlebars.helpers[parsedName.fullNameWithoutType]; - }, - /** - Look up the specified object (from parsedName) on the appropriate - namespace (usually on the Application) - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveOther - */ - resolveOther: function(parsedName) { - var className = classify(parsedName.name) + classify(parsedName.type); - var factory = get(parsedName.root, className); - if (factory) { return factory; } - }, - - /** - @method _logLookup - @param {Boolean} found - @param {Object} parsedName - @private - */ - _logLookup: function(found, parsedName) { - var symbol, padding; - - if (found) { symbol = '[✓]'; } - else { symbol = '[ ]'; } - - if (parsedName.fullName.length > 60) { - padding = '.'; - } else { - padding = new Array(60 - parsedName.fullName.length).join('.'); - } - - Logger.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); - } - }); - }); -enifed("ember-debug", - ["ember-metal/core","ember-metal/error","ember-metal/logger","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /*global __fail__*/ - - var Ember = __dependency1__["default"]; - var EmberError = __dependency2__["default"]; - var Logger = __dependency3__["default"]; - - /** - Ember Debug - - @module ember - @submodule ember-debug - */ - - /** - @class Ember - */ - - /** - Define an assertion that will throw an exception if the condition is not - met. Ember build tools will remove any calls to `Ember.assert()` when - doing a production build. Example: - - ```javascript - // Test for truthiness - Ember.assert('Must pass a valid object', obj); - - // Fail unconditionally - Ember.assert('This code path should never be run'); - ``` - - @method assert - @param {String} desc A description of the assertion. This will become - the text of the Error thrown if the assertion fails. - @param {Boolean} test Must be truthy for the assertion to pass. If - falsy, an exception will be thrown. - */ - Ember.assert = function(desc, test) { - if (!test) { - throw new EmberError("Assertion Failed: " + desc); - } - }; - - - /** - Display a warning with the provided message. Ember build tools will - remove any calls to `Ember.warn()` when doing a production build. - - @method warn - @param {String} message A warning to display. - @param {Boolean} test An optional boolean. If falsy, the warning - will be displayed. - */ - Ember.warn = function(message, test) { - if (!test) { - Logger.warn("WARNING: "+message); - if ('trace' in Logger) Logger.trace(); - } - }; - - /** - Display a debug notice. Ember build tools will remove any calls to - `Ember.debug()` when doing a production build. - - ```javascript - Ember.debug('I\'m a debug notice!'); - ``` - - @method debug - @param {String} message A debug message to display. - */ - Ember.debug = function(message) { - Logger.debug("DEBUG: "+message); - }; - - /** - Display a deprecation warning with the provided message and a stack trace - (Chrome and Firefox only). Ember build tools will remove any calls to - `Ember.deprecate()` when doing a production build. - - @method deprecate - @param {String} message A description of the deprecation. - @param {Boolean} test An optional boolean. If falsy, the deprecation - will be displayed. - */ - Ember.deprecate = function(message, test) { - if (test) { return; } - - if (Ember.ENV.RAISE_ON_DEPRECATION) { throw new EmberError(message); } - - var error; - - // When using new Error, we can't do the arguments check for Chrome. Alternatives are welcome - try { __fail__.fail(); } catch (e) { error = e; } - - if (Ember.LOG_STACKTRACE_ON_DEPRECATION && error.stack) { - var stack; - var stackStr = ''; - - if (error['arguments']) { - // Chrome - stack = error.stack.replace(/^\s+at\s+/gm, ''). - replace(/^([^\(]+?)([\n$])/gm, '{anonymous}($1)$2'). - replace(/^Object.\s*\(([^\)]+)\)/gm, '{anonymous}($1)').split('\n'); - stack.shift(); - } else { - // Firefox - stack = error.stack.replace(/(?:\n@:0)?\s+$/m, ''). - replace(/^\(/gm, '{anonymous}(').split('\n'); - } - - stackStr = "\n " + stack.slice(2).join("\n "); - message = message + stackStr; - } - - Logger.warn("DEPRECATION: "+message); - }; - - - - /** - Alias an old, deprecated method with its new counterpart. - - Display a deprecation warning with the provided message and a stack trace - (Chrome and Firefox only) when the assigned method is called. - - Ember build tools will not remove calls to `Ember.deprecateFunc()`, though - no warnings will be shown in production. - - ```javascript - Ember.oldMethod = Ember.deprecateFunc('Please use the new, updated method', Ember.newMethod); - ``` - - @method deprecateFunc - @param {String} message A description of the deprecation. - @param {Function} func The new function called to replace its deprecated counterpart. - @return {Function} a new function that wrapped the original function with a deprecation warning - */ - Ember.deprecateFunc = function(message, func) { - return function() { - Ember.deprecate(message); - return func.apply(this, arguments); - }; - }; - - - /** - Run a function meant for debugging. Ember build tools will remove any calls to - `Ember.runInDebug()` when doing a production build. - - ```javascript - Ember.runInDebug(function() { - Ember.Handlebars.EachView.reopen({ - didInsertElement: function() { - console.log('I\'m happy'); - } - }); - }); - ``` - - @method runInDebug - @param {Function} func The function to be executed. - @since 1.5.0 - */ - Ember.runInDebug = function(func) { - func(); - }; - - /** - Will call `Ember.warn()` if ENABLE_ALL_FEATURES, ENABLE_OPTIONAL_FEATURES, or - any specific FEATURES flag is truthy. - - This method is called automatically in debug canary builds. - - @private - @method _warnIfUsingStrippedFeatureFlags - @return {void} - */ - function _warnIfUsingStrippedFeatureFlags(FEATURES, featuresWereStripped) { - if (featuresWereStripped) { - Ember.warn('Ember.ENV.ENABLE_ALL_FEATURES is only available in canary builds.', !Ember.ENV.ENABLE_ALL_FEATURES); - Ember.warn('Ember.ENV.ENABLE_OPTIONAL_FEATURES is only available in canary builds.', !Ember.ENV.ENABLE_OPTIONAL_FEATURES); - - for (var key in FEATURES) { - if (FEATURES.hasOwnProperty(key) && key !== 'isEnabled') { - Ember.warn('FEATURE["' + key + '"] is set as enabled, but FEATURE flags are only available in canary builds.', !FEATURES[key]); - } - } - } - } - - __exports__._warnIfUsingStrippedFeatureFlags = _warnIfUsingStrippedFeatureFlags;if (!Ember.testing) { - // Complain if they're using FEATURE flags in builds other than canary - Ember.FEATURES['features-stripped-test'] = true; - var featuresWereStripped = true; - - - delete Ember.FEATURES['features-stripped-test']; - _warnIfUsingStrippedFeatureFlags(Ember.ENV.FEATURES, featuresWereStripped); - - // Inform the developer about the Ember Inspector if not installed. - var isFirefox = typeof InstallTrigger !== 'undefined'; - var isChrome = !!window.chrome && !window.opera; - - if (typeof window !== 'undefined' && (isFirefox || isChrome) && window.addEventListener) { - window.addEventListener("load", function() { - if (document.documentElement && document.documentElement.dataset && !document.documentElement.dataset.emberExtension) { - var downloadURL; - - if(isChrome) { - downloadURL = 'https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi'; - } else if(isFirefox) { - downloadURL = 'https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/'; - } - - Ember.debug('For more advanced debugging, install the Ember Inspector from ' + downloadURL); - } - }, false); - } - } - }); -enifed("ember-extension-support", - ["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"], - function(__dependency1__, __dependency2__, __dependency3__) { - "use strict"; - /** - Ember Extension Support - - @module ember - @submodule ember-extension-support - @requires ember-application - */ - - var Ember = __dependency1__["default"]; - var DataAdapter = __dependency2__["default"]; - var ContainerDebugAdapter = __dependency3__["default"]; - - Ember.DataAdapter = DataAdapter; - Ember.ContainerDebugAdapter = ContainerDebugAdapter; - }); -enifed("ember-extension-support/container_debug_adapter", - ["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var emberA = __dependency2__.A; - var typeOf = __dependency3__.typeOf; - var dasherize = __dependency4__.dasherize; - var classify = __dependency4__.classify; - var Namespace = __dependency5__["default"]; - var EmberObject = __dependency6__["default"]; - - /** - @module ember - @submodule ember-extension-support - */ - - /** - The `ContainerDebugAdapter` helps the container and resolver interface - with tools that debug Ember such as the - [Ember Extension](https://github.com/tildeio/ember-extension) - for Chrome and Firefox. - - This class can be extended by a custom resolver implementer - to override some of the methods with library-specific code. - - The methods likely to be overridden are: - - * `canCatalogEntriesByType` - * `catalogEntriesByType` - - The adapter will need to be registered - in the application's container as `container-debug-adapter:main` - - Example: - - ```javascript - Application.initializer({ - name: "containerDebugAdapter", - - initialize: function(container, application) { - application.register('container-debug-adapter:main', require('app/container-debug-adapter')); - } - }); - ``` - - @class ContainerDebugAdapter - @namespace Ember - @extends EmberObject - @since 1.5.0 - */ - __exports__["default"] = EmberObject.extend({ - /** - The container of the application being debugged. - This property will be injected - on creation. - - @property container - @default null - */ - container: null, - - /** - The resolver instance of the application - being debugged. This property will be injected - on creation. - - @property resolver - @default null - */ - resolver: null, - - /** - Returns true if it is possible to catalog a list of available - classes in the resolver for a given type. - - @method canCatalogEntriesByType - @param {String} type The type. e.g. "model", "controller", "route" - @return {boolean} whether a list is available for this type. - */ - canCatalogEntriesByType: function(type) { - if (type === 'model' || type === 'template') return false; - return true; - }, - - /** - Returns the available classes a given type. - - @method catalogEntriesByType - @param {String} type The type. e.g. "model", "controller", "route" - @return {Array} An array of strings. - */ - catalogEntriesByType: function(type) { - var namespaces = emberA(Namespace.NAMESPACES), types = emberA(); - var typeSuffixRegex = new RegExp(classify(type) + "$"); - - namespaces.forEach(function(namespace) { - if (namespace !== Ember) { - for (var key in namespace) { - if (!namespace.hasOwnProperty(key)) { continue; } - if (typeSuffixRegex.test(key)) { - var klass = namespace[key]; - if (typeOf(klass) === 'class') { - types.push(dasherize(key.replace(typeSuffixRegex, ''))); - } - } - } - } - }); - return types; - } - }); - }); -enifed("ember-extension-support/data_adapter", - ["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var get = __dependency2__.get; - var run = __dependency3__["default"]; - var dasherize = __dependency4__.dasherize; - var Namespace = __dependency5__["default"]; - var EmberObject = __dependency6__["default"]; - var emberA = __dependency7__.A; - var Application = __dependency8__["default"]; - - /** - @module ember - @submodule ember-extension-support - */ - - /** - The `DataAdapter` helps a data persistence library - interface with tools that debug Ember such - as the [Ember Extension](https://github.com/tildeio/ember-extension) - for Chrome and Firefox. - - This class will be extended by a persistence library - which will override some of the methods with - library-specific code. - - The methods likely to be overridden are: - - * `getFilters` - * `detect` - * `columnsForType` - * `getRecords` - * `getRecordColumnValues` - * `getRecordKeywords` - * `getRecordFilterValues` - * `getRecordColor` - * `observeRecord` - - The adapter will need to be registered - in the application's container as `dataAdapter:main` - - Example: - - ```javascript - Application.initializer({ - name: "data-adapter", - - initialize: function(container, application) { - application.register('data-adapter:main', DS.DataAdapter); - } - }); - ``` - - @class DataAdapter - @namespace Ember - @extends EmberObject - */ - __exports__["default"] = EmberObject.extend({ - init: function() { - this._super(); - this.releaseMethods = emberA(); - }, - - /** - The container of the application being debugged. - This property will be injected - on creation. - - @property container - @default null - @since 1.3.0 - */ - container: null, - - - /** - The container-debug-adapter which is used - to list all models. - - @property containerDebugAdapter - @default undefined - @since 1.5.0 - **/ - containerDebugAdapter: undefined, - - /** - Number of attributes to send - as columns. (Enough to make the record - identifiable). - - @private - @property attributeLimit - @default 3 - @since 1.3.0 - */ - attributeLimit: 3, - - /** - Stores all methods that clear observers. - These methods will be called on destruction. - - @private - @property releaseMethods - @since 1.3.0 - */ - releaseMethods: emberA(), - - /** - Specifies how records can be filtered. - Records returned will need to have a `filterValues` - property with a key for every name in the returned array. - - @public - @method getFilters - @return {Array} List of objects defining filters. - The object should have a `name` and `desc` property. - */ - getFilters: function() { - return emberA(); - }, - - /** - Fetch the model types and observe them for changes. - - @public - @method watchModelTypes - - @param {Function} typesAdded Callback to call to add types. - Takes an array of objects containing wrapped types (returned from `wrapModelType`). - - @param {Function} typesUpdated Callback to call when a type has changed. - Takes an array of objects containing wrapped types. - - @return {Function} Method to call to remove all observers - */ - watchModelTypes: function(typesAdded, typesUpdated) { - var modelTypes = this.getModelTypes(); - var self = this; - var releaseMethods = emberA(); - var typesToSend; - - typesToSend = modelTypes.map(function(type) { - var klass = type.klass; - var wrapped = self.wrapModelType(klass, type.name); - releaseMethods.push(self.observeModelType(klass, typesUpdated)); - return wrapped; - }); - - typesAdded(typesToSend); - - var release = function() { - releaseMethods.forEach(function(fn) { fn(); }); - self.releaseMethods.removeObject(release); - }; - this.releaseMethods.pushObject(release); - return release; - }, - - _nameToClass: function(type) { - if (typeof type === 'string') { - type = this.container.lookupFactory('model:' + type); - } - return type; - }, - - /** - Fetch the records of a given type and observe them for changes. - - @public - @method watchRecords - - @param {Function} recordsAdded Callback to call to add records. - Takes an array of objects containing wrapped records. - The object should have the following properties: - columnValues: {Object} key and value of a table cell - object: {Object} the actual record object - - @param {Function} recordsUpdated Callback to call when a record has changed. - Takes an array of objects containing wrapped records. - - @param {Function} recordsRemoved Callback to call when a record has removed. - Takes the following parameters: - index: the array index where the records were removed - count: the number of records removed - - @return {Function} Method to call to remove all observers - */ - watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) { - var self = this, releaseMethods = emberA(), records = this.getRecords(type), release; - - var recordUpdated = function(updatedRecord) { - recordsUpdated([updatedRecord]); - }; - - var recordsToSend = records.map(function(record) { - releaseMethods.push(self.observeRecord(record, recordUpdated)); - return self.wrapRecord(record); - }); - - - var contentDidChange = function(array, idx, removedCount, addedCount) { - for (var i = idx; i < idx + addedCount; i++) { - var record = array.objectAt(i); - var wrapped = self.wrapRecord(record); - releaseMethods.push(self.observeRecord(record, recordUpdated)); - recordsAdded([wrapped]); - } - - if (removedCount) { - recordsRemoved(idx, removedCount); - } - }; - - var observer = { didChange: contentDidChange, willChange: Ember.K }; - records.addArrayObserver(self, observer); - - release = function() { - releaseMethods.forEach(function(fn) { fn(); }); - records.removeArrayObserver(self, observer); - self.releaseMethods.removeObject(release); - }; - - recordsAdded(recordsToSend); - - this.releaseMethods.pushObject(release); - return release; - }, - - /** - Clear all observers before destruction - @private - @method willDestroy - */ - willDestroy: function() { - this._super(); - this.releaseMethods.forEach(function(fn) { - fn(); - }); - }, - - /** - Detect whether a class is a model. - - Test that against the model class - of your persistence library - - @private - @method detect - @param {Class} klass The class to test - @return boolean Whether the class is a model class or not - */ - detect: function(klass) { - return false; - }, - - /** - Get the columns for a given model type. - - @private - @method columnsForType - @param {Class} type The model type - @return {Array} An array of columns of the following format: - name: {String} name of the column - desc: {String} Humanized description (what would show in a table column name) - */ - columnsForType: function(type) { - return emberA(); - }, - - /** - Adds observers to a model type class. - - @private - @method observeModelType - @param {Class} type The model type class - @param {Function} typesUpdated Called when a type is modified. - @return {Function} The function to call to remove observers - */ - - observeModelType: function(type, typesUpdated) { - var self = this; - var records = this.getRecords(type); - - var onChange = function() { - typesUpdated([self.wrapModelType(type)]); - }; - var observer = { - didChange: function() { - run.scheduleOnce('actions', this, onChange); - }, - willChange: Ember.K - }; - - records.addArrayObserver(this, observer); - - var release = function() { - records.removeArrayObserver(self, observer); - }; - - return release; - }, - - - /** - Wraps a given model type and observes changes to it. - - @private - @method wrapModelType - @param {Class} type A model class - @param {String} Optional name of the class - @return {Object} contains the wrapped type and the function to remove observers - Format: - type: {Object} the wrapped type - The wrapped type has the following format: - name: {String} name of the type - count: {Integer} number of records available - columns: {Columns} array of columns to describe the record - object: {Class} the actual Model type class - release: {Function} The function to remove observers - */ - wrapModelType: function(type, name) { - var records = this.getRecords(type); - var typeToSend; - - typeToSend = { - name: name || type.toString(), - count: get(records, 'length'), - columns: this.columnsForType(type), - object: type - }; - - - return typeToSend; - }, - - - /** - Fetches all models defined in the application. - - @private - @method getModelTypes - @return {Array} Array of model types - */ - getModelTypes: function() { - var self = this; - var containerDebugAdapter = this.get('containerDebugAdapter'); - var types; - - if (containerDebugAdapter.canCatalogEntriesByType('model')) { - types = containerDebugAdapter.catalogEntriesByType('model'); - } else { - types = this._getObjectsOnNamespaces(); - } - - // New adapters return strings instead of classes - types = emberA(types).map(function(name) { - return { - klass: self._nameToClass(name), - name: name - }; - }); - types = emberA(types).filter(function(type) { - return self.detect(type.klass); - }); - - return emberA(types); - }, - - /** - Loops over all namespaces and all objects - attached to them - - @private - @method _getObjectsOnNamespaces - @return {Array} Array of model type strings - */ - _getObjectsOnNamespaces: function() { - var namespaces = emberA(Namespace.NAMESPACES); - var types = emberA(); - var self = this; - - namespaces.forEach(function(namespace) { - for (var key in namespace) { - if (!namespace.hasOwnProperty(key)) { continue; } - // Even though we will filter again in `getModelTypes`, - // we should not call `lookupContainer` on non-models - // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) - if (!self.detect(namespace[key])) { continue; } - var name = dasherize(key); - if (!(namespace instanceof Application) && namespace.toString()) { - name = namespace + '/' + name; - } - types.push(name); - } - }); - return types; - }, - - /** - Fetches all loaded records for a given type. - - @private - @method getRecords - @return {Array} An array of records. - This array will be observed for changes, - so it should update when new records are added/removed. - */ - getRecords: function(type) { - return emberA(); - }, - - /** - Wraps a record and observers changes to it. - - @private - @method wrapRecord - @param {Object} record The record instance. - @return {Object} The wrapped record. Format: - columnValues: {Array} - searchKeywords: {Array} - */ - wrapRecord: function(record) { - var recordToSend = { object: record }; - - recordToSend.columnValues = this.getRecordColumnValues(record); - recordToSend.searchKeywords = this.getRecordKeywords(record); - recordToSend.filterValues = this.getRecordFilterValues(record); - recordToSend.color = this.getRecordColor(record); - - return recordToSend; - }, - - /** - Gets the values for each column. - - @private - @method getRecordColumnValues - @return {Object} Keys should match column names defined - by the model type. - */ - getRecordColumnValues: function(record) { - return {}; - }, - - /** - Returns keywords to match when searching records. - - @private - @method getRecordKeywords - @return {Array} Relevant keywords for search. - */ - getRecordKeywords: function(record) { - return emberA(); - }, - - /** - Returns the values of filters defined by `getFilters`. - - @private - @method getRecordFilterValues - @param {Object} record The record instance - @return {Object} The filter values - */ - getRecordFilterValues: function(record) { - return {}; - }, - - /** - Each record can have a color that represents its state. - - @private - @method getRecordColor - @param {Object} record The record instance - @return {String} The record's color - Possible options: black, red, blue, green - */ - getRecordColor: function(record) { - return null; - }, - - /** - Observes all relevant properties and re-sends the wrapped record - when a change occurs. - - @private - @method observerRecord - @param {Object} record The record instance - @param {Function} recordUpdated The callback to call when a record is updated. - @return {Function} The function to call to remove all observers. - */ - observeRecord: function(record, recordUpdated) { - return function(){}; - } - }); - }); -enifed("ember-extension-support/initializers", - [], - function() { - "use strict"; - - }); -enifed("ember-handlebars-compiler", - ["ember-metal/core","exports"], - function(__dependency1__, __exports__) { - /* global Handlebars:true */ - - // Remove "use strict"; from transpiled module (in browser builds only) until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - /** - @module ember - @submodule ember-handlebars-compiler - */ - - var Ember = __dependency1__["default"]; - - // ES6Todo: you'll need to import debugger once debugger is es6'd. - if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; } - if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; } - - var objectCreate = Object.create || function(parent) { - function F() {} - F.prototype = parent; - return new F(); - }; - - // set up for circular references later - var View, Component; - - // ES6Todo: when ember-debug is es6'ed import this. - // var emberAssert = Ember.assert; - var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); - if (!Handlebars && typeof eriuqer === 'function') { - Handlebars = eriuqer('handlebars'); - } - - Ember.assert("Ember Handlebars requires Handlebars version 2.0. Include " + - "a SCRIPT tag in the HTML HEAD linking to the Handlebars file " + - "before you link to Ember.", Handlebars); - - Ember.assert("Ember Handlebars requires Handlebars version 2.0. " + - "Please see more details at http://emberjs.com/blog/2014/10/16/handlebars-update.html.", - Handlebars.COMPILER_REVISION === 6); - - /** - Prepares the Handlebars templating library for use inside Ember's view - system. - - The `Ember.Handlebars` object is the standard Handlebars library, extended to - use Ember's `get()` method instead of direct property access, which allows - computed properties to be used inside templates. - - To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. - This will return a function that can be used by `Ember.View` for rendering. - - @class Handlebars - @namespace Ember - */ - var EmberHandlebars = Ember.Handlebars = Handlebars.create(); - - /** - Register a bound helper or custom view helper. - - ## Simple bound helper example - - ```javascript - Ember.Handlebars.helper('capitalize', function(value) { - return value.toUpperCase(); - }); - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{capitalize name}} - ``` - - 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`. - - ## 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: - - ```javascript - Ember.Handlebars.helper('calendar', App.CalendarView): - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{calendar}} - ``` - - Which is functionally equivalent to: - - ```handlebars - {{view 'calendar'}} - ``` - - Options in the helper will be passed to the view in exactly the same - manner as with the `view` helper. - - @method helper - @for Ember.Handlebars - @param {String} name - @param {Function|Ember.View} function or view class constructor - @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 - - 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); - } - - 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__) { - "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 - */ - - // 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; - - - // 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; - - // 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); - - // run load hooks - runLoadHooks('Ember.Handlebars', EmberHandlebars); - - __exports__["default"] = EmberHandlebars; - }); -enifed("ember-handlebars/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-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__) { - "use strict"; - var Checkbox = __dependency1__["default"]; - var TextField = __dependency2__["default"]; - var TextArea = __dependency3__["default"]; - - var Ember = __dependency4__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var EmberHandlebars = __dependency5__["default"]; - - /** - @module ember - @submodule ember-handlebars-compiler - */ - - /** - - The `{{input}}` helper inserts an HTML `` tag into the template, - with a `type` value of either `text` or `checkbox`. If no `type` is provided, - `text` will be the default value applied. The attributes of `{{input}}` - match those of the native HTML tag as closely as possible for these two types. - - ## Use as text field - An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. - The following HTML attributes can be set via the helper: - - - - - - - - - - - - -
    `readonly``required``autofocus`
    `value``placeholder``disabled`
    `size``tabindex``maxlength`
    `name``min``max`
    `pattern``accept``autocomplete`
    `autosave``formaction``formenctype`
    `formmethod``formnovalidate``formtarget`
    `height``inputmode``multiple`
    `step``width``form`
    `selectionDirection``spellcheck` 
    - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input value="http://www.facebook.com"}} - ``` - - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - firstName: "Stanley", - entryNotAllowed: true - }); - ``` - - - ```handlebars - {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} - ``` - - - ```html - - ``` - - ## Actions - - The helper can send multiple actions based on user events. - - 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` - * `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 - {{input focus-in="alertMessage"}} - ``` - - - See more about [Text Support Actions](/api/classes/Ember.TextField.html) - - ## Extension - - Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing - arguments from the helper to `Ember.TextField`'s `create` method. You can extend the - capabilities of text inputs in your applications by reopening this class. For example, - if you are building a Bootstrap project where `data-*` attributes are used, you - can add one to the `TextField`'s `attributeBindings` property: - - - ```javascript - Ember.TextField.reopen({ - attributeBindings: ['data-error'] - }); - ``` - - Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` - 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) - - - ## Use as checkbox - - An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. - The following HTML attributes can be set via the helper: - - * `checked` - * `disabled` - * `tabindex` - * `indeterminate` - * `name` - * `autofocus` - * `form` - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input type="checkbox" name="isAdmin"}} - ``` - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - isAdmin: true - }); - ``` - - - ```handlebars - {{input type="checkbox" checked=isAdmin }} - ``` - - - ```html - - ``` - - ## Extension - - Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing - arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the - capablilties of checkbox inputs in your applications by reopening this class. For example, - if you wanted to add a css class to all checkboxes in your application: - - - ```javascript - Ember.Checkbox.reopen({ - classNames: ['my-app-checkbox'] - }); - ``` - - - @method input - @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); - - 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; - } - - 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'); - - return EmberHandlebars.helpers.view.call(this, Checkbox, options); - } else { - delete hash.on; - - hash.onEvent = onEvent || 'enter'; - return EmberHandlebars.helpers.view.call(this, TextField, options); - } - } - - __exports__.inputHelper = inputHelper;/** - `{{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(options) { - Ember.assert('You can only pass attributes to the `textarea` helper, not arguments', arguments.length < 2); - - return EmberHandlebars.helpers.view.call(this, TextArea, options); - } - - __exports__.textareaHelper = textareaHelper; - }); -enifed("ember-handlebars/controls/checkbox", - ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var set = __dependency2__.set; - var View = __dependency3__["default"]; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `checkbox`. - - See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Direct manipulation of `checked` - - The `checked` attribute of an `Ember.Checkbox` object should always be set - through the Ember object or by interacting with its rendered element - representation via the mouse, keyboard, or touch. Updating the value of the - checkbox via jQuery will result in the checked value of the object and its - element losing synchronization. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class Checkbox - @namespace Ember - @extends Ember.View - */ - __exports__["default"] = View.extend({ - instrumentDisplay: '{{input type="checkbox"}}', - - classNames: ['ember-checkbox'], - - tagName: 'input', - - attributeBindings: [ - 'type', - 'checked', - 'indeterminate', - 'disabled', - 'tabindex', - 'name', - 'autofocus', - 'required', - 'form' - ], - - type: 'checkbox', - checked: false, - disabled: false, - indeterminate: false, - - init: function() { - this._super(); - this.on('change', this, this._updateElementValue); - }, - - didInsertElement: function() { - this._super(); - get(this, 'element').indeterminate = !!get(this, 'indeterminate'); - }, - - _updateElementValue: function() { - set(this, 'checked', this.$().prop('checked')); - } - }); - }); -enifed("ember-handlebars/controls/select", - ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - - var forEach = __dependency2__.forEach; - var indexOf = __dependency2__.indexOf; - var indexesOf = __dependency2__.indexesOf; - var replace = __dependency2__.replace; - - var get = __dependency3__.get; - var set = __dependency4__.set; - var View = __dependency5__["default"]; - var CollectionView = __dependency6__["default"]; - var isArray = __dependency7__.isArray; - var isNone = __dependency8__["default"]; - var computed = __dependency9__.computed; - var emberA = __dependency10__.A; - var observer = __dependency11__.observer; - var defineProperty = __dependency12__.defineProperty; - - - var SelectOption = View.extend({ - instrumentDisplay: 'Ember.SelectOption', - - tagName: 'option', - attributeBindings: ['value', 'selected'], - - defaultTemplate: function(context, options) { - options = { data: options.data, hash: {} }; - EmberHandlebars.helpers.bind.call(context, "view.label", options); - }, - - init: function() { - this.labelPathDidChange(); - this.valuePathDidChange(); - - this._super(); - }, - - selected: computed(function() { - var content = get(this, 'content'); - var selection = get(this, 'parentView.selection'); - if (get(this, 'parentView.multiple')) { - return selection && indexOf(selection, content.valueOf()) > -1; - } else { - // Primitives get passed through bindings as objects... since - // `new Number(4) !== 4`, we use `==` below - return content == selection; // jshint ignore:line - } - }).property('content', 'parentView.selection'), - - labelPathDidChange: observer('parentView.optionLabelPath', function() { - var labelPath = get(this, 'parentView.optionLabelPath'); - - if (!labelPath) { return; } - - defineProperty(this, 'label', computed(function() { - return get(this, labelPath); - }).property(labelPath)); - }), - - valuePathDidChange: observer('parentView.optionValuePath', function() { - var valuePath = get(this, 'parentView.optionValuePath'); - - if (!valuePath) { return; } - - defineProperty(this, 'value', computed(function() { - return get(this, valuePath); - }).property(valuePath)); - }) - }); - - var SelectOptgroup = CollectionView.extend({ - instrumentDisplay: 'Ember.SelectOptgroup', - - tagName: 'optgroup', - attributeBindings: ['label'], - - selectionBinding: 'parentView.selection', - multipleBinding: 'parentView.multiple', - optionLabelPathBinding: 'parentView.optionLabelPath', - optionValuePathBinding: 'parentView.optionValuePath', - - itemViewClassBinding: 'parentView.optionView' - }); - - /** - The `Ember.Select` view class renders a - [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, - allowing the user to choose from a list of options. - - The text and `value` property of each ` - - - ``` - - The `value` attribute of the selected `"); - return buffer; - },"3":function(depth0,helpers,partials,data) { - var stack1; - stack1 = helpers.each.call(depth0, "group", "in", "view.groupedContent", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(4, data),"inverse":this.noop,"types":["ID","ID","ID"],"contexts":[depth0,depth0,depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - },"4":function(depth0,helpers,partials,data) { - var escapeExpression=this.escapeExpression; - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {"name":"view","hash":{ - 'label': ("group.label"), - 'content': ("group.content") - },"hashTypes":{'label': "ID",'content': "ID"},"hashContexts":{'label': depth0,'content': depth0},"types":["ID"],"contexts":[depth0],"data":data}))); - },"6":function(depth0,helpers,partials,data) { - var stack1; - stack1 = helpers.each.call(depth0, "item", "in", "view.content", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(7, data),"inverse":this.noop,"types":["ID","ID","ID"],"contexts":[depth0,depth0,depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - },"7":function(depth0,helpers,partials,data) { - var escapeExpression=this.escapeExpression; - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {"name":"view","hash":{ - 'content': ("item") - },"hashTypes":{'content': "ID"},"hashContexts":{'content': depth0},"types":["ID"],"contexts":[depth0],"data":data}))); - },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var stack1, buffer = ''; - stack1 = helpers['if'].call(depth0, "view.prompt", {"name":"if","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(1, data),"inverse":this.noop,"types":["ID"],"contexts":[depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {"name":"if","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(3, data),"inverse":this.program(6, data),"types":["ID"],"contexts":[depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - return buffer; - },"useData":true}), - attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', - 'form', 'size'], - - /** - The `multiple` attribute of the select element. Indicates whether multiple - options can be selected. - - @property multiple - @type Boolean - @default false - */ - multiple: false, - - /** - The `disabled` attribute of the select element. Indicates whether - the element is disabled from interactions. - - @property disabled - @type Boolean - @default false - */ - disabled: false, - - /** - The `required` attribute of the select element. Indicates whether - a selected option is required for form validation. - - @property required - @type Boolean - @default false - @since 1.5.0 - */ - required: false, - - /** - The list of options. - - If `optionLabelPath` and `optionValuePath` are not overridden, this should - be a list of strings, which will serve simultaneously as labels and values. - - Otherwise, this should be a list of objects. For instance: - - ```javascript - var App = Ember.Application.create(); - var App.MySelect = Ember.Select.extend({ - content: Ember.A([ - { id: 1, firstName: 'Yehuda' }, - { id: 2, firstName: 'Tom' } - ]), - optionLabelPath: 'content.firstName', - optionValuePath: 'content.id' - }); - ``` - - @property content - @type Array - @default null - */ - content: null, - - /** - When `multiple` is `false`, the element of `content` that is currently - selected, if any. - - When `multiple` is `true`, an array of such elements. - - @property selection - @type Object or Array - @default null - */ - selection: null, - - /** - In single selection mode (when `multiple` is `false`), value can be used to - get the current selection's value or set the selection by it's value. - - It is not currently supported in multiple selection mode. - - @property value - @type String - @default null - */ - value: computed(function(key, value) { - if (arguments.length === 2) { return value; } - var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); - return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); - }).property('selection'), - - /** - If given, a top-most dummy option will be rendered to serve as a user - prompt. - - @property prompt - @type String - @default null - */ - prompt: null, - - /** - The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionLabelPath - @type String - @default 'content' - */ - optionLabelPath: 'content', - - /** - The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionValuePath - @type String - @default 'content' - */ - optionValuePath: 'content', - - /** - The path of the option group. - When this property is used, `content` should be sorted by `optionGroupPath`. - - @property optionGroupPath - @type String - @default null - */ - optionGroupPath: null, - - /** - The view class for optgroup. - - @property groupView - @type Ember.View - @default Ember.SelectOptgroup - */ - groupView: SelectOptgroup, - - groupedContent: computed(function() { - var groupPath = get(this, 'optionGroupPath'); - var groupedContent = emberA(); - var content = get(this, 'content') || []; - - forEach(content, function(item) { - var label = get(item, groupPath); - - if (get(groupedContent, 'lastObject.label') !== label) { - groupedContent.pushObject({ - label: label, - content: emberA() - }); - } - - get(groupedContent, 'lastObject.content').push(item); - }); - - return groupedContent; - }).property('optionGroupPath', 'content.@each'), - - /** - The view class for option. - - @property optionView - @type Ember.View - @default Ember.SelectOption - */ - optionView: SelectOption, - - _change: function() { - if (get(this, 'multiple')) { - this._changeMultiple(); - } else { - this._changeSingle(); - } - }, - - selectionDidChange: observer('selection.@each', function() { - var selection = get(this, 'selection'); - if (get(this, 'multiple')) { - if (!isArray(selection)) { - set(this, 'selection', emberA([selection])); - return; - } - this._selectionDidChangeMultiple(); - } else { - this._selectionDidChangeSingle(); - } - }), - - valueDidChange: observer('value', function() { - var content = get(this, 'content'); - var value = get(this, 'value'); - var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); - var selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')); - var selection; - - if (value !== selectedValue) { - selection = content ? content.find(function(obj) { - return value === (valuePath ? get(obj, valuePath) : obj); - }) : null; - - this.set('selection', selection); - } - }), - - - _triggerChange: function() { - var selection = get(this, 'selection'); - var value = get(this, 'value'); - - if (!isNone(selection)) { this.selectionDidChange(); } - if (!isNone(value)) { this.valueDidChange(); } - - this._change(); - }, - - _changeSingle: function() { - var selectedIndex = this.$()[0].selectedIndex; - var content = get(this, 'content'); - var prompt = get(this, 'prompt'); - - if (!content || !get(content, 'length')) { return; } - if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } - - if (prompt) { selectedIndex -= 1; } - set(this, 'selection', content.objectAt(selectedIndex)); - }, - - - _changeMultiple: function() { - var options = this.$('option:selected'); - var prompt = get(this, 'prompt'); - var offset = prompt ? 1 : 0; - var content = get(this, 'content'); - var selection = get(this, 'selection'); - - if (!content) { return; } - if (options) { - var selectedIndexes = options.map(function() { - return this.index - offset; - }).toArray(); - var newSelection = content.objectsAt(selectedIndexes); - - if (isArray(selection)) { - replace(selection, 0, get(selection, 'length'), newSelection); - } else { - set(this, 'selection', newSelection); - } - } - }, - - _selectionDidChangeSingle: function() { - var el = this.get('element'); - if (!el) { return; } - - var content = get(this, 'content'); - var selection = get(this, 'selection'); - var selectionIndex = content ? indexOf(content, selection) : -1; - var prompt = get(this, 'prompt'); - - if (prompt) { selectionIndex += 1; } - if (el) { el.selectedIndex = selectionIndex; } - }, - - _selectionDidChangeMultiple: function() { - var content = get(this, 'content'); - var selection = get(this, 'selection'); - var selectedIndexes = content ? indexesOf(content, selection) : [-1]; - var prompt = get(this, 'prompt'); - var offset = prompt ? 1 : 0; - var options = this.$('option'); - var adjusted; - - if (options) { - options.each(function() { - adjusted = this.index > -1 ? this.index - offset : -1; - this.selected = indexOf(selectedIndexes, adjusted) > -1; - }); - } - }, - - init: function() { - this._super(); - this.on("didInsertElement", this, this._triggerChange); - this.on("change", this, this._change); - } - }); - - __exports__["default"] = Select; - __exports__.Select = Select; - __exports__.SelectOption = SelectOption; - __exports__.SelectOptgroup = SelectOptgroup; - }); -enifed("ember-handlebars/controls/text_area", - ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var get = __dependency1__.get; - var Component = __dependency2__["default"]; - var TextSupport = __dependency3__["default"]; - var observer = __dependency4__.observer; - - /** - The internal class used to create textarea element when the `{{textarea}}` - helper is used. - - See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. - - ## Layout and LayoutName properties - - Because HTML `textarea` elements do not contain inner HTML the `layout` and - `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextArea - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - __exports__["default"] = Component.extend(TextSupport, { - instrumentDisplay: '{{textarea}}', - - classNames: ['ember-text-area'], - - tagName: "textarea", - attributeBindings: [ - 'rows', - 'cols', - 'name', - 'selectionEnd', - 'selectionStart', - 'wrap', - 'lang', - 'dir' - ], - rows: null, - cols: null, - - _updateElementValue: observer('value', function() { - // We do this check so cursor position doesn't get affected in IE - var value = get(this, 'value'); - var $el = this.$(); - if ($el && value !== $el.val()) { - $el.val(value); - } - }), - - init: function() { - this._super(); - this.on("didInsertElement", this, this._updateElementValue); - } - }); - }); -enifed("ember-handlebars/controls/text_field", - ["ember-views/views/component","ember-handlebars/controls/text_support","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - var Component = __dependency1__["default"]; - var TextSupport = __dependency2__["default"]; - - /** - - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `text`. - - See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextField - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - __exports__["default"] = Component.extend(TextSupport, { - instrumentDisplay: '{{input type="text"}}', - - classNames: ['ember-text-field'], - tagName: "input", - attributeBindings: [ - 'accept', - 'autocomplete', - 'autosave', - 'dir', - 'formaction', - 'formenctype', - 'formmethod', - 'formnovalidate', - 'formtarget', - 'height', - 'inputmode', - 'lang', - 'list', - 'max', - 'min', - 'multiple', - 'name', - 'pattern', - 'size', - 'step', - 'type', - 'value', - 'width' - ], - - /** - The `value` attribute of the input element. As the user inputs text, this - property is updated live. - - @property value - @type String - @default "" - */ - value: "", - - /** - The `type` attribute of the input element. - - @property type - @type String - @default "text" - */ - type: "text", - - /** - The `size` of the text field in characters. - - @property size - @type String - @default null - */ - size: null, - - /** - The `pattern` attribute of input element. - - @property pattern - @type String - @default null - */ - pattern: null, - - /** - The `min` attribute of input element used with `type="number"` or `type="range"`. - - @property min - @type String - @default null - @since 1.4.0 - */ - min: null, - - /** - The `max` attribute of input element used with `type="number"` or `type="range"`. - - @property max - @type String - @default null - @since 1.4.0 - */ - max: null - }); - }); -enifed("ember-handlebars/controls/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-handlebars - */ - - var get = __dependency1__.get; - var set = __dependency2__.set; - var Mixin = __dependency3__.Mixin; - var TargetActionSupport = __dependency4__["default"]; - - /** - Shared mixin used by `Ember.TextField` and `Ember.TextArea`. - - @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()); - }, - - /** - Called when the user inserts a new line. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. - Uses sendAction to send the `enter` action. - - @method insertNewline - @param {Event} event - */ - insertNewline: function(event) { - sendAction('enter', this, event); - sendAction('insert-newline', this, event); - }, - - /** - Called when the user hits escape. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. - Uses sendAction to send the `escape-press` action. - - @method cancel - @param {Event} event - */ - cancel: function(event) { - sendAction('escape-press', this, event); - }, - - change: function(event) { - this._elementValueDidChange(event); - }, - - /** - Called when the text area is focused. - - Uses sendAction to send the `focus-in` action. - - @method focusIn - @param {Event} event - */ - focusIn: function(event) { - sendAction('focus-in', this, event); - }, - - /** - Called when the text area is blurred. - - Uses sendAction to send the `focus-out` action. - - @method focusOut - @param {Event} event - */ - focusOut: function(event) { - this._elementValueDidChange(event); - sendAction('focus-out', this, event); - }, - - /** - Called when the user presses a key. Enabled by setting - the `onEvent` property to `keyPress`. - - Uses sendAction to send the `key-press` action. - - @method keyPress - @param {Event} event - */ - keyPress: function(event) { - sendAction('key-press', this, event); - }, - - /** - Called when the browser triggers a `keyup` event on the element. - - Uses sendAction to send the `key-up` action passing the current value - and event as parameters. - - @method keyUp - @param {Event} event - */ - keyUp: function(event) { - this.interpretKeyEvents(event); - - this.sendAction('key-up', get(this, 'value'), event); - }, - - /** - Called when the browser triggers a `keydown` event on the element. - - Uses sendAction to send the `key-down` action passing the current value - and event as parameters. Note that generally in key-down the value is unchanged - (as the key pressing has not completed yet). - - @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-handlebars/ext", - ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-metal/path_cache","ember-metal/streams/stream","ember-metal/streams/read","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup - // var emberAssert = Ember.assert; - - var fmt = __dependency2__.fmt; - - var EmberHandlebars = __dependency3__["default"]; - - var get = __dependency4__.get; - var EmberError = __dependency5__["default"]; - var IS_BINDING = __dependency6__.IS_BINDING; - - var View = __dependency7__["default"]; - var detectIsGlobal = __dependency8__.isGlobal; - - // late bound via requireModule because of circular dependencies. - var resolveHelper, SimpleHandlebarsView; - - var Stream = __dependency9__["default"]; - var readArray = __dependency10__.readArray; - var readHash = __dependency10__.readHash; - - var slice = [].slice; - - /** - Lookup both on root and on window. If the path starts with - a keyword, the corresponding object will be looked up in the - template's data hash and used to resolve the path. - - @method get - @for Ember.Handlebars - @param {Object} root The object to look up the property on - @param {String} path The path to be lookedup - @param {Object} options The template's option hash - @deprecated - */ - function handlebarsGet(root, path, options) { - Ember.deprecate('Usage of Ember.Handlebars.get is deprecated, use a Component or Ember.Handlebars.makeBoundHelper instead.'); - - return options.data.view.getStream(path).value(); - } - - /** - handlebarsGetView resolves a view based on strings passed into a template. - For example: - - ```handlebars - {{view "some-view"}} - {{view view.someView}} - {{view App.SomeView}} {{! deprecated }} - ``` - - A value is first checked to be a string- non-strings are presumed to be - an object and returned. This handles the "access a view on a context" - case (line 2 in the above examples). - - Next a string is normalized, then called on the context with `get`. If - there is still no value, a GlobalPath will be fetched from the global - context (raising a deprecation) and a localPath will be passed to the - container to be looked up. - - @private - @for Ember.Handlebars - @param {Object} context The context of the template being rendered - @param {String} path The path to be lookedup - @param {Object} container The container - @param {Object} data The template's data hash - */ - function handlebarsGetView(context, path, container, data) { - var viewClass; - if ('string' === typeof path) { - if (!data) { - throw new Error("handlebarsGetView: must pass data"); - } - - // Only lookup view class on context if there is a context. If not, - // the global lookup path on get may kick in. - var lazyValue = data.view.getStream(path); - viewClass = lazyValue.value(); - var isGlobal = detectIsGlobal(path); - - if (!viewClass && !isGlobal) { - Ember.assert("View requires a container to resolve views not passed in through the context", !!container); - viewClass = container.lookupFactory('view:'+path); - } - if (!viewClass && isGlobal) { - var globalViewClass = get(path); - Ember.deprecate('Resolved the view "'+path+'" on the global context. Pass a view name to be looked' + - ' up on the container instead, such as {{view "select"}}.' + - ' http://emberjs.com/guides/deprecations#toc_global-lookup-of-views', !globalViewClass); - if (globalViewClass) { - viewClass = globalViewClass; - } - } - } else { - viewClass = path; - } - - // Sometimes a view's value is yet another path - if ('string' === typeof viewClass && data && data.view) { - viewClass = handlebarsGetView(data.view, viewClass, container, data); - } - - Ember.assert( - fmt(path+" must be a subclass or an instance of Ember.View, not %@", [viewClass]), - View.detect(viewClass) || View.detectInstance(viewClass) - ); - - return viewClass; - } - - function stringifyValue(value, shouldEscape) { - if (value === null || value === undefined) { - value = ""; - } else if (!(value instanceof Handlebars.SafeString)) { - value = String(value); - } - - if (shouldEscape) { - value = Handlebars.Utils.escapeExpression(value); - } - - return value; - } - - __exports__.stringifyValue = stringifyValue;/** - Registers a helper in Handlebars that will be called if no property with the - given name can be found on the current context object, and no helper with - that name is registered. - - This throws an exception with a more helpful error message so the user can - track down where the problem is happening. - - @private - @method helperMissing - @for Ember.Handlebars.helpers - @param {String} path - @param {Hash} options - */ - function helperMissingHelper(path) { - if (!resolveHelper) { - resolveHelper = requireModule('ember-handlebars/helpers/binding')['resolveHelper']; - } // ES6TODO: stupid circular dep - - var error, fmtError, view = ""; - - var options = arguments[arguments.length - 1]; - - var helper = resolveHelper(options.data.view.container, options.name); - - if (helper) { - return helper.apply(this, arguments); - } - - if (options.data) { - view = options.data.view; - } - - if (options.name.match(/-/)) { - error = "%@ Handlebars error: Could not find component or helper named '%@'"; - fmtError = fmt(error, [view, options.name]); - } else { - error = "%@ Handlebars error: Could not find property '%@' on object %@."; - fmtError = fmt(error, [view, options.name, this]); - } - - throw new EmberError(fmtError); - } - - __exports__.helperMissingHelper = helperMissingHelper;/** - @private - @method blockHelperMissingHelper - @for Ember.Handlebars.helpers - */ - function blockHelperMissingHelper() { - return; - } - - __exports__.blockHelperMissingHelper = blockHelperMissingHelper;/** - 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 example - - ```javascript - Ember.Handlebars.registerBoundHelper('capitalize', function(value) { - return Ember.String.capitalize(value); - }); - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{capitalize name}} - ``` - - 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. - - ## Example with options - - Like normal handlebars helpers, bound helpers have access to the options - passed into the helper call. - - ```javascript - Ember.Handlebars.registerBoundHelper('repeat', function(value, options) { - var count = options.hash.count; - var a = []; - while(a.length < count) { - a.push(value); - } - return a.join(''); - }); - ``` - - This helper could be used in a template as follows: - - ```handlebars - {{repeat text count=3}} - ``` - - ## Example with bound options - - Bound hash options are also supported. Example: - - ```handlebars - {{repeat text count=numRepeats}} - ``` - - 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. - - ## 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} function - @param {String} dependentKeys* - */ - function registerBoundHelper(name, fn) { - var boundHelperArgs = slice.call(arguments, 1); - var boundFn = makeBoundHelper.apply(this, boundHelperArgs); - EmberHandlebars.registerHelper(name, boundFn); - } - - __exports__.registerBoundHelper = registerBoundHelper;/** - A helper function used by `registerBoundHelper`. Takes the - provided Handlebars helper function fn and returns it in wrapped - bound helper form. - - The main use case for using this outside of `registerBoundHelper` - is for registering helpers on the container: - - ```js - var boundHelperFn = Ember.Handlebars.makeBoundHelper(function(word) { - return word.toUpperCase(); - }); - - container.register('helper:my-bound-helper', boundHelperFn); - ``` - - In the above example, if the helper function hadn't been wrapped in - `makeBoundHelper`, the registered helper would be unbound. - - @method makeBoundHelper - @for Ember.Handlebars - @param {Function} function - @param {String} dependentKeys* - @since 1.2.0 - */ - function makeBoundHelper(fn) { - if (!SimpleHandlebarsView) { - SimpleHandlebarsView = requireModule('ember-handlebars/views/handlebars_bound_view')['SimpleHandlebarsView']; - } // ES6TODO: stupid circular dep - - var dependentKeys = []; - for (var i = 1; i < arguments.length; i++) { - dependentKeys.push(arguments[i]); - } - - function helper() { - var numParams = arguments.length - 1; - var options = arguments[numParams]; - var data = options.data; - var view = data.view; - var types = options.types; - var hash = options.hash; - var hashTypes = options.hashTypes; - var context = this; - - Ember.assert("registerBoundHelper-generated helpers do not support use with Handlebars blocks.", !options.fn); - - var properties = new Array(numParams); - var params = new Array(numParams); - - for (var i = 0; i < numParams; i++) { - properties[i] = arguments[i]; - if (types[i] === 'ID') { - params[i] = view.getStream(arguments[i]); - } else { - params[i] = arguments[i]; - } - } - - for (var prop in hash) { - if (IS_BINDING.test(prop)) { - hash[prop.slice(0, -7)] = view.getStream(hash[prop]); - hash[prop] = undefined; - } else if (hashTypes[prop] === 'ID') { - hash[prop] = view.getStream(hash[prop]); - } - } - - var valueFn = function() { - var args = readArray(params); - args.push({ - hash: readHash(hash), - data: { properties: properties } - }); - return fn.apply(context, args); - }; - - if (data.isUnbound) { - return valueFn(); - } else { - var lazyValue = new Stream(valueFn); - var bindView = new SimpleHandlebarsView(lazyValue, !options.hash.unescaped); - view.appendChild(bindView); - - var scheduledRerender = view._wrapAsScheduled(bindView.rerender); - lazyValue.subscribe(scheduledRerender, bindView); - - var param; - - for (i = 0; i < numParams; i++) { - param = params[i]; - if (param && param.isStream) { - param.subscribe(lazyValue.notify, lazyValue); - } - } - - for (prop in hash) { - param = hash[prop]; - if (param && param.isStream) { - param.subscribe(lazyValue.notify, lazyValue); - } - } - - if (numParams > 0) { - var firstParam = params[0]; - // Only bother with subscriptions if the first argument - // is a stream itself, and not a primitive. - if (firstParam && firstParam.isStream) { - 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 helper; - } - - __exports__.makeBoundHelper = makeBoundHelper; - __exports__.handlebarsGetView = handlebarsGetView; - __exports__.handlebarsGet = handlebarsGet; - }); -enifed("ember-handlebars/helpers/bind_attr", - ["ember-metal/core","ember-handlebars-compiler","ember-metal/utils","ember-runtime/system/string","ember-metal/array","ember-views/views/view","ember-metal/keys","ember-views/system/sanitize_attribute_value","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var EmberHandlebars = __dependency2__["default"]; - - var uuid = __dependency3__.uuid; - var fmt = __dependency4__.fmt; - var typeOf = __dependency3__.typeOf; - var forEach = __dependency5__.forEach; - var View = __dependency6__["default"]; - var keys = __dependency7__["default"]; - - var sanitizeAttributeValue = __dependency8__["default"]; - - var helpers = EmberHandlebars.helpers; - var SafeString = EmberHandlebars.SafeString; - - /** - `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 - - ``` - - 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(options) { - var attrs = options.hash; - - Ember.assert("You must specify at least one hash argument to bind-attr", !!keys(attrs).length); - - var view = options.data.view; - var ret = []; - - // we relied on the behavior of calling without - // context to mean this === window, but when running - // "use strict", it's possible for this to === undefined; - var ctx = this || window; - - // Generate a unique id for this element. This will be added as a - // data attribute to the element so it can be looked up when - // the bound property changes. - var dataId = uuid(); - - // Handle classes differently, as we can bind multiple classes - var classBindings = attrs['class']; - if (classBindings != null) { - var classResults = bindClasses(ctx, classBindings, view, dataId, options); - - ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); - delete attrs['class']; - } - - var attrKeys = keys(attrs); - - // For each attribute passed, create an observer and emit the - // current value of the property as an attribute. - forEach.call(attrKeys, function(attr) { - var path = attrs[attr]; - - Ember.assert(fmt("You must provide an expression as the value of bound attribute." + - " You specified: %@=%@", [attr, path]), typeof path === 'string'); - - var lazyValue = view.getStream(path); - var value = lazyValue.value(); - value = sanitizeAttributeValue(null, attr, value); - 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'); - - lazyValue.subscribe(view._wrapAsScheduled(function applyAttributeBindings() { - var result = lazyValue.value(); - - Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]), - result === null || result === undefined || typeof result === 'number' || - typeof result === 'string' || typeof result === 'boolean'); - - var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); - - Ember.assert("An attribute binding was triggered when the element was not in the DOM", elem && elem.length !== 0); - - View.applyAttributeBindings(elem, attr, result); - })); - - // if this changes, also change the logic in ember-views/lib/views/view.js - if ((type === 'string' || (type === 'number' && !isNaN(value)))) { - ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); - } else if (value && type === 'boolean') { - // The developer controls the attr name, so it should always be safe - ret.push(attr + '="' + attr + '"'); - } - }, this); - - // Add the unique identifier - // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG - ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); - return new SafeString(ret.join(' ')); - } - - /** - See `bind-attr` - - @method bindAttr - @for Ember.Handlebars.helpers - @deprecated - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function bindAttrHelperDeprecated() { - Ember.deprecate("The 'bindAttr' view helper is deprecated in favor of 'bind-attr'"); - - return helpers['bind-attr'].apply(this, arguments); - } - - /** - Helper that, given a space-separated string of property paths and a context, - returns an array of class names. Calling this method also has the side - effect of setting up observers at those property paths, such that if they - change, the correct class name will be reapplied to the DOM element. - - For example, if you pass the string "fooBar", it will first look up the - "fooBar" value of the context. If that value is true, it will add the - "foo-bar" class to the current element (i.e., the dasherized form of - "fooBar"). If the value is a string, it will add that string as the class. - Otherwise, it will not add any new class name. - - @private - @method bindClasses - @for Ember.Handlebars - @param {Ember.Object} context The context from which to lookup properties - @param {String} classBindings A string, space-separated, of class bindings - to use - @param {View} view The view in which observers should look for the - element to update - @param {Srting} bindAttrId Optional bindAttr id used to lookup elements - @return {Array} An array of class names to add - */ - function bindClasses(context, classBindings, view, bindAttrId, options) { - var ret = []; - var newClass, value, elem; - - // For each property passed, loop through and setup - // an observer. - forEach.call(classBindings.split(' '), function(binding) { - - // 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; - var parsedPath = View._parsePropertyPath(binding); - var path = parsedPath.path; - var initialValue; - - if (path === '') { - initialValue = true; - } else { - var lazyValue = view.getStream(path); - initialValue = lazyValue.value(); - - // Set up an observer on the context. If the property changes, toggle the - // class name. - lazyValue.subscribe(view._wrapAsScheduled(function applyClassNameBindings() { - // Get the current value of the property - var value = lazyValue.value(); - newClass = classStringForParsedPath(parsedPath, value); - elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); - - Ember.assert("A class name binding was triggered when the element was not in the DOM", elem && elem.length !== 0); - - // If we had previously added a class to the element, remove it. - if (oldClass) { - elem.removeClass(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; - } - })); - } - - // We've already setup the observer; now we just need to figure out the - // correct behavior right now on the first pass through. - value = classStringForParsedPath(parsedPath, initialValue); - - if (value) { - ret.push(value); - - // Make sure we save the current value so that it can be removed if the - // observer fires. - oldClass = value; - } - }); - - return ret; - } - - function classStringForParsedPath(parsedPath, value) { - return View._classStringForValue(parsedPath.path, value, parsedPath.className, parsedPath.falsyClassName); - } - - __exports__["default"] = bindAttrHelper; - - __exports__.bindAttrHelper = bindAttrHelper; - __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; - __exports__.bindClasses = bindClasses; - }); -enifed("ember-handlebars/helpers/binding", - ["ember-metal/core","ember-handlebars-compiler","ember-metal/is_none","ember-metal/run_loop","ember-metal/cache","ember-metal/streams/simple","ember-handlebars/views/handlebars_bound_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var EmberHandlebars = __dependency2__["default"]; - - var isNone = __dependency3__["default"]; - var run = __dependency4__["default"]; - var Cache = __dependency5__["default"]; - var SimpleStream = __dependency6__["default"]; - - var _HandlebarsBoundView = __dependency7__._HandlebarsBoundView; - var SimpleHandlebarsView = __dependency7__.SimpleHandlebarsView; - - var helpers = EmberHandlebars.helpers; - - function exists(value) { - return !isNone(value); - } - - // Binds a property into the DOM. This will create a hook in DOM that the - // KVO system will look for and update if the property changes. - function bind(property, options, preserveContext, shouldDisplay, valueNormalizer, childProperties, _viewClass) { - var data = options.data; - var view = data.view; - - // we relied on the behavior of calling without - // context to mean this === window, but when running - // "use strict", it's possible for this to === undefined; - var currentContext = this || window; - - var valueStream = view.getStream(property); - var lazyValue; - - if (childProperties) { - lazyValue = new SimpleStream(valueStream); - - var subscriber = function(childStream) { - childStream.value(); - lazyValue.notify(); - }; - - for (var i = 0; i < childProperties.length; i++) { - var childStream = valueStream.get(childProperties[i]); - childStream.value(); - childStream.subscribe(subscriber); - } - } else { - lazyValue = valueStream; - } - - // Set up observers for observable objects - var viewClass = _viewClass || _HandlebarsBoundView; - var viewOptions = { - preserveContext: preserveContext, - shouldDisplayFunc: shouldDisplay, - valueNormalizerFunc: valueNormalizer, - displayTemplate: options.fn, - inverseTemplate: options.inverse, - lazyValue: lazyValue, - previousContext: currentContext, - isEscaped: !options.hash.unescaped, - templateData: options.data, - templateHash: options.hash, - helperName: options.helperName - }; - - if (options.keywords) { - viewOptions._keywords = options.keywords; - } - - // Create the view that will wrap the output of this template/property - // and add it to the nearest view's childViews array. - // See the documentation of Ember._HandlebarsBoundView for more. - var bindView = view.createChildView(viewClass, viewOptions); - - view.appendChild(bindView); - - lazyValue.subscribe(view._wrapAsScheduled(function() { - run.scheduleOnce('render', bindView, 'rerenderIfNeeded'); - })); - } - - function simpleBind(currentContext, lazyValue, options) { - var data = options.data; - var view = data.view; - - var bindView = new SimpleHandlebarsView( - lazyValue, !options.hash.unescaped - ); - - bindView._parentView = view; - view.appendChild(bindView); - - lazyValue.subscribe(view._wrapAsScheduled(function() { - run.scheduleOnce('render', bindView, 'rerender'); - })); - } - - /** - '_triageMustache' is used internally select between a binding, helper, or component for - the given context. Until this point, it would be hard to determine if the - mustache is a property reference or a regular helper reference. This triage - helper resolves that. - - This would not be typically invoked by directly. - - @private - @method _triageMustache - @for Ember.Handlebars.helpers - @param {String} property Property/helperID to triage - @param {Object} options hash of template/rendering options - @return {String} HTML string - */ - function _triageMustacheHelper(property, options) { - Ember.assert("You cannot pass more than one argument to the _triageMustache helper", arguments.length <= 2); - - var helper = EmberHandlebars.resolveHelper(options.data.view.container, property); - if (helper) { - return helper.call(this, options); - } - - return helpers.bind.call(this, property, options); - } - - 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} - */ - function resolveHelper(container, name) { - if (helpers[name]) { - return helpers[name]; - } - - if (!container || ISNT_HELPER_CACHE.get(name)) { - return; - } - - var helper = container.lookup('helper:' + name); - 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 = EmberHandlebars.makeViewHelper(Component); - container.register('helper:' + name, helper); - } - } - return helper; - } - - - /** - `bind` can be used to display a value, then update that value if it - changes. For example, if you wanted to print the `title` property of - `content`: - - ```handlebars - {{bind "content.title"}} - ``` - - This will return the `title` property as a string, then create a new observer - at the specified path. If it changes, it will update the value in DOM. Note - that if you need to support IE7 and IE8 you must modify the model objects - properties using `Ember.get()` and `Ember.set()` for this to work as it - relies on Ember's KVO system. For all other browsers this will be handled for - you automatically. - - @private - @method bind - @for Ember.Handlebars.helpers - @param {String} property Property to bind - @param {Function} fn Context to provide for rendering - @return {String} HTML string - */ - function bindHelper(property, options) { - Ember.assert("You cannot pass more than one argument to the bind helper", arguments.length <= 2); - - var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; - - if (!options.fn) { - var lazyValue = options.data.view.getStream(property); - return simpleBind(context, lazyValue, options); - } - - options.helperName = 'bind'; - - return bind.call(context, property, options, false, exists); - } - - __exports__.bind = bind; - __exports__._triageMustacheHelper = _triageMustacheHelper; - __exports__.resolveHelper = resolveHelper; - __exports__.bindHelper = bindHelper; - }); -enifed("ember-handlebars/helpers/collection", - ["ember-metal/core","ember-handlebars-compiler","ember-metal/mixin","ember-runtime/system/string","ember-metal/property_get","ember-metal/streams/simple","ember-handlebars/ext","ember-handlebars/helpers/view","ember-views/views/view","ember-views/views/collection_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert, Ember.deprecate - - // var emberAssert = Ember.assert; - // emberDeprecate = Ember.deprecate; - - var EmberHandlebars = __dependency2__["default"]; - - var IS_BINDING = __dependency3__.IS_BINDING; - var fmt = __dependency4__.fmt; - var get = __dependency5__.get; - var SimpleStream = __dependency6__["default"]; - var handlebarsGetView = __dependency7__.handlebarsGetView; - var ViewHelper = __dependency8__.ViewHelper; - var View = __dependency9__["default"]; - var CollectionView = __dependency10__["default"]; - - /** - `{{collection}}` is a `Ember.Handlebars` helper for adding instances of - `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) - for additional information on how a `CollectionView` functions. - - `{{collection}}`'s primary use is as a block helper with a `contentBinding` - option pointing towards an `Ember.Array`-compatible object. An `Ember.View` - instance will be created for each item in its `content` property. Each view - will have its own `content` property set to the appropriate item in the - collection. - - The provided block will be applied as the template for each item's view. - - Given an empty `` 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(path, options) { - Ember.deprecate("Using the {{collection}} helper without specifying a class has been" + - " deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection'); - - // If no path is provided, treat path param as options. - if (path && path.data && path.data.isRenderData) { - options = path; - path = undefined; - Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1); - } else { - Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2); - } - - var fn = options.fn, - data = options.data, - inverse = options.inverse, - view = options.data.view, - // This should be deterministic, and should probably come from a - // parent view and not the controller. - container = (view.controller && view.controller.container ? view.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 = handlebarsGetView(this, path, container, options.data); - Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass); - } - else { - collectionClass = CollectionView; - } - - var hash = options.hash; - var hashTypes = options.hashTypes; - 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 = hash.itemView; - } else if (hash.itemViewClass) { - if (hashTypes.itemViewClass === 'ID') { - var itemViewClassStream = view.getStream(hash.itemViewClass); - Ember.deprecate('Resolved the view "'+hash.itemViewClass+'" on the global context. Pass a view name to be looked up on the container instead, such as {{view "select"}}. http://emberjs.com/guides/deprecations#toc_global-lookup-of-views', !itemViewClassStream.isGlobal()); - itemViewClass = itemViewClassStream.value(); - } else { - itemViewClass = hash.itemViewClass; - } - } 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; - delete hashTypes.itemViewClass; - delete hashTypes.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 (hashTypes[prop] === 'ID' || IS_BINDING.test(prop)) { - itemHash[childProp] = view._getBindingForStream(hash[prop]); - } else { - itemHash[childProp] = hash[prop]; - } - delete hash[prop]; - } - } - } - - if (fn) { - itemHash.template = fn; - delete options.fn; - } - - var emptyViewClass; - if (inverse && inverse !== EmberHandlebars.VM.noop) { - emptyViewClass = get(collectionPrototype, 'emptyViewClass'); - emptyViewClass = emptyViewClass.extend({ - template: inverse, - tagName: itemHash.tagName - }); - } else if (hash.emptyViewClass) { - emptyViewClass = handlebarsGetView(this, hash.emptyViewClass, container, options.data); - } - if (emptyViewClass) { hash.emptyView = emptyViewClass; } - - if (hash.keyword) { - itemHash._contextBinding = '_parentView.context'; - } else { - itemHash._contextBinding = 'content'; - } - - var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); - - if (hash.itemClassBinding) { - var itemClassBindings = hash.itemClassBinding.split(' '); - - for (var i = 0; i < itemClassBindings.length; i++) { - var parsedPath = View._parsePropertyPath(itemClassBindings[i]); - if (parsedPath.path === '') { - parsedPath.stream = new SimpleStream(true); - } else { - parsedPath.stream = view.getStream(parsedPath.path); - } - itemClassBindings[i] = parsedPath; - } - - viewOptions.classNameBindings = itemClassBindings; - } - - hash.itemViewClass = itemViewClass; - hash._itemViewProps = viewOptions; - - options.helperName = options.helperName || 'collection'; - - return EmberHandlebars.helpers.view.call(this, collectionClass, options); - } - - __exports__["default"] = collectionHelper; - }); -enifed("ember-handlebars/helpers/debug", - ["ember-metal/core","ember-metal/utils","ember-metal/logger","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /*jshint debug:true*/ - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.FEATURES, - var inspect = __dependency2__.inspect; - var Logger = __dependency3__["default"]; - - var a_slice = [].slice; - - /** - `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() { - var params = a_slice.call(arguments, 0, -1); - var options = arguments[arguments.length - 1]; - var view = options.data.view; - var logger = Logger.log; - var values = []; - - for (var i = 0; i < params.length; i++) { - if (options.types[i] === 'ID') { - var stream = view.getStream(params[i]); - values.push(stream.value()); - } else { - values.push(params[i]); - } - } - - logger.apply(logger, values); - } - - /** - Execute the `debugger` statement in the current context. - - ```handlebars - {{debugger}} - ``` - - 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: - - - templateContext: this is most likely a controller - from which this template looks up / displays properties - - typeOfTemplateContext: a string description of - what the templateContext is - - 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(options) { - - // These are helpful values you can inspect while debugging. - /* jshint unused: false */ - var templateContext = this; - var typeOfTemplateContext = inspect(templateContext); - Ember.Logger.info('Use `this` to access the context of the calling template.'); - - debugger; - } - - __exports__.logHelper = logHelper; - __exports__.debuggerHelper = debuggerHelper; - }); -enifed("ember-handlebars/helpers/each", - ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-views/views/collection_view","ember-metal/binding","ember-runtime/mixins/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-metal/observer","ember-handlebars/views/metamorph_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.assert;, Ember.K - - var EmberHandlebars = __dependency2__["default"]; - - var fmt = __dependency3__.fmt; - var get = __dependency4__.get; - var set = __dependency5__.set; - var CollectionView = __dependency6__["default"]; - var Binding = __dependency7__.Binding; - var ControllerMixin = __dependency8__["default"]; - var ArrayController = __dependency9__["default"]; - var EmberArray = __dependency10__["default"]; - - var addObserver = __dependency11__.addObserver; - var removeObserver = __dependency11__.removeObserver; - var addBeforeObserver = __dependency11__.addBeforeObserver; - var removeBeforeObserver = __dependency11__.removeBeforeObserver; - - var _MetamorphView = __dependency12__["default"]; - var _Metamorph = __dependency12__._Metamorph; - - var EachView = CollectionView.extend(_Metamorph, { - - init: function() { - var itemController = get(this, 'itemController'); - var binding; - - if (itemController) { - var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ - _isVirtual: true, - parentController: get(this, 'controller'), - itemController: itemController, - target: get(this, 'controller'), - _eachView: this - }); - - this.disableContentObservers(function() { - set(this, 'content', controller); - binding = new Binding('content', '_eachView.dataSource').oneWay(); - binding.connect(controller); - }); - - set(this, '_arrayController', controller); - } else { - this.disableContentObservers(function() { - binding = new Binding('content', 'dataSource').oneWay(); - binding.connect(this); - }); - } - - return this._super(); - }, - - _assertArrayLike: function(content) { - Ember.assert(fmt("The value that #each loops over must be an Array. You " + - "passed %@, but it should have been an ArrayController", - [content.constructor]), - !ControllerMixin.detect(content) || - (content && content.isGenerated) || - content instanceof ArrayController); - Ember.assert(fmt("The value that #each loops over must be an Array. You passed %@", - [(ControllerMixin.detect(content) && - content.get('model') !== undefined) ? - fmt("'%@' (wrapped in %@)", [content.get('model'), content]) : content]), - EmberArray.detect(content)); - }, - - disableContentObservers: function(callback) { - removeBeforeObserver(this, 'content', null, '_contentWillChange'); - removeObserver(this, 'content', null, '_contentDidChange'); - - callback.call(this); - - addBeforeObserver(this, 'content', null, '_contentWillChange'); - addObserver(this, 'content', null, '_contentDidChange'); - }, - - itemViewClass: _MetamorphView, - emptyViewClass: _MetamorphView, - - createChildView: function(view, attrs) { - view = this._super(view, attrs); - - var content = get(view, 'content'); - var keyword = get(this, 'keyword'); - - if (keyword) { - view._keywords[keyword] = content; - } - - // If {{#each}} is looping over an array of controllers, - // point each child view at their respective controller. - if (content && content.isController) { - set(view, 'controller', content); - } - - return view; - }, - - destroy: function() { - if (!this._super()) { return; } - - var arrayController = get(this, '_arrayController'); - - if (arrayController) { - arrayController.destroy(); - } - - return this; - } - }); - - /** - 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(path) { - var options = arguments[arguments.length - 1]; - var helperName = 'each'; - var keywordName; - - if (arguments.length === 4) { - Ember.assert("If you pass more than one argument to the each helper," + - " it must be in the form #each foo in bar", arguments[1] === "in"); - - keywordName = arguments[0]; - path = arguments[2]; - - helperName += ' ' + keywordName + ' in ' + path; - - options.hash.keyword = keywordName; - } else if (arguments.length === 1) { - path = ''; - } else { - helperName += ' ' + path; - } - - Ember.deprecate('Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.', keywordName); - - options.hash.emptyViewClass = Ember._MetamorphView; - options.hash.dataSourceBinding = path; - options.hashTypes.dataSourceBinding = 'STRING'; - options.helperName = options.helperName || helperName; - - return EmberHandlebars.helpers.collection.call(this, EmberHandlebars.EachView, options); - } - - __exports__.EachView = EachView; - __exports__.eachHelper = eachHelper; - }); -enifed("ember-handlebars/helpers/if_unless", - ["ember-metal/core","ember-handlebars-compiler","ember-handlebars/helpers/binding","ember-metal/property_get","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var EmberHandlebars = __dependency2__["default"]; - - var bind = __dependency3__.bind; - - var get = __dependency4__.get; - var isArray = __dependency5__.isArray; - - var helpers = EmberHandlebars.helpers; - - 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; - } - } - - /** - 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(property, fn) { - var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this; - - fn.helperName = fn.helperName || 'boundIf'; - - return bind.call(context, property, fn, 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(property, fn) { - var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this; - var data = fn.data; - var view = data.view; - var template = fn.fn; - var inverse = fn.inverse; - - var propertyValue = view.getStream(property).value(); - - if (!shouldDisplayIfHelperContent(propertyValue)) { - template = inverse; - } - - template(context, { data: data }); - } - - /** - 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(context, options) { - Ember.assert("You must pass exactly one argument to the if helper", arguments.length === 2); - Ember.assert("You must pass a block to the if helper", options.fn && options.fn !== Handlebars.VM.noop); - - options.helperName = options.helperName || ('if ' + context); - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - /** - @method unless - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function unlessHelper(context, options) { - Ember.assert("You must pass exactly one argument to the unless helper", arguments.length === 2); - Ember.assert("You must pass a block to the unless helper", options.fn && options.fn !== Handlebars.VM.noop); - - var fn = options.fn; - var inverse = options.inverse; - var helperName = 'unless'; - - if (context) { - helperName += ' ' + context; - } - - options.fn = inverse; - options.inverse = fn; - - options.helperName = options.helperName || helperName; - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - __exports__.ifHelper = ifHelper; - __exports__.boundIfHelper = boundIfHelper; - __exports__.unboundIfHelper = unboundIfHelper; - __exports__.unlessHelper = unlessHelper; - }); -enifed("ember-handlebars/helpers/loc", - ["ember-runtime/system/string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var loc = __dependency1__.loc; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - 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} - */ - __exports__["default"] = loc; - }); -enifed("ember-handlebars/helpers/partial", - ["ember-metal/core","ember-metal/is_none","ember-handlebars/helpers/binding","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var isNone = __dependency2__["default"]; - var bind = __dependency3__.bind; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - 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 - */ - - __exports__["default"] = function partialHelper(name, options) { - var view = options.data.view; - - var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; - - options.helperName = options.helperName || 'partial'; - - if (options.types[0] === "ID") { - var partialNameStream = view.getStream(name); - // Helper was passed a property path; we need to - // create a binding that will re-render whenever - // this property changes. - options.fn = function(context, fnOptions) { - renderPartial(context, partialNameStream.value(), fnOptions); - }; - - return bind.call(context, name, options, true, exists); - } else { - // Render the partial right into parent template. - renderPartial(context, name, options); - } - } - - function exists(value) { - return !isNone(value); - } - - function renderPartial(context, name, options) { - var nameParts = name.split("/"); - var lastPart = nameParts[nameParts.length - 1]; - - nameParts[nameParts.length - 1] = "_" + lastPart; - - var view = options.data.view; - var underscoredName = nameParts.join("/"); - var template = view.templateForName(underscoredName); - var deprecatedTemplate = !template && view.templateForName(name); - - Ember.assert("Unable to find partial with name '"+name+"'.", template || deprecatedTemplate); - - template = template || deprecatedTemplate; - - template(context, { - data: options.data - }); - } - }); -enifed("ember-handlebars/helpers/template", - ["ember-metal/core","ember-handlebars-compiler","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.deprecate; - - var EmberHandlebars = __dependency2__["default"]; - /** - @module ember - @submodule ember-handlebars - */ - - /** - @deprecated - @method template - @for Ember.Handlebars.helpers - @param {String} templateName the template to render - */ - __exports__["default"] = function templateHelper(name, options) { - 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 EmberHandlebars.helpers.partial.apply(this, arguments); - } - }); -enifed("ember-handlebars/helpers/unbound", - ["ember-handlebars-compiler","ember-handlebars/helpers/binding","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - - var resolveHelper = __dependency2__.resolveHelper; - - /** - `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 - */ - __exports__["default"] = function unboundHelper(property) { - var argsLength = arguments.length; - var options = arguments[argsLength - 1]; - var view = options.data.view; - var container = view.container; - - if (argsLength <= 2) { - return view.getStream(property).value(); - } else { - options.data.isUnbound = true; - options.types.shift(); - - var args = new Array(argsLength - 1); - for (var i = 1; i < argsLength; i++) { - args[i - 1] = arguments[i]; - } - - var helper = resolveHelper(container, property) || EmberHandlebars.helpers.helperMissing; - - // Attempt to exec the first field as a helper - options.name = arguments[0]; - - var result = helper.apply(this, args); - - delete options.data.isUnbound; - return result; - } - } - }); -enifed("ember-handlebars/helpers/view", - ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/keys","ember-metal/mixin","ember-views/streams/read","ember-views/views/view","ember-metal/streams/simple","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.warn, Ember.assert - // var emberWarn = Ember.warn, emberAssert = Ember.assert; - - var EmberObject = __dependency2__["default"]; - var get = __dependency3__.get; - var keys = __dependency4__["default"]; - var IS_BINDING = __dependency5__.IS_BINDING; - var readViewFactory = __dependency6__.readViewFactory; - var View = __dependency7__["default"]; - var SimpleStream = __dependency8__["default"]; - - function makeBindings(options) { - var hash = options.hash; - var hashTypes = options.hashTypes; - var view = options.data.view; - - for (var prop in hash) { - var hashType = hashTypes[prop]; - var value = hash[prop]; - - if (IS_BINDING.test(prop)) { - // classBinding is processed separately - if (prop === 'classBinding') { - continue; - } - - if (hashType === 'ID') { - Ember.warn("You're attempting to render a view by passing " + - prop + "=" + value + - " to a view helper, but this syntax is ambiguous. You should either surround " + - value + " in quotes or remove `Binding` from " + prop + "."); - hash[prop] = view._getBindingForStream(value); - } else if (typeof value === 'string') { - hash[prop] = view._getBindingForStream(value); - } - } else { - if (hashType === 'ID') { - if (prop === 'class') { - hash.classBinding = value; - } else { - hash[prop + 'Binding'] = view._getBindingForStream(value); - } - delete hash[prop]; - delete hashTypes[prop]; - } - } - } - - if (hash.idBinding) { - // id can't be bound, so just perform one-time lookup. - hash.id = hash.idBinding.value(); - hashTypes.id = 'STRING'; - delete hash.idBinding; - delete hashTypes.idBinding; - } - } - - var ViewHelper = EmberObject.create({ - propertiesFromHTMLOptions: function(options) { - var view = options.data.view; - var hash = options.hash; - var classes = hash['class']; - - var extensions = { - helperName: options.helperName || '' - }; - - if (hash.id) { - extensions.elementId = 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 Handlebars 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]; - } - } - - var classNameBindings = extensions.classNameBindings; - if (classNameBindings) { - for (var j = 0; j < classNameBindings.length; j++) { - var parsedPath = View._parsePropertyPath(classNameBindings[j]); - if (parsedPath.path === '') { - parsedPath.stream = new SimpleStream(true); - } else { - parsedPath.stream = view.getStream(parsedPath.path); - } - classNameBindings[j] = parsedPath; - } - } - - return extensions; - }, - - helper: function(thisContext, newView, options) { - var data = options.data; - var fn = options.fn; - var newViewProto; - - makeBindings(options); - - var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); - var currentView = data.view; - viewOptions.templateData = data; - - if (View.detectInstance(newView)) { - newViewProto = newView; - } else { - newViewProto = newView.proto(); - } - - if (fn) { - Ember.assert("You cannot provide a template block if you also specified a templateName", - !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName')); - viewOptions.template = fn; - } - - // 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 = thisContext; - } - - currentView.appendChild(newView, viewOptions); - }, - - instanceHelper: function(thisContext, newView, options) { - var data = options.data; - var fn = options.fn; - - makeBindings(options); - - Ember.assert( - 'Only a instance of a view may be passed to the ViewHelper.instanceHelper', - View.detectInstance(newView) - ); - - var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); - var currentView = data.view; - viewOptions.templateData = data; - - if (fn) { - Ember.assert("You cannot provide a template block if you also specified a templateName", - !get(viewOptions, 'templateName') && !get(newView, 'templateName')); - viewOptions.template = fn; - } - - // 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 = thisContext; - } - - 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(path) { - Ember.assert("The view helper only takes a single argument", arguments.length <= 2); - - var options = arguments[arguments.length - 1]; - var types = options.types; - var view = options.data.view; - var container = view.container || view._keywords.view.value().container; - var viewClass; - - // If no path is provided, treat path param as options - // and get an instance of the registered `view:toplevel` - if (arguments.length === 1) { - if (container) { - viewClass = container.lookupFactory('view:toplevel'); - } else { - viewClass = View; - } - } else { - var pathStream; - if (typeof path === 'string' && types[0] === 'ID') { - pathStream = view.getStream(path); - Ember.deprecate('Resolved the view "'+path+'" on the global context. Pass a view name to be looked up on the container instead, such as {{view "select"}}. http://emberjs.com/guides/deprecations#toc_global-lookup-of-views', !pathStream.isGlobal()); - } else { - pathStream = path; - } - - viewClass = readViewFactory(pathStream, container); - } - - options.helperName = options.helperName || 'view'; - - return ViewHelper.helper(this, viewClass, options); - } - - __exports__.viewHelper = viewHelper; - }); -enifed("ember-handlebars/helpers/with", - ["ember-metal/core","ember-metal/property_set","ember-metal/utils","ember-metal/platform","ember-metal/is_none","ember-handlebars/helpers/binding","ember-handlebars/views/handlebars_bound_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - - var set = __dependency2__.set; - var apply = __dependency3__.apply; - var o_create = __dependency4__.create; - var isNone = __dependency5__["default"]; - var bind = __dependency6__.bind; - var _HandlebarsBoundView = __dependency7__._HandlebarsBoundView; - - function exists(value) { - return !isNone(value); - } - - var WithView = _HandlebarsBoundView.extend({ - init: function() { - apply(this, this._super, arguments); - - var keywordName = this.templateHash.keywordName; - 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._keywords[keywordName] = 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()); - } - }, - - willDestroy: function() { - this._super(); - - if (this._generatedController) { - this._generatedController.destroy(); - } - } - }); - - /** - 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}} -
  1. {{post.title}}
  2. - {{/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 - */ - __exports__["default"] = function withHelper(contextPath) { - var options = arguments[arguments.length - 1]; - var view = options.data.view; - var bindContext, preserveContext; - var helperName = 'with'; - - if (arguments.length === 4) { - Ember.assert("If you pass more than one argument to the with helper," + - " it must be in the form #with foo as bar", arguments[1] === "as"); - - var keywordName = arguments[2]; - - if (contextPath) { - helperName += ' ' + contextPath + ' as ' + keywordName; - } - - Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); - - var localizedOptions = o_create(options); - localizedOptions.data = o_create(options.data); - - localizedOptions.keywords = {}; - localizedOptions.keywords[keywordName] = view.getStream(contextPath); - - localizedOptions.hash.keywordName = keywordName; - - bindContext = this; - options = localizedOptions; - preserveContext = true; - } else { - Ember.deprecate('Using the context switching form of `{{with}}` is deprecated. Please use the keyword form (`{{with foo as bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.'); - - Ember.assert("You must pass exactly one argument to the with helper", arguments.length === 2); - Ember.assert("You must pass a block to the with helper", options.fn && options.fn !== Handlebars.VM.noop); - - helperName += ' ' + contextPath; - bindContext = options.contexts[0]; - preserveContext = false; - } - - options.helperName = helperName; - - return bind.call(bindContext, contextPath, options, preserveContext, exists, undefined, undefined, WithView); - } - }); -enifed("ember-handlebars/helpers/yield", - ["ember-metal/core","ember-metal/property_get","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // var emberAssert = Ember.assert; - - 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 - */ - __exports__["default"] = function yieldHelper(options) { - var view = options.data.view; - - 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); - - view._yield(this, options); - } - }); -enifed("ember-handlebars/loader", - ["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /*globals Handlebars */ - - var ComponentLookup = __dependency1__["default"]; - var jQuery = __dependency2__["default"]; - var EmberError = __dependency3__["default"]; - var onLoad = __dependency4__.onLoad; - - var EmberHandlebars = __dependency5__["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) : - jQuery.proxy(EmberHandlebars.compile, EmberHandlebars); - // 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-handlebars/string", - ["ember-runtime/system/string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - // required so we can extend this object. - var EmberStringUtils = __dependency1__["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 Handlebars.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__["default"] = htmlSafe; - }); -enifed("ember-handlebars/views/handlebars_bound_view", - ["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-handlebars/string","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { - "use strict"; - /*jshint newcap:false*/ - - - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - // EmberHandlebars.SafeString; - - var Ember = __dependency2__["default"]; - // Ember.K - var K = Ember.K; - - var EmberError = __dependency3__["default"]; - var get = __dependency4__.get; - var set = __dependency5__.set; - var merge = __dependency6__["default"]; - var run = __dependency7__["default"]; - var htmlSafe = __dependency8__["default"]; - var cloneStates = __dependency9__.cloneStates; - var viewStates = __dependency9__.states; - - var _MetamorphView = __dependency10__["default"]; - var uuid = __dependency11__.uuid; - - function SimpleHandlebarsView(lazyValue, isEscaped) { - this.lazyValue = lazyValue; - this.isEscaped = isEscaped; - this[Ember.GUID_KEY] = uuid(); - this._lastNormalizedValue = undefined; - this.state = 'preRender'; - this.updateId = null; - this._parentView = null; - this.buffer = null; - this._morph = null; - } - - SimpleHandlebarsView.prototype = { - isVirtual: true, - isView: true, - - destroy: function () { - if (this.updateId) { - run.cancel(this.updateId); - this.updateId = null; - } - if (this._parentView) { - this._parentView.removeChild(this); - } - this.morph = null; - this.state = 'destroyed'; - }, - - propertyWillChange: K, - - propertyDidChange: K, - - normalizedValue: function() { - var result = this.lazyValue.value(); - - if (result === null || result === undefined) { - result = ""; - } else if (!this.isEscaped && !(result instanceof EmberHandlebars.SafeString)) { - result = htmlSafe(result); - } - - return result; - }, - - render: function(buffer) { - var value = this.normalizedValue(); - this._lastNormalizedValue = value; - buffer._element = value; - }, - - rerender: function() { - switch(this.state) { - case 'preRender': - case 'destroyed': - break; - case 'inBuffer': - throw new EmberError("Something you did tried to replace an {{expression}} before it was inserted into the DOM."); - case 'hasElement': - case 'inDOM': - this.updateId = run.scheduleOnce('render', this, 'update'); - break; - } - return this; - }, - - update: function () { - this.updateId = null; - var value = this.normalizedValue(); - // doesn't diff EmberHandlebars.SafeString instances - if (value !== this._lastNormalizedValue) { - this._lastNormalizedValue = value; - this._morph.update(value); - } - }, - - _transitionTo: function(state) { - this.state = state; - } - }; - - var states = cloneStates(viewStates); - - merge(states._default, { - rerenderIfNeeded: K - }); - - merge(states.inDOM, { - rerenderIfNeeded: function(view) { - if (view.normalizedValue() !== view._lastNormalizedValue) { - view.rerender(); - } - } - }); - - /** - `Ember._HandlebarsBoundView` is a private view created by the Handlebars - `{{bind}}` helpers that is used to keep track of bound properties. - - Every time a property is bound using a `{{mustache}}`, an anonymous subclass - of `Ember._HandlebarsBoundView` is created with the appropriate sub-template - and context set up. When the associated property changes, just the template - for this view will re-render. - - @class _HandlebarsBoundView - @namespace Ember - @extends Ember._MetamorphView - @private - */ - var _HandlebarsBoundView = _MetamorphView.extend({ - instrumentName: 'boundHandlebars', - - _states: states, - - /** - The function used to determine if the `displayTemplate` or - `inverseTemplate` should be rendered. This should be a function that takes - a value and returns a Boolean. - - @property shouldDisplayFunc - @type Function - @default null - */ - shouldDisplayFunc: null, - - /** - Whether the template rendered by this view gets passed the context object - of its parent template, or gets passed the value of retrieving `path` - from the `pathRoot`. - - For example, this is true when using the `{{#if}}` helper, because the - template inside the helper should look up properties relative to the same - object as outside the block. This would be `false` when used with `{{#with - foo}}` because the template should receive the object found by evaluating - `foo`. - - @property preserveContext - @type Boolean - @default false - */ - preserveContext: false, - - /** - If `preserveContext` is true, this is the object that will be used - to render the template. - - @property previousContext - @type Object - */ - previousContext: null, - - /** - The template to render when `shouldDisplayFunc` evaluates to `true`. - - @property displayTemplate - @type Function - @default null - */ - displayTemplate: null, - - /** - The template to render when `shouldDisplayFunc` evaluates to `false`. - - @property inverseTemplate - @type Function - @default null - */ - inverseTemplate: null, - - lazyValue: null, - - normalizedValue: function() { - var value = this.lazyValue.value(); - var valueNormalizer = get(this, 'valueNormalizerFunc'); - return valueNormalizer ? valueNormalizer(value) : value; - }, - - rerenderIfNeeded: function() { - this.currentState.rerenderIfNeeded(this); - }, - - /** - Determines which template to invoke, sets up the correct state based on - that logic, then invokes the default `Ember.View` `render` implementation. - - This method will first look up the `path` key on `pathRoot`, - then pass that value to the `shouldDisplayFunc` function. If that returns - `true,` the `displayTemplate` function will be rendered to DOM. Otherwise, - `inverseTemplate`, if specified, will be rendered. - - For example, if this `Ember._HandlebarsBoundView` represented the `{{#with - foo}}` helper, it would look up the `foo` property of its context, and - `shouldDisplayFunc` would always return true. The object found by looking - up `foo` would be passed to `displayTemplate`. - - @method render - @param {Ember.RenderBuffer} buffer - */ - render: function(buffer) { - // If not invoked via a triple-mustache ({{{foo}}}), escape - // the content of the template. - var escape = get(this, 'isEscaped'); - - var shouldDisplay = get(this, 'shouldDisplayFunc'); - var preserveContext = get(this, 'preserveContext'); - var context = get(this, 'previousContext'); - - var inverseTemplate = get(this, 'inverseTemplate'); - var displayTemplate = get(this, 'displayTemplate'); - - var result = this.normalizedValue(); - - this._lastNormalizedValue = result; - - // First, test the conditional to see if we should - // render the template or not. - if (shouldDisplay(result)) { - set(this, 'template', displayTemplate); - - // If we are preserving the context (for example, if this - // is an #if block, call the template with the same object. - if (preserveContext) { - set(this, '_context', context); - } else { - // Otherwise, determine if this is a block bind or not. - // If so, pass the specified object to the template - if (displayTemplate) { - set(this, '_context', result); - } else { - // This is not a bind block, just push the result of the - // expression to the render context and return. - if (result === null || result === undefined) { - result = ""; - } else if (!(result instanceof EmberHandlebars.SafeString)) { - result = String(result); - } - - if (escape) { result = Handlebars.Utils.escapeExpression(result); } - buffer.push(result); - return; - } - } - } else if (inverseTemplate) { - set(this, 'template', inverseTemplate); - - if (preserveContext) { - set(this, '_context', context); - } else { - set(this, '_context', result); - } - } else { - set(this, 'template', function() { return ''; }); - } - - return this._super(buffer); - } - }); - - __exports__._HandlebarsBoundView = _HandlebarsBoundView; - __exports__.SimpleHandlebarsView = SimpleHandlebarsView; - }); -enifed("ember-handlebars/views/metamorph_view", - ["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /*jshint newcap:false*/ - var Ember = __dependency1__["default"]; - // Ember.deprecate - - var CoreView = __dependency2__["default"]; - var View = __dependency3__["default"]; - var Mixin = __dependency4__.Mixin; - - /** - @module ember - @submodule ember-handlebars - */ - - // The `morph` and `outerHTML` properties are internal only - // and not observable. - - /** - @class _Metamorph - @namespace Ember - @private - */ - var _Metamorph = Mixin.create({ - isVirtual: true, - tagName: '', - - instrumentName: 'metamorph', - - init: function() { - this._super(); - Ember.deprecate('Supplying a tagName to Metamorph views is unreliable and is deprecated.' + - ' You may be setting the tagName on a Handlebars helper that creates a Metamorph.', !this.tagName); - } - }); - __exports__._Metamorph = _Metamorph; - /** - @class _MetamorphView - @namespace Ember - @extends Ember.View - @uses Ember._Metamorph - @private - */ - __exports__["default"] = View.extend(_Metamorph); - - /** - @class _SimpleMetamorphView - @namespace Ember - @extends Ember.CoreView - @uses Ember._Metamorph - @private - */ - var _SimpleMetamorphView = CoreView.extend(_Metamorph); - __exports__._SimpleMetamorphView = _SimpleMetamorphView; - }); -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; - } - Ember.assert("Required contextualElement for view "+_view+" is missing", contextualElement); - 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({ - done: Ember.computed.empty('todos') - }); - - var todoList = ToDoList.create({ - todos: ['Unit Test', 'Documentation', 'Release'] - }); - - todoList.get('done'); // false - todoList.get('todos').clear(); - todoList.get('done'); // 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 propogate 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.9.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.9.1' - @static - */ - Ember.VERSION = '1.9.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 `ENV.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: - - * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled. - * `ENV.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 `ENV.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 = Ember.K; } - if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; } - if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; } - if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = Ember.K; } - if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.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 listenersUnion(obj, eventName, otherActions) { - 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) { - 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); - } - } - } - - __exports__.listenersUnion = listenersUnion;function listenersDiff(obj, eventName, otherActions) { - var meta = obj['__ember_meta__']; - var actions = meta && meta.listeners && meta.listeners[eventName]; - var diffActions = []; - - if (!actions) { return; } - 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) { continue; } - - otherActions.push(target, method, flags); - diffActions.push(target, method, flags); - } - - return diffActions; - } - - __exports__.listenersDiff = listenersDiff;/** - 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 - @param obj - @param {String...|Array} list of keys to get - @return {Hash} - */ - __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/properties","ember-metal/platform","ember-metal/utils","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var ComputedProperty = __dependency2__.ComputedProperty; - var Descriptor = __dependency3__.Descriptor; - var create = __dependency4__.create; - var inspect = __dependency5__.inspect; - var EmberError = __dependency6__["default"]; - - /** - 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(function(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(type + ':' + (name || keyName)); - }, { readOnly: true }); - } - - InjectedProperty.prototype = create(Descriptor.prototype); - - var InjectedPropertyPrototype = InjectedProperty.prototype; - var ComputedPropertyPrototype = ComputedProperty.prototype; - - InjectedPropertyPrototype._super$Constructor = ComputedProperty; - - InjectedPropertyPrototype.get = ComputedPropertyPrototype.get; - - InjectedPropertyPrototype.set = function(obj, keyName) { - throw new EmberError("Cannot set injected property '" + keyName + "' on object: " + inspect(obj)); - }; - - 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. - - @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. - - @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","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __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 apply = __dependency7__.apply; - 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 REQUIRED; - var a_slice = [].slice; - - function superFunction(){ - var func = this.__nextSuper; - var ret; - if (func) { - var args = new Array(arguments.length); - for (var i = 0, l = args.length; i < l; i++) { - args[i] = arguments[i]; - } - this.__nextSuper = null; - ret = apply(this, func, args); - this.__nextSuper = func; - } - return ret; - } - - 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.indexOf(HAS_THIS) !== -1; }); - 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", - ["exports"], - function(__exports__) { - // Remove "use strict"; from transpiled module until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - /** - @class platform - @namespace Ember - @static - */ - - /** - Identical to `Object.create()`. Implements if not available natively. - - @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) { - Object.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; - - // 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 listenersUnion = __dependency2__.listenersUnion; - var listenersDiff = __dependency2__.listenersDiff; - 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; - } - }; - - // Currently used only by Ember Data tests - if (Ember.config.overrideAccessors) { - Ember.get = get; - Ember.config.overrideAccessors(); - get = Ember.get; - } - - /** - 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 captial 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 (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; - }; - - // Currently used only by Ember Data tests - // ES6TODO: Verify still true - if (Ember.config.overrideAccessors) { - Ember.set = set; - Ember.config.overrideAccessors(); - set = Ember.set; - } - - 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 execute 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 {Object} return value from invoking the passed function. Please note, - when called within an existing loop, no return value is possible. - @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 execute 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 execute 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 an 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/read", - ["exports"], - function(__exports__) { - "use strict"; - function read(object) { - if (object && object.isStream) { - return object.value(); - } else { - return object; - } - } - - __exports__.read = read;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;function readHash(object) { - var ret = {}; - for (var key in object) { - ret[key] = read(object[key]); - } - return ret; - } - - __exports__.readHash = readHash; - }); -enifed("ember-metal/streams/simple", - ["ember-metal/merge","ember-metal/streams/stream","ember-metal/platform","ember-metal/streams/read","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; - - function SimpleStream(source) { - this.source = source; - - if (source && source.isStream) { - 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 (source && source.isStream) { - source.setValue(value); - } - }, - - setSource: function(nextSource) { - var prevSource = this.source; - if (nextSource !== prevSource) { - if (prevSource && prevSource.isStream) { - prevSource.unsubscribe(this._didChange, this); - } - - if (nextSource && nextSource.isStream) { - nextSource.subscribe(this._didChange, this); - } - - this.source = nextSource; - this.notify(); - } - }, - - _didChange: function() { - this.notify(); - }, - - destroy: function() { - if (this.source && this.source.isStream) { - this.source.unsubscribe(this._didChange, this); - } - - this.source = undefined; - Stream.prototype.destroy.call(this); - } - }); - - __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; - - var NIL = function NIL(){}; - - function Stream(fn) { - this.valueFn = fn; - this.cache = NIL; - this.subscribers = undefined; - this.children = undefined; - this.destroyed = false; - } - - Stream.prototype = { - isStream: true, - - cache: NIL, - - 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.cache !== NIL) { - return this.cache; - } else { - return this.cache = this.valueFn(); - } - }, - - setValue: function() { - throw new Error("Stream error: setValue not implemented"); - }, - - notify: function() { - this.notifyExcept(); - }, - - notifyExcept: function(callbackToSkip, contextToSkip) { - if (this.cache !== NIL) { - this.cache = NIL; - 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.destroyed) return; - this.destroyed = true; - - var children = this.children; - for (var key in children) { - children[key].destroy(); - } - }, - - 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.stream = stream; - this.senderCallback = undefined; - this.senderContext = undefined; - this.senderValue = undefined; - this.destroyed = false; - - 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.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.cache = undefined; - - this.notifyExcept(senderCallback, senderContext); - }, - - destroy: function() { - if (this.destroyed) { - return; - } - - this.destroyed = true; - this.stream.unsubscribe(this._onNotify, this); - } - }); - - __exports__["default"] = StreamBinding; - }); -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 - comparision. - - 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 comparisions 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-handlebars", - ["ember-metal/core","ember-handlebars","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - /** - Ember Routing Handlebars - - @module ember - @submodule ember-routing-handlebars - @requires ember-views - */ - - var Ember = __dependency1__["default"]; - var EmberHandlebars = __dependency2__["default"]; - - var deprecatedLinkToHelper = __dependency3__.deprecatedLinkToHelper; - var linkToHelper = __dependency3__.linkToHelper; - var LinkView = __dependency3__.LinkView; - var queryParamsHelper = __dependency3__.queryParamsHelper; - - var outletHelper = __dependency4__.outletHelper; - var OutletView = __dependency4__.OutletView; - - var renderHelper = __dependency5__["default"]; - - var ActionHelper = __dependency6__.ActionHelper; - var actionHelper = __dependency6__.actionHelper; - - Ember.LinkView = LinkView; - EmberHandlebars.ActionHelper = ActionHelper; - EmberHandlebars.OutletView = OutletView; - - EmberHandlebars.registerHelper('render', renderHelper); - EmberHandlebars.registerHelper('action', actionHelper); - EmberHandlebars.registerHelper('outlet', outletHelper); - EmberHandlebars.registerHelper('link-to', linkToHelper); - EmberHandlebars.registerHelper('linkTo', deprecatedLinkToHelper); - EmberHandlebars.registerHelper('query-params', queryParamsHelper); - - __exports__["default"] = Ember; - }); -enifed("ember-routing-handlebars/helpers/action", - ["ember-metal/core","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/streams/read","ember-views/system/utils","ember-views/system/action_manager","ember-handlebars","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Handlebars, uuid, FEATURES, assert, deprecate - var forEach = __dependency2__.forEach; - var uuid = __dependency3__.uuid; - var run = __dependency4__["default"]; - - var readUnwrappedModel = __dependency5__.readUnwrappedModel; - var isSimpleClick = __dependency6__.isSimpleClick; - var ActionManager = __dependency7__["default"]; - var EmberHandlebars = __dependency8__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - function actionArgs(parameters, actionName) { - var ret, i; - - if (actionName === undefined) { - ret = new Array(parameters.length); - for (i = 0; i < parameters.length; i++) { - ret[i] = readUnwrappedModel(parameters[i]); - } - } else { - ret = new Array(parameters.length + 1); - ret[0] = actionName; - for (i = 0; i < parameters.length; i++) { - ret[i + 1] = readUnwrappedModel(parameters[i]); - } - } - - return ret; - } - - var ActionHelper = {}; - - // registeredActions is re-exported for compatibility with older plugins - // that were using this undocumented API. - ActionHelper.registeredActions = ActionManager.registeredActions; - - __exports__.ActionHelper = ActionHelper; - - var keys = ["alt", "shift", "meta", "ctrl"]; - - var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; - - var isAllowedEvent = function(event, allowedKeys) { - if (typeof allowedKeys === "undefined") { - if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { - return isSimpleClick(event); - } else { - allowedKeys = ''; - } - } - - if (allowedKeys.indexOf("any") >= 0) { - return true; - } - - var allowed = true; - - forEach.call(keys, function(key) { - if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { - allowed = false; - } - }); - - return allowed; - }; - - function isKeyEvent(eventName) { - return ['keyUp', 'keyPress', 'keyDown'].indexOf(eventName) !== -1; - } - - function ignoreKeyEvent(eventName, event, keyCode) { - var any = 'any'; - keyCode = keyCode || any; - return isKeyEvent(eventName) && keyCode !== any && keyCode !== event.which.toString(); - } - - ActionHelper.registerAction = function(actionNameOrStream, options, allowedKeys) { - var actionId = uuid(); - var eventName = options.eventName; - var parameters = options.parameters; - - ActionManager.registeredActions[actionId] = { - eventName: eventName, - handler: function handleRegisteredAction(event) { - if (!isAllowedEvent(event, allowedKeys)) { return true; } - - if (options.preventDefault !== false) { - event.preventDefault(); - } - - if (options.bubbles === false) { - event.stopPropagation(); - } - - var target = options.target.value(); - - - var actionName; - - if (actionNameOrStream.isStream) { - actionName = actionNameOrStream.value(); - - if (typeof actionName === 'undefined' || typeof actionName === 'function') { - actionName = actionNameOrStream._originalPath; - Ember.deprecate("You specified a quoteless path to the {{action}} helper '" + - actionName + "' which did not resolve to an actionName." + - " Perhaps you meant to use a quoted actionName? (e.g. {{action '" + actionName + "'}})."); - } - } - - if (!actionName) { - actionName = actionNameOrStream; - } - - run(function runRegisteredAction() { - if (target.send) { - target.send.apply(target, actionArgs(parameters, actionName)); - } else { - Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function'); - target[actionName].apply(target, actionArgs(parameters)); - } - }); - } - }; - - options.view.on('willClearRender', function() { - delete ActionManager.registeredActions[actionId]; - }); - - return actionId; - }; - - /** - The `{{action}}` helper provides a useful shortcut for registering an HTML - element within a template for a single DOM event and forwarding that - interaction to the template's controller or specified `target` option. - - If the controller does not implement the specified action, the event is sent - to the current route, and it bubbles up the route hierarchy from there. - - For more advanced event handling see [Ember.Component](/api/classes/Ember.Component.html) - - - ### Use - Given the following application Handlebars template on the page - - ```handlebars -
    - 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(actionName) { - var length = arguments.length; - var options = arguments[length - 1]; - var view = options.data.view; - var hash = options.hash; - var types = options.types; - - // create a hash to pass along to registerAction - var parameters = []; - - var actionOptions = { - eventName: hash.on || "click", - parameters: parameters, - view: options.data.view, - bubbles: hash.bubbles, - preventDefault: hash.preventDefault, - target: view.getStream(hash.target || 'controller'), - withKeyCode: hash.withKeyCode - }; - - var actionNameStream; - - if (types[0] === "ID") { - actionNameStream = view.getStream(actionName); - actionNameStream._originalPath = actionName; - } else { - actionNameStream = actionName; - } - - for (var i = 1; i < length - 1; i++) { - if (types[i] === "ID") { - parameters.push(view.getStream(arguments[i])); - } else { - parameters.push(arguments[i]); - } - } - - var actionId = ActionHelper.registerAction(actionNameStream, actionOptions, hash.allowedKeys); - return new EmberHandlebars.SafeString('data-ember-action="' + actionId + '"'); - } - - __exports__.actionHelper = actionHelper; - }); -enifed("ember-routing-handlebars/helpers/link_to", - ["ember-metal/core","ember-metal/property_get","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/controller","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars/helpers/view","ember-routing/utils","ember-handlebars/ext","ember-metal/streams/read","ember-handlebars","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // FEATURES, Logger, Handlebars, warn, assert - var get = __dependency2__.get; - var merge = __dependency3__["default"]; - var run = __dependency4__["default"]; - var computed = __dependency5__.computed; - - var fmt = __dependency6__.fmt; - var EmberObject = __dependency7__["default"]; - var ControllerMixin = __dependency8__["default"]; - var keys = __dependency9__["default"]; - var isSimpleClick = __dependency10__.isSimpleClick; - var EmberComponent = __dependency11__["default"]; - var viewHelper = __dependency12__.viewHelper; - var routeArgs = __dependency13__.routeArgs; - var stringifyValue = __dependency14__.stringifyValue; - var read = __dependency15__.read; - - - /** - @module ember - @submodule ember-routing - */ - - var slice = [].slice; - - 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; - }; - - var QueryParams = EmberObject.extend({ - values: null - }); - - /** - `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, - - /** - 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 discourage that you override these defaults, - however you can push onto the array if needed. - - @property attributeBindings - @type Array | String - @default ['href', 'title', 'rel'] - **/ - 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) { - this.linkTitle.subscribe(scheduledRerender, this); - } - - for (var i = 0; i < params.length; i++) { - var param = params[i]; - if (param && param.isStream) { - param.subscribe(scheduledParamsChanged, this); - } - } - - var queryParamsObject = this.queryParamsObject; - if (queryParamsObject) { - var values = queryParamsObject.values; - for (var k in values) { - if (!values.hasOwnProperty(k)) { - continue; - } - - var value = values[k]; - if (value && value.isStream) { - value.subscribe(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 - }); - - - /** - 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}} - ``` - - ```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 -
  3. - Great Hamster Photos -
  4. - ``` - - 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(name) { - var options = slice.call(arguments, -1)[0]; - var params = slice.call(arguments, 0, -1); - var view = options.data.view; - var hash = options.hash; - var hashTypes = options.hashTypes; - var types = options.types; - var shouldEscape = !hash.unescaped; - var queryParamsObject; - - Ember.assert("You must provide one or more parameters to the link-to helper.", params.length); - - if (params[params.length - 1] instanceof QueryParams) { - hash.queryParamsObject = queryParamsObject = params.pop(); - } - - if (hash.disabledWhen) { - hash.disabledBinding = hash.disabledWhen; - hashTypes.disabledBinding = hashTypes.disabledWhen; - delete hash.disabledWhen; - delete hashTypes.disabledWhen; - } - - if (!options.fn) { - var linkTitle = params.shift(); - var linkTitleType = types.shift(); - if (linkTitleType === 'ID') { - hash.linkTitle = linkTitle = view.getStream(linkTitle); - options.fn = function() { - return stringifyValue(linkTitle.value(), shouldEscape); - }; - } else { - options.fn = function() { - return linkTitle; - }; - } - } - - // Setup route & param streams - for (var i = 0; i < params.length; i++) { - var paramPath = params[i]; - if (types[i] === 'ID') { - var lazyValue = view.getStream(paramPath); - - // TODO: Consider a better approach to unwrapping controllers. - if (paramPath !== 'controller') { - while (ControllerMixin.detect(lazyValue.value())) { - paramPath = (paramPath === '') ? 'model' : paramPath + '.model'; - lazyValue = view.getStream(paramPath); - } - } - params[i] = lazyValue; - } - } - - hash.params = params; - - options.helperName = options.helperName || 'link-to'; - - return viewHelper.call(this, LinkView, options); - } - - /** - 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(options) { - Ember.assert(fmt("The `query-params` helper only accepts hash parameters, e.g. (query-params queryParamPropertyName='%@') as opposed to just (query-params '%@')", [options, options]), arguments.length === 1); - - var view = options.data.view; - var hash = options.hash; - var hashTypes = options.hashTypes; - - for (var k in hash) { - if (hashTypes[k] === 'ID') { - hash[k] = view.getStream(hash[k]); - } - } - - return QueryParams.create({ - values: options.hash - }); - } - - __exports__.queryParamsHelper = queryParamsHelper;/** - 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() { - Ember.deprecate("The 'linkTo' view helper is deprecated in favor of 'link-to'"); - - return linkToHelper.apply(this, arguments); - } - - 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; - __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; - __exports__.linkToHelper = linkToHelper; - }); -enifed("ember-routing-handlebars/helpers/outlet", - ["ember-metal/core","ember-metal/property_set","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // assert - var set = __dependency2__.set; - var ContainerView = __dependency3__["default"]; - var _Metamorph = __dependency4__._Metamorph; - var viewHelper = __dependency5__.viewHelper; - - /** - @module ember - @submodule ember-routing - */ - - /** - @module ember - @submodule ember-routing - */ - - var OutletView = ContainerView.extend(_Metamorph); - __exports__.OutletView = 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(property, options) { - var outletSource; - var viewName; - var viewClass; - var viewFullName; - - if (property && property.data && property.data.isRenderData) { - options = property; - property = 'main'; - } - - Ember.deprecate( - "Using {{outlet}} with an unquoted name is not supported. " + - "Please update to quoted usage '{{outlet \"" + property + "\"}}'.", - arguments.length === 1 || options.types[0] === 'STRING' - ); - - var view = options.data.view; - var container = view.container; - - outletSource = view; - while (!outletSource.get('template.isTop')) { - outletSource = outletSource.get('_parentView'); - } - set(view, 'outletSource', outletSource); - - // provide controller override - viewName = options.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 + "\"}}.", - options.hashTypes.view !== 'ID' - ); - Ember.assert( - "The view name you supplied '" + viewName + "' did not resolve to a view.", - container.has(viewFullName) - ); - } - - viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || OutletView; - options.types = [ 'ID' ]; - - options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; - options.hashTypes.currentViewBinding = 'STRING'; - - options.helperName = options.helperName || 'outlet'; - - return viewHelper.call(this, viewClass, options); - } - - __exports__.outletHelper = outletHelper; - }); -enifed("ember-routing-handlebars/helpers/render", - ["ember-metal/core","ember-metal/error","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/helpers/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - 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; - - /** - @module ember - @submodule ember-routing - */ - - /** - 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?} contextString - @param {Hash} options - @return {String} HTML string - */ - __exports__["default"] = function renderHelper(name, contextString, options) { - var length = arguments.length; - var container, router, controller, view, initialContext; - - container = (options || contextString).data.view._keywords.controller.value().container; - router = container.lookup('router:main'); - - if (length === 2) { - // use the singleton controller - options = contextString; - contextString = undefined; - 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 (length === 3) { - // create a new controller - initialContext = options.data.view.getStream(contextString).value(); - } else { - throw new EmberError("You must pass a templateName to render"); - } - - Ember.deprecate("Using a quoteless parameter with {{render}} is deprecated. Please update to" + - " quoted usage '{{render \"" + name + "\"}}.", options.types[0] !== 'ID'); - - // # 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 = options.hash.controller || name; - var controllerFullName = 'controller:' + controllerName; - - if (options.hash.controller) { - Ember.assert("The controller name you supplied '" + controllerName + - "' did not resolve to a controller.", container.has(controllerFullName)); - } - - var parentController = options.data.view._keywords.controller.value(); - - // choose name - if (length > 2) { - var factory = container.lookupFactory(controllerFullName) || - generateControllerFactory(container, controllerName, initialContext); - - controller = factory.create({ - modelBinding: options.data.view._getBindingForStream(contextString), - parentController: parentController, - target: parentController - }); - - view.one('willDestroyElement', function() { - controller.destroy(); - }); - } else { - controller = container.lookup(controllerFullName) || - generateController(container, controllerName); - - controller.setProperties({ - target: parentController, - parentController: parentController - }); - } - - options.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.fn); - options.hash.template = container.lookup(templateName); - - options.hash.controller = controller; - - if (router && !initialContext) { - router._connectActiveView(name, view); - } - - options.helperName = options.helperName || ('render "' + name + '"'); - - ViewHelper.instanceHelper(this, view, options); - } - }); -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'); - ``` - - 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. - @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, 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/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, K, 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; - - /** - @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: Ember.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 = this.get('_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: Ember.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: Ember.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'); - ``` - - 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); - } - } - }); - ``` - - @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. - @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 either - return Ember.RSVP.reject(e); - }); - } - } - }); - ``` - - @method beforeModel - @param {Transition} transition - @param {Object} queryParams the active query params for this route - @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: Ember.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 - @param {Object} queryParams the active query params for this handler - @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: Ember.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: Ember.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 - @param {Object} queryParams the query params for this route - @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 (/_id$/.test(name) && params.length === 1) { - 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; - - if (typeof name === 'object' && !options) { - options = name; - name = this.routeName; - } - - options = options || {}; - options.namePassed = namePassed; - - var templateName; - - if (name) { - name = name.replace(/\//g, '.'); - templateName = name; - } else { - name = this.routeName; - templateName = this.templateName || name; - } - - var viewName = options.view || namePassed && name || this.viewName || name; - - var container = this.container; - var view = container.lookup('view:' + viewName); - var template = view ? view.get('template') : null; - - if (!template) { - template = container.lookup('template:' + templateName); - } - - if (!view && !template) { - Ember.assert("Could not find \"" + name + "\" template or view.", Ember.isEmpty(arguments[0])); - if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { - Ember.Logger.info("Could not find \"" + name + "\" template or view. Nothing will be rendered", { fullName: 'template:' + name }); - } - return; - } - - options = normalizeOptions(this, name, template, options); - view = setupView(view, container, options); - - if (options.outlet === 'main') { this.lastRenderedTemplate = name; } - - appendView(this, view, options); - }, - - /** - 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, 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]; - if (qps.length > 1) { - var qp0 = qps[0].qp, qp1=qps[1].qp; - 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-%@' }`", [qp0.fprop, qp1.fprop, qp0.urlKey, qp0.prop, qp0.prop]), false); - } - 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 = Ember.K; - router._triggerWillLeave = Ember.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.constructor)) { - return v.constructor.compare(v, w); - } - - if (type2 === 'instance' && Comparable.detect(w.constructor)) { - return 1 - w.constructor.compare(w, v); - } - } - - 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; - // 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.cacheable(); - - 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. - - ```javascript - function(item, index); - ``` - - ```javascript - var Hamster = Ember.Object.extend({ - remainingChores: Ember.computed.filter('chores', function(chore, index) { - 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); - 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, { - - /** - The controller used to wrap items, if any. If the value is a string, it will - be used to lookup the container for the controller. As an alternative, you - can also provide a controller class as the value. - - For example: - - ```javascript - App.MyArrayController = Ember.ArrayController.extend({ - itemController: Ember.ObjectController.extend({ - //Item Controller Implementation - }) - }); - ``` - - @property itemController - @type String | Ember.Controller - @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)); - } - - - __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 () { - for (var i = 0, l = arguments.length; i < l; i++) { - var arg = arguments[i]; - Ember.assert('Immediate observers must observe internal properties only, ' + - 'not properties on other objects.', arg.indexOf('.') === -1); - } - - // 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 (error) { - 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); - Ember.assert(error, false); - } - } - }; - - 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/injected_property","ember-metal/keys","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var indexOf = __dependency2__.indexOf; - var InjectedProperty = __dependency3__["default"]; - var keys = __dependency4__["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 intended to be invoked at when extending a factory with - injected properties. Runs per-type validation functions once for each injected - type encountered. - - 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 validatePropertyInjections - @namespace Ember - @param {Object} factory The factory object being extended - @param {Object} props A hash of properties to be added to the factory - */ - function validatePropertyInjections(factory, props) { - var types = []; - var key, desc, validator, i, l; - - for (key in props) { - desc = props[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 - it's 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); - - 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} `true` if the passed function returns `true` for any item - @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} `true` if the passed function returns `true` for any item - @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} `true` if the passed function returns `true` for any item - @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) { - 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 it's - 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.K, 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 = []; - var K = Ember.K; - - /** - 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 (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; - var args = new Array(length); - for (var x = 0; x < length; x++) { - args[x] = arguments[x]; - } - apply(this, this.init, 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 to Ember that 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; }; - } - - if (Ember.config.overridePrototypeMixin) { - Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin); - } - - 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()`. - - @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. - - @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); - } - } - }; - - - var ClassMixin = Mixin.create(ClassMixinProps); - - ClassMixin.ownerConstructor = CoreObject; - - if (Ember.config.overrideClassMixin) { - Ember.config.overrideClassMixin(ClassMixin); - } - - 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.'); - 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-metal/core","ember-runtime/system/core_object","ember-runtime/mixins/observable","ember-runtime/inject","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var CoreObject = __dependency2__["default"]; - var Observable = __dependency3__["default"]; - var validatePropertyInjections = __dependency4__.validatePropertyInjections; - - /** - `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"; - }; - - function injectedPropertyAssertion(props) { - // Injection validations are a debugging aid only, so ensure that they are - // not performed in production builds by invoking from an assertion - Ember.assert("Injected properties are invalid", validatePropertyInjections(this.constructor, props)); - } - - - __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; - - - __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-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-metal/core","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.K - var EmberObject = __dependency2__["default"]; - - /** - @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: Ember.K, - - /** - This callback will be called whenever an async operation has completed. - - @public - @method asyncEnd - */ - asyncEnd: Ember.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')) { - 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() { - // 1. If the router is loading, keep polling - var routerIsLoading = !!app.__container__.lookup('router:main').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'); - ``` - - @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/compare","ember-runtime/ext/rsvp","ember-testing/setup_for_testing","ember-application/system/application","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var emberRun = __dependency2__["default"]; - var create = __dependency3__.create; - var compare = __dependency4__["default"]; - var RSVP = __dependency5__["default"]; - var setupForTesting = __dependency6__["default"]; - var EmberApplication = __dependency7__["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) { - var pair; - if (!this.waiters) { return; } - if (arguments.length === 1) { - callback = context; - context = null; - } - pair = [context, callback]; - this.waiters = Ember.A(this.waiters.filter(function(elt) { - return compare(elt, pair)!==0; - })); - } - }; - - 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","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __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"]; - // 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.ContainerView = ContainerView; - Ember.CollectionView = CollectionView; - Ember.Component = Component; - Ember.EventDispatcher = EventDispatcher; - // END EXPORTS - - __exports__["default"] = Ember; - }); -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']; - } - - if (deprecatedProperty) { - Ember.deprecate('Do not specify ' + deprecatedProperty + ' on a Component, use ' + replacementProperty + ' instead.', false); - } - } - }); - }); -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/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.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/read","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; - - 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.source = source; - this.obj = undefined; - this.key = key; - - if (source && source.isStream) { - 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 (prevSource && prevSource.isStream) { - prevSource.unsubscribe(this._didChange, this); - } - - if (nextSource && nextSource.isStream) { - nextSource.subscribe(this._didChange, this); - } - - this.source = nextSource; - this.notify(); - } - }, - - _didChange: function() { - this.notify(); - }, - - destroy: function() { - if (this.source && this.source.isStream) { - 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; - - Stream.prototype.destroy.call(this); - } - }); - - __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/read", - ["ember-metal/core","ember-metal/property_get","ember-metal/path_cache","ember-runtime/system/string","ember-metal/streams/read","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 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"}}. http://emberjs.com/guides/deprecations#toc_global-lookup-of-views', !viewClass); - } 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 (object && object.isStream) { - 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","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-views - */ - - var jQuery = __dependency1__["default"]; - var DOMHelper = __dependency2__.DOMHelper; - var Ember = __dependency3__["default"]; - var create = __dependency4__.create; - - // 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 occured - } - }) - }); - - 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'); - }), - - /** - 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('_parentView', function(key) { - 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) { - var template = get(this, 'template'); - if (template) { template(context, options); } - }, - - 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) { - 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.setSource(this.isVirtual ? parentKeywords.view : this); - - for (var name in parentKeywords) { - if (keywords[name]) continue; - keywords[name] = parentKeywords[name]; - } - } else { - keywords.view.setSource(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. - - Ember.assert('template must be a function. Did you mean to call Ember.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function'); - // The template should write directly to the render buffer instead - // of returning a string. - output = template(context, { data: data }); - - // 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 parsedPath; - - if (typeof binding === 'string') { - 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']", binding.indexOf(' ') === -1); - parsedPath = View._parsePropertyPath(binding); - if (parsedPath.path === '') { - parsedPath.stream = new SimpleStream(true); - } else { - parsedPath.stream = this.getStream('_view.' + parsedPath.path); - } - } else { - parsedPath = binding; - } - - // 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 - newClass = this._classStringForProperty(parsedPath); - elem = this.$(); - - // 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 = this._classStringForProperty(parsedPath); - - 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; - } - - parsedPath.stream.subscribe(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); - - View.applyAttributeBindings(elem, attributeName, 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, - `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 - - @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, `createElement()` will be called - 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: Ember.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: Ember.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: Ember.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: Ember.K, - - /** - Called when the parentView property has changed. - - @event parentViewDidChange - */ - parentViewDidChange: Ember.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 = get(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 = get(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 = new SimpleStream(); - this._keywords._view = this; - 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 are allowed for 'classNames'", 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.templateData = attrs.templateData || get(this, 'templateData'); - - 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); - - attrs.templateData = get(this, 'templateData'); - view = ViewKlass.create(attrs); - } else { - Ember.assert('You must pass instance or subclass of View', view.isView); - attrs.container = this.container; - - if (!get(view, 'templateData')) { - attrs.templateData = get(this, 'templateData'); - } - - setProperties(view, attrs); - - } - - return view; - }, - - becameVisible: Ember.K, - becameHidden: Ember.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) { - return this._getContextStream().get(path); - }, - - _getBindingForStream: function(path) { - if (this._streamBindings === undefined) { - this._streamBindings = create(null); - this.one('willDestroyElement', this, this._destroyStreamBindings); - } - - if (this._streamBindings[path] !== undefined) { - return this._streamBindings[path]; - } else { - var stream = this._getContextStream().get(path); - return this._streamBindings[path] = new StreamBinding(stream); - } - }, - - _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. - - View.reopenClass({ - - /** - 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 - */ - _parsePropertyPath: function(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 { - stream: undefined, - path: propertyPath, - classNames: classNames, - className: (className === '') ? undefined : className, - falsyClassName: falsyClassName - }; - }, - - /** - 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 - */ - _classStringForValue: function(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; - } - } - }); - - 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; - - 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", - ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { - "use strict"; - /* global navigator */ - // require the main entry points for each of these packages - // this is so that the global exports occur properly - - // 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'); - } - - /** - 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("morph", - ["./morph/morph","./morph/dom-helper","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Morph = __dependency1__["default"]; - var Morph; - __exports__.Morph = Morph; - var DOMHelper = __dependency2__["default"]; - var DOMHelper; - __exports__.DOMHelper = DOMHelper; - }); -enifed("morph/dom-helper", - ["../morph/morph","./dom-helper/build-html-dom","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Morph = __dependency1__["default"]; - var buildHTMLDOM = __dependency2__.buildHTMLDOM; - var svgNamespace = __dependency2__.svgNamespace; - var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints; - - var deletesBlankTextNodes = (function(){ - var element = document.createElement('div'); - element.appendChild( document.createTextNode('') ); - var clonedElement = element.cloneNode(true); - return clonedElement.childNodes.length === 0; - })(); - - var ignoresCheckedAttribute = (function(){ - var element = document.createElement('input'); - element.setAttribute('checked', 'checked'); - var clonedElement = element.cloneNode(false); - return !clonedElement.checked; - })(); - - function isSVG(ns){ - return ns === svgNamespace; - } - - // 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 || window.document; - this.namespace = null; - } - - var prototype = DOMHelper.prototype; - prototype.constructor = DOMHelper; - - prototype.insertBefore = function(element, childElement, referenceChild) { - return element.insertBefore(childElement, referenceChild); - }; - - prototype.appendChild = function(element, childElement) { - return element.appendChild(childElement); - }; - - prototype.appendText = function(element, text) { - return element.appendChild(this.document.createTextNode(text)); - }; - - prototype.setAttribute = function(element, name, value) { - element.setAttribute(name, value); - }; - - if (document.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); - } - }; - } else { - prototype.createElement = function(tagName) { - return this.document.createElement(tagName); - }; - } - - 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.repairClonedNode = function(element, blankChildTextNodes, isChecked){ - if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { - for (var i=0, len=blankChildTextNodes.length;i]*selected/; - detectAutoSelectedOption = 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' ) - ); - }; - } - - // 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 tagNamesRequiringInnerHTMLFix, 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) { - tagNamesRequiringInnerHTMLFix = tagNamesRequiringInnerHTMLFix || {}; - tagNamesRequiringInnerHTMLFix.select = []; - } - - 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 = []; - 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;node=nodes[i];i++) { - if (node.nodeType !== 1) { - continue; - } - if (node.tagName === 'SCRIPT') { - scriptNodes.push(node); - } else { - nodeScriptNodes = node.getElementsByTagName('script'); - for (j=0;j 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/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.reset(); - } - - Morph.prototype.reset = function() { - this.text = null; - this.owner = null; - this.morphs = null; - this.before = null; - this.after = null; - this.escaped = true; - }; - - Morph.prototype.parent = function () { - if (!this.element) { - var parent = this.start.parentNode; - if (this._parent !== parent) { - this.element = this._parent = 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] ? decodeURIComponent(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/assets/scripts/vendor/ember.prod.js b/assets/scripts/vendor/ember.prod.js deleted file mode 100644 index 685da6ad..00000000 --- a/assets/scripts/vendor/ember.prod.js +++ /dev/null @@ -1,48510 +0,0 @@ -/*! - * @overview Ember - JavaScript Application Framework - * @copyright Copyright 2011-2014 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.9.1 - */ - -(function() { -var enifed, requireModule, eriuqer, requirejs, Ember; - -(function() { - Ember = this.Ember = this.Ember || {}; - if (typeof Ember === 'undefined') { Ember = {}; }; - function UNDEFINED() { } - - if (typeof Ember.__loader === 'undefined') { - var registry = {}, seen = {}; - - enifed = function(name, deps, callback) { - registry[name] = { deps: deps, callback: callback }; - }; - - 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", - ["container/container","exports"], - function(__dependency1__, __exports__) { - "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; - } - - - var Container = __dependency1__["default"]; - - __exports__["default"] = Container; - }); -enifed("container/container", - ["ember-metal/core","ember-metal/keys","ember-metal/dictionary","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var emberKeys = __dependency2__["default"]; - var dictionary = __dependency3__["default"]; - - // A lightweight container that helps to assemble and decouple components. - // Public api for the container is still in flux. - // The public api, specified on the application namespace should be considered the stable api. - function Container(parent) { - this.parent = parent; - this.children = []; - - this.resolver = parent && parent.resolver || function() {}; - - this.registry = dictionary(parent ? parent.registry : null); - this.cache = dictionary(parent ? parent.cache : null); - this.factoryCache = dictionary(parent ? parent.factoryCache : null); - this.resolveCache = dictionary(parent ? parent.resolveCache : null); - this.typeInjections = dictionary(parent ? parent.typeInjections : null); - this.injections = dictionary(null); - this.normalizeCache = dictionary(null); - - this.factoryTypeInjections = dictionary(parent ? parent.factoryTypeInjections : null); - this.factoryInjections = dictionary(null); - - this._options = dictionary(parent ? parent._options : null); - this._typeOptions = dictionary(parent ? parent._typeOptions : null); - } - - Container.prototype = { - - /** - @property parent - @type Container - @default null - */ - parent: null, - - /** - @property children - @type Array - @default [] - */ - children: null, - - /** - @property resolver - @type function - */ - resolver: null, - - /** - @property registry - @type InheritingDict - */ - registry: null, - - /** - @property cache - @type InheritingDict - */ - cache: null, - - /** - @property typeInjections - @type InheritingDict - */ - typeInjections: null, - - /** - @property injections - @type Object - @default {} - */ - injections: null, - - /** - @private - - @property _options - @type InheritingDict - @default null - */ - _options: null, - - /** - @private - - @property _typeOptions - @type InheritingDict - */ - _typeOptions: null, - - /** - Returns a new child of the current container. These children are configured - to correctly inherit from the current container. - - @method child - @return {Container} - */ - child: function() { - var container = new Container(this); - this.children.push(container); - return container; - }, - - /** - Registers a factory for later injection. - - Example: - - ```javascript - var container = new Container(); - - container.register('model:user', Person, {singleton: false }); - container.register('fruit:favorite', Orange); - container.register('communication:main', Email, {singleton: false}); - ``` - - @method register - @param {String} fullName - @param {Function} factory - @param {Object} options - */ - register: function(fullName, factory, options) { - - if (factory === undefined) { - throw new TypeError('Attempting to register an unknown factory: `' + fullName + '`'); - } - - var normalizedName = this.normalize(fullName); - - if (normalizedName in this.cache) { - throw new Error('Cannot re-register: `' + fullName +'`, as it has already been looked up.'); - } - - this.registry[normalizedName] = factory; - this._options[normalizedName] = (options || {}); - }, - - /** - Unregister a fullName - - ```javascript - var container = new Container(); - container.register('model:user', User); - - container.lookup('model:user') instanceof User //=> true - - container.unregister('model:user') - container.lookup('model:user') === undefined //=> true - ``` - - @method unregister - @param {String} fullName - */ - unregister: function(fullName) { - - var normalizedName = this.normalize(fullName); - - delete this.registry[normalizedName]; - delete this.cache[normalizedName]; - delete this.factoryCache[normalizedName]; - delete this.resolveCache[normalizedName]; - delete this._options[normalizedName]; - }, - - /** - Given a fullName return the corresponding factory. - - By default `resolve` will retrieve the factory from - its container's registry. - - ```javascript - var container = new Container(); - container.register('api:twitter', Twitter); - - container.resolve('api:twitter') // => Twitter - ``` - - Optionally the container 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 container = new Container(); - container.resolver = function(fullName) { - // lookup via the module system of choice - }; - - // the twitter factory is added to the module system - container.resolve('api:twitter') // => Twitter - ``` - - @method resolve - @param {String} fullName - @return {Function} fullName's factory - */ - resolve: function(fullName) { - return resolve(this, this.normalize(fullName)); - }, - - /** - 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 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 container = new Container(); - container.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 container = new Container(); - container.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) { - return lookup(this, this.normalize(fullName), options); - }, - - /** - Given a fullName return the corresponding factory. - - @method lookupFactory - @param {String} fullName - @return {any} - */ - lookupFactory: function(fullName) { - return factoryFor(this, this.normalize(fullName)); - }, - - /** - 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) { - return has(this, this.normalize(fullName)); - }, - - /** - Allow registering options for all factories of a type. - - ```javascript - var container = new Container(); - - // if all of type `connection` must not be singletons - container.optionsForType('connection', { singleton: false }); - - container.register('connection:twitter', TwitterConnection); - container.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) { - if (this.parent) { illegalChildOperation('optionsForType'); } - - this._typeOptions[type] = options; - }, - - /** - @method options - @param {String} fullName - @param {Object} options - */ - options: function(fullName, options) { - options = options || {}; - var normalizedName = this.normalize(fullName); - this._options[normalizedName] = options; - }, - - /** - 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 container = new Container(); - - container.register('router:main', Router); - container.register('controller:user', UserController); - container.register('controller:post', PostController); - - container.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) { - - if (this.parent) { illegalChildOperation('typeInjection'); } - - var fullNameType = fullName.split(':')[0]; - if (fullNameType === type) { - throw new Error('Cannot inject a `' + fullName + - '` on other ' + type + - '(s). Register the `' + fullName + - '` as a different type and perform the typeInjection.'); - } - - addTypeInjection(this.typeInjections, type, property, 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 container = new Container(); - - container.register('source:main', Source); - container.register('model:user', User); - container.register('model:post', Post); - - // injecting one fullName on another fullName - // eg. each user model gets a post model - container.injection('model:user', 'post', 'model:post'); - - // injecting one fullName on another type - container.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) { - if (this.parent) { illegalChildOperation('injection'); } - - validateFullName(injectionName); - var normalizedInjectionName = this.normalize(injectionName); - - if (fullName.indexOf(':') === -1) { - return this.typeInjection(fullName, property, normalizedInjectionName); - } - - var normalizedName = this.normalize(fullName); - - if (this.cache[normalizedName]) { - throw new Error("Attempted to register an injection for a type that has already been looked up. ('" + - normalizedName + "', '" + - property + "', '" + - injectionName + "')"); - } - - addInjection(initRules(this.injections, normalizedName), property, 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 container = new Container(); - - container.register('store:main', SomeStore); - - container.factoryTypeInjection('model', 'store', 'store:main'); - - var store = container.lookup('store:main'); - var UserFactory = container.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) { - if (this.parent) { illegalChildOperation('factoryTypeInjection'); } - - addTypeInjection(this.factoryTypeInjections, type, property, this.normalize(fullName)); - }, - - /** - Defines factory injection rules. - - Similar to regular injection rules, but are run against factories, via - `Container#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 container = new Container(); - - container.register('store:main', Store); - container.register('store:secondary', OtherStore); - container.register('model:user', User); - container.register('model:post', Post); - - // injecting one fullName on another type - container.factoryInjection('model', 'store', 'store:main'); - - // injecting one fullName on another fullName - container.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) { - if (this.parent) { illegalChildOperation('injection'); } - - var normalizedName = this.normalize(fullName); - var normalizedInjectionName = this.normalize(injectionName); - - validateFullName(injectionName); - - if (fullName.indexOf(':') === -1) { - return this.factoryTypeInjection(normalizedName, property, normalizedInjectionName); - } - - - if (this.factoryCache[normalizedName]) { - throw new Error('Attempted to register a factoryInjection for a type that has already ' + - 'been looked up. (\'' + normalizedName + '\', \'' + property + '\', \'' + injectionName + '\')'); - } - - addInjection(initRules(this.factoryInjections, normalizedName), property, normalizedInjectionName); - }, - - /** - A depth first traversal, destroying the container, its descendant containers and all - their managed objects. - - @method destroy - */ - destroy: function() { - for (var i = 0, length = this.children.length; i < length; i++) { - this.children[i].destroy(); - } - - this.children = []; - - eachDestroyable(this, function(item) { - item.destroy(); - }); - - this.parent = undefined; - this.isDestroyed = true; - }, - - /** - @method reset - */ - reset: function() { - for (var i = 0, length = this.children.length; i < length; i++) { - resetCache(this.children[i]); - } - - resetCache(this); - } - }; - - function resolve(container, normalizedName) { - var cached = container.resolveCache[normalizedName]; - if (cached) { return cached; } - - var resolved = container.resolver(normalizedName) || container.registry[normalizedName]; - container.resolveCache[normalizedName] = resolved; - - return resolved; - } - - function has(container, fullName){ - if (container.cache[fullName]) { - return true; - } - - return container.resolve(fullName) !== undefined; - } - - 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 (isSingleton(container, fullName) && options.singleton !== false) { - container.cache[fullName] = value; - } - - return value; - } - - function illegalChildOperation(operation) { - throw new Error(operation + ' is not currently supported on child containers'); - } - - function isSingleton(container, fullName) { - var singleton = option(container, fullName, 'singleton'); - - return singleton !== false; - } - - function buildInjections(container, injections) { - var hash = {}; - - if (!injections) { return hash; } - - validateInjections(container, injections); - - var injection; - - for (var i = 0, length = injections.length; i < length; i++) { - injection = injections[i]; - hash[injection.property] = lookup(container, injection.fullName); - } - - return hash; - } - - function validateInjections(container, injections) { - if (!injections) { return; } - - var fullName; - - for (var i = 0, length = injections.length; i < length; i++) { - fullName = injections[i].fullName; - - if (!container.has(fullName)) { - throw new Error('Attempting to inject an unknown injection: `' + fullName + '`'); - } - } - } - - function option(container, fullName, optionName) { - var options = container._options[fullName]; - - if (options && options[optionName] !== undefined) { - return options[optionName]; - } - - var type = fullName.split(':')[0]; - options = container._typeOptions[type]; - - if (options) { - return options[optionName]; - } - } - - function factoryFor(container, fullName) { - var cache = container.factoryCache; - if (cache[fullName]) { - return cache[fullName]; - } - var factory = container.resolve(fullName); - if (factory === undefined) { return; } - - var type = fullName.split(':')[0]; - if (!factory || typeof factory.extend !== 'function' || (!Ember.MODEL_FACTORY_INJECTIONS && type === 'model')) { - // 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 = container.makeToString(factory, fullName); - - var injectedFactory = factory.extend(injections); - injectedFactory.reopenClass(factoryInjections); - - cache[fullName] = injectedFactory; - - return injectedFactory; - } - } - - function injectionsFor(container, fullName) { - var splitName = fullName.split(':'); - var type = splitName[0]; - var injections = []; - - injections = injections.concat(container.typeInjections[type] || []); - injections = injections.concat(container.injections[fullName] || []); - - injections = buildInjections(container, injections); - injections._debugContainerKey = fullName; - injections.container = container; - - return injections; - } - - function factoryInjectionsFor(container, fullName) { - var splitName = fullName.split(':'); - var type = splitName[0]; - var factoryInjections = []; - - factoryInjections = factoryInjections.concat(container.factoryTypeInjections[type] || []); - factoryInjections = factoryInjections.concat(container.factoryInjections[fullName] || []); - - factoryInjections = buildInjections(container, factoryInjections); - factoryInjections._debugContainerKey = fullName; - - return factoryInjections; - } - - function normalizeInjectionsHash(hash) { - var injections = []; - - for (var key in hash) { - if (hash.hasOwnProperty(key)) { - - addInjection(injections, key, hash[key]); - } - } - - return injections; - } - - function instantiate(container, fullName) { - var factory = factoryFor(container, fullName); - var lazyInjections; - - if (option(container, 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.'); - } - - - 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(cache); - var key, value; - - for (var i = 0, l = keys.length; i < l; i++) { - key = keys[i]; - value = cache[key]; - - if (option(container, key, 'instantiate') !== false) { - callback(value); - } - } - } - - function resetCache(container) { - eachDestroyable(container, function(value) { - value.destroy(); - }); - - container.cache.dict = dictionary(null); - } - - function addTypeInjection(rules, type, property, fullName) { - var injections = rules[type]; - - if (!injections) { - injections = []; - rules[type] = injections; - } - - injections.push({ - property: property, - fullName: fullName - }); - } - - var VALID_FULL_NAME_REGEXP = /^[^:]+.+:[^:]+$/; - function validateFullName(fullName) { - if (!VALID_FULL_NAME_REGEXP.test(fullName)) { - throw new TypeError('Invalid Fullname, expected: `type:name` got: ' + fullName); - } - return true; - } - - function initRules(rules, factoryName) { - return rules[factoryName] || (rules[factoryName] = []); - } - - function addInjection(injections, property, injectionName) { - injections.push({ - property: property, - fullName: injectionName - }); - } - - __exports__["default"] = Container; - }); -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("ember-application", - ["ember-metal/core","ember-runtime/system/lazy_load","ember-application/system/resolver","ember-application/system/application","ember-application/ext/controller"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) { - "use strict"; - var Ember = __dependency1__["default"]; - var runLoadHooks = __dependency2__.runLoadHooks; - - /** - Ember Application - - @module ember - @submodule ember-application - @requires ember-views, ember-routing - */ - - var Resolver = __dependency3__.Resolver; - var DefaultResolver = __dependency3__["default"]; - var Application = __dependency4__["default"]; - // side effect of extending ControllerMixin - - Ember.Application = Application; - Ember.Resolver = Resolver; - Ember.DefaultResolver = DefaultResolver; - - runLoadHooks('Ember.Application', Application); - }); -enifed("ember-application/ext/controller", - ["ember-metal/core","ember-metal/property_get","ember-metal/error","ember-metal/utils","ember-metal/computed","ember-runtime/mixins/controller","ember-routing/system/controller_for","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-application - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var get = __dependency2__.get; - var EmberError = __dependency3__["default"]; - var inspect = __dependency4__.inspect; - var computed = __dependency5__.computed; - var ControllerMixin = __dependency6__["default"]; - var meta = __dependency4__.meta; - var controllerFor = __dependency7__["default"]; - - function verifyNeedsDependencies(controller, container, needs) { - var dependency, i, l; - var missing = []; - - for (i=0, l=needs.length; i 1 ? 'they' : 'it') + " could not be found"); - } - } - - var defaultControllersComputedProperty = computed(function() { - var controller = this; - - return { - needs: get(controller, 'needs'), - container: get(controller, 'container'), - unknownProperty: function(controllerName) { - var needs = this.needs; - var dependency, i, l; - - for (i=0, l=needs.length; i 0) { - - if (this.container) { - verifyNeedsDependencies(this, this.container, needs); - } - - // if needs then initialize controllers proxy - get(this, 'controllers'); - } - - this._super.apply(this, arguments); - }, - - /** - @method controllerFor - @see {Ember.Route#controllerFor} - @deprecated Use `needs` instead - */ - controllerFor: function(controllerName) { - return controllerFor(get(this, 'container'), controllerName); - }, - - /** - Stores the instances of other controllers available from within - this controller. Any controller listed by name in the `needs` - property will be accessible by name through this property. - - ```javascript - App.CommentsController = Ember.ArrayController.extend({ - needs: ['post'], - postTitle: function(){ - var currentPost = this.get('controllers.post'); // instance of App.PostController - return currentPost.get('title'); - }.property('controllers.post.title') - }); - ``` - - @see {Ember.ControllerMixin#needs} - @property {Object} controllers - @default null - */ - controllers: defaultControllersComputedProperty - }); - - __exports__["default"] = ControllerMixin; - }); -enifed("ember-application/system/application", - ["dag-map","container/container","ember-metal","ember-metal/property_get","ember-metal/property_set","ember-runtime/system/lazy_load","ember-runtime/system/namespace","ember-runtime/mixins/deferred","ember-application/system/resolver","ember-metal/platform","ember-metal/run_loop","ember-metal/utils","ember-runtime/controllers/controller","ember-metal/enumerable_utils","ember-runtime/controllers/object_controller","ember-runtime/controllers/array_controller","ember-handlebars/controls/select","ember-views/system/event_dispatcher","ember-views/system/jquery","ember-routing/system/route","ember-routing/system/router","ember-routing/location/hash_location","ember-routing/location/history_location","ember-routing/location/auto_location","ember-routing/location/none_location","ember-routing/system/cache","ember-extension-support/container_debug_adapter","ember-metal/core","ember-handlebars-compiler","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__, __dependency29__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-application - */ - var DAG = __dependency1__["default"]; - var Container = __dependency2__["default"]; - - - var Ember = __dependency3__["default"]; - // Ember.FEATURES, Ember.deprecate, Ember.assert, Ember.libraries, LOG_VERSION, Namespace, BOOTED - var get = __dependency4__.get; - var set = __dependency5__.set; - var runLoadHooks = __dependency6__.runLoadHooks; - var Namespace = __dependency7__["default"]; - var DeferredMixin = __dependency8__["default"]; - var DefaultResolver = __dependency9__["default"]; - var create = __dependency10__.create; - var run = __dependency11__["default"]; - var canInvoke = __dependency12__.canInvoke; - var Controller = __dependency13__["default"]; - var EnumerableUtils = __dependency14__["default"]; - var ObjectController = __dependency15__["default"]; - var ArrayController = __dependency16__["default"]; - var SelectView = __dependency17__["default"]; - var EventDispatcher = __dependency18__["default"]; - var jQuery = __dependency19__["default"]; - var Route = __dependency20__["default"]; - var Router = __dependency21__["default"]; - var HashLocation = __dependency22__["default"]; - var HistoryLocation = __dependency23__["default"]; - var AutoLocation = __dependency24__["default"]; - var NoneLocation = __dependency25__["default"]; - var BucketCache = __dependency26__["default"]; - - // this is technically incorrect (per @wycats) - // it should work properly with: - // `import ContainerDebugAdapter from 'ember-extension-support/container_debug_adapter';` but - // es6-module-transpiler 0.4.0 eagerly grabs the module (which is undefined) - - var ContainerDebugAdapter = __dependency27__["default"]; - - var K = __dependency28__.K; - var EmberHandlebars = __dependency29__["default"]; - - function props(obj) { - var properties = []; - - for (var key in obj) { - properties.push(key); - } - - return properties; - } - - /** - An instance of `Ember.Application` is the starting point for every Ember - application. It helps to instantiate, initialize and coordinate the many - objects that make up your app. - - Each Ember app has one and only one `Ember.Application` object. In fact, the - very first thing you should do in your application is create the instance: - - ```javascript - window.App = Ember.Application.create(); - ``` - - Typically, the application object is the only global variable. All other - classes in your app should be properties on the `Ember.Application` instance, - which highlights its first role: a global namespace. - - For example, if you define a view class, it might look like this: - - ```javascript - App.MyView = Ember.View.extend(); - ``` - - By default, calling `Ember.Application.create()` will automatically initialize - your application by calling the `Ember.Application.initialize()` method. If - you need to delay initialization, you can call your app's `deferReadiness()` - method. When you are ready for your app to be initialized, call its - `advanceReadiness()` method. - - You can define a `ready` method on the `Ember.Application` instance, which - will be run by Ember when the application is initialized. - - Because `Ember.Application` inherits from `Ember.Namespace`, any classes - you create will have useful string representations when calling `toString()`. - See the `Ember.Namespace` documentation for more information. - - While you can think of your `Ember.Application` as a container that holds the - other classes in your application, there are several other responsibilities - going on under-the-hood that you may want to understand. - - ### Event Delegation - - Ember uses a technique called _event delegation_. This allows the framework - to set up a global, shared event listener instead of requiring each view to - do it manually. For example, instead of each view registering its own - `mousedown` listener on its associated element, Ember sets up a `mousedown` - listener on the `body`. - - If a `mousedown` event occurs, Ember will look at the target of the event and - start walking up the DOM node tree, finding corresponding views and invoking - their `mouseDown` method as it goes. - - `Ember.Application` has a number of default events that it listens for, as - well as a mapping from lowercase events to camel-cased view method names. For - example, the `keypress` event causes the `keyPress` method on the view to be - called, the `dblclick` event causes `doubleClick` to be called, and so on. - - If there is a bubbling browser event that Ember does not listen for by - default, you can specify custom events and their corresponding view method - names by setting the application's `customEvents` property: - - ```javascript - var App = Ember.Application.create({ - customEvents: { - // add support for the paste event - paste: 'paste' - } - }); - ``` - - By default, the application sets up these event listeners on the document - body. However, in cases where you are embedding an Ember application inside - an existing page, you may want it to set up the listeners on an element - inside the body. - - For example, if only events inside a DOM element with the ID of `ember-app` - should be delegated, set your application's `rootElement` property: - - ```javascript - var App = Ember.Application.create({ - rootElement: '#ember-app' - }); - ``` - - The `rootElement` can be either a DOM element or a jQuery-compatible selector - string. Note that *views appended to the DOM outside the root element will - not receive events.* If you specify a custom root element, make sure you only - append views inside it! - - To learn more about the advantages of event delegation and the Ember view - layer, and a list of the event listeners that are setup by default, visit the - [Ember View Layer guide](http://emberjs.com/guides/understanding-ember/the-view-layer/#toc_event-delegation). - - ### Initializers - - Libraries on top of Ember can add initializers, like so: - - ```javascript - Ember.Application.initializer({ - name: 'api-adapter', - - initialize: function(container, application) { - application.register('api-adapter:main', ApiAdapter); - } - }); - ``` - - Initializers provide an opportunity to access the container, which - organizes the different components of an Ember application. Additionally - they provide a chance to access the instantiated application. Beyond - being used for libraries, initializers are also a great way to organize - dependency injection or setup in your own application. - - ### Routing - - In addition to creating your application's router, `Ember.Application` is - also responsible for telling the router when to start routing. Transitions - between routes can be logged with the `LOG_TRANSITIONS` flag, and more - detailed intra-transition logging can be logged with - the `LOG_TRANSITIONS_INTERNAL` flag: - - ```javascript - var App = Ember.Application.create({ - LOG_TRANSITIONS: true, // basic logging of successful transitions - LOG_TRANSITIONS_INTERNAL: true // detailed logging of all routing steps - }); - ``` - - By default, the router will begin trying to translate the current URL into - application state once the browser emits the `DOMContentReady` event. If you - need to defer routing, you can call the application's `deferReadiness()` - method. Once routing can begin, call the `advanceReadiness()` method. - - If there is any setup required before routing begins, you can implement a - `ready()` method on your app that will be invoked immediately before routing - begins. - ``` - - @class Application - @namespace Ember - @extends Ember.Namespace - */ - - var Application = Namespace.extend(DeferredMixin, { - _suppressDeferredDeprecation: true, - - /** - The root DOM element of the Application. This can be specified as an - element or a - [jQuery-compatible selector string](http://api.jquery.com/category/selectors/). - - This is the element that will be passed to the Application's, - `eventDispatcher`, which sets up the listeners for event delegation. Every - view in your application should be a child of the element you specify here. - - @property rootElement - @type DOMElement - @default 'body' - */ - rootElement: 'body', - - /** - The `Ember.EventDispatcher` responsible for delegating events to this - application's views. - - The event dispatcher is created by the application at initialization time - and sets up event listeners on the DOM element described by the - application's `rootElement` property. - - See the documentation for `Ember.EventDispatcher` for more information. - - @property eventDispatcher - @type Ember.EventDispatcher - @default null - */ - eventDispatcher: null, - - /** - The DOM events for which the event dispatcher should listen. - - By default, the application's `Ember.EventDispatcher` listens - for a set of standard DOM events, such as `mousedown` and - `keyup`, and delegates them to your application's `Ember.View` - instances. - - If you would like additional bubbling events to be delegated to your - views, set your `Ember.Application`'s `customEvents` property - to a hash containing the DOM event name as the key and the - corresponding view method name as the value. For example: - - ```javascript - var App = Ember.Application.create({ - customEvents: { - // add support for the paste event - paste: 'paste' - } - }); - ``` - - @property customEvents - @type Object - @default null - */ - customEvents: null, - - // Start off the number of deferrals at 1. This will be - // decremented by the Application's own `initialize` method. - _readinessDeferrals: 1, - - init: function() { - if (!this.$) { - this.$ = jQuery; - } - this.__container__ = this.buildContainer(); - - this.Router = this.defaultRouter(); - - this._super(); - - this.scheduleInitialize(); - - Ember.libraries.registerCoreLibrary('Handlebars' + (EmberHandlebars.compile ? '' : '-runtime'), EmberHandlebars.VERSION); - Ember.libraries.registerCoreLibrary('jQuery', jQuery().jquery); - - if ( Ember.LOG_VERSION ) { - Ember.LOG_VERSION = false; // we only need to see this once per Application#init - - var nameLengths = EnumerableUtils.map(Ember.libraries, function(item) { - return get(item, "name.length"); - }); - - var maxNameLength = Math.max.apply(this, nameLengths); - - Ember.libraries.each(function(name, version) { - var spaces = new Array(maxNameLength - name.length + 1).join(" "); - }); - } - }, - - /** - Build the container for the current application. - - Also register a default application view in case the application - itself does not. - - @private - @method buildContainer - @return {Ember.Container} the configured container - */ - buildContainer: function() { - var container = this.__container__ = Application.buildContainer(this); - - return container; - }, - - /** - If the application has not opted out of routing and has not explicitly - defined a router, supply a default router for the application author - to configure. - - This allows application developers to do: - - ```javascript - var App = Ember.Application.create(); - - App.Router.map(function() { - this.resource('posts'); - }); - ``` - - @private - @method defaultRouter - @return {Ember.Router} the default router - */ - - defaultRouter: function() { - if (this.Router === false) { return; } - var container = this.__container__; - - if (this.Router) { - container.unregister('router:main'); - container.register('router:main', this.Router); - } - - return container.lookupFactory('router:main'); - }, - - /** - Automatically initialize the application once the DOM has - become ready. - - The initialization itself is scheduled on the actions queue - which ensures that application loading finishes before - booting. - - If you are asynchronously loading code, you should call - `deferReadiness()` to defer booting, and then call - `advanceReadiness()` once all of your code has finished - loading. - - @private - @method scheduleInitialize - */ - scheduleInitialize: function() { - var self = this; - - if (!this.$ || this.$.isReady) { - run.schedule('actions', self, '_initialize'); - } else { - this.$().ready(function runInitialize() { - run(self, '_initialize'); - }); - } - }, - - /** - Use this to defer readiness until some condition is true. - - Example: - - ```javascript - var App = Ember.Application.create(); - - App.deferReadiness(); - // Ember.$ is a reference to the jQuery object/function - Ember.$.getJSON('/auth-token', function(token) { - App.token = token; - App.advanceReadiness(); - }); - ``` - - This allows you to perform asynchronous setup logic and defer - booting your application until the setup has finished. - - However, if the setup requires a loading UI, it might be better - to use the router for this purpose. - - @method deferReadiness - */ - deferReadiness: function() { - this._readinessDeferrals++; - }, - - /** - Call `advanceReadiness` after any asynchronous setup logic has completed. - Each call to `deferReadiness` must be matched by a call to `advanceReadiness` - or the application will never become ready and routing will not begin. - - @method advanceReadiness - @see {Ember.Application#deferReadiness} - */ - advanceReadiness: function() { - this._readinessDeferrals--; - - if (this._readinessDeferrals === 0) { - run.once(this, this.didBecomeReady); - } - }, - - /** - Registers a factory that can be used for dependency injection (with - `App.inject`) or for service lookup. Each factory is registered with - a full name including two parts: `type:name`. - - A simple example: - - ```javascript - var App = Ember.Application.create(); - - App.Orange = Ember.Object.extend(); - App.register('fruit:favorite', App.Orange); - ``` - - Ember will resolve factories from the `App` namespace automatically. - For example `App.CarsController` will be discovered and returned if - an application requests `controller:cars`. - - An example of registering a controller with a non-standard name: - - ```javascript - var App = Ember.Application.create(); - var Session = Ember.Controller.extend(); - - App.register('controller:session', Session); - - // The Session controller can now be treated like a normal controller, - // despite its non-standard name. - App.ApplicationController = Ember.Controller.extend({ - needs: ['session'] - }); - ``` - - Registered factories are **instantiated** by having `create` - called on them. Additionally they are **singletons**, each time - they are looked up they return the same instance. - - Some examples modifying that default behavior: - - ```javascript - var App = Ember.Application.create(); - - App.Person = Ember.Object.extend(); - App.Orange = Ember.Object.extend(); - App.Email = Ember.Object.extend(); - App.session = Ember.Object.create(); - - App.register('model:user', App.Person, { singleton: false }); - App.register('fruit:favorite', App.Orange); - App.register('communication:main', App.Email, { singleton: false }); - App.register('session', App.session, { instantiate: false }); - ``` - - @method register - @param fullName {String} type:name (e.g., 'model:user') - @param factory {Function} (e.g., App.Person) - @param options {Object} (optional) disable instantiation or singleton usage - **/ - register: function() { - var container = this.__container__; - container.register.apply(container, arguments); - }, - - /** - Define a dependency injection onto a specific factory or all factories - of a type. - - When Ember instantiates a controller, view, or other framework component - it can attach a dependency to that component. This is often used to - provide services to a set of framework components. - - An example of providing a session object to all controllers: - - ```javascript - var App = Ember.Application.create(); - var Session = Ember.Object.extend({ isAuthenticated: false }); - - // A factory must be registered before it can be injected - App.register('session:main', Session); - - // Inject 'session:main' onto all factories of the type 'controller' - // with the name 'session' - App.inject('controller', 'session', 'session:main'); - - App.IndexController = Ember.Controller.extend({ - isLoggedIn: Ember.computed.alias('session.isAuthenticated') - }); - ``` - - Injections can also be performed on specific factories. - - ```javascript - App.inject(, , ) - App.inject('route', 'source', 'source:main') - App.inject('route:application', 'email', 'model:email') - ``` - - It is important to note that injections can only be performed on - classes that are instantiated by Ember itself. Instantiating a class - directly (via `create` or `new`) bypasses the dependency injection - system. - - **Note:** Ember-Data instantiates its models in a unique manner, and consequently - injections onto models (or all models) will not work as expected. Injections - on models can be enabled by setting `Ember.MODEL_FACTORY_INJECTIONS` - to `true`. - - @method inject - @param factoryNameOrType {String} - @param property {String} - @param injectionName {String} - **/ - inject: function() { - var container = this.__container__; - container.injection.apply(container, arguments); - }, - - /** - Calling initialize manually is not supported. - - Please see Ember.Application#advanceReadiness and - Ember.Application#deferReadiness. - - @private - @deprecated - @method initialize - **/ - initialize: function() { - }, - - /** - Initialize the application. This happens automatically. - - Run any initializers and run the application load hook. These hooks may - choose to defer readiness. For example, an authentication hook might want - to defer readiness until the auth token has been retrieved. - - @private - @method _initialize - */ - _initialize: function() { - if (this.isDestroyed) { return; } - - // At this point, the App.Router must already be assigned - if (this.Router) { - var container = this.__container__; - container.unregister('router:main'); - container.register('router:main', this.Router); - } - - this.runInitializers(); - runLoadHooks('application', this); - - // At this point, any initializers or load hooks that would have wanted - // to defer readiness have fired. In general, advancing readiness here - // will proceed to didBecomeReady. - this.advanceReadiness(); - - return this; - }, - - /** - Reset the application. This is typically used only in tests. It cleans up - the application in the following order: - - 1. Deactivate existing routes - 2. Destroy all objects in the container - 3. Create a new application container - 4. Re-route to the existing url - - Typical Example: - - ```javascript - var App; - - run(function() { - App = Ember.Application.create(); - }); - - module('acceptance test', { - setup: function() { - App.reset(); - } - }); - - test('first test', function() { - // App is freshly reset - }); - - test('second test', function() { - // App is again freshly reset - }); - ``` - - Advanced Example: - - Occasionally you may want to prevent the app from initializing during - setup. This could enable extra configuration, or enable asserting prior - to the app becoming ready. - - ```javascript - var App; - - run(function() { - App = Ember.Application.create(); - }); - - module('acceptance test', { - setup: function() { - run(function() { - App.reset(); - App.deferReadiness(); - }); - } - }); - - test('first test', function() { - ok(true, 'something before app is initialized'); - - run(function() { - App.advanceReadiness(); - }); - - ok(true, 'something after app is initialized'); - }); - ``` - - @method reset - **/ - reset: function() { - this._readinessDeferrals = 1; - - function handleReset() { - var router = this.__container__.lookup('router:main'); - router.reset(); - - run(this.__container__, 'destroy'); - - this.buildContainer(); - - run.schedule('actions', this, function() { - this._initialize(); - }); - } - - run.join(this, handleReset); - }, - - /** - @private - @method runInitializers - */ - runInitializers: function() { - var initializersByName = get(this.constructor, 'initializers'); - var initializers = props(initializersByName); - var container = this.__container__; - var graph = new DAG(); - var namespace = this; - var initializer; - - for (var i = 0; i < initializers.length; i++) { - initializer = initializersByName[initializers[i]]; - graph.addEdges(initializer.name, initializer.initialize, initializer.before, initializer.after); - } - - graph.topsort(function (vertex) { - var initializer = vertex.value; - initializer(container, namespace); - }); - }, - - /** - @private - @method didBecomeReady - */ - didBecomeReady: function() { - this.setupEventDispatcher(); - this.ready(); // user hook - this.startRouting(); - - if (!Ember.testing) { - // Eagerly name all classes that are already loaded - Ember.Namespace.processAll(); - Ember.BOOTED = true; - } - - this.resolve(this); - }, - - /** - Setup up the event dispatcher to receive events on the - application's `rootElement` with any registered - `customEvents`. - - @private - @method setupEventDispatcher - */ - setupEventDispatcher: function() { - var customEvents = get(this, 'customEvents'); - var rootElement = get(this, 'rootElement'); - var dispatcher = this.__container__.lookup('event_dispatcher:main'); - - set(this, 'eventDispatcher', dispatcher); - dispatcher.setup(customEvents, rootElement); - }, - - /** - If the application has a router, use it to route to the current URL, and - trigger a new call to `route` whenever the URL changes. - - @private - @method startRouting - @property router {Ember.Router} - */ - startRouting: function() { - var router = this.__container__.lookup('router:main'); - if (!router) { return; } - - router.startRouting(); - }, - - handleURL: function(url) { - var router = this.__container__.lookup('router:main'); - - router.handleURL(url); - }, - - /** - Called when the Application has become ready. - The call will be delayed until the DOM has become ready. - - @event ready - */ - ready: K, - - /** - @deprecated Use 'Resolver' instead - Set this to provide an alternate class to `Ember.DefaultResolver` - - - @property resolver - */ - resolver: null, - - /** - Set this to provide an alternate class to `Ember.DefaultResolver` - - @property resolver - */ - Resolver: null, - - willDestroy: function() { - Ember.BOOTED = false; - // Ensure deactivation of routes before objects are destroyed - this.__container__.lookup('router:main').reset(); - - this.__container__.destroy(); - }, - - initializer: function(options) { - this.constructor.initializer(options); - }, - - /** - @method then - @private - @deprecated - */ - then: function() { - - this._super.apply(this, arguments); - } - }); - - Application.reopenClass({ - initializers: create(null), - - /** - Initializer receives an object which has the following attributes: - `name`, `before`, `after`, `initialize`. The only required attribute is - `initialize, all others are optional. - - * `name` allows you to specify under which name the initializer is registered. - This must be a unique name, as trying to register two initializers with the - same name will result in an error. - - ```javascript - Ember.Application.initializer({ - name: 'namedInitializer', - - initialize: function(container, application) { - Ember.debug('Running namedInitializer!'); - } - }); - ``` - - * `before` and `after` are used to ensure that this initializer is ran prior - or after the one identified by the value. This value can be a single string - or an array of strings, referencing the `name` of other initializers. - - An example of ordering initializers, we create an initializer named `first`: - - ```javascript - Ember.Application.initializer({ - name: 'first', - - initialize: function(container, application) { - Ember.debug('First initializer!'); - } - }); - - // DEBUG: First initializer! - ``` - - We add another initializer named `second`, specifying that it should run - after the initializer named `first`: - - ```javascript - Ember.Application.initializer({ - name: 'second', - after: 'first', - - initialize: function(container, application) { - Ember.debug('Second initializer!'); - } - }); - - // DEBUG: First initializer! - // DEBUG: Second initializer! - ``` - - Afterwards we add a further initializer named `pre`, this time specifying - that it should run before the initializer named `first`: - - ```javascript - Ember.Application.initializer({ - name: 'pre', - before: 'first', - - initialize: function(container, application) { - Ember.debug('Pre initializer!'); - } - }); - - // DEBUG: Pre initializer! - // DEBUG: First initializer! - // DEBUG: Second initializer! - ``` - - Finally we add an initializer named `post`, specifying it should run after - both the `first` and the `second` initializers: - - ```javascript - Ember.Application.initializer({ - name: 'post', - after: ['first', 'second'], - - initialize: function(container, application) { - Ember.debug('Post initializer!'); - } - }); - - // DEBUG: Pre initializer! - // DEBUG: First initializer! - // DEBUG: Second initializer! - // DEBUG: Post initializer! - ``` - - * `initialize` is a callback function that receives two arguments, `container` - and `application` on which you can operate. - - Example of using `container` to preload data into the store: - - ```javascript - Ember.Application.initializer({ - name: 'preload-data', - - initialize: function(container, application) { - var store = container.lookup('store:main'); - - store.pushPayload(preloadedData); - } - }); - ``` - - Example of using `application` to register an adapter: - - ```javascript - Ember.Application.initializer({ - name: 'api-adapter', - - initialize: function(container, application) { - application.register('api-adapter:main', ApiAdapter); - } - }); - ``` - - @method initializer - @param initializer {Object} - */ - initializer: function(initializer) { - // If this is the first initializer being added to a subclass, we are going to reopen the class - // to make sure we have a new `initializers` object, which extends from the parent class' using - // prototypal inheritance. Without this, attempting to add initializers to the subclass would - // pollute the parent class as well as other subclasses. - if (this.superclass.initializers !== undefined && this.superclass.initializers === this.initializers) { - this.reopenClass({ - initializers: create(this.initializers) - }); - } - - - this.initializers[initializer.name] = initializer; - }, - - /** - This creates a container with the default Ember naming conventions. - - It also configures the container: - - * registered views are created every time they are looked up (they are - not singletons) - * registered templates are not factories; the registered value is - returned directly. - * the router receives the application as its `namespace` property - * all controllers receive the router as their `target` and `controllers` - properties - * all controllers receive the application as their `namespace` property - * the application view receives the application controller as its - `controller` property - * the application view receives the application template as its - `defaultTemplate` property - - @private - @method buildContainer - @static - @param {Ember.Application} namespace the application to build the - container for. - @return {Ember.Container} the built container - */ - buildContainer: function(namespace) { - var container = new Container(); - - container.set = set; - container.resolver = resolverFor(namespace); - container.normalizeFullName = container.resolver.normalize; - container.describe = container.resolver.describe; - container.makeToString = container.resolver.makeToString; - - container.optionsForType('component', { singleton: false }); - container.optionsForType('view', { singleton: false }); - container.optionsForType('template', { instantiate: false }); - container.optionsForType('helper', { instantiate: false }); - - container.register('application:main', namespace, { instantiate: false }); - - container.register('controller:basic', Controller, { instantiate: false }); - container.register('controller:object', ObjectController, { instantiate: false }); - container.register('controller:array', ArrayController, { instantiate: false }); - - container.register('view:select', SelectView); - - container.register('route:basic', Route, { instantiate: false }); - container.register('event_dispatcher:main', EventDispatcher); - - container.register('router:main', Router); - container.injection('router:main', 'namespace', 'application:main'); - - container.register('location:auto', AutoLocation); - container.register('location:hash', HashLocation); - container.register('location:history', HistoryLocation); - container.register('location:none', NoneLocation); - - container.injection('controller', 'target', 'router:main'); - container.injection('controller', 'namespace', 'application:main'); - - container.register('-bucket-cache:main', BucketCache); - container.injection('router', '_bucketCache', '-bucket-cache:main'); - container.injection('route', '_bucketCache', '-bucket-cache:main'); - container.injection('controller', '_bucketCache', '-bucket-cache:main'); - - container.injection('route', 'router', 'router:main'); - container.injection('location', 'rootURL', '-location-setting:root-url'); - - // DEBUGGING - container.register('resolver-for-debugging:main', container.resolver.__resolver__, { instantiate: false }); - container.injection('container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main'); - container.injection('data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main'); - // Custom resolver authors may want to register their own ContainerDebugAdapter with this key - - container.register('container-debug-adapter:main', ContainerDebugAdapter); - - return container; - } - }); - - /** - This function defines the default lookup rules for container lookups: - - * templates are looked up on `Ember.TEMPLATES` - * other names are looked up on the application after classifying the name. - For example, `controller:post` looks up `App.PostController` by default. - * if the default lookup fails, look for registered classes on the container - - This allows the application to register default injections in the container - that could be overridden by the normal naming convention. - - @private - @method resolverFor - @param {Ember.Namespace} namespace the namespace to look for classes - @return {*} the resolved value for a given lookup - */ - function resolverFor(namespace) { - if (namespace.get('resolver')) { - } - - var ResolverClass = namespace.get('resolver') || namespace.get('Resolver') || DefaultResolver; - var resolver = ResolverClass.create({ - namespace: namespace - }); - - function resolve(fullName) { - return resolver.resolve(fullName); - } - - resolve.describe = function(fullName) { - return resolver.lookupDescription(fullName); - }; - - resolve.makeToString = function(factory, fullName) { - return resolver.makeToString(factory, fullName); - }; - - resolve.normalize = function(fullName) { - if (resolver.normalize) { - return resolver.normalize(fullName); - } else { - return fullName; - } - }; - - resolve.__resolver__ = resolver; - - return resolve; - } - - __exports__["default"] = Application; - }); -enifed("ember-application/system/resolver", - ["ember-metal/core","ember-metal/property_get","ember-metal/logger","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/system/namespace","ember-handlebars","ember-metal/dictionary","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-application - */ - - var Ember = __dependency1__["default"]; - // Ember.TEMPLATES, Ember.assert - var get = __dependency2__.get; - var Logger = __dependency3__["default"]; - var classify = __dependency4__.classify; - var capitalize = __dependency4__.capitalize; - var decamelize = __dependency4__.decamelize; - var EmberObject = __dependency5__["default"]; - var Namespace = __dependency6__["default"]; - var EmberHandlebars = __dependency7__["default"]; - - var Resolver = EmberObject.extend({ - /** - This will be set to the Application instance when it is - created. - - @property namespace - */ - namespace: null, - normalize: Ember.required(Function), - resolve: Ember.required(Function), - parseName: Ember.required(Function), - lookupDescription: Ember.required(Function), - makeToString: Ember.required(Function), - resolveOther: Ember.required(Function), - _logLookup: Ember.required(Function) - }); - __exports__.Resolver = Resolver; - /** - The DefaultResolver defines the default lookup rules to resolve - container lookups before consulting the container for registered - items: - - * templates are looked up on `Ember.TEMPLATES` - * other names are looked up on the application after converting - the name. For example, `controller:post` looks up - `App.PostController` by default. - * there are some nuances (see examples below) - - ### How Resolving Works - - The container calls this object's `resolve` method with the - `fullName` argument. - - It first parses the fullName into an object using `parseName`. - - Then it checks for the presence of a type-specific instance - method of the form `resolve[Type]` and calls it if it exists. - For example if it was resolving 'template:post', it would call - the `resolveTemplate` method. - - Its last resort is to call the `resolveOther` method. - - The methods of this object are designed to be easy to override - in a subclass. For example, you could enhance how a template - is resolved like so: - - ```javascript - App = Ember.Application.create({ - Resolver: Ember.DefaultResolver.extend({ - resolveTemplate: function(parsedName) { - var resolvedTemplate = this._super(parsedName); - if (resolvedTemplate) { return resolvedTemplate; } - return Ember.TEMPLATES['not_found']; - } - }) - }); - ``` - - Some examples of how names are resolved: - - ``` - 'template:post' //=> Ember.TEMPLATES['post'] - 'template:posts/byline' //=> Ember.TEMPLATES['posts/byline'] - 'template:posts.byline' //=> Ember.TEMPLATES['posts/byline'] - 'template:blogPost' //=> Ember.TEMPLATES['blogPost'] - // OR - // Ember.TEMPLATES['blog_post'] - 'controller:post' //=> App.PostController - 'controller:posts.index' //=> App.PostsIndexController - 'controller:blog/post' //=> Blog.PostController - 'controller:basic' //=> Ember.Controller - 'route:post' //=> App.PostRoute - 'route:posts.index' //=> App.PostsIndexRoute - 'route:blog/post' //=> Blog.PostRoute - 'route:basic' //=> Ember.Route - 'view:post' //=> App.PostView - 'view:posts.index' //=> App.PostsIndexView - 'view:blog/post' //=> Blog.PostView - 'view:basic' //=> Ember.View - 'foo:post' //=> App.PostFoo - 'model:post' //=> App.Post - ``` - - @class DefaultResolver - @namespace Ember - @extends Ember.Object - */ - var dictionary = __dependency8__["default"]; - - __exports__["default"] = EmberObject.extend({ - /** - This will be set to the Application instance when it is - created. - - @property namespace - */ - namespace: null, - - init: function() { - this._parseNameCache = dictionary(null); - }, - normalize: function(fullName) { - var split = fullName.split(':', 2); - var type = split[0]; - var name = split[1]; - - - if (type !== 'template') { - var result = name; - - if (result.indexOf('.') > -1) { - result = result.replace(/\.(.)/g, function(m) { - return m.charAt(1).toUpperCase(); - }); - } - - if (name.indexOf('_') > -1) { - result = result.replace(/_(.)/g, function(m) { - return m.charAt(1).toUpperCase(); - }); - } - - return type + ':' + result; - } else { - return fullName; - } - }, - - - /** - This method is called via the container's resolver method. - It parses the provided `fullName` and then looks up and - returns the appropriate template or class. - - @method resolve - @param {String} fullName the lookup string - @return {Object} the resolved factory - */ - resolve: function(fullName) { - var parsedName = this.parseName(fullName); - var resolveMethodName = parsedName.resolveMethodName; - var resolved; - - if (!(parsedName.name && parsedName.type)) { - throw new TypeError('Invalid fullName: `' + fullName + '`, must be of the form `type:name` '); - } - - if (this[resolveMethodName]) { - resolved = this[resolveMethodName](parsedName); - } - - if (!resolved) { - resolved = this.resolveOther(parsedName); - } - - if (parsedName.root && parsedName.root.LOG_RESOLVER) { - this._logLookup(resolved, parsedName); - } - - return resolved; - }, - /** - Convert the string name of the form 'type:name' to - a Javascript object with the parsed aspects of the name - broken out. - - @protected - @param {String} fullName the lookup string - @method parseName - */ - - parseName: function(fullName) { - return this._parseNameCache[fullName] || ( - this._parseNameCache[fullName] = this._parseName(fullName) - ); - }, - - _parseName: function(fullName) { - var nameParts = fullName.split(':'); - var type = nameParts[0], fullNameWithoutType = nameParts[1]; - var name = fullNameWithoutType; - var namespace = get(this, 'namespace'); - var root = namespace; - - if (type !== 'template' && name.indexOf('/') !== -1) { - var parts = name.split('/'); - name = parts[parts.length - 1]; - var namespaceName = capitalize(parts.slice(0, -1).join('.')); - root = Namespace.byName(namespaceName); - - } - - return { - fullName: fullName, - type: type, - fullNameWithoutType: fullNameWithoutType, - name: name, - root: root, - resolveMethodName: 'resolve' + classify(type) - }; - }, - - /** - Returns a human-readable description for a fullName. Used by the - Application namespace in assertions to describe the - precise name of the class that Ember is looking for, rather than - container keys. - - @protected - @param {String} fullName the lookup string - @method lookupDescription - */ - lookupDescription: function(fullName) { - var parsedName = this.parseName(fullName); - - if (parsedName.type === 'template') { - return 'template at ' + parsedName.fullNameWithoutType.replace(/\./g, '/'); - } - - var description = parsedName.root + '.' + classify(parsedName.name); - - if (parsedName.type !== 'model') { - description += classify(parsedName.type); - } - - return description; - }, - - makeToString: function(factory, fullName) { - return factory.toString(); - }, - /** - Given a parseName object (output from `parseName`), apply - the conventions expected by `Ember.Router` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method useRouterNaming - */ - useRouterNaming: function(parsedName) { - parsedName.name = parsedName.name.replace(/\./g, '_'); - if (parsedName.name === 'basic') { - parsedName.name = ''; - } - }, - /** - Look up the template in Ember.TEMPLATES - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveTemplate - */ - resolveTemplate: function(parsedName) { - var templateName = parsedName.fullNameWithoutType.replace(/\./g, '/'); - - if (Ember.TEMPLATES[templateName]) { - return Ember.TEMPLATES[templateName]; - } - - templateName = decamelize(templateName); - if (Ember.TEMPLATES[templateName]) { - return Ember.TEMPLATES[templateName]; - } - }, - - /** - Lookup the view using `resolveOther` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveView - */ - resolveView: function(parsedName) { - this.useRouterNaming(parsedName); - return this.resolveOther(parsedName); - }, - - /** - Lookup the controller using `resolveOther` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveController - */ - resolveController: function(parsedName) { - this.useRouterNaming(parsedName); - return this.resolveOther(parsedName); - }, - /** - Lookup the route using `resolveOther` - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveRoute - */ - resolveRoute: function(parsedName) { - this.useRouterNaming(parsedName); - return this.resolveOther(parsedName); - }, - - /** - Lookup the model on the Application namespace - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveModel - */ - resolveModel: function(parsedName) { - var className = classify(parsedName.name); - var factory = get(parsedName.root, className); - - if (factory) { return factory; } - }, - /** - Look up the specified object (from parsedName) on the appropriate - namespace (usually on the Application) - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveHelper - */ - resolveHelper: function(parsedName) { - return this.resolveOther(parsedName) || EmberHandlebars.helpers[parsedName.fullNameWithoutType]; - }, - /** - Look up the specified object (from parsedName) on the appropriate - namespace (usually on the Application) - - @protected - @param {Object} parsedName a parseName object with the parsed - fullName lookup string - @method resolveOther - */ - resolveOther: function(parsedName) { - var className = classify(parsedName.name) + classify(parsedName.type); - var factory = get(parsedName.root, className); - if (factory) { return factory; } - }, - - /** - @method _logLookup - @param {Boolean} found - @param {Object} parsedName - @private - */ - _logLookup: function(found, parsedName) { - var symbol, padding; - - if (found) { symbol = '[✓]'; } - else { symbol = '[ ]'; } - - if (parsedName.fullName.length > 60) { - padding = '.'; - } else { - padding = new Array(60 - parsedName.fullName.length).join('.'); - } - - Logger.info(symbol, parsedName.fullName, padding, this.lookupDescription(parsedName.fullName)); - } - }); - }); -enifed("ember-extension-support", - ["ember-metal/core","ember-extension-support/data_adapter","ember-extension-support/container_debug_adapter"], - function(__dependency1__, __dependency2__, __dependency3__) { - "use strict"; - /** - Ember Extension Support - - @module ember - @submodule ember-extension-support - @requires ember-application - */ - - var Ember = __dependency1__["default"]; - var DataAdapter = __dependency2__["default"]; - var ContainerDebugAdapter = __dependency3__["default"]; - - Ember.DataAdapter = DataAdapter; - Ember.ContainerDebugAdapter = ContainerDebugAdapter; - }); -enifed("ember-extension-support/container_debug_adapter", - ["ember-metal/core","ember-runtime/system/native_array","ember-metal/utils","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var emberA = __dependency2__.A; - var typeOf = __dependency3__.typeOf; - var dasherize = __dependency4__.dasherize; - var classify = __dependency4__.classify; - var Namespace = __dependency5__["default"]; - var EmberObject = __dependency6__["default"]; - - /** - @module ember - @submodule ember-extension-support - */ - - /** - The `ContainerDebugAdapter` helps the container and resolver interface - with tools that debug Ember such as the - [Ember Extension](https://github.com/tildeio/ember-extension) - for Chrome and Firefox. - - This class can be extended by a custom resolver implementer - to override some of the methods with library-specific code. - - The methods likely to be overridden are: - - * `canCatalogEntriesByType` - * `catalogEntriesByType` - - The adapter will need to be registered - in the application's container as `container-debug-adapter:main` - - Example: - - ```javascript - Application.initializer({ - name: "containerDebugAdapter", - - initialize: function(container, application) { - application.register('container-debug-adapter:main', require('app/container-debug-adapter')); - } - }); - ``` - - @class ContainerDebugAdapter - @namespace Ember - @extends EmberObject - @since 1.5.0 - */ - __exports__["default"] = EmberObject.extend({ - /** - The container of the application being debugged. - This property will be injected - on creation. - - @property container - @default null - */ - container: null, - - /** - The resolver instance of the application - being debugged. This property will be injected - on creation. - - @property resolver - @default null - */ - resolver: null, - - /** - Returns true if it is possible to catalog a list of available - classes in the resolver for a given type. - - @method canCatalogEntriesByType - @param {String} type The type. e.g. "model", "controller", "route" - @return {boolean} whether a list is available for this type. - */ - canCatalogEntriesByType: function(type) { - if (type === 'model' || type === 'template') return false; - return true; - }, - - /** - Returns the available classes a given type. - - @method catalogEntriesByType - @param {String} type The type. e.g. "model", "controller", "route" - @return {Array} An array of strings. - */ - catalogEntriesByType: function(type) { - var namespaces = emberA(Namespace.NAMESPACES), types = emberA(); - var typeSuffixRegex = new RegExp(classify(type) + "$"); - - namespaces.forEach(function(namespace) { - if (namespace !== Ember) { - for (var key in namespace) { - if (!namespace.hasOwnProperty(key)) { continue; } - if (typeSuffixRegex.test(key)) { - var klass = namespace[key]; - if (typeOf(klass) === 'class') { - types.push(dasherize(key.replace(typeSuffixRegex, ''))); - } - } - } - } - }); - return types; - } - }); - }); -enifed("ember-extension-support/data_adapter", - ["ember-metal/core","ember-metal/property_get","ember-metal/run_loop","ember-runtime/system/string","ember-runtime/system/namespace","ember-runtime/system/object","ember-runtime/system/native_array","ember-application/system/application","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - var get = __dependency2__.get; - var run = __dependency3__["default"]; - var dasherize = __dependency4__.dasherize; - var Namespace = __dependency5__["default"]; - var EmberObject = __dependency6__["default"]; - var emberA = __dependency7__.A; - var Application = __dependency8__["default"]; - - /** - @module ember - @submodule ember-extension-support - */ - - /** - The `DataAdapter` helps a data persistence library - interface with tools that debug Ember such - as the [Ember Extension](https://github.com/tildeio/ember-extension) - for Chrome and Firefox. - - This class will be extended by a persistence library - which will override some of the methods with - library-specific code. - - The methods likely to be overridden are: - - * `getFilters` - * `detect` - * `columnsForType` - * `getRecords` - * `getRecordColumnValues` - * `getRecordKeywords` - * `getRecordFilterValues` - * `getRecordColor` - * `observeRecord` - - The adapter will need to be registered - in the application's container as `dataAdapter:main` - - Example: - - ```javascript - Application.initializer({ - name: "data-adapter", - - initialize: function(container, application) { - application.register('data-adapter:main', DS.DataAdapter); - } - }); - ``` - - @class DataAdapter - @namespace Ember - @extends EmberObject - */ - __exports__["default"] = EmberObject.extend({ - init: function() { - this._super(); - this.releaseMethods = emberA(); - }, - - /** - The container of the application being debugged. - This property will be injected - on creation. - - @property container - @default null - @since 1.3.0 - */ - container: null, - - - /** - The container-debug-adapter which is used - to list all models. - - @property containerDebugAdapter - @default undefined - @since 1.5.0 - **/ - containerDebugAdapter: undefined, - - /** - Number of attributes to send - as columns. (Enough to make the record - identifiable). - - @private - @property attributeLimit - @default 3 - @since 1.3.0 - */ - attributeLimit: 3, - - /** - Stores all methods that clear observers. - These methods will be called on destruction. - - @private - @property releaseMethods - @since 1.3.0 - */ - releaseMethods: emberA(), - - /** - Specifies how records can be filtered. - Records returned will need to have a `filterValues` - property with a key for every name in the returned array. - - @public - @method getFilters - @return {Array} List of objects defining filters. - The object should have a `name` and `desc` property. - */ - getFilters: function() { - return emberA(); - }, - - /** - Fetch the model types and observe them for changes. - - @public - @method watchModelTypes - - @param {Function} typesAdded Callback to call to add types. - Takes an array of objects containing wrapped types (returned from `wrapModelType`). - - @param {Function} typesUpdated Callback to call when a type has changed. - Takes an array of objects containing wrapped types. - - @return {Function} Method to call to remove all observers - */ - watchModelTypes: function(typesAdded, typesUpdated) { - var modelTypes = this.getModelTypes(); - var self = this; - var releaseMethods = emberA(); - var typesToSend; - - typesToSend = modelTypes.map(function(type) { - var klass = type.klass; - var wrapped = self.wrapModelType(klass, type.name); - releaseMethods.push(self.observeModelType(klass, typesUpdated)); - return wrapped; - }); - - typesAdded(typesToSend); - - var release = function() { - releaseMethods.forEach(function(fn) { fn(); }); - self.releaseMethods.removeObject(release); - }; - this.releaseMethods.pushObject(release); - return release; - }, - - _nameToClass: function(type) { - if (typeof type === 'string') { - type = this.container.lookupFactory('model:' + type); - } - return type; - }, - - /** - Fetch the records of a given type and observe them for changes. - - @public - @method watchRecords - - @param {Function} recordsAdded Callback to call to add records. - Takes an array of objects containing wrapped records. - The object should have the following properties: - columnValues: {Object} key and value of a table cell - object: {Object} the actual record object - - @param {Function} recordsUpdated Callback to call when a record has changed. - Takes an array of objects containing wrapped records. - - @param {Function} recordsRemoved Callback to call when a record has removed. - Takes the following parameters: - index: the array index where the records were removed - count: the number of records removed - - @return {Function} Method to call to remove all observers - */ - watchRecords: function(type, recordsAdded, recordsUpdated, recordsRemoved) { - var self = this, releaseMethods = emberA(), records = this.getRecords(type), release; - - var recordUpdated = function(updatedRecord) { - recordsUpdated([updatedRecord]); - }; - - var recordsToSend = records.map(function(record) { - releaseMethods.push(self.observeRecord(record, recordUpdated)); - return self.wrapRecord(record); - }); - - - var contentDidChange = function(array, idx, removedCount, addedCount) { - for (var i = idx; i < idx + addedCount; i++) { - var record = array.objectAt(i); - var wrapped = self.wrapRecord(record); - releaseMethods.push(self.observeRecord(record, recordUpdated)); - recordsAdded([wrapped]); - } - - if (removedCount) { - recordsRemoved(idx, removedCount); - } - }; - - var observer = { didChange: contentDidChange, willChange: Ember.K }; - records.addArrayObserver(self, observer); - - release = function() { - releaseMethods.forEach(function(fn) { fn(); }); - records.removeArrayObserver(self, observer); - self.releaseMethods.removeObject(release); - }; - - recordsAdded(recordsToSend); - - this.releaseMethods.pushObject(release); - return release; - }, - - /** - Clear all observers before destruction - @private - @method willDestroy - */ - willDestroy: function() { - this._super(); - this.releaseMethods.forEach(function(fn) { - fn(); - }); - }, - - /** - Detect whether a class is a model. - - Test that against the model class - of your persistence library - - @private - @method detect - @param {Class} klass The class to test - @return boolean Whether the class is a model class or not - */ - detect: function(klass) { - return false; - }, - - /** - Get the columns for a given model type. - - @private - @method columnsForType - @param {Class} type The model type - @return {Array} An array of columns of the following format: - name: {String} name of the column - desc: {String} Humanized description (what would show in a table column name) - */ - columnsForType: function(type) { - return emberA(); - }, - - /** - Adds observers to a model type class. - - @private - @method observeModelType - @param {Class} type The model type class - @param {Function} typesUpdated Called when a type is modified. - @return {Function} The function to call to remove observers - */ - - observeModelType: function(type, typesUpdated) { - var self = this; - var records = this.getRecords(type); - - var onChange = function() { - typesUpdated([self.wrapModelType(type)]); - }; - var observer = { - didChange: function() { - run.scheduleOnce('actions', this, onChange); - }, - willChange: Ember.K - }; - - records.addArrayObserver(this, observer); - - var release = function() { - records.removeArrayObserver(self, observer); - }; - - return release; - }, - - - /** - Wraps a given model type and observes changes to it. - - @private - @method wrapModelType - @param {Class} type A model class - @param {String} Optional name of the class - @return {Object} contains the wrapped type and the function to remove observers - Format: - type: {Object} the wrapped type - The wrapped type has the following format: - name: {String} name of the type - count: {Integer} number of records available - columns: {Columns} array of columns to describe the record - object: {Class} the actual Model type class - release: {Function} The function to remove observers - */ - wrapModelType: function(type, name) { - var records = this.getRecords(type); - var typeToSend; - - typeToSend = { - name: name || type.toString(), - count: get(records, 'length'), - columns: this.columnsForType(type), - object: type - }; - - - return typeToSend; - }, - - - /** - Fetches all models defined in the application. - - @private - @method getModelTypes - @return {Array} Array of model types - */ - getModelTypes: function() { - var self = this; - var containerDebugAdapter = this.get('containerDebugAdapter'); - var types; - - if (containerDebugAdapter.canCatalogEntriesByType('model')) { - types = containerDebugAdapter.catalogEntriesByType('model'); - } else { - types = this._getObjectsOnNamespaces(); - } - - // New adapters return strings instead of classes - types = emberA(types).map(function(name) { - return { - klass: self._nameToClass(name), - name: name - }; - }); - types = emberA(types).filter(function(type) { - return self.detect(type.klass); - }); - - return emberA(types); - }, - - /** - Loops over all namespaces and all objects - attached to them - - @private - @method _getObjectsOnNamespaces - @return {Array} Array of model type strings - */ - _getObjectsOnNamespaces: function() { - var namespaces = emberA(Namespace.NAMESPACES); - var types = emberA(); - var self = this; - - namespaces.forEach(function(namespace) { - for (var key in namespace) { - if (!namespace.hasOwnProperty(key)) { continue; } - // Even though we will filter again in `getModelTypes`, - // we should not call `lookupContainer` on non-models - // (especially when `Ember.MODEL_FACTORY_INJECTIONS` is `true`) - if (!self.detect(namespace[key])) { continue; } - var name = dasherize(key); - if (!(namespace instanceof Application) && namespace.toString()) { - name = namespace + '/' + name; - } - types.push(name); - } - }); - return types; - }, - - /** - Fetches all loaded records for a given type. - - @private - @method getRecords - @return {Array} An array of records. - This array will be observed for changes, - so it should update when new records are added/removed. - */ - getRecords: function(type) { - return emberA(); - }, - - /** - Wraps a record and observers changes to it. - - @private - @method wrapRecord - @param {Object} record The record instance. - @return {Object} The wrapped record. Format: - columnValues: {Array} - searchKeywords: {Array} - */ - wrapRecord: function(record) { - var recordToSend = { object: record }; - - recordToSend.columnValues = this.getRecordColumnValues(record); - recordToSend.searchKeywords = this.getRecordKeywords(record); - recordToSend.filterValues = this.getRecordFilterValues(record); - recordToSend.color = this.getRecordColor(record); - - return recordToSend; - }, - - /** - Gets the values for each column. - - @private - @method getRecordColumnValues - @return {Object} Keys should match column names defined - by the model type. - */ - getRecordColumnValues: function(record) { - return {}; - }, - - /** - Returns keywords to match when searching records. - - @private - @method getRecordKeywords - @return {Array} Relevant keywords for search. - */ - getRecordKeywords: function(record) { - return emberA(); - }, - - /** - Returns the values of filters defined by `getFilters`. - - @private - @method getRecordFilterValues - @param {Object} record The record instance - @return {Object} The filter values - */ - getRecordFilterValues: function(record) { - return {}; - }, - - /** - Each record can have a color that represents its state. - - @private - @method getRecordColor - @param {Object} record The record instance - @return {String} The record's color - Possible options: black, red, blue, green - */ - getRecordColor: function(record) { - return null; - }, - - /** - Observes all relevant properties and re-sends the wrapped record - when a change occurs. - - @private - @method observerRecord - @param {Object} record The record instance - @param {Function} recordUpdated The callback to call when a record is updated. - @return {Function} The function to call to remove all observers. - */ - observeRecord: function(record, recordUpdated) { - return function(){}; - } - }); - }); -enifed("ember-extension-support/initializers", - [], - function() { - "use strict"; - - }); -enifed("ember-handlebars-compiler", - ["ember-metal/core","exports"], - function(__dependency1__, __exports__) { - /* global Handlebars:true */ - - // Remove "use strict"; from transpiled module (in browser builds only) until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - /** - @module ember - @submodule ember-handlebars-compiler - */ - - var Ember = __dependency1__["default"]; - - // ES6Todo: you'll need to import debugger once debugger is es6'd. - if (typeof Ember.assert === 'undefined') { Ember.assert = function(){}; } - if (typeof Ember.FEATURES === 'undefined') { Ember.FEATURES = { isEnabled: function(){} }; } - - var objectCreate = Object.create || function(parent) { - function F() {} - F.prototype = parent; - return new F(); - }; - - // set up for circular references later - var View, Component; - - // ES6Todo: when ember-debug is es6'ed import this. - // var emberAssert = Ember.assert; - var Handlebars = (Ember.imports && Ember.imports.Handlebars) || (this && this.Handlebars); - if (!Handlebars && typeof eriuqer === 'function') { - Handlebars = eriuqer('handlebars'); - } - - - - /** - Prepares the Handlebars templating library for use inside Ember's view - system. - - The `Ember.Handlebars` object is the standard Handlebars library, extended to - use Ember's `get()` method instead of direct property access, which allows - computed properties to be used inside templates. - - To create an `Ember.Handlebars` template, call `Ember.Handlebars.compile()`. - This will return a function that can be used by `Ember.View` for rendering. - - @class Handlebars - @namespace Ember - */ - var EmberHandlebars = Ember.Handlebars = Handlebars.create(); - - /** - Register a bound helper or custom view helper. - - ## Simple bound helper example - - ```javascript - Ember.Handlebars.helper('capitalize', function(value) { - return value.toUpperCase(); - }); - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{capitalize name}} - ``` - - 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`. - - ## 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: - - ```javascript - Ember.Handlebars.helper('calendar', App.CalendarView): - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{calendar}} - ``` - - Which is functionally equivalent to: - - ```handlebars - {{view 'calendar'}} - ``` - - Options in the helper will be passed to the view in exactly the same - manner as with the `view` helper. - - @method helper - @for Ember.Handlebars - @param {String} name - @param {Function|Ember.View} function or view class constructor - @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 - - - 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) { - 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); - } - - 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__) { - "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 - */ - - // 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; - - - // 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; - - // 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); - - // run load hooks - runLoadHooks('Ember.Handlebars', EmberHandlebars); - - __exports__["default"] = EmberHandlebars; - }); -enifed("ember-handlebars/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-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__) { - "use strict"; - var Checkbox = __dependency1__["default"]; - var TextField = __dependency2__["default"]; - var TextArea = __dependency3__["default"]; - - var Ember = __dependency4__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var EmberHandlebars = __dependency5__["default"]; - - /** - @module ember - @submodule ember-handlebars-compiler - */ - - /** - - The `{{input}}` helper inserts an HTML `` tag into the template, - with a `type` value of either `text` or `checkbox`. If no `type` is provided, - `text` will be the default value applied. The attributes of `{{input}}` - match those of the native HTML tag as closely as possible for these two types. - - ## Use as text field - An `{{input}}` with no `type` or a `type` of `text` will render an HTML text input. - The following HTML attributes can be set via the helper: - -
    - - - - - - - - - - -
    `readonly``required``autofocus`
    `value``placeholder``disabled`
    `size``tabindex``maxlength`
    `name``min``max`
    `pattern``accept``autocomplete`
    `autosave``formaction``formenctype`
    `formmethod``formnovalidate``formtarget`
    `height``inputmode``multiple`
    `step``width``form`
    `selectionDirection``spellcheck` 
    - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input value="http://www.facebook.com"}} - ``` - - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - firstName: "Stanley", - entryNotAllowed: true - }); - ``` - - - ```handlebars - {{input type="text" value=firstName disabled=entryNotAllowed size="50"}} - ``` - - - ```html - - ``` - - ## Actions - - The helper can send multiple actions based on user events. - - 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` - * `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 - {{input focus-in="alertMessage"}} - ``` - - - See more about [Text Support Actions](/api/classes/Ember.TextField.html) - - ## Extension - - Internally, `{{input type="text"}}` creates an instance of `Ember.TextField`, passing - arguments from the helper to `Ember.TextField`'s `create` method. You can extend the - capabilities of text inputs in your applications by reopening this class. For example, - if you are building a Bootstrap project where `data-*` attributes are used, you - can add one to the `TextField`'s `attributeBindings` property: - - - ```javascript - Ember.TextField.reopen({ - attributeBindings: ['data-error'] - }); - ``` - - Keep in mind when writing `Ember.TextField` subclasses that `Ember.TextField` - 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) - - - ## Use as checkbox - - An `{{input}}` with a `type` of `checkbox` will render an HTML checkbox input. - The following HTML attributes can be set via the helper: - - * `checked` - * `disabled` - * `tabindex` - * `indeterminate` - * `name` - * `autofocus` - * `form` - - - When set to a quoted string, these values will be directly applied to the HTML - element. When left unquoted, these values will be bound to a property on the - template's current rendering context (most typically a controller instance). - - ## Unbound: - - ```handlebars - {{input type="checkbox" name="isAdmin"}} - ``` - - ```html - - ``` - - ## Bound: - - ```javascript - App.ApplicationController = Ember.Controller.extend({ - isAdmin: true - }); - ``` - - - ```handlebars - {{input type="checkbox" checked=isAdmin }} - ``` - - - ```html - - ``` - - ## Extension - - Internally, `{{input type="checkbox"}}` creates an instance of `Ember.Checkbox`, passing - arguments from the helper to `Ember.Checkbox`'s `create` method. You can extend the - capablilties of checkbox inputs in your applications by reopening this class. For example, - if you wanted to add a css class to all checkboxes in your application: - - - ```javascript - Ember.Checkbox.reopen({ - classNames: ['my-app-checkbox'] - }); - ``` - - - @method input - @for Ember.Handlebars.helpers - @param {Hash} options - */ - function inputHelper(options) { - - 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; - } - - if (inputType === 'checkbox') { - delete hash.type; - delete types.type; - - - return EmberHandlebars.helpers.view.call(this, Checkbox, options); - } else { - delete hash.on; - - hash.onEvent = onEvent || 'enter'; - return EmberHandlebars.helpers.view.call(this, TextField, options); - } - } - - __exports__.inputHelper = inputHelper;/** - `{{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(options) { - - return EmberHandlebars.helpers.view.call(this, TextArea, options); - } - - __exports__.textareaHelper = textareaHelper; - }); -enifed("ember-handlebars/controls/checkbox", - ["ember-metal/property_get","ember-metal/property_set","ember-views/views/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var get = __dependency1__.get; - var set = __dependency2__.set; - var View = __dependency3__["default"]; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `checkbox`. - - See [handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Direct manipulation of `checked` - - The `checked` attribute of an `Ember.Checkbox` object should always be set - through the Ember object or by interacting with its rendered element - representation via the mouse, keyboard, or touch. Updating the value of the - checkbox via jQuery will result in the checked value of the object and its - element losing synchronization. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class Checkbox - @namespace Ember - @extends Ember.View - */ - __exports__["default"] = View.extend({ - instrumentDisplay: '{{input type="checkbox"}}', - - classNames: ['ember-checkbox'], - - tagName: 'input', - - attributeBindings: [ - 'type', - 'checked', - 'indeterminate', - 'disabled', - 'tabindex', - 'name', - 'autofocus', - 'required', - 'form' - ], - - type: 'checkbox', - checked: false, - disabled: false, - indeterminate: false, - - init: function() { - this._super(); - this.on('change', this, this._updateElementValue); - }, - - didInsertElement: function() { - this._super(); - get(this, 'element').indeterminate = !!get(this, 'indeterminate'); - }, - - _updateElementValue: function() { - set(this, 'checked', this.$().prop('checked')); - } - }); - }); -enifed("ember-handlebars/controls/select", - ["ember-handlebars-compiler","ember-metal/enumerable_utils","ember-metal/property_get","ember-metal/property_set","ember-views/views/view","ember-views/views/collection_view","ember-metal/utils","ember-metal/is_none","ember-metal/computed","ember-runtime/system/native_array","ember-metal/mixin","ember-metal/properties","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - - var forEach = __dependency2__.forEach; - var indexOf = __dependency2__.indexOf; - var indexesOf = __dependency2__.indexesOf; - var replace = __dependency2__.replace; - - var get = __dependency3__.get; - var set = __dependency4__.set; - var View = __dependency5__["default"]; - var CollectionView = __dependency6__["default"]; - var isArray = __dependency7__.isArray; - var isNone = __dependency8__["default"]; - var computed = __dependency9__.computed; - var emberA = __dependency10__.A; - var observer = __dependency11__.observer; - var defineProperty = __dependency12__.defineProperty; - - - var SelectOption = View.extend({ - instrumentDisplay: 'Ember.SelectOption', - - tagName: 'option', - attributeBindings: ['value', 'selected'], - - defaultTemplate: function(context, options) { - options = { data: options.data, hash: {} }; - EmberHandlebars.helpers.bind.call(context, "view.label", options); - }, - - init: function() { - this.labelPathDidChange(); - this.valuePathDidChange(); - - this._super(); - }, - - selected: computed(function() { - var content = get(this, 'content'); - var selection = get(this, 'parentView.selection'); - if (get(this, 'parentView.multiple')) { - return selection && indexOf(selection, content.valueOf()) > -1; - } else { - // Primitives get passed through bindings as objects... since - // `new Number(4) !== 4`, we use `==` below - return content == selection; // jshint ignore:line - } - }).property('content', 'parentView.selection'), - - labelPathDidChange: observer('parentView.optionLabelPath', function() { - var labelPath = get(this, 'parentView.optionLabelPath'); - - if (!labelPath) { return; } - - defineProperty(this, 'label', computed(function() { - return get(this, labelPath); - }).property(labelPath)); - }), - - valuePathDidChange: observer('parentView.optionValuePath', function() { - var valuePath = get(this, 'parentView.optionValuePath'); - - if (!valuePath) { return; } - - defineProperty(this, 'value', computed(function() { - return get(this, valuePath); - }).property(valuePath)); - }) - }); - - var SelectOptgroup = CollectionView.extend({ - instrumentDisplay: 'Ember.SelectOptgroup', - - tagName: 'optgroup', - attributeBindings: ['label'], - - selectionBinding: 'parentView.selection', - multipleBinding: 'parentView.multiple', - optionLabelPathBinding: 'parentView.optionLabelPath', - optionValuePathBinding: 'parentView.optionValuePath', - - itemViewClassBinding: 'parentView.optionView' - }); - - /** - The `Ember.Select` view class renders a - [select](https://developer.mozilla.org/en/HTML/Element/select) HTML element, - allowing the user to choose from a list of options. - - The text and `value` property of each ` - - - ``` - - The `value` attribute of the selected `"); - return buffer; - },"3":function(depth0,helpers,partials,data) { - var stack1; - stack1 = helpers.each.call(depth0, "group", "in", "view.groupedContent", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(4, data),"inverse":this.noop,"types":["ID","ID","ID"],"contexts":[depth0,depth0,depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - },"4":function(depth0,helpers,partials,data) { - var escapeExpression=this.escapeExpression; - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.groupView", {"name":"view","hash":{ - 'label': ("group.label"), - 'content': ("group.content") - },"hashTypes":{'label': "ID",'content': "ID"},"hashContexts":{'label': depth0,'content': depth0},"types":["ID"],"contexts":[depth0],"data":data}))); - },"6":function(depth0,helpers,partials,data) { - var stack1; - stack1 = helpers.each.call(depth0, "item", "in", "view.content", {"name":"each","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(7, data),"inverse":this.noop,"types":["ID","ID","ID"],"contexts":[depth0,depth0,depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - else { data.buffer.push(''); } - },"7":function(depth0,helpers,partials,data) { - var escapeExpression=this.escapeExpression; - data.buffer.push(escapeExpression(helpers.view.call(depth0, "view.optionView", {"name":"view","hash":{ - 'content': ("item") - },"hashTypes":{'content': "ID"},"hashContexts":{'content': depth0},"types":["ID"],"contexts":[depth0],"data":data}))); - },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var stack1, buffer = ''; - stack1 = helpers['if'].call(depth0, "view.prompt", {"name":"if","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(1, data),"inverse":this.noop,"types":["ID"],"contexts":[depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - stack1 = helpers['if'].call(depth0, "view.optionGroupPath", {"name":"if","hash":{},"hashTypes":{},"hashContexts":{},"fn":this.program(3, data),"inverse":this.program(6, data),"types":["ID"],"contexts":[depth0],"data":data}); - if (stack1 != null) { data.buffer.push(stack1); } - return buffer; - },"useData":true}), - attributeBindings: ['multiple', 'disabled', 'tabindex', 'name', 'required', 'autofocus', - 'form', 'size'], - - /** - The `multiple` attribute of the select element. Indicates whether multiple - options can be selected. - - @property multiple - @type Boolean - @default false - */ - multiple: false, - - /** - The `disabled` attribute of the select element. Indicates whether - the element is disabled from interactions. - - @property disabled - @type Boolean - @default false - */ - disabled: false, - - /** - The `required` attribute of the select element. Indicates whether - a selected option is required for form validation. - - @property required - @type Boolean - @default false - @since 1.5.0 - */ - required: false, - - /** - The list of options. - - If `optionLabelPath` and `optionValuePath` are not overridden, this should - be a list of strings, which will serve simultaneously as labels and values. - - Otherwise, this should be a list of objects. For instance: - - ```javascript - var App = Ember.Application.create(); - var App.MySelect = Ember.Select.extend({ - content: Ember.A([ - { id: 1, firstName: 'Yehuda' }, - { id: 2, firstName: 'Tom' } - ]), - optionLabelPath: 'content.firstName', - optionValuePath: 'content.id' - }); - ``` - - @property content - @type Array - @default null - */ - content: null, - - /** - When `multiple` is `false`, the element of `content` that is currently - selected, if any. - - When `multiple` is `true`, an array of such elements. - - @property selection - @type Object or Array - @default null - */ - selection: null, - - /** - In single selection mode (when `multiple` is `false`), value can be used to - get the current selection's value or set the selection by it's value. - - It is not currently supported in multiple selection mode. - - @property value - @type String - @default null - */ - value: computed(function(key, value) { - if (arguments.length === 2) { return value; } - var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); - return valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection'); - }).property('selection'), - - /** - If given, a top-most dummy option will be rendered to serve as a user - prompt. - - @property prompt - @type String - @default null - */ - prompt: null, - - /** - The path of the option labels. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionLabelPath - @type String - @default 'content' - */ - optionLabelPath: 'content', - - /** - The path of the option values. See [content](/api/classes/Ember.Select.html#property_content). - - @property optionValuePath - @type String - @default 'content' - */ - optionValuePath: 'content', - - /** - The path of the option group. - When this property is used, `content` should be sorted by `optionGroupPath`. - - @property optionGroupPath - @type String - @default null - */ - optionGroupPath: null, - - /** - The view class for optgroup. - - @property groupView - @type Ember.View - @default Ember.SelectOptgroup - */ - groupView: SelectOptgroup, - - groupedContent: computed(function() { - var groupPath = get(this, 'optionGroupPath'); - var groupedContent = emberA(); - var content = get(this, 'content') || []; - - forEach(content, function(item) { - var label = get(item, groupPath); - - if (get(groupedContent, 'lastObject.label') !== label) { - groupedContent.pushObject({ - label: label, - content: emberA() - }); - } - - get(groupedContent, 'lastObject.content').push(item); - }); - - return groupedContent; - }).property('optionGroupPath', 'content.@each'), - - /** - The view class for option. - - @property optionView - @type Ember.View - @default Ember.SelectOption - */ - optionView: SelectOption, - - _change: function() { - if (get(this, 'multiple')) { - this._changeMultiple(); - } else { - this._changeSingle(); - } - }, - - selectionDidChange: observer('selection.@each', function() { - var selection = get(this, 'selection'); - if (get(this, 'multiple')) { - if (!isArray(selection)) { - set(this, 'selection', emberA([selection])); - return; - } - this._selectionDidChangeMultiple(); - } else { - this._selectionDidChangeSingle(); - } - }), - - valueDidChange: observer('value', function() { - var content = get(this, 'content'); - var value = get(this, 'value'); - var valuePath = get(this, 'optionValuePath').replace(/^content\.?/, ''); - var selectedValue = (valuePath ? get(this, 'selection.' + valuePath) : get(this, 'selection')); - var selection; - - if (value !== selectedValue) { - selection = content ? content.find(function(obj) { - return value === (valuePath ? get(obj, valuePath) : obj); - }) : null; - - this.set('selection', selection); - } - }), - - - _triggerChange: function() { - var selection = get(this, 'selection'); - var value = get(this, 'value'); - - if (!isNone(selection)) { this.selectionDidChange(); } - if (!isNone(value)) { this.valueDidChange(); } - - this._change(); - }, - - _changeSingle: function() { - var selectedIndex = this.$()[0].selectedIndex; - var content = get(this, 'content'); - var prompt = get(this, 'prompt'); - - if (!content || !get(content, 'length')) { return; } - if (prompt && selectedIndex === 0) { set(this, 'selection', null); return; } - - if (prompt) { selectedIndex -= 1; } - set(this, 'selection', content.objectAt(selectedIndex)); - }, - - - _changeMultiple: function() { - var options = this.$('option:selected'); - var prompt = get(this, 'prompt'); - var offset = prompt ? 1 : 0; - var content = get(this, 'content'); - var selection = get(this, 'selection'); - - if (!content) { return; } - if (options) { - var selectedIndexes = options.map(function() { - return this.index - offset; - }).toArray(); - var newSelection = content.objectsAt(selectedIndexes); - - if (isArray(selection)) { - replace(selection, 0, get(selection, 'length'), newSelection); - } else { - set(this, 'selection', newSelection); - } - } - }, - - _selectionDidChangeSingle: function() { - var el = this.get('element'); - if (!el) { return; } - - var content = get(this, 'content'); - var selection = get(this, 'selection'); - var selectionIndex = content ? indexOf(content, selection) : -1; - var prompt = get(this, 'prompt'); - - if (prompt) { selectionIndex += 1; } - if (el) { el.selectedIndex = selectionIndex; } - }, - - _selectionDidChangeMultiple: function() { - var content = get(this, 'content'); - var selection = get(this, 'selection'); - var selectedIndexes = content ? indexesOf(content, selection) : [-1]; - var prompt = get(this, 'prompt'); - var offset = prompt ? 1 : 0; - var options = this.$('option'); - var adjusted; - - if (options) { - options.each(function() { - adjusted = this.index > -1 ? this.index - offset : -1; - this.selected = indexOf(selectedIndexes, adjusted) > -1; - }); - } - }, - - init: function() { - this._super(); - this.on("didInsertElement", this, this._triggerChange); - this.on("change", this, this._change); - } - }); - - __exports__["default"] = Select; - __exports__.Select = Select; - __exports__.SelectOption = SelectOption; - __exports__.SelectOptgroup = SelectOptgroup; - }); -enifed("ember-handlebars/controls/text_area", - ["ember-metal/property_get","ember-views/views/component","ember-handlebars/controls/text_support","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var get = __dependency1__.get; - var Component = __dependency2__["default"]; - var TextSupport = __dependency3__["default"]; - var observer = __dependency4__.observer; - - /** - The internal class used to create textarea element when the `{{textarea}}` - helper is used. - - See [handlebars.helpers.textarea](/api/classes/Ember.Handlebars.helpers.html#method_textarea) for usage details. - - ## Layout and LayoutName properties - - Because HTML `textarea` elements do not contain inner HTML the `layout` and - `layoutName` properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextArea - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - __exports__["default"] = Component.extend(TextSupport, { - instrumentDisplay: '{{textarea}}', - - classNames: ['ember-text-area'], - - tagName: "textarea", - attributeBindings: [ - 'rows', - 'cols', - 'name', - 'selectionEnd', - 'selectionStart', - 'wrap', - 'lang', - 'dir' - ], - rows: null, - cols: null, - - _updateElementValue: observer('value', function() { - // We do this check so cursor position doesn't get affected in IE - var value = get(this, 'value'); - var $el = this.$(); - if ($el && value !== $el.val()) { - $el.val(value); - } - }), - - init: function() { - this._super(); - this.on("didInsertElement", this, this._updateElementValue); - } - }); - }); -enifed("ember-handlebars/controls/text_field", - ["ember-views/views/component","ember-handlebars/controls/text_support","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - var Component = __dependency1__["default"]; - var TextSupport = __dependency2__["default"]; - - /** - - The internal class used to create text inputs when the `{{input}}` - helper is used with `type` of `text`. - - See [Handlebars.helpers.input](/api/classes/Ember.Handlebars.helpers.html#method_input) for usage details. - - ## Layout and LayoutName properties - - Because HTML `input` elements are self closing `layout` and `layoutName` - properties will not be applied. See [Ember.View](/api/classes/Ember.View.html)'s - layout section for more information. - - @class TextField - @namespace Ember - @extends Ember.Component - @uses Ember.TextSupport - */ - __exports__["default"] = Component.extend(TextSupport, { - instrumentDisplay: '{{input type="text"}}', - - classNames: ['ember-text-field'], - tagName: "input", - attributeBindings: [ - 'accept', - 'autocomplete', - 'autosave', - 'dir', - 'formaction', - 'formenctype', - 'formmethod', - 'formnovalidate', - 'formtarget', - 'height', - 'inputmode', - 'lang', - 'list', - 'max', - 'min', - 'multiple', - 'name', - 'pattern', - 'size', - 'step', - 'type', - 'value', - 'width' - ], - - /** - The `value` attribute of the input element. As the user inputs text, this - property is updated live. - - @property value - @type String - @default "" - */ - value: "", - - /** - The `type` attribute of the input element. - - @property type - @type String - @default "text" - */ - type: "text", - - /** - The `size` of the text field in characters. - - @property size - @type String - @default null - */ - size: null, - - /** - The `pattern` attribute of input element. - - @property pattern - @type String - @default null - */ - pattern: null, - - /** - The `min` attribute of input element used with `type="number"` or `type="range"`. - - @property min - @type String - @default null - @since 1.4.0 - */ - min: null, - - /** - The `max` attribute of input element used with `type="number"` or `type="range"`. - - @property max - @type String - @default null - @since 1.4.0 - */ - max: null - }); - }); -enifed("ember-handlebars/controls/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-handlebars - */ - - var get = __dependency1__.get; - var set = __dependency2__.set; - var Mixin = __dependency3__.Mixin; - var TargetActionSupport = __dependency4__["default"]; - - /** - Shared mixin used by `Ember.TextField` and `Ember.TextArea`. - - @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()); - }, - - /** - Called when the user inserts a new line. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 13. - Uses sendAction to send the `enter` action. - - @method insertNewline - @param {Event} event - */ - insertNewline: function(event) { - sendAction('enter', this, event); - sendAction('insert-newline', this, event); - }, - - /** - Called when the user hits escape. - - Called by the `Ember.TextSupport` mixin on keyUp if keycode matches 27. - Uses sendAction to send the `escape-press` action. - - @method cancel - @param {Event} event - */ - cancel: function(event) { - sendAction('escape-press', this, event); - }, - - change: function(event) { - this._elementValueDidChange(event); - }, - - /** - Called when the text area is focused. - - Uses sendAction to send the `focus-in` action. - - @method focusIn - @param {Event} event - */ - focusIn: function(event) { - sendAction('focus-in', this, event); - }, - - /** - Called when the text area is blurred. - - Uses sendAction to send the `focus-out` action. - - @method focusOut - @param {Event} event - */ - focusOut: function(event) { - this._elementValueDidChange(event); - sendAction('focus-out', this, event); - }, - - /** - Called when the user presses a key. Enabled by setting - the `onEvent` property to `keyPress`. - - Uses sendAction to send the `key-press` action. - - @method keyPress - @param {Event} event - */ - keyPress: function(event) { - sendAction('key-press', this, event); - }, - - /** - Called when the browser triggers a `keyup` event on the element. - - Uses sendAction to send the `key-up` action passing the current value - and event as parameters. - - @method keyUp - @param {Event} event - */ - keyUp: function(event) { - this.interpretKeyEvents(event); - - this.sendAction('key-up', get(this, 'value'), event); - }, - - /** - Called when the browser triggers a `keydown` event on the element. - - Uses sendAction to send the `key-down` action passing the current value - and event as parameters. Note that generally in key-down the value is unchanged - (as the key pressing has not completed yet). - - @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-handlebars/ext", - ["ember-metal/core","ember-runtime/system/string","ember-handlebars-compiler","ember-metal/property_get","ember-metal/error","ember-metal/mixin","ember-views/views/view","ember-metal/path_cache","ember-metal/streams/stream","ember-metal/streams/read","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.FEATURES, Ember.assert, Ember.Handlebars, Ember.lookup - // var emberAssert = Ember.assert; - - var fmt = __dependency2__.fmt; - - var EmberHandlebars = __dependency3__["default"]; - - var get = __dependency4__.get; - var EmberError = __dependency5__["default"]; - var IS_BINDING = __dependency6__.IS_BINDING; - - var View = __dependency7__["default"]; - var detectIsGlobal = __dependency8__.isGlobal; - - // late bound via requireModule because of circular dependencies. - var resolveHelper, SimpleHandlebarsView; - - var Stream = __dependency9__["default"]; - var readArray = __dependency10__.readArray; - var readHash = __dependency10__.readHash; - - var slice = [].slice; - - /** - Lookup both on root and on window. If the path starts with - a keyword, the corresponding object will be looked up in the - template's data hash and used to resolve the path. - - @method get - @for Ember.Handlebars - @param {Object} root The object to look up the property on - @param {String} path The path to be lookedup - @param {Object} options The template's option hash - @deprecated - */ - function handlebarsGet(root, path, options) { - - return options.data.view.getStream(path).value(); - } - - /** - handlebarsGetView resolves a view based on strings passed into a template. - For example: - - ```handlebars - {{view "some-view"}} - {{view view.someView}} - {{view App.SomeView}} {{! deprecated }} - ``` - - A value is first checked to be a string- non-strings are presumed to be - an object and returned. This handles the "access a view on a context" - case (line 2 in the above examples). - - Next a string is normalized, then called on the context with `get`. If - there is still no value, a GlobalPath will be fetched from the global - context (raising a deprecation) and a localPath will be passed to the - container to be looked up. - - @private - @for Ember.Handlebars - @param {Object} context The context of the template being rendered - @param {String} path The path to be lookedup - @param {Object} container The container - @param {Object} data The template's data hash - */ - function handlebarsGetView(context, path, container, data) { - var viewClass; - if ('string' === typeof path) { - if (!data) { - throw new Error("handlebarsGetView: must pass data"); - } - - // Only lookup view class on context if there is a context. If not, - // the global lookup path on get may kick in. - var lazyValue = data.view.getStream(path); - viewClass = lazyValue.value(); - var isGlobal = detectIsGlobal(path); - - if (!viewClass && !isGlobal) { - viewClass = container.lookupFactory('view:'+path); - } - if (!viewClass && isGlobal) { - var globalViewClass = get(path); - if (globalViewClass) { - viewClass = globalViewClass; - } - } - } else { - viewClass = path; - } - - // Sometimes a view's value is yet another path - if ('string' === typeof viewClass && data && data.view) { - viewClass = handlebarsGetView(data.view, viewClass, container, data); - } - - - return viewClass; - } - - function stringifyValue(value, shouldEscape) { - if (value === null || value === undefined) { - value = ""; - } else if (!(value instanceof Handlebars.SafeString)) { - value = String(value); - } - - if (shouldEscape) { - value = Handlebars.Utils.escapeExpression(value); - } - - return value; - } - - __exports__.stringifyValue = stringifyValue;/** - Registers a helper in Handlebars that will be called if no property with the - given name can be found on the current context object, and no helper with - that name is registered. - - This throws an exception with a more helpful error message so the user can - track down where the problem is happening. - - @private - @method helperMissing - @for Ember.Handlebars.helpers - @param {String} path - @param {Hash} options - */ - function helperMissingHelper(path) { - if (!resolveHelper) { - resolveHelper = requireModule('ember-handlebars/helpers/binding')['resolveHelper']; - } // ES6TODO: stupid circular dep - - var error, fmtError, view = ""; - - var options = arguments[arguments.length - 1]; - - var helper = resolveHelper(options.data.view.container, options.name); - - if (helper) { - return helper.apply(this, arguments); - } - - if (options.data) { - view = options.data.view; - } - - if (options.name.match(/-/)) { - error = "%@ Handlebars error: Could not find component or helper named '%@'"; - fmtError = fmt(error, [view, options.name]); - } else { - error = "%@ Handlebars error: Could not find property '%@' on object %@."; - fmtError = fmt(error, [view, options.name, this]); - } - - throw new EmberError(fmtError); - } - - __exports__.helperMissingHelper = helperMissingHelper;/** - @private - @method blockHelperMissingHelper - @for Ember.Handlebars.helpers - */ - function blockHelperMissingHelper() { - return; - } - - __exports__.blockHelperMissingHelper = blockHelperMissingHelper;/** - 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 example - - ```javascript - Ember.Handlebars.registerBoundHelper('capitalize', function(value) { - return Ember.String.capitalize(value); - }); - ``` - - The above bound helper can be used inside of templates as follows: - - ```handlebars - {{capitalize name}} - ``` - - 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. - - ## Example with options - - Like normal handlebars helpers, bound helpers have access to the options - passed into the helper call. - - ```javascript - Ember.Handlebars.registerBoundHelper('repeat', function(value, options) { - var count = options.hash.count; - var a = []; - while(a.length < count) { - a.push(value); - } - return a.join(''); - }); - ``` - - This helper could be used in a template as follows: - - ```handlebars - {{repeat text count=3}} - ``` - - ## Example with bound options - - Bound hash options are also supported. Example: - - ```handlebars - {{repeat text count=numRepeats}} - ``` - - 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. - - ## 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} function - @param {String} dependentKeys* - */ - function registerBoundHelper(name, fn) { - var boundHelperArgs = slice.call(arguments, 1); - var boundFn = makeBoundHelper.apply(this, boundHelperArgs); - EmberHandlebars.registerHelper(name, boundFn); - } - - __exports__.registerBoundHelper = registerBoundHelper;/** - A helper function used by `registerBoundHelper`. Takes the - provided Handlebars helper function fn and returns it in wrapped - bound helper form. - - The main use case for using this outside of `registerBoundHelper` - is for registering helpers on the container: - - ```js - var boundHelperFn = Ember.Handlebars.makeBoundHelper(function(word) { - return word.toUpperCase(); - }); - - container.register('helper:my-bound-helper', boundHelperFn); - ``` - - In the above example, if the helper function hadn't been wrapped in - `makeBoundHelper`, the registered helper would be unbound. - - @method makeBoundHelper - @for Ember.Handlebars - @param {Function} function - @param {String} dependentKeys* - @since 1.2.0 - */ - function makeBoundHelper(fn) { - if (!SimpleHandlebarsView) { - SimpleHandlebarsView = requireModule('ember-handlebars/views/handlebars_bound_view')['SimpleHandlebarsView']; - } // ES6TODO: stupid circular dep - - var dependentKeys = []; - for (var i = 1; i < arguments.length; i++) { - dependentKeys.push(arguments[i]); - } - - function helper() { - var numParams = arguments.length - 1; - var options = arguments[numParams]; - var data = options.data; - var view = data.view; - var types = options.types; - var hash = options.hash; - var hashTypes = options.hashTypes; - var context = this; - - - var properties = new Array(numParams); - var params = new Array(numParams); - - for (var i = 0; i < numParams; i++) { - properties[i] = arguments[i]; - if (types[i] === 'ID') { - params[i] = view.getStream(arguments[i]); - } else { - params[i] = arguments[i]; - } - } - - for (var prop in hash) { - if (IS_BINDING.test(prop)) { - hash[prop.slice(0, -7)] = view.getStream(hash[prop]); - hash[prop] = undefined; - } else if (hashTypes[prop] === 'ID') { - hash[prop] = view.getStream(hash[prop]); - } - } - - var valueFn = function() { - var args = readArray(params); - args.push({ - hash: readHash(hash), - data: { properties: properties } - }); - return fn.apply(context, args); - }; - - if (data.isUnbound) { - return valueFn(); - } else { - var lazyValue = new Stream(valueFn); - var bindView = new SimpleHandlebarsView(lazyValue, !options.hash.unescaped); - view.appendChild(bindView); - - var scheduledRerender = view._wrapAsScheduled(bindView.rerender); - lazyValue.subscribe(scheduledRerender, bindView); - - var param; - - for (i = 0; i < numParams; i++) { - param = params[i]; - if (param && param.isStream) { - param.subscribe(lazyValue.notify, lazyValue); - } - } - - for (prop in hash) { - param = hash[prop]; - if (param && param.isStream) { - param.subscribe(lazyValue.notify, lazyValue); - } - } - - if (numParams > 0) { - var firstParam = params[0]; - // Only bother with subscriptions if the first argument - // is a stream itself, and not a primitive. - if (firstParam && firstParam.isStream) { - 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 helper; - } - - __exports__.makeBoundHelper = makeBoundHelper; - __exports__.handlebarsGetView = handlebarsGetView; - __exports__.handlebarsGet = handlebarsGet; - }); -enifed("ember-handlebars/helpers/bind_attr", - ["ember-metal/core","ember-handlebars-compiler","ember-metal/utils","ember-runtime/system/string","ember-metal/array","ember-views/views/view","ember-metal/keys","ember-views/system/sanitize_attribute_value","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var EmberHandlebars = __dependency2__["default"]; - - var uuid = __dependency3__.uuid; - var fmt = __dependency4__.fmt; - var typeOf = __dependency3__.typeOf; - var forEach = __dependency5__.forEach; - var View = __dependency6__["default"]; - var keys = __dependency7__["default"]; - - var sanitizeAttributeValue = __dependency8__["default"]; - - var helpers = EmberHandlebars.helpers; - var SafeString = EmberHandlebars.SafeString; - - /** - `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 - - ``` - - 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(options) { - var attrs = options.hash; - - - var view = options.data.view; - var ret = []; - - // we relied on the behavior of calling without - // context to mean this === window, but when running - // "use strict", it's possible for this to === undefined; - var ctx = this || window; - - // Generate a unique id for this element. This will be added as a - // data attribute to the element so it can be looked up when - // the bound property changes. - var dataId = uuid(); - - // Handle classes differently, as we can bind multiple classes - var classBindings = attrs['class']; - if (classBindings != null) { - var classResults = bindClasses(ctx, classBindings, view, dataId, options); - - ret.push('class="' + Handlebars.Utils.escapeExpression(classResults.join(' ')) + '"'); - delete attrs['class']; - } - - var attrKeys = keys(attrs); - - // For each attribute passed, create an observer and emit the - // current value of the property as an attribute. - forEach.call(attrKeys, function(attr) { - var path = attrs[attr]; - - - var lazyValue = view.getStream(path); - var value = lazyValue.value(); - value = sanitizeAttributeValue(null, attr, value); - var type = typeOf(value); - - - lazyValue.subscribe(view._wrapAsScheduled(function applyAttributeBindings() { - var result = lazyValue.value(); - - - var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']"); - - - View.applyAttributeBindings(elem, attr, result); - })); - - // if this changes, also change the logic in ember-views/lib/views/view.js - if ((type === 'string' || (type === 'number' && !isNaN(value)))) { - ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"'); - } else if (value && type === 'boolean') { - // The developer controls the attr name, so it should always be safe - ret.push(attr + '="' + attr + '"'); - } - }, this); - - // Add the unique identifier - // NOTE: We use all lower-case since Firefox has problems with mixed case in SVG - ret.push('data-bindattr-' + dataId + '="' + dataId + '"'); - return new SafeString(ret.join(' ')); - } - - /** - See `bind-attr` - - @method bindAttr - @for Ember.Handlebars.helpers - @deprecated - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function bindAttrHelperDeprecated() { - - return helpers['bind-attr'].apply(this, arguments); - } - - /** - Helper that, given a space-separated string of property paths and a context, - returns an array of class names. Calling this method also has the side - effect of setting up observers at those property paths, such that if they - change, the correct class name will be reapplied to the DOM element. - - For example, if you pass the string "fooBar", it will first look up the - "fooBar" value of the context. If that value is true, it will add the - "foo-bar" class to the current element (i.e., the dasherized form of - "fooBar"). If the value is a string, it will add that string as the class. - Otherwise, it will not add any new class name. - - @private - @method bindClasses - @for Ember.Handlebars - @param {Ember.Object} context The context from which to lookup properties - @param {String} classBindings A string, space-separated, of class bindings - to use - @param {View} view The view in which observers should look for the - element to update - @param {Srting} bindAttrId Optional bindAttr id used to lookup elements - @return {Array} An array of class names to add - */ - function bindClasses(context, classBindings, view, bindAttrId, options) { - var ret = []; - var newClass, value, elem; - - // For each property passed, loop through and setup - // an observer. - forEach.call(classBindings.split(' '), function(binding) { - - // 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; - var parsedPath = View._parsePropertyPath(binding); - var path = parsedPath.path; - var initialValue; - - if (path === '') { - initialValue = true; - } else { - var lazyValue = view.getStream(path); - initialValue = lazyValue.value(); - - // Set up an observer on the context. If the property changes, toggle the - // class name. - lazyValue.subscribe(view._wrapAsScheduled(function applyClassNameBindings() { - // Get the current value of the property - var value = lazyValue.value(); - newClass = classStringForParsedPath(parsedPath, value); - elem = bindAttrId ? view.$("[data-bindattr-" + bindAttrId + "='" + bindAttrId + "']") : view.$(); - - - // If we had previously added a class to the element, remove it. - if (oldClass) { - elem.removeClass(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; - } - })); - } - - // We've already setup the observer; now we just need to figure out the - // correct behavior right now on the first pass through. - value = classStringForParsedPath(parsedPath, initialValue); - - if (value) { - ret.push(value); - - // Make sure we save the current value so that it can be removed if the - // observer fires. - oldClass = value; - } - }); - - return ret; - } - - function classStringForParsedPath(parsedPath, value) { - return View._classStringForValue(parsedPath.path, value, parsedPath.className, parsedPath.falsyClassName); - } - - __exports__["default"] = bindAttrHelper; - - __exports__.bindAttrHelper = bindAttrHelper; - __exports__.bindAttrHelperDeprecated = bindAttrHelperDeprecated; - __exports__.bindClasses = bindClasses; - }); -enifed("ember-handlebars/helpers/binding", - ["ember-metal/core","ember-handlebars-compiler","ember-metal/is_none","ember-metal/run_loop","ember-metal/cache","ember-metal/streams/simple","ember-handlebars/views/handlebars_bound_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var EmberHandlebars = __dependency2__["default"]; - - var isNone = __dependency3__["default"]; - var run = __dependency4__["default"]; - var Cache = __dependency5__["default"]; - var SimpleStream = __dependency6__["default"]; - - var _HandlebarsBoundView = __dependency7__._HandlebarsBoundView; - var SimpleHandlebarsView = __dependency7__.SimpleHandlebarsView; - - var helpers = EmberHandlebars.helpers; - - function exists(value) { - return !isNone(value); - } - - // Binds a property into the DOM. This will create a hook in DOM that the - // KVO system will look for and update if the property changes. - function bind(property, options, preserveContext, shouldDisplay, valueNormalizer, childProperties, _viewClass) { - var data = options.data; - var view = data.view; - - // we relied on the behavior of calling without - // context to mean this === window, but when running - // "use strict", it's possible for this to === undefined; - var currentContext = this || window; - - var valueStream = view.getStream(property); - var lazyValue; - - if (childProperties) { - lazyValue = new SimpleStream(valueStream); - - var subscriber = function(childStream) { - childStream.value(); - lazyValue.notify(); - }; - - for (var i = 0; i < childProperties.length; i++) { - var childStream = valueStream.get(childProperties[i]); - childStream.value(); - childStream.subscribe(subscriber); - } - } else { - lazyValue = valueStream; - } - - // Set up observers for observable objects - var viewClass = _viewClass || _HandlebarsBoundView; - var viewOptions = { - preserveContext: preserveContext, - shouldDisplayFunc: shouldDisplay, - valueNormalizerFunc: valueNormalizer, - displayTemplate: options.fn, - inverseTemplate: options.inverse, - lazyValue: lazyValue, - previousContext: currentContext, - isEscaped: !options.hash.unescaped, - templateData: options.data, - templateHash: options.hash, - helperName: options.helperName - }; - - if (options.keywords) { - viewOptions._keywords = options.keywords; - } - - // Create the view that will wrap the output of this template/property - // and add it to the nearest view's childViews array. - // See the documentation of Ember._HandlebarsBoundView for more. - var bindView = view.createChildView(viewClass, viewOptions); - - view.appendChild(bindView); - - lazyValue.subscribe(view._wrapAsScheduled(function() { - run.scheduleOnce('render', bindView, 'rerenderIfNeeded'); - })); - } - - function simpleBind(currentContext, lazyValue, options) { - var data = options.data; - var view = data.view; - - var bindView = new SimpleHandlebarsView( - lazyValue, !options.hash.unescaped - ); - - bindView._parentView = view; - view.appendChild(bindView); - - lazyValue.subscribe(view._wrapAsScheduled(function() { - run.scheduleOnce('render', bindView, 'rerender'); - })); - } - - /** - '_triageMustache' is used internally select between a binding, helper, or component for - the given context. Until this point, it would be hard to determine if the - mustache is a property reference or a regular helper reference. This triage - helper resolves that. - - This would not be typically invoked by directly. - - @private - @method _triageMustache - @for Ember.Handlebars.helpers - @param {String} property Property/helperID to triage - @param {Object} options hash of template/rendering options - @return {String} HTML string - */ - function _triageMustacheHelper(property, options) { - - var helper = EmberHandlebars.resolveHelper(options.data.view.container, property); - if (helper) { - return helper.call(this, options); - } - - return helpers.bind.call(this, property, options); - } - - 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} - */ - function resolveHelper(container, name) { - if (helpers[name]) { - return helpers[name]; - } - - if (!container || ISNT_HELPER_CACHE.get(name)) { - return; - } - - var helper = container.lookup('helper:' + name); - if (!helper) { - var componentLookup = container.lookup('component-lookup:main'); - - var Component = componentLookup.lookupFactory(name, container); - if (Component) { - helper = EmberHandlebars.makeViewHelper(Component); - container.register('helper:' + name, helper); - } - } - return helper; - } - - - /** - `bind` can be used to display a value, then update that value if it - changes. For example, if you wanted to print the `title` property of - `content`: - - ```handlebars - {{bind "content.title"}} - ``` - - This will return the `title` property as a string, then create a new observer - at the specified path. If it changes, it will update the value in DOM. Note - that if you need to support IE7 and IE8 you must modify the model objects - properties using `Ember.get()` and `Ember.set()` for this to work as it - relies on Ember's KVO system. For all other browsers this will be handled for - you automatically. - - @private - @method bind - @for Ember.Handlebars.helpers - @param {String} property Property to bind - @param {Function} fn Context to provide for rendering - @return {String} HTML string - */ - function bindHelper(property, options) { - - var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; - - if (!options.fn) { - var lazyValue = options.data.view.getStream(property); - return simpleBind(context, lazyValue, options); - } - - options.helperName = 'bind'; - - return bind.call(context, property, options, false, exists); - } - - __exports__.bind = bind; - __exports__._triageMustacheHelper = _triageMustacheHelper; - __exports__.resolveHelper = resolveHelper; - __exports__.bindHelper = bindHelper; - }); -enifed("ember-handlebars/helpers/collection", - ["ember-metal/core","ember-handlebars-compiler","ember-metal/mixin","ember-runtime/system/string","ember-metal/property_get","ember-metal/streams/simple","ember-handlebars/ext","ember-handlebars/helpers/view","ember-views/views/view","ember-views/views/collection_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert, Ember.deprecate - - // var emberAssert = Ember.assert; - // emberDeprecate = Ember.deprecate; - - var EmberHandlebars = __dependency2__["default"]; - - var IS_BINDING = __dependency3__.IS_BINDING; - var fmt = __dependency4__.fmt; - var get = __dependency5__.get; - var SimpleStream = __dependency6__["default"]; - var handlebarsGetView = __dependency7__.handlebarsGetView; - var ViewHelper = __dependency8__.ViewHelper; - var View = __dependency9__["default"]; - var CollectionView = __dependency10__["default"]; - - /** - `{{collection}}` is a `Ember.Handlebars` helper for adding instances of - `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html) - for additional information on how a `CollectionView` functions. - - `{{collection}}`'s primary use is as a block helper with a `contentBinding` - option pointing towards an `Ember.Array`-compatible object. An `Ember.View` - instance will be created for each item in its `content` property. Each view - will have its own `content` property set to the appropriate item in the - collection. - - The provided block will be applied as the template for each item's view. - - Given an empty `` 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(path, options) { - - // If no path is provided, treat path param as options. - if (path && path.data && path.data.isRenderData) { - options = path; - path = undefined; - } else { - } - - var fn = options.fn, - data = options.data, - inverse = options.inverse, - view = options.data.view, - // This should be deterministic, and should probably come from a - // parent view and not the controller. - container = (view.controller && view.controller.container ? view.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 = handlebarsGetView(this, path, container, options.data); - } - else { - collectionClass = CollectionView; - } - - var hash = options.hash; - var hashTypes = options.hashTypes; - 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 = hash.itemView; - } else if (hash.itemViewClass) { - if (hashTypes.itemViewClass === 'ID') { - var itemViewClassStream = view.getStream(hash.itemViewClass); - itemViewClass = itemViewClassStream.value(); - } else { - itemViewClass = hash.itemViewClass; - } - } else { - itemViewClass = collectionPrototype.itemViewClass; - } - - if (typeof itemViewClass === 'string') { - itemViewClass = container.lookupFactory('view:'+itemViewClass); - } - - - delete hash.itemViewClass; - delete hash.itemView; - delete hashTypes.itemViewClass; - delete hashTypes.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 (hashTypes[prop] === 'ID' || IS_BINDING.test(prop)) { - itemHash[childProp] = view._getBindingForStream(hash[prop]); - } else { - itemHash[childProp] = hash[prop]; - } - delete hash[prop]; - } - } - } - - if (fn) { - itemHash.template = fn; - delete options.fn; - } - - var emptyViewClass; - if (inverse && inverse !== EmberHandlebars.VM.noop) { - emptyViewClass = get(collectionPrototype, 'emptyViewClass'); - emptyViewClass = emptyViewClass.extend({ - template: inverse, - tagName: itemHash.tagName - }); - } else if (hash.emptyViewClass) { - emptyViewClass = handlebarsGetView(this, hash.emptyViewClass, container, options.data); - } - if (emptyViewClass) { hash.emptyView = emptyViewClass; } - - if (hash.keyword) { - itemHash._contextBinding = '_parentView.context'; - } else { - itemHash._contextBinding = 'content'; - } - - var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this); - - if (hash.itemClassBinding) { - var itemClassBindings = hash.itemClassBinding.split(' '); - - for (var i = 0; i < itemClassBindings.length; i++) { - var parsedPath = View._parsePropertyPath(itemClassBindings[i]); - if (parsedPath.path === '') { - parsedPath.stream = new SimpleStream(true); - } else { - parsedPath.stream = view.getStream(parsedPath.path); - } - itemClassBindings[i] = parsedPath; - } - - viewOptions.classNameBindings = itemClassBindings; - } - - hash.itemViewClass = itemViewClass; - hash._itemViewProps = viewOptions; - - options.helperName = options.helperName || 'collection'; - - return EmberHandlebars.helpers.view.call(this, collectionClass, options); - } - - __exports__["default"] = collectionHelper; - }); -enifed("ember-handlebars/helpers/debug", - ["ember-metal/core","ember-metal/utils","ember-metal/logger","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - /*jshint debug:true*/ - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.FEATURES, - var inspect = __dependency2__.inspect; - var Logger = __dependency3__["default"]; - - var a_slice = [].slice; - - /** - `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() { - var params = a_slice.call(arguments, 0, -1); - var options = arguments[arguments.length - 1]; - var view = options.data.view; - var logger = Logger.log; - var values = []; - - for (var i = 0; i < params.length; i++) { - if (options.types[i] === 'ID') { - var stream = view.getStream(params[i]); - values.push(stream.value()); - } else { - values.push(params[i]); - } - } - - logger.apply(logger, values); - } - - /** - Execute the `debugger` statement in the current context. - - ```handlebars - {{debugger}} - ``` - - 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: - - - templateContext: this is most likely a controller - from which this template looks up / displays properties - - typeOfTemplateContext: a string description of - what the templateContext is - - 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(options) { - - // These are helpful values you can inspect while debugging. - /* jshint unused: false */ - var templateContext = this; - var typeOfTemplateContext = inspect(templateContext); - - debugger; - } - - __exports__.logHelper = logHelper; - __exports__.debuggerHelper = debuggerHelper; - }); -enifed("ember-handlebars/helpers/each", - ["ember-metal/core","ember-handlebars-compiler","ember-runtime/system/string","ember-metal/property_get","ember-metal/property_set","ember-views/views/collection_view","ember-metal/binding","ember-runtime/mixins/controller","ember-runtime/controllers/array_controller","ember-runtime/mixins/array","ember-metal/observer","ember-handlebars/views/metamorph_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __exports__) { - "use strict"; - - /** - @module ember - @submodule ember-handlebars - */ - var Ember = __dependency1__["default"]; - // Ember.assert;, Ember.K - - var EmberHandlebars = __dependency2__["default"]; - - var fmt = __dependency3__.fmt; - var get = __dependency4__.get; - var set = __dependency5__.set; - var CollectionView = __dependency6__["default"]; - var Binding = __dependency7__.Binding; - var ControllerMixin = __dependency8__["default"]; - var ArrayController = __dependency9__["default"]; - var EmberArray = __dependency10__["default"]; - - var addObserver = __dependency11__.addObserver; - var removeObserver = __dependency11__.removeObserver; - var addBeforeObserver = __dependency11__.addBeforeObserver; - var removeBeforeObserver = __dependency11__.removeBeforeObserver; - - var _MetamorphView = __dependency12__["default"]; - var _Metamorph = __dependency12__._Metamorph; - - var EachView = CollectionView.extend(_Metamorph, { - - init: function() { - var itemController = get(this, 'itemController'); - var binding; - - if (itemController) { - var controller = get(this, 'controller.container').lookupFactory('controller:array').create({ - _isVirtual: true, - parentController: get(this, 'controller'), - itemController: itemController, - target: get(this, 'controller'), - _eachView: this - }); - - this.disableContentObservers(function() { - set(this, 'content', controller); - binding = new Binding('content', '_eachView.dataSource').oneWay(); - binding.connect(controller); - }); - - set(this, '_arrayController', controller); - } else { - this.disableContentObservers(function() { - binding = new Binding('content', 'dataSource').oneWay(); - binding.connect(this); - }); - } - - return this._super(); - }, - - _assertArrayLike: function(content) { - }, - - disableContentObservers: function(callback) { - removeBeforeObserver(this, 'content', null, '_contentWillChange'); - removeObserver(this, 'content', null, '_contentDidChange'); - - callback.call(this); - - addBeforeObserver(this, 'content', null, '_contentWillChange'); - addObserver(this, 'content', null, '_contentDidChange'); - }, - - itemViewClass: _MetamorphView, - emptyViewClass: _MetamorphView, - - createChildView: function(view, attrs) { - view = this._super(view, attrs); - - var content = get(view, 'content'); - var keyword = get(this, 'keyword'); - - if (keyword) { - view._keywords[keyword] = content; - } - - // If {{#each}} is looping over an array of controllers, - // point each child view at their respective controller. - if (content && content.isController) { - set(view, 'controller', content); - } - - return view; - }, - - destroy: function() { - if (!this._super()) { return; } - - var arrayController = get(this, '_arrayController'); - - if (arrayController) { - arrayController.destroy(); - } - - return this; - } - }); - - /** - 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(path) { - var options = arguments[arguments.length - 1]; - var helperName = 'each'; - var keywordName; - - if (arguments.length === 4) { - - keywordName = arguments[0]; - path = arguments[2]; - - helperName += ' ' + keywordName + ' in ' + path; - - options.hash.keyword = keywordName; - } else if (arguments.length === 1) { - path = ''; - } else { - helperName += ' ' + path; - } - - - options.hash.emptyViewClass = Ember._MetamorphView; - options.hash.dataSourceBinding = path; - options.hashTypes.dataSourceBinding = 'STRING'; - options.helperName = options.helperName || helperName; - - return EmberHandlebars.helpers.collection.call(this, EmberHandlebars.EachView, options); - } - - __exports__.EachView = EachView; - __exports__.eachHelper = eachHelper; - }); -enifed("ember-handlebars/helpers/if_unless", - ["ember-metal/core","ember-handlebars-compiler","ember-handlebars/helpers/binding","ember-metal/property_get","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var EmberHandlebars = __dependency2__["default"]; - - var bind = __dependency3__.bind; - - var get = __dependency4__.get; - var isArray = __dependency5__.isArray; - - var helpers = EmberHandlebars.helpers; - - 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; - } - } - - /** - 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(property, fn) { - var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this; - - fn.helperName = fn.helperName || 'boundIf'; - - return bind.call(context, property, fn, 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(property, fn) { - var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this; - var data = fn.data; - var view = data.view; - var template = fn.fn; - var inverse = fn.inverse; - - var propertyValue = view.getStream(property).value(); - - if (!shouldDisplayIfHelperContent(propertyValue)) { - template = inverse; - } - - template(context, { data: data }); - } - - /** - 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(context, options) { - - options.helperName = options.helperName || ('if ' + context); - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - /** - @method unless - @for Ember.Handlebars.helpers - @param {Function} context - @param {Hash} options - @return {String} HTML string - */ - function unlessHelper(context, options) { - - var fn = options.fn; - var inverse = options.inverse; - var helperName = 'unless'; - - if (context) { - helperName += ' ' + context; - } - - options.fn = inverse; - options.inverse = fn; - - options.helperName = options.helperName || helperName; - - if (options.data.isUnbound) { - return helpers.unboundIf.call(options.contexts[0], context, options); - } else { - return helpers.boundIf.call(options.contexts[0], context, options); - } - } - - __exports__.ifHelper = ifHelper; - __exports__.boundIfHelper = boundIfHelper; - __exports__.unboundIfHelper = unboundIfHelper; - __exports__.unlessHelper = unlessHelper; - }); -enifed("ember-handlebars/helpers/loc", - ["ember-runtime/system/string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - var loc = __dependency1__.loc; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - 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} - */ - __exports__["default"] = loc; - }); -enifed("ember-handlebars/helpers/partial", - ["ember-metal/core","ember-metal/is_none","ember-handlebars/helpers/binding","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - // var emberAssert = Ember.assert; - - var isNone = __dependency2__["default"]; - var bind = __dependency3__.bind; - - /** - @module ember - @submodule ember-handlebars - */ - - /** - 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 - */ - - __exports__["default"] = function partialHelper(name, options) { - var view = options.data.view; - - var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this; - - options.helperName = options.helperName || 'partial'; - - if (options.types[0] === "ID") { - var partialNameStream = view.getStream(name); - // Helper was passed a property path; we need to - // create a binding that will re-render whenever - // this property changes. - options.fn = function(context, fnOptions) { - renderPartial(context, partialNameStream.value(), fnOptions); - }; - - return bind.call(context, name, options, true, exists); - } else { - // Render the partial right into parent template. - renderPartial(context, name, options); - } - } - - function exists(value) { - return !isNone(value); - } - - function renderPartial(context, name, options) { - var nameParts = name.split("/"); - var lastPart = nameParts[nameParts.length - 1]; - - nameParts[nameParts.length - 1] = "_" + lastPart; - - var view = options.data.view; - var underscoredName = nameParts.join("/"); - var template = view.templateForName(underscoredName); - var deprecatedTemplate = !template && view.templateForName(name); - - - template = template || deprecatedTemplate; - - template(context, { - data: options.data - }); - } - }); -enifed("ember-handlebars/helpers/template", - ["ember-metal/core","ember-handlebars-compiler","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.deprecate; - - var EmberHandlebars = __dependency2__["default"]; - /** - @module ember - @submodule ember-handlebars - */ - - /** - @deprecated - @method template - @for Ember.Handlebars.helpers - @param {String} templateName the template to render - */ - __exports__["default"] = function templateHelper(name, options) { - - options.helperName = options.helperName || 'template'; - - return EmberHandlebars.helpers.partial.apply(this, arguments); - } - }); -enifed("ember-handlebars/helpers/unbound", - ["ember-handlebars-compiler","ember-handlebars/helpers/binding","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - - var resolveHelper = __dependency2__.resolveHelper; - - /** - `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 - */ - __exports__["default"] = function unboundHelper(property) { - var argsLength = arguments.length; - var options = arguments[argsLength - 1]; - var view = options.data.view; - var container = view.container; - - if (argsLength <= 2) { - return view.getStream(property).value(); - } else { - options.data.isUnbound = true; - options.types.shift(); - - var args = new Array(argsLength - 1); - for (var i = 1; i < argsLength; i++) { - args[i - 1] = arguments[i]; - } - - var helper = resolveHelper(container, property) || EmberHandlebars.helpers.helperMissing; - - // Attempt to exec the first field as a helper - options.name = arguments[0]; - - var result = helper.apply(this, args); - - delete options.data.isUnbound; - return result; - } - } - }); -enifed("ember-handlebars/helpers/view", - ["ember-metal/core","ember-runtime/system/object","ember-metal/property_get","ember-metal/keys","ember-metal/mixin","ember-views/streams/read","ember-views/views/view","ember-metal/streams/simple","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.warn, Ember.assert - // var emberWarn = Ember.warn, emberAssert = Ember.assert; - - var EmberObject = __dependency2__["default"]; - var get = __dependency3__.get; - var keys = __dependency4__["default"]; - var IS_BINDING = __dependency5__.IS_BINDING; - var readViewFactory = __dependency6__.readViewFactory; - var View = __dependency7__["default"]; - var SimpleStream = __dependency8__["default"]; - - function makeBindings(options) { - var hash = options.hash; - var hashTypes = options.hashTypes; - var view = options.data.view; - - for (var prop in hash) { - var hashType = hashTypes[prop]; - var value = hash[prop]; - - if (IS_BINDING.test(prop)) { - // classBinding is processed separately - if (prop === 'classBinding') { - continue; - } - - if (hashType === 'ID') { - hash[prop] = view._getBindingForStream(value); - } else if (typeof value === 'string') { - hash[prop] = view._getBindingForStream(value); - } - } else { - if (hashType === 'ID') { - if (prop === 'class') { - hash.classBinding = value; - } else { - hash[prop + 'Binding'] = view._getBindingForStream(value); - } - delete hash[prop]; - delete hashTypes[prop]; - } - } - } - - if (hash.idBinding) { - // id can't be bound, so just perform one-time lookup. - hash.id = hash.idBinding.value(); - hashTypes.id = 'STRING'; - delete hash.idBinding; - delete hashTypes.idBinding; - } - } - - var ViewHelper = EmberObject.create({ - propertiesFromHTMLOptions: function(options) { - var view = options.data.view; - var hash = options.hash; - var classes = hash['class']; - - var extensions = { - helperName: options.helperName || '' - }; - - if (hash.id) { - extensions.elementId = 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) { - 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]; - } - } - - var classNameBindings = extensions.classNameBindings; - if (classNameBindings) { - for (var j = 0; j < classNameBindings.length; j++) { - var parsedPath = View._parsePropertyPath(classNameBindings[j]); - if (parsedPath.path === '') { - parsedPath.stream = new SimpleStream(true); - } else { - parsedPath.stream = view.getStream(parsedPath.path); - } - classNameBindings[j] = parsedPath; - } - } - - return extensions; - }, - - helper: function(thisContext, newView, options) { - var data = options.data; - var fn = options.fn; - var newViewProto; - - makeBindings(options); - - var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); - var currentView = data.view; - viewOptions.templateData = data; - - if (View.detectInstance(newView)) { - newViewProto = newView; - } else { - newViewProto = newView.proto(); - } - - if (fn) { - viewOptions.template = fn; - } - - // 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 = thisContext; - } - - currentView.appendChild(newView, viewOptions); - }, - - instanceHelper: function(thisContext, newView, options) { - var data = options.data; - var fn = options.fn; - - makeBindings(options); - - - var viewOptions = this.propertiesFromHTMLOptions(options, thisContext); - var currentView = data.view; - viewOptions.templateData = data; - - if (fn) { - viewOptions.template = fn; - } - - // 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 = thisContext; - } - - 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(path) { - - var options = arguments[arguments.length - 1]; - var types = options.types; - var view = options.data.view; - var container = view.container || view._keywords.view.value().container; - var viewClass; - - // If no path is provided, treat path param as options - // and get an instance of the registered `view:toplevel` - if (arguments.length === 1) { - if (container) { - viewClass = container.lookupFactory('view:toplevel'); - } else { - viewClass = View; - } - } else { - var pathStream; - if (typeof path === 'string' && types[0] === 'ID') { - pathStream = view.getStream(path); - } else { - pathStream = path; - } - - viewClass = readViewFactory(pathStream, container); - } - - options.helperName = options.helperName || 'view'; - - return ViewHelper.helper(this, viewClass, options); - } - - __exports__.viewHelper = viewHelper; - }); -enifed("ember-handlebars/helpers/with", - ["ember-metal/core","ember-metal/property_set","ember-metal/utils","ember-metal/platform","ember-metal/is_none","ember-handlebars/helpers/binding","ember-handlebars/views/handlebars_bound_view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - - var set = __dependency2__.set; - var apply = __dependency3__.apply; - var o_create = __dependency4__.create; - var isNone = __dependency5__["default"]; - var bind = __dependency6__.bind; - var _HandlebarsBoundView = __dependency7__._HandlebarsBoundView; - - function exists(value) { - return !isNone(value); - } - - var WithView = _HandlebarsBoundView.extend({ - init: function() { - apply(this, this._super, arguments); - - var keywordName = this.templateHash.keywordName; - 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._keywords[keywordName] = 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()); - } - }, - - willDestroy: function() { - this._super(); - - if (this._generatedController) { - this._generatedController.destroy(); - } - } - }); - - /** - 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}} -
  5. {{post.title}}
  6. - {{/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 - */ - __exports__["default"] = function withHelper(contextPath) { - var options = arguments[arguments.length - 1]; - var view = options.data.view; - var bindContext, preserveContext; - var helperName = 'with'; - - if (arguments.length === 4) { - - var keywordName = arguments[2]; - - if (contextPath) { - helperName += ' ' + contextPath + ' as ' + keywordName; - } - - - var localizedOptions = o_create(options); - localizedOptions.data = o_create(options.data); - - localizedOptions.keywords = {}; - localizedOptions.keywords[keywordName] = view.getStream(contextPath); - - localizedOptions.hash.keywordName = keywordName; - - bindContext = this; - options = localizedOptions; - preserveContext = true; - } else { - - - helperName += ' ' + contextPath; - bindContext = options.contexts[0]; - preserveContext = false; - } - - options.helperName = helperName; - - return bind.call(bindContext, contextPath, options, preserveContext, exists, undefined, undefined, WithView); - } - }); -enifed("ember-handlebars/helpers/yield", - ["ember-metal/core","ember-metal/property_get","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-handlebars - */ - - var Ember = __dependency1__["default"]; - // var emberAssert = Ember.assert; - - 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 - */ - __exports__["default"] = function yieldHelper(options) { - var view = options.data.view; - - while (view && !get(view, 'layout')) { - if (view._contextView) { - view = view._contextView; - } else { - view = get(view, '_parentView'); - } - } - - - view._yield(this, options); - } - }); -enifed("ember-handlebars/loader", - ["ember-handlebars/component_lookup","ember-views/system/jquery","ember-metal/error","ember-runtime/system/lazy_load","ember-handlebars-compiler","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - /*globals Handlebars */ - - var ComponentLookup = __dependency1__["default"]; - var jQuery = __dependency2__["default"]; - var EmberError = __dependency3__["default"]; - var onLoad = __dependency4__.onLoad; - - var EmberHandlebars = __dependency5__["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) : - jQuery.proxy(EmberHandlebars.compile, EmberHandlebars); - // 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-handlebars/string", - ["ember-runtime/system/string","exports"], - function(__dependency1__, __exports__) { - "use strict"; - // required so we can extend this object. - var EmberStringUtils = __dependency1__["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 Handlebars.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__["default"] = htmlSafe; - }); -enifed("ember-handlebars/views/handlebars_bound_view", - ["ember-handlebars-compiler","ember-metal/core","ember-metal/error","ember-metal/property_get","ember-metal/property_set","ember-metal/merge","ember-metal/run_loop","ember-handlebars/string","ember-views/views/states","ember-handlebars/views/metamorph_view","ember-metal/utils","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __exports__) { - "use strict"; - /*jshint newcap:false*/ - - - /** - @module ember - @submodule ember-handlebars - */ - - var EmberHandlebars = __dependency1__["default"]; - // EmberHandlebars.SafeString; - - var Ember = __dependency2__["default"]; - // Ember.K - var K = Ember.K; - - var EmberError = __dependency3__["default"]; - var get = __dependency4__.get; - var set = __dependency5__.set; - var merge = __dependency6__["default"]; - var run = __dependency7__["default"]; - var htmlSafe = __dependency8__["default"]; - var cloneStates = __dependency9__.cloneStates; - var viewStates = __dependency9__.states; - - var _MetamorphView = __dependency10__["default"]; - var uuid = __dependency11__.uuid; - - function SimpleHandlebarsView(lazyValue, isEscaped) { - this.lazyValue = lazyValue; - this.isEscaped = isEscaped; - this[Ember.GUID_KEY] = uuid(); - this._lastNormalizedValue = undefined; - this.state = 'preRender'; - this.updateId = null; - this._parentView = null; - this.buffer = null; - this._morph = null; - } - - SimpleHandlebarsView.prototype = { - isVirtual: true, - isView: true, - - destroy: function () { - if (this.updateId) { - run.cancel(this.updateId); - this.updateId = null; - } - if (this._parentView) { - this._parentView.removeChild(this); - } - this.morph = null; - this.state = 'destroyed'; - }, - - propertyWillChange: K, - - propertyDidChange: K, - - normalizedValue: function() { - var result = this.lazyValue.value(); - - if (result === null || result === undefined) { - result = ""; - } else if (!this.isEscaped && !(result instanceof EmberHandlebars.SafeString)) { - result = htmlSafe(result); - } - - return result; - }, - - render: function(buffer) { - var value = this.normalizedValue(); - this._lastNormalizedValue = value; - buffer._element = value; - }, - - rerender: function() { - switch(this.state) { - case 'preRender': - case 'destroyed': - break; - case 'inBuffer': - throw new EmberError("Something you did tried to replace an {{expression}} before it was inserted into the DOM."); - case 'hasElement': - case 'inDOM': - this.updateId = run.scheduleOnce('render', this, 'update'); - break; - } - return this; - }, - - update: function () { - this.updateId = null; - var value = this.normalizedValue(); - // doesn't diff EmberHandlebars.SafeString instances - if (value !== this._lastNormalizedValue) { - this._lastNormalizedValue = value; - this._morph.update(value); - } - }, - - _transitionTo: function(state) { - this.state = state; - } - }; - - var states = cloneStates(viewStates); - - merge(states._default, { - rerenderIfNeeded: K - }); - - merge(states.inDOM, { - rerenderIfNeeded: function(view) { - if (view.normalizedValue() !== view._lastNormalizedValue) { - view.rerender(); - } - } - }); - - /** - `Ember._HandlebarsBoundView` is a private view created by the Handlebars - `{{bind}}` helpers that is used to keep track of bound properties. - - Every time a property is bound using a `{{mustache}}`, an anonymous subclass - of `Ember._HandlebarsBoundView` is created with the appropriate sub-template - and context set up. When the associated property changes, just the template - for this view will re-render. - - @class _HandlebarsBoundView - @namespace Ember - @extends Ember._MetamorphView - @private - */ - var _HandlebarsBoundView = _MetamorphView.extend({ - instrumentName: 'boundHandlebars', - - _states: states, - - /** - The function used to determine if the `displayTemplate` or - `inverseTemplate` should be rendered. This should be a function that takes - a value and returns a Boolean. - - @property shouldDisplayFunc - @type Function - @default null - */ - shouldDisplayFunc: null, - - /** - Whether the template rendered by this view gets passed the context object - of its parent template, or gets passed the value of retrieving `path` - from the `pathRoot`. - - For example, this is true when using the `{{#if}}` helper, because the - template inside the helper should look up properties relative to the same - object as outside the block. This would be `false` when used with `{{#with - foo}}` because the template should receive the object found by evaluating - `foo`. - - @property preserveContext - @type Boolean - @default false - */ - preserveContext: false, - - /** - If `preserveContext` is true, this is the object that will be used - to render the template. - - @property previousContext - @type Object - */ - previousContext: null, - - /** - The template to render when `shouldDisplayFunc` evaluates to `true`. - - @property displayTemplate - @type Function - @default null - */ - displayTemplate: null, - - /** - The template to render when `shouldDisplayFunc` evaluates to `false`. - - @property inverseTemplate - @type Function - @default null - */ - inverseTemplate: null, - - lazyValue: null, - - normalizedValue: function() { - var value = this.lazyValue.value(); - var valueNormalizer = get(this, 'valueNormalizerFunc'); - return valueNormalizer ? valueNormalizer(value) : value; - }, - - rerenderIfNeeded: function() { - this.currentState.rerenderIfNeeded(this); - }, - - /** - Determines which template to invoke, sets up the correct state based on - that logic, then invokes the default `Ember.View` `render` implementation. - - This method will first look up the `path` key on `pathRoot`, - then pass that value to the `shouldDisplayFunc` function. If that returns - `true,` the `displayTemplate` function will be rendered to DOM. Otherwise, - `inverseTemplate`, if specified, will be rendered. - - For example, if this `Ember._HandlebarsBoundView` represented the `{{#with - foo}}` helper, it would look up the `foo` property of its context, and - `shouldDisplayFunc` would always return true. The object found by looking - up `foo` would be passed to `displayTemplate`. - - @method render - @param {Ember.RenderBuffer} buffer - */ - render: function(buffer) { - // If not invoked via a triple-mustache ({{{foo}}}), escape - // the content of the template. - var escape = get(this, 'isEscaped'); - - var shouldDisplay = get(this, 'shouldDisplayFunc'); - var preserveContext = get(this, 'preserveContext'); - var context = get(this, 'previousContext'); - - var inverseTemplate = get(this, 'inverseTemplate'); - var displayTemplate = get(this, 'displayTemplate'); - - var result = this.normalizedValue(); - - this._lastNormalizedValue = result; - - // First, test the conditional to see if we should - // render the template or not. - if (shouldDisplay(result)) { - set(this, 'template', displayTemplate); - - // If we are preserving the context (for example, if this - // is an #if block, call the template with the same object. - if (preserveContext) { - set(this, '_context', context); - } else { - // Otherwise, determine if this is a block bind or not. - // If so, pass the specified object to the template - if (displayTemplate) { - set(this, '_context', result); - } else { - // This is not a bind block, just push the result of the - // expression to the render context and return. - if (result === null || result === undefined) { - result = ""; - } else if (!(result instanceof EmberHandlebars.SafeString)) { - result = String(result); - } - - if (escape) { result = Handlebars.Utils.escapeExpression(result); } - buffer.push(result); - return; - } - } - } else if (inverseTemplate) { - set(this, 'template', inverseTemplate); - - if (preserveContext) { - set(this, '_context', context); - } else { - set(this, '_context', result); - } - } else { - set(this, 'template', function() { return ''; }); - } - - return this._super(buffer); - } - }); - - __exports__._HandlebarsBoundView = _HandlebarsBoundView; - __exports__.SimpleHandlebarsView = SimpleHandlebarsView; - }); -enifed("ember-handlebars/views/metamorph_view", - ["ember-metal/core","ember-views/views/core_view","ember-views/views/view","ember-metal/mixin","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /*jshint newcap:false*/ - var Ember = __dependency1__["default"]; - // Ember.deprecate - - var CoreView = __dependency2__["default"]; - var View = __dependency3__["default"]; - var Mixin = __dependency4__.Mixin; - - /** - @module ember - @submodule ember-handlebars - */ - - // The `morph` and `outerHTML` properties are internal only - // and not observable. - - /** - @class _Metamorph - @namespace Ember - @private - */ - var _Metamorph = Mixin.create({ - isVirtual: true, - tagName: '', - - instrumentName: 'metamorph', - - init: function() { - this._super(); - } - }); - __exports__._Metamorph = _Metamorph; - /** - @class _MetamorphView - @namespace Ember - @extends Ember.View - @uses Ember._Metamorph - @private - */ - __exports__["default"] = View.extend(_Metamorph); - - /** - @class _SimpleMetamorphView - @namespace Ember - @extends Ember.CoreView - @uses Ember._Metamorph - @private - */ - var _SimpleMetamorphView = CoreView.extend(_Metamorph); - __exports__._SimpleMetamorphView = _SimpleMetamorphView; - }); -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"); - } - 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) { - - 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) { - - 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({ - done: Ember.computed.empty('todos') - }); - - var todoList = ToDoList.create({ - todos: ['Unit Test', 'Documentation', 'Release'] - }); - - todoList.get('done'); // false - todoList.get('todos').clear(); - todoList.get('done'); // 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 propogate 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) { - - 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) { - - 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.9.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.9.1' - @static - */ - Ember.VERSION = '1.9.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 `ENV.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: - - * `ENV.ENABLE_ALL_FEATURES` - force all features to be enabled. - * `ENV.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 `ENV.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 = Ember.K; } - if ('undefined' === typeof Ember.warn) { Ember.warn = Ember.K; } - if ('undefined' === typeof Ember.debug) { Ember.debug = Ember.K; } - if ('undefined' === typeof Ember.runInDebug) { Ember.runInDebug = Ember.K; } - if ('undefined' === typeof Ember.deprecate) { Ember.deprecate = Ember.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() { - } - - 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 listenersUnion(obj, eventName, otherActions) { - 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) { - 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); - } - } - } - - __exports__.listenersUnion = listenersUnion;function listenersDiff(obj, eventName, otherActions) { - var meta = obj['__ember_meta__']; - var actions = meta && meta.listeners && meta.listeners[eventName]; - var diffActions = []; - - if (!actions) { return; } - 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) { continue; } - - otherActions.push(target, method, flags); - diffActions.push(target, method, flags); - } - - return diffActions; - } - - __exports__.listenersDiff = listenersDiff;/** - 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) { - - 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) { - - 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 - @param obj - @param {String...|Array} list of keys to get - @return {Hash} - */ - __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/properties","ember-metal/platform","ember-metal/utils","ember-metal/error","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var ComputedProperty = __dependency2__.ComputedProperty; - var Descriptor = __dependency3__.Descriptor; - var create = __dependency4__.create; - var inspect = __dependency5__.inspect; - var EmberError = __dependency6__["default"]; - - /** - 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(function(keyName) { - - return this.container.lookup(type + ':' + (name || keyName)); - }, { readOnly: true }); - } - - InjectedProperty.prototype = create(Descriptor.prototype); - - var InjectedPropertyPrototype = InjectedProperty.prototype; - var ComputedPropertyPrototype = ComputedProperty.prototype; - - InjectedPropertyPrototype._super$Constructor = ComputedProperty; - - InjectedPropertyPrototype.get = ComputedPropertyPrototype.get; - - InjectedPropertyPrototype.set = function(obj, keyName) { - throw new EmberError("Cannot set injected property '" + keyName + "' on object: " + inspect(obj)); - }; - - 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. - - @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) { - - return this["delete"](key); - }, - - /** - Removes a value from the map for an associated key. - - @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","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __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 apply = __dependency7__.apply; - 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 REQUIRED; - var a_slice = [].slice; - - function superFunction(){ - var func = this.__nextSuper; - var ret; - if (func) { - var args = new Array(arguments.length); - for (var i = 0, l = args.length; i < l; i++) { - args[i] = arguments[i]; - } - this.__nextSuper = null; - ret = apply(this, func, args); - this.__nextSuper = func; - } - return ret; - } - - 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]; - - - 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]; - - 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.indexOf(HAS_THIS) !== -1; }); - 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", - ["exports"], - function(__exports__) { - // Remove "use strict"; from transpiled module until - // https://bugs.webkit.org/show_bug.cgi?id=138038 is fixed - // - // REMOVE_USE_STRICT: true - - /** - @class platform - @namespace Ember - @static - */ - - /** - Identical to `Object.create()`. Implements if not available natively. - - @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) { - Object.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; - - // 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) { - }; - } - - __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; - - 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; - - - 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 listenersUnion = __dependency2__.listenersUnion; - var listenersDiff = __dependency2__.listenersDiff; - 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 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') { - value = keyName; - keyName = obj; - obj = null; - } - - - 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); - } - - - 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) { - - currentValue = obj[keyName]; - - // only trigger a change if the value has changed - if (value !== currentValue) { - propertyWillChange(obj, keyName); - - obj[keyName] = value; - - propertyDidChange(obj, keyName); - } - } else { - obj[keyName] = value; - } - } - return value; - }; - - // Currently used only by Ember Data tests - // ES6TODO: Verify still true - if (Ember.config.overrideAccessors) { - Ember.set = set; - Ember.config.overrideAccessors(); - set = Ember.set; - } - - 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 execute 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 {Object} return value from invoking the passed function. Please note, - when called within an existing loop, no return value is possible. - @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 execute 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 execute 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) { - } - } - - /** - 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/read", - ["exports"], - function(__exports__) { - "use strict"; - function read(object) { - if (object && object.isStream) { - return object.value(); - } else { - return object; - } - } - - __exports__.read = read;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;function readHash(object) { - var ret = {}; - for (var key in object) { - ret[key] = read(object[key]); - } - return ret; - } - - __exports__.readHash = readHash; - }); -enifed("ember-metal/streams/simple", - ["ember-metal/merge","ember-metal/streams/stream","ember-metal/platform","ember-metal/streams/read","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; - - function SimpleStream(source) { - this.source = source; - - if (source && source.isStream) { - 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 (source && source.isStream) { - source.setValue(value); - } - }, - - setSource: function(nextSource) { - var prevSource = this.source; - if (nextSource !== prevSource) { - if (prevSource && prevSource.isStream) { - prevSource.unsubscribe(this._didChange, this); - } - - if (nextSource && nextSource.isStream) { - nextSource.subscribe(this._didChange, this); - } - - this.source = nextSource; - this.notify(); - } - }, - - _didChange: function() { - this.notify(); - }, - - destroy: function() { - if (this.source && this.source.isStream) { - this.source.unsubscribe(this._didChange, this); - } - - this.source = undefined; - Stream.prototype.destroy.call(this); - } - }); - - __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; - - var NIL = function NIL(){}; - - function Stream(fn) { - this.valueFn = fn; - this.cache = NIL; - this.subscribers = undefined; - this.children = undefined; - this.destroyed = false; - } - - Stream.prototype = { - isStream: true, - - cache: NIL, - - 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.cache !== NIL) { - return this.cache; - } else { - return this.cache = this.valueFn(); - } - }, - - setValue: function() { - throw new Error("Stream error: setValue not implemented"); - }, - - notify: function() { - this.notifyExcept(); - }, - - notifyExcept: function(callbackToSkip, contextToSkip) { - if (this.cache !== NIL) { - this.cache = NIL; - 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.destroyed) return; - this.destroyed = true; - - var children = this.children; - for (var key in children) { - children[key].destroy(); - } - }, - - 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) { - - this.stream = stream; - this.senderCallback = undefined; - this.senderContext = undefined; - this.senderValue = undefined; - this.destroyed = false; - - 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.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.cache = undefined; - - this.notifyExcept(senderCallback, senderContext); - }, - - destroy: function() { - if (this.destroyed) { - return; - } - - this.destroyed = true; - this.stream.unsubscribe(this._onNotify, this); - } - }); - - __exports__["default"] = StreamBinding; - }); -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 - comparision. - - 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 comparisions 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); - - - /** - 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); - - - 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; - - - 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) { - 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-handlebars", - ["ember-metal/core","ember-handlebars","ember-routing-handlebars/helpers/link_to","ember-routing-handlebars/helpers/outlet","ember-routing-handlebars/helpers/render","ember-routing-handlebars/helpers/action","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { - "use strict"; - /** - Ember Routing Handlebars - - @module ember - @submodule ember-routing-handlebars - @requires ember-views - */ - - var Ember = __dependency1__["default"]; - var EmberHandlebars = __dependency2__["default"]; - - var deprecatedLinkToHelper = __dependency3__.deprecatedLinkToHelper; - var linkToHelper = __dependency3__.linkToHelper; - var LinkView = __dependency3__.LinkView; - var queryParamsHelper = __dependency3__.queryParamsHelper; - - var outletHelper = __dependency4__.outletHelper; - var OutletView = __dependency4__.OutletView; - - var renderHelper = __dependency5__["default"]; - - var ActionHelper = __dependency6__.ActionHelper; - var actionHelper = __dependency6__.actionHelper; - - Ember.LinkView = LinkView; - EmberHandlebars.ActionHelper = ActionHelper; - EmberHandlebars.OutletView = OutletView; - - EmberHandlebars.registerHelper('render', renderHelper); - EmberHandlebars.registerHelper('action', actionHelper); - EmberHandlebars.registerHelper('outlet', outletHelper); - EmberHandlebars.registerHelper('link-to', linkToHelper); - EmberHandlebars.registerHelper('linkTo', deprecatedLinkToHelper); - EmberHandlebars.registerHelper('query-params', queryParamsHelper); - - __exports__["default"] = Ember; - }); -enifed("ember-routing-handlebars/helpers/action", - ["ember-metal/core","ember-metal/array","ember-metal/utils","ember-metal/run_loop","ember-views/streams/read","ember-views/system/utils","ember-views/system/action_manager","ember-handlebars","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Handlebars, uuid, FEATURES, assert, deprecate - var forEach = __dependency2__.forEach; - var uuid = __dependency3__.uuid; - var run = __dependency4__["default"]; - - var readUnwrappedModel = __dependency5__.readUnwrappedModel; - var isSimpleClick = __dependency6__.isSimpleClick; - var ActionManager = __dependency7__["default"]; - var EmberHandlebars = __dependency8__["default"]; - - /** - @module ember - @submodule ember-routing - */ - - function actionArgs(parameters, actionName) { - var ret, i; - - if (actionName === undefined) { - ret = new Array(parameters.length); - for (i = 0; i < parameters.length; i++) { - ret[i] = readUnwrappedModel(parameters[i]); - } - } else { - ret = new Array(parameters.length + 1); - ret[0] = actionName; - for (i = 0; i < parameters.length; i++) { - ret[i + 1] = readUnwrappedModel(parameters[i]); - } - } - - return ret; - } - - var ActionHelper = {}; - - // registeredActions is re-exported for compatibility with older plugins - // that were using this undocumented API. - ActionHelper.registeredActions = ActionManager.registeredActions; - - __exports__.ActionHelper = ActionHelper; - - var keys = ["alt", "shift", "meta", "ctrl"]; - - var POINTER_EVENT_TYPE_REGEX = /^click|mouse|touch/; - - var isAllowedEvent = function(event, allowedKeys) { - if (typeof allowedKeys === "undefined") { - if (POINTER_EVENT_TYPE_REGEX.test(event.type)) { - return isSimpleClick(event); - } else { - allowedKeys = ''; - } - } - - if (allowedKeys.indexOf("any") >= 0) { - return true; - } - - var allowed = true; - - forEach.call(keys, function(key) { - if (event[key + "Key"] && allowedKeys.indexOf(key) === -1) { - allowed = false; - } - }); - - return allowed; - }; - - function isKeyEvent(eventName) { - return ['keyUp', 'keyPress', 'keyDown'].indexOf(eventName) !== -1; - } - - function ignoreKeyEvent(eventName, event, keyCode) { - var any = 'any'; - keyCode = keyCode || any; - return isKeyEvent(eventName) && keyCode !== any && keyCode !== event.which.toString(); - } - - ActionHelper.registerAction = function(actionNameOrStream, options, allowedKeys) { - var actionId = uuid(); - var eventName = options.eventName; - var parameters = options.parameters; - - ActionManager.registeredActions[actionId] = { - eventName: eventName, - handler: function handleRegisteredAction(event) { - if (!isAllowedEvent(event, allowedKeys)) { return true; } - - if (options.preventDefault !== false) { - event.preventDefault(); - } - - if (options.bubbles === false) { - event.stopPropagation(); - } - - var target = options.target.value(); - - - var actionName; - - if (actionNameOrStream.isStream) { - actionName = actionNameOrStream.value(); - - if (typeof actionName === 'undefined' || typeof actionName === 'function') { - actionName = actionNameOrStream._originalPath; - } - } - - if (!actionName) { - actionName = actionNameOrStream; - } - - run(function runRegisteredAction() { - if (target.send) { - target.send.apply(target, actionArgs(parameters, actionName)); - } else { - target[actionName].apply(target, actionArgs(parameters)); - } - }); - } - }; - - options.view.on('willClearRender', function() { - delete ActionManager.registeredActions[actionId]; - }); - - return actionId; - }; - - /** - The `{{action}}` helper provides a useful shortcut for registering an HTML - element within a template for a single DOM event and forwarding that - interaction to the template's controller or specified `target` option. - - If the controller does not implement the specified action, the event is sent - to the current route, and it bubbles up the route hierarchy from there. - - For more advanced event handling see [Ember.Component](/api/classes/Ember.Component.html) - - - ### Use - Given the following application Handlebars template on the page - - ```handlebars -
    - 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(actionName) { - var length = arguments.length; - var options = arguments[length - 1]; - var view = options.data.view; - var hash = options.hash; - var types = options.types; - - // create a hash to pass along to registerAction - var parameters = []; - - var actionOptions = { - eventName: hash.on || "click", - parameters: parameters, - view: options.data.view, - bubbles: hash.bubbles, - preventDefault: hash.preventDefault, - target: view.getStream(hash.target || 'controller'), - withKeyCode: hash.withKeyCode - }; - - var actionNameStream; - - if (types[0] === "ID") { - actionNameStream = view.getStream(actionName); - actionNameStream._originalPath = actionName; - } else { - actionNameStream = actionName; - } - - for (var i = 1; i < length - 1; i++) { - if (types[i] === "ID") { - parameters.push(view.getStream(arguments[i])); - } else { - parameters.push(arguments[i]); - } - } - - var actionId = ActionHelper.registerAction(actionNameStream, actionOptions, hash.allowedKeys); - return new EmberHandlebars.SafeString('data-ember-action="' + actionId + '"'); - } - - __exports__.actionHelper = actionHelper; - }); -enifed("ember-routing-handlebars/helpers/link_to", - ["ember-metal/core","ember-metal/property_get","ember-metal/merge","ember-metal/run_loop","ember-metal/computed","ember-runtime/system/string","ember-runtime/system/object","ember-runtime/mixins/controller","ember-metal/keys","ember-views/system/utils","ember-views/views/component","ember-handlebars/helpers/view","ember-routing/utils","ember-handlebars/ext","ember-metal/streams/read","ember-handlebars","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // FEATURES, Logger, Handlebars, warn, assert - var get = __dependency2__.get; - var merge = __dependency3__["default"]; - var run = __dependency4__["default"]; - var computed = __dependency5__.computed; - - var fmt = __dependency6__.fmt; - var EmberObject = __dependency7__["default"]; - var ControllerMixin = __dependency8__["default"]; - var keys = __dependency9__["default"]; - var isSimpleClick = __dependency10__.isSimpleClick; - var EmberComponent = __dependency11__["default"]; - var viewHelper = __dependency12__.viewHelper; - var routeArgs = __dependency13__.routeArgs; - var stringifyValue = __dependency14__.stringifyValue; - var read = __dependency15__.read; - - - /** - @module ember - @submodule ember-routing - */ - - var slice = [].slice; - - 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; - }; - - var QueryParams = EmberObject.extend({ - values: null - }); - - /** - `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, - - /** - 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 discourage that you override these defaults, - however you can push onto the array if needed. - - @property attributeBindings - @type Array | String - @default ['href', 'title', 'rel'] - **/ - 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); - - - // 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) { - this.linkTitle.subscribe(scheduledRerender, this); - } - - for (var i = 0; i < params.length; i++) { - var param = params[i]; - if (param && param.isStream) { - param.subscribe(scheduledParamsChanged, this); - } - } - - var queryParamsObject = this.queryParamsObject; - if (queryParamsObject) { - var values = queryParamsObject.values; - for (var k in values) { - if (!values.hasOwnProperty(k)) { - continue; - } - - var value = values[k]; - if (value && value.isStream) { - value.subscribe(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; } - - - 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 - }); - - - /** - 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}} - ``` - - ```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 -
  7. - Great Hamster Photos -
  8. - ``` - - 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(name) { - var options = slice.call(arguments, -1)[0]; - var params = slice.call(arguments, 0, -1); - var view = options.data.view; - var hash = options.hash; - var hashTypes = options.hashTypes; - var types = options.types; - var shouldEscape = !hash.unescaped; - var queryParamsObject; - - - if (params[params.length - 1] instanceof QueryParams) { - hash.queryParamsObject = queryParamsObject = params.pop(); - } - - if (hash.disabledWhen) { - hash.disabledBinding = hash.disabledWhen; - hashTypes.disabledBinding = hashTypes.disabledWhen; - delete hash.disabledWhen; - delete hashTypes.disabledWhen; - } - - if (!options.fn) { - var linkTitle = params.shift(); - var linkTitleType = types.shift(); - if (linkTitleType === 'ID') { - hash.linkTitle = linkTitle = view.getStream(linkTitle); - options.fn = function() { - return stringifyValue(linkTitle.value(), shouldEscape); - }; - } else { - options.fn = function() { - return linkTitle; - }; - } - } - - // Setup route & param streams - for (var i = 0; i < params.length; i++) { - var paramPath = params[i]; - if (types[i] === 'ID') { - var lazyValue = view.getStream(paramPath); - - // TODO: Consider a better approach to unwrapping controllers. - if (paramPath !== 'controller') { - while (ControllerMixin.detect(lazyValue.value())) { - paramPath = (paramPath === '') ? 'model' : paramPath + '.model'; - lazyValue = view.getStream(paramPath); - } - } - params[i] = lazyValue; - } - } - - hash.params = params; - - options.helperName = options.helperName || 'link-to'; - - return viewHelper.call(this, LinkView, options); - } - - /** - 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(options) { - - var view = options.data.view; - var hash = options.hash; - var hashTypes = options.hashTypes; - - for (var k in hash) { - if (hashTypes[k] === 'ID') { - hash[k] = view.getStream(hash[k]); - } - } - - return QueryParams.create({ - values: options.hash - }); - } - - __exports__.queryParamsHelper = queryParamsHelper;/** - 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() { - - return linkToHelper.apply(this, arguments); - } - - 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; - __exports__.deprecatedLinkToHelper = deprecatedLinkToHelper; - __exports__.linkToHelper = linkToHelper; - }); -enifed("ember-routing-handlebars/helpers/outlet", - ["ember-metal/core","ember-metal/property_set","ember-views/views/container_view","ember-handlebars/views/metamorph_view","ember-handlebars/helpers/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // assert - var set = __dependency2__.set; - var ContainerView = __dependency3__["default"]; - var _Metamorph = __dependency4__._Metamorph; - var viewHelper = __dependency5__.viewHelper; - - /** - @module ember - @submodule ember-routing - */ - - /** - @module ember - @submodule ember-routing - */ - - var OutletView = ContainerView.extend(_Metamorph); - __exports__.OutletView = 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(property, options) { - var outletSource; - var viewName; - var viewClass; - var viewFullName; - - if (property && property.data && property.data.isRenderData) { - options = property; - property = 'main'; - } - - - var view = options.data.view; - var container = view.container; - - outletSource = view; - while (!outletSource.get('template.isTop')) { - outletSource = outletSource.get('_parentView'); - } - set(view, 'outletSource', outletSource); - - // provide controller override - viewName = options.hash.view; - - if (viewName) { - viewFullName = 'view:' + viewName; - } - - viewClass = viewName ? container.lookupFactory(viewFullName) : options.hash.viewClass || OutletView; - options.types = [ 'ID' ]; - - options.hash.currentViewBinding = '_view.outletSource._outlets.' + property; - options.hashTypes.currentViewBinding = 'STRING'; - - options.helperName = options.helperName || 'outlet'; - - return viewHelper.call(this, viewClass, options); - } - - __exports__.outletHelper = outletHelper; - }); -enifed("ember-routing-handlebars/helpers/render", - ["ember-metal/core","ember-metal/error","ember-runtime/system/string","ember-routing/system/generate_controller","ember-handlebars/helpers/view","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { - "use strict"; - 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; - - /** - @module ember - @submodule ember-routing - */ - - /** - 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?} contextString - @param {Hash} options - @return {String} HTML string - */ - __exports__["default"] = function renderHelper(name, contextString, options) { - var length = arguments.length; - var container, router, controller, view, initialContext; - - container = (options || contextString).data.view._keywords.controller.value().container; - router = container.lookup('router:main'); - - if (length === 2) { - // use the singleton controller - options = contextString; - contextString = undefined; - } else if (length === 3) { - // create a new controller - initialContext = options.data.view.getStream(contextString).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 = options.hash.controller || name; - var controllerFullName = 'controller:' + controllerName; - - if (options.hash.controller) { - } - - var parentController = options.data.view._keywords.controller.value(); - - // choose name - if (length > 2) { - var factory = container.lookupFactory(controllerFullName) || - generateControllerFactory(container, controllerName, initialContext); - - controller = factory.create({ - modelBinding: options.data.view._getBindingForStream(contextString), - parentController: parentController, - target: parentController - }); - - view.one('willDestroyElement', function() { - controller.destroy(); - }); - } else { - controller = container.lookup(controllerFullName) || - generateController(container, controllerName); - - controller.setProperties({ - target: parentController, - parentController: parentController - }); - } - - options.hash.viewName = camelize(name); - - var templateName = 'template:' + name; - options.hash.template = container.lookup(templateName); - - options.hash.controller = controller; - - if (router && !initialContext) { - router._connectActiveView(name, view); - } - - options.helperName = options.helperName || ('render "' + name + '"'); - - ViewHelper.instanceHelper(this, view, options); - } - }); -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'); - ``` - - 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. - @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() { - 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() { - return this.replaceRoute.apply(this, arguments); - } - }); - - var ALL_PERIODS_REGEX = /\./g; - - function accumulateQueryParamDescriptors(_desc, accum) { - var desc = _desc, 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; - - var implementationClass = this.implementations[implementation]; - - 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) { - - 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; - - - // 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) { - 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'; - - - 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 -
    - {{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) { - - var namePassed = typeof name === 'string' && !!name; - - if (typeof name === 'object' && !options) { - options = name; - name = this.routeName; - } - - options = options || {}; - options.namePassed = namePassed; - - var templateName; - - if (name) { - name = name.replace(/\//g, '.'); - templateName = name; - } else { - name = this.routeName; - templateName = this.templateName || name; - } - - var viewName = options.view || namePassed && name || this.viewName || name; - - var container = this.container; - var view = container.lookup('view:' + viewName); - var template = view ? view.get('template') : null; - - if (!template) { - template = container.lookup('template:' + templateName); - } - - if (!view && !template) { - if (get(this.router, 'namespace.LOG_VIEW_LOOKUPS')) { - } - return; - } - - options = normalizeOptions(this, name, template, options); - view = setupView(view, container, options); - - if (options.outlet === 'main') { this.lastRenderedTemplate = name; } - - appendView(this, view, options); - }, - - /** - 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, current; - for (var i=0, l=handlerInfos.length; i 1) { - var qp0 = qps[0].qp, qp1=qps[1].qp; - } - 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); - - 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 = Ember.K; - router._triggerWillLeave = Ember.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.constructor)) { - return v.constructor.compare(v, w); - } - - if (type2 === 'instance' && Comparable.detect(w.constructor)) { - return 1 - w.constructor.compare(w, v); - } - } - - 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) { - - 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; - // 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.cacheable(); - - 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) { - - 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) { - - 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. - - ```javascript - function(item, index); - ``` - - ```javascript - var Hamster = Ember.Object.extend({ - remainingChores: Ember.computed.filter('chores', function(chore, index) { - 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); - 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) { - - 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, { - - /** - The controller used to wrap items, if any. If the value is a string, it will - be used to lookup the container for the controller. As an alternative, you - can also provide a controller class as the value. - - For example: - - ```javascript - App.MyArrayController = Ember.ArrayController.extend({ - itemController: Ember.ObjectController.extend({ - //Item Controller Implementation - }) - }); - ``` - - @property itemController - @type String | Ember.Controller - @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) { - } - - - __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]; - } - - - // 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 () { - for (var i = 0, l = arguments.length; i < l; i++) { - var arg = arguments[i]; - } - - // 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){ - return this['catch'](callback, label); - }; - - RSVP.onerrorDefault = function (error) { - 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/injected_property","ember-metal/keys","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - var Ember = __dependency1__["default"]; - // Ember.assert - var indexOf = __dependency2__.indexOf; - var InjectedProperty = __dependency3__["default"]; - var keys = __dependency4__["default"]; - - /** - Namespace for injection helper methods. - - @class inject - @namespace Ember - */ - function inject() { - } - - // 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 intended to be invoked at when extending a factory with - injected properties. Runs per-type validation functions once for each injected - type encountered. - - 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 validatePropertyInjections - @namespace Ember - @param {Object} factory The factory object being extended - @param {Object} props A hash of properties to be added to the factory - */ - function validatePropertyInjections(factory, props) { - var types = []; - var key, desc, validator, i, l; - - for (key in props) { - desc = props[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() { - }), - - 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'); - 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) { - - if (typeOf(props.actions) === 'object') { - hashName = 'actions'; - } else if (typeOf(props.events) === 'object') { - 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')) { - 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 - it's 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']; - - } - } - }); - }); -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() { - - 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} `true` if the passed function returns `true` for any item - @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} `true` if the passed function returns `true` for any item - @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} `true` if the passed function returns `true` for any item - @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) { - 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; } - 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; } - set(this, keyName, (get(this, keyName) || 0) - decrement); - return get(this, keyName); - }, - - /** - Set the value of a boolean property to the opposite of it's - 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'); - - - 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 { - 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.K, 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 = []; - var K = Ember.K; - - /** - 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'); - - - this._setupContent(); - }), - - _setupContent: function() { - var content = get(this, 'content'); - - if (content) { - - 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; - - - this._setupArrangedContent(); - - this.arrangedContentDidChange(this); - this.arrangedContentArrayDidChange(this, 0, undefined, len); - }), - - _setupArrangedContent: function() { - var arrangedContent = get(this, 'arrangedContent'); - - if (arrangedContent) { - - 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'); - 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 (desc) { - desc.set(this, keyName, value); - } else { - if (typeof this.setUnknownProperty === 'function' && !(keyName in this)) { - this.setUnknownProperty(keyName, value); - } else { - - this[keyName] = value; - - } - } - } - } - } - finishPartial(this, m); - var length = arguments.length; - var args = new Array(length); - for (var x = 0; x < length; x++) { - args[x] = arguments[x]; - } - apply(this, this.init, 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 to Ember that 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; }; - } - - if (Ember.config.overridePrototypeMixin) { - Ember.config.overridePrototypeMixin(CoreObject.PrototypeMixin); - } - - 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()`. - - @method metaForProperty - @param key {String} property name - */ - metaForProperty: function(key) { - var meta = this.proto()['__ember_meta__']; - var desc = meta && meta.descs[key]; - - 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. - - @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); - } - } - }; - - - var ClassMixin = Mixin.create(ClassMixinProps); - - ClassMixin.ownerConstructor = CoreObject; - - if (Ember.config.overrideClassMixin) { - Ember.config.overrideClassMixin(ClassMixin); - } - - 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() { - 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) { - 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-metal/core","ember-runtime/system/core_object","ember-runtime/mixins/observable","ember-runtime/inject","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-runtime - */ - - var Ember = __dependency1__["default"]; - // Ember.assert - var CoreObject = __dependency2__["default"]; - var Observable = __dependency3__["default"]; - var validatePropertyInjections = __dependency4__.validatePropertyInjections; - - /** - `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"; - }; - - function injectedPropertyAssertion(props) { - // Injection validations are a debugging aid only, so ensure that they are - // not performed in production builds by invoking from an assertion - } - - - __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; - - - __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) { - 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-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","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __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"]; - // 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.ContainerView = ContainerView; - Ember.CollectionView = CollectionView; - Ember.Component = Component; - Ember.EventDispatcher = EventDispatcher; - // END EXPORTS - - __exports__["default"] = Ember; - }); -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']; - } - - if (deprecatedProperty) { - } - } - }); - }); -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/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) { - 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]) { - 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/read","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; - - function KeyStream(source, key) { - - this.source = source; - this.obj = undefined; - this.key = key; - - if (source && source.isStream) { - 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) { - - var prevSource = this.source; - - if (nextSource !== prevSource) { - if (prevSource && prevSource.isStream) { - prevSource.unsubscribe(this._didChange, this); - } - - if (nextSource && nextSource.isStream) { - nextSource.subscribe(this._didChange, this); - } - - this.source = nextSource; - this.notify(); - } - }, - - _didChange: function() { - this.notify(); - }, - - destroy: function() { - if (this.source && this.source.isStream) { - 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; - - Stream.prototype.destroy.call(this); - } - }); - - __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/read", - ["ember-metal/core","ember-metal/property_get","ember-metal/path_cache","ember-runtime/system/string","ember-metal/streams/read","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 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); - } else { - viewClass = container.lookupFactory('view:'+value); - } - } else { - viewClass = value; - } - - - return viewClass; - } - - __exports__.readViewFactory = readViewFactory;function readUnwrappedModel(object) { - if (object && object.isStream) { - 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')); - - - rootElement.addClass('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'); - } - - - /** - @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","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { - "use strict"; - /** - @module ember - @submodule ember-views - */ - - var jQuery = __dependency1__["default"]; - var DOMHelper = __dependency2__.DOMHelper; - var Ember = __dependency3__["default"]; - var create = __dependency4__.create; - - // 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 occured - } - }) - }); - - 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'); - - - return template || get(this, 'defaultTemplate'); - }), - - /** - 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('_parentView', function(key) { - 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'); - - - return layout || get(this, 'defaultLayout'); - }).property('layoutName'), - - _yield: function(context, options) { - var template = get(this, 'template'); - if (template) { template(context, options); } - }, - - templateForName: function(name, type) { - if (!name) { return; } - - 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) { - 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) { - 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.setSource(this.isVirtual ? parentKeywords.view : this); - - for (var name in parentKeywords) { - if (keywords[name]) continue; - keywords[name] = parentKeywords[name]; - } - } else { - keywords.view.setSource(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. - output = template(context, { data: data }); - - // 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 parsedPath; - - if (typeof binding === 'string') { - parsedPath = View._parsePropertyPath(binding); - if (parsedPath.path === '') { - parsedPath.stream = new SimpleStream(true); - } else { - parsedPath.stream = this.getStream('_view.' + parsedPath.path); - } - } else { - parsedPath = binding; - } - - // 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 - newClass = this._classStringForProperty(parsedPath); - elem = this.$(); - - // 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 = this._classStringForProperty(parsedPath); - - 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; - } - - parsedPath.stream.subscribe(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; - - - 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); - - View.applyAttributeBindings(elem, attributeName, 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); - - - 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, - `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 - - @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); - - - 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, `createElement()` will be called - 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: Ember.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: Ember.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: Ember.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: Ember.K, - - /** - Called when the parentView property has changed. - - @event parentViewDidChange - */ - parentViewDidChange: Ember.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 = get(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 = get(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 = new SimpleStream(); - this._keywords._view = this; - this._keywords.controller = new KeyStream(this, 'controller'); - this._setupKeywords(); - - this.classNameBindings = emberA(this.classNameBindings.slice()); - - 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.templateData = attrs.templateData || get(this, 'templateData'); - - 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); - - - attrs.templateData = get(this, 'templateData'); - view = ViewKlass.create(attrs); - } else { - attrs.container = this.container; - - if (!get(view, 'templateData')) { - attrs.templateData = get(this, 'templateData'); - } - - setProperties(view, attrs); - - } - - return view; - }, - - becameVisible: Ember.K, - becameHidden: Ember.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) { - 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) { - return this._getContextStream().get(path); - }, - - _getBindingForStream: function(path) { - if (this._streamBindings === undefined) { - this._streamBindings = create(null); - this.one('willDestroyElement', this, this._destroyStreamBindings); - } - - if (this._streamBindings[path] !== undefined) { - return this._streamBindings[path]; - } else { - var stream = this._getContextStream().get(path); - return this._streamBindings[path] = new StreamBinding(stream); - } - }, - - _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. - - View.reopenClass({ - - /** - 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 - */ - _parsePropertyPath: function(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 { - stream: undefined, - path: propertyPath, - classNames: classNames, - className: (className === '') ? undefined : className, - falsyClassName: falsyClassName - }; - }, - - /** - 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 - */ - _classStringForValue: function(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; - } - } - }); - - 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; - - 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", - ["ember-metal","ember-runtime","ember-handlebars","ember-views","ember-routing","ember-routing-handlebars","ember-application","ember-extension-support"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__) { - "use strict"; - /* global navigator */ - // require the main entry points for each of these packages - // this is so that the global exports occur properly - - // 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'); - } - - /** - Ember - - @module ember - */ - - }); -enifed("morph", - ["./morph/morph","./morph/dom-helper","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Morph = __dependency1__["default"]; - var Morph; - __exports__.Morph = Morph; - var DOMHelper = __dependency2__["default"]; - var DOMHelper; - __exports__.DOMHelper = DOMHelper; - }); -enifed("morph/dom-helper", - ["../morph/morph","./dom-helper/build-html-dom","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - var Morph = __dependency1__["default"]; - var buildHTMLDOM = __dependency2__.buildHTMLDOM; - var svgNamespace = __dependency2__.svgNamespace; - var svgHTMLIntegrationPoints = __dependency2__.svgHTMLIntegrationPoints; - - var deletesBlankTextNodes = (function(){ - var element = document.createElement('div'); - element.appendChild( document.createTextNode('') ); - var clonedElement = element.cloneNode(true); - return clonedElement.childNodes.length === 0; - })(); - - var ignoresCheckedAttribute = (function(){ - var element = document.createElement('input'); - element.setAttribute('checked', 'checked'); - var clonedElement = element.cloneNode(false); - return !clonedElement.checked; - })(); - - function isSVG(ns){ - return ns === svgNamespace; - } - - // 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 || window.document; - this.namespace = null; - } - - var prototype = DOMHelper.prototype; - prototype.constructor = DOMHelper; - - prototype.insertBefore = function(element, childElement, referenceChild) { - return element.insertBefore(childElement, referenceChild); - }; - - prototype.appendChild = function(element, childElement) { - return element.appendChild(childElement); - }; - - prototype.appendText = function(element, text) { - return element.appendChild(this.document.createTextNode(text)); - }; - - prototype.setAttribute = function(element, name, value) { - element.setAttribute(name, value); - }; - - if (document.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); - } - }; - } else { - prototype.createElement = function(tagName) { - return this.document.createElement(tagName); - }; - } - - 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.repairClonedNode = function(element, blankChildTextNodes, isChecked){ - if (deletesBlankTextNodes && blankChildTextNodes.length > 0) { - for (var i=0, len=blankChildTextNodes.length;i]*selected/; - detectAutoSelectedOption = 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' ) - ); - }; - } - - // 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 tagNamesRequiringInnerHTMLFix, 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) { - tagNamesRequiringInnerHTMLFix = tagNamesRequiringInnerHTMLFix || {}; - tagNamesRequiringInnerHTMLFix.select = []; - } - - 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 = []; - 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;node=nodes[i];i++) { - if (node.nodeType !== 1) { - continue; - } - if (node.tagName === 'SCRIPT') { - scriptNodes.push(node); - } else { - nodeScriptNodes = node.getElementsByTagName('script'); - for (j=0;j 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/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.reset(); - } - - Morph.prototype.reset = function() { - this.text = null; - this.owner = null; - this.morphs = null; - this.before = null; - this.after = null; - this.escaped = true; - }; - - Morph.prototype.parent = function () { - if (!this.element) { - var parent = this.start.parentNode; - if (this._parent !== parent) { - this.element = this._parent = 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] ? decodeURIComponent(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/assets/scripts/vendor/handlebars.js b/assets/scripts/vendor/handlebars.js deleted file mode 100644 index f826bbfd..00000000 --- a/assets/scripts/vendor/handlebars.js +++ /dev/null @@ -1,3079 +0,0 @@ -/*! - - handlebars v2.0.0 - -Copyright (C) 2011-2014 by Yehuda Katz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -@license -*/ -/* exported Handlebars */ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.Handlebars = root.Handlebars || factory(); - } -}(this, function () { -// handlebars/safe-string.js -var __module4__ = (function() { - "use strict"; - var __exports__; - // Build out our basic SafeString type - function SafeString(string) { - this.string = string; - } - - SafeString.prototype.toString = function() { - return "" + this.string; - }; - - __exports__ = SafeString; - return __exports__; -})(); - -// handlebars/utils.js -var __module3__ = (function(__dependency1__) { - "use strict"; - var __exports__ = {}; - /*jshint -W004 */ - var SafeString = __dependency1__; - - 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 instanceof SafeString) { - return string.toString(); - } 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; - return __exports__; -})(__module4__); - -// handlebars/exception.js -var __module5__ = (function() { - "use strict"; - var __exports__; - - var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; - - function Exception(message, node) { - var line; - if (node && node.firstLine) { - line = node.firstLine; - - message += ' - ' + line + ':' + node.firstColumn; - } - - var tmp = Error.prototype.constructor.call(this, message); - - // 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]]; - } - - if (line) { - this.lineNumber = line; - this.column = node.firstColumn; - } - } - - Exception.prototype = new Error(); - - __exports__ = Exception; - return __exports__; -})(); - -// handlebars/base.js -var __module2__ = (function(__dependency1__, __dependency2__) { - "use strict"; - var __exports__ = {}; - var Utils = __dependency1__; - var Exception = __dependency2__; - - var VERSION = "2.0.0"; - __exports__.VERSION = VERSION;var COMPILER_REVISION = 6; - __exports__.COMPILER_REVISION = COMPILER_REVISION; - var REVISION_CHANGES = { - 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it - 2: '== 1.0.0-rc.3', - 3: '== 1.0.0-rc.4', - 4: '== 1.x.x', - 5: '== 2.0.0-alpha.x', - 6: '>= 2.0.0-beta.1' - }; - __exports__.REVISION_CHANGES = REVISION_CHANGES; - var isArray = Utils.isArray, - isFunction = Utils.isFunction, - toString = Utils.toString, - objectType = '[object Object]'; - - function HandlebarsEnvironment(helpers, partials) { - this.helpers = helpers || {}; - this.partials = partials || {}; - - registerDefaultHelpers(this); - } - - __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { - constructor: HandlebarsEnvironment, - - logger: logger, - log: log, - - registerHelper: function(name, fn) { - if (toString.call(name) === objectType) { - if (fn) { throw new Exception('Arg not supported with multiple helpers'); } - Utils.extend(this.helpers, name); - } else { - this.helpers[name] = fn; - } - }, - unregisterHelper: function(name) { - delete this.helpers[name]; - }, - - registerPartial: function(name, partial) { - if (toString.call(name) === objectType) { - Utils.extend(this.partials, name); - } else { - this.partials[name] = partial; - } - }, - unregisterPartial: function(name) { - delete this.partials[name]; - } - }; - - function registerDefaultHelpers(instance) { - instance.registerHelper('helperMissing', function(/* [args, ]options */) { - if(arguments.length === 1) { - // A missing field in a {{foo}} constuct. - return undefined; - } else { - // Someone is actually trying to call something, blow up. - throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'"); - } - }); - - instance.registerHelper('blockHelperMissing', function(context, options) { - var inverse = options.inverse, - fn = options.fn; - - if(context === true) { - return fn(this); - } else if(context === false || context == null) { - return inverse(this); - } else if (isArray(context)) { - if(context.length > 0) { - if (options.ids) { - options.ids = [options.name]; - } - - return instance.helpers.each(context, options); - } else { - return inverse(this); - } - } else { - if (options.data && options.ids) { - var data = createFrame(options.data); - data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name); - options = {data: data}; - } - - return fn(context, options); - } - }); - - instance.registerHelper('each', function(context, options) { - if (!options) { - throw new Exception('Must pass iterator to #each'); - } - - var fn = options.fn, inverse = options.inverse; - var i = 0, ret = "", data; - - var contextPath; - if (options.data && options.ids) { - contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; - } - - if (isFunction(context)) { context = context.call(this); } - - if (options.data) { - data = createFrame(options.data); - } - - if(context && typeof context === 'object') { - if (isArray(context)) { - for(var j = context.length; i 0) { - throw new Exception("Invalid path: " + original, this); - } else if (part === "..") { - depth++; - depthString += '../'; - } else { - this.isScoped = true; - } - } else { - dig.push(part); - } - } - - this.original = original; - this.parts = dig; - this.string = dig.join('.'); - this.depth = depth; - this.idName = depthString + this.string; - - // an ID is simple if it only has one part, and that part is not - // `..` or `this`. - this.isSimple = parts.length === 1 && !this.isScoped && depth === 0; - - this.stringModeValue = this.string; - }, - - PartialNameNode: function(name, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "PARTIAL_NAME"; - this.name = name.original; - }, - - DataNode: function(id, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "DATA"; - this.id = id; - this.stringModeValue = id.stringModeValue; - this.idName = '@' + id.stringModeValue; - }, - - StringNode: function(string, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "STRING"; - this.original = - this.string = - this.stringModeValue = string; - }, - - NumberNode: function(number, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "NUMBER"; - this.original = - this.number = number; - this.stringModeValue = Number(number); - }, - - BooleanNode: function(bool, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "BOOLEAN"; - this.bool = bool; - this.stringModeValue = bool === "true"; - }, - - CommentNode: function(comment, locInfo) { - LocationInfo.call(this, locInfo); - this.type = "comment"; - this.comment = comment; - - this.strip = { - inlineStandalone: true - }; - } - }; - - - // Must be exported as an object rather than the root of the module as the jison lexer - // most modify the object to operate properly. - __exports__ = AST; - return __exports__; -})(__module5__); - -// handlebars/compiler/parser.js -var __module9__ = (function() { - "use strict"; - var __exports__; - /* jshint ignore:start */ - /* istanbul ignore next */ - /* Jison generated parser */ - var handlebars = (function(){ - var parser = {trace: function trace() { }, - yy: {}, - symbols_: {"error":2,"root":3,"program":4,"EOF":5,"program_repetition0":6,"statement":7,"mustache":8,"block":9,"rawBlock":10,"partial":11,"CONTENT":12,"COMMENT":13,"openRawBlock":14,"END_RAW_BLOCK":15,"OPEN_RAW_BLOCK":16,"sexpr":17,"CLOSE_RAW_BLOCK":18,"openBlock":19,"block_option0":20,"closeBlock":21,"openInverse":22,"block_option1":23,"OPEN_BLOCK":24,"CLOSE":25,"OPEN_INVERSE":26,"inverseAndProgram":27,"INVERSE":28,"OPEN_ENDBLOCK":29,"path":30,"OPEN":31,"OPEN_UNESCAPED":32,"CLOSE_UNESCAPED":33,"OPEN_PARTIAL":34,"partialName":35,"param":36,"partial_option0":37,"partial_option1":38,"sexpr_repetition0":39,"sexpr_option0":40,"dataName":41,"STRING":42,"NUMBER":43,"BOOLEAN":44,"OPEN_SEXPR":45,"CLOSE_SEXPR":46,"hash":47,"hash_repetition_plus0":48,"hashSegment":49,"ID":50,"EQUALS":51,"DATA":52,"pathSegments":53,"SEP":54,"$accept":0,"$end":1}, - terminals_: {2:"error",5:"EOF",12:"CONTENT",13:"COMMENT",15:"END_RAW_BLOCK",16:"OPEN_RAW_BLOCK",18:"CLOSE_RAW_BLOCK",24:"OPEN_BLOCK",25:"CLOSE",26:"OPEN_INVERSE",28:"INVERSE",29:"OPEN_ENDBLOCK",31:"OPEN",32:"OPEN_UNESCAPED",33:"CLOSE_UNESCAPED",34:"OPEN_PARTIAL",42:"STRING",43:"NUMBER",44:"BOOLEAN",45:"OPEN_SEXPR",46:"CLOSE_SEXPR",50:"ID",51:"EQUALS",52:"DATA",54:"SEP"}, - productions_: [0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[10,3],[14,3],[9,4],[9,4],[19,3],[22,3],[27,2],[21,3],[8,3],[8,3],[11,5],[11,4],[17,3],[17,1],[36,1],[36,1],[36,1],[36,1],[36,1],[36,3],[47,1],[49,3],[35,1],[35,1],[35,1],[41,2],[30,1],[53,3],[53,1],[6,0],[6,2],[20,0],[20,1],[23,0],[23,1],[37,0],[37,1],[38,0],[38,1],[39,0],[39,2],[40,0],[40,1],[48,1],[48,2]], - performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) { - - var $0 = $$.length - 1; - switch (yystate) { - case 1: yy.prepareProgram($$[$0-1].statements, true); return $$[$0-1]; - break; - case 2:this.$ = new yy.ProgramNode(yy.prepareProgram($$[$0]), {}, this._$); - break; - case 3:this.$ = $$[$0]; - break; - case 4:this.$ = $$[$0]; - break; - case 5:this.$ = $$[$0]; - break; - case 6:this.$ = $$[$0]; - break; - case 7:this.$ = new yy.ContentNode($$[$0], this._$); - break; - case 8:this.$ = new yy.CommentNode($$[$0], this._$); - break; - case 9:this.$ = new yy.RawBlockNode($$[$0-2], $$[$0-1], $$[$0], this._$); - break; - case 10:this.$ = new yy.MustacheNode($$[$0-1], null, '', '', this._$); - break; - case 11:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], false, this._$); - break; - case 12:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], true, this._$); - break; - case 13:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); - break; - case 14:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); - break; - case 15:this.$ = { strip: yy.stripFlags($$[$0-1], $$[$0-1]), program: $$[$0] }; - break; - case 16:this.$ = {path: $$[$0-1], strip: yy.stripFlags($$[$0-2], $$[$0])}; - break; - case 17:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); - break; - case 18:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$); - break; - case 19:this.$ = new yy.PartialNode($$[$0-3], $$[$0-2], $$[$0-1], yy.stripFlags($$[$0-4], $$[$0]), this._$); - break; - case 20:this.$ = new yy.PartialNode($$[$0-2], undefined, $$[$0-1], yy.stripFlags($$[$0-3], $$[$0]), this._$); - break; - case 21:this.$ = new yy.SexprNode([$$[$0-2]].concat($$[$0-1]), $$[$0], this._$); - break; - case 22:this.$ = new yy.SexprNode([$$[$0]], null, this._$); - break; - case 23:this.$ = $$[$0]; - break; - case 24:this.$ = new yy.StringNode($$[$0], this._$); - break; - case 25:this.$ = new yy.NumberNode($$[$0], this._$); - break; - case 26:this.$ = new yy.BooleanNode($$[$0], this._$); - break; - case 27:this.$ = $$[$0]; - break; - case 28:$$[$0-1].isHelper = true; this.$ = $$[$0-1]; - break; - case 29:this.$ = new yy.HashNode($$[$0], this._$); - break; - case 30:this.$ = [$$[$0-2], $$[$0]]; - break; - case 31:this.$ = new yy.PartialNameNode($$[$0], this._$); - break; - case 32:this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0], this._$), this._$); - break; - case 33:this.$ = new yy.PartialNameNode(new yy.NumberNode($$[$0], this._$)); - break; - case 34:this.$ = new yy.DataNode($$[$0], this._$); - break; - case 35:this.$ = new yy.IdNode($$[$0], this._$); - break; - case 36: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2]; - break; - case 37:this.$ = [{part: $$[$0]}]; - break; - case 38:this.$ = []; - break; - case 39:$$[$0-1].push($$[$0]); - break; - case 48:this.$ = []; - break; - case 49:$$[$0-1].push($$[$0]); - break; - case 52:this.$ = [$$[$0]]; - break; - case 53:$$[$0-1].push($$[$0]); - break; - } - }, - table: [{3:1,4:2,5:[2,38],6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],31:[2,38],32:[2,38],34:[2,38]},{1:[3]},{5:[1,4]},{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:[1,10],13:[1,11],14:16,16:[1,20],19:14,22:15,24:[1,18],26:[1,19],28:[2,2],29:[2,2],31:[1,12],32:[1,13],34:[1,17]},{1:[2,1]},{5:[2,39],12:[2,39],13:[2,39],16:[2,39],24:[2,39],26:[2,39],28:[2,39],29:[2,39],31:[2,39],32:[2,39],34:[2,39]},{5:[2,3],12:[2,3],13:[2,3],16:[2,3],24:[2,3],26:[2,3],28:[2,3],29:[2,3],31:[2,3],32:[2,3],34:[2,3]},{5:[2,4],12:[2,4],13:[2,4],16:[2,4],24:[2,4],26:[2,4],28:[2,4],29:[2,4],31:[2,4],32:[2,4],34:[2,4]},{5:[2,5],12:[2,5],13:[2,5],16:[2,5],24:[2,5],26:[2,5],28:[2,5],29:[2,5],31:[2,5],32:[2,5],34:[2,5]},{5:[2,6],12:[2,6],13:[2,6],16:[2,6],24:[2,6],26:[2,6],28:[2,6],29:[2,6],31:[2,6],32:[2,6],34:[2,6]},{5:[2,7],12:[2,7],13:[2,7],16:[2,7],24:[2,7],26:[2,7],28:[2,7],29:[2,7],31:[2,7],32:[2,7],34:[2,7]},{5:[2,8],12:[2,8],13:[2,8],16:[2,8],24:[2,8],26:[2,8],28:[2,8],29:[2,8],31:[2,8],32:[2,8],34:[2,8]},{17:21,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:27,30:22,41:23,50:[1,26],52:[1,25],53:24},{4:28,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{4:29,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{12:[1,30]},{30:32,35:31,42:[1,33],43:[1,34],50:[1,26],53:24},{17:35,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:36,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:37,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[1,38]},{18:[2,48],25:[2,48],33:[2,48],39:39,42:[2,48],43:[2,48],44:[2,48],45:[2,48],46:[2,48],50:[2,48],52:[2,48]},{18:[2,22],25:[2,22],33:[2,22],46:[2,22]},{18:[2,35],25:[2,35],33:[2,35],42:[2,35],43:[2,35],44:[2,35],45:[2,35],46:[2,35],50:[2,35],52:[2,35],54:[1,40]},{30:41,50:[1,26],53:24},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],52:[2,37],54:[2,37]},{33:[1,42]},{20:43,27:44,28:[1,45],29:[2,40]},{23:46,27:47,28:[1,45],29:[2,42]},{15:[1,48]},{25:[2,46],30:51,36:49,38:50,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],47:57,48:58,49:60,50:[1,59],52:[1,25],53:24},{25:[2,31],42:[2,31],43:[2,31],44:[2,31],45:[2,31],50:[2,31],52:[2,31]},{25:[2,32],42:[2,32],43:[2,32],44:[2,32],45:[2,32],50:[2,32],52:[2,32]},{25:[2,33],42:[2,33],43:[2,33],44:[2,33],45:[2,33],50:[2,33],52:[2,33]},{25:[1,61]},{25:[1,62]},{18:[1,63]},{5:[2,17],12:[2,17],13:[2,17],16:[2,17],24:[2,17],26:[2,17],28:[2,17],29:[2,17],31:[2,17],32:[2,17],34:[2,17]},{18:[2,50],25:[2,50],30:51,33:[2,50],36:65,40:64,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],46:[2,50],47:66,48:58,49:60,50:[1,59],52:[1,25],53:24},{50:[1,67]},{18:[2,34],25:[2,34],33:[2,34],42:[2,34],43:[2,34],44:[2,34],45:[2,34],46:[2,34],50:[2,34],52:[2,34]},{5:[2,18],12:[2,18],13:[2,18],16:[2,18],24:[2,18],26:[2,18],28:[2,18],29:[2,18],31:[2,18],32:[2,18],34:[2,18]},{21:68,29:[1,69]},{29:[2,41]},{4:70,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{21:71,29:[1,69]},{29:[2,43]},{5:[2,9],12:[2,9],13:[2,9],16:[2,9],24:[2,9],26:[2,9],28:[2,9],29:[2,9],31:[2,9],32:[2,9],34:[2,9]},{25:[2,44],37:72,47:73,48:58,49:60,50:[1,74]},{25:[1,75]},{18:[2,23],25:[2,23],33:[2,23],42:[2,23],43:[2,23],44:[2,23],45:[2,23],46:[2,23],50:[2,23],52:[2,23]},{18:[2,24],25:[2,24],33:[2,24],42:[2,24],43:[2,24],44:[2,24],45:[2,24],46:[2,24],50:[2,24],52:[2,24]},{18:[2,25],25:[2,25],33:[2,25],42:[2,25],43:[2,25],44:[2,25],45:[2,25],46:[2,25],50:[2,25],52:[2,25]},{18:[2,26],25:[2,26],33:[2,26],42:[2,26],43:[2,26],44:[2,26],45:[2,26],46:[2,26],50:[2,26],52:[2,26]},{18:[2,27],25:[2,27],33:[2,27],42:[2,27],43:[2,27],44:[2,27],45:[2,27],46:[2,27],50:[2,27],52:[2,27]},{17:76,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[2,47]},{18:[2,29],25:[2,29],33:[2,29],46:[2,29],49:77,50:[1,74]},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],51:[1,78],52:[2,37],54:[2,37]},{18:[2,52],25:[2,52],33:[2,52],46:[2,52],50:[2,52]},{12:[2,13],13:[2,13],16:[2,13],24:[2,13],26:[2,13],28:[2,13],29:[2,13],31:[2,13],32:[2,13],34:[2,13]},{12:[2,14],13:[2,14],16:[2,14],24:[2,14],26:[2,14],28:[2,14],29:[2,14],31:[2,14],32:[2,14],34:[2,14]},{12:[2,10]},{18:[2,21],25:[2,21],33:[2,21],46:[2,21]},{18:[2,49],25:[2,49],33:[2,49],42:[2,49],43:[2,49],44:[2,49],45:[2,49],46:[2,49],50:[2,49],52:[2,49]},{18:[2,51],25:[2,51],33:[2,51],46:[2,51]},{18:[2,36],25:[2,36],33:[2,36],42:[2,36],43:[2,36],44:[2,36],45:[2,36],46:[2,36],50:[2,36],52:[2,36],54:[2,36]},{5:[2,11],12:[2,11],13:[2,11],16:[2,11],24:[2,11],26:[2,11],28:[2,11],29:[2,11],31:[2,11],32:[2,11],34:[2,11]},{30:79,50:[1,26],53:24},{29:[2,15]},{5:[2,12],12:[2,12],13:[2,12],16:[2,12],24:[2,12],26:[2,12],28:[2,12],29:[2,12],31:[2,12],32:[2,12],34:[2,12]},{25:[1,80]},{25:[2,45]},{51:[1,78]},{5:[2,20],12:[2,20],13:[2,20],16:[2,20],24:[2,20],26:[2,20],28:[2,20],29:[2,20],31:[2,20],32:[2,20],34:[2,20]},{46:[1,81]},{18:[2,53],25:[2,53],33:[2,53],46:[2,53],50:[2,53]},{30:51,36:82,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],50:[1,26],52:[1,25],53:24},{25:[1,83]},{5:[2,19],12:[2,19],13:[2,19],16:[2,19],24:[2,19],26:[2,19],28:[2,19],29:[2,19],31:[2,19],32:[2,19],34:[2,19]},{18:[2,28],25:[2,28],33:[2,28],42:[2,28],43:[2,28],44:[2,28],45:[2,28],46:[2,28],50:[2,28],52:[2,28]},{18:[2,30],25:[2,30],33:[2,30],46:[2,30],50:[2,30]},{5:[2,16],12:[2,16],13:[2,16],16:[2,16],24:[2,16],26:[2,16],28:[2,16],29:[2,16],31:[2,16],32:[2,16],34:[2,16]}], - defaultActions: {4:[2,1],44:[2,41],47:[2,43],57:[2,47],63:[2,10],70:[2,15],73:[2,45]}, - parseError: function parseError(str, hash) { - throw new Error(str); - }, - parse: function parse(input) { - var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1; - this.lexer.setInput(input); - this.lexer.yy = this.yy; - this.yy.lexer = this.lexer; - this.yy.parser = this; - if (typeof this.lexer.yylloc == "undefined") - this.lexer.yylloc = {}; - var yyloc = this.lexer.yylloc; - lstack.push(yyloc); - var ranges = this.lexer.options && this.lexer.options.ranges; - if (typeof this.yy.parseError === "function") - this.parseError = this.yy.parseError; - function popStack(n) { - stack.length = stack.length - 2 * n; - vstack.length = vstack.length - n; - lstack.length = lstack.length - n; - } - function lex() { - var token; - token = self.lexer.lex() || 1; - if (typeof token !== "number") { - token = self.symbols_[token] || token; - } - return token; - } - var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; - while (true) { - state = stack[stack.length - 1]; - if (this.defaultActions[state]) { - action = this.defaultActions[state]; - } else { - if (symbol === null || typeof symbol == "undefined") { - symbol = lex(); - } - action = table[state] && table[state][symbol]; - } - if (typeof action === "undefined" || !action.length || !action[0]) { - var errStr = ""; - if (!recovering) { - expected = []; - for (p in table[state]) - if (this.terminals_[p] && p > 2) { - expected.push("'" + this.terminals_[p] + "'"); - } - if (this.lexer.showPosition) { - errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'"; - } else { - errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'"); - } - this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected}); - } - } - if (action[0] instanceof Array && action.length > 1) { - throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol); - } - switch (action[0]) { - case 1: - stack.push(symbol); - vstack.push(this.lexer.yytext); - lstack.push(this.lexer.yylloc); - stack.push(action[1]); - symbol = null; - if (!preErrorSymbol) { - yyleng = this.lexer.yyleng; - yytext = this.lexer.yytext; - yylineno = this.lexer.yylineno; - yyloc = this.lexer.yylloc; - if (recovering > 0) - recovering--; - } else { - symbol = preErrorSymbol; - preErrorSymbol = null; - } - break; - case 2: - len = this.productions_[action[1]][1]; - yyval.$ = vstack[vstack.length - len]; - yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column}; - if (ranges) { - yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]]; - } - r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack); - if (typeof r !== "undefined") { - return r; - } - if (len) { - stack = stack.slice(0, -1 * len * 2); - vstack = vstack.slice(0, -1 * len); - lstack = lstack.slice(0, -1 * len); - } - stack.push(this.productions_[action[1]][0]); - vstack.push(yyval.$); - lstack.push(yyval._$); - newState = table[stack[stack.length - 2]][stack[stack.length - 1]]; - stack.push(newState); - break; - case 3: - return true; - } - } - return true; - } - }; - /* Jison generated lexer */ - var lexer = (function(){ - var lexer = ({EOF:1, - parseError:function parseError(str, hash) { - if (this.yy.parser) { - this.yy.parser.parseError(str, hash); - } else { - throw new Error(str); - } - }, - setInput:function (input) { - this._input = input; - this._more = this._less = this.done = false; - this.yylineno = this.yyleng = 0; - this.yytext = this.matched = this.match = ''; - this.conditionStack = ['INITIAL']; - this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0}; - if (this.options.ranges) this.yylloc.range = [0,0]; - this.offset = 0; - return this; - }, - input:function () { - var ch = this._input[0]; - this.yytext += ch; - this.yyleng++; - this.offset++; - this.match += ch; - this.matched += ch; - var lines = ch.match(/(?:\r\n?|\n).*/g); - if (lines) { - this.yylineno++; - this.yylloc.last_line++; - } else { - this.yylloc.last_column++; - } - if (this.options.ranges) this.yylloc.range[1]++; - - this._input = this._input.slice(1); - return ch; - }, - unput:function (ch) { - var len = ch.length; - var lines = ch.split(/(?:\r\n?|\n)/g); - - this._input = ch + this._input; - this.yytext = this.yytext.substr(0, this.yytext.length-len-1); - //this.yyleng -= len; - this.offset -= len; - var oldLines = this.match.split(/(?:\r\n?|\n)/g); - this.match = this.match.substr(0, this.match.length-1); - this.matched = this.matched.substr(0, this.matched.length-1); - - if (lines.length-1) this.yylineno -= lines.length-1; - var r = this.yylloc.range; - - this.yylloc = {first_line: this.yylloc.first_line, - last_line: this.yylineno+1, - first_column: this.yylloc.first_column, - last_column: lines ? - (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length: - this.yylloc.first_column - len - }; - - if (this.options.ranges) { - this.yylloc.range = [r[0], r[0] + this.yyleng - len]; - } - return this; - }, - more:function () { - this._more = true; - return this; - }, - less:function (n) { - this.unput(this.match.slice(n)); - }, - pastInput:function () { - var past = this.matched.substr(0, this.matched.length - this.match.length); - return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, ""); - }, - upcomingInput:function () { - var next = this.match; - if (next.length < 20) { - next += this._input.substr(0, 20-next.length); - } - return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, ""); - }, - showPosition:function () { - var pre = this.pastInput(); - var c = new Array(pre.length + 1).join("-"); - return pre + this.upcomingInput() + "\n" + c+"^"; - }, - next:function () { - if (this.done) { - return this.EOF; - } - if (!this._input) this.done = true; - - var token, - match, - tempMatch, - index, - col, - lines; - if (!this._more) { - this.yytext = ''; - this.match = ''; - } - var rules = this._currentRules(); - for (var i=0;i < rules.length; i++) { - tempMatch = this._input.match(this.rules[rules[i]]); - if (tempMatch && (!match || tempMatch[0].length > match[0].length)) { - match = tempMatch; - index = i; - if (!this.options.flex) break; - } - } - if (match) { - lines = match[0].match(/(?:\r\n?|\n).*/g); - if (lines) this.yylineno += lines.length; - this.yylloc = {first_line: this.yylloc.last_line, - last_line: this.yylineno+1, - first_column: this.yylloc.last_column, - last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length}; - this.yytext += match[0]; - this.match += match[0]; - this.matches = match; - this.yyleng = this.yytext.length; - if (this.options.ranges) { - this.yylloc.range = [this.offset, this.offset += this.yyleng]; - } - this._more = false; - this._input = this._input.slice(match[0].length); - this.matched += match[0]; - token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]); - if (this.done && this._input) this.done = false; - if (token) return token; - else return; - } - if (this._input === "") { - return this.EOF; - } else { - return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), - {text: "", token: null, line: this.yylineno}); - } - }, - lex:function lex() { - var r = this.next(); - if (typeof r !== 'undefined') { - return r; - } else { - return this.lex(); - } - }, - begin:function begin(condition) { - this.conditionStack.push(condition); - }, - popState:function popState() { - return this.conditionStack.pop(); - }, - _currentRules:function _currentRules() { - return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules; - }, - topState:function () { - return this.conditionStack[this.conditionStack.length-2]; - }, - pushState:function begin(condition) { - this.begin(condition); - }}); - lexer.options = {}; - lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) { - - - function strip(start, end) { - return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end); - } - - - var YYSTATE=YY_START - switch($avoiding_name_collisions) { - case 0: - if(yy_.yytext.slice(-2) === "\\\\") { - strip(0,1); - this.begin("mu"); - } else if(yy_.yytext.slice(-1) === "\\") { - strip(0,1); - this.begin("emu"); - } else { - this.begin("mu"); - } - if(yy_.yytext) return 12; - - break; - case 1:return 12; - break; - case 2: - this.popState(); - return 12; - - break; - case 3: - yy_.yytext = yy_.yytext.substr(5, yy_.yyleng-9); - this.popState(); - return 15; - - break; - case 4: return 12; - break; - case 5:strip(0,4); this.popState(); return 13; - break; - case 6:return 45; - break; - case 7:return 46; - break; - case 8: return 16; - break; - case 9: - this.popState(); - this.begin('raw'); - return 18; - - break; - case 10:return 34; - break; - case 11:return 24; - break; - case 12:return 29; - break; - case 13:this.popState(); return 28; - break; - case 14:this.popState(); return 28; - break; - case 15:return 26; - break; - case 16:return 26; - break; - case 17:return 32; - break; - case 18:return 31; - break; - case 19:this.popState(); this.begin('com'); - break; - case 20:strip(3,5); this.popState(); return 13; - break; - case 21:return 31; - break; - case 22:return 51; - break; - case 23:return 50; - break; - case 24:return 50; - break; - case 25:return 54; - break; - case 26:// ignore whitespace - break; - case 27:this.popState(); return 33; - break; - case 28:this.popState(); return 25; - break; - case 29:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 42; - break; - case 30:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 42; - break; - case 31:return 52; - break; - case 32:return 44; - break; - case 33:return 44; - break; - case 34:return 43; - break; - case 35:return 50; - break; - case 36:yy_.yytext = strip(1,2); return 50; - break; - case 37:return 'INVALID'; - break; - case 38:return 5; - break; - } - }; - lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{\/)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/]; - lexer.conditions = {"mu":{"rules":[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[5],"inclusive":false},"raw":{"rules":[3,4],"inclusive":false},"INITIAL":{"rules":[0,1,38],"inclusive":true}}; - return lexer;})() - parser.lexer = lexer; - function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser; - return new Parser; - })();__exports__ = handlebars; - /* jshint ignore:end */ - return __exports__; -})(); - -// handlebars/compiler/helpers.js -var __module10__ = (function(__dependency1__) { - "use strict"; - var __exports__ = {}; - var Exception = __dependency1__; - - function stripFlags(open, close) { - return { - left: open.charAt(2) === '~', - right: close.charAt(close.length-3) === '~' - }; - } - - __exports__.stripFlags = stripFlags; - function prepareBlock(mustache, program, inverseAndProgram, close, inverted, locInfo) { - /*jshint -W040 */ - if (mustache.sexpr.id.original !== close.path.original) { - throw new Exception(mustache.sexpr.id.original + ' doesn\'t match ' + close.path.original, mustache); - } - - var inverse = inverseAndProgram && inverseAndProgram.program; - - var strip = { - left: mustache.strip.left, - right: close.strip.right, - - // Determine the standalone candiacy. Basically flag our content as being possibly standalone - // so our parent can determine if we actually are standalone - openStandalone: isNextWhitespace(program.statements), - closeStandalone: isPrevWhitespace((inverse || program).statements) - }; - - if (mustache.strip.right) { - omitRight(program.statements, null, true); - } - - if (inverse) { - var inverseStrip = inverseAndProgram.strip; - - if (inverseStrip.left) { - omitLeft(program.statements, null, true); - } - if (inverseStrip.right) { - omitRight(inverse.statements, null, true); - } - if (close.strip.left) { - omitLeft(inverse.statements, null, true); - } - - // Find standalone else statments - if (isPrevWhitespace(program.statements) - && isNextWhitespace(inverse.statements)) { - - omitLeft(program.statements); - omitRight(inverse.statements); - } - } else { - if (close.strip.left) { - omitLeft(program.statements, null, true); - } - } - - if (inverted) { - return new this.BlockNode(mustache, inverse, program, strip, locInfo); - } else { - return new this.BlockNode(mustache, program, inverse, strip, locInfo); - } - } - - __exports__.prepareBlock = prepareBlock; - function prepareProgram(statements, isRoot) { - for (var i = 0, l = statements.length; i < l; i++) { - var current = statements[i], - strip = current.strip; - - if (!strip) { - continue; - } - - var _isPrevWhitespace = isPrevWhitespace(statements, i, isRoot, current.type === 'partial'), - _isNextWhitespace = isNextWhitespace(statements, i, isRoot), - - openStandalone = strip.openStandalone && _isPrevWhitespace, - closeStandalone = strip.closeStandalone && _isNextWhitespace, - inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace; - - if (strip.right) { - omitRight(statements, i, true); - } - if (strip.left) { - omitLeft(statements, i, true); - } - - if (inlineStandalone) { - omitRight(statements, i); - - if (omitLeft(statements, i)) { - // If we are on a standalone node, save the indent info for partials - if (current.type === 'partial') { - current.indent = (/([ \t]+$)/).exec(statements[i-1].original) ? RegExp.$1 : ''; - } - } - } - if (openStandalone) { - omitRight((current.program || current.inverse).statements); - - // Strip out the previous content node if it's whitespace only - omitLeft(statements, i); - } - if (closeStandalone) { - // Always strip the next node - omitRight(statements, i); - - omitLeft((current.inverse || current.program).statements); - } - } - - return statements; - } - - __exports__.prepareProgram = prepareProgram;function isPrevWhitespace(statements, i, isRoot) { - if (i === undefined) { - i = statements.length; - } - - // Nodes that end with newlines are considered whitespace (but are special - // cased for strip operations) - var prev = statements[i-1], - sibling = statements[i-2]; - if (!prev) { - return isRoot; - } - - if (prev.type === 'content') { - return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original); - } - } - function isNextWhitespace(statements, i, isRoot) { - if (i === undefined) { - i = -1; - } - - var next = statements[i+1], - sibling = statements[i+2]; - if (!next) { - return isRoot; - } - - if (next.type === 'content') { - return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original); - } - } - - // Marks the node to the right of the position as omitted. - // I.e. {{foo}}' ' will mark the ' ' node as omitted. - // - // If i is undefined, then the first child will be marked as such. - // - // If mulitple is truthy then all whitespace will be stripped out until non-whitespace - // content is met. - function omitRight(statements, i, multiple) { - var current = statements[i == null ? 0 : i + 1]; - if (!current || current.type !== 'content' || (!multiple && current.rightStripped)) { - return; - } - - var original = current.string; - current.string = current.string.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), ''); - current.rightStripped = current.string !== original; - } - - // Marks the node to the left of the position as omitted. - // I.e. ' '{{foo}} will mark the ' ' node as omitted. - // - // If i is undefined then the last child will be marked as such. - // - // If mulitple is truthy then all whitespace will be stripped out until non-whitespace - // content is met. - function omitLeft(statements, i, multiple) { - var current = statements[i == null ? statements.length - 1 : i - 1]; - if (!current || current.type !== 'content' || (!multiple && current.leftStripped)) { - return; - } - - // We omit the last node if it's whitespace only and not preceeded by a non-content node. - var original = current.string; - current.string = current.string.replace(multiple ? (/\s+$/) : (/[ \t]+$/), ''); - current.leftStripped = current.string !== original; - return current.leftStripped; - } - return __exports__; -})(__module5__); - -// handlebars/compiler/base.js -var __module8__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) { - "use strict"; - var __exports__ = {}; - var parser = __dependency1__; - var AST = __dependency2__; - var Helpers = __dependency3__; - var extend = __dependency4__.extend; - - __exports__.parser = parser; - - var yy = {}; - extend(yy, Helpers, AST); - - function parse(input) { - // Just return if an already-compile AST was passed in. - if (input.constructor === AST.ProgramNode) { return input; } - - parser.yy = yy; - - return parser.parse(input); - } - - __exports__.parse = parse; - return __exports__; -})(__module9__, __module7__, __module10__, __module3__); - -// handlebars/compiler/compiler.js -var __module11__ = (function(__dependency1__, __dependency2__) { - "use strict"; - var __exports__ = {}; - var Exception = __dependency1__; - var isArray = __dependency2__.isArray; - - var slice = [].slice; - - function Compiler() {} - - __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a - // function in a context. This is necessary for mustache compatibility, which - // requires that context functions in blocks are evaluated by blockHelperMissing, - // and then proceed as if the resulting value was provided to blockHelperMissing. - - Compiler.prototype = { - compiler: Compiler, - - equals: function(other) { - var len = this.opcodes.length; - if (other.opcodes.length !== len) { - return false; - } - - for (var i = 0; i < len; i++) { - var opcode = this.opcodes[i], - otherOpcode = other.opcodes[i]; - if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) { - return false; - } - } - - // We know that length is the same between the two arrays because they are directly tied - // to the opcode behavior above. - len = this.children.length; - for (i = 0; i < len; i++) { - if (!this.children[i].equals(other.children[i])) { - return false; - } - } - - return true; - }, - - guid: 0, - - compile: function(program, options) { - this.opcodes = []; - this.children = []; - this.depths = {list: []}; - this.options = options; - this.stringParams = options.stringParams; - this.trackIds = options.trackIds; - - // These changes will propagate to the other compiler components - var knownHelpers = this.options.knownHelpers; - this.options.knownHelpers = { - 'helperMissing': true, - 'blockHelperMissing': true, - 'each': true, - 'if': true, - 'unless': true, - 'with': true, - 'log': true, - 'lookup': true - }; - if (knownHelpers) { - for (var name in knownHelpers) { - this.options.knownHelpers[name] = knownHelpers[name]; - } - } - - return this.accept(program); - }, - - accept: function(node) { - return this[node.type](node); - }, - - program: function(program) { - var statements = program.statements; - - for(var i=0, l=statements.length; i 0) { - varDeclarations += ", " + locals.join(", "); - } - - // Generate minimizer alias mappings - for (var alias in this.aliases) { - if (this.aliases.hasOwnProperty(alias)) { - varDeclarations += ', ' + alias + '=' + this.aliases[alias]; - } - } - - var params = ["depth0", "helpers", "partials", "data"]; - - if (this.useDepths) { - params.push('depths'); - } - - // Perform a second pass over the output to merge content when possible - var source = this.mergeSource(varDeclarations); - - if (asObject) { - params.push(source); - - return Function.apply(this, params); - } else { - return 'function(' + params.join(',') + ') {\n ' + source + '}'; - } - }, - mergeSource: function(varDeclarations) { - var source = '', - buffer, - appendOnly = !this.forceBuffer, - appendFirst; - - for (var i = 0, len = this.source.length; i < len; i++) { - var line = this.source[i]; - if (line.appendToBuffer) { - if (buffer) { - buffer = buffer + '\n + ' + line.content; - } else { - buffer = line.content; - } - } else { - if (buffer) { - if (!source) { - appendFirst = true; - source = buffer + ';\n '; - } else { - source += 'buffer += ' + buffer + ';\n '; - } - buffer = undefined; - } - source += line + '\n '; - - if (!this.environment.isSimple) { - appendOnly = false; - } - } - } - - if (appendOnly) { - if (buffer || !source) { - source += 'return ' + (buffer || '""') + ';\n'; - } - } else { - varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer()); - if (buffer) { - source += 'return buffer + ' + buffer + ';\n'; - } else { - source += 'return buffer;\n'; - } - } - - if (varDeclarations) { - source = 'var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n ') + source; - } - - return source; - }, - - // [blockValue] - // - // On stack, before: hash, inverse, program, value - // On stack, after: return value of blockHelperMissing - // - // The purpose of this opcode is to take a block of the form - // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and - // replace it on the stack with the result of properly - // invoking blockHelperMissing. - blockValue: function(name) { - this.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; - - var params = [this.contextName(0)]; - this.setupParams(name, 0, params); - - var blockName = this.popStack(); - params.splice(1, 0, blockName); - - this.push('blockHelperMissing.call(' + params.join(', ') + ')'); - }, - - // [ambiguousBlockValue] - // - // On stack, before: hash, inverse, program, value - // Compiler value, before: lastHelper=value of last found helper, if any - // On stack, after, if no lastHelper: same as [blockValue] - // On stack, after, if lastHelper: value - ambiguousBlockValue: function() { - this.aliases.blockHelperMissing = 'helpers.blockHelperMissing'; - - // We're being a bit cheeky and reusing the options value from the prior exec - var params = [this.contextName(0)]; - this.setupParams('', 0, params, true); - - this.flushInline(); - - var current = this.topStack(); - params.splice(1, 0, current); - - this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }"); - }, - - // [appendContent] - // - // On stack, before: ... - // On stack, after: ... - // - // Appends the string value of `content` to the current buffer - appendContent: function(content) { - if (this.pendingContent) { - content = this.pendingContent + content; - } - - this.pendingContent = content; - }, - - // [append] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Coerces `value` to a String and appends it to the current buffer. - // - // If `value` is truthy, or 0, it is coerced into a string and appended - // Otherwise, the empty string is appended - append: function() { - // Force anything that is inlined onto the stack so we don't have duplication - // when we examine local - this.flushInline(); - var local = this.popStack(); - this.pushSource('if (' + local + ' != null) { ' + this.appendToBuffer(local) + ' }'); - if (this.environment.isSimple) { - this.pushSource("else { " + this.appendToBuffer("''") + " }"); - } - }, - - // [appendEscaped] - // - // On stack, before: value, ... - // On stack, after: ... - // - // Escape `value` and append it to the buffer - appendEscaped: function() { - this.aliases.escapeExpression = 'this.escapeExpression'; - - this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")")); - }, - - // [getContext] - // - // On stack, before: ... - // On stack, after: ... - // Compiler value, after: lastContext=depth - // - // Set the value of the `lastContext` compiler value to the depth - getContext: function(depth) { - this.lastContext = depth; - }, - - // [pushContext] - // - // On stack, before: ... - // On stack, after: currentContext, ... - // - // Pushes the value of the current context onto the stack. - pushContext: function() { - this.pushStackLiteral(this.contextName(this.lastContext)); - }, - - // [lookupOnContext] - // - // On stack, before: ... - // On stack, after: currentContext[name], ... - // - // Looks up the value of `name` on the current context and pushes - // it onto the stack. - lookupOnContext: function(parts, falsy, scoped) { - /*jshint -W083 */ - var i = 0, - len = parts.length; - - if (!scoped && this.options.compat && !this.lastContext) { - // The depthed query is expected to handle the undefined logic for the root level that - // is implemented below, so we evaluate that directly in compat mode - this.push(this.depthedLookup(parts[i++])); - } else { - this.pushContext(); - } - - for (; i < len; i++) { - this.replaceStack(function(current) { - var lookup = this.nameLookup(current, parts[i], 'context'); - // We want to ensure that zero and false are handled properly if the context (falsy flag) - // needs to have the special handling for these values. - if (!falsy) { - return ' != null ? ' + lookup + ' : ' + current; - } else { - // Otherwise we can use generic falsy handling - return ' && ' + lookup; - } - }); - } - }, - - // [lookupData] - // - // On stack, before: ... - // On stack, after: data, ... - // - // Push the data lookup operator - lookupData: function(depth, parts) { - /*jshint -W083 */ - if (!depth) { - this.pushStackLiteral('data'); - } else { - this.pushStackLiteral('this.data(data, ' + depth + ')'); - } - - var len = parts.length; - for (var i = 0; i < len; i++) { - this.replaceStack(function(current) { - return ' && ' + this.nameLookup(current, parts[i], 'data'); - }); - } - }, - - // [resolvePossibleLambda] - // - // On stack, before: value, ... - // On stack, after: resolved value, ... - // - // If the `value` is a lambda, replace it on the stack by - // the return value of the lambda - resolvePossibleLambda: function() { - this.aliases.lambda = 'this.lambda'; - - this.push('lambda(' + this.popStack() + ', ' + this.contextName(0) + ')'); - }, - - // [pushStringParam] - // - // On stack, before: ... - // On stack, after: string, currentContext, ... - // - // This opcode is designed for use in string mode, which - // provides the string value of a parameter along with its - // depth rather than resolving it immediately. - pushStringParam: function(string, type) { - this.pushContext(); - this.pushString(type); - - // If it's a subexpression, the string result - // will be pushed after this opcode. - if (type !== 'sexpr') { - if (typeof string === 'string') { - this.pushString(string); - } else { - this.pushStackLiteral(string); - } - } - }, - - emptyHash: function() { - this.pushStackLiteral('{}'); - - if (this.trackIds) { - this.push('{}'); // hashIds - } - if (this.stringParams) { - this.push('{}'); // hashContexts - this.push('{}'); // hashTypes - } - }, - pushHash: function() { - if (this.hash) { - this.hashes.push(this.hash); - } - this.hash = {values: [], types: [], contexts: [], ids: []}; - }, - popHash: function() { - var hash = this.hash; - this.hash = this.hashes.pop(); - - if (this.trackIds) { - this.push('{' + hash.ids.join(',') + '}'); - } - if (this.stringParams) { - this.push('{' + hash.contexts.join(',') + '}'); - this.push('{' + hash.types.join(',') + '}'); - } - - this.push('{\n ' + hash.values.join(',\n ') + '\n }'); - }, - - // [pushString] - // - // On stack, before: ... - // On stack, after: quotedString(string), ... - // - // Push a quoted version of `string` onto the stack - pushString: function(string) { - this.pushStackLiteral(this.quotedString(string)); - }, - - // [push] - // - // On stack, before: ... - // On stack, after: expr, ... - // - // Push an expression onto the stack - push: function(expr) { - this.inlineStack.push(expr); - return expr; - }, - - // [pushLiteral] - // - // On stack, before: ... - // On stack, after: value, ... - // - // Pushes a value onto the stack. This operation prevents - // the compiler from creating a temporary variable to hold - // it. - pushLiteral: function(value) { - this.pushStackLiteral(value); - }, - - // [pushProgram] - // - // On stack, before: ... - // On stack, after: program(guid), ... - // - // Push a program expression onto the stack. This takes - // a compile-time guid and converts it into a runtime-accessible - // expression. - pushProgram: function(guid) { - if (guid != null) { - this.pushStackLiteral(this.programExpression(guid)); - } else { - this.pushStackLiteral(null); - } - }, - - // [invokeHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // Pops off the helper's parameters, invokes the helper, - // and pushes the helper's return value onto the stack. - // - // If the helper is not found, `helperMissing` is called. - invokeHelper: function(paramSize, name, isSimple) { - this.aliases.helperMissing = 'helpers.helperMissing'; - - var nonHelper = this.popStack(); - var helper = this.setupHelper(paramSize, name); - - var lookup = (isSimple ? helper.name + ' || ' : '') + nonHelper + ' || helperMissing'; - this.push('((' + lookup + ').call(' + helper.callParams + '))'); - }, - - // [invokeKnownHelper] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of helper invocation - // - // This operation is used when the helper is known to exist, - // so a `helperMissing` fallback is not required. - invokeKnownHelper: function(paramSize, name) { - var helper = this.setupHelper(paramSize, name); - this.push(helper.name + ".call(" + helper.callParams + ")"); - }, - - // [invokeAmbiguous] - // - // On stack, before: hash, inverse, program, params..., ... - // On stack, after: result of disambiguation - // - // This operation is used when an expression like `{{foo}}` - // is provided, but we don't know at compile-time whether it - // is a helper or a path. - // - // This operation emits more code than the other options, - // and can be avoided by passing the `knownHelpers` and - // `knownHelpersOnly` flags at compile-time. - invokeAmbiguous: function(name, helperCall) { - this.aliases.functionType = '"function"'; - this.aliases.helperMissing = 'helpers.helperMissing'; - this.useRegister('helper'); - - var nonHelper = this.popStack(); - - this.emptyHash(); - var helper = this.setupHelper(0, name, helperCall); - - var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper'); - - this.push( - '((helper = (helper = ' + helperName + ' || ' + nonHelper + ') != null ? helper : helperMissing' - + (helper.paramsInit ? '),(' + helper.paramsInit : '') + '),' - + '(typeof helper === functionType ? helper.call(' + helper.callParams + ') : helper))'); - }, - - // [invokePartial] - // - // On stack, before: context, ... - // On stack after: result of partial invocation - // - // This operation pops off a context, invokes a partial with that context, - // and pushes the result of the invocation back. - invokePartial: function(name, indent) { - var params = [this.nameLookup('partials', name, 'partial'), "'" + indent + "'", "'" + name + "'", this.popStack(), this.popStack(), "helpers", "partials"]; - - if (this.options.data) { - params.push("data"); - } else if (this.options.compat) { - params.push('undefined'); - } - if (this.options.compat) { - params.push('depths'); - } - - this.push("this.invokePartial(" + params.join(", ") + ")"); - }, - - // [assignToHash] - // - // On stack, before: value, ..., hash, ... - // On stack, after: ..., hash, ... - // - // Pops a value off the stack and assigns it to the current hash - assignToHash: function(key) { - var value = this.popStack(), - context, - type, - id; - - if (this.trackIds) { - id = this.popStack(); - } - if (this.stringParams) { - type = this.popStack(); - context = this.popStack(); - } - - var hash = this.hash; - if (context) { - hash.contexts.push("'" + key + "': " + context); - } - if (type) { - hash.types.push("'" + key + "': " + type); - } - if (id) { - hash.ids.push("'" + key + "': " + id); - } - hash.values.push("'" + key + "': (" + value + ")"); - }, - - pushId: function(type, name) { - if (type === 'ID' || type === 'DATA') { - this.pushString(name); - } else if (type === 'sexpr') { - this.pushStackLiteral('true'); - } else { - this.pushStackLiteral('null'); - } - }, - - // HELPERS - - compiler: JavaScriptCompiler, - - compileChildren: function(environment, options) { - var children = environment.children, child, compiler; - - for(var i=0, l=children.length; i this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); } - return this.topStackName(); - }, - topStackName: function() { - return "stack" + this.stackSlot; - }, - flushInline: function() { - var inlineStack = this.inlineStack; - if (inlineStack.length) { - this.inlineStack = []; - for (var i = 0, len = inlineStack.length; i < len; i++) { - var entry = inlineStack[i]; - if (entry instanceof Literal) { - this.compileStack.push(entry); - } else { - this.pushStack(entry); - } - } - } - }, - isInline: function() { - return this.inlineStack.length; - }, - - popStack: function(wrapped) { - var inline = this.isInline(), - item = (inline ? this.inlineStack : this.compileStack).pop(); - - if (!wrapped && (item instanceof Literal)) { - return item.value; - } else { - if (!inline) { - /* istanbul ignore next */ - if (!this.stackSlot) { - throw new Exception('Invalid stack pop'); - } - this.stackSlot--; - } - return item; - } - }, - - topStack: function() { - var stack = (this.isInline() ? this.inlineStack : this.compileStack), - item = stack[stack.length - 1]; - - if (item instanceof Literal) { - return item.value; - } else { - return item; - } - }, - - contextName: function(context) { - if (this.useDepths && context) { - return 'depths[' + context + ']'; - } else { - return 'depth' + context; - } - }, - - quotedString: function(str) { - return '"' + str - .replace(/\\/g, '\\\\') - .replace(/"/g, '\\"') - .replace(/\n/g, '\\n') - .replace(/\r/g, '\\r') - .replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4 - .replace(/\u2029/g, '\\u2029') + '"'; - }, - - objectLiteral: function(obj) { - var pairs = []; - - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - pairs.push(this.quotedString(key) + ':' + obj[key]); - } - } - - return '{' + pairs.join(',') + '}'; - }, - - setupHelper: function(paramSize, name, blockHelper) { - var params = [], - paramsInit = this.setupParams(name, paramSize, params, blockHelper); - var foundHelper = this.nameLookup('helpers', name, 'helper'); - - return { - params: params, - paramsInit: paramsInit, - name: foundHelper, - callParams: [this.contextName(0)].concat(params).join(", ") - }; - }, - - setupOptions: function(helper, paramSize, params) { - var options = {}, contexts = [], types = [], ids = [], param, inverse, program; - - options.name = this.quotedString(helper); - options.hash = this.popStack(); - - if (this.trackIds) { - options.hashIds = this.popStack(); - } - if (this.stringParams) { - options.hashTypes = this.popStack(); - options.hashContexts = this.popStack(); - } - - inverse = this.popStack(); - program = this.popStack(); - - // Avoid setting fn and inverse if neither are set. This allows - // helpers to do a check for `if (options.fn)` - if (program || inverse) { - if (!program) { - program = 'this.noop'; - } - - if (!inverse) { - inverse = 'this.noop'; - } - - options.fn = program; - options.inverse = inverse; - } - - // The parameters go on to the stack in order (making sure that they are evaluated in order) - // so we need to pop them off the stack in reverse order - var i = paramSize; - while (i--) { - param = this.popStack(); - params[i] = param; - - if (this.trackIds) { - ids[i] = this.popStack(); - } - if (this.stringParams) { - types[i] = this.popStack(); - contexts[i] = this.popStack(); - } - } - - if (this.trackIds) { - options.ids = "[" + ids.join(",") + "]"; - } - if (this.stringParams) { - options.types = "[" + types.join(",") + "]"; - options.contexts = "[" + contexts.join(",") + "]"; - } - - if (this.options.data) { - options.data = "data"; - } - - return options; - }, - - // the params and contexts arguments are passed in arrays - // to fill in - setupParams: function(helperName, paramSize, params, useRegister) { - var options = this.objectLiteral(this.setupOptions(helperName, paramSize, params)); - - if (useRegister) { - this.useRegister('options'); - params.push('options'); - return 'options=' + options; - } else { - params.push(options); - return ''; - } - } - }; - - var reservedWords = ( - "break else new var" + - " case finally return void" + - " catch for switch while" + - " continue function this with" + - " default if throw" + - " delete in try" + - " do instanceof typeof" + - " abstract enum int short" + - " boolean export interface static" + - " byte extends long super" + - " char final native synchronized" + - " class float package throws" + - " const goto private transient" + - " debugger implements protected volatile" + - " double import public let yield" - ).split(" "); - - var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {}; - - for(var i=0, l=reservedWords.length; i-1?b.split(".")[1].length:0):a=isNaN(b=M(b))?2:b;var b=a,c=c===void 0?e.decimalPoint:c,d=d===void 0?e.thousandsSep:d,e=f<0?"-":"",a=String(w(f=M(+f||0).toFixed(b))),g=a.length>3?a.length%3:0;return e+(g?a.substr(0,g)+d:"")+ -a.substr(g).replace(/(\d{3})(?=\d)/g,"$1"+d)+(b?c+M(f-a).toFixed(b).slice(2):"")}function sa(a,b){return Array((b||2)+1-String(a).length).join(0)+a}function gb(a,b,c,d){var e,c=o(c,1);e=a/c;b||(b=[1,2,2.5,5,10],d&&d.allowDecimals===!1&&(c===1?b=[1,2,5,10]:c<=0.1&&(b=[1/c])));for(d=0;d=D[hb]&&(i.setMilliseconds(0),i.setSeconds(b>=D[Ya]?0:j*W(i.getSeconds()/j)));if(b>=D[Ya])i[wb](b>=D[Ma]?0:j*W(i[ib]()/j)); -if(b>=D[Ma])i[xb](b>=D[oa]?0:j*W(i[jb]()/j));if(b>=D[oa])i[kb](b>=D[Na]?1:j*W(i[Oa]()/j));b>=D[Na]&&(i[yb](b>=D[ta]?0:j*W(i[$a]()/j)),h=i[ab]());b>=D[ta]&&(h-=h%j,i[zb](h));if(b===D[Za])i[kb](i[Oa]()-i[lb]()+o(d,1));d=1;h=i[ab]();for(var k=i.getTime(),l=i[$a](),m=i[Oa](),i=g?0:(864E5+i.getTimezoneOffset()*6E4)%864E5;kc&&(c=a[b]);return c}function Ba(a,b){for(var c in a)a[c]&&a[c]!==b&&a[c].destroy&&a[c].destroy(),delete a[c]}function Qa(a){cb||(cb=S(ia)); -a&&cb.appendChild(a);cb.innerHTML=""}function mb(a,b){var c="Highcharts error #"+a+": www.highcharts.com/errors/"+a;if(b)throw c;else N.console&&console.log(c)}function ja(a){return parseFloat(a.toPrecision(14))}function ua(a,b){Ra=o(a,b.animation)}function Bb(){var a=V.global.useUTC,b=a?"getUTC":"get",c=a?"setUTC":"set";bb=a?Date.UTC:function(a,b,c,g,h,i){return(new Date(a,b,o(c,1),o(g,0),o(h,0),o(i,0))).getTime()};ib=b+"Minutes";jb=b+"Hours";lb=b+"Day";Oa=b+"Date";$a=b+"Month";ab=b+"FullYear";wb= -c+"Minutes";xb=c+"Hours";kb=c+"Date";yb=c+"Month";zb=c+"FullYear"}function va(){}function Sa(a,b,c){this.axis=a;this.pos=b;this.type=c||"";this.isNew=!0;c||this.addLabel()}function nb(a,b){this.axis=a;if(b)this.options=b,this.id=b.id;return this}function Cb(a,b,c,d,e){var f=a.chart.inverted;this.axis=a;this.isNegative=c;this.options=b;this.x=d;this.stack=e;this.alignOptions={align:b.align||(f?c?"left":"right":"center"),verticalAlign:b.verticalAlign||(f?"middle":c?"bottom":"top"),y:o(b.y,f?4:c?14: --6),x:o(b.x,f?c?-6:6:0)};this.textAlign=b.textAlign||(f?c?"right":"left":"center")}function ob(){this.init.apply(this,arguments)}function pb(a,b){var c=b.borderWidth,d=b.style,e=b.shared,f=w(d.padding);this.chart=a;this.options=b;d.padding=0;this.crosshairs=[];this.currentY=this.currentX=0;this.tooltipIsHidden=!0;this.label=a.renderer.label("",0,0,null,null,null,b.useHTML,null,"tooltip").attr({padding:f,fill:b.backgroundColor,"stroke-width":c,r:b.borderRadius,zIndex:8}).css(d).hide().add();ga||this.label.shadow(b.shadow); -this.shared=e}function Db(a,b){var c=ga?"":b.chart.zoomType;this.zoomX=/x/.test(c);this.zoomY=/y/.test(c);this.options=b;this.chart=a;this.init(a,b.tooltip)}function qb(a){this.init(a)}function rb(a,b){var c,d=a.series;a.series=null;c=C(V,a);c.series=a.series=d;var d=c.chart,e=d.margin,e=aa(e)?e:[e,e,e,e];this.optionsMarginTop=o(d.marginTop,e[0]);this.optionsMarginRight=o(d.marginRight,e[1]);this.optionsMarginBottom=o(d.marginBottom,e[2]);this.optionsMarginLeft=o(d.marginLeft,e[3]);this.runChartClick= -(e=d.events)&&!!e.click;this.callback=b;this.isResizing=0;this.options=c;this.axes=[];this.series=[];this.hasCartesianSeries=d.showAxes;this.init(e)}var A,B=document,N=window,L=Math,t=L.round,W=L.floor,wa=L.ceil,x=L.max,O=L.min,M=L.abs,X=L.cos,da=L.sin,xa=L.PI,Eb=xa*2/360,ya=navigator.userAgent,La=/msie/i.test(ya)&&!N.opera,Ca=B.documentMode===8,Fb=/AppleWebKit/.test(ya),Gb=/Firefox/.test(ya),Da=!!B.createElementNS&&!!B.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect,Rb=Gb&&parseInt(ya.split("Firefox/")[1], -10)<4,ga=!Da&&!La&&!!B.createElement("canvas").getContext,Ta,ea=B.documentElement.ontouchstart!==A,Hb={},sb=0,cb,V,db,Ra,Ua,D,Sb=function(){},ia="div",U="none",tb="rgba(192,192,192,"+(Da?1.0E-6:0.0020)+")",vb="millisecond",hb="second",Ya="minute",Ma="hour",oa="day",Za="week",Na="month",ta="year",bb,ib,jb,lb,Oa,$a,ab,wb,xb,kb,yb,zb,Y={};N.Highcharts={};db=function(a,b,c){if(!s(b)||isNaN(b))return"Invalid date";var a=o(a,"%Y-%m-%d %H:%M:%S"),d=new Date(b),e,f=d[jb](),g=d[lb](),h=d[Oa](),i=d[$a](),j= -d[ab](),k=V.lang,l=k.weekdays,b={a:l[g].substr(0,3),A:l[g],d:sa(h),e:h,b:k.shortMonths[i],B:k.months[i],m:sa(i+1),y:j.toString().substr(2,2),Y:j,H:sa(f),I:sa(f%12||12),l:f%12||12,M:sa(d[ib]()),p:f<12?"AM":"PM",P:f<12?"am":"pm",S:sa(d.getSeconds()),L:sa(t(b%1E3),3)};for(e in b)a=a.replace("%"+e,b[e]);return c?a.substr(0,1).toUpperCase()+a.substr(1):a};Ab.prototype={wrapColor:function(a){if(this.color>=a)this.color=0},wrapSymbol:function(a){if(this.symbol>=a)this.symbol=0}};D=la(vb,1,hb,1E3,Ya,6E4, -Ma,36E5,oa,864E5,Za,6048E5,Na,2592E6,ta,31556952E3);Ua={init:function(a,b,c){var b=b||"",d=a.shift,e=b.indexOf("C")>-1,f=e?7:3,g,b=b.split(" "),c=[].concat(c),h,i,j=function(a){for(g=a.length;g--;)a[g]==="M"&&a.splice(g+1,0,a[g+1],a[g+2],a[g+1],a[g+2])};e&&(j(b),j(c));a.isArea&&(h=b.splice(b.length-6,6),i=c.splice(c.length-6,6));if(d<=c.length/f)for(;d--;)c=[].concat(c).splice(0,f).concat(c);a.shift=0;if(b.length)for(a=c.length;b.length{point.key}
    ',pointFormat:'{series.name}: {point.y}
    ',shadow:!0,shared:ga,snap:ea?25:10,style:{color:"#333333",fontSize:"12px",padding:"5px",whiteSpace:"nowrap"}},credits:{enabled:!0,text:"Highcharts.com",href:"http://www.highcharts.com",position:{align:"right",x:-10,verticalAlign:"bottom",y:-5}, -style:{cursor:"pointer",color:"#909090",fontSize:"10px"}}};var Z=V.plotOptions,T=Z.line;Bb();var pa=function(a){var b=[],c;(function(a){(c=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/.exec(a))?b=[w(c[1]),w(c[2]),w(c[3]),parseFloat(c[4],10)]:(c=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(a))&&(b=[w(c[1],16),w(c[2],16),w(c[3],16),1])})(a);return{get:function(c){return b&&!isNaN(b[0])?c==="rgb"?"rgb("+b[0]+","+b[1]+","+b[2]+")":c==="a"?b[3]: -"rgba("+b.join(",")+")":a},brighten:function(a){if(Ka(a)&&a!==0){var c;for(c=0;c<3;c++)b[c]+=w(a*255),b[c]<0&&(b[c]=0),b[c]>255&&(b[c]=255)}return this},setOpacity:function(a){b[3]=a;return this}}};va.prototype={init:function(a,b){this.element=b==="span"?S(b):B.createElementNS("http://www.w3.org/2000/svg",b);this.renderer=a;this.attrSetters={}},animate:function(a,b,c){b=o(b,Ra,!0);Fa(this);if(b){b=C(b);if(c)b.complete=c;eb(this,a,b)}else this.attr(a),c&&c()},attr:function(a,b){var c,d,e,f,g=this.element, -h=g.nodeName,i=this.renderer,j,k=this.attrSetters,l=this.shadows,m,p,q=this;ra(a)&&s(b)&&(c=a,a={},a[c]=b);if(ra(a))c=a,h==="circle"?c={x:"cx",y:"cy"}[c]||c:c==="strokeWidth"&&(c="stroke-width"),q=z(g,c)||this[c]||0,c!=="d"&&c!=="visibility"&&(q=parseFloat(q));else for(c in a)if(j=!1,d=a[c],e=k[c]&&k[c](d,c),e!==!1){e!==A&&(d=e);if(c==="d")d&&d.join&&(d=d.join(" ")),/(NaN| {2}|^$)/.test(d)&&(d="M 0 0");else if(c==="x"&&h==="text"){for(e=0;em&&/[ \-]/.test(b.innerText)&&(F(b,{width:m+"px",display:"block",whiteSpace:"normal"}),k=m),m=a.fontMetrics(b.style.fontSize).b,r=p<0&&-k,y=q<0&&-l,fa=p*q<0,r+=q*m*(fa?1-h:h),y-=p*m*(j?fa?h:1-h:1),i&&(r-=k*h*(p<0?-1:1),j&&(y-=l*h*(q<0?-1:1)),F(b,{textAlign:g})),this.xCorr=r,this.yCorr=y;F(b,{left:e+r+"px",top:f+y+"px"});this.cTT=$}}else this.alignOnAdd= -!0},updateTransform:function(){var a=this.translateX||0,b=this.translateY||0,c=this.inverted,d=this.rotation,e=[];c&&(a+=this.attr("width"),b+=this.attr("height"));(a||b)&&e.push("translate("+a+","+b+")");c?e.push("rotate(90) scale(-1,1)"):d&&e.push("rotate("+d+" "+(this.x||0)+" "+(this.y||0)+")");e.length&&z(this.element,"transform",e.join(" "))},toFront:function(){var a=this.element;a.parentNode.appendChild(a);return this},align:function(a,b,c){a?(this.alignOptions=a,this.alignByTranslate=b,c|| -this.renderer.alignedObjects.push(this)):(a=this.alignOptions,b=this.alignByTranslate);var c=o(c,this.renderer),d=a.align,e=a.verticalAlign,f=(c.x||0)+(a.x||0),g=(c.y||0)+(a.y||0),h={};/^(right|center)$/.test(d)&&(f+=(c.width-(a.width||0))/{right:1,center:2}[d]);h[b?"translateX":"x"]=t(f);/^(bottom|middle)$/.test(e)&&(g+=(c.height-(a.height||0))/({bottom:1,middle:2}[e]||1));h[b?"translateY":"y"]=t(g);this[this.placed?"animate":"attr"](h);this.placed=!0;this.alignAttr=h;return this},getBBox:function(a){var b, -c,d=this.rotation;c=this.element;var e=d*Eb;if(c.namespaceURI==="http://www.w3.org/2000/svg"||this.renderer.forExport){try{b=c.getBBox?u({},c.getBBox()):{width:c.offsetWidth,height:c.offsetHeight}}catch(f){}if(!b||b.width<0)b={width:0,height:0};a=b.width;c=b.height;if(d)b.width=M(c*da(e))+M(a*X(e)),b.height=M(c*X(e))+M(a*da(e))}else b=this.htmlGetBBox(a);return b},show:function(){return this.attr({visibility:"visible"})},hide:function(){return this.attr({visibility:"hidden"})},add:function(a){var b= -this.renderer,c=a||b,d=c.element||b.box,e=d.childNodes,f=this.element,g=z(f,"zIndex"),h;this.parentInverted=a&&a.inverted;this.textStr!==void 0&&b.buildText(this);if(g)c.handleZ=!0,g=w(g);if(c.handleZ)for(c=0;cg||!s(g)&&s(b))){d.insertBefore(f,a);h=!0;break}h||d.appendChild(f);this.added=!0;E(this,"add");return this},safeRemoveChild:function(a){var b=a.parentNode;b&&b.removeChild(a)},destroy:function(){var a=this,b=a.element||{},c=a.shadows,d=a.box, -e,f;b.onclick=b.onmouseout=b.onmouseover=b.onmousemove=null;Fa(a);if(a.clipPath)a.clipPath=a.clipPath.destroy();if(a.stops){for(f=0;f/g,'').replace(/<(i|em)>/g,'').replace(//g,"").split(//g),d=b.childNodes,e=/style="([^"]+)"/,f=/href="([^"]+)"/,g=z(b,"x"),h=a.styles,i=h&&w(h.width),j=h&&h.lineHeight,k,h=d.length,l=[];h--;)b.removeChild(d[h]);i&&!a.added&&this.box.appendChild(b);c[c.length-1]===""&&c.pop();n(c,function(c,d){var h,fa=0,r,c=c.replace(//g,"|||");h=c.split("|||");n(h,function(c){if(c!==""||h.length===1){var m={},n=B.createElementNS("http://www.w3.org/2000/svg", -"tspan");e.test(c)&&z(n,"style",c.match(e)[1].replace(/(;| |^)color([ :])/,"$1fill$2"));f.test(c)&&(z(n,"onclick",'location.href="'+c.match(f)[1]+'"'),F(n,{cursor:"pointer"}));c=(c.replace(/<(.|\n)*?>/g,"")||" ").replace(/</g,"<").replace(/>/g,">");n.appendChild(B.createTextNode(c));fa?m.dx=3:m.x=g;if(!fa){if(d){!Da&&a.renderer.forExport&&F(n,{display:"block"});r=N.getComputedStyle&&w(N.getComputedStyle(k,null).getPropertyValue("line-height"));if(!r||isNaN(r)){var o;if(!(o=j))if(!(o=k.offsetHeight))l[d]= -b.getBBox().height,o=t(l[d]-(l[d-1]||0))||18;r=o}z(n,"dy",r)}k=n}z(n,m);b.appendChild(n);fa++;if(i)for(var c=c.replace(/-/g,"- ").split(" "),H=[];c.length||H.length;)o=a.getBBox().width,m=o>i,!m||c.length===1?(c=H,H=[],c.length&&(n=B.createElementNS("http://www.w3.org/2000/svg","tspan"),z(n,{dy:j||16,x:g}),b.appendChild(n),o>i&&(i=o))):(n.removeChild(n.firstChild),H.unshift(c.pop())),c.length&&n.appendChild(B.createTextNode(c.join(" ").replace(/- /g,"-")))}})})},button:function(a,b,c,d,e,f,g){var h= -this.label(a,b,c),i=0,j,k,l,m,p,a={x1:0,y1:0,x2:0,y2:1},e=C(la("stroke-width",1,"stroke","#999","fill",la("linearGradient",a,"stops",[[0,"#FFF"],[1,"#DDD"]]),"r",3,"padding",3,"style",la("color","black")),e);l=e.style;delete e.style;f=C(e,la("stroke","#68A","fill",la("linearGradient",a,"stops",[[0,"#FFF"],[1,"#ACF"]])),f);m=f.style;delete f.style;g=C(e,la("stroke","#68A","fill",la("linearGradient",a,"stops",[[0,"#9BD"],[1,"#CDF"]])),g);p=g.style;delete g.style;I(h.element,"mouseenter",function(){h.attr(f).css(m)}); -I(h.element,"mouseleave",function(){j=[e,f,g][i];k=[l,m,p][i];h.attr(j).css(k)});h.setState=function(a){(i=a)?a===2&&h.attr(g).css(p):h.attr(e).css(l)};return h.on("click",function(){d.call(h)}).attr(e).css(u({cursor:"default"},l))},crispLine:function(a,b){a[1]===a[4]&&(a[1]=a[4]=t(a[1])+b%2/2);a[2]===a[5]&&(a[2]=a[5]=t(a[2])+b%2/2);return a},path:function(a){var b={fill:U};Ja(a)?b.d=a:aa(a)&&u(b,a);return this.createElement("path").attr(b)},circle:function(a,b,c){a=aa(a)?a:{x:a,y:b,r:c};return this.createElement("circle").attr(a)}, -arc:function(a,b,c,d,e,f){if(aa(a))b=a.y,c=a.r,d=a.innerR,e=a.start,f=a.end,a=a.x;return this.symbol("arc",a||0,b||0,c||0,c||0,{innerR:d||0,start:e||0,end:f||0})},rect:function(a,b,c,d,e,f){e=aa(a)?a.r:e;e=this.createElement("rect").attr({rx:e,ry:e,fill:U});return e.attr(aa(a)?a:e.crisp(f,a,b,x(c,0),x(d,0)))},setSize:function(a,b,c){var d=this.alignedObjects,e=d.length;this.width=a;this.height=b;for(this.boxWrapper[o(c,!0)?"animate":"attr"]({width:a,height:b});e--;)d[e].align()},g:function(a){var b= -this.createElement("g");return s(a)?b.attr({"class":"highcharts-"+a}):b},image:function(a,b,c,d,e){var f={preserveAspectRatio:U};arguments.length>1&&u(f,{x:b,y:c,width:d,height:e});f=this.createElement("image").attr(f);f.element.setAttributeNS?f.element.setAttributeNS("http://www.w3.org/1999/xlink","href",a):f.element.setAttribute("hc-svg-href",a);return f},symbol:function(a,b,c,d,e,f){var g,h=this.symbols[a],h=h&&h(t(b),t(c),d,e,f),i=/^url\((.*?)\)$/,j,k;h?(g=this.path(h),u(g,{symbolName:a,x:b,y:c, -width:d,height:e}),f&&u(g,f)):i.test(a)&&(k=function(a,b){a.attr({width:b[0],height:b[1]});a.alignByTranslate||a.translate(-t(b[0]/2),-t(b[1]/2))},j=a.match(i)[1],a=Hb[j],g=this.image(j).attr({x:b,y:c}),a?k(g,a):(g.attr({width:0,height:0}),S("img",{onload:function(){k(g,Hb[j]=[this.width,this.height])},src:j})));return g},symbols:{circle:function(a,b,c,d){var e=0.166*c;return["M",a+c/2,b,"C",a+c+e,b,a+c+e,b+d,a+c/2,b+d,"C",a-e,b+d,a-e,b,a+c/2,b,"Z"]},square:function(a,b,c,d){return["M",a,b,"L",a+ -c,b,a+c,b+d,a,b+d,"Z"]},triangle:function(a,b,c,d){return["M",a+c/2,b,"L",a+c,b+d,a,b+d,"Z"]},"triangle-down":function(a,b,c,d){return["M",a,b,"L",a+c,b,a+c/2,b+d,"Z"]},diamond:function(a,b,c,d){return["M",a+c/2,b,"L",a+c,b+d/2,a+c/2,b+d,a,b+d/2,"Z"]},arc:function(a,b,c,d,e){var f=e.start,c=e.r||c||d,g=e.end-1.0E-6,d=e.innerR,h=e.open,i=X(f),j=da(f),k=X(g),g=da(g),e=e.end-f');if(b)c=b===ia||b==="span"||b==="img"?c.join(""):a.prepVML(c),this.element=S(c);this.renderer=a;this.attrSetters={}},add:function(a){var b=this.renderer,c=this.element,d=b.box,d=a?a.element||a:d;a&&a.inverted&&b.invertChild(c,d);Ca&&d.gVis==="hidden"&&F(c,{visibility:"hidden"});d.appendChild(c);this.added=!0;this.alignOnAdd&& -!this.deferUpdateTransform&&this.updateTransform();E(this,"add");return this},toggleChildren:function(a,b){for(var c=a.childNodes,d=c.length;d--;)F(c[d],{visibility:b}),c[d].nodeName==="DIV"&&this.toggleChildren(c[d],b)},updateTransform:va.prototype.htmlUpdateTransform,attr:function(a,b){var c,d,e,f=this.element||{},g=f.style,h=f.nodeName,i=this.renderer,j=this.symbolName,k,l=this.shadows,m,p=this.attrSetters,q=this;ra(a)&&s(b)&&(c=a,a={},a[c]=b);if(ra(a))c=a,q=c==="strokeWidth"||c==="stroke-width"? -this.strokeweight:this[c];else for(c in a)if(d=a[c],m=!1,e=p[c]&&p[c](d,c),e!==!1&&d!==null){e!==A&&(d=e);if(j&&/^(x|y|r|start|end|width|height|innerR|anchorX|anchorY)/.test(c))k||(this.symbolAttr(a),k=!0),m=!0;else if(c==="d"){d=d||[];this.d=d.join(" ");e=d.length;for(m=[];e--;)m[e]=Ka(d[e])?t(d[e]*10)-5:d[e]==="Z"?"x":d[e];d=m.join(" ")||"x";f.path=d;if(l)for(e=l.length;e--;)l[e].path=l[e].cutOff?this.cutOffPath(d,l[e].cutOff):d;m=!0}else if(c==="zIndex"||c==="visibility"){if(Ca&&c==="visibility"&& -h==="DIV")f.gVis=d,this.toggleChildren(f,d),d==="visible"&&(d=null);d&&(g[c]=d);m=!0}else if(c==="width"||c==="height")d=x(0,d),this[c]=d,this.updateClipping?(this[c]=d,this.updateClipping()):g[c]=d,m=!0;else if(c==="x"||c==="y")this[c]=d,g[{x:"left",y:"top"}[c]]=d;else if(c==="class")f.className=d;else if(c==="stroke")d=i.color(d,f,c),c="strokecolor";else if(c==="stroke-width"||c==="strokeWidth")f.stroked=d?!0:!1,c="strokeweight",this[c]=d,Ka(d)&&(d+="px");else if(c==="dashstyle")(f.getElementsByTagName("stroke")[0]|| -S(i.prepVML([""]),null,null,f))[c]=d||"solid",this.dashstyle=d,m=!0;else if(c==="fill")h==="SPAN"?g.color=d:(f.filled=d!==U?!0:!1,d=i.color(d,f,c),c="fillcolor");else if(h==="shape"&&c==="rotation")this[c]=d;else if(c==="translateX"||c==="translateY"||c==="rotation")this[c]=d,this.updateTransform(),m=!0;else if(c==="text")this.bBox=null,f.innerHTML=d,m=!0;if(l&&c==="visibility")for(e=l.length;e--;)l[e].style[c]=d;m||(Ca?f[c]=d:z(f,c,d))}return q},clip:function(a){var b=this,c=a.members,d= -b.element,e=d.parentNode;c.push(b);b.destroyClip=function(){za(c,b)};e&&e.className==="highcharts-tracker"&&!Ca&&F(d,{visibility:"hidden"});return b.css(a.getCSS(b))},css:va.prototype.htmlCss,safeRemoveChild:function(a){a.parentNode&&Qa(a)},destroy:function(){this.destroyClip&&this.destroyClip();return va.prototype.destroy.apply(this)},empty:function(){for(var a=this.element.childNodes,b=a.length,c;b--;)c=a[b],c.parentNode.removeChild(c)},on:function(a,b){this.element["on"+a]=function(){var a=N.event; -a.target=a.srcElement;b(a)};return this},cutOffPath:function(a,b){var c,a=a.split(/[ ,]/);c=a.length;if(c===9||c===11)a[c-4]=a[c-2]=w(a[c-2])-10*b;return a.join(" ")},shadow:function(a,b,c){var d=[],e=this.element,f=this.renderer,g,h=e.style,i,j=e.path,k,l;j&&typeof j.value!=="string"&&(j="x");l=j;if(a){for(a=1;a<=3;a++){k=7-2*a;c&&(l=this.cutOffPath(j.value,k+0.5));i=[''];g= -S(f.prepVML(i),null,{left:w(h.left)+1,top:w(h.top)+1});if(c)g.cutOff=k+1;i=[''];S(f.prepVML(i),null,null,g);b?b.element.appendChild(g):e.parentNode.insertBefore(g,e);d.push(g)}this.shadows=d}return this}};ka=ca(va,ka);var ha={Element:ka,isIE8:ya.indexOf("MSIE 8.0")>-1,init:function(a,b,c){var d,e;this.alignedObjects=[];d=this.createElement(ia);e=d.element;e.style.position="relative";a.appendChild(d.element);this.box=e;this.boxWrapper=d;this.setSize(b,c, -!1);if(!B.namespaces.hcv)B.namespaces.add("hcv","urn:schemas-microsoft-com:vml"),B.createStyleSheet().cssText="hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke{ behavior:url(#default#VML); display: inline-block; } "},isHidden:function(){return!this.box.offsetWidth},clipRect:function(a,b,c,d){var e=this.createElement();return u(e,{members:[],left:a,top:b,width:c,height:d,getCSS:function(a){var b=a.inverted,c=this.top,d=this.left,e=d+this.width,k=c+this.height,c={clip:"rect("+t(b?d:c)+"px,"+t(b?k: -e)+"px,"+t(b?e:k)+"px,"+t(b?c:d)+"px)"};!b&&Ca&&a.element.nodeName!=="IMG"&&u(c,{width:e+"px",height:k+"px"});return c},updateClipping:function(){n(e.members,function(a){a.css(e.getCSS(a))})}})},color:function(a,b,c){var d,e=/^rgba/,f,g=U;a&&a.linearGradient?f="gradient":a&&a.radialGradient&&(f="pattern");if(f){var h,i,j=a.linearGradient||a.radialGradient,k,l,m,p,q,o,r="",a=a.stops,y,s=[];l=a[0];y=a[a.length-1];l[0]>0&&a.unshift([0,l[1]]);y[0]<1&&a.push([1,y[1]]);n(a,function(a,b){e.test(a[1])?(d= -pa(a[1]),h=d.get("rgb"),i=d.get("a")):(h=a[1],i=1);s.push(a[0]*100+"% "+h);b?(p=i,q=h):(m=i,o=h)});f==="gradient"?(k=j.x1||j[0]||0,a=j.y1||j[1]||0,l=j.x2||j[2]||0,j=j.y2||j[3]||0,k=90-L.atan((j-a)/(l-k))*180/xa):(g=j.r*2,r='src="http://code.highcharts.com/gfx/radial-gradient.png" size="'+g+","+g+'" origin="0.5,0.5" position="'+j.cx+","+j.cy+'" color2="'+o+'" ',g=q);c==="fill"?(c=[''], -S(this.prepVML(c),null,null,b)):g=h}else if(e.test(a)&&b.tagName!=="IMG")d=pa(a),c=["<",c,' opacity="',d.get("a"),'"/>'],S(this.prepVML(c),null,null,b),g=d.get("rgb");else{b=b.getElementsByTagName(c);if(b.length)b[0].opacity=1;g=a}return g},prepVML:function(a){var b=this.isIE8,a=a.join("");b?(a=a.replace("/>",' xmlns="urn:schemas-microsoft-com:vml" />'),a=a.indexOf('style="')===-1?a.replace("/>",' style="display:inline-block;behavior:url(#default#VML);" />'):a.replace('style="','style="display:inline-block;behavior:url(#default#VML);')): -a=a.replace("<","1&&f.css({left:b,top:c,width:d, -height:e});return f},rect:function(a,b,c,d,e,f){if(aa(a))b=a.y,c=a.width,d=a.height,f=a.strokeWidth,a=a.x;var g=this.symbol("rect");g.r=e;return g.attr(g.crisp(f,a,b,x(c,0),x(d,0)))},invertChild:function(a,b){var c=b.style;F(a,{flip:"x",left:w(c.width)-1,top:w(c.height)-1,rotation:-90})},symbols:{arc:function(a,b,c,d,e){var f=e.start,g=e.end,h=e.r||c||d,c=X(f),d=da(f),i=X(g),j=da(g),k=e.innerR,l=0.08/h,m=k&&0.1/k||0;if(g-f===0)return["x"];else 2*xa-g+fj&&(c=!1)):h+k>m&&(h=m-k,d&&h+l0&&b.height>0){f=C({align:c&&k&&"center",x:c?!k&&4:10,verticalAlign:!c&&k&&"middle",y:c?k?16:10:k?6:-4,rotation:c&&!k&&90},f);if(!g)a.label=g=u.text(f.text,0,0).attr({align:f.textAlign||f.align,rotation:f.rotation, -zIndex:y}).css(f.style).add();b=[q[1],q[4],o(q[6],q[1])];q=[q[2],q[5],o(q[7],q[2])];c=Pa(b);k=Pa(q);g.align(f,!1,{x:c,y:k,width:Aa(b)-c,height:Aa(q)-k});g.show()}else g&&g.hide();return a},destroy:function(){za(this.axis.plotLinesAndBands,this);Ba(this,this.axis)}};Cb.prototype={destroy:function(){Ba(this,this.axis)},setTotal:function(a){this.cum=this.total=a},render:function(a){var b=this.options.formatter.call(this);this.label?this.label.attr({text:b,visibility:"hidden"}):this.label=this.axis.chart.renderer.text(b, -0,0).css(this.options.style).attr({align:this.textAlign,rotation:this.options.rotation,visibility:"hidden"}).add(a)},setOffset:function(a,b){var c=this.axis,d=c.chart,e=d.inverted,f=this.isNegative,g=c.translate(this.total,0,0,0,1),c=c.translate(0),c=M(g-c),h=d.xAxis[0].translate(this.x)+a,d=d.plotHeight,e={x:e?f?g:g-c:h,y:e?d-h-b:f?d-g-c:d-g,width:e?c:b,height:e?b:c};this.label&&this.label.align(this.alignOptions,null,e).attr({visibility:"visible"})}};ob.prototype={defaultOptions:{dateTimeLabelFormats:{millisecond:"%H:%M:%S.%L", -second:"%H:%M:%S",minute:"%H:%M",hour:"%H:%M",day:"%e. %b",week:"%e. %b",month:"%b '%y",year:"%Y"},endOnTick:!1,gridLineColor:"#C0C0C0",labels:G,lineColor:"#C0D0E0",lineWidth:1,minPadding:0.01,maxPadding:0.01,minorGridLineColor:"#E0E0E0",minorGridLineWidth:1,minorTickColor:"#A0A0A0",minorTickLength:2,minorTickPosition:"outside",startOfWeek:1,startOnTick:!1,tickColor:"#C0D0E0",tickLength:5,tickmarkPlacement:"between",tickPixelInterval:100,tickPosition:"outside",tickWidth:1,title:{align:"middle",style:{color:"#6D869F", -fontWeight:"bold"}},type:"linear"},defaultYAxisOptions:{endOnTick:!0,gridLineWidth:1,tickPixelInterval:72,showLastLabel:!0,labels:{align:"right",x:-8,y:3},lineWidth:0,maxPadding:0.05,minPadding:0.05,startOnTick:!0,tickWidth:0,title:{rotation:270,text:"Y-values"},stackLabels:{enabled:!1,formatter:function(){return this.total},style:G.style}},defaultLeftAxisOptions:{labels:{align:"right",x:-8,y:null},title:{rotation:270}},defaultRightAxisOptions:{labels:{align:"left",x:8,y:null},title:{rotation:90}}, -defaultBottomAxisOptions:{labels:{align:"center",x:0,y:14},title:{rotation:0}},defaultTopAxisOptions:{labels:{align:"center",x:0,y:-5},title:{rotation:0}},init:function(a,b){var c=b.isX;this.horiz=a.inverted?!c:c;this.xOrY=(this.isXAxis=c)?"x":"y";this.opposite=b.opposite;this.side=this.horiz?this.opposite?0:2:this.opposite?1:3;this.setOptions(b);var d=this.options,e=d.type,f=e==="datetime";this.labelFormatter=d.labels.formatter||this.defaultLabelFormatter;this.staggerLines=this.horiz&&d.labels.staggerLines; -this.userOptions=b;this.minPixelPadding=0;this.chart=a;this.reversed=d.reversed;this.categories=d.categories;this.isLog=e==="logarithmic";this.isLinked=s(d.linkedTo);this.isDatetimeAxis=f;this.ticks={};this.minorTicks={};this.plotLinesAndBands=[];this.alternateBands={};this.len=0;this.minRange=this.userMinRange=d.minRange||d.maxZoom;this.range=d.range;this.offset=d.offset||0;this.stacks={};this.min=this.max=null;var g,d=this.options.events;a.axes.push(this);a[c?"xAxis":"yAxis"].push(this);this.series= -[];if(a.inverted&&c&&this.reversed===A)this.reversed=!0;this.removePlotLine=this.removePlotBand=this.removePlotBandOrLine;this.addPlotLine=this.addPlotBand=this.addPlotBandOrLine;for(g in d)I(this,g,d[g]);if(this.isLog)this.val2lin=ma,this.lin2val=ba},setOptions:function(a){this.options=C(this.defaultOptions,this.isXAxis?{}:this.defaultYAxisOptions,[this.defaultTopAxisOptions,this.defaultRightAxisOptions,this.defaultBottomAxisOptions,this.defaultLeftAxisOptions][this.side],a)},defaultLabelFormatter:function(){var a= -this.axis,b=this.value,c=a.tickInterval,d=this.dateTimeLabelFormat;return a.categories?b:d?db(d,b):c%1E6===0?b/1E6+"M":c%1E3===0?b/1E3+"k":b>=1E3?Xa(b,0):Xa(b,-1)},getSeriesExtremes:function(){var a=this,b=a.chart,c=a.stacks,d=[],e=[],f;a.dataMin=a.dataMax=null;n(a.series,function(g){if(g.visible||!b.options.chart.ignoreHiddenSeries){var h=g.options,i,j,k,l,m,p,q,n,r,y=h.threshold,t,u=[],v=0;if(a.isLog&&y<=0)y=h.threshold=null;if(a.isXAxis){if(h=g.xData,h.length)a.dataMin=O(o(a.dataMin,h[0]),Pa(h)), -a.dataMax=x(o(a.dataMax,h[0]),Aa(h))}else{var H,J,K,C=g.cropped,Ha=g.xAxis.getExtremes(),w=!!g.modifyValue;i=h.stacking;a.usePercentage=i==="percent";if(i)m=h.stack,l=g.type+o(m,""),p="-"+l,g.stackKey=l,j=d[l]||[],d[l]=j,k=e[p]||[],e[p]=k;if(a.usePercentage)a.dataMin=0,a.dataMax=99;h=g.processedXData;q=g.processedYData;t=q.length;for(f=0;f=Ha.min&&(h[f-1]||n)<=Ha.max))if(n=r.length)for(;n--;)r[n]!==null&&(u[v++]=r[n]);else u[v++]=r;if(!a.usePercentage&&u.length)a.dataMin=O(o(a.dataMin,u[0]),Pa(u)),a.dataMax=x(o(a.dataMax,u[0]),Aa(u));if(s(y))if(a.dataMin>=y)a.dataMin=y,a.ignoreMinPadding=!0;else if(a.dataMaxe+this.width)l= -!0}else if(c=e,h=k-this.right,gf+this.height)l=!0;return l?null:d.renderer.crispLine(["M",c,g,"L",h,i],b||0)},getPlotBandPath:function(a,b){var c=this.getPlotLinePath(b),d=this.getPlotLinePath(a);d&&c?d.push(c[4],c[5],c[1],c[2]):d=null;return d},getLinearTickPositions:function(a,b,c){for(var d,b=ja(W(b/a)*a),c=ja(wa(c/a)*a),e=[];b<=c;){e.push(b);b=ja(b+a);if(b===d)break;d=b}return e},getLogTickPositions:function(a,b,c,d){var e=this.options,f=this.len,g=[];if(!d)this._minorAutoInterval=null; -if(a>=0.5)a=t(a),g=this.getLinearTickPositions(a,b,c);else if(a>=0.08)for(var f=W(b),h,i,j,k,l,e=a>0.3?[1,2,4]:a>0.15?[1,2,4,6,8]:[1,2,3,4,5,6,7,8,9];fb&&g.push(k),k>c&&(l=!0),k=j}else if(b=ba(b),c=ba(c),a=e[d?"minorTickInterval":"tickInterval"],a=o(a==="auto"?null:a,this._minorAutoInterval,(c-b)*(e.tickPixelInterval/(d?5:1))/((d?f/this.tickPositions.length:f)||1)),a=gb(a,null,L.pow(10,W(L.log(a)/L.LN10))),g=Ea(this.getLinearTickPositions(a, -b,c),ma),!d)this._minorAutoInterval=a/5;if(!d)this.tickInterval=a;return g},getMinorTickPositions:function(){var a=this.tickPositions,b=this.minorTickInterval,c=[],d,e;if(this.isLog){e=a.length;for(d=1;d=this.minRange,f,g,h,i,j;if(this.isXAxis&&this.minRange===A&& -!this.isLog)s(a.min)||s(a.max)?this.minRange=null:(n(this.series,function(a){i=a.xData;for(g=j=a.xIncrement?1:i.length-1;g>0;g--)if(h=i[g]-i[g-1],f===A||h0||!b.ignoreMaxPadding))b.max+=c*j}b.tickInterval=b.min===b.max||b.min===void 0||b.max===void 0?1:h&&!l&&m===b.linkedParent.options.tickPixelInterval?b.linkedParent.tickInterval:o(l,p?1:(b.max-b.min)*m/(b.len||1));g&&!a&&n(b.series,function(a){a.processData(b.min!==b.oldMin||b.max!==b.oldMax)}); -b.setAxisTranslation();b.beforeSetTickPositions&&b.beforeSetTickPositions();if(b.postProcessTickInterval)b.tickInterval=b.postProcessTickInterval(b.tickInterval);if(!f&&!e&&(a=L.pow(10,W(L.log(b.tickInterval)/L.LN10)),!s(d.tickInterval)))b.tickInterval=gb(b.tickInterval,null,a,d);b.minorTickInterval=d.minorTickInterval==="auto"&&b.tickInterval?b.tickInterval/5:d.minorTickInterval;b.tickPositions=i=d.tickPositions||i&&i.apply(b,[b.min,b.max]);if(!i)i=f?(b.getNonLinearTimeTicks||Pb)(Ob(b.tickInterval, -d.units),b.min,b.max,d.startOfWeek,b.ordinalPositions,b.closestPointRange,!0):e?b.getLogTickPositions(b.tickInterval,b.min,b.max):b.getLinearTickPositions(b.tickInterval,b.min,b.max),b.tickPositions=i;if(!h)e=i[0],f=i[i.length-1],d.startOnTick?b.min=e:b.min>e&&i.shift(),d.endOnTick?b.max=f:b.maxb[d]&&this.options.alignTicks!==!1)b[d]= -c.length;a.maxTicks=b},adjustTickAmount:function(){var a=this.xOrY,b=this.tickPositions,c=this.chart.maxTicks;if(c&&c[a]&&!this.isDatetimeAxis&&!this.categories&&!this.isLinked&&this.options.alignTicks!==!1){var d=this.tickAmount,e=b.length;this.tickAmount=a=c[a];if(ea||a===null?a=c:b=a.min&&b<=a.max)j[b]||(j[b]=new Sa(a,b)),r&&j[b].isNew&&j[b].render(c,!0),j[b].isActive=!0,j[b].render(c)}),p&&n(g,function(b,c){if(c%2===0&&b1|| -M(b-c.currentY)>1?function(){c.move(a,b)}:null},hide:function(){if(!this.tooltipIsHidden){var a=this.chart.hoverPoints;this.label.hide();a&&n(a,function(a){a.setState()});this.chart.hoverPoints=null;this.tooltipIsHidden=!0}},hideCrosshairs:function(){n(this.crosshairs,function(a){a&&a.hide()})},getAnchor:function(a,b){var c,d=this.chart,e=d.inverted,f=0,g=0,a=na(a);c=a[0].tooltipPos;c||(n(a,function(a){f+=a.plotX;g+=a.plotLow?(a.plotLow+a.plotHigh)/2:a.plotY}),f/=a.length,g/=a.length,c=[e?d.plotWidth- -g:f,this.shared&&!e&&a.length>1&&b?b.chartY-d.plotTop:e?d.plotHeight-f:g]);return Ea(c,t)},getPosition:function(a,b,c){var d=this.chart,e=d.plotLeft,f=d.plotTop,g=d.plotWidth,h=d.plotHeight,i=o(this.options.distance,12),j=c.plotX,c=c.plotY,d=j+e+(d.inverted?i:-a-i),k=c-b+f+15,l;d<7&&(d=e+j+i);d+a>e+g&&(d-=d+a-(e+g),k=c-b+f-i,l=!0);k=k&&c<=k+b&&(k=c+f+i));k+b>f+h&&(k=x(f,f+h-b-i));return{x:d,y:k}},refresh:function(a,b){function c(){var a=this.points||na(this),b=a[0].series,c;c=[b.tooltipHeaderFormatter(a[0].key)]; -n(a,function(a){b=a.series;c.push(b.tooltipFormatter&&b.tooltipFormatter(a)||a.point.tooltipFormatter(b.tooltipOptions.pointFormat))});c.push(f.footerFormat||"");return c.join("")}var d=this.chart,e=this.label,f=this.options,g,h,i,j={},k,l=[];k=f.formatter||c;var j=d.hoverPoints,m,p=f.crosshairs;i=this.shared;h=this.getAnchor(a,b);g=h[0];h=h[1];i&&(!a.series||!a.series.noSharedTooltip)?(j&&n(j,function(a){a.setState()}),d.hoverPoints=a,n(a,function(a){a.setState("hover");l.push(a.getLabelConfig())}), -j={x:a[0].category,y:a[0].y},j.points=l,a=a[0]):j=a.getLabelConfig();k=k.call(j);j=a.series;i=i||!j.isCartesian||j.tooltipOutsidePlot||d.isInsidePlot(g,h);k===!1||!i?this.hide():(this.tooltipIsHidden&&e.show(),e.attr({text:k}),m=f.borderColor||a.color||j.color||"#606060",e.attr({stroke:m}),e=(f.positioner||this.getPosition).call(this,e.width,e.height,{plotX:g,plotY:h}),this.move(t(e.x),t(e.y)),this.tooltipIsHidden=!1);if(p){p=na(p);for(e=p.length;e--;)if(i=a.series[e?"yAxis":"xAxis"],p[e]&&i)if(i= -i.getPlotLinePath(e?o(a.stackY,a.y):a.x,1),this.crosshairs[e])this.crosshairs[e].attr({d:i,visibility:"visible"});else{j={"stroke-width":p[e].width||1,stroke:p[e].color||"#C0C0C0",zIndex:p[e].zIndex||2};if(p[e].dashStyle)j.dashstyle=p[e].dashStyle;this.crosshairs[e]=d.renderer.path(i).attr(j).add()}}E(d,"tooltipRefresh",{text:k,x:g+d.plotLeft,y:h+d.plotTop,borderColor:m})},tick:function(){this.tooltipTick&&this.tooltipTick()}};Db.prototype={normalizeMouseEvent:function(a){var b,c,d,a=a||N.event;if(!a.target)a.target= -a.srcElement;if(a.originalEvent)a=a.originalEvent;if(a.event)a=a.event;d=a.touches?a.touches.item(0):a;this.chartPosition=b=Jb(this.chart.container);d.pageX===A?(c=a.x,b=a.y):(c=d.pageX-b.left,b=d.pageY-b.top);return u(a,{chartX:t(c),chartY:t(b)})},getMouseCoordinates:function(a){var b={xAxis:[],yAxis:[]},c=this.chart;n(c.axes,function(d){var e=d.isXAxis;b[e?"xAxis":"yAxis"].push({axis:d,value:d.translate((c.inverted?!e:e)?a.chartX-c.plotLeft:c.plotHeight-a.chartY+c.plotTop,!0)})});return b},onmousemove:function(a){var b= -this.chart,c=b.series,d,e,f=b.hoverPoint,g=b.hoverSeries,h,i,j=b.chartWidth,k=b.inverted?b.plotHeight+b.plotTop-a.chartY:a.chartX-b.plotLeft;if(b.tooltip&&this.options.tooltip.shared&&(!g||!g.noSharedTooltip)){e=[];h=c.length;for(i=0;ij&&e.splice(h,1);if(e.length&&e[0].plotX!==this.hoverX)b.tooltip.refresh(e, -a),this.hoverX=e[0].plotX}if(g&&g.tracker&&(d=g.tooltipPoints[k])&&d!==f)d.onMouseOver()},resetTracker:function(a){var b=this.chart,c=b.hoverSeries,d=b.hoverPoint,e=b.hoverPoints||d,b=b.tooltip;(a=a&&b&&e)&&na(e)[0].plotX===A&&(a=!1);if(a)b.refresh(e);else{if(d)d.onMouseOut();if(c)c.onMouseOut();b&&(b.hide(),b.hideCrosshairs());this.hoverX=null}},setDOMEvents:function(){function a(){if(b.selectionMarker){var f={xAxis:[],yAxis:[]},g=b.selectionMarker.getBBox(),h=g.x-c.plotLeft,l=g.y-c.plotTop,m;e&& -(n(c.axes,function(a){if(a.options.zoomEnabled!==!1){var b=a.isXAxis,d=c.inverted?!b:b,e=a.translate(d?h:c.plotHeight-l-g.height,!0,0,0,1),d=a.translate(d?h+g.width:c.plotHeight-l,!0,0,0,1);!isNaN(e)&&!isNaN(d)&&(f[b?"xAxis":"yAxis"].push({axis:a,min:O(e,d),max:x(e,d)}),m=!0)}}),m&&E(c,"selection",f,function(a){c.zoom(a)}));b.selectionMarker=b.selectionMarker.destroy()}if(c)F(d,{cursor:"auto"}),c.cancelClick=e,c.mouseIsDown=e=!1;P(B,ea?"touchend":"mouseup",a)}var b=this,c=b.chart,d=c.container,e, -f=b.zoomX&&!c.inverted||b.zoomY&&c.inverted,g=b.zoomY&&!c.inverted||b.zoomX&&c.inverted;b.hideTooltipOnMouseMove=function(a){Kb(a);b.chartPosition&&c.hoverSeries&&c.hoverSeries.isCartesian&&!c.isInsidePlot(a.pageX-b.chartPosition.left-c.plotLeft,a.pageY-b.chartPosition.top-c.plotTop)&&b.resetTracker()};b.hideTooltipOnMouseLeave=function(){b.resetTracker();b.chartPosition=null};d.onmousedown=function(d){d=b.normalizeMouseEvent(d);!ea&&d.preventDefault&&d.preventDefault();c.mouseIsDown=!0;c.cancelClick= -!1;c.mouseDownX=b.mouseDownX=d.chartX;b.mouseDownY=d.chartY;I(B,ea?"touchend":"mouseup",a)};var h=function(a){if(!a||!(a.touches&&a.touches.length>1)){a=b.normalizeMouseEvent(a);if(!ea)a.returnValue=!1;var d=a.chartX,h=a.chartY,l=!c.isInsidePlot(d-c.plotLeft,h-c.plotTop);ea&&a.type==="touchstart"&&(z(a.target,"isTracker")?c.runTrackerClick||a.preventDefault():!c.runChartClick&&!l&&a.preventDefault());if(l)dc.plotLeft+c.plotWidth&&(d=c.plotLeft+c.plotWidth),hc.plotTop+c.plotHeight&&(h=c.plotTop+c.plotHeight);if(c.mouseIsDown&&a.type!=="touchstart"){if(e=Math.sqrt(Math.pow(b.mouseDownX-d,2)+Math.pow(b.mouseDownY-h,2)),e>10){a=c.isInsidePlot(b.mouseDownX-c.plotLeft,b.mouseDownY-c.plotTop);if(c.hasCartesianSeries&&(b.zoomX||b.zoomY)&&a&&!b.selectionMarker)b.selectionMarker=c.renderer.rect(c.plotLeft,c.plotTop,f?1:c.plotWidth,g?1:c.plotHeight,0).attr({fill:b.options.chart.selectionMarkerFill||"rgba(69,114,167,0.25)",zIndex:7}).add();if(b.selectionMarker&& -f){var m=d-b.mouseDownX;b.selectionMarker.attr({width:M(m),x:(m>0?0:m)+b.mouseDownX})}b.selectionMarker&&g&&(h-=b.mouseDownY,b.selectionMarker.attr({height:M(h),y:(h>0?0:h)+b.mouseDownY}));a&&!b.selectionMarker&&b.options.chart.panning&&c.pan(d)}}else if(!l)b.onmousemove(a);return l||!c.hasCartesianSeries}};d.onmousemove=h;I(d,"mouseleave",b.hideTooltipOnMouseLeave);I(B,"mousemove",b.hideTooltipOnMouseMove);d.ontouchstart=function(a){if(b.zoomX||b.zoomY)d.onmousedown(a);h(a)};d.ontouchmove=h;d.ontouchend= -function(){e&&b.resetTracker()};d.onclick=function(a){var d=c.hoverPoint,e,f,a=b.normalizeMouseEvent(a);a.cancelBubble=!0;if(!c.cancelClick)d&&(z(a.target,"isTracker")||z(a.target.parentNode,"isTracker"))?(e=d.plotX,f=d.plotY,u(d,{pageX:b.chartPosition.left+c.plotLeft+(c.inverted?c.plotWidth-f:e),pageY:b.chartPosition.top+c.plotTop+(c.inverted?c.plotHeight-e:f)}),E(d.series,"click",u(a,{point:d})),d.firePointEvent("click",a)):(u(a,b.getMouseCoordinates(a)),c.isInsidePlot(a.chartX-c.plotLeft,a.chartY- -c.plotTop)&&E(c,"click",a))}},destroy:function(){var a=this.chart,b=a.container;if(a.trackerGroup)a.trackerGroup=a.trackerGroup.destroy();P(b,"mouseleave",this.hideTooltipOnMouseLeave);P(B,"mousemove",this.hideTooltipOnMouseMove);b.onclick=b.onmousedown=b.onmousemove=b.ontouchstart=b.ontouchend=b.ontouchmove=null;clearInterval(this.tooltipInterval)},init:function(a,b){if(!a.trackerGroup)a.trackerGroup=a.renderer.g("tracker").attr({zIndex:9}).add();if(b.enabled)a.tooltip=new pb(a,b),this.tooltipInterval= -setInterval(function(){a.tooltip.tick()},32);this.setDOMEvents()}};qb.prototype={init:function(a){var b=this,c=b.options=a.options.legend;if(c.enabled){var d=c.itemStyle,e=o(c.padding,8),f=c.itemMarginTop||0;b.baseline=w(d.fontSize)+3+f;b.itemStyle=d;b.itemHiddenStyle=C(d,c.itemHiddenStyle);b.itemMarginTop=f;b.padding=e;b.initialItemX=e;b.initialItemY=e-5;b.maxItemWidth=0;b.chart=a;b.itemHeight=0;b.lastLineHeight=0;b.render();I(b.chart,"endResize",function(){b.positionCheckboxes()})}},colorizeItem:function(a, -b){var c=this.options,d=a.legendItem,e=a.legendLine,f=a.legendSymbol,g=this.itemHiddenStyle.color,c=b?c.itemStyle.color:g,g=b?a.color:g;d&&d.css({fill:c});e&&e.attr({stroke:g});f&&f.attr({stroke:g,fill:g})},positionItem:function(a){var b=this.options,c=b.symbolPadding,b=!b.rtl,d=a._legendItemPos,e=d[0],d=d[1],f=a.checkbox;a.legendGroup&&a.legendGroup.translate(b?e:this.legendWidth-e-2*c-4,d);if(f)f.x=e,f.y=d},destroyItem:function(a){var b=a.checkbox;n(["legendItem","legendLine","legendSymbol","legendGroup"], -function(b){a[b]&&a[b].destroy()});b&&Qa(a.checkbox)},destroy:function(){var a=this.group,b=this.box;if(b)this.box=b.destroy();if(a)this.group=a.destroy()},positionCheckboxes:function(){var a=this;n(a.allItems,function(b){var c=b.checkbox,d=a.group.alignAttr;c&&F(c,{left:d.translateX+b.legendItemWidth+c.x-20+"px",top:d.translateY+c.y+3+"px"})})},renderItem:function(a){var q;var b=this,c=b.chart,d=c.renderer,e=b.options,f=e.layout==="horizontal",g=e.symbolWidth,h=e.symbolPadding,i=b.itemStyle,j=b.itemHiddenStyle, -k=b.padding,l=!e.rtl,m=e.width,p=e.itemMarginBottom||0,n=b.itemMarginTop,o=b.initialItemX,r=a.legendItem,s=a.series||a,t=s.options,u=t.showCheckbox;if(!r&&(a.legendGroup=d.g("legend-item").attr({zIndex:1}).add(b.scrollGroup),s.drawLegendSymbol(b,a),a.legendItem=r=d.text(e.labelFormatter.call(a),l?g+h:-h,b.baseline,e.useHTML).css(C(a.visible?i:j)).attr({align:l?"left":"right",zIndex:2}).add(a.legendGroup),a.legendGroup.on("mouseover",function(){a.setState("hover");r.css(b.options.itemHoverStyle)}).on("mouseout", -function(){r.css(a.visible?i:j);a.setState()}).on("click",function(b){var c=function(){a.setVisible()},b={browserEvent:b};a.firePointEvent?a.firePointEvent("legendItemClick",b,c):E(a,"legendItemClick",b,c)}),b.colorizeItem(a,a.visible),t&&u))a.checkbox=S("input",{type:"checkbox",checked:a.selected,defaultChecked:a.selected},e.itemCheckboxStyle,c.container),I(a.checkbox,"click",function(b){E(a,"checkboxClick",{checked:b.target.checked},function(){a.select()})});d=r.getBBox();q=a.legendItemWidth=e.itemWidth|| -g+h+d.width+k+(u?20:0),e=q;b.itemHeight=g=d.height;if(f&&b.itemX-o+e>(m||c.chartWidth-2*k-o))b.itemX=o,b.itemY+=n+b.lastLineHeight+p,b.lastLineHeight=0;b.maxItemWidth=x(b.maxItemWidth,e);b.lastItemY=n+b.itemY+p;b.lastLineHeight=x(g,b.lastLineHeight);a._legendItemPos=[b.itemX,b.itemY];f?b.itemX+=e:(b.itemY+=n+g+p,b.lastLineHeight=g);b.offsetWidth=m||x(f?b.itemX-o:e,b.offsetWidth)},render:function(){var a=this,b=a.chart,c=b.renderer,d=a.group,e,f,g,h,i=a.box,j=a.options,k=a.padding,l=j.borderWidth, -m=j.backgroundColor;a.itemX=a.initialItemX;a.itemY=a.initialItemY;a.offsetWidth=0;a.lastItemY=0;if(!d)a.group=d=c.g("legend").attr({zIndex:7}).add(),a.contentGroup=c.g().attr({zIndex:1}).add(d),a.scrollGroup=c.g().add(a.contentGroup),a.clipRect=c.clipRect(0,0,9999,b.chartHeight),a.contentGroup.clip(a.clipRect);e=[];n(b.series,function(a){var b=a.options;b.showInLegend&&(e=e.concat(a.legendItems||(b.legendType==="point"?a.data:a)))});Qb(e,function(a,b){return(a.options.legendIndex||0)-(b.options.legendIndex|| -0)});j.reversed&&e.reverse();a.allItems=e;a.display=f=!!e.length;n(e,function(b){a.renderItem(b)});g=j.width||a.offsetWidth;h=a.lastItemY+a.lastLineHeight;h=a.handleOverflow(h);if(l||m){g+=k;h+=k;if(i){if(g>0&&h>0)i[i.isNew?"attr":"animate"](i.crisp(null,null,null,g,h)),i.isNew=!1}else a.box=i=c.rect(0,0,g,h,j.borderRadius,l||0).attr({stroke:j.borderColor,"stroke-width":l||0,fill:m||U}).add(d).shadow(j.shadow),i.isNew=!0;i[f?"show":"hide"]()}a.legendWidth=g;a.legendHeight=h;n(e,function(b){a.positionItem(b)}); -f&&d.align(u({width:g,height:h},j),!0,b.spacingBox);b.isResizing||this.positionCheckboxes()},handleOverflow:function(a){var b=this,c=this.chart,d=c.renderer,e=this.options,f=e.y,f=c.spacingBox.height+(e.verticalAlign==="top"?-f:f)-this.padding,g=e.maxHeight,h=this.clipRect,i=e.navigation,j=o(i.animation,!0),k=i.arrowSize||12,l=this.nav;e.layout==="horizontal"&&(f/=2);g&&(f=O(f,g));if(a>f){this.clipHeight=c=f-20;this.pageCount=wa(a/c);this.currentPage=o(this.currentPage,1);this.fullHeight=a;h.attr({height:c}); -if(!l)this.nav=l=d.g().attr({zIndex:1}).add(this.group),this.up=d.symbol("triangle",0,0,k,k).on("click",function(){b.scroll(-1,j)}).add(l),this.pager=d.text("",15,10).css(i.style).add(l),this.down=d.symbol("triangle-down",0,0,k,k).on("click",function(){b.scroll(1,j)}).add(l);b.scroll(0);a=f}else l&&(h.attr({height:c.chartHeight}),l.hide(),this.scrollGroup.attr({translateY:1}));return a},scroll:function(a,b){var c=this.pageCount,d=this.currentPage+a,e=this.clipHeight,f=this.options.navigation,g=f.activeColor, -f=f.inactiveColor,h=this.pager,i=this.padding;d>c&&(d=c);if(d>0)b!==A&&ua(b,this.chart),this.nav.attr({translateX:i,translateY:e+7,visibility:"visible"}),this.up.attr({fill:d===1?f:g}).css({cursor:d===1?"default":"pointer"}),h.attr({text:d+"/"+this.pageCount}),this.down.attr({x:18+this.pager.getBBox().width,fill:d===c?f:g}).css({cursor:d===c?"default":"pointer"}),this.scrollGroup.animate({translateY:-O(e*(d-1),this.fullHeight-e+i)+1}),h.attr({text:d+"/"+c}),this.currentPage=d}};rb.prototype={initSeries:function(a){var b= -this.options.chart,b=new Y[a.type||b.type||b.defaultSeriesType];b.init(this,a);return b},addSeries:function(a,b,c){var d=this;a&&(ua(c,d),b=o(b,!0),E(d,"addSeries",{options:a},function(){d.initSeries(a);d.isDirtyLegend=!0;b&&d.redraw()}))},isInsidePlot:function(a,b){return a>=0&&a<=this.plotWidth&&b>=0&&b<=this.plotHeight},adjustTickAmounts:function(){this.options.chart.alignTicks!==!1&&n(this.axes,function(a){a.adjustTickAmount()});this.maxTicks=null},redraw:function(a){var b=this.axes,c=this.series, -d=this.tracker,e=this.legend,f=this.isDirtyLegend,g,h=this.isDirtyBox,i=c.length,j=i,k=this.clipRect,l=this.renderer,m=l.isHidden();ua(a,this);for(m&&this.cloneRenderTo();j--;)if(a=c[j],a.isDirty&&a.options.stacking){g=!0;break}if(g)for(j=i;j--;)if(a=c[j],a.options.stacking)a.isDirty=!0;n(c,function(a){a.isDirty&&a.options.legendType==="point"&&(f=!0)});if(f&&e.options.enabled)e.render(),this.isDirtyLegend=!1;if(this.hasCartesianSeries){if(!this.isResizing)this.maxTicks=null,n(b,function(a){a.setScale()}); -this.adjustTickAmounts();this.getMargins();n(b,function(a){if(a.isDirtyExtremes)a.isDirtyExtremes=!1,E(a,"afterSetExtremes",a.getExtremes());if(a.isDirty||h||g)a.redraw(),h=!0})}h&&(this.drawChartBox(),k&&(Fa(k),k.animate({width:this.plotSizeX,height:this.plotSizeY+1})));n(c,function(a){a.isDirty&&a.visible&&(!a.isCartesian||a.xAxis)&&a.redraw()});d&&d.resetTracker&&d.resetTracker(!0);l.draw();E(this,"redraw");m&&this.cloneRenderTo(!0)},showLoading:function(a){var b=this.options,c=this.loadingDiv, -d=b.loading;if(!c)this.loadingDiv=c=S(ia,{className:"highcharts-loading"},u(d.style,{left:this.plotLeft+"px",top:this.plotTop+"px",width:this.plotWidth+"px",height:this.plotHeight+"px",zIndex:10,display:U}),this.container),this.loadingSpan=S("span",null,d.labelStyle,c);this.loadingSpan.innerHTML=a||b.lang.loading;if(!this.loadingShown)F(c,{opacity:0,display:""}),eb(c,{opacity:d.style.opacity},{duration:d.showDuration||0}),this.loadingShown=!0},hideLoading:function(){var a=this.options,b=this.loadingDiv; -b&&eb(b,{opacity:0},{duration:a.loading.hideDuration||100,complete:function(){F(b,{display:U})}});this.loadingShown=!1},get:function(a){var b=this.axes,c=this.series,d,e;for(d=0;dO(e.dataMin,e.min)&&c19?this.containerHeight:400)},cloneRenderTo:function(a){var b=this.renderToClone,c=this.container;a?b&&(this.renderTo.appendChild(c),Qa(b),delete this.renderToClone):(c&&this.renderTo.removeChild(c),this.renderToClone=b=this.renderTo.cloneNode(0),F(b,{position:"absolute",top:"-9999px",display:"block"}), -B.body.appendChild(b),c&&b.appendChild(c))},getContainer:function(){var a,b=this.options.chart,c,d,e;this.renderTo=a=b.renderTo;e="highcharts-"+sb++;if(ra(a))this.renderTo=a=B.getElementById(a);a||mb(13,!0);a.innerHTML="";a.offsetWidth||this.cloneRenderTo();this.getChartSize();c=this.chartWidth;d=this.chartHeight;this.container=a=S(ia,{className:"highcharts-container"+(b.className?" "+b.className:""),id:e},u({position:"relative",overflow:"hidden",width:c+"px",height:d+"px",textAlign:"left",lineHeight:"normal"}, -b.style),this.renderToClone||a);this.renderer=b.forExport?new qa(a,c,d,!0):new Ta(a,c,d);ga&&this.renderer.create(this,a,c,d)},getMargins:function(){var a=this.options.chart,b=a.spacingTop,c=a.spacingRight,d=a.spacingBottom,a=a.spacingLeft,e,f=this.legend,g=this.optionsMarginTop,h=this.optionsMarginLeft,i=this.optionsMarginRight,j=this.optionsMarginBottom,k=this.chartTitleOptions,l=this.chartSubtitleOptions,m=this.options.legend,p=o(m.margin,10),q=m.x,t=m.y,r=m.align,y=m.verticalAlign;this.resetMargins(); -e=this.axisOffset;if((this.title||this.subtitle)&&!s(this.optionsMarginTop))if(l=x(this.title&&!k.floating&&!k.verticalAlign&&k.y||0,this.subtitle&&!l.floating&&!l.verticalAlign&&l.y||0))this.plotTop=x(this.plotTop,l+o(k.margin,15)+b);if(f.display&&!m.floating)if(r==="right"){if(!s(i))this.marginRight=x(this.marginRight,f.legendWidth-q+p+c)}else if(r==="left"){if(!s(h))this.plotLeft=x(this.plotLeft,f.legendWidth+q+p+a)}else if(y==="top"){if(!s(g))this.plotTop=x(this.plotTop,f.legendHeight+t+p+b)}else if(y=== -"bottom"&&!s(j))this.marginBottom=x(this.marginBottom,f.legendHeight-t+p+d);this.extraBottomMargin&&(this.marginBottom+=this.extraBottomMargin);this.extraTopMargin&&(this.plotTop+=this.extraTopMargin);this.hasCartesianSeries&&n(this.axes,function(a){a.getOffset()});s(h)||(this.plotLeft+=e[3]);s(g)||(this.plotTop+=e[0]);s(j)||(this.marginBottom+=e[2]);s(i)||(this.marginRight+=e[1]);this.setChartSize()},initReflow:function(){function a(a){var g=c.width||Va(d,"width"),h=c.height||Va(d,"height"),a=a? -a.target:N;if(g&&h&&(a===N||a===B)){if(g!==b.containerWidth||h!==b.containerHeight)clearTimeout(e),e=setTimeout(function(){b.resize(g,h,!1)},100);b.containerWidth=g;b.containerHeight=h}}var b=this,c=b.options.chart,d=b.renderTo,e;I(N,"resize",a);I(b,"destroy",function(){P(N,"resize",a)})},fireEndResize:function(){var a=this;a&&E(a,"endResize",null,function(){a.isResizing-=1})},resize:function(a,b,c){var d,e,f=this.title,g=this.subtitle;this.isResizing+=1;ua(c,this);this.oldChartHeight=this.chartHeight; -this.oldChartWidth=this.chartWidth;if(s(a))this.chartWidth=d=t(a);if(s(b))this.chartHeight=e=t(b);F(this.container,{width:d+"px",height:e+"px"});this.renderer.setSize(d,e,c);this.plotWidth=d-this.plotLeft-this.marginRight;this.plotHeight=e-this.plotTop-this.marginBottom;this.maxTicks=null;n(this.axes,function(a){a.isDirty=!0;a.setScale()});n(this.series,function(a){a.isDirty=!0});this.isDirtyBox=this.isDirtyLegend=!0;this.getMargins();a=this.spacingBox;f&&f.align(null,null,a);g&&g.align(null,null, -a);this.redraw(c);this.oldChartHeight=null;E(this,"resize");Ra===!1?this.fireEndResize():setTimeout(this.fireEndResize,Ra&&Ra.duration||500)},setChartSize:function(){var a=this.inverted,b=this.chartWidth,c=this.chartHeight,d=this.options.chart,e=d.spacingTop,f=d.spacingRight,g=d.spacingBottom,d=d.spacingLeft;this.plotLeft=t(this.plotLeft);this.plotTop=t(this.plotTop);this.plotWidth=t(b-this.plotLeft-this.marginRight);this.plotHeight=t(c-this.plotTop-this.marginBottom);this.plotSizeX=a?this.plotHeight: -this.plotWidth;this.plotSizeY=a?this.plotWidth:this.plotHeight;this.spacingBox={x:d,y:e,width:b-d-f,height:c-e-g};n(this.axes,function(a){a.setAxisSize();a.setAxisTranslation()})},resetMargins:function(){var a=this.options.chart,b=a.spacingRight,c=a.spacingBottom,d=a.spacingLeft;this.plotTop=o(this.optionsMarginTop,a.spacingTop);this.marginRight=o(this.optionsMarginRight,b);this.marginBottom=o(this.optionsMarginBottom,c);this.plotLeft=o(this.optionsMarginLeft,d);this.axisOffset=[0,0,0,0]},drawChartBox:function(){var a= -this.options.chart,b=this.renderer,c=this.chartWidth,d=this.chartHeight,e=this.chartBackground,f=this.plotBackground,g=this.plotBorder,h=this.plotBGImage,i=a.borderWidth||0,j=a.backgroundColor,k=a.plotBackgroundColor,l=a.plotBackgroundImage,m,p={x:this.plotLeft,y:this.plotTop,width:this.plotWidth,height:this.plotHeight};m=i+(a.shadow?8:0);if(i||j)if(e)e.animate(e.crisp(null,null,null,c-m,d-m));else{e={fill:j||U};if(i)e.stroke=a.borderColor,e["stroke-width"]=i;this.chartBackground=b.rect(m/2,m/2,c- -m,d-m,a.borderRadius,i).attr(e).add().shadow(a.shadow)}if(k)f?f.animate(p):this.plotBackground=b.rect(this.plotLeft,this.plotTop,this.plotWidth,this.plotHeight,0).attr({fill:k}).add().shadow(a.plotShadow);if(l)h?h.animate(p):this.plotBGImage=b.image(l,this.plotLeft,this.plotTop,this.plotWidth,this.plotHeight).add();if(a.plotBorderWidth)g?g.animate(g.crisp(null,this.plotLeft,this.plotTop,this.plotWidth,this.plotHeight)):this.plotBorder=b.rect(this.plotLeft,this.plotTop,this.plotWidth,this.plotHeight, -0,a.plotBorderWidth).attr({stroke:a.plotBorderColor,"stroke-width":a.plotBorderWidth,zIndex:4}).add();this.isDirtyBox=!1},propFromSeries:function(){var a=this,b=a.options.chart,c,d=a.options.series,e,f;n(["inverted","angular","polar"],function(g){c=Y[b.type||b.defaultSeriesType];f=a[g]||b[g]||c&&c.prototype[g];for(e=d&&d.length;!f&&e--;)(c=Y[d[e].type])&&c.prototype[g]&&(f=!0);a[g]=f})},render:function(){var a=this,b=a.axes,c=a.renderer,d=a.options,e=d.labels,d=d.credits,f;a.setTitle();a.legend=new qb(a); -n(b,function(a){a.setScale()});a.getMargins();a.maxTicks=null;n(b,function(a){a.setTickPositions(!0);a.setMaxTicks()});a.adjustTickAmounts();a.getMargins();a.drawChartBox();a.hasCartesianSeries&&n(b,function(a){a.render()});if(!a.seriesGroup)a.seriesGroup=c.g("series-group").attr({zIndex:3}).add();n(a.series,function(a){a.translate();a.setTooltipPoints();a.render()});e.items&&n(e.items,function(){var b=u(e.style,this.style),d=w(b.left)+a.plotLeft,f=w(b.top)+a.plotTop+12;delete b.left;delete b.top; -c.text(this.html,d,f).attr({zIndex:2}).css(b).add()});if(d.enabled&&!a.credits)f=d.href,a.credits=c.text(d.text,0,0).on("click",function(){if(f)location.href=f}).attr({align:d.position.align,zIndex:8}).css(d.style).add().align(d.position);a.hasRendered=!0},destroy:function(){var a=this,b=a.axes,c=a.series,d=a.container,e,f=d&&d.parentNode;if(a!==null){E(a,"destroy");P(a);for(e=b.length;e--;)b[e]=b[e].destroy();for(e=c.length;e--;)c[e]=c[e].destroy();n("title,subtitle,chartBackground,plotBackground,plotBGImage,plotBorder,seriesGroup,clipRect,credits,tracker,scroller,rangeSelector,legend,resetZoomButton,tooltip,renderer".split(","), -function(b){var c=a[b];c&&(a[b]=c.destroy())});if(d)d.innerHTML="",P(d),f&&Qa(d),d=null;for(e in a)delete a[e];a=a.options=null}},firstRender:function(){var a=this,b=a.options,c=a.callback;if(!Da&&N==N.top&&B.readyState!=="complete"||ga&&!N.canvg)ga?Nb.push(function(){a.firstRender()},b.global.canvasToolsURL):B.attachEvent("onreadystatechange",function(){B.detachEvent("onreadystatechange",a.firstRender);B.readyState==="complete"&&a.firstRender()});else{a.getContainer();E(a,"init");if(Highcharts.RangeSelector&& -b.rangeSelector.enabled)a.rangeSelector=new Highcharts.RangeSelector(a);a.resetMargins();a.setChartSize();a.propFromSeries();a.getAxes();n(b.series||[],function(b){a.initSeries(b)});if(Highcharts.Scroller&&(b.navigator.enabled||b.scrollbar.enabled))a.scroller=new Highcharts.Scroller(a);a.tracker=new Db(a,b);a.render();a.renderer.draw();c&&c.apply(a,[a]);n(a.callbacks,function(b){b.apply(a,[a])});a.cloneRenderTo(!0);E(a,"load")}},init:function(a){var b=this.options.chart,c;b.reflow!==!1&&I(this,"load", -this.initReflow);if(a)for(c in a)I(this,c,a[c]);this.xAxis=[];this.yAxis=[];this.animation=ga?!1:o(b.animation,!0);this.setSize=this.resize;this.pointCount=0;this.counters=new Ab;this.firstRender()}};rb.prototype.callbacks=[];var Wa=function(){};Wa.prototype={init:function(a,b,c){var d=a.chart.counters;this.series=a;this.applyOptions(b,c);this.pointAttr={};if(a.options.colorByPoint){b=a.chart.options.colors;if(!this.options)this.options={};this.color=this.options.color=this.color||b[d.color++];d.wrapColor(b.length)}a.chart.pointCount++; -return this},applyOptions:function(a,b){var c=this.series,d=typeof a;this.config=a;if(d==="number"||a===null)this.y=a;else if(typeof a[0]==="number")this.x=a[0],this.y=a[1];else if(d==="object"&&typeof a.length!=="number"){if(u(this,a),this.options=a,a.dataLabels)c._hasPointLabels=!0}else if(typeof a[0]==="string")this.name=a[0],this.y=a[1];if(this.x===A)this.x=b===A?c.autoIncrement():b},destroy:function(){var a=this.series.chart,b=a.hoverPoints,c;a.pointCount--;if(b&&(this.setState(),za(b,this), -!b.length))a.hoverPoints=null;if(this===a.hoverPoint)this.onMouseOut();if(this.graphic||this.dataLabel)P(this),this.destroyElements();this.legendItem&&a.legend.destroyItem(this);for(c in this)this[c]=null},destroyElements:function(){for(var a="graphic,tracker,dataLabel,group,connector,shadowGroup".split(","),b,c=6;c--;)b=a[c],this[b]&&(this[b]=this[b].destroy())},getLabelConfig:function(){return{x:this.category,y:this.y,key:this.name||this.category,series:this.series,point:this,percentage:this.percentage, -total:this.total||this.stackTotal}},select:function(a,b){var c=this,d=c.series.chart,a=o(a,!c.selected);c.firePointEvent(a?"select":"unselect",{accumulate:b},function(){c.selected=a;c.setState(a&&"select");b||n(d.getSelectedPoints(),function(a){if(a.selected&&a!==c)a.selected=!1,a.setState(""),a.firePointEvent("unselect")})})},onMouseOver:function(){var a=this.series,b=a.chart,c=b.tooltip,d=b.hoverPoint;if(d&&d!==this)d.onMouseOut();this.firePointEvent("mouseOver");c&&(!c.shared||a.noSharedTooltip)&& -c.refresh(this);this.setState("hover");b.hoverPoint=this},onMouseOut:function(){this.firePointEvent("mouseOut");this.setState();this.series.chart.hoverPoint=null},tooltipFormatter:function(a){var b=this.series,c=b.tooltipOptions,d=a.match(/\{(series|point)\.[a-zA-Z]+\}/g),e=/[{\.}]/,f,g,h,i,j={y:0,open:0,high:0,low:0,close:0,percentage:1,total:1};c.valuePrefix=c.valuePrefix||c.yPrefix;c.valueDecimals=c.valueDecimals||c.yDecimals;c.valueSuffix=c.valueSuffix||c.ySuffix;for(i in d)g=d[i],ra(g)&&g!== -a&&(h=(" "+g).split(e),f={point:this,series:b}[h[1]],h=h[2],f===this&&j.hasOwnProperty(h)?(f=j[h]?h:"value",f=(c[f+"Prefix"]||"")+Xa(this[h],o(c[f+"Decimals"],-1))+(c[f+"Suffix"]||"")):f=f[h],a=a.replace(g,f));return a},update:function(a,b,c){var d=this,e=d.series,f=d.graphic,g,h=e.data,i=h.length,j=e.chart,b=o(b,!0);d.firePointEvent("update",{options:a},function(){d.applyOptions(a);aa(a)&&(e.getAttribs(),f&&f.attr(d.pointAttr[e.state]));for(g=0;ga+1&&b.push(d.slice(a+1,g)),a=g):g===e-1&&b.push(d.slice(a+1,g+1))});this.segments=b},setOptions:function(a){var b=this.chart.options,c=b.plotOptions,d=a.data;a.data=null;c=C(c[this.type],c.series,a);c.data=a.data=d;this.tooltipOptions=C(b.tooltip,c.tooltip);return c},getColor:function(){var a= -this.options,b=this.chart.options.colors,c=this.chart.counters;this.color=a.color||!a.colorByPoint&&b[c.color++]||"gray";c.wrapColor(b.length)},getSymbol:function(){var a=this.options.marker,b=this.chart,c=b.options.symbols,b=b.counters;this.symbol=a.symbol||c[b.symbol++];if(/^url/.test(this.symbol))a.radius=0;b.wrapSymbol(c.length)},drawLegendSymbol:function(a){var b=this.options,c=b.marker,d=a.options.symbolWidth,e=this.chart.renderer,f=this.legendGroup,a=a.baseline,g;if(b.lineWidth){g={"stroke-width":b.lineWidth}; -if(b.dashStyle)g.dashstyle=b.dashStyle;this.legendLine=e.path(["M",0,a-4,"L",d,a-4]).attr(g).add(f)}if(c&&c.enabled)b=c.radius,this.legendSymbol=e.symbol(this.symbol,d/2-b,a-4-b,2*b,2*b).attr(this.pointAttr[""]).add(f)},addPoint:function(a,b,c,d){var e=this.data,f=this.graph,g=this.area,h=this.chart,i=this.xData,j=this.yData,k=f&&f.shift||0,l=this.options.data;ua(d,h);if(f&&c)f.shift=k+1;if(g){if(c)g.shift=k+1;g.isArea=!0}b=o(b,!0);d={series:this};this.pointClass.prototype.applyOptions.apply(d,[a]); -i.push(d.x);j.push(this.valueCount===4?[d.open,d.high,d.low,d.close]:d.y);l.push(a);c&&(e[0]&&e[0].remove?e[0].remove(!1):(e.shift(),i.shift(),j.shift(),l.shift()));this.getAttribs();this.isDirtyData=this.isDirty=!0;b&&h.redraw()},setData:function(a,b){var c=this.points,d=this.options,e=this.initialColor,f=this.chart,g=null,h=this.xAxis,i=this.pointClass.prototype;this.xIncrement=null;this.pointRange=h&&h.categories&&1||d.pointRange;if(s(e))f.counters.color=e;var j=[],k=[],l=a?a.length:[],m=this.valueCount; -if(l>(d.turboThreshold||1E3)){for(e=0;g===null&&ek||this.forceCrop))if(a=i.getExtremes(),i=a.min,k=a.max,b[d-1]k)b=[],c=[];else if(b[0]k){for(a=0;a=i){e=x(0,a-1);break}for(;ak){f=a+1;break}b=b.slice(e,f);c=c.slice(e,f);g=!0}for(a=b.length-1;a>0;a--)if(d=b[a]-b[a-1],d>0&&(h===A||d=0&&d<=e;)h[d++]=f}this.tooltipPoints=h}},tooltipHeaderFormatter:function(a){var b=this.tooltipOptions,c=b.xDateFormat,d=this.xAxis,e=d&&d.options.type==="datetime",f;if(e&&!c)for(f in D)if(D[f]>=d.closestPointRange){c=b.dateTimeLabelFormats[f];break}return b.headerFormat.replace("{point.key}",e?db(c,a):a).replace("{series.name}", -this.name).replace("{series.color}",this.color)},onMouseOver:function(){var a=this.chart,b=a.hoverSeries;if(ea||!a.mouseIsDown){if(b&&b!==this)b.onMouseOut();this.options.events.mouseOver&&E(this,"mouseOver");this.setState("hover");a.hoverSeries=this}},onMouseOut:function(){var a=this.options,b=this.chart,c=b.tooltip,d=b.hoverPoint;if(d)d.onMouseOut();this&&a.events.mouseOut&&E(this,"mouseOut");c&&!a.stickyTracking&&!c.shared&&c.hide();this.setState();b.hoverSeries=null},animate:function(a){var b= -this.chart,c=this.clipRect,d=this.options.animation;d&&!aa(d)&&(d={});if(a){if(!c.isAnimating)c.attr("width",0),c.isAnimating=!0}else c.animate({width:b.plotSizeX},d),this.animate=null},drawPoints:function(){var a,b=this.points,c=this.chart,d,e,f,g,h,i,j,k;if(this.options.marker.enabled)for(f=b.length;f--;)if(g=b[f],d=g.plotX,e=g.plotY,k=g.graphic,e!==A&&!isNaN(e))if(a=g.pointAttr[g.selected?"select":""],h=a.r,i=o(g.marker&&g.marker.symbol,this.symbol),j=i.indexOf("url")===0,k)k.animate(u({x:d-h, -y:e-h},k.symbolName?{width:2*h,height:2*h}:{}));else if(h>0||j)g.graphic=c.renderer.symbol(i,d-h,e-h,2*h,2*h).attr(a).add(this.group)},convertAttribs:function(a,b,c,d){var e=this.pointAttrToOptions,f,g,h={},a=a||{},b=b||{},c=c||{},d=d||{};for(f in e)g=e[f],h[f]=o(a[g],b[f],c[f],d[f]);return h},getAttribs:function(){var a=this,b=Z[a.type].marker?a.options.marker:a.options,c=b.states,d=c.hover,e,f=a.color,g={stroke:f,fill:f},h=a.points||[],i=[],j,k=a.pointAttrToOptions,l;a.options.marker?(d.radius= -d.radius||b.radius+2,d.lineWidth=d.lineWidth||b.lineWidth+1):d.color=d.color||pa(d.color||f).brighten(d.brightness).get();i[""]=a.convertAttribs(b,g);n(["hover","select"],function(b){i[b]=a.convertAttribs(c[b],i[""])});a.pointAttr=i;for(f=h.length;f--;){g=h[f];if((b=g.options&&g.options.marker||g.options)&&b.enabled===!1)b.radius=0;e=!1;if(g.options)for(l in k)s(b[k[l]])&&(e=!0);if(e){j=[];c=b.states||{};e=c.hover=c.hover||{};if(!a.options.marker)e.color=pa(e.color||g.options.color).brighten(e.brightness|| -d.brightness).get();j[""]=a.convertAttribs(b,i[""]);j.hover=a.convertAttribs(c.hover,i.hover,j[""]);j.select=a.convertAttribs(c.select,i.select,j[""])}else j=i;g.pointAttr=j}},destroy:function(){var a=this,b=a.chart,c=a.clipRect,d=/AppleWebKit\/533/.test(ya),e,f,g=a.data||[],h,i,j;E(a,"destroy");P(a);n(["xAxis","yAxis"],function(b){if(j=a[b])za(j.series,a),j.isDirty=!0});a.legendItem&&a.chart.legend.destroyItem(a);for(f=g.length;f--;)(h=g[f])&&h.destroy&&h.destroy();a.points=null;if(c&&c!==b.clipRect)a.clipRect= -c.destroy();n("area,graph,dataLabelsGroup,group,tracker,trackerGroup".split(","),function(b){a[b]&&(e=d&&b==="group"?"hide":"destroy",a[b][e]())});if(b.hoverSeries===a)b.hoverSeries=null;za(b.series,a);for(i in a)delete a[i]},drawDataLabels:function(){var a=this,b=a.options,c=b.dataLabels;if(c.enabled||a._hasPointLabels){var d,e,f=a.points,g,h,i,j=a.dataLabelsGroup,k=a.chart,l=a.xAxis,l=l?l.left:k.plotLeft,m=a.yAxis,m=m?m.top:k.plotTop,p=k.renderer,q=k.inverted,u=a.type,r=b.stacking,y=u==="column"|| -u==="bar",x=c.verticalAlign===null,w=c.y===null,v=p.fontMetrics(c.style.fontSize),H=v.h,J=v.b,K,z;y&&(v={top:J,middle:J-H/2,bottom:-H+J},r?(x&&(c=C(c,{verticalAlign:"middle"})),w&&(c=C(c,{y:v[c.verticalAlign]}))):x?c=C(c,{verticalAlign:"top"}):w&&(c=C(c,{y:v[c.verticalAlign]})));j?j.translate(l,m):j=a.dataLabelsGroup=p.g("data-labels").attr({visibility:a.visible?"visible":"hidden",zIndex:6}).translate(l,m).add();h=c;n(f,function(f){K=f.dataLabel;c=h;(g=f.options)&&g.dataLabels&&(c=C(c,g.dataLabels)); -if(z=c.enabled){var l=f.barX&&f.barX+f.barW/2||o(f.plotX,-999),m=o(f.plotY,-999),n=c.y===null?f.y>=b.threshold?-H+J:J:c.y;d=(q?k.plotWidth-m:l)+c.x;e=t((q?k.plotHeight-l:m)+n)}if(K&&a.isCartesian&&(!k.isInsidePlot(d,e)||!z))f.dataLabel=K.destroy();else if(z){var l=c.align,v;i=c.formatter.call(f.getLabelConfig(),c);u==="column"&&(d+={left:-1,right:1}[l]*f.barW/2||0);!r&&q&&f.y<0&&(l="right",d-=10);c.style.color=o(c.color,c.style.color,a.color,"black");if(K)K.attr({text:i}).animate({x:d,y:e});else if(s(i)){l= -{align:l,fill:c.backgroundColor,stroke:c.borderColor,"stroke-width":c.borderWidth,r:c.borderRadius||0,rotation:c.rotation,padding:c.padding,zIndex:1};for(v in l)l[v]===A&&delete l[v];K=f.dataLabel=p[c.rotation?"text":"label"](i,d,e,null,null,null,c.useHTML,!0).attr(l).css(c.style).add(j).shadow(c.shadow)}if(y&&b.stacking&&K)v=f.barX,l=f.barY,m=f.barW,f=f.barH,K.align(c,null,{x:q?k.plotWidth-l-f:v,y:q?k.plotHeight-v-m:l,width:q?f:m,height:q?m:f})}})}},getSegmentPath:function(a){var b=this,c=[];n(a, -function(d,e){b.getPointSpline?c.push.apply(c,b.getPointSpline(a,d,e)):(c.push(e?"L":"M"),e&&b.options.step&&c.push(d.plotX,a[e-1].plotY),c.push(d.plotX,d.plotY))});return c},drawGraph:function(){var a=this,b=a.options,c=a.graph,d=[],e=a.group,f=b.lineColor||a.color,g=b.lineWidth,h=b.dashStyle,i,j=a.chart.renderer,k=[];n(a.segments,function(b){i=a.getSegmentPath(b);b.length>1?d=d.concat(i):k.push(b[0])});a.graphPath=d;a.singlePoints=k;if(c)Fa(c),c.animate({d:d});else if(g){c={stroke:f,"stroke-width":g}; -if(h)c.dashstyle=h;a.graph=j.path(d).attr(c).add(e).shadow(b.shadow)}},invertGroups:function(){function a(){var a={width:b.yAxis.len,height:b.xAxis.len};c.attr(a).invert();d&&d.attr(a).invert()}var b=this,c=b.group,d=b.trackerGroup,e=b.chart;I(e,"resize",a);I(b,"destroy",function(){P(e,"resize",a)});a();b.invertGroups=a},createGroup:function(){var a=this.chart;(this.group=a.renderer.g("series")).attr({visibility:this.visible?"visible":"hidden",zIndex:this.options.zIndex}).translate(this.xAxis.left, -this.yAxis.top).add(a.seriesGroup);this.createGroup=Sb},render:function(){var a=this,b=a.chart,c,d=a.options,e=d.clip!==!1,f=d.animation,f=(d=f&&a.animate)?f&&f.duration||500:0,g=a.clipRect,h=b.renderer;if(!g&&(g=a.clipRect=!b.hasRendered&&b.clipRect?b.clipRect:h.clipRect(0,0,b.plotSizeX,b.plotSizeY+1),!b.clipRect))b.clipRect=g;a.createGroup();c=a.group;a.drawDataLabels();d&&a.animate(!0);a.getAttribs();a.drawGraph&&a.drawGraph();a.drawPoints();a.options.enableMouseTracking!==!1&&a.drawTracker(); -b.inverted&&a.invertGroups();e&&!a.hasRendered&&(c.clip(g),a.trackerGroup&&a.trackerGroup.clip(b.clipRect));d&&a.animate();setTimeout(function(){g.isAnimating=!1;if((c=a.group)&&g!==b.clipRect&&g.renderer){if(e)c.clip(a.clipRect=b.clipRect);g.destroy()}},f);a.isDirty=a.isDirtyData=!1;a.hasRendered=!0},redraw:function(){var a=this.chart,b=this.isDirtyData,c=this.group;c&&(a.inverted&&c.attr({width:a.plotWidth,height:a.plotHeight}),c.animate({translateX:this.xAxis.left,translateY:this.yAxis.top})); -this.translate();this.setTooltipPoints(!0);this.render();b&&E(this,"updatedData")},setState:function(a){var b=this.options,c=this.graph,d=b.states,b=b.lineWidth,a=a||"";if(this.state!==a)this.state=a,d[a]&&d[a].enabled===!1||(a&&(b=d[a].lineWidth||b+1),c&&!c.dashstyle&&c.attr({"stroke-width":b},a?0:500))},setVisible:function(a,b){var c=this.chart,d=this.legendItem,e=this.group,f=this.tracker,g=this.dataLabelsGroup,h,i=this.points,j=c.options.chart.ignoreHiddenSeries;h=this.visible;h=(this.visible= -a=a===A?!h:a)?"show":"hide";if(e)e[h]();if(f)f[h]();else if(i)for(e=i.length;e--;)if(f=i[e],f.tracker)f.tracker[h]();if(g)g[h]();d&&c.legend.colorizeItem(this,a);this.isDirty=!0;this.options.stacking&&n(c.series,function(a){if(a.options.stacking&&a.visible)a.isDirty=!0});if(j)c.isDirtyBox=!0;b!==!1&&c.redraw();E(this,h)},show:function(){this.setVisible(!0)},hide:function(){this.setVisible(!1)},select:function(a){this.selected=a=a===A?!this.selected:a;if(this.checkbox)this.checkbox.checked=a;E(this, -a?"select":"unselect")},drawTrackerGroup:function(){var a=this.trackerGroup,b=this.chart;if(this.isCartesian){if(!a)this.trackerGroup=a=b.renderer.g().attr({zIndex:this.options.zIndex||1}).add(b.trackerGroup);a.translate(this.xAxis.left,this.yAxis.top)}return a},drawTracker:function(){var a=this,b=a.options,c=b.trackByArea,d=[].concat(c?a.areaPath:a.graphPath),e=d.length,f=a.chart,g=f.renderer,h=f.options.tooltip.snap,i=a.tracker,j=b.cursor,j=j&&{cursor:j},k=a.singlePoints,l=a.drawTrackerGroup(), -m;if(e&&!c)for(m=e+1;m--;)d[m]==="M"&&d.splice(m+1,0,d[m+1]-h,d[m+2],"L"),(m&&d[m]==="M"||m===e)&&d.splice(m,0,"L",d[m-2]+h,d[m-1]);for(m=0;m=0;d--)da&&i>e?(i=x(a,e),k=2*e-i):ig&&k>e?(k=x(g,e),i=2*e-k):kv?g-v:z-(f<=z?v:0));u(c,{barX:h,barY:i,barW:y,barH:j,pointWidth:r});c.shapeType="rect";c.shapeArgs=f=b.renderer.Element.prototype.crisp.call(0,e,h,i,y,j);e%2&&(f.y-=1,f.height+=1);c.trackerArgs=M(j)<3&&C(c.shapeArgs,{height:6,y:i-3})})},getSymbol:function(){},drawLegendSymbol:G.prototype.drawLegendSymbol,drawGraph:function(){},drawPoints:function(){var a=this,b=a.options,c=a.chart.renderer,d,e;n(a.points,function(f){var g=f.plotY;if(g!==A&&!isNaN(g)&& -f.y!==null)d=f.graphic,e=f.shapeArgs,d?(Fa(d),d.animate(C(e))):f.graphic=d=c[f.shapeType](e).attr(f.pointAttr[f.selected?"select":""]).add(a.group).shadow(b.shadow,null,b.stacking&&!b.borderRadius)})},drawTracker:function(){var a=this,b=a.chart,c=b.renderer,d,e,f=+new Date,g=a.options,h=g.cursor,i=h&&{cursor:h},j=a.drawTrackerGroup(),k,l,m;n(a.points,function(h){e=h.tracker;d=h.trackerArgs||h.shapeArgs;l=h.plotY;m=!a.isCartesian||l!==A&&!isNaN(l);delete d.strokeWidth;if(h.y!==null&&m)e?e.attr(d): -h.tracker=c[h.shapeType](d).attr({isTracker:f,fill:tb,visibility:a.visible?"visible":"hidden"}).on(ea?"touchstart":"mouseover",function(c){k=c.relatedTarget||c.fromElement;if(b.hoverSeries!==a&&z(k,"isTracker")!==f)a.onMouseOver();h.onMouseOver()}).on("mouseout",function(b){if(!g.stickyTracking&&(k=b.relatedTarget||b.toElement,z(k,"isTracker")!==f))a.onMouseOut()}).css(i).add(h.group||j)})},animate:function(a){var b=this,c=b.points,d=b.options;if(!a)n(c,function(a){var c=a.graphic,a=a.shapeArgs,g= -b.yAxis,h=d.threshold;c&&(c.attr({height:0,y:s(h)?g.getThreshold(h):g.translate(g.getExtremes().min,0,1,0,1)}),c.animate({height:a.height,y:a.y},d.animation))}),b.animate=null},remove:function(){var a=this,b=a.chart;b.hasRendered&&n(b.series,function(b){if(b.type===a.type)b.isDirty=!0});R.prototype.remove.apply(a,arguments)}});Y.column=ha;Z.bar=C(Z.column,{dataLabels:{align:"left",x:5,y:null,verticalAlign:"middle"}});Ia=ca(ha,{type:"bar",inverted:!0});Y.bar=Ia;Z.scatter=C(T,{lineWidth:0,states:{hover:{lineWidth:0}}, -tooltip:{headerFormat:'{series.name}
    ',pointFormat:"x: {point.x}
    y: {point.y}
    "}});Ia=ca(R,{type:"scatter",sorted:!1,translate:function(){var a=this;R.prototype.translate.apply(a);n(a.points,function(b){b.shapeType="circle";b.shapeArgs={x:b.plotX,y:b.plotY,r:a.chart.options.tooltip.snap}})},drawTracker:function(){for(var a=this,b=a.options.cursor,b=b&&{cursor:b},c=a.points,d=c.length,e;d--;)if(e=c[d].graphic)e.element._i= -d;a._hasTracking?a._hasTracking=!0:a.group.attr({isTracker:!0}).on(ea?"touchstart":"mouseover",function(b){a.onMouseOver();if(b.target._i!==A)c[b.target._i].onMouseOver()}).on("mouseout",function(){if(!a.options.stickyTracking)a.onMouseOut()}).css(b)}});Y.scatter=Ia;Z.pie=C(T,{borderColor:"#FFFFFF",borderWidth:1,center:["50%","50%"],colorByPoint:!0,dataLabels:{distance:30,enabled:!0,formatter:function(){return this.point.name},y:5},legendType:"point",marker:null,size:"75%",showInLegend:!1,slicedOffset:10, -states:{hover:{brightness:0.1,shadow:!1}}});T={type:"pie",isCartesian:!1,pointClass:ca(Wa,{init:function(){Wa.prototype.init.apply(this,arguments);var a=this,b;u(a,{visible:a.visible!==!1,name:o(a.name,"Slice")});b=function(){a.slice()};I(a,"select",b);I(a,"unselect",b);return a},setVisible:function(a){var b=this.series.chart,c=this.tracker,d=this.dataLabel,e=this.connector,f=this.shadowGroup,g;g=(this.visible=a=a===A?!this.visible:a)?"show":"hide";this.group[g]();if(c)c[g]();if(d)d[g]();if(e)e[g](); -if(f)f[g]();this.legendItem&&b.legend.colorizeItem(this,a)},slice:function(a,b,c){var d=this.series.chart,e=this.slicedTranslation;ua(c,d);o(b,!0);a=this.sliced=s(a)?a:!this.sliced;a={translateX:a?e[0]:d.plotLeft,translateY:a?e[1]:d.plotTop};this.group.animate(a);this.shadowGroup&&this.shadowGroup.animate(a)}}),pointAttrToOptions:{stroke:"borderColor","stroke-width":"borderWidth",fill:"color"},getColor:function(){this.initialColor=this.chart.counters.color},animate:function(){var a=this;n(a.points, -function(b){var c=b.graphic,b=b.shapeArgs,d=-xa/2;c&&(c.attr({r:0,start:d,end:d}),c.animate({r:b.r,start:b.start,end:b.end},a.options.animation))});a.animate=null},setData:function(a,b){R.prototype.setData.call(this,a,!1);this.processData();this.generatePoints();o(b,!0)&&this.chart.redraw()},getCenter:function(){var a=this.options,b=this.chart,c=b.plotWidth,d=b.plotHeight,a=a.center.concat([a.size,a.innerSize||0]),e=O(c,d),f;return Ea(a,function(a,b){return(f=/%$/.test(a))?[c,d,e,e][b]*w(a)/100:a})}, -translate:function(){this.generatePoints();var a=0,b=-0.25,c=this.options,d=c.slicedOffset,e=d+c.borderWidth,f,g=this.chart,h,i,j,k=this.points,l=2*xa,m,p,o,s=c.dataLabels.distance;this.center=f=this.getCenter();this.getX=function(a,b){j=L.asin((a-f[1])/(f[2]/2+s));return f[0]+(b?-1:1)*X(j)*(f[2]/2+s)};n(k,function(b){a+=b.y});n(k,function(c){m=a?c.y/a:0;h=t(b*l*1E3)/1E3;b+=m;i=t(b*l*1E3)/1E3;c.shapeType="arc";c.shapeArgs={x:f[0],y:f[1],r:f[2]/2,innerR:f[3]/2,start:h,end:i};j=(i+h)/2;c.slicedTranslation= -Ea([X(j)*d+g.plotLeft,da(j)*d+g.plotTop],t);p=X(j)*f[2]/2;o=da(j)*f[2]/2;c.tooltipPos=[f[0]+p*0.7,f[1]+o*0.7];c.labelPos=[f[0]+p+X(j)*s,f[1]+o+da(j)*s,f[0]+p+X(j)*e,f[1]+o+da(j)*e,f[0]+p,f[1]+o,s<0?"center":j0,q=[[],[]],s,r,t,u,x=2,v;if(d.enabled){R.prototype.drawDataLabels.apply(this);n(a,function(a){a.dataLabel&&q[a.labelPos[7]0){for(v=m-l-j;v<=m+l+j;v+=a)w.push(v);t=w.length;if(A>t){h=[].concat(z);h.sort(u);for(v=A;v--;)h[v].rank=v;for(v=A;v--;)z[v].rank>=t&&z.splice(v,1);A=z.length}for(v=0;v -0){if(r=C.pop(),B=r.i,r=r.y,s>r&&w[B+1]!==null||s type pairs - class2type = {}, - - // List of deleted data cache ids, so we can reuse them - core_deletedIds = [], - - core_version = "1.9.1", - - // Save a reference to some core methods - core_concat = core_deletedIds.concat, - core_push = core_deletedIds.push, - core_slice = core_deletedIds.slice, - core_indexOf = core_deletedIds.indexOf, - core_toString = class2type.toString, - core_hasOwn = class2type.hasOwnProperty, - core_trim = core_version.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, - - // Used for splitting on whitespace - core_rnotwhite = /\S+/g, - - // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }, - - // The ready event handler - completed = function( event ) { - - // readyState === "complete" is good enough for us to call the dom ready in oldIE - if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { - detach(); - jQuery.ready(); - } - }, - // Clean-up method for dom ready events - detach = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", completed, false ); - window.removeEventListener( "load", completed, false ); - - } else { - document.detachEvent( "onreadystatechange", completed ); - window.detachEvent( "onload", completed ); - } - }; - -jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: core_version, - - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - - // scripts is true for back-compat - jQuery.merge( this, jQuery.parseHTML( - match[1], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - ret.context = this.context; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var src, copyIsArray, copy, name, options, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - if ( obj == null ) { - return String( obj ); - } - return typeof obj === "object" || typeof obj === "function" ? - class2type[ core_toString.call(obj) ] || "object" : - typeof obj; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // keepScripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, keepScripts ) { - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - keepScripts = context; - context = false; - } - context = context || document; - - var parsed = rsingleTag.exec( data ), - scripts = !keepScripts && []; - - // Single tag - if ( parsed ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ); - if ( scripts ) { - jQuery( scripts ).remove(); - } - return jQuery.merge( [], parsed.childNodes ); - }, - - parseJSON: function( data ) { - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - if ( data === null ) { - return data; - } - - if ( typeof data === "string" ) { - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - if ( data ) { - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - } - } - } - - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && jQuery.trim( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var value, - i = 0, - length = obj.length, - isArray = isArraylike( obj ); - - if ( args ) { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim && !core_trim.call("\uFEFF\xA0") ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArraylike( Object(arr) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - core_push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, - i = 0, - length = elems.length, - isArray = isArraylike( elems ), - ret = []; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return core_concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var args, proxy, tmp; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - length = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < length; i++ ) { - fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); - } - } - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the browser event has already occurred. - // we once tried to use readyState "interactive" here, but it caused issues like the one - // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", completed ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", completed ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // detach all dom ready events - detach(); - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -function isArraylike( obj ) { - var length = obj.length, - type = jQuery.type( obj ); - - if ( jQuery.isWindow( obj ) ) { - return false; - } - - if ( obj.nodeType === 1 && length ) { - return true; - } - - return type === "array" || type !== "function" && - ( length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj ); -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache -function createOptions( options ) { - var object = optionsCache[ options ] = {}; - jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // End of the loop when firing - firingLength, - // Index of currently firing callback (modified by remove if needed) - firingIndex, - // First callback to fire (used internally by add and fireWith) - firingStart, - // Actual callback list - list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], - // Fire callbacks - fire = function( data ) { - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { - memory = false; // To prevent further calls using add - break; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - var type = jQuery.type( arg ); - if ( type === "function" ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && type !== "string" ) { - // Inspect recursively - add( arg ); - } - }); - })( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); - } - } - return this; - }, - // Remove a callback from the list - remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } - } - }); - } - return this; - }, - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -jQuery.extend({ - - Deferred: function( func ) { - var tuples = [ - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ](function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); - } - }); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] - deferred[ tuple[0] ] = function() { - deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); - return this; - }; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, all, a, - input, select, fragment, - opt, eventName, isSupported, i, - div = document.createElement("div"); - - // Setup - div.setAttribute( "className", "t" ); - div.innerHTML = "
    a"; - - // Support tests won't run in some limited or non-browser environments - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - if ( !all || !a || !all.length ) { - return {}; - } - - // First batch of tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - a.style.cssText = "top:1px;float:left;opacity:.5"; - support = { - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) - checkOn: !!input.value, - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Tests for enctype support on a form (#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: document.compatMode === "CSS1Compat", - - // Will be defined later - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Support: IE<9 - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - // Check if we can trust getAttribute("value") - input = document.createElement("input"); - input.setAttribute( "value", "" ); - support.input = input.getAttribute( "value" ) === ""; - - // Check if an input maintains its value after becoming a radio - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "checked", "t" ); - input.setAttribute( "name", "t" ); - - fragment = document.createDocumentFragment(); - fragment.appendChild( input ); - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE<9 - // Opera does not clone events (and typeof div.attachEvent === undefined). - // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() - if ( div.attachEvent ) { - div.attachEvent( "onclick", function() { - support.noCloneEvent = false; - }); - - div.cloneNode( true ).click(); - } - - // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) - // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php - for ( i in { submit: true, change: true, focusin: true }) { - div.setAttribute( eventName = "on" + i, "t" ); - - support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; - } - - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - // Run tests that need a body at doc ready - jQuery(function() { - var container, marginDiv, tds, - divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; - - body.appendChild( container ).appendChild( div ); - - // Support: IE8 - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - div.innerHTML = "
    t
    "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Support: IE8 - // Check if empty table cells still have offsetWidth/Height - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // Use window.getComputedStyle because jsdom on node.js will break without it. - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. (#3333) - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = div.appendChild( document.createElement("div") ); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== core_strundefined ) { - // Support: IE<8 - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Support: IE6 - // Check if elements with layout shrink-wrap their children - div.style.display = "block"; - div.innerHTML = "
    "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - if ( support.inlineBlockNeedsLayout ) { - // Prevent IE 6 from affecting layout for positioned elements #11048 - // Prevent IE from shrinking the body in IE 7 mode #12869 - // Support: IE<8 - body.style.zoom = 1; - } - } - - body.removeChild( container ); - - // Null elements to avoid leaks in IE - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - all = select = fragment = opt = a = input = null; - - return support; -})(); - -var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, - rmultiDash = /([A-Z])/g; - -function internalData( elem, name, data, pvt /* Internal Use Only */ ){ - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; -} - -function internalRemoveData( elem, name, pvt ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var i, l, thisCache, - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } else { - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = name.concat( jQuery.map( name, jQuery.camelCase ) ); - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } -} - -jQuery.extend({ - cache: {}, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data ) { - return internalData( elem, name, data ); - }, - - removeData: function( elem, name ) { - return internalRemoveData( elem, name ); - }, - - // For internal use only. - _data: function( elem, name, data ) { - return internalData( elem, name, data, true ); - }, - - _removeData: function( elem, name ) { - return internalRemoveData( elem, name, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - // Do not set data on non-element because it will not be cleared (#8335). - if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { - return false; - } - - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var attrs, name, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attrs = elem.attributes; - for ( ; i < attrs.length; i++ ) { - name = attrs[i].name; - - if ( !name.indexOf( "data-" ) ) { - name = jQuery.camelCase( name.slice(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - // Try to fetch any internally stored data first - return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; - } - - this.each(function() { - jQuery.data( this, key, value ); - }); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - hooks.cur = fn; - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery._removeData( elem, type + "queue" ); - jQuery._removeData( elem, key ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - tmp = jQuery._data( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rfocusable = /^(?:input|select|textarea|button|object)$/i, - rclickable = /^(?:a|area)$/i, - rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, - ruseDefault = /^(?:checked|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute, - getSetInput = jQuery.support.input; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call( this, j, this.className ) ); - }); - } - - if ( proceed ) { - // The disjunction here is for better compressibility (see removeClass) - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - " " - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - elem.className = jQuery.trim( cur ); - - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = arguments.length === 0 || typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call( this, j, this.className ) ); - }); - } - if ( proceed ) { - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - "" - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - elem.className = value ? jQuery.trim( cur ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.match( core_rnotwhite ) || []; - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - // Toggle whole class name - } else if ( type === core_strundefined || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.className ); - } - - // 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. - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var ret, hooks, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, option, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? - max : - one ? index : 0; - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // oldIE doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - // Don't return options that are disabled or in a disabled optgroup - ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && - ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attr: function( elem, name, value ) { - var hooks, notxml, ret, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === core_strundefined ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - - } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, value + "" ); - return value; - } - - } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - // In IE9+, Flash objects don't have .getAttribute (#12945) - // Support: IE9+ - if ( typeof elem.getAttribute !== core_strundefined ) { - ret = elem.getAttribute( name ); - } - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var name, propName, - i = 0, - attrNames = value && value.match( core_rnotwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( (name = attrNames[i++]) ) { - propName = jQuery.propFix[ name ] || name; - - // Boolean attributes get special treatment (#10870) - if ( rboolean.test( name ) ) { - // Set corresponding property to false for boolean attributes - // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 - if ( !getSetAttribute && ruseDefault.test( name ) ) { - elem[ jQuery.camelCase( "default-" + name ) ] = - elem[ propName ] = false; - } else { - elem[ propName ] = false; - } - - // See #9699 for explanation of this approach (setting first, then removal) - } else { - jQuery.attr( elem, name, "" ); - } - - elem.removeAttribute( getSetAttribute ? name : propName ); - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !jQuery.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 ) { - elem.value = val; - } - return value; - } - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - var - // Use .prop to determine if this attribute is understood as boolean - prop = jQuery.prop( elem, name ), - - // Fetch it accordingly - attr = typeof prop === "boolean" && elem.getAttribute( name ), - detail = typeof prop === "boolean" ? - - getSetInput && getSetAttribute ? - attr != null : - // oldIE fabricates an empty string for missing boolean attributes - // and conflates checked/selected into attroperties - ruseDefault.test( name ) ? - elem[ jQuery.camelCase( "default-" + name ) ] : - !!attr : - - // fetch an attribute node for properties not recognized as boolean - elem.getAttributeNode( name ); - - return detail && detail.value !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { - // IE<8 needs the *property* name - elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); - - // Use defaultChecked and defaultSelected for oldIE - } else { - elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; - } - - return name; - } -}; - -// fix oldIE value attroperty -if ( !getSetInput || !getSetAttribute ) { - jQuery.attrHooks.value = { - get: function( elem, name ) { - var ret = elem.getAttributeNode( name ); - return jQuery.nodeName( elem, "input" ) ? - - // Ignore the value *property* by using defaultValue - elem.defaultValue : - - ret && ret.specified ? ret.value : undefined; - }, - set: function( elem, value, name ) { - if ( jQuery.nodeName( elem, "input" ) ) { - // Does not return so that setAttribute is also used - elem.defaultValue = value; - } else { - // Use nodeHook if defined (#1954); otherwise setAttribute is fine - return nodeHook && nodeHook.set( elem, value, name ); - } - } - }; -} - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret = elem.getAttributeNode( name ); - return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - elem.setAttributeNode( - (ret = elem.ownerDocument.createAttribute( name )) - ); - } - - ret.value = value += ""; - - // Break association with cloned elements by also using setAttribute (#9646) - return name === "value" || value === elem.getAttribute( name ) ? - value : - undefined; - } - }; - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - nodeHook.set( elem, value === "" ? false : value, name ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); -} - - -// Some attributes require a special call on IE -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret == null ? undefined : ret; - } - }); - }); - - // href/src property should get the full normalized URL (#10299/#12915) - jQuery.each([ "href", "src" ], function( i, name ) { - jQuery.propHooks[ name ] = { - get: function( elem ) { - return elem.getAttribute( name, 4 ); - } - }; - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Note: IE uppercases css property names, but if we were to .toLowerCase() - // .cssText, that would destroy case senstitivity in URL's, like in "background" - return elem.style.cssText || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = value + "" ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:input|select|textarea)$/i, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - var tmp, events, t, handleObjIn, - special, eventHandle, handleObj, - handlers, type, namespaces, origType, - elemData = jQuery._data( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !(events = elemData.events) ) { - events = elemData.events = {}; - } - if ( !(eventHandle = elemData.handle) ) { - eventHandle = elemData.handle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !(handlers = events[ type ]) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - var j, handleObj, tmp, - origCount, t, events, - special, handlers, type, - namespaces, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery._removeData( elem, "events" ); - } - }, - - trigger: function( event, data, elem, onlyHandlers ) { - var handle, ontype, cur, - bubbleType, special, tmp, i, - eventPath = [ elem || document ], - type = core_hasOwn.call( event, "type" ) ? event.type : event, - namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf(":") < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - event.isTrigger = true; - event.namespace = namespaces.join("."); - event.namespace_re = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === (elem.ownerDocument || document) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - try { - elem[ type ](); - } catch ( e ) { - // IE<9 dies on focus/blur to hidden element (#1486,#12518) - // only reproducible on winXP IE8 native, not IE9 in IE8 mode - } - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); - - var i, ret, handleObj, matched, j, - handlerQueue = [], - args = core_slice.call( arguments ), - handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( (event.result = ret) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var sel, handleObj, matches, i, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { - - for ( ; cur != this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) >= 0 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matches[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, handlers: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( delegateCount < handlers.length ) { - handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); - } - - return handlerQueue; - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: IE<9 - // Fix target property (#1925) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Support: Chrome 23+, Safari? - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Support: IE<9 - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) - event.metaKey = !!event.metaKey; - - return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var body, eventDoc, doc, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - special: { - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { - this.click(); - return false; - } - } - }, - focus: { - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== document.activeElement && this.focus ) { - try { - this.focus(); - return false; - } catch ( e ) { - // Support: IE<9 - // If we error on focus to hidden element (#1486, #12518), - // let .trigger() run the handlers - } - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === document.activeElement && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - - beforeunload: { - postDispatch: function( event ) { - - // Even when returnValue equals to undefined Firefox will still show alert - if ( event.result !== undefined ) { - event.originalEvent.returnValue = event.result; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === core_strundefined ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - if ( !e ) { - return; - } - - // If preventDefault exists, run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // Support: IE - // Otherwise set the returnValue property of the original event to false - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - if ( !e ) { - return; - } - // If stopPropagation exists, run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - - // Support: IE - // Set the cancelBubble property of the original event to true - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - } -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "submitBubbles" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "submitBubbles", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "changeBubbles", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return !rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var type, origFn; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - var elem = this[0]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var i, - cachedruns, - Expr, - getText, - isXML, - compile, - hasDuplicate, - outermostContext, - - // Local document vars - setDocument, - document, - docElem, - documentIsXML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - sortOrder, - - // Instance-specific data - expando = "sizzle" + -(new Date()), - preferredDoc = window.document, - support = {}, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - - // General-purpose constants - strundefined = typeof undefined, - MAX_NEGATIVE = 1 << 31, - - // Array methods - arr = [], - pop = arr.pop, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf if we can't use a native one - indexOf = arr.indexOf || function( elem ) { - var i = 0, - len = this.length; - for ( ; i < len; i++ ) { - if ( this[i] === elem ) { - return i; - } - } - return -1; - }, - - - // Regular expressions - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - - // Prefer arguments quoted, - // then not containing pseudos/brackets, - // then attribute selectors/non-parenthetical expressions, - // then anything else - // These preferences are here to reduce the number of selectors - // needing tokenize in the PSEUDO preFilter - pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - - rnative = /^[^{]+\{\s*\[native code/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, - funescape = function( _, escaped ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - return high !== high ? - escaped : - // BMP codepoint - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }; - -// Use a stripped-down slice if we can't use a native one -try { - slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, - results = []; - while ( (elem = this[i++]) ) { - results.push( elem ); - } - return results; - }; -} - -/** - * For feature detection - * @param {Function} fn The function to test for native support - */ -function isNative( fn ) { - return rnative.test( fn + "" ); -} - -/** - * Create key-value caches of limited size - * @returns {Function(string, Object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var cache, - keys = []; - - return (cache = function( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key += " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key ] = value); - }); -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result - */ -function assert( fn ) { - var div = document.createElement("div"); - - try { - return fn( div ); - } catch (e) { - return false; - } finally { - // release memory in IE - div = null; - } -} - -function Sizzle( selector, context, results, seed ) { - var match, elem, m, nodeType, - // QSA vars - i, groups, old, nid, newContext, newSelector; - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - - context = context || document; - results = results || []; - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !documentIsXML && !seed ) { - - // Shortcuts - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - - // QSA path - if ( support.qsa && !rbuggyQSA.test(selector) ) { - old = true; - nid = expando; - newContext = context; - newSelector = nodeType === 9 && selector; - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - groups = tokenize( selector ); - - if ( (old = context.getAttribute("id")) ) { - nid = old.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - nid = "[id='" + nid + "'] "; - - i = groups.length; - while ( i-- ) { - groups[i] = nid + toSelector( groups[i] ); - } - newContext = rsibling.test( selector ) && context.parentNode || context; - newSelector = groups.join(","); - } - - if ( newSelector ) { - try { - push.apply( results, slice.call( newContext.querySelectorAll( - newSelector - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Detect xml - * @param {Element|Object} elem An element or a document - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var doc = node ? node.ownerDocument || node : preferredDoc; - - // If no document and documentElement is available, return - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Set our document - document = doc; - docElem = doc.documentElement; - - // Support tests - documentIsXML = isXML( doc ); - - // Check if getElementsByTagName("*") returns only elements - support.tagNameNoComments = assert(function( div ) { - div.appendChild( doc.createComment("") ); - return !div.getElementsByTagName("*").length; - }); - - // Check if attributes should be retrieved by attribute nodes - support.attributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }); - - // Check if getElementsByClassName can be trusted - support.getByClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { - return false; - } - - // Safari 3.2 caches class attributes and doesn't catch changes - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length === 2; - }); - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - support.getByName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
    "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = doc.getElementsByName && - // buggy browsers will return fewer than the correct 2 - doc.getElementsByName( expando ).length === 2 + - // buggy browsers will return more than the correct 0 - doc.getElementsByName( expando + 0 ).length; - support.getIdNotName = !doc.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }); - - // IE6/7 return modified attributes - Expr.attrHandle = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }) ? - {} : - { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; - - // ID find and filter - if ( support.getIdNotName ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && !documentIsXML ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - } else { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && !documentIsXML ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - } - - // Tag - Expr.find["TAG"] = support.tagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var elem, - tmp = [], - i = 0, - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Name - Expr.find["NAME"] = support.getByName && function( tag, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; - - // Class - Expr.find["CLASS"] = support.getByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { - return context.getElementsByClassName( className ); - } - }; - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21), - // no need to also add to buggyMatches since matches checks buggyQSA - // A support test would require too much code (would include document ready) - rbuggyQSA = [ ":focus" ]; - - if ( (support.qsa = isNative(doc.querySelectorAll)) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explictly - // setting a boolean content attribute, - // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE8 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = ""; - if ( div.querySelectorAll("[i^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = new RegExp( rbuggyMatches.join("|") ); - - // Element contains another - // Purposefully does not implement inclusive descendent - // As in, an element does not contain itself - contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - // Document order sorting - sortOrder = docElem.compareDocumentPosition ? - function( a, b ) { - var compare; - - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) { - if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) { - if ( a === doc || contains( preferredDoc, a ) ) { - return -1; - } - if ( b === doc || contains( preferredDoc, b ) ) { - return 1; - } - return 0; - } - return compare & 4 ? -1 : 1; - } - - return a.compareDocumentPosition ? -1 : 1; - } : - function( a, b ) { - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Parentless nodes are either documents or disconnected - } else if ( !aup || !bup ) { - return a === doc ? -1 : - b === doc ? 1 : - aup ? -1 : - bup ? 1 : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - // Always assume the presence of duplicates if sort doesn't - // pass them to our comparison function (as in Google Chrome). - hasDuplicate = false; - [0, 0].sort( sortOrder ); - support.detectDuplicates = hasDuplicate; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyQSA always contains :focus, so no need for an existence check - if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, document, null, [elem] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - var val; - - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - if ( !documentIsXML ) { - name = name.toLowerCase(); - } - if ( (val = Expr.attrHandle[ name ]) ) { - return val( elem ); - } - if ( documentIsXML || support.attributes ) { - return elem.getAttribute( name ); - } - return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? - name : - val && val.specified ? val.value : null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - i = 1, - j = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - return results; -}; - -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -// Returns a function to use in pseudos for input types -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -// Returns a function to use in pseudos for buttons -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -// Returns a function to use in pseudos for positionals -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[5] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[4] ) { - match[2] = match[4]; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - - nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, outerCache, node, diff, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || (parent[ expando ] = {}); - cache = outerCache[ type ] || []; - nodeIndex = cache[0] === dirruns && cache[1]; - diff = cache[0] === dirruns && cache[2]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - // Use previously-cached element index if available - } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { - diff = cache[1]; - - // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) - } else { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { - // Cache the index of each encountered element - if ( useCache ) { - (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf.call( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifider - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsXML ? - elem.getAttribute("xml:lang") || elem.getAttribute("lang") : - elem.lang) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -function tokenize( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( tokens = [] ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push( { - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -} - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var data, cache, outerCache, - dirkey = dirruns + " " + doneName; - - // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { - if ( (data = cache[1]) === true || data === cachedruns ) { - return data === true; - } - } else { - cache = outerCache[ dir ] = [ dirkey ]; - cache[1] = matcher( elem, context, xml ) || cachedruns; - if ( cache[1] === true ) { - return true; - } - } - } - } - } - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf.call( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - // A counter to specify which element is currently being matched - var matcherCachedRuns = 0, - bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, expandContext ) { - var elem, j, matcher, - setMatched = [], - matchedCount = 0, - i = "0", - unmatched = seed && [], - outermost = expandContext != null, - contextBackup = outermostContext, - // We must always have either seed elements or context - elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); - - if ( outermost ) { - outermostContext = context !== document && context; - cachedruns = matcherCachedRuns; - } - - // Add elements passing elementMatchers directly to results - // Keep `i` a string if there are no elements so `matchedCount` will be "00" below - for ( ; (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - cachedruns = ++matcherCachedRuns; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // Apply set filters to unmatched elements - matchedCount += i; - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !group ) { - group = tokenize( selector ); - } - i = group.length; - while ( i-- ) { - cached = matcherFromTokens( group[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - } - return cached; -}; - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function select( selector, context, results, seed ) { - var i, tokens, token, type, find, - match = tokenize( selector ); - - if ( !seed ) { - // Try to minimize operations if there is only one group - if ( match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && !documentIsXML && - Expr.relative[ tokens[1].type ] ) { - - context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && context.parentNode || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, slice.call( seed, 0 ) ); - return results; - } - - break; - } - } - } - } - } - - // Compile and execute a filtering function - // Provide `match` to avoid retokenization if we modified the selector above - compile( selector, match )( - seed, - context, - documentIsXML, - results, - rsibling.test( selector ) - ); - return results; -} - -// Deprecated -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Easy API for creating new setFilters -function setFilters() {} -Expr.filters = setFilters.prototype = Expr.pseudos; -Expr.setFilters = new setFilters(); - -// Initialize with the default document -setDocument(); - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, ret, self, - len = this.length; - - if ( typeof selector !== "string" ) { - self = this; - return this.pushStack( jQuery( selector ).filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }) ); - } - - ret = []; - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, this[ i ], ret ); - } - - // Needed because $( selector, context ) becomes $( context ).find( selector ) - ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); - ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false) ); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true) ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( jQuery.unique(all) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /\s*$/g, - - // We have to close these tags to support XHTML (#13200) - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
    ", "
    " ], - area: [ 1, "", "" ], - param: [ 1, "", "" ], - thead: [ 1, "", "
    " ], - tr: [ 2, "", "
    " ], - col: [ 2, "", "
    " ], - td: [ 3, "", "
    " ], - - // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, - // unless wrapped in a div with non-breaking characters in front of it. - _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
    ", "
    " ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - return this.domManip( arguments, false, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - }); - }, - - after: function() { - return this.domManip( arguments, false, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - }); - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem ) ); - } - - if ( elem.parentNode ) { - if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { - setGlobalEval( getAll( elem, "script" ) ); - } - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - - // If this is a select, ensure that it displays empty (#12336) - // Support: IE<9 - if ( elem.options && jQuery.nodeName( elem, "select" ) ) { - elem.options.length = 0; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - var isFunc = jQuery.isFunction( value ); - - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( !isFunc && typeof value !== "string" ) { - value = jQuery( value ).not( this ).detach(); - } - - return this.domManip( [ value ], true, function( elem ) { - var next = this.nextSibling, - parent = this.parentNode; - - if ( parent ) { - jQuery( this ).remove(); - parent.insertBefore( elem, next ); - } - }); - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = core_concat.apply( [], args ); - - var first, node, hasScripts, - scripts, doc, fragment, - i = 0, - l = this.length, - set = this, - iNoClone = l - 1, - value = args[0], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { - return this.each(function( index ) { - var self = set.eq( index ); - if ( isFunction ) { - args[0] = value.call( this, index, table ? self.html() : undefined ); - } - self.domManip( args, table, callback ); - }); - } - - if ( l ) { - fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - node, - i - ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - - if ( node.src ) { - // Hope ajax is available... - jQuery.ajax({ - url: node.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - } - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - var attr = elem.getAttributeNode("type"); - elem.type = ( attr && attr.specified ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - if ( match ) { - elem.type = match[1]; - } else { - elem.removeAttribute("type"); - } - return elem; -} - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var elem, - i = 0; - for ( ; (elem = elems[i]) != null; i++ ) { - jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); - } -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function fixCloneNodeIssues( src, dest ) { - var nodeName, e, data; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - nodeName = dest.nodeName.toLowerCase(); - - // IE6-8 copies events bound via attachEvent when using cloneNode. - if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { - data = jQuery._data( dest ); - - for ( e in data.events ) { - jQuery.removeEvent( dest, e, data.handle ); - } - - // Event data gets referenced instead of copied if the expando gets copied too - dest.removeAttribute( jQuery.expando ); - } - - // IE blanks contents when cloning scripts, and tries to evaluate newly-set text - if ( nodeName === "script" && dest.text !== src.text ) { - disableScript( dest ).text = src.text; - restoreScript( dest ); - - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - } else if ( nodeName === "object" ) { - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.defaultSelected = dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone(true); - jQuery( insert[i] )[ original ]( elems ); - - // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() - core_push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -}); - -function getAll( context, tag ) { - var elems, elem, - i = 0, - found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : - undefined; - - if ( !found ) { - for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { - if ( !tag || jQuery.nodeName( elem, tag ) ) { - found.push( elem ); - } else { - jQuery.merge( found, getAll( elem, tag ) ); - } - } - } - - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], found ) : - found; -} - -// Used in buildFragment, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( manipulation_rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var destElements, node, clone, i, srcElements, - inPage = jQuery.contains( elem.ownerDocument, elem ); - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - // Fix all IE cloning issues - for ( i = 0; (node = srcElements[i]) != null; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - fixCloneNodeIssues( node, destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0; (node = srcElements[i]) != null; i++ ) { - cloneCopyEvent( node, destElements[i] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - destElements = srcElements = node = null; - - // Return the cloned set - return clone; - }, - - buildFragment: function( elems, context, scripts, selection ) { - var j, elem, contains, - tmp, tag, tbody, wrap, - l = elems.length, - - // Ensure a safe fragment - safe = createSafeFragment( context ), - - nodes = [], - i = 0; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || safe.appendChild( context.createElement("div") ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - - tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; - - // Descend through wrappers to the right content - j = wrap[0]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Manually add leading whitespace removed by IE - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - elem = tag === "table" && !rtbody.test( elem ) ? - tmp.firstChild : - - // String was a bare or - wrap[1] === "
    " && !rtbody.test( elem ) ? - tmp : - 0; - - j = elem && elem.childNodes.length; - while ( j-- ) { - if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { - elem.removeChild( tbody ); - } - } - } - - jQuery.merge( nodes, tmp.childNodes ); - - // Fix #12392 for WebKit and IE > 9 - tmp.textContent = ""; - - // Fix #12392 for oldIE - while ( tmp.firstChild ) { - tmp.removeChild( tmp.firstChild ); - } - - // Remember the top-level container for proper cleanup - tmp = safe.lastChild; - } - } - } - - // Fix #11356: Clear elements from fragment - if ( tmp ) { - safe.removeChild( tmp ); - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); - } - - i = 0; - while ( (elem = nodes[ i++ ]) ) { - - // #4087 - If origin and destination elements are the same, and this is - // that element, do not do anything - if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( safe.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( (elem = tmp[ j++ ]) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - tmp = null; - - return safe; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var elem, type, id, data, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( typeof elem.removeAttribute !== core_strundefined ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - core_deletedIds.push( id ); - } - } - } - } - } -}); -var iframe, getStyles, curCSS, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity\s*=\s*([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - // 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]).+)/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), - elemdisplay = { BODY: "block" }, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - // isHidden might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var display, elem, hidden, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - values[ index ] = jQuery._data( elem, "olddisplay" ); - display = elem.style.display; - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - - if ( !values[ index ] ) { - hidden = isHidden( elem ); - - if ( display && display !== "none" || !hidden ) { - jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); - } - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - var len, styles, - map = {}, - i = 0; - - if ( jQuery.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - var bool = typeof state === "boolean"; - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -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; - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "columnCount": true, - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // 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; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the 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 - 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 NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, 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 specifing setters in cssHooks, - // but it would mean to define eight (for every problematic property) identical functions - if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var num, val, hooks, - origName = jQuery.camelCase( name ); - - // 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 - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - //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 - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: we've included the "window" in window.getComputedStyle -// because jsdom on node.js will break without it. -if ( window.getComputedStyle ) { - getStyles = function( elem ) { - return window.getComputedStyle( elem, null ); - }; - - curCSS = function( elem, name, _computed ) { - var width, minWidth, maxWidth, - computed = _computed || getStyles( elem ), - - // getPropertyValue is only needed for .css('filter') in IE9, see #12537 - ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, - style = elem.style; - - if ( computed ) { - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels - // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - getStyles = function( elem ) { - return elem.currentStyle; - }; - - curCSS = function( elem, name, _computed ) { - var left, rs, rsLeft, - computed = _computed || getStyles( elem ), - ret = computed ? computed[ name ] : undefined, - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rs = elem.runtimeStyle; - rsLeft = rs && rs.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - rs.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - rs.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // 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 - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // 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 ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var valueIsBorderBox = true, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - styles = getStyles( elem ), - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // 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 ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name, styles ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - // Use the already-created iframe if possible - iframe = ( iframe || - jQuery("