diff --git a/app/assets/javascripts/admin/templates/email_preview_digest.hbs b/app/assets/javascripts/admin/templates/email_preview_digest.hbs index d5f3f932b..7670d6194 100644 --- a/app/assets/javascripts/admin/templates/email_preview_digest.hbs +++ b/app/assets/javascripts/admin/templates/email_preview_digest.hbs @@ -18,10 +18,10 @@ -{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if showHtml}} {{{html_content}}} {{else}}
{{{text_content}}}
{{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/admin/templates/flags-list.hbs b/app/assets/javascripts/admin/templates/flags-list.hbs index 6285d9e93..e001e92ae 100644 --- a/app/assets/javascripts/admin/templates/flags-list.hbs +++ b/app/assets/javascripts/admin/templates/flags-list.hbs @@ -147,7 +147,7 @@ - {{loading-spinner condition=view.loading}} + {{conditional-loading-spinner condition=view.loading}} {{else}}

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

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


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


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

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


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

{{i18n 'search.no_results'}}

{{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/views/activity-filter.js.es6 b/app/assets/javascripts/discourse/components/activity-filter.js.es6 similarity index 100% rename from app/assets/javascripts/discourse/views/activity-filter.js.es6 rename to app/assets/javascripts/discourse/components/activity-filter.js.es6 diff --git a/app/assets/javascripts/discourse/views/category-chooser.js.es6 b/app/assets/javascripts/discourse/components/category-chooser.js.es6 similarity index 96% rename from app/assets/javascripts/discourse/views/category-chooser.js.es6 rename to app/assets/javascripts/discourse/components/category-chooser.js.es6 index 9f6fc1674..ed2b8a55e 100644 --- a/app/assets/javascripts/discourse/views/category-chooser.js.es6 +++ b/app/assets/javascripts/discourse/components/category-chooser.js.es6 @@ -1,4 +1,4 @@ -import ComboboxView from 'discourse/views/combo-box'; +import ComboboxView from 'discourse/components/combo-box'; import { categoryBadgeHTML } from 'discourse/helpers/category-link'; export default ComboboxView.extend({ @@ -41,7 +41,7 @@ export default ComboboxView.extend({ } }.property(), - template(item) { + comboTemplate(item) { let category; diff --git a/app/assets/javascripts/discourse/views/combo-box.js.es6 b/app/assets/javascripts/discourse/components/combo-box.js.es6 similarity index 92% rename from app/assets/javascripts/discourse/views/combo-box.js.es6 rename to app/assets/javascripts/discourse/components/combo-box.js.es6 index 96afbc9b8..e440f839a 100644 --- a/app/assets/javascripts/discourse/views/combo-box.js.es6 +++ b/app/assets/javascripts/discourse/components/combo-box.js.es6 @@ -1,5 +1,4 @@ -// This view handles rendering of a combobox -export default Discourse.View.extend({ +export default Ember.Component.extend({ tagName: 'select', attributeBindings: ['tabindex'], classNames: ['combobox'], @@ -65,7 +64,7 @@ export default Discourse.View.extend({ o.selected = !!$(o).attr('selected'); }); - $elem.select2({formatResult: this.template, minimumResultsForSearch: 5, width: 'resolve'}); + $elem.select2({formatResult: this.comboTemplate, minimumResultsForSearch: 5, width: 'resolve'}); const castInteger = this.get('castInteger'); $elem.on("change", function (e) { diff --git a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 index 19103360d..807990d70 100644 --- a/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 +++ b/app/assets/javascripts/discourse/components/conditional-loading-spinner.js.es6 @@ -9,7 +9,7 @@ export default Ember.Component.extend({ if (this.get('condition')) { buffer.push('
'); } else { - return this._super(); + return this._super(buffer); } }, diff --git a/app/assets/javascripts/discourse/components/count-i18n.js.es6 b/app/assets/javascripts/discourse/components/count-i18n.js.es6 new file mode 100644 index 000000000..28c908be2 --- /dev/null +++ b/app/assets/javascripts/discourse/components/count-i18n.js.es6 @@ -0,0 +1,8 @@ +export default Ember.Component.extend(Discourse.StringBuffer, { + tagName: 'span', + rerenderTriggers: ['count', 'suffix'], + + renderString: function(buffer) { + buffer.push(I18n.t(this.get('key') + (this.get('suffix') || ''), { count: this.get('count') })); + } +}); diff --git a/app/assets/javascripts/discourse/components/d-button.js.es6 b/app/assets/javascripts/discourse/components/d-button.js.es6 index 973405128..7673e60ac 100644 --- a/app/assets/javascripts/discourse/components/d-button.js.es6 +++ b/app/assets/javascripts/discourse/components/d-button.js.es6 @@ -26,7 +26,7 @@ export default Ember.Component.extend({ if (label) { buffer.push(label); } } else { // If no label or icon is present, yield - return this._super(); + return this._super(buffer); } }, diff --git a/app/assets/javascripts/discourse/components/input-tip.js.es6 b/app/assets/javascripts/discourse/components/input-tip.js.es6 new file mode 100644 index 000000000..2ba1c074c --- /dev/null +++ b/app/assets/javascripts/discourse/components/input-tip.js.es6 @@ -0,0 +1,17 @@ +import StringBuffer from 'discourse/mixins/string-buffer'; +import { iconHTML } from 'discourse/helpers/fa-icon'; + +export default Ember.Component.extend(StringBuffer, { + classNameBindings: [':tip', 'good', 'bad'], + rerenderTriggers: ['validation'], + + bad: Em.computed.alias('validation.failed'), + good: Em.computed.not('bad'), + + renderString(buffer) { + const reason = this.get('validation.reason'); + if (reason) { + buffer.push(iconHTML(this.get('good') ? 'check' : 'times') + ' ' + reason); + } + } +}); diff --git a/app/assets/javascripts/discourse/views/popup_input_tip_view.js b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 similarity index 63% rename from app/assets/javascripts/discourse/views/popup_input_tip_view.js rename to app/assets/javascripts/discourse/components/popup-input-tip.js.es6 index a21d18629..db5b69080 100644 --- a/app/assets/javascripts/discourse/views/popup_input_tip_view.js +++ b/app/assets/javascripts/discourse/components/popup-input-tip.js.es6 @@ -1,23 +1,12 @@ -/** - This view extends the functionality of InputTipView with these extra features: - * it can be dismissed - * it bounces when it's shown - * it's absolutely positioned beside the input element, with the help of - extra css you'll need to write to line it up correctly. +import { iconHTML } from 'discourse/helpers/fa-icon'; - @class PopupInputTipView - @extends Discourse.View - @namespace Discourse - @module Discourse -**/ -Discourse.PopupInputTipView = Discourse.View.extend({ - templateName: 'popup_input_tip', +export default Ember.Component.extend({ classNameBindings: [':popup-tip', 'good', 'bad', 'shownAt::hide'], animateAttribute: null, bouncePixels: 6, bounceDelay: 100, - click: function() { + click() { this.set('shownAt', false); }, @@ -43,17 +32,23 @@ Discourse.PopupInputTipView = Discourse.View.extend({ } }.observes('shownAt'), - bounceLeft: function($elem) { + render(buffer) { + const reason = this.get('validation.reason'); + if (!reason) { return; } + + buffer.push("" + iconHTML('times-circle') + ""); + buffer.push(reason); + }, + + bounceLeft($elem) { for( var i = 0; i < 5; i++ ) { $elem.animate({ left: '+=' + this.bouncePixels }, this.bounceDelay).animate({ left: '-=' + this.bouncePixels }, this.bounceDelay); } }, - bounceRight: function($elem) { + bounceRight($elem) { for( var i = 0; i < 5; i++ ) { $elem.animate({ right: '-=' + this.bouncePixels }, this.bounceDelay).animate({ right: '+=' + this.bouncePixels }, this.bounceDelay); } } }); - -Discourse.View.registerHelper('popupInputTip', Discourse.PopupInputTipView); diff --git a/app/assets/javascripts/discourse/helpers/count-i18n.js.es6 b/app/assets/javascripts/discourse/helpers/count-i18n.js.es6 deleted file mode 100644 index 85fb9bc46..000000000 --- a/app/assets/javascripts/discourse/helpers/count-i18n.js.es6 +++ /dev/null @@ -1,17 +0,0 @@ -/** - Set up an i18n binding that will update as a count changes, complete with pluralization. - - @method countI18n - @for Handlebars -**/ -Ember.Handlebars.registerHelper('countI18n', function(key, options) { - var view = Discourse.View.extend(Discourse.StringBuffer, { - tagName: 'span', - rerenderTriggers: ['count', 'suffix'], - - renderString: function(buffer) { - buffer.push(I18n.t(key + (this.get('suffix') || ''), { count: this.get('count') })); - } - }); - return Ember.Handlebars.helpers.view.call(this, view, options); -}); diff --git a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 index 42155096d..e802e058b 100644 --- a/app/assets/javascripts/discourse/helpers/custom-html.js.es6 +++ b/app/assets/javascripts/discourse/helpers/custom-html.js.es6 @@ -1,4 +1,4 @@ -Handlebars.registerHelper('custom-html', function(name, contextString, options) { +Ember.Handlebars.registerHelper('custom-html', function(name, contextString, options) { var html = Discourse.HTML.getCustomHTML(name); if (html) { return html; } diff --git a/app/assets/javascripts/discourse/helpers/loading-spinner.es6 b/app/assets/javascripts/discourse/helpers/loading-spinner.es6 index 4d0cdb7af..86ffcc89f 100644 --- a/app/assets/javascripts/discourse/helpers/loading-spinner.es6 +++ b/app/assets/javascripts/discourse/helpers/loading-spinner.es6 @@ -1,5 +1,3 @@ -import ConditionalLoadingSpinner from 'discourse/components/conditional-loading-spinner'; - function renderSpinner(cssClass) { var html = "
- {{loading-spinner condition=canLoadMore}} + {{conditional-loading-spinner condition=canLoadMore}} {{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs b/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs index 9fa600c9b..f8afeb575 100644 --- a/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs +++ b/app/assets/javascripts/discourse/templates/components/basic-topic-list.hbs @@ -1,4 +1,4 @@ -{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if topics}} {{topic-list showParticipants=showParticipants @@ -9,4 +9,4 @@ {{i18n 'choose_topic.none_found'}} {{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/components/category-drop.hbs b/app/assets/javascripts/discourse/templates/components/category-drop.hbs index 9e50cf11c..803fe6f19 100644 --- a/app/assets/javascripts/discourse/templates/components/category-drop.hbs +++ b/app/assets/javascripts/discourse/templates/components/category-drop.hbs @@ -16,7 +16,7 @@ {{#if categories}} -
+
{{#if subCategory}} diff --git a/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs b/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs index 578263c61..f58685e5c 100644 --- a/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs +++ b/app/assets/javascripts/discourse/templates/components/ip-lookup.hbs @@ -46,7 +46,7 @@ {{/if}} - {{#loading-spinner size="small" condition=otherAccountsLoading}} + {{#conditional-loading-spinner size="small" condition=otherAccountsLoading}} {{#if other_accounts.length}}
@@ -73,7 +73,7 @@
{{/if}} - {{/loading-spinner}} + {{/conditional-loading-spinner}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index 454ff2793..20443650b 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -57,13 +57,13 @@ so I'm going to stop rendering it until we figure out what's up
{{text-field value=model.title tabindex="2" id="reply-title" maxLength=maxTitleLength placeholderKey="composer.title_placeholder"}} - {{popupInputTip validation=view.titleValidation shownAt=view.showTitleTip}} + {{popup-input-tip validation=view.titleValidation shownAt=view.showTitleTip}}
{{#unless model.privateMessage}}
{{category-chooser valueAttribute="id" value=model.categoryId scopedCategoryId=scopedCategoryId tabindex="3"}} - {{popupInputTip validation=view.categoryValidation shownAt=view.showCategoryTip}} + {{popup-input-tip validation=view.categoryValidation shownAt=view.showCategoryTip}}
{{#if model.archetype.hasOptions}} @@ -80,7 +80,7 @@ so I'm going to stop rendering it until we figure out what's up
{{composer-text-area tabindex="4" value=model.reply}} - {{popupInputTip validation=view.replyValidation shownAt=view.showReplyTip}} + {{popup-input-tip validation=view.replyValidation shownAt=view.showReplyTip}}
diff --git a/app/assets/javascripts/discourse/templates/discovery.hbs b/app/assets/javascripts/discourse/templates/discovery.hbs index 1bf0814aa..be18d07ba 100644 --- a/app/assets/javascripts/discourse/templates/discovery.hbs +++ b/app/assets/javascripts/discourse/templates/discovery.hbs @@ -10,7 +10,7 @@
-{{loading-spinner condition=loading}} +{{conditional-loading-spinner condition=loading}}
diff --git a/app/assets/javascripts/discourse/templates/discovery/topics.hbs b/app/assets/javascripts/discourse/templates/discovery/topics.hbs index 494da1abb..bdcc9800f 100644 --- a/app/assets/javascripts/discourse/templates/discovery/topics.hbs +++ b/app/assets/javascripts/discourse/templates/discovery/topics.hbs @@ -25,7 +25,7 @@ {{#if topicTrackingState.hasIncoming}}
- {{countI18n topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} + {{count-i18n key=topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} {{i18n 'click_to_show'}}
@@ -51,7 +51,7 @@
diff --git a/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs b/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs index 9d07aba9c..2dfeb9ad4 100644 --- a/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs @@ -1,4 +1,4 @@ -{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#if topics}} @@ -54,4 +54,4 @@ {{i18n 'choose_topic.none_found'}} {{/if}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs b/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs index feb13c5d4..bbedfb7ca 100644 --- a/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs @@ -7,7 +7,7 @@ {{#if topicTrackingState.hasIncoming}}
- {{countI18n topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} + {{count-i18n key=topic_count_ suffix=topicTrackingState.filter count=topicTrackingState.incomingCount}} {{i18n 'click_to_show'}}
{{/if}} @@ -22,7 +22,7 @@
- {{loading-spinner condition=invitesLoading}} + {{conditional-loading-spinner condition=invitesLoading}} {{else}} {{#if canBulkInvite}} diff --git a/app/assets/javascripts/discourse/templates/user/notifications.hbs b/app/assets/javascripts/discourse/templates/user/notifications.hbs index ab18934d4..e3a137390 100644 --- a/app/assets/javascripts/discourse/templates/user/notifications.hbs +++ b/app/assets/javascripts/discourse/templates/user/notifications.hbs @@ -23,7 +23,7 @@ {{/each}} -{{#loading-spinner condition=loading}} +{{#conditional-loading-spinner condition=loading}} {{#unless canLoadMore}} {{#if showDismissButton}}
@@ -31,4 +31,4 @@
{{/if}} {{/unless}} -{{/loading-spinner}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs index 58a20209e..45ea960e7 100644 --- a/app/assets/javascripts/discourse/templates/users.hbs +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -6,7 +6,7 @@ {{text-field value=nameInput placeholderKey="directory.filter_name" class="filter-name"}} - {{#loading-spinner condition=model.loading}} + {{#conditional-loading-spinner condition=model.loading}} {{#if model.length}}
{{i18n "directory.total_rows" count=model.totalRows}}
@@ -43,12 +43,12 @@ - {{loading-spinner condition=model.loadingMore}} + {{conditional-loading-spinner condition=model.loadingMore}} {{else}}

{{i18n "directory.no_results"}}

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

Howdy Yehuda

+

Howdy Tom

+

Howdy Peter

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

Sorry, nobody is available for this task.

+ {{/each}} + ``` + + ### Specifying an alternative view for each item + + `itemViewClass` can control which view will be used during the render of each + item's template. + + The following template: + + ```handlebars +
    + {{#each developer in developers itemViewClass="person"}} + {{developer.name}} + {{/each}} +
+ ``` + + Will use the following view for each item + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li' + }); + ``` + + Resulting in HTML output that looks like the following: + + ```html +
    +
  • Yehuda
  • +
  • Tom
  • +
  • Paul
  • +
+ ``` + + `itemViewClass` also enables a non-block form of `{{each}}`. The view + must {{#crossLink "Ember.View/toc_templates"}}provide its own template{{/crossLink}}, + and then the block should be dropped. An example that outputs the same HTML + as the previous one: + + ```javascript + App.PersonView = Ember.View.extend({ + tagName: 'li', + template: '{{developer.name}}' + }); + ``` + + ```handlebars +
    + {{each developer in developers itemViewClass="person"}} +
+ ``` + + ### Specifying an alternative view for no items (else) + + The `emptyViewClass` option provides the same flexibility to the `{{else}}` + case of the each helper. + + ```javascript + App.NoPeopleView = Ember.View.extend({ + tagName: 'li', + template: 'No person is available, sorry' + }); + ``` + + ```handlebars +
    + {{#each developer in developers emptyViewClass="no-people"}} +
  • {{developer.name}}
  • + {{/each}} +
+ ``` + + ### Wrapping each item in a controller + + Controllers in Ember manage state and decorate data. In many cases, + providing a controller for each item in a list can be useful. + Specifically, an {{#crossLink "Ember.ObjectController"}}Ember.ObjectController{{/crossLink}} + should probably be used. Item controllers are passed the item they + will present as a `model` property, and an object controller will + proxy property lookups to `model` for us. + + This allows state and decoration to be added to the controller + while any other property lookups are delegated to the model. An example: + + ```javascript + App.RecruitController = Ember.ObjectController.extend({ + isAvailableForHire: function() { + return !this.get('isEmployed') && this.get('isSeekingWork'); + }.property('isEmployed', 'isSeekingWork') + }) + ``` + + ```handlebars + {{#each person in developers itemController="recruit"}} + {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}} + {{/each}} + ``` + + @method each + @for Ember.Handlebars.helpers + @param [name] {String} name for item (used with `in`) + @param [path] {String} path + @param [options] {Object} Handlebars key/value pairs of options + @param [options.itemViewClass] {String} a path to a view class used for each item + @param [options.emptyViewClass] {String} a path to a view class used for each item + @param [options.itemController] {String} name of a controller to be created for each item + */ + function eachHelper(params, hash, options, env) { + var helperName = 'each'; + var path = params[0] || this.getStream(''); + + Ember.assert( + "If you pass more than one argument to the each helper, " + + "it must be in the form #each foo in bar", + params.length <= 1 + ); + + if (options.template && options.template.blockParams) { + hash.keyword = true; + } + + Ember.deprecate( + "Using the context switching form of {{each}} is deprecated. " + + "Please use the keyword form (`{{#each foo in bar}}`) instead.", + hash.keyword === true || typeof hash.keyword === 'string', + { url: 'http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope' } + ); + + hash.dataSource = path; + options.helperName = options.helperName || helperName; + + return env.helpers.collection.helperFunction.call(this, [EachView], hash, options, env); + } + + __exports__.EachView = EachView; + __exports__.eachHelper = eachHelper; + }); +enifed("ember-htmlbars/helpers/if_unless", + ["ember-metal/core","ember-htmlbars/helpers/binding","ember-metal/property_get","ember-metal/utils","ember-views/streams/conditional_stream","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var bind = __dependency2__.bind; + + var get = __dependency3__.get; + var isArray = __dependency4__.isArray; + var ConditionalStream = __dependency5__["default"]; + var isStream = __dependency6__.isStream; + + function shouldDisplayIfHelperContent(result) { + var truthy = result && get(result, 'isTruthy'); + if (typeof truthy === 'boolean') { return truthy; } + + if (isArray(result)) { + return get(result, 'length') !== 0; + } else { + return !!result; + } + } + + var EMPTY_TEMPLATE = { + isHTMLBars: true, + render: function() { + return ''; + } + }; + /** + Use the `boundIf` helper to create a conditional that re-evaluates + whenever the truthiness of the bound value changes. + + ```handlebars + {{#boundIf "content.shouldDisplayTitle"}} + {{content.title}} + {{/boundIf}} + ``` + + @private + @method boundIf + @for Ember.Handlebars.helpers + @param {String} property Property to bind + @param {Function} fn Context to provide for rendering + @return {String} HTML string + */ + function boundIfHelper(params, hash, options, env) { + options.helperName = options.helperName || 'boundIf'; + return bind.call(this, params[0], hash, options, env, true, shouldDisplayIfHelperContent, shouldDisplayIfHelperContent, [ + 'isTruthy', + 'length' + ]); + } + + /** + @private + + Use the `unboundIf` helper to create a conditional that evaluates once. + + ```handlebars + {{#unboundIf "content.shouldDisplayTitle"}} + {{content.title}} + {{/unboundIf}} + ``` + + @method unboundIf + @for Ember.Handlebars.helpers + @param {String} property Property to bind + @param {Function} fn Context to provide for rendering + @return {String} HTML string + @since 1.4.0 + */ + function unboundIfHelper(params, hash, options, env) { + var template = options.template; + var value = params[0]; + + if (isStream(params[0])) { + value = params[0].value(); + } + + if (!shouldDisplayIfHelperContent(value)) { + template = options.inverse || EMPTY_TEMPLATE; + } + + return template.render(this, env, options.morph.contextualElement); + } + + function _inlineIfAssertion(params) { + Ember.assert("If helper in inline form expects between two and three arguments", params.length === 2 || params.length === 3); + } + + /** + See [boundIf](/api/classes/Ember.Handlebars.helpers.html#method_boundIf) + and [unboundIf](/api/classes/Ember.Handlebars.helpers.html#method_unboundIf) + + @method if + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function ifHelper(params, hash, options, env) { + Ember.assert("If helper in block form expect exactly one argument", !options.template || params.length === 1); + + options.inverse = options.inverse || EMPTY_TEMPLATE; + + options.helperName = options.helperName || ('if '); + + if (env.data.isUnbound) { + env.data.isUnbound = false; + return env.helpers.unboundIf.helperFunction.call(this, params, hash, options, env); + } else { + return env.helpers.boundIf.helperFunction.call(this, params, hash, options, env); + } + } + + /** + @method unless + @for Ember.Handlebars.helpers + @param {Function} context + @param {Hash} options + @return {String} HTML string + */ + function unlessHelper(params, hash, options, env) { + Ember.assert("You must pass exactly one argument to the unless helper", params.length === 1); + Ember.assert("You must pass a block to the unless helper", !!options.template); + + var template = options.template; + var inverse = options.inverse || EMPTY_TEMPLATE; + var helperName = 'unless'; + + options.template = inverse; + options.inverse = template; + + options.helperName = options.helperName || helperName; + + if (env.data.isUnbound) { + env.data.isUnbound = false; + return env.helpers.unboundIf.helperFunction.call(this, params, hash, options, env); + } else { + return env.helpers.boundIf.helperFunction.call(this, params, hash, options, env); + } + } + + __exports__.ifHelper = ifHelper; + __exports__.boundIfHelper = boundIfHelper; + __exports__.unboundIfHelper = unboundIfHelper; + __exports__.unlessHelper = unlessHelper; + }); +enifed("ember-htmlbars/helpers/input", + ["ember-views/views/checkbox","ember-views/views/text_field","ember-metal/streams/utils","ember-metal/core","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { "use strict"; var Checkbox = __dependency1__["default"]; var TextField = __dependency2__["default"]; - var TextArea = __dependency3__["default"]; + var read = __dependency3__.read; var Ember = __dependency4__["default"]; // Ember.assert - // var emberAssert = Ember.assert; - - var EmberHandlebars = __dependency5__["default"]; /** @module ember - @submodule ember-handlebars-compiler + @submodule ember-htmlbars */ /** @@ -5262,12 +6489,10 @@ enifed("ember-handlebars/controls", The action property defines the action which is sent when the user presses the return key. - ```handlebars {{input action="submit"}} ``` - The helper allows some user events to send actions. * `enter` @@ -5281,12 +6506,10 @@ enifed("ember-handlebars/controls", For example, if you desire an action to be sent when the input is blurred, you only need to setup the action name to the event name property. - ```handlebars {{input focus-in="alertMessage"}} ``` - See more about [Text Support Actions](/api/classes/Ember.TextField.html) ## Extension @@ -5376,38 +6599,274 @@ enifed("ember-handlebars/controls", @for Ember.Handlebars.helpers @param {Hash} options */ - function inputHelper(options) { - Ember.assert('You can only pass attributes to the `input` helper, not arguments', arguments.length < 2); + function inputHelper(params, hash, options, env) { + Ember.assert('You can only pass attributes to the `input` helper, not arguments', params.length === 0); - var view = options.data.view; - var hash = options.hash; - var types = options.hashTypes; var onEvent = hash.on; var inputType; - if (types.type === 'ID') { - inputType = view.getStream(hash.type).value(); - } else { - inputType = hash.type; - } + inputType = read(hash.type); if (inputType === 'checkbox') { delete hash.type; - delete types.type; Ember.assert("{{input type='checkbox'}} does not support setting `value=someBooleanValue`;" + - " you must use `checked=someBooleanValue` instead.", options.hashTypes.value !== 'ID'); + " you must use `checked=someBooleanValue` instead.", !hash.hasOwnProperty('value')); - return EmberHandlebars.helpers.view.call(this, Checkbox, options); + env.helpers.view.helperFunction.call(this, [Checkbox], hash, options, env); } else { delete hash.on; hash.onEvent = onEvent || 'enter'; - return EmberHandlebars.helpers.view.call(this, TextField, options); + env.helpers.view.helperFunction.call(this, [TextField], hash, options, env); } } - __exports__.inputHelper = inputHelper;/** + __exports__.inputHelper = inputHelper; + }); +enifed("ember-htmlbars/helpers/loc", + ["ember-metal/core","ember-runtime/system/string","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + var loc = __dependency2__.loc; + var isStream = __dependency3__.isStream; + + /** + @module ember + @submodule ember-htmlbars + */ + + /** + Calls [Ember.String.loc](/api/classes/Ember.String.html#method_loc) with the + provided string. + + This is a convenient way to localize text within a template: + + ```javascript + Ember.STRINGS = { + '_welcome_': 'Bonjour' + }; + ``` + + ```handlebars +
+ {{loc '_welcome_'}} +
+ ``` + + ```html +
+ Bonjour +
+ ``` + + See [Ember.String.loc](/api/classes/Ember.String.html#method_loc) for how to + set up localized string references. + + @method loc + @for Ember.Handlebars.helpers + @param {String} str The string to format + @see {Ember.String#loc} + */ + function locHelper(params, hash, options, env) { + Ember.assert('You cannot pass bindings to `loc` helper', (function ifParamsContainBindings() { + for (var i = 0, l = params.length; i < l; i++) { + if (isStream(params[i])) { + return false; + } + } + return true; + })()); + + return loc.apply(this, params); + } + + __exports__.locHelper = locHelper; + }); +enifed("ember-htmlbars/helpers/log", + ["ember-metal/logger","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + var Logger = __dependency1__["default"]; + var read = __dependency2__.read; + + /** + `log` allows you to output the value of variables in the current rendering + context. `log` also accepts primitive types such as strings or numbers. + + ```handlebars + {{log "myVariable:" myVariable }} + ``` + + @method log + @for Ember.Handlebars.helpers + @param {String} property + */ + function logHelper(params, hash, options, env) { + var logger = Logger.log; + var values = []; + + for (var i = 0; i < params.length; i++) { + values.push(read(params[i])); + } + + logger.apply(logger, values); + } + + __exports__.logHelper = logHelper; + }); +enifed("ember-htmlbars/helpers/partial", + ["ember-metal/core","ember-metal/is_none","./binding","ember-metal/streams/utils","exports"], + function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.assert + + var isNone = __dependency2__["default"]; + var bind = __dependency3__.bind; + var isStream = __dependency4__.isStream; + + /** + @module ember + @submodule ember-htmlbars + */ + + /** + The `partial` helper renders another template without + changing the template context: + + ```handlebars + {{foo}} + {{partial "nav"}} + ``` + + The above example template will render a template named + "_nav", which has the same context as the parent template + it's rendered into, so if the "_nav" template also referenced + `{{foo}}`, it would print the same thing as the `{{foo}}` + in the above example. + + If a "_nav" template isn't found, the `partial` helper will + fall back to a template named "nav". + + ## Bound template names + + The parameter supplied to `partial` can also be a path + to a property containing a template name, e.g.: + + ```handlebars + {{partial someTemplateName}} + ``` + + The above example will look up the value of `someTemplateName` + on the template context (e.g. a controller) and use that + value as the name of the template to render. If the resolved + value is falsy, nothing will be rendered. If `someTemplateName` + changes, the partial will be re-rendered using the new template + name. + + + @method partial + @for Ember.Handlebars.helpers + @param {String} partialName the name of the template to render minus the leading underscore + */ + + function partialHelper(params, hash, options, env) { + options.helperName = options.helperName || 'partial'; + + var name = params[0]; + + if (isStream(name)) { + options.template = createPartialTemplate(name); + bind.call(this, name, hash, options, env, true, exists); + } else { + return renderPartial(name, this, env, options.morph.contextualElement); + } + } + + __exports__.partialHelper = partialHelper;function exists(value) { + return !isNone(value); + } + + function lookupPartial(view, templateName) { + var nameParts = templateName.split("/"); + var lastPart = nameParts[nameParts.length - 1]; + + nameParts[nameParts.length - 1] = "_" + lastPart; + + var underscoredName = nameParts.join('/'); + var template = view.templateForName(underscoredName); + if (!template) { + template = view.templateForName(templateName); + } + + Ember.assert('Unable to find partial with name "'+templateName+'"', !!template); + + return template; + } + + function renderPartial(name, view, env, contextualElement) { + var template = lookupPartial(view, name); + return template.render(view, env, contextualElement); + } + + function createPartialTemplate(nameStream) { + return { + isHTMLBars: true, + render: function(view, env, contextualElement) { + return renderPartial(nameStream.value(), view, env, contextualElement); + } + }; + } + }); +enifed("ember-htmlbars/helpers/template", + ["ember-metal/core","exports"], + function(__dependency1__, __exports__) { + "use strict"; + var Ember = __dependency1__["default"]; + // Ember.deprecate; + + /** + @module ember + @submodule ember-htmlbars + */ + + /** + @deprecated + @method template + @for Ember.Handlebars.helpers + @param {String} templateName the template to render + */ + function templateHelper(params, hash, options, env) { + Ember.deprecate("The `template` helper has been deprecated in favor of the `partial` helper." + + " Please use `partial` instead, which will work the same way."); + + options.helperName = options.helperName || 'template'; + + return env.helpers.partial.helperFunction.call(this, params, hash, options, env); + } + + __exports__.templateHelper = templateHelper; + }); +enifed("ember-htmlbars/helpers/text_area", + ["ember-metal/core","ember-views/views/text_area","exports"], + function(__dependency1__, __dependency2__, __exports__) { + "use strict"; + /** + @module ember + @submodule ember-htmlbars + */ + + var Ember = __dependency1__["default"]; + // Ember.assert + var TextArea = __dependency2__["default"]; + + /** `{{textarea}}` inserts a new instance of `