Clean up discourse.js

This commit is contained in:
Robin Ward 2013-02-26 14:54:43 -05:00
parent b9ccf4d09c
commit 1caf1e6b45
21 changed files with 818 additions and 537 deletions

View file

@ -4,7 +4,7 @@
@method buildRoutes @method buildRoutes
@for Discourse.AdminRoute @for Discourse.AdminRoute
**/ **/
Discourse.buildRoutes(function() { Discourse.Route.buildRoutes(function() {
this.resource('admin', { path: '/admin' }, function() { this.resource('admin', { path: '/admin' }, function() {
this.route('dashboard', { path: '/' }); this.route('dashboard', { path: '/' });
this.route('site_settings', { path: '/site_settings' }); this.route('site_settings', { path: '/site_settings' });

View file

@ -1,31 +1,28 @@
/*global Modernizr:true*/ /*global Modernizr:true*/
/*global assetPath:true*/ /*global assetPath:true*/
var csrf_token; /**
The main Discourse Application
@class Discourse
@extends Ember.Application
**/
Discourse = Ember.Application.createWithMixins({ Discourse = Ember.Application.createWithMixins({
rootElement: '#main', rootElement: '#main',
// Data we want to remember for a short period // Data we want to remember for a short period
transient: Em.Object.create(), transient: Em.Object.create(),
// Whether the app has focus or not
hasFocus: true, hasFocus: true,
// Are we currently scrolling?
scrolling: false, scrolling: false,
// The highest seen post number by topic // The highest seen post number by topic
highestSeenByTopic: {}, highestSeenByTopic: {},
logoSmall: (function() { titleChanged: function() {
var logo;
logo = Discourse.SiteSettings.logo_small_url;
if (logo && logo.length > 1) {
return "<img src='" + logo + "' width='33' height='33'>";
} else {
return "<i class='icon-home'></i>";
}
}).property(),
titleChanged: (function() {
var title; var title;
title = ""; title = "";
if (this.get('title')) { if (this.get('title')) {
@ -37,51 +34,45 @@ Discourse = Ember.Application.createWithMixins({
title = "(*) " + title; title = "(*) " + title;
} }
// chrome bug workaround see: http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome // chrome bug workaround see: http://stackoverflow.com/questions/2952384/changing-the-window-title-when-focussing-the-window-doesnt-work-in-chrome
window.setTimeout((function() { window.setTimeout(function() {
document.title = "."; document.title = ".";
document.title = title; document.title = title;
}), 200); }, 200);
}).observes('title', 'hasFocus', 'notify'), }.observes('title', 'hasFocus', 'notify'),
currentUserChanged: (function() { currentUserChanged: function() {
var bus, user;
bus = Discourse.MessageBus;
// We don't want to receive any previous user notifications // We don't want to receive any previous user notifications
var bus = Discourse.MessageBus;
bus.unsubscribe("/notification/*"); bus.unsubscribe("/notification/*");
bus.callbackInterval = Discourse.SiteSettings.anon_polling_interval; bus.callbackInterval = Discourse.SiteSettings.anon_polling_interval;
bus.enableLongPolling = false; bus.enableLongPolling = false;
user = this.get('currentUser');
var user = this.get('currentUser');
if (user) { if (user) {
bus.callbackInterval = Discourse.SiteSettings.polling_interval; bus.callbackInterval = Discourse.SiteSettings.polling_interval;
bus.enableLongPolling = true; bus.enableLongPolling = true;
if (user.admin) { if (user.admin) {
bus.subscribe("/flagged_counts", function(data) { bus.subscribe("/flagged_counts", function(data) {
return user.set('site_flagged_posts_count', data.total); user.set('site_flagged_posts_count', data.total);
}); });
} }
return bus.subscribe("/notification/" + user.id, (function(data) { bus.subscribe("/notification/" + user.id, (function(data) {
user.set('unread_notifications', data.unread_notifications); user.set('unread_notifications', data.unread_notifications);
return user.set('unread_private_messages', data.unread_private_messages); user.set('unread_private_messages', data.unread_private_messages);
}), user.notification_channel_position); }), user.notification_channel_position);
} }
}).observes('currentUser'), }.observes('currentUser'),
notifyTitle: function() {
return this.set('notify', true);
},
// Browser aware replaceState // The classes of buttons to show on a post
replaceState: function(path) { postButtons: function() {
if (window.history && return Discourse.SiteSettings.post_menu.split("|").map(function(i) {
window.history.pushState && return (i.replace(/\+/, '').capitalize());
window.history.replaceState && });
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/)) { }.property('Discourse.SiteSettings.post_menu'),
if (window.location.pathname !== path) {
return history.replaceState({ notifyTitle: function() {
path: path this.set('notify', true);
}, null, path);
}
}
}, },
openComposer: function(opts) { openComposer: function(opts) {
@ -90,291 +81,108 @@ Discourse = Ember.Application.createWithMixins({
if (composer) composer.open(opts); if (composer) composer.open(opts);
}, },
// Like router.route, but allow full urls rather than relative one /**
// HERE BE HACKS - uses the ember container for now until we can do this nicer. Establishes global DOM events and bindings via jQuery.
routeTo: function(path) {
var newMatches, newTopicId, oldMatches, oldTopicId, opts, router, topicController, topicRegexp;
path = path.replace(/https?\:\/\/[^\/]+/, '');
// If we're in the same topic, don't push the state
topicRegexp = /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/;
newMatches = topicRegexp.exec(path);
newTopicId = newMatches ? newMatches[2] : null;
if (newTopicId) {
oldMatches = topicRegexp.exec(window.location.pathname);
if ((oldTopicId = oldMatches ? oldMatches[2] : void 0) && (oldTopicId === newTopicId)) {
Discourse.replaceState(path);
topicController = Discourse.__container__.lookup('controller:topic');
opts = {
trackVisit: false
};
if (newMatches[3]) {
opts.nearPost = newMatches[3];
}
topicController.get('content').loadPosts(opts);
return;
}
}
// Be wary of looking up the router. In this case, we have links in our
// HTML, say form compiled markdown posts, that need to be routed.
router = Discourse.__container__.lookup('router:main');
router.router.updateURL(path);
return router.handleURL(path);
},
// The classes of buttons to show on a post
postButtons: (function() {
return Discourse.SiteSettings.post_menu.split("|").map(function(i) {
return "" + (i.replace(/\+/, '').capitalize());
});
}).property('Discourse.SiteSettings.post_menu'),
@method bindDOMEvents
**/
bindDOMEvents: function() { bindDOMEvents: function() {
var $html, hasTouch, var $html, hasTouch;
_this = this;
$html = $('html');
/* Add the discourse touch event */ $html = $('html');
hasTouch = false; hasTouch = false;
if ($html.hasClass('touch')) { if ($html.hasClass('touch')) {
hasTouch = true; hasTouch = true;
} }
if (Modernizr.prefixed("MaxTouchPoints", navigator) > 1) { if (Modernizr.prefixed("MaxTouchPoints", navigator) > 1) {
hasTouch = true; hasTouch = true;
} }
if (hasTouch) { if (hasTouch) {
$html.addClass('discourse-touch'); $html.addClass('discourse-touch');
this.touch = true; this.touch = true;
this.hasTouch = true; this.hasTouch = true;
} else { } else {
$html.addClass('discourse-no-touch'); $html.addClass('discourse-no-touch');
this.touch = false; this.touch = false;
} }
$('#main').on('click.discourse', '[data-not-implemented=true]', function(e) { $('#main').on('click.discourse', '[data-not-implemented=true]', function(e) {
e.preventDefault(); e.preventDefault();
alert(Em.String.i18n('not_implemented')); alert(Em.String.i18n('not_implemented'));
return false; return false;
}); });
$('#main').on('click.discourse', 'a', function(e) { $('#main').on('click.discourse', 'a', function(e) {
var $currentTarget, href; if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey) return;
if (e.isDefaultPrevented() || e.metaKey || e.ctrlKey) {
return; var $currentTarget = $(e.currentTarget);
} var href = $currentTarget.attr('href');
$currentTarget = $(e.currentTarget); if (!href) return;
href = $currentTarget.attr('href'); if (href === '#') return;
if (href === void 0) { if ($currentTarget.attr('target')) return;
return; if ($currentTarget.data('auto-route')) return;
} if ($currentTarget.hasClass('lightbox')) return;
if (href === '#') { if (href.indexOf("mailto:") === 0) return;
return; if (href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i"))) return;
}
if ($currentTarget.attr('target')) {
return;
}
if ($currentTarget.data('auto-route')) {
return;
}
if ($currentTarget.hasClass('lightbox')) {
return;
}
if (href.indexOf("mailto:") === 0) {
return;
}
if (href.match(/^http[s]?:\/\//i) && !href.match(new RegExp("^http:\\/\\/" + window.location.hostname, "i"))) {
return;
}
e.preventDefault(); e.preventDefault();
_this.routeTo(href); Discourse.URL.routeTo(href);
return false; return false;
}); });
return $(window).focus(function() {
_this.set('hasFocus', true); $(window).focus(function() {
return _this.set('notify', false); Discourse.set('hasFocus', true);
Discourse.set('notify', false);
}).blur(function() { }).blur(function() {
return _this.set('hasFocus', false); Discourse.set('hasFocus', false);
}); });
},
logout: function() { // Add a CSRF token to all AJAX requests
var username, var csrfToken = $('meta[name=csrf-token]').attr('content');
_this = this; jQuery.ajaxPrefilter(function(options, originalOptions, xhr) {
username = this.get('currentUser.username'); if (!options.crossDomain) {
Discourse.KeyValueStore.abandonLocal(); xhr.setRequestHeader('X-CSRF-Token', csrfToken);
return jQuery.ajax("/session/" + username, {
type: 'DELETE',
success: function(result) {
/* To keep lots of our variables unbound, we can handle a redirect on logging out.
*/
return window.location.reload();
} }
}); });
}, },
/* fancy probes in ember
*/
insertProbes: function() { /**
var topLevel; Log the current user out of Discourse
if (typeof console === "undefined" || console === null) {
return; @method logout
} **/
topLevel = function(fn, name) { logout: function() {
return window.probes.measure(fn, { Discourse.KeyValueStore.abandonLocal();
name: name, return jQuery.ajax("/session/" + this.get('currentUser.username'), {
before: function(data, owner, args) { type: 'DELETE',
if (owner) { success: function(result) {
return window.probes.clear(); // To keep lots of our variables unbound, we can handle a redirect on logging out.
} window.location.reload();
}, }
after: function(data, owner, args) { });
var ary, f, n, v, _ref;
if (owner && data.time > 10) {
f = function(name, data) {
if (data && data.count) {
return "" + name + " - " + data.count + " calls " + ((data.time + 0.0).toFixed(2)) + "ms";
}
};
if (console && console.group) {
console.group(f(name, data));
} else {
console.log("");
console.log(f(name, data));
}
ary = [];
_ref = window.probes;
for (n in _ref) {
v = _ref[n];
if (n === name || v.time < 1) {
continue;
}
ary.push({
k: n,
v: v
});
}
ary.sortBy(function(item) {
if (item.v && item.v.time) {
return -item.v.time;
} else {
return 0;
}
}).each(function(item) {
var output = f("" + item.k, item.v);
if (output) {
return console.log(output);
}
});
if (typeof console !== "undefined" && console !== null) {
if (typeof console.groupEnd === "function") {
console.groupEnd();
}
}
return window.probes.clear();
}
}
});
};
Ember.View.prototype.renderToBuffer = window.probes.measure(Ember.View.prototype.renderToBuffer, "renderToBuffer");
Discourse.routeTo = topLevel(Discourse.routeTo, "Discourse.routeTo");
Ember.run.end = topLevel(Ember.run.end, "Ember.run.end");
}, },
authenticationComplete: function(options) { authenticationComplete: function(options) {
// TODO, how to dispatch this to the view without the container? // TODO, how to dispatch this to the view without the container?
var loginView; var loginView;
loginView = Discourse.__container__.lookup('controller:modal').get('currentView'); loginView = Discourse.__container__.lookup('controller:modal').get('currentView');
return loginView.authenticationComplete(options); return loginView.authenticationComplete(options);
}, },
buildRoutes: function(builder) {
var oldBuilder;
oldBuilder = Discourse.routeBuilder;
Discourse.routeBuilder = function() {
if (oldBuilder) {
oldBuilder.call(this);
}
return builder.call(this);
};
},
start: function() { start: function() {
this.bindDOMEvents(); Discourse.bindDOMEvents();
Discourse.SiteSettings = PreloadStore.getStatic('siteSettings'); Discourse.SiteSettings = PreloadStore.getStatic('siteSettings');
Discourse.MessageBus.start(); Discourse.MessageBus.start();
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus); Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
Discourse.insertProbes();
// subscribe to any site customizations that are loaded // Developer specific functions
$('link.custom-css').each(function() { Discourse.Development.setupProbes();
var id, split, stylesheet, Discourse.Development.observeLiveChanges();
_this = this;
split = this.href.split("/");
id = split[split.length - 1].split(".css")[0];
stylesheet = this;
return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
var orig, sp;
if (!$(stylesheet).data('orig')) {
$(stylesheet).data('orig', stylesheet.href);
}
orig = $(stylesheet).data('orig');
sp = orig.split(".css?");
stylesheet.href = sp[0] + ".css?" + data;
});
});
$('header.custom').each(function() {
var header;
header = $(this);
return Discourse.MessageBus.subscribe("/header-change/" + ($(this).data('key')), function(data) {
return header.html(data);
});
});
// possibly move this to dev only
return Discourse.MessageBus.subscribe("/file-change", function(data) {
Ember.TEMPLATES.empty = Handlebars.compile("<div></div>");
return data.each(function(me) {
var js;
if (me === "refresh") {
return document.location.reload(true);
} else if (me.name.substr(-10) === "handlebars") {
js = me.name.replace(".handlebars", "").replace("app/assets/javascripts", "/assets");
return $LAB.script(js + "?hash=" + me.hash).wait(function() {
var templateName;
templateName = js.replace(".js", "").replace("/assets/", "");
return jQuery.each(Ember.View.views, function() {
var _this = this;
if (this.get('templateName') === templateName) {
this.set('templateName', 'empty');
this.rerender();
return Em.run.next(function() {
_this.set('templateName', templateName);
return _this.rerender();
});
}
});
});
} else {
return $('link').each(function() {
if (this.href.match(me.name) && me.hash) {
if (!$(this).data('orig')) {
$(this).data('orig', this.href);
}
this.href = $(this).data('orig') + "&hash=" + me.hash;
}
});
}
});
});
} }
}); });
Discourse.Router = Discourse.Router.reopen({ Discourse.Router = Discourse.Router.reopen({ location: 'discourse_location' });
location: 'discourse_location'
});
// since we have no jquery-rails these days, hook up csrf token
csrf_token = $('meta[name=csrf-token]').attr('content');
jQuery.ajaxPrefilter(function(options, originalOptions, xhr) {
if (!options.crossDomain) {
xhr.setRequestHeader('X-CSRF-Token', csrf_token);
}
});

View file

@ -88,7 +88,7 @@ Discourse.ClickTrack = {
topic_id: topicId, topic_id: topicId,
redirect: false redirect: false
}); });
Discourse.routeTo(href); Discourse.URL.routeTo(href);
return false; return false;
} }

View file

@ -0,0 +1,158 @@
/**
Functions to help development of Discourse, such as inserting probes
@class Development
@namespace Discourse
@module Discourse
**/
Discourse.Development = {
/**
Set up probes for performance measurements.
@method setupProbes
**/
setupProbes: function() {
// Don't probe if we don't have a console
if (typeof console === "undefined" || console === null) return;
var topLevel = function(fn, name) {
return window.probes.measure(fn, {
name: name,
before: function(data, owner, args) {
if (owner) {
return window.probes.clear();
}
},
after: function(data, owner, args) {
var ary, f, n, v, _ref;
if (owner && data.time > 10) {
f = function(name, data) {
if (data && data.count) return name + " - " + data.count + " calls " + ((data.time + 0.0).toFixed(2)) + "ms";
};
if (console && console.group) {
console.group(f(name, data));
} else {
console.log("");
console.log(f(name, data));
}
ary = [];
_ref = window.probes;
for (n in _ref) {
v = _ref[n];
if (n === name || v.time < 1) {
continue;
}
ary.push({
k: n,
v: v
});
}
ary.sortBy(function(item) {
if (item.v && item.v.time) {
return -item.v.time;
} else {
return 0;
}
}).each(function(item) {
var output = f("" + item.k, item.v);
if (output) {
return console.log(output);
}
});
if (typeof console !== "undefined" && console !== null) {
if (typeof console.groupEnd === "function") {
console.groupEnd();
}
}
return window.probes.clear();
}
}
});
};
Ember.View.prototype.renderToBuffer = window.probes.measure(Ember.View.prototype.renderToBuffer, "renderToBuffer");
Discourse.URL.routeTo = topLevel(Discourse.URL.routeTo, "Discourse.URL.routeTo");
Ember.run.end = topLevel(Ember.run.end, "Ember.run.end");
},
/**
Use the message bus for live reloading of components for faster development.
@method observeLiveChanges
**/
observeLiveChanges: function() {
// subscribe to any site customizations that are loaded
$('link.custom-css').each(function() {
var id, split, stylesheet,
_this = this;
split = this.href.split("/");
id = split[split.length - 1].split(".css")[0];
stylesheet = this;
return Discourse.MessageBus.subscribe("/file-change/" + id, function(data) {
var orig, sp;
if (!$(stylesheet).data('orig')) {
$(stylesheet).data('orig', stylesheet.href);
}
orig = $(stylesheet).data('orig');
sp = orig.split(".css?");
stylesheet.href = sp[0] + ".css?" + data;
});
});
// Custom header changes
$('header.custom').each(function() {
var header;
header = $(this);
return Discourse.MessageBus.subscribe("/header-change/" + ($(this).data('key')), function(data) {
return header.html(data);
});
});
// Observe file changes
return Discourse.MessageBus.subscribe("/file-change", function(data) {
Ember.TEMPLATES.empty = Handlebars.compile("<div></div>");
return data.each(function(me) {
var js;
if (me === "refresh") {
return document.location.reload(true);
} else if (me.name.substr(-10) === "handlebars") {
js = me.name.replace(".handlebars", "").replace("app/assets/javascripts", "/assets");
return $LAB.script(js + "?hash=" + me.hash).wait(function() {
var templateName;
templateName = js.replace(".js", "").replace("/assets/", "");
return jQuery.each(Ember.View.views, function() {
var _this = this;
if (this.get('templateName') === templateName) {
this.set('templateName', 'empty');
this.rerender();
return Em.run.next(function() {
_this.set('templateName', templateName);
return _this.rerender();
});
}
});
});
} else {
return $('link').each(function() {
if (this.href.match(me.name) && me.hash) {
if (!$(this).data('orig')) {
$(this).data('orig', this.href);
}
this.href = $(this).data('orig') + "&hash=" + me.hash;
}
});
}
});
});
}
};

View file

@ -0,0 +1,69 @@
/**
URL related functions.
@class URL
@namespace Discourse
@module Discourse
**/
Discourse.URL = {
/**
Browser aware replaceState. Will only be invoked if the browser supports it.
@method replaceState
@param {String} path The path we are replacing our history state with.
**/
replaceState: function(path) {
if (window.history &&
window.history.pushState &&
window.history.replaceState &&
!navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/) &&
(window.location.pathname !== path)) {
return history.replaceState({ path: path }, null, path);
}
},
/**
Our custom routeTo method is used to intelligently overwrite default routing
behavior.
It contains the logic necessary to route within a topic using replaceState to
keep the history intact.
Note that currently it uses `__container__` which is not advised
but there is no other way to access the router.
@method routeTo
@param {String} path The path we are routing to.
**/
routeTo: function(path) {
var newMatches, newTopicId, oldMatches, oldTopicId, opts, router, topicController, topicRegexp;
path = path.replace(/https?\:\/\/[^\/]+/, '');
console.log("route to: " + path);
// If we're in the same topic, don't push the state
topicRegexp = /\/t\/([^\/]+)\/(\d+)\/?(\d+)?/;
newMatches = topicRegexp.exec(path);
newTopicId = newMatches ? newMatches[2] : null;
if (newTopicId) {
oldMatches = topicRegexp.exec(window.location.pathname);
if ((oldTopicId = oldMatches ? oldMatches[2] : void 0) && (oldTopicId === newTopicId)) {
Discourse.URL.replaceState(path);
topicController = Discourse.__container__.lookup('controller:topic');
opts = { trackVisit: false };
if (newMatches[3]) {
opts.nearPost = newMatches[3];
}
topicController.get('content').loadPosts(opts);
return;
}
}
// Be wary of looking up the router. In this case, we have links in our
// HTML, say form compiled markdown posts, that need to be routed.
router = Discourse.__container__.lookup('router:main');
router.router.updateURL(path);
return router.handleURL(path);
}
};

View file

@ -42,7 +42,7 @@ Discourse.ComposerController = Discourse.Controller.extend({
} else { } else {
Discourse.set('currentUser.reply_count', Discourse.get('currentUser.reply_count') + 1); Discourse.set('currentUser.reply_count', Discourse.get('currentUser.reply_count') + 1);
} }
Discourse.routeTo(opts.post.get('url')); Discourse.URL.routeTo(opts.post.get('url'));
}, function(error) { }, function(error) {
composer.set('disableDrafts', false); composer.set('disableDrafts', false);
bootbox.alert(error); bootbox.alert(error);
@ -159,7 +159,7 @@ Discourse.ComposerController = Discourse.Controller.extend({
// View a new reply we've made // View a new reply we've made
viewNewReply: function() { viewNewReply: function() {
Discourse.routeTo(this.get('createdPost.url')); Discourse.URL.routeTo(this.get('createdPost.url'));
this.close(); this.close();
return false; return false;
}, },

View file

@ -1,21 +1,21 @@
/** /**
This controller supports actions on the site header This controller supports actions on the site header
@class HeaderController @class HeaderController
@extends Discourse.Controller @extends Discourse.Controller
@namespace Discourse @namespace Discourse
@module Discourse @module Discourse
**/ **/
Discourse.HeaderController = Discourse.Controller.extend({ Discourse.HeaderController = Discourse.Controller.extend({
topic: null, topic: null,
showExtraInfo: false, showExtraInfo: null,
toggleStar: function() { toggleStar: function() {
var topic = this.get('topic'); var topic = this.get('topic');
if (topic) topic.toggleStar(); if (topic) topic.toggleStar();
return false; return false;
} }
}); });

View file

@ -10,7 +10,6 @@ Discourse.TopicController = Discourse.ObjectController.extend({
userFilters: new Em.Set(), userFilters: new Em.Set(),
multiSelect: false, multiSelect: false,
bestOf: false, bestOf: false,
showExtraHeaderInfo: false,
needs: ['header', 'modal', 'composer', 'quoteButton'], needs: ['header', 'modal', 'composer', 'quoteButton'],
filter: (function() { filter: (function() {
@ -42,10 +41,6 @@ Discourse.TopicController = Discourse.ObjectController.extend({
return this.get('canDeleteSelected'); return this.get('canDeleteSelected');
}).property('canDeleteSelected'), }).property('canDeleteSelected'),
showExtraHeaderInfoChanged: (function() {
this.set('controllers.header.showExtraInfo', this.get('showExtraHeaderInfo'));
}).observes('showExtraHeaderInfo'),
canDeleteSelected: (function() { canDeleteSelected: (function() {
var canDelete, selectedPosts; var canDelete, selectedPosts;
selectedPosts = this.get('selectedPosts'); selectedPosts = this.get('selectedPosts');
@ -109,11 +104,11 @@ Discourse.TopicController = Discourse.ObjectController.extend({
}, },
jumpTop: function() { jumpTop: function() {
Discourse.routeTo(this.get('content.url')); Discourse.URL.routeTo(this.get('content.url'));
}, },
jumpBottom: function() { jumpBottom: function() {
Discourse.routeTo(this.get('content.lastPostUrl')); Discourse.URL.routeTo(this.get('content.lastPostUrl'));
}, },
cancelFilter: function() { cancelFilter: function() {

View file

@ -9,7 +9,7 @@
Discourse.UserPrivateMessagesController = Discourse.ObjectController.extend({ Discourse.UserPrivateMessagesController = Discourse.ObjectController.extend({
editPreferences: function() { editPreferences: function() {
return Discourse.routeTo("/users/" + (this.get('content.username_lower')) + "/preferences"); return Discourse.URL.routeTo("/users/" + (this.get('content.username_lower')) + "/preferences");
}, },
composePrivateMessage: function() { composePrivateMessage: function() {

View file

@ -14,7 +14,7 @@ Discourse.TopicList = Discourse.Model.extend({
_this = this; _this = this;
promise = new RSVP.Promise(); promise = new RSVP.Promise();
if (moreUrl = this.get('more_topics_url')) { if (moreUrl = this.get('more_topics_url')) {
Discourse.replaceState("/" + (this.get('filter')) + "/more"); Discourse.URL.replaceState("/" + (this.get('filter')) + "/more");
jQuery.ajax(moreUrl, { jQuery.ajax(moreUrl, {
success: function(result) { success: function(result) {
var newTopics, topicIds, topics; var newTopics, topicIds, topics;

View file

@ -4,7 +4,7 @@
@method buildRoutes @method buildRoutes
@for Discourse.ApplicationRoute @for Discourse.ApplicationRoute
**/ **/
Discourse.buildRoutes(function() { Discourse.Route.buildRoutes(function() {
var router = this; var router = this;
// Topic routes // Topic routes

View file

@ -28,3 +28,14 @@ Discourse.Route = Em.Route.extend({
}); });
Discourse.Route.reopenClass({
buildRoutes: function(builder) {
var oldBuilder = Discourse.routeBuilder;
Discourse.routeBuilder = function() {
if (oldBuilder) oldBuilder.call(this);
return builder.call(this);
};
}
});

View file

@ -34,10 +34,7 @@ Discourse.TopicRoute = Discourse.Route.extend({
}, },
setupController: function(controller, model) { setupController: function(controller, model) {
var headerController; this.controllerFor('header').set('topic', model);
controller.set('showExtraHeaderInfo', false);
headerController = this.controllerFor('header');
headerController.set('topic', model);
} }
}); });

View file

@ -1,17 +1,7 @@
<div class='container'> <div class='container'>
<div class='contents clearfix'> <div class='contents clearfix'>
<div class='title'>
{{#if controller.showExtraInfo}}
{{#linkTo list.popular}}{{{Discourse.logoSmall}}}{{/linkTo}}
{{else}}
{{#linkTo list.popular}}<img src="{{unbound Discourse.SiteSettings.logo_url}}" alt="{{unbound Discourse.SiteSettings.title}}" id='site-logo'>{{/linkTo}}
{{/if}}
</div>
{{view.logoHTML}}
{{view Discourse.TopicExtraInfoView}} {{view Discourse.TopicExtraInfoView}}
<div class='panel clearfix'> <div class='panel clearfix'>
@ -24,7 +14,7 @@
{{/if}} {{/if}}
</div> </div>
{{/unless}} {{/unless}}
<ul class='icons clearfix'> <ul class='icons clearfix'>
<li class='notifications'> <li class='notifications'>
{{#if view.currentUser}} {{#if view.currentUser}}
<a class='icon' href="#" {{action showNotifications target="view"}} data-notifications="notifications-dropdown" id='user-notifications' title='{{i18n notifications.title}}'><i class='icon-comment'></i></a> <a class='icon' href="#" {{action showNotifications target="view"}} data-notifications="notifications-dropdown" id='user-notifications' title='{{i18n notifications.title}}'><i class='icon-comment'></i></a>
@ -38,7 +28,7 @@
<a class='icon' href="#" {{action showLogin}} title='{{i18n notifications.title}}'><i class='icon-comment'></i></a> <a class='icon' href="#" {{action showLogin}} title='{{i18n notifications.title}}'><i class='icon-comment'></i></a>
{{/if}} {{/if}}
</li> </li>
<li> <li>
<a class='icon expand' href='#' data-dropdown="search-dropdown" title='{{i18n search.title}}'><i class='icon-search'></i></a> <a class='icon expand' href='#' data-dropdown="search-dropdown" title='{{i18n search.title}}'><i class='icon-search'></i></a>
</li> </li>
<li class='categories dropdown'> <li class='categories dropdown'>
@ -46,7 +36,7 @@
{{#if view.currentUser.site_flagged_posts_count}} {{#if view.currentUser.site_flagged_posts_count}}
<a href='/admin/flags/active' title='total flagged posts' class='badge-notification flagged-posts'>{{view.currentUser.site_flagged_posts_count}}</a> <a href='/admin/flags/active' title='total flagged posts' class='badge-notification flagged-posts'>{{view.currentUser.site_flagged_posts_count}}</a>
{{/if}} {{/if}}
</li> </li>
<li class='current-user'> <li class='current-user'>
{{#if view.currentUser}} {{#if view.currentUser}}
{{#titledLinkTo user.activity view.currentUser titleKey="current_user" class="icon"}}{{avatar Discourse.currentUser imageSize="medium" }}{{/titledLinkTo}} {{#titledLinkTo user.activity view.currentUser titleKey="current_user" class="icon"}}{{avatar Discourse.currentUser imageSize="medium" }}{{/titledLinkTo}}
@ -58,7 +48,7 @@
{{view Discourse.SearchView currentUserBinding="view.currentUser"}} {{view Discourse.SearchView currentUserBinding="view.currentUser"}}
<section class='d-dropdown' id='notifications-dropdown'> <section class='d-dropdown' id='notifications-dropdown'>
{{#if view.notifications}} {{#if view.notifications}}
<ul> <ul>
{{#each view.notifications}} {{#each view.notifications}}
@ -73,7 +63,7 @@
{{/if}} {{/if}}
</section> </section>
<section class='d-dropdown' id='site-map-dropdown'> <section class='d-dropdown' id='site-map-dropdown'>
<ul> <ul>
{{#if Discourse.currentUser.admin}} {{#if Discourse.currentUser.admin}}
<li><a href="/admin"><i class='icon-cog'></i>{{i18n admin_title}}</a></li> <li><a href="/admin"><i class='icon-cog'></i>{{i18n admin_title}}</a></li>
@ -99,7 +89,7 @@
<li class='heading' title="{{i18n filters.categories.help}}"> <li class='heading' title="{{i18n filters.categories.help}}">
{{#linkTo "list.categories"}}{{i18n filters.categories.title}}{{/linkTo}} {{#linkTo "list.categories"}}{{i18n filters.categories.title}}{{/linkTo}}
</li> </li>
{{#each view.categories}} {{#each view.categories}}
<li class='category'> <li class='category'>
{{categoryLink this}} {{categoryLink this}}

View file

@ -81,6 +81,27 @@ Discourse.HeaderView = Discourse.View.extend({
} }
}, },
/**
Display the correct logo in the header, showing a custom small icon if it exists.
@property logoHTML
**/
logoHTML: function() {
var result = "<div class='title'><a href='/'>";
if (this.get('controller.showExtraInfo')) {
var logo = Discourse.SiteSettings.logo_small_url;
if (logo && logo.length > 1) {
result += "<img src='" + logo + "' width='33' height='33'>";
} else {
result += "<i class='icon-home'></i>";
}
} else {
result += "<img src=\"" + Discourse.SiteSettings.logo_url + "\" alt=\"" + Discourse.SiteSettings.title + "\" id='site-logo'>";
}
result += "</a></div>";
return new Handlebars.SafeString(result);
}.property('controller.showExtraInfo'),
willDestroyElement: function() { willDestroyElement: function() {
$(window).unbind('scroll.discourse-dock'); $(window).unbind('scroll.discourse-dock');
return $(document).unbind('touchmove.discourse-dock'); return $(document).unbind('touchmove.discourse-dock');

View file

@ -42,7 +42,7 @@ Discourse.EditCategoryView = Discourse.ModalBodyView.extend({
showCategoryTopic: function() { showCategoryTopic: function() {
$('#discourse-modal').modal('hide'); $('#discourse-modal').modal('hide');
Discourse.routeTo(this.get('category.topic_url')); Discourse.URL.routeTo(this.get('category.topic_url'));
return false; return false;
}, },

View file

@ -36,8 +36,8 @@ Discourse.MoveSelectedView = Discourse.ModalBodyView.extend({
Discourse.Topic.movePosts(this.get('topic.id'), this.get('topicName'), postIds).then(function(result) { Discourse.Topic.movePosts(this.get('topic.id'), this.get('topicName'), postIds).then(function(result) {
if (result.success) { if (result.success) {
$('#discourse-modal').modal('hide'); $('#discourse-modal').modal('hide');
return Em.run.next(function() { Em.run.next(function() {
return Discourse.routeTo(result.url); Discourse.URL.routeTo(result.url);
}); });
} else { } else {
_this.flash(Em.String.i18n('topic.move_selected.error')); _this.flash(Em.String.i18n('topic.move_selected.error'));

View file

@ -139,13 +139,10 @@ window.Discourse.SearchView = Discourse.View.extend({
}, },
select: function() { select: function() {
var href; if (this.get('loading')) return;
if (this.get('loading')) { var href = $('#search-dropdown li.selected a').prop('href');
return;
}
href = $('#search-dropdown li.selected a').prop('href');
if (href) { if (href) {
Discourse.routeTo(href); Discourse.URL.routeTo(href);
} }
return false; return false;
} }

View file

@ -84,7 +84,7 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
postUrl += "/best_of"; postUrl += "/best_of";
} }
} }
Discourse.replaceState(postUrl); Discourse.URL.replaceState(postUrl);
// Show appropriate jump tools // Show appropriate jump tools
if (current === 1) { if (current === 1) {
@ -441,10 +441,12 @@ Discourse.TopicView = Discourse.View.extend(Discourse.Scrolling, {
this.docAt = title.offset().top; this.docAt = title.offset().top;
} }
} }
var headerController = this.get('controller.controllers.header');
if (this.docAt) { if (this.docAt) {
this.set('controller.showExtraHeaderInfo', offset >= this.docAt || !firstLoaded); headerController.set('showExtraInfo', offset >= this.docAt || !firstLoaded);
} else { } else {
this.set('controller.showExtraHeaderInfo', !firstLoaded); headerController.set('showExtraInfo', !firstLoaded);
} }
// there is a whole bunch of caching we could add here // there is a whole bunch of caching we could add here

View file

@ -1,5 +1,5 @@
// Version: v1.0.0-pre.2-723-g052062c // Version: v1.0.0-pre.2-756-gb26f1f0
// Last commit: 052062c (2013-02-18 19:32:17 -0800) // Last commit: b26f1f0 (2013-02-26 09:03:26 -0800)
(function() { (function() {
@ -150,8 +150,8 @@ Ember.deprecateFunc = function(message, func) {
})(); })();
// Version: v1.0.0-pre.2-723-g052062c // Version: v1.0.0-pre.2-756-gb26f1f0
// Last commit: 052062c (2013-02-18 19:32:17 -0800) // Last commit: b26f1f0 (2013-02-26 09:03:26 -0800)
(function() { (function() {
@ -297,6 +297,15 @@ Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !
*/ */
Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : 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. Empty function. Useful for some operations.
@ -1752,7 +1761,7 @@ var MapWithDefault = Ember.MapWithDefault = function(options) {
@static @static
@param [options] @param [options]
@param {anything} [options.defaultValue] @param {anything} [options.defaultValue]
@return {Ember.MapWithDefault|Ember.Map} If options are passed, returns @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
`Ember.MapWithDefault` otherwise returns `Ember.Map` `Ember.MapWithDefault` otherwise returns `Ember.Map`
*/ */
MapWithDefault.create = function(options) { MapWithDefault.create = function(options) {
@ -1826,7 +1835,7 @@ var FIRST_KEY = /^([^\.\*]+)/;
If you plan to run on IE8 and older browsers then you should use this If you plan to run on IE8 and older browsers then you should use this
method anytime you want to retrieve a property on an object that you don't method anytime you want to retrieve a property on an object that you don't
know for sure is private. (Properties beginning with an underscore '_' know for sure is private. (Properties beginning with an underscore '_'
are considered private.) are considered private.)
On all newer browsers, you only need to use this method to retrieve On all newer browsers, you only need to use this method to retrieve
@ -1888,7 +1897,7 @@ get = function get(obj, keyName) {
If you plan to run on IE8 and older browsers then you should use this If you plan to run on IE8 and older browsers then you should use this
method anytime you want to set a property on an object that you don't method anytime you want to set a property on an object that you don't
know for sure is private. (Properties beginning with an underscore '_' know for sure is private. (Properties beginning with an underscore '_'
are considered private.) are considered private.)
On all newer browsers, you only need to use this method to set On all newer browsers, you only need to use this method to set
@ -4229,7 +4238,7 @@ Ember.RunLoop = RunLoop;
```javascript ```javascript
Ember.run(function(){ Ember.run(function(){
// code to be execute within a RunLoop // code to be execute within a RunLoop
}); });
``` ```
@ -4268,7 +4277,7 @@ var run = Ember.run;
```javascript ```javascript
Ember.run.begin(); Ember.run.begin();
// code to be execute within a RunLoop // code to be execute within a RunLoop
Ember.run.end(); Ember.run.end();
``` ```
@ -4286,7 +4295,7 @@ Ember.run.begin = function() {
```javascript ```javascript
Ember.run.begin(); Ember.run.begin();
// code to be execute within a RunLoop // code to be execute within a RunLoop
Ember.run.end(); Ember.run.end();
``` ```
@ -6123,7 +6132,6 @@ define("container",
register: function(type, name, factory, options) { register: function(type, name, factory, options) {
var fullName; var fullName;
if (type.indexOf(':') !== -1){ if (type.indexOf(':') !== -1){
options = factory; options = factory;
factory = name; factory = name;
@ -6133,15 +6141,23 @@ define("container",
fullName = type + ":" + name; fullName = type + ":" + name;
} }
this.registry.set(fullName, factory); var normalizedName = this.normalize(fullName);
this._options.set(fullName, options || {});
this.registry.set(normalizedName, factory);
this._options.set(normalizedName, options || {});
}, },
resolve: function(fullName) { resolve: function(fullName) {
return this.resolver(fullName) || this.registry.get(fullName); return this.resolver(fullName) || this.registry.get(fullName);
}, },
normalize: function(fullName) {
return fullName;
},
lookup: function(fullName, options) { lookup: function(fullName, options) {
fullName = this.normalize(fullName);
options = options || {}; options = options || {};
if (this.cache.has(fullName) && options.singleton !== false) { if (this.cache.has(fullName) && options.singleton !== false) {
@ -6270,7 +6286,8 @@ define("container",
} }
function factoryFor(container, fullName) { function factoryFor(container, fullName) {
return container.resolve(fullName); var name = container.normalize(fullName);
return container.resolve(name);
} }
function instantiate(container, fullName) { function instantiate(container, fullName) {
@ -6745,6 +6762,20 @@ Ember.Error.prototype = Ember.create(Error.prototype);
(function() {
/**
Expose RSVP implementation
@class RSVP
@namespace Ember
@constructor
*/
Ember.RSVP = requireModule('rsvp');
})();
(function() { (function() {
/** /**
@module ember @module ember
@ -7358,7 +7389,7 @@ Ember.Enumerable = Ember.Mixin.create(
@method nextObject @method nextObject
@param {Number} index the current index of the iteration @param {Number} index the current index of the iteration
@param {Object} previousObject the value returned by the last call to @param {Object} previousObject the value returned by the last call to
`nextObject`. `nextObject`.
@param {Object} context a context object you can use to maintain state. @param {Object} context a context object you can use to maintain state.
@return {Object} the next object in the iteration or undefined @return {Object} the next object in the iteration or undefined
@ -8425,9 +8456,9 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
@method arrayContentWillChange @method arrayContentWillChange
@param {Number} startIdx The starting index in the array that will change. @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 @param {Number} removeAmt The number of items that will be removed. If you
pass `null` assumes 0 pass `null` assumes 0
@param {Number} addAmt The number of items that will be added If you @param {Number} addAmt The number of items that will be added If you
pass `null` assumes 0. pass `null` assumes 0.
@return {Ember.Array} receiver @return {Ember.Array} receiver
*/ */
@ -8901,11 +8932,11 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
passed array. You should also call `this.enumerableContentDidChange()` passed array. You should also call `this.enumerableContentDidChange()`
@method replace @method replace
@param {Number} idx Starting index in the array to replace. If @param {Number} idx Starting index in the array to replace. If
idx >= length, then append to the end of the array. idx >= length, then append to the end of the array.
@param {Number} amt Number of elements that should be removed from @param {Number} amt Number of elements that should be removed from
the array, starting at *idx*. the array, starting at *idx*.
@param {Array} objects An array of zero or more objects that should be @param {Array} objects An array of zero or more objects that should be
inserted into the array at *idx* inserted into the array at *idx*
*/ */
replace: Ember.required(), replace: Ember.required(),
@ -10160,14 +10191,14 @@ CoreObject.PrototypeMixin = Mixin.create({
view.get('classNames'); // ['ember-view', 'bar', 'foo', '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: Adding a single property that is not an array will just add it in the array:
```javascript ```javascript
var view = App.FooBarView.create({ var view = App.FooBarView.create({
classNames: 'baz' classNames: 'baz'
}) })
view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
``` ```
Using the `concatenatedProperties` property, we can tell to Ember that mix Using the `concatenatedProperties` property, we can tell to Ember that mix
the content of the properties. the content of the properties.
@ -11125,40 +11156,8 @@ Ember.Mixin.prototype.toString = classToString;
(function() { (function() {
/**
@module ember
@submodule ember-runtime
*/
/**
Defines a namespace that will contain an executable application. This is
very similar to a normal namespace except that it is expected to include at
least a 'ready' function which can be run to initialize the application.
Currently `Ember.Application` is very similar to `Ember.Namespace.` However,
this class may be augmented by additional frameworks so it is important to
use this instance when building new applications.
# Example Usage
```javascript
MyApp = Ember.Application.create({
VERSION: '1.0.0',
store: Ember.Store.create().from(Ember.fixtures)
});
MyApp.ready = function() {
//..init code goes here...
}
```
@class Application
@namespace Ember
@extends Ember.Namespace
*/
Ember.Application = Ember.Namespace.extend(); Ember.Application = Ember.Namespace.extend();
})(); })();
@ -11544,6 +11543,25 @@ Ember.ObjectProxy = Ember.Object.extend(
} }
}); });
Ember.ObjectProxy.reopenClass({
create: function () {
var mixin, prototype, i, l, properties, keyName;
if (arguments.length) {
prototype = this.proto();
for (i = 0, l = arguments.length; i < l; i++) {
properties = arguments[i];
for (keyName in properties) {
if (!properties.hasOwnProperty(keyName) || keyName in prototype) { continue; }
if (!mixin) mixin = {};
mixin[keyName] = null;
}
}
if (mixin) this._initMixins([mixin]);
}
return this._super.apply(this, arguments);
}
});
})(); })();
@ -11864,7 +11882,7 @@ if (ignore.length>0) {
/** /**
The NativeArray mixin contains the properties needed to to make the native The NativeArray mixin contains the properties needed to to make the native
Array support Ember.MutableArray and all of its dependent APIs. Unless you Array support Ember.MutableArray and all of its dependent APIs. Unless you
have `Ember.EXTEND_PROTOTYPES or `Ember.EXTEND_PROTOTYPES.Array` set to have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to
false, this will be applied automatically. Otherwise you can apply the mixin false, this will be applied automatically. Otherwise you can apply the mixin
at anytime by calling `Ember.NativeArray.activate`. at anytime by calling `Ember.NativeArray.activate`.
@ -12440,7 +12458,8 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
objectAtContent: function(idx) { objectAtContent: function(idx) {
var length = get(this, 'length'), var length = get(this, 'length'),
object = get(this,'arrangedContent').objectAt(idx); arrangedContent = get(this,'arrangedContent'),
object = arrangedContent && arrangedContent.objectAt(idx);
if (idx >= 0 && idx < length) { if (idx >= 0 && idx < length) {
var controllerClass = this.lookupItemController(object); var controllerClass = this.lookupItemController(object);
@ -12591,15 +12610,16 @@ Ember.$ = jQuery;
@module ember @module ember
@submodule ember-views @submodule ember-views
*/ */
if (Ember.$) {
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend');
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents // Copies the `dataTransfer` property from a browser event object onto the
var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend'); // jQuery event object for the specified events
Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
// Copies the `dataTransfer` property from a browser event object onto the Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
// jQuery event object for the specified events });
Ember.EnumerableUtils.forEach(dragEvents, function(eventName) { }
Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
});
})(); })();
@ -12616,7 +12636,8 @@ Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making // is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use &shy; // the first node an invisible text node. We, like Modernizr, use &shy;
var needsShy = (function(){
var needsShy = this.document && (function(){
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "<div></div>"; testEl.innerHTML = "<div></div>";
testEl.firstChild.innerHTML = "<script></script>"; testEl.firstChild.innerHTML = "<script></script>";
@ -12626,7 +12647,7 @@ var needsShy = (function(){
// IE 8 (and likely earlier) likes to move whitespace preceeding // IE 8 (and likely earlier) likes to move whitespace preceeding
// a script tag to appear after it. This means that we can // a script tag to appear after it. This means that we can
// accidentally remove whitespace when updating a morph. // accidentally remove whitespace when updating a morph.
var movesWhitespace = (function() { var movesWhitespace = this.document && (function() {
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value"; testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
return testEl.childNodes[0].nodeValue === 'Test:' && return testEl.childNodes[0].nodeValue === 'Test:' &&
@ -13297,7 +13318,7 @@ Ember.EventDispatcher = Ember.Object.extend(
setup: function(addedEvents) { setup: function(addedEvents) {
var event, events = { var event, events = {
touchstart : 'touchStart', touchstart : 'touchStart',
// touchmove : 'touchMove', touchmove : 'touchMove',
touchend : 'touchEnd', touchend : 'touchEnd',
touchcancel : 'touchCancel', touchcancel : 'touchCancel',
keydown : 'keyDown', keydown : 'keyDown',
@ -13308,8 +13329,7 @@ Ember.EventDispatcher = Ember.Object.extend(
contextmenu : 'contextMenu', contextmenu : 'contextMenu',
click : 'click', click : 'click',
dblclick : 'doubleClick', dblclick : 'doubleClick',
// https://github.com/emberjs/ember.js/pull/2148 mousemove : 'mouseMove',
// mousemove : 'mouseMove',
focusin : 'focusIn', focusin : 'focusIn',
focusout : 'focusOut', focusout : 'focusOut',
mouseenter : 'mouseEnter', mouseenter : 'mouseEnter',
@ -13459,8 +13479,9 @@ Ember.EventDispatcher = Ember.Object.extend(
// Add a new named queue for rendering views that happens // Add a new named queue for rendering views that happens
// after bindings have synced, and a queue for scheduling actions // after bindings have synced, and a queue for scheduling actions
// that that should occur after view rendering. // that that should occur after view rendering.
var queues = Ember.run.queues; var queues = Ember.run.queues,
queues.splice(Ember.$.inArray('actions', queues)+1, 0, 'render', 'afterRender'); indexOf = Ember.ArrayPolyfills.indexOf;
queues.splice(indexOf.call(queues, 'actions')+1, 0, 'render', 'afterRender');
})(); })();
@ -14250,7 +14271,7 @@ class:
* `mouseEnter` * `mouseEnter`
* `mouseLeave` * `mouseLeave`
Form events: Form events:
* `submit` * `submit`
* `change` * `change`
@ -14258,7 +14279,7 @@ class:
* `focusOut` * `focusOut`
* `input` * `input`
HTML5 drag and drop events: HTML5 drag and drop events:
* `dragStart` * `dragStart`
* `drag` * `drag`
@ -15706,17 +15727,24 @@ Ember.View = Ember.CoreView.extend(
// once the view has been inserted into the DOM, legal manipulations // once the view has been inserted into the DOM, legal manipulations
// are done on the DOM element. // are done on the DOM element.
function notifyMutationListeners() {
Ember.run.once(Ember.View, 'notifyMutationListeners');
}
var DOMManager = { var DOMManager = {
prepend: function(view, html) { prepend: function(view, html) {
view.$().prepend(html); view.$().prepend(html);
notifyMutationListeners();
}, },
after: function(view, html) { after: function(view, html) {
view.$().after(html); view.$().after(html);
notifyMutationListeners();
}, },
html: function(view, html) { html: function(view, html) {
view.$().html(html); view.$().html(html);
notifyMutationListeners();
}, },
replace: function(view) { replace: function(view) {
@ -15726,15 +15754,18 @@ var DOMManager = {
view._insertElementLater(function() { view._insertElementLater(function() {
Ember.$(element).replaceWith(get(view, 'element')); Ember.$(element).replaceWith(get(view, 'element'));
notifyMutationListeners();
}); });
}, },
remove: function(view) { remove: function(view) {
view.$().remove(); view.$().remove();
notifyMutationListeners();
}, },
empty: function(view) { empty: function(view) {
view.$().empty(); view.$().empty();
notifyMutationListeners();
} }
}; };
@ -15795,14 +15826,14 @@ Ember.View.reopenClass({
`className` and optional `falsyClassName`. `className` and optional `falsyClassName`.
- if a `className` or `falsyClassName` has been specified: - if a `className` or `falsyClassName` has been specified:
- if the value is truthy and `className` has been specified, - if the value is truthy and `className` has been specified,
`className` is returned `className` is returned
- if the value is falsy and `falsyClassName` has been specified, - if the value is falsy and `falsyClassName` has been specified,
`falsyClassName` is returned `falsyClassName` is returned
- otherwise `null` is returned - otherwise `null` is returned
- if the value is `true`, the dasherized last part of the supplied path - if the value is `true`, the dasherized last part of the supplied path
is returned is returned
- if the value is not `false`, `undefined` or `null`, the `value` - if the value is not `false`, `undefined` or `null`, the `value`
is returned is returned
- if none of the above rules apply, `null` is returned - if none of the above rules apply, `null` is returned
@ -15849,6 +15880,20 @@ Ember.View.reopenClass({
} }
}); });
var mutation = Ember.Object.extend(Ember.Evented).create();
Ember.View.addMutationListener = function(callback) {
mutation.on('change', callback);
};
Ember.View.removeMutationListener = function(callback) {
mutation.off('change', callback);
};
Ember.View.notifyMutationListeners = function() {
mutation.trigger('change');
};
/** /**
Global views hash Global views hash
@ -16652,7 +16697,7 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
Given an empty `<body>` and the following code: Given an empty `<body>` and the following code:
```javascript ```javascript
someItemsView = Ember.CollectionView.create({ someItemsView = Ember.CollectionView.create({
classNames: ['a-collection'], classNames: ['a-collection'],
content: ['A','B','C'], content: ['A','B','C'],
@ -17008,15 +17053,15 @@ define("metamorph",
var K = function(){}, var K = function(){},
guid = 0, guid = 0,
document = window.document, document = this.document,
// Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
supportsRange = ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, supportsRange = document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making // is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use &shy; // the first node an invisible text node. We, like Modernizr, use &shy;
needsShy = (function(){ needsShy = document && (function(){
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "<div></div>"; testEl.innerHTML = "<div></div>";
testEl.firstChild.innerHTML = "<script></script>"; testEl.firstChild.innerHTML = "<script></script>";
@ -17027,7 +17072,7 @@ define("metamorph",
// IE 8 (and likely earlier) likes to move whitespace preceeding // IE 8 (and likely earlier) likes to move whitespace preceeding
// a script tag to appear after it. This means that we can // a script tag to appear after it. This means that we can
// accidentally remove whitespace when updating a morph. // accidentally remove whitespace when updating a morph.
movesWhitespace = (function() { movesWhitespace = document && (function() {
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value"; testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
return testEl.childNodes[0].nodeValue === 'Test:' && return testEl.childNodes[0].nodeValue === 'Test:' &&
@ -17471,7 +17516,11 @@ var objectCreate = Object.create || function(parent) {
return new F(); return new F();
}; };
var Handlebars = this.Handlebars || Ember.imports.Handlebars; var Handlebars = this.Handlebars || (Ember.imports && Ember.imports.Handlebars);
if(!Handlebars && typeof require === 'function') {
Handlebars = require('handlebars');
}
Ember.assert("Ember Handlebars requires Handlebars 1.0.0-rc.3 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0\.[0-9](\.rc\.[23456789]+)?/)); Ember.assert("Ember Handlebars requires Handlebars 1.0.0-rc.3 or greater", Handlebars && Handlebars.VERSION.match(/^1\.0\.[0-9](\.rc\.[23456789]+)?/));
/** /**
@ -17824,7 +17873,7 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
## Example with bound options ## Example with bound options
Bound hash options are also supported. Example: Bound hash options are also supported. Example:
```handlebars ```handlebars
{{repeat text countBinding="numRepeats"}} {{repeat text countBinding="numRepeats"}}
@ -17862,15 +17911,15 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
{{concatenate prop1 prop2 prop3}}. If any of the properties change, {{concatenate prop1 prop2 prop3}}. If any of the properties change,
the helpr will re-render. Note that dependency keys cannot be the helpr will re-render. Note that dependency keys cannot be
using in conjunction with multi-property helpers, since it is ambiguous using in conjunction with multi-property helpers, since it is ambiguous
which property the dependent keys would belong to. which property the dependent keys would belong to.
## Use with unbound helper ## Use with unbound helper
The {{unbound}} helper can be used with bound helper invocations The {{unbound}} helper can be used with bound helper invocations
to render them in their unbound form, e.g. to render them in their unbound form, e.g.
```handlebars ```handlebars
{{unbound capitalize name}} {{unbound capitalize name}}
``` ```
In this example, if the name property changes, the helper In this example, if the name property changes, the helper
@ -17896,7 +17945,7 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) {
view = data.view, view = data.view,
currentContext = (options.contexts && options.contexts[0]) || this, currentContext = (options.contexts && options.contexts[0]) || this,
normalized, normalized,
pathRoot, path, pathRoot, path,
loc, hashOption; loc, hashOption;
// Detect bound options (e.g. countBinding="otherCount") // Detect bound options (e.g. countBinding="otherCount")
@ -18002,7 +18051,7 @@ function evaluateMultiPropertyBoundHelper(context, fn, normalizedProperties, opt
// Assemble liast of watched properties that'll re-render this helper. // Assemble liast of watched properties that'll re-render this helper.
watchedProperties = []; watchedProperties = [];
for (boundOption in boundOptions) { for (boundOption in boundOptions) {
if (boundOptions.hasOwnProperty(boundOption)) { if (boundOptions.hasOwnProperty(boundOption)) {
watchedProperties.push(normalizePath(context, boundOptions[boundOption], data)); watchedProperties.push(normalizePath(context, boundOptions[boundOption], data));
} }
} }
@ -18131,22 +18180,30 @@ Ember.Handlebars.resolvePaths = function(options) {
var set = Ember.set, get = Ember.get; var set = Ember.set, get = Ember.get;
var Metamorph = requireModule('metamorph'); var Metamorph = requireModule('metamorph');
function notifyMutationListeners() {
Ember.run.once(Ember.View, 'notifyMutationListeners');
}
// DOMManager should just abstract dom manipulation between jquery and metamorph // DOMManager should just abstract dom manipulation between jquery and metamorph
var DOMManager = { var DOMManager = {
remove: function(view) { remove: function(view) {
view.morph.remove(); view.morph.remove();
notifyMutationListeners();
}, },
prepend: function(view, html) { prepend: function(view, html) {
view.morph.prepend(html); view.morph.prepend(html);
notifyMutationListeners();
}, },
after: function(view, html) { after: function(view, html) {
view.morph.after(html); view.morph.after(html);
notifyMutationListeners();
}, },
html: function(view, html) { html: function(view, html) {
view.morph.html(html); view.morph.html(html);
notifyMutationListeners();
}, },
// This is messed up. // This is messed up.
@ -18169,11 +18226,13 @@ var DOMManager = {
morph.replaceWith(buffer.string()); morph.replaceWith(buffer.string());
view.transitionTo('inDOM'); view.transitionTo('inDOM');
view.triggerRecursively('didInsertElement'); view.triggerRecursively('didInsertElement');
notifyMutationListeners();
}); });
}, },
empty: function(view) { empty: function(view) {
view.morph.html(""); view.morph.html("");
notifyMutationListeners();
} }
}; };
@ -18937,14 +18996,14 @@ EmberHandlebars.registerHelper('unless', function(context, options) {
Result in the following rendered output: Result in the following rendered output:
```html ```html
<img class="aValue"> <img class="aValue">
``` ```
A boolean return value will insert a specified class name if the property 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`. returns `true` and remove the class name if the property returns `false`.
A class name is provided via the syntax A class name is provided via the syntax
`somePropertyName:class-name-if-true`. `somePropertyName:class-name-if-true`.
```javascript ```javascript
@ -19103,9 +19162,9 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
@method bindClasses @method bindClasses
@for Ember.Handlebars @for Ember.Handlebars
@param {Ember.Object} context The context from which to lookup properties @param {Ember.Object} context The context from which to lookup properties
@param {String} classBindings A string, space-separated, of class bindings @param {String} classBindings A string, space-separated, of class bindings
to use to use
@param {Ember.View} view The view in which observers should look for the @param {Ember.View} view The view in which observers should look for the
element to update element to update
@param {Srting} bindAttrId Optional bindAttr id used to lookup elements @param {Srting} bindAttrId Optional bindAttr id used to lookup elements
@return {Array} An array of class names to add @return {Array} An array of class names to add
@ -19795,7 +19854,7 @@ Ember.Handlebars.registerHelper('unbound', function(property, fn) {
// Unbound helper call. // Unbound helper call.
options.data.isUnbound = true; options.data.isUnbound = true;
helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing; helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing;
out = helper.apply(this, Array.prototype.slice.call(arguments, 1)); out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
delete options.data.isUnbound; delete options.data.isUnbound;
return out; return out;
} }
@ -21093,7 +21152,7 @@ helpers = helpers || Ember.Handlebars.helpers; data = data || {};
var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this; var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this;
function program1(depth0,data) { function program1(depth0,data) {
var buffer = '', hashTypes; var buffer = '', hashTypes;
data.buffer.push("<option value=\"\">"); data.buffer.push("<option value=\"\">");
hashTypes = {}; hashTypes = {};
@ -21103,7 +21162,7 @@ function program1(depth0,data) {
} }
function program3(depth0,data) { function program3(depth0,data) {
var hashTypes; var hashTypes;
hashTypes = {'contentBinding': "STRING"}; hashTypes = {'contentBinding': "STRING"};
data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{ data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{
@ -21118,7 +21177,7 @@ function program3(depth0,data) {
stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}); stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data});
if(stack1 || stack1 === 0) { data.buffer.push(stack1); } if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
return buffer; return buffer;
}), }),
attributeBindings: ['multiple', 'disabled', 'tabindex'], attributeBindings: ['multiple', 'disabled', 'tabindex'],
@ -23555,6 +23614,34 @@ function teardownView(route) {
(function() {
Ember.onLoad('Ember.Handlebars', function() {
var handlebarsResolve = Ember.Handlebars.resolveParams,
map = Ember.ArrayPolyfills.map,
get = Ember.get;
function resolveParams(context, params, options) {
var resolved = handlebarsResolve(context, params, options);
return map.call(resolved, unwrap);
function unwrap(object, i) {
if (params[i] === 'controller') { return object; }
if (Ember.ControllerMixin.detect(object)) {
return unwrap(get(object, 'model'));
} else {
return object;
}
}
}
Ember.Router.resolveParams = resolveParams;
});
})();
(function() { (function() {
/** /**
@module ember @module ember
@ -23564,7 +23651,7 @@ function teardownView(route) {
var get = Ember.get, set = Ember.set; var get = Ember.get, set = Ember.set;
Ember.onLoad('Ember.Handlebars', function(Handlebars) { Ember.onLoad('Ember.Handlebars', function(Handlebars) {
var resolveParams = Ember.Handlebars.resolveParams, var resolveParams = Ember.Router.resolveParams,
isSimpleClick = Ember.ViewUtils.isSimpleClick; isSimpleClick = Ember.ViewUtils.isSimpleClick;
function fullRouteName(router, name) { function fullRouteName(router, name) {
@ -23847,7 +23934,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
*/ */
Ember.onLoad('Ember.Handlebars', function(Handlebars) { Ember.onLoad('Ember.Handlebars', function(Handlebars) {
var resolveParams = Ember.Handlebars.resolveParams, var resolveParams = Ember.Router.resolveParams,
isSimpleClick = Ember.ViewUtils.isSimpleClick; isSimpleClick = Ember.ViewUtils.isSimpleClick;
var EmberHandlebars = Ember.Handlebars, var EmberHandlebars = Ember.Handlebars,
@ -24473,7 +24560,7 @@ Ember.HashLocation = Ember.Object.extend({
set(self, 'lastSetURL', null); set(self, 'lastSetURL', null);
callback(location.hash.substr(1)); callback(path);
}); });
}); });
}, },
@ -24851,11 +24938,14 @@ var get = Ember.get, set = Ember.set,
``` ```
By default, calling `Ember.Application.create()` will automatically initialize By default, calling `Ember.Application.create()` will automatically initialize
your application by calling the `Ember.Application.initialize()` method. If your application by calling the `Ember.Application.initialize()` method. If
you need to delay initialization, you can call your app's `deferReadiness()` 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 method. When you are ready for your app to be initialized, call its
`advanceReadiness()` method. `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 Because `Ember.Application` inherits from `Ember.Namespace`, any classes
you create will have useful string representations when calling `toString()`. you create will have useful string representations when calling `toString()`.
See the `Ember.Namespace` documentation for more information. See the `Ember.Namespace` documentation for more information.
@ -25050,11 +25140,13 @@ var Application = Ember.Application = Ember.Namespace.extend({
this.scheduleInitialize(); this.scheduleInitialize();
} }
Ember.debug('-------------------------------'); if ( Ember.LOG_VERSION ) {
Ember.debug('Ember.VERSION : ' + Ember.VERSION); Ember.debug('-------------------------------');
Ember.debug('Handlebars.VERSION : ' + Ember.Handlebars.VERSION); Ember.debug('Ember.VERSION : ' + Ember.VERSION);
Ember.debug('jQuery.VERSION : ' + Ember.$().jquery); Ember.debug('Handlebars.VERSION : ' + Ember.Handlebars.VERSION);
Ember.debug('-------------------------------'); Ember.debug('jQuery.VERSION : ' + Ember.$().jquery);
Ember.debug('-------------------------------');
}
}, },
/** /**
@ -25414,6 +25506,7 @@ Ember.Application.reopenClass({
Ember.Container.defaultContainer = Ember.Container.defaultContainer || container; Ember.Container.defaultContainer = Ember.Container.defaultContainer || container;
container.set = Ember.set; container.set = Ember.set;
container.normalize = normalize;
container.resolver = resolverFor(namespace); container.resolver = resolverFor(namespace);
container.optionsForType('view', { singleton: false }); container.optionsForType('view', { singleton: false });
container.optionsForType('template', { instantiate: false }); container.optionsForType('template', { instantiate: false });
@ -25453,6 +25546,7 @@ function resolverFor(namespace) {
if (type === 'template') { if (type === 'template') {
var templateName = name.replace(/\./g, '/'); var templateName = name.replace(/\./g, '/');
if (Ember.TEMPLATES[templateName]) { if (Ember.TEMPLATES[templateName]) {
return Ember.TEMPLATES[templateName]; return Ember.TEMPLATES[templateName];
} }
@ -25483,9 +25577,31 @@ function resolverFor(namespace) {
}; };
} }
Ember.runLoadHooks('Ember.Application', Ember.Application); function normalize(fullName) {
var split = fullName.split(':'),
type = split[0],
name = split[1];
if (type !== 'template') {
var result = name;
if (result.indexOf('.') > -1) {
result = result.replace(/\.(.)/g, function(m) { return m[1].toUpperCase(); });
}
if (name.indexOf('_') > -1) {
result = result.replace(/_(.)/g, function(m) { return m[1].toUpperCase(); });
}
return type + ':' + result;
} else {
return fullName;
}
}
Ember.runLoadHooks('Ember.Application', Ember.Application);
})(); })();
@ -26831,8 +26947,8 @@ Ember States
})(); })();
// Version: v1.0.0-pre.2-723-g052062c // Version: v1.0.0-pre.2-756-gb26f1f0
// Last commit: 052062c (2013-02-18 19:32:17 -0800) // Last commit: b26f1f0 (2013-02-26 09:03:26 -0800)
(function() { (function() {

View file

@ -141,6 +141,15 @@ Ember.LOG_STACKTRACE_ON_DEPRECATION = (Ember.ENV.LOG_STACKTRACE_ON_DEPRECATION !
*/ */
Ember.SHIM_ES5 = (Ember.ENV.SHIM_ES5 === false) ? false : 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. Empty function. Useful for some operations.
@ -1596,7 +1605,7 @@ var MapWithDefault = Ember.MapWithDefault = function(options) {
@static @static
@param [options] @param [options]
@param {anything} [options.defaultValue] @param {anything} [options.defaultValue]
@return {Ember.MapWithDefault|Ember.Map} If options are passed, returns @return {Ember.MapWithDefault|Ember.Map} If options are passed, returns
`Ember.MapWithDefault` otherwise returns `Ember.Map` `Ember.MapWithDefault` otherwise returns `Ember.Map`
*/ */
MapWithDefault.create = function(options) { MapWithDefault.create = function(options) {
@ -1670,7 +1679,7 @@ var FIRST_KEY = /^([^\.\*]+)/;
If you plan to run on IE8 and older browsers then you should use this If you plan to run on IE8 and older browsers then you should use this
method anytime you want to retrieve a property on an object that you don't method anytime you want to retrieve a property on an object that you don't
know for sure is private. (Properties beginning with an underscore '_' know for sure is private. (Properties beginning with an underscore '_'
are considered private.) are considered private.)
On all newer browsers, you only need to use this method to retrieve On all newer browsers, you only need to use this method to retrieve
@ -1731,7 +1740,7 @@ get = function get(obj, keyName) {
If you plan to run on IE8 and older browsers then you should use this If you plan to run on IE8 and older browsers then you should use this
method anytime you want to set a property on an object that you don't method anytime you want to set a property on an object that you don't
know for sure is private. (Properties beginning with an underscore '_' know for sure is private. (Properties beginning with an underscore '_'
are considered private.) are considered private.)
On all newer browsers, you only need to use this method to set On all newer browsers, you only need to use this method to set
@ -4069,7 +4078,7 @@ Ember.RunLoop = RunLoop;
```javascript ```javascript
Ember.run(function(){ Ember.run(function(){
// code to be execute within a RunLoop // code to be execute within a RunLoop
}); });
``` ```
@ -4108,7 +4117,7 @@ var run = Ember.run;
```javascript ```javascript
Ember.run.begin(); Ember.run.begin();
// code to be execute within a RunLoop // code to be execute within a RunLoop
Ember.run.end(); Ember.run.end();
``` ```
@ -4126,7 +4135,7 @@ Ember.run.begin = function() {
```javascript ```javascript
Ember.run.begin(); Ember.run.begin();
// code to be execute within a RunLoop // code to be execute within a RunLoop
Ember.run.end(); Ember.run.end();
``` ```
@ -5963,7 +5972,6 @@ define("container",
register: function(type, name, factory, options) { register: function(type, name, factory, options) {
var fullName; var fullName;
if (type.indexOf(':') !== -1){ if (type.indexOf(':') !== -1){
options = factory; options = factory;
factory = name; factory = name;
@ -5973,15 +5981,23 @@ define("container",
fullName = type + ":" + name; fullName = type + ":" + name;
} }
this.registry.set(fullName, factory); var normalizedName = this.normalize(fullName);
this._options.set(fullName, options || {});
this.registry.set(normalizedName, factory);
this._options.set(normalizedName, options || {});
}, },
resolve: function(fullName) { resolve: function(fullName) {
return this.resolver(fullName) || this.registry.get(fullName); return this.resolver(fullName) || this.registry.get(fullName);
}, },
normalize: function(fullName) {
return fullName;
},
lookup: function(fullName, options) { lookup: function(fullName, options) {
fullName = this.normalize(fullName);
options = options || {}; options = options || {};
if (this.cache.has(fullName) && options.singleton !== false) { if (this.cache.has(fullName) && options.singleton !== false) {
@ -6110,7 +6126,8 @@ define("container",
} }
function factoryFor(container, fullName) { function factoryFor(container, fullName) {
return container.resolve(fullName); var name = container.normalize(fullName);
return container.resolve(name);
} }
function instantiate(container, fullName) { function instantiate(container, fullName) {
@ -6584,6 +6601,20 @@ Ember.Error.prototype = Ember.create(Error.prototype);
(function() {
/**
Expose RSVP implementation
@class RSVP
@namespace Ember
@constructor
*/
Ember.RSVP = requireModule('rsvp');
})();
(function() { (function() {
/** /**
@module ember @module ember
@ -7197,7 +7228,7 @@ Ember.Enumerable = Ember.Mixin.create(
@method nextObject @method nextObject
@param {Number} index the current index of the iteration @param {Number} index the current index of the iteration
@param {Object} previousObject the value returned by the last call to @param {Object} previousObject the value returned by the last call to
`nextObject`. `nextObject`.
@param {Object} context a context object you can use to maintain state. @param {Object} context a context object you can use to maintain state.
@return {Object} the next object in the iteration or undefined @return {Object} the next object in the iteration or undefined
@ -8264,9 +8295,9 @@ Ember.Array = Ember.Mixin.create(Ember.Enumerable, /** @scope Ember.Array.protot
@method arrayContentWillChange @method arrayContentWillChange
@param {Number} startIdx The starting index in the array that will change. @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 @param {Number} removeAmt The number of items that will be removed. If you
pass `null` assumes 0 pass `null` assumes 0
@param {Number} addAmt The number of items that will be added If you @param {Number} addAmt The number of items that will be added If you
pass `null` assumes 0. pass `null` assumes 0.
@return {Ember.Array} receiver @return {Ember.Array} receiver
*/ */
@ -8740,11 +8771,11 @@ Ember.MutableArray = Ember.Mixin.create(Ember.Array, Ember.MutableEnumerable,
passed array. You should also call `this.enumerableContentDidChange()` passed array. You should also call `this.enumerableContentDidChange()`
@method replace @method replace
@param {Number} idx Starting index in the array to replace. If @param {Number} idx Starting index in the array to replace. If
idx >= length, then append to the end of the array. idx >= length, then append to the end of the array.
@param {Number} amt Number of elements that should be removed from @param {Number} amt Number of elements that should be removed from
the array, starting at *idx*. the array, starting at *idx*.
@param {Array} objects An array of zero or more objects that should be @param {Array} objects An array of zero or more objects that should be
inserted into the array at *idx* inserted into the array at *idx*
*/ */
replace: Ember.required(), replace: Ember.required(),
@ -9998,14 +10029,14 @@ CoreObject.PrototypeMixin = Mixin.create({
view.get('classNames'); // ['ember-view', 'bar', 'foo', '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: Adding a single property that is not an array will just add it in the array:
```javascript ```javascript
var view = App.FooBarView.create({ var view = App.FooBarView.create({
classNames: 'baz' classNames: 'baz'
}) })
view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz'] view.get('classNames'); // ['ember-view', 'bar', 'foo', 'baz']
``` ```
Using the `concatenatedProperties` property, we can tell to Ember that mix Using the `concatenatedProperties` property, we can tell to Ember that mix
the content of the properties. the content of the properties.
@ -10962,40 +10993,8 @@ Ember.Mixin.prototype.toString = classToString;
(function() { (function() {
/**
@module ember
@submodule ember-runtime
*/
/**
Defines a namespace that will contain an executable application. This is
very similar to a normal namespace except that it is expected to include at
least a 'ready' function which can be run to initialize the application.
Currently `Ember.Application` is very similar to `Ember.Namespace.` However,
this class may be augmented by additional frameworks so it is important to
use this instance when building new applications.
# Example Usage
```javascript
MyApp = Ember.Application.create({
VERSION: '1.0.0',
store: Ember.Store.create().from(Ember.fixtures)
});
MyApp.ready = function() {
//..init code goes here...
}
```
@class Application
@namespace Ember
@extends Ember.Namespace
*/
Ember.Application = Ember.Namespace.extend(); Ember.Application = Ember.Namespace.extend();
})(); })();
@ -11379,6 +11378,25 @@ Ember.ObjectProxy = Ember.Object.extend(
} }
}); });
Ember.ObjectProxy.reopenClass({
create: function () {
var mixin, prototype, i, l, properties, keyName;
if (arguments.length) {
prototype = this.proto();
for (i = 0, l = arguments.length; i < l; i++) {
properties = arguments[i];
for (keyName in properties) {
if (!properties.hasOwnProperty(keyName) || keyName in prototype) { continue; }
if (!mixin) mixin = {};
mixin[keyName] = null;
}
}
if (mixin) this._initMixins([mixin]);
}
return this._super.apply(this, arguments);
}
});
})(); })();
@ -11699,7 +11717,7 @@ if (ignore.length>0) {
/** /**
The NativeArray mixin contains the properties needed to to make the native The NativeArray mixin contains the properties needed to to make the native
Array support Ember.MutableArray and all of its dependent APIs. Unless you Array support Ember.MutableArray and all of its dependent APIs. Unless you
have `Ember.EXTEND_PROTOTYPES or `Ember.EXTEND_PROTOTYPES.Array` set to have `Ember.EXTEND_PROTOTYPES` or `Ember.EXTEND_PROTOTYPES.Array` set to
false, this will be applied automatically. Otherwise you can apply the mixin false, this will be applied automatically. Otherwise you can apply the mixin
at anytime by calling `Ember.NativeArray.activate`. at anytime by calling `Ember.NativeArray.activate`.
@ -12274,7 +12292,8 @@ Ember.ArrayController = Ember.ArrayProxy.extend(Ember.ControllerMixin,
objectAtContent: function(idx) { objectAtContent: function(idx) {
var length = get(this, 'length'), var length = get(this, 'length'),
object = get(this,'arrangedContent').objectAt(idx); arrangedContent = get(this,'arrangedContent'),
object = arrangedContent && arrangedContent.objectAt(idx);
if (idx >= 0 && idx < length) { if (idx >= 0 && idx < length) {
var controllerClass = this.lookupItemController(object); var controllerClass = this.lookupItemController(object);
@ -12425,15 +12444,16 @@ Ember.$ = jQuery;
@module ember @module ember
@submodule ember-views @submodule ember-views
*/ */
if (Ember.$) {
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents
var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend');
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#dndevents // Copies the `dataTransfer` property from a browser event object onto the
var dragEvents = Ember.String.w('dragstart drag dragenter dragleave dragover drop dragend'); // jQuery event object for the specified events
Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
// Copies the `dataTransfer` property from a browser event object onto the Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
// jQuery event object for the specified events });
Ember.EnumerableUtils.forEach(dragEvents, function(eventName) { }
Ember.$.event.fixHooks[eventName] = { props: ['dataTransfer'] };
});
})(); })();
@ -12450,7 +12470,8 @@ Ember.EnumerableUtils.forEach(dragEvents, function(eventName) {
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making // is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use &shy; // the first node an invisible text node. We, like Modernizr, use &shy;
var needsShy = (function(){
var needsShy = this.document && (function(){
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "<div></div>"; testEl.innerHTML = "<div></div>";
testEl.firstChild.innerHTML = "<script></script>"; testEl.firstChild.innerHTML = "<script></script>";
@ -12460,7 +12481,7 @@ var needsShy = (function(){
// IE 8 (and likely earlier) likes to move whitespace preceeding // IE 8 (and likely earlier) likes to move whitespace preceeding
// a script tag to appear after it. This means that we can // a script tag to appear after it. This means that we can
// accidentally remove whitespace when updating a morph. // accidentally remove whitespace when updating a morph.
var movesWhitespace = (function() { var movesWhitespace = this.document && (function() {
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value"; testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
return testEl.childNodes[0].nodeValue === 'Test:' && return testEl.childNodes[0].nodeValue === 'Test:' &&
@ -13131,7 +13152,7 @@ Ember.EventDispatcher = Ember.Object.extend(
setup: function(addedEvents) { setup: function(addedEvents) {
var event, events = { var event, events = {
touchstart : 'touchStart', touchstart : 'touchStart',
// touchmove : 'touchMove', touchmove : 'touchMove',
touchend : 'touchEnd', touchend : 'touchEnd',
touchcancel : 'touchCancel', touchcancel : 'touchCancel',
keydown : 'keyDown', keydown : 'keyDown',
@ -13142,7 +13163,7 @@ Ember.EventDispatcher = Ember.Object.extend(
contextmenu : 'contextMenu', contextmenu : 'contextMenu',
click : 'click', click : 'click',
dblclick : 'doubleClick', dblclick : 'doubleClick',
// mousemove : 'mouseMove', mousemove : 'mouseMove',
focusin : 'focusIn', focusin : 'focusIn',
focusout : 'focusOut', focusout : 'focusOut',
mouseenter : 'mouseEnter', mouseenter : 'mouseEnter',
@ -13290,8 +13311,9 @@ Ember.EventDispatcher = Ember.Object.extend(
// Add a new named queue for rendering views that happens // Add a new named queue for rendering views that happens
// after bindings have synced, and a queue for scheduling actions // after bindings have synced, and a queue for scheduling actions
// that that should occur after view rendering. // that that should occur after view rendering.
var queues = Ember.run.queues; var queues = Ember.run.queues,
queues.splice(Ember.$.inArray('actions', queues)+1, 0, 'render', 'afterRender'); indexOf = Ember.ArrayPolyfills.indexOf;
queues.splice(indexOf.call(queues, 'actions')+1, 0, 'render', 'afterRender');
})(); })();
@ -14080,7 +14102,7 @@ class:
* `mouseEnter` * `mouseEnter`
* `mouseLeave` * `mouseLeave`
Form events: Form events:
* `submit` * `submit`
* `change` * `change`
@ -14088,7 +14110,7 @@ class:
* `focusOut` * `focusOut`
* `input` * `input`
HTML5 drag and drop events: HTML5 drag and drop events:
* `dragStart` * `dragStart`
* `drag` * `drag`
@ -15530,17 +15552,24 @@ Ember.View = Ember.CoreView.extend(
// once the view has been inserted into the DOM, legal manipulations // once the view has been inserted into the DOM, legal manipulations
// are done on the DOM element. // are done on the DOM element.
function notifyMutationListeners() {
Ember.run.once(Ember.View, 'notifyMutationListeners');
}
var DOMManager = { var DOMManager = {
prepend: function(view, html) { prepend: function(view, html) {
view.$().prepend(html); view.$().prepend(html);
notifyMutationListeners();
}, },
after: function(view, html) { after: function(view, html) {
view.$().after(html); view.$().after(html);
notifyMutationListeners();
}, },
html: function(view, html) { html: function(view, html) {
view.$().html(html); view.$().html(html);
notifyMutationListeners();
}, },
replace: function(view) { replace: function(view) {
@ -15550,15 +15579,18 @@ var DOMManager = {
view._insertElementLater(function() { view._insertElementLater(function() {
Ember.$(element).replaceWith(get(view, 'element')); Ember.$(element).replaceWith(get(view, 'element'));
notifyMutationListeners();
}); });
}, },
remove: function(view) { remove: function(view) {
view.$().remove(); view.$().remove();
notifyMutationListeners();
}, },
empty: function(view) { empty: function(view) {
view.$().empty(); view.$().empty();
notifyMutationListeners();
} }
}; };
@ -15619,14 +15651,14 @@ Ember.View.reopenClass({
`className` and optional `falsyClassName`. `className` and optional `falsyClassName`.
- if a `className` or `falsyClassName` has been specified: - if a `className` or `falsyClassName` has been specified:
- if the value is truthy and `className` has been specified, - if the value is truthy and `className` has been specified,
`className` is returned `className` is returned
- if the value is falsy and `falsyClassName` has been specified, - if the value is falsy and `falsyClassName` has been specified,
`falsyClassName` is returned `falsyClassName` is returned
- otherwise `null` is returned - otherwise `null` is returned
- if the value is `true`, the dasherized last part of the supplied path - if the value is `true`, the dasherized last part of the supplied path
is returned is returned
- if the value is not `false`, `undefined` or `null`, the `value` - if the value is not `false`, `undefined` or `null`, the `value`
is returned is returned
- if none of the above rules apply, `null` is returned - if none of the above rules apply, `null` is returned
@ -15673,6 +15705,20 @@ Ember.View.reopenClass({
} }
}); });
var mutation = Ember.Object.extend(Ember.Evented).create();
Ember.View.addMutationListener = function(callback) {
mutation.on('change', callback);
};
Ember.View.removeMutationListener = function(callback) {
mutation.off('change', callback);
};
Ember.View.notifyMutationListeners = function() {
mutation.trigger('change');
};
/** /**
Global views hash Global views hash
@ -16476,7 +16522,7 @@ var get = Ember.get, set = Ember.set, fmt = Ember.String.fmt;
Given an empty `<body>` and the following code: Given an empty `<body>` and the following code:
```javascript ```javascript
someItemsView = Ember.CollectionView.create({ someItemsView = Ember.CollectionView.create({
classNames: ['a-collection'], classNames: ['a-collection'],
content: ['A','B','C'], content: ['A','B','C'],
@ -16831,15 +16877,15 @@ define("metamorph",
var K = function(){}, var K = function(){},
guid = 0, guid = 0,
document = window.document, document = this.document,
// Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
supportsRange = ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment, supportsRange = document && ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
// Internet Explorer prior to 9 does not allow setting innerHTML if the first element // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
// is a "zero-scope" element. This problem can be worked around by making // is a "zero-scope" element. This problem can be worked around by making
// the first node an invisible text node. We, like Modernizr, use &shy; // the first node an invisible text node. We, like Modernizr, use &shy;
needsShy = (function(){ needsShy = document && (function(){
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "<div></div>"; testEl.innerHTML = "<div></div>";
testEl.firstChild.innerHTML = "<script></script>"; testEl.firstChild.innerHTML = "<script></script>";
@ -16850,7 +16896,7 @@ define("metamorph",
// IE 8 (and likely earlier) likes to move whitespace preceeding // IE 8 (and likely earlier) likes to move whitespace preceeding
// a script tag to appear after it. This means that we can // a script tag to appear after it. This means that we can
// accidentally remove whitespace when updating a morph. // accidentally remove whitespace when updating a morph.
movesWhitespace = (function() { movesWhitespace = document && (function() {
var testEl = document.createElement('div'); var testEl = document.createElement('div');
testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value"; testEl.innerHTML = "Test: <script type='text/x-placeholder'></script>Value";
return testEl.childNodes[0].nodeValue === 'Test:' && return testEl.childNodes[0].nodeValue === 'Test:' &&
@ -17294,7 +17340,10 @@ var objectCreate = Object.create || function(parent) {
return new F(); return new F();
}; };
var Handlebars = this.Handlebars || Ember.imports.Handlebars; var Handlebars = this.Handlebars || (Ember.imports && Ember.imports.Handlebars);
if(!Handlebars && typeof require === 'function') {
Handlebars = require('handlebars');
}
/** /**
@ -17647,7 +17696,7 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
## Example with bound options ## Example with bound options
Bound hash options are also supported. Example: Bound hash options are also supported. Example:
```handlebars ```handlebars
{{repeat text countBinding="numRepeats"}} {{repeat text countBinding="numRepeats"}}
@ -17685,15 +17734,15 @@ Ember.Handlebars.registerHelper('helperMissing', function(path, options) {
{{concatenate prop1 prop2 prop3}}. If any of the properties change, {{concatenate prop1 prop2 prop3}}. If any of the properties change,
the helpr will re-render. Note that dependency keys cannot be the helpr will re-render. Note that dependency keys cannot be
using in conjunction with multi-property helpers, since it is ambiguous using in conjunction with multi-property helpers, since it is ambiguous
which property the dependent keys would belong to. which property the dependent keys would belong to.
## Use with unbound helper ## Use with unbound helper
The {{unbound}} helper can be used with bound helper invocations The {{unbound}} helper can be used with bound helper invocations
to render them in their unbound form, e.g. to render them in their unbound form, e.g.
```handlebars ```handlebars
{{unbound capitalize name}} {{unbound capitalize name}}
``` ```
In this example, if the name property changes, the helper In this example, if the name property changes, the helper
@ -17719,7 +17768,7 @@ Ember.Handlebars.registerBoundHelper = function(name, fn) {
view = data.view, view = data.view,
currentContext = (options.contexts && options.contexts[0]) || this, currentContext = (options.contexts && options.contexts[0]) || this,
normalized, normalized,
pathRoot, path, pathRoot, path,
loc, hashOption; loc, hashOption;
// Detect bound options (e.g. countBinding="otherCount") // Detect bound options (e.g. countBinding="otherCount")
@ -17824,7 +17873,7 @@ function evaluateMultiPropertyBoundHelper(context, fn, normalizedProperties, opt
// Assemble liast of watched properties that'll re-render this helper. // Assemble liast of watched properties that'll re-render this helper.
watchedProperties = []; watchedProperties = [];
for (boundOption in boundOptions) { for (boundOption in boundOptions) {
if (boundOptions.hasOwnProperty(boundOption)) { if (boundOptions.hasOwnProperty(boundOption)) {
watchedProperties.push(normalizePath(context, boundOptions[boundOption], data)); watchedProperties.push(normalizePath(context, boundOptions[boundOption], data));
} }
} }
@ -17953,22 +18002,30 @@ Ember.Handlebars.resolvePaths = function(options) {
var set = Ember.set, get = Ember.get; var set = Ember.set, get = Ember.get;
var Metamorph = requireModule('metamorph'); var Metamorph = requireModule('metamorph');
function notifyMutationListeners() {
Ember.run.once(Ember.View, 'notifyMutationListeners');
}
// DOMManager should just abstract dom manipulation between jquery and metamorph // DOMManager should just abstract dom manipulation between jquery and metamorph
var DOMManager = { var DOMManager = {
remove: function(view) { remove: function(view) {
view.morph.remove(); view.morph.remove();
notifyMutationListeners();
}, },
prepend: function(view, html) { prepend: function(view, html) {
view.morph.prepend(html); view.morph.prepend(html);
notifyMutationListeners();
}, },
after: function(view, html) { after: function(view, html) {
view.morph.after(html); view.morph.after(html);
notifyMutationListeners();
}, },
html: function(view, html) { html: function(view, html) {
view.morph.html(html); view.morph.html(html);
notifyMutationListeners();
}, },
// This is messed up. // This is messed up.
@ -17991,11 +18048,13 @@ var DOMManager = {
morph.replaceWith(buffer.string()); morph.replaceWith(buffer.string());
view.transitionTo('inDOM'); view.transitionTo('inDOM');
view.triggerRecursively('didInsertElement'); view.triggerRecursively('didInsertElement');
notifyMutationListeners();
}); });
}, },
empty: function(view) { empty: function(view) {
view.morph.html(""); view.morph.html("");
notifyMutationListeners();
} }
}; };
@ -18757,14 +18816,14 @@ EmberHandlebars.registerHelper('unless', function(context, options) {
Result in the following rendered output: Result in the following rendered output:
```html ```html
<img class="aValue"> <img class="aValue">
``` ```
A boolean return value will insert a specified class name if the property 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`. returns `true` and remove the class name if the property returns `false`.
A class name is provided via the syntax A class name is provided via the syntax
`somePropertyName:class-name-if-true`. `somePropertyName:class-name-if-true`.
```javascript ```javascript
@ -18919,9 +18978,9 @@ EmberHandlebars.registerHelper('bindAttr', function(options) {
@method bindClasses @method bindClasses
@for Ember.Handlebars @for Ember.Handlebars
@param {Ember.Object} context The context from which to lookup properties @param {Ember.Object} context The context from which to lookup properties
@param {String} classBindings A string, space-separated, of class bindings @param {String} classBindings A string, space-separated, of class bindings
to use to use
@param {Ember.View} view The view in which observers should look for the @param {Ember.View} view The view in which observers should look for the
element to update element to update
@param {Srting} bindAttrId Optional bindAttr id used to lookup elements @param {Srting} bindAttrId Optional bindAttr id used to lookup elements
@return {Array} An array of class names to add @return {Array} An array of class names to add
@ -19610,7 +19669,7 @@ Ember.Handlebars.registerHelper('unbound', function(property, fn) {
// Unbound helper call. // Unbound helper call.
options.data.isUnbound = true; options.data.isUnbound = true;
helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing; helper = Ember.Handlebars.helpers[arguments[0]] || Ember.Handlebars.helperMissing;
out = helper.apply(this, Array.prototype.slice.call(arguments, 1)); out = helper.apply(this, Array.prototype.slice.call(arguments, 1));
delete options.data.isUnbound; delete options.data.isUnbound;
return out; return out;
} }
@ -20905,7 +20964,7 @@ helpers = helpers || Ember.Handlebars.helpers; data = data || {};
var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this; var buffer = '', stack1, hashTypes, escapeExpression=this.escapeExpression, self=this;
function program1(depth0,data) { function program1(depth0,data) {
var buffer = '', hashTypes; var buffer = '', hashTypes;
data.buffer.push("<option value=\"\">"); data.buffer.push("<option value=\"\">");
hashTypes = {}; hashTypes = {};
@ -20915,7 +20974,7 @@ function program1(depth0,data) {
} }
function program3(depth0,data) { function program3(depth0,data) {
var hashTypes; var hashTypes;
hashTypes = {'contentBinding': "STRING"}; hashTypes = {'contentBinding': "STRING"};
data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{ data.buffer.push(escapeExpression(helpers.view.call(depth0, "Ember.SelectOption", {hash:{
@ -20930,7 +20989,7 @@ function program3(depth0,data) {
stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data}); stack1 = helpers.each.call(depth0, "view.content", {hash:{},inverse:self.noop,fn:self.program(3, program3, data),contexts:[depth0],types:["ID"],hashTypes:hashTypes,data:data});
if(stack1 || stack1 === 0) { data.buffer.push(stack1); } if(stack1 || stack1 === 0) { data.buffer.push(stack1); }
return buffer; return buffer;
}), }),
attributeBindings: ['multiple', 'disabled', 'tabindex'], attributeBindings: ['multiple', 'disabled', 'tabindex'],
@ -23362,6 +23421,34 @@ function teardownView(route) {
(function() {
Ember.onLoad('Ember.Handlebars', function() {
var handlebarsResolve = Ember.Handlebars.resolveParams,
map = Ember.ArrayPolyfills.map,
get = Ember.get;
function resolveParams(context, params, options) {
var resolved = handlebarsResolve(context, params, options);
return map.call(resolved, unwrap);
function unwrap(object, i) {
if (params[i] === 'controller') { return object; }
if (Ember.ControllerMixin.detect(object)) {
return unwrap(get(object, 'model'));
} else {
return object;
}
}
}
Ember.Router.resolveParams = resolveParams;
});
})();
(function() { (function() {
/** /**
@module ember @module ember
@ -23371,7 +23458,7 @@ function teardownView(route) {
var get = Ember.get, set = Ember.set; var get = Ember.get, set = Ember.set;
Ember.onLoad('Ember.Handlebars', function(Handlebars) { Ember.onLoad('Ember.Handlebars', function(Handlebars) {
var resolveParams = Ember.Handlebars.resolveParams, var resolveParams = Ember.Router.resolveParams,
isSimpleClick = Ember.ViewUtils.isSimpleClick; isSimpleClick = Ember.ViewUtils.isSimpleClick;
function fullRouteName(router, name) { function fullRouteName(router, name) {
@ -23652,7 +23739,7 @@ Ember.onLoad('Ember.Handlebars', function(Handlebars) {
*/ */
Ember.onLoad('Ember.Handlebars', function(Handlebars) { Ember.onLoad('Ember.Handlebars', function(Handlebars) {
var resolveParams = Ember.Handlebars.resolveParams, var resolveParams = Ember.Router.resolveParams,
isSimpleClick = Ember.ViewUtils.isSimpleClick; isSimpleClick = Ember.ViewUtils.isSimpleClick;
var EmberHandlebars = Ember.Handlebars, var EmberHandlebars = Ember.Handlebars,
@ -24277,7 +24364,7 @@ Ember.HashLocation = Ember.Object.extend({
set(self, 'lastSetURL', null); set(self, 'lastSetURL', null);
callback(location.hash.substr(1)); callback(path);
}); });
}); });
}, },
@ -24655,11 +24742,14 @@ var get = Ember.get, set = Ember.set,
``` ```
By default, calling `Ember.Application.create()` will automatically initialize By default, calling `Ember.Application.create()` will automatically initialize
your application by calling the `Ember.Application.initialize()` method. If your application by calling the `Ember.Application.initialize()` method. If
you need to delay initialization, you can call your app's `deferReadiness()` 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 method. When you are ready for your app to be initialized, call its
`advanceReadiness()` method. `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 Because `Ember.Application` inherits from `Ember.Namespace`, any classes
you create will have useful string representations when calling `toString()`. you create will have useful string representations when calling `toString()`.
See the `Ember.Namespace` documentation for more information. See the `Ember.Namespace` documentation for more information.
@ -24854,10 +24944,13 @@ var Application = Ember.Application = Ember.Namespace.extend({
this.scheduleInitialize(); this.scheduleInitialize();
} }
if ( Ember.LOG_VERSION ) {
}
}, },
/** /**
@ -25216,6 +25309,7 @@ Ember.Application.reopenClass({
Ember.Container.defaultContainer = Ember.Container.defaultContainer || container; Ember.Container.defaultContainer = Ember.Container.defaultContainer || container;
container.set = Ember.set; container.set = Ember.set;
container.normalize = normalize;
container.resolver = resolverFor(namespace); container.resolver = resolverFor(namespace);
container.optionsForType('view', { singleton: false }); container.optionsForType('view', { singleton: false });
container.optionsForType('template', { instantiate: false }); container.optionsForType('template', { instantiate: false });
@ -25255,6 +25349,7 @@ function resolverFor(namespace) {
if (type === 'template') { if (type === 'template') {
var templateName = name.replace(/\./g, '/'); var templateName = name.replace(/\./g, '/');
if (Ember.TEMPLATES[templateName]) { if (Ember.TEMPLATES[templateName]) {
return Ember.TEMPLATES[templateName]; return Ember.TEMPLATES[templateName];
} }
@ -25284,9 +25379,31 @@ function resolverFor(namespace) {
}; };
} }
Ember.runLoadHooks('Ember.Application', Ember.Application); function normalize(fullName) {
var split = fullName.split(':'),
type = split[0],
name = split[1];
if (type !== 'template') {
var result = name;
if (result.indexOf('.') > -1) {
result = result.replace(/\.(.)/g, function(m) { return m[1].toUpperCase(); });
}
if (name.indexOf('_') > -1) {
result = result.replace(/_(.)/g, function(m) { return m[1].toUpperCase(); });
}
return type + ':' + result;
} else {
return fullName;
}
}
Ember.runLoadHooks('Ember.Application', Ember.Application);
})(); })();