/** * 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 invoke 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: * * var a = {b: {}}; * var path = 'b.c.d'; * var value = 1; * Em.setFullPath(a, path, value); // a = {b: {c: {d: 1}}} * * * @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 set on destroyed view'); } } }); Ember.TextArea.reopen({ attributeBindings: ['readonly'] }); /** * Simply converts query string to object. * * @param {string} queryString query string e.g. '?param1=value1¶m2=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 serialize method. * You need to specify `:query` dynamic sygment in your route's route attribute * e.g. Em.Route.extend({ route: '/login:query'}) and return result of this method. * This method will set serializedQuery 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¶m2=value2 * // App.router.get('controllerNameToSetQueryObject').get('serializedQuery') * // will return { param1: 'value1', param2: 'value2' } * * @param {Em.Router} router router instance passed to serialize method * @param {object} params dynamic segment passed to seriazlie * @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); } } });