blob: 8e47091e8ca6edb71a49de47a19cc1b214819cc2 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
Merge the contents of two objects together into the first object.
```javascript
Ember.merge({first: 'Tom'}, {last: 'Dale'}); // {first: 'Tom', last: 'Dale'}
var a = {first: 'Yehuda'}, b = {last: 'Katz'};
Ember.merge(a, b); // a == {first: 'Yehuda', last: 'Katz'}, b == {last: 'Katz'}
```
@method merge
@for Ember
@param {Object} original The object to merge into
@param {Object} updates The object to copy properties from
@return {Object}
*/
Ember.merge = function(original, updates) {
for (var prop in updates) {
if (!updates.hasOwnProperty(prop)) { continue; }
original[prop] = updates[prop];
}
return original;
};
/**
Returns true if the passed value is null or undefined. This avoids errors
from JSLint complaining about use of ==, which can be technically
confusing.
```javascript
Ember.isNone(); // true
Ember.isNone(null); // true
Ember.isNone(undefined); // true
Ember.isNone(''); // false
Ember.isNone([]); // false
Ember.isNone(function() {}); // false
```
@method isNone
@for Ember
@param {Object} obj Value to test
@return {Boolean}
*/
Ember.isNone = function(obj) {
return obj === null || obj === undefined;
};
/**
Verifies that a value is `null` or an empty string, empty array,
or empty function.
Constrains the rules on `Ember.isNone` by returning false for empty
string and empty arrays.
```javascript
Ember.isEmpty(); // true
Ember.isEmpty(null); // true
Ember.isEmpty(undefined); // true
Ember.isEmpty(''); // true
Ember.isEmpty([]); // true
Ember.isEmpty('Adam Hawkins'); // false
Ember.isEmpty([0,1,2]); // false
```
@method isEmpty
@for Ember
@param {Object} obj Value to test
@return {Boolean}
*/
Ember.isEmpty = function(obj) {
return Ember.isNone(obj) || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && Ember.get(obj, 'length') === 0);
};
/**
A value is blank if it is empty or a whitespace string.
```javascript
Ember.isBlank(); // true
Ember.isBlank(null); // true
Ember.isBlank(undefined); // true
Ember.isBlank(''); // true
Ember.isBlank([]); // true
Ember.isBlank('\n\t'); // true
Ember.isBlank(' '); // true
Ember.isBlank({}); // false
Ember.isBlank('\n\t Hello'); // false
Ember.isBlank('Hello world'); // false
Ember.isBlank([1,2,3]); // false
```
@method isBlank
@for Ember
@param {Object} obj Value to test
@return {Boolean}
*/
Ember.isBlank = function(obj) {
return Ember.isEmpty(obj) || (typeof obj === 'string' && obj.match(/\S/) === null);
};
/**
* Calculates sum of two numbers
* Use this function as a callback on <code>invoke</code> etc
*
* @method sum
* @param {Number} a
* @param {Number} b
* @returns {Number}
*/
Ember.sum = function (a, b) {
return a + b;
};
/**
* Execute passed callback
*
* @param {Function} callback
* @returns {*}
*/
Ember.clb = function (callback) {
return callback();
};
/**
*
*/
Ember.RadioButton = Ember.Checkbox.extend({
tagName: "input",
type: "radio",
attributeBindings: [ "type", "name", "value", "checked", "style", "disabled" ],
style: "vertical-align: middle; margin: 0px;",
click: function () {
this.set("selection", this.$().val())
},
checked: function () {
return this.get("value") == this.get("selection");
}.property('value', 'selection')
});
/**
* Set value to obj by path
* Create nested objects if needed
* Example:
* <code>
* var a = {b: {}};
* var path = 'b.c.d';
* var value = 1;
* Em.setFullPath(a, path, value); // a = {b: {c: {d: 1}}}
* </code>
*
* @param {object} obj
* @param {string} path
* @param {*} value
*/
Ember.setFullPath = function (obj, path, value) {
var parts = path.split('.'),
sub_path = '';
parts.forEach(function(_path, _index) {
Em.assert('path parts can\'t be empty', _path.length);
sub_path += '.' + _path;
if (_index === parts.length - 1) {
Em.set(obj, sub_path, value);
return;
}
if (Em.isNone(Em.get(obj, sub_path))) {
Em.set(obj, sub_path, {});
}
});
};
/**
*
* @param {object} target
* @param {string[]} propertyNames
* @returns {{}}
*/
Ember.getProperties = function (target, propertyNames) {
var ret = {};
for(var i = 0; i < propertyNames.length; i++) {
ret[propertyNames[i]] = Em.get(target, propertyNames[i]);
}
return ret;
};
Em.View.reopen({
/**
* overwritten set method of Ember.View to avoid uncaught errors
* when trying to set property of destroyed view
*/
set: function(attr, value){
if(!this.get('isDestroyed') && !this.get('isDestroying')){
this._super(attr, value);
} else {
console.debug('Calling set on destroyed view');
}
},
/**
* overwritten setProperties method of Ember.View to avoid uncaught errors
* when trying to set multiple properties of destroyed view
*/
setProperties: function(hash){
if(!this.get('isDestroyed') && !this.get('isDestroying')){
this._super(hash);
} else {
console.debug('Calling setProperties on destroyed view');
}
}
});
Ember._HandlebarsBoundView.reopen({
/**
* overwritten set method of Ember._HandlebarsBoundView to avoid uncaught errors
* when trying to set property of destroyed view
*/
render: function(buffer){
if(!this.get('isDestroyed') && !this.get('isDestroying')){
this._super(buffer);
} else {
console.debug('Calling render on destroyed view');
}
}
});
Ember.TextArea.reopen({
attributeBindings: ['readonly']
});
/**
* Simply converts query string to object.
*
* @param {string} queryString query string e.g. '?param1=value1&param2=value2'
* @return {object} converted object
*/
function parseQueryParams(queryString) {
if (!queryString) {
return {};
}
return queryString.replace(/^\?/, '').split('&').map(decodeURIComponent)
.reduce(function(p, c) {
var keyVal = c.split('=');
p[keyVal[0]] = keyVal[1];
return p;
}, {});
};
Ember.Route.reopen({
/**
* When you move to a new route by pressing the back or forward button, change url manually, click on link with url defined in href,
* call Router.transitionTo or Router.route this method is called.
* This method unites unroutePath, navigateAway and exit events to handle Route leaving in one place.
* Also unlike the exit event it is possible to stop transition inside this handler.
* To proceed transition just call callback..
*
* @param {Router} router
* @param {Object|String} context context from transition or path from route
* @param {callback} callback should be called to proceed transition
*/
exitRoute: function (router, context, callback) {
callback();
},
/**
* Query Params serializer. This method should be used inside <code>serialize</code> method.
* You need to specify `:query` dynamic sygment in your route's <code>route</code> attribute
* e.g. Em.Route.extend({ route: '/login:query'}) and return result of this method.
* This method will set <code>serializedQuery</code> property to specified controller by name.
* For concrete example see `app/routes/main.js`.
*
* @example
* queryParams: Em.Route.extend({
* route: '/queryDemo:query',
* serialize: function(route, params) {
* return this.serializeQueryParams(route, params, 'controllerNameToSetQueryObject');
* }
* });
* // now when navigated to http://example.com/#/queryDemo?param1=value1&param2=value2
* // App.router.get('controllerNameToSetQueryObject').get('serializedQuery')
* // will return { param1: 'value1', param2: 'value2' }
*
* @param {Em.Router} router router instance passed to <code>serialize</code> method
* @param {object} params dynamic segment passed to <code>seriazlie</code>
* @param {string} controllerName name of the controller to set `serializedQuery` as result
* @return {object}
*/
serializeQueryParams: function(router, params, controllerName) {
var controller = router.get(controllerName);
controller.set('serializedQuery', parseQueryParams(params ? params.query : ''));
return params || { query: ''};
}
});
Ember.Router.reopen({
// reopen original transitionTo and route methods to add calling of exitRoute
transitionTo: function (router, context) {
var self = this;
var args = arguments;
var transitionTo = self._super;
var callback = function () {
transitionTo.apply(self, args);
};
if (!this.get('currentState.exitRoute')) {
callback();
} else {
this.get('currentState').exitRoute(this, context, callback);
}
},
route: function (path) {
var self = this;
var args = arguments;
var transitionTo = self._super;
var callback = function () {
self.get('location').setURL(path);
transitionTo.apply(self, args);
};
var realPath;
if (!this.get('currentState.exitRoute')) {
callback();
} else {
realPath = this.get('currentState').absoluteRoute(this);
this.get('location').setURL(realPath);
this.get('currentState').exitRoute(this, path, callback);
}
}
});