/** * 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. */ var computed = Em.computed; var get = Em.get; var makeArray = Em.makeArray; var slice = [].slice; var dataUtils = require('utils/data_manipulation'); /** * Returns hash with values of name properties from the context * If propertyName starts with 'App.', App is used as context, self used otherwise * If some propertyName starts with '!' its value will be inverted * * @param {object} self current context * @param {string[]} propertyNames needed properties * @returns {object} hash with needed values */ function getProperties(self, propertyNames) { var ret = {}; for (var i = 0; i < propertyNames.length; i++) { var propertyName = propertyNames[i]; var shouldBeInverted = propertyName.startsWith('!'); propertyName = shouldBeInverted ? propertyName.substr(1) : propertyName; var isApp = propertyName.startsWith('App.'); var name = isApp ? propertyName.replace('App.', '') : propertyName; var value = isApp ? App.get(name) : self.get(name); value = shouldBeInverted ? !value : value; ret[propertyName] = value; } return ret; } /** * Returns value of named property from the context * If propertyName starts with 'App.', App is used as context, self used otherwise * * @param {object} self current context * @param {string} propertyName needed property * @returns {*} needed value */ function smartGet(self, propertyName) { var isApp = propertyName.startsWith('App.'); var name = isApp ? propertyName.replace('App.', '') : propertyName; return isApp ? App.get(name) : self.get(name); } /** * Returns list with values of name properties from the context * If propertyName starts with 'App.', App is used as context, self used otherwise * * @param {object} self current context * @param {string[]} propertyNames needed properties * @returns {array} list of needed values */ function getValues(self, propertyNames) { return propertyNames.map(function (propertyName) { return smartGet(self, propertyName); }); } function generateComputedWithKey(macro) { return function () { var properties = slice.call(arguments, 1); var key = arguments[0]; var computedFunc = computed(function () { var values = getValues(this, properties); return macro.call(this, key, values); }); return computedFunc.property.apply(computedFunc, properties); } } function generateComputedWithProperties(macro) { return function () { var properties = slice.call(arguments); var computedFunc = computed(function () { return macro.apply(this, [getProperties(this, properties)]); }); var realProperties = properties.slice().invoke('replace', '!', ''); return computedFunc.property.apply(computedFunc, realProperties); }; } function generateComputedWithValues(macro) { return function () { var properties = slice.call(arguments); var computedFunc = computed(function () { return macro.apply(this, [getValues(this, properties)]); }); return computedFunc.property.apply(computedFunc, properties); }; } /** * * A computed property that returns true if the provided dependent property * is equal to the given value. * App.*-keys are supported * Example* * ```javascript * var Hamster = Ember.Object.extend({ * napTime: Ember.computed.equal('state', 'sleepy') * }); * var hamster = Hamster.create(); * hamster.get('napTime'); // false * hamster.set('state', 'sleepy'); * hamster.get('napTime'); // true * hamster.set('state', 'hungry'); * hamster.get('napTime'); // false * ``` * @method equal * @param {String} dependentKey * @param {String|Number|Object} value * @return {Ember.ComputedProperty} computed property which returns true if * the original value for property is equal to the given value. * @public */ computed.equal = function (dependentKey, value) { return computed(dependentKey, function () { return smartGet(this, dependentKey) === value; }).cacheable(); }; /** * A computed property that returns true if the provided dependent property is not equal to the given value * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 'a',
 *  p2: Em.computed.notEqual('p1', 'a')
 * });
 * console.log(o.get('p2')); // false
 * o.set('p1', 'b');
 * console.log(o.get('p2')); // true
 * 
* * @method notEqual * @param {string} dependentKey * @param {*} value * @returns {Ember.ComputedProperty} */ computed.notEqual = function (dependentKey, value) { return computed(dependentKey, function () { return smartGet(this, dependentKey) !== value; }); }; /** * A computed property that returns true if provided dependent properties are equal to the each other * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 'a',
 *  p2: 'b',
 *  p3: Em.computed.equalProperties('p1', 'p2')
 * });
 * console.log(o.get('p3')); // false
 * o.set('p1', 'b');
 * console.log(o.get('p3')); // true
 * 
* * @method equalProperties * @param {string} dependentKey1 * @param {string} dependentKey2 * @returns {Ember.ComputedProperty} */ computed.equalProperties = function (dependentKey1, dependentKey2) { return computed(dependentKey1, dependentKey2, function () { return smartGet(this, dependentKey1) === smartGet(this, dependentKey2); }); }; /** * A computed property that returns true if provided dependent properties are not equal to the each other * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 'a',
 *  p2: 'b',
 *  p3: Em.computed.notEqualProperties('p1', 'p2')
 * });
 * console.log(o.get('p3')); // true
 * o.set('p1', 'b');
 * console.log(o.get('p3')); // false
 * 
* * @method notEqualProperties * @param {string} dependentKey1 * @param {string} dependentKey2 * @returns {Ember.ComputedProperty} */ computed.notEqualProperties = function (dependentKey1, dependentKey2) { return computed(dependentKey1, dependentKey2, function () { return smartGet(this, dependentKey1) !== smartGet(this, dependentKey2); }); }; /** * A computed property that returns grouped collection's items by propertyName-value * * @method groupBy * @param {string} collectionKey * @param {string} propertyName * @returns {Ember.ComputedProperty} */ computed.groupBy = function (collectionKey, propertyName) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = get(this, collectionKey); return dataUtils.groupPropertyValues(collection, propertyName); }); }; /** * A computed property that returns filtered collection by propertyName values-list * Wrapper to filterProperty-method that allows using list of values to filter * * @method filterByMany * @param {string} collectionKey * @param {string} propertyName * @param {array} valuesToFilter * @returns {Ember.ComputedProperty} */ computed.filterByMany = function (collectionKey, propertyName, valuesToFilter) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = get(this, collectionKey); return dataUtils.filterPropertyValues(collection, propertyName, makeArray(valuesToFilter)); }); }; /** * A computed property that returns collection without elements with value that is in valuesToReject * Exclude objects from collection if its key exist in valuesToReject * * @method rejectMany * @param {string} collectionKey * @param {string} propertyName * @param {array} valuesToReject * @returns {Ember.ComputedProperty} */ computed.rejectMany = function (collectionKey, propertyName, valuesToReject) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = get(this, collectionKey); return dataUtils.rejectPropertyValues(collection, propertyName, makeArray(valuesToReject)); }); }; /** * A computed property that returns trueValue if dependent value is true and falseValue otherwise * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: true,
 *  p2: Em.computed.ifThenElse('p1', 'abc', 'cba')
 * });
 * console.log(o.get('p2')); // 'abc'
 * o.set('p1', false);
 * console.log(o.get('p2')); // 'cba'
 * 
* * @method ifThenElse * @param {string} dependentKey * @param {*} trueValue * @param {*} falseValue * @returns {Ember.ComputedProperty} */ computed.ifThenElse = function (dependentKey, trueValue, falseValue) { return computed(dependentKey, function () { return smartGet(this, dependentKey) ? trueValue : falseValue; }); }; /** * A computed property that is equal to the logical 'and' * Takes any number of arguments * Returns true if all of them are truly, false - otherwise * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: true,
 *  p2: true,
 *  p3: true,
 *  p4: Em.computed.and('p1', 'p2', 'p3')
 * });
 * console.log(o.get('p4')); // true
 * o.set('p1', false);
 * console.log(o.get('p4')); // false
 * 
* * @method and * @param {...string} dependentKeys * @returns {Ember.ComputedProperty} */ computed.and = generateComputedWithProperties(function (properties) { var value; for (var key in properties) { value = !!properties[key]; if (properties.hasOwnProperty(key) && !value) { return false; } } return value; }); /** * A computed property that is equal to the logical 'or' * Takes any number of arguments * Returns true if at least one of them is truly, false - otherwise * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: false,
 *  p2: false,
 *  p3: false,
 *  p4: Em.computed.or('p1', 'p2', 'p3')
 * });
 * console.log(o.get('p4')); // false
 * o.set('p1', true);
 * console.log(o.get('p4')); // true
 * 
* * @method or * @param {...string} dependentKeys * @returns {Ember.ComputedProperty} */ computed.or = generateComputedWithProperties(function (properties) { var value; for (var key in properties) { value = !!properties[key]; if (properties.hasOwnProperty(key) && value) { return value; } } return value; }); /** * A computed property that returns sum on the dependent properties values * Takes any number of arguments * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 1,
 *  p2: 2,
 *  p3: 3,
 *  p4: Em.computed.sumProperties('p1', 'p2', 'p3')
 * });
 * console.log(o.get('p4')); // 6
 * o.set('p1', 2);
 * console.log(o.get('p4')); // 7
 * 
* * @method sumProperties * @param {...string} dependentKeys * @returns {Ember.ComputedProperty} */ computed.sumProperties = generateComputedWithProperties(function (properties) { var sum = 0; for (var key in properties) { if (properties.hasOwnProperty(key)) { sum += Number(properties[key]); } } return sum; }); /** * A computed property that returns true if dependent value is greater or equal to the needed value * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: Em.computed.gte('p1', 1)
 * });
 * console.log(o.get('p2')); // true
 * o.set('p1', 4);
 * console.log(o.get('p2')); // true
 * o.set('p1', 5);
 * console.log(o.get('p2')); // false
 * 
* * @method gte * @param {string} dependentKey * @param {*} value * @returns {Ember.ComputedProperty} */ computed.gte = function (dependentKey, value) { return computed(dependentKey, function () { return smartGet(this, dependentKey) >= value; }); }; /** * A computed property that returns true if first dependent property is greater or equal to the second dependent property * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: 1,
 *  p3: Em.computed.gteProperties('p1', 'p2')
 * });
 * console.log(o.get('p3')); // true
 * o.set('p2', 4);
 * console.log(o.get('p3')); // true
 * o.set('p2', 5);
 * console.log(o.get('p3')); // false
 * 
* * @method gteProperties * @param {string} dependentKey1 * @param {string} dependentKey2 * @returns {Ember.ComputedProperty} */ computed.gteProperties = function (dependentKey1, dependentKey2) { return computed(dependentKey1, dependentKey2, function () { return smartGet(this, dependentKey1) >= smartGet(this, dependentKey2); }); }; /** * A computed property that returns true if dependent property is less or equal to the needed value * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: Em.computed.lte('p1', 1)
 * });
 * console.log(o.get('p2')); // false
 * o.set('p1', 4);
 * console.log(o.get('p2')); // true
 * o.set('p1', 5);
 * console.log(o.get('p2')); // true
 * 
* * @method lte * @param {string} dependentKey * @param {*} value * @returns {Ember.ComputedProperty} */ computed.lte = function (dependentKey, value) { return computed(dependentKey, function () { return smartGet(this, dependentKey) <= value; }); }; /** * A computed property that returns true if first dependent property is less or equal to the second dependent property * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: 1,
 *  p3: Em.computed.lteProperties('p1', 'p2')
 * });
 * console.log(o.get('p3')); // false
 * o.set('p2', 4);
 * console.log(o.get('p3')); // true
 * o.set('p2', 5);
 * console.log(o.get('p3')); // true
 * 
* * @method lteProperties * @param {string} dependentKey1 * @param {string} dependentKey2 * @returns {Ember.ComputedProperty} */ computed.lteProperties = function (dependentKey1, dependentKey2) { return computed(dependentKey1, dependentKey2, function () { return smartGet(this, dependentKey1) <= smartGet(this, dependentKey2); }); }; /** * A computed property that returns true if dependent value is greater than the needed value * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: Em.computed.gt('p1', 1)
 * });
 * console.log(o.get('p2')); // true
 * o.set('p1', 4);
 * console.log(o.get('p2')); // false
 * o.set('p1', 5);
 * console.log(o.get('p2')); // false
 * 
* * @method gt * @param {string} dependentKey * @param {*} value * @returns {Ember.ComputedProperty} */ computed.gt = function (dependentKey, value) { return computed(dependentKey, function () { return smartGet(this, dependentKey) > value; }); }; /** * A computed property that returns true if first dependent property is greater than the second dependent property * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: 1,
 *  p3: Em.computed.gteProperties('p1', 'p2')
 * });
 * console.log(o.get('p3')); // true
 * o.set('p2', 4);
 * console.log(o.get('p3')); // false
 * o.set('p2', 5);
 * console.log(o.get('p3')); // false
 * 
* * @method gtProperties * @param {string} dependentKey1 * @param {string} dependentKey2 * @returns {Ember.ComputedProperty} */ computed.gtProperties = function (dependentKey1, dependentKey2) { return computed(dependentKey1, dependentKey2, function () { return smartGet(this, dependentKey1) > smartGet(this, dependentKey2); }); }; /** * A computed property that returns true if dependent value is less than the needed value * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: Em.computed.lt('p1', 1)
 * });
 * console.log(o.get('p2')); // false
 * o.set('p1', 4);
 * console.log(o.get('p2')); // false
 * o.set('p1', 5);
 * console.log(o.get('p2')); // true
 * 
* * @method lt * @param {string} dependentKey * @param {*} value * @returns {Ember.ComputedProperty} */ computed.lt = function (dependentKey, value) { return computed(dependentKey, function () { return smartGet(this, dependentKey) < value; }); }; /** * A computed property that returns true if first dependent property is less than the second dependent property * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 4,
 *  p2: 1,
 *  p3: Em.computed.ltProperties('p1', 'p2')
 * });
 * console.log(o.get('p3')); // false
 * o.set('p2', 4);
 * console.log(o.get('p3')); // false
 * o.set('p2', 5);
 * console.log(o.get('p3')); // true
 * 
* * @method gtProperties * @param {string} dependentKey1 * @param {string} dependentKey2 * @returns {Ember.ComputedProperty} */ computed.ltProperties = function (dependentKey1, dependentKey2) { return computed(dependentKey1, dependentKey2, function () { return smartGet(this, dependentKey1) < smartGet(this, dependentKey2); }); }; /** * A computed property that returns true if dependent property is match to the needed regular expression *
 * var o = Em.Object.create({
 *  p1: 'abc',
 *  p2: Em.computed.match('p1', /^a/)
 * });
 * console.log(o.get('p2')); // true
 * o.set('p1', 'bc');
 * console.log(o.get('p2')); // false
 * 
* * @method match * @param {string} dependentKey * @param {RegExp} regexp * @returns {Ember.ComputedProperty} */ computed.match = function (dependentKey, regexp) { return computed(dependentKey, function () { var value = get(this, dependentKey); if (!regexp) { return false; } return regexp.test(value); }); }; /** * A computed property that returns true of some collection's item has property with needed value *
 * var o = Em.Object.create({
 *  p1: [{a: 1}, {a: 2}, {a: 3}],
 *  p2: Em.computed.someBy('p1', 'a', 1)
 * });
 * console.log(o.get('p2')); // true
 * o.set('p1.0.a', 2);
 * console.log(o.get('p2')); // false
 * 
* * @method someBy * @param {string} collectionKey * @param {string} propertyName * @param {*} neededValue * @returns {Ember.ComputedProperty} */ computed.someBy = function (collectionKey, propertyName, neededValue) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = smartGet(this, collectionKey); if (!collection) { return false; } return collection.someProperty(propertyName, neededValue); }); }; /** * A computed property that returns true of all collection's items have property with needed value *
 * var o = Em.Object.create({
 *  p1: [{a: 1}, {a: 1}, {a: 1}],
 *  p2: Em.computed.everyBy('p1', 'a', 1)
 * });
 * console.log(o.get('p2')); // true
 * o.set('p1.0.a', 2);
 * console.log(o.get('p2')); // false
 * 
* * @method everyBy * @param {string} collectionKey * @param {string} propertyName * @param {*} neededValue * @returns {Ember.ComputedProperty} */ computed.everyBy = function (collectionKey, propertyName, neededValue) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = smartGet(this, collectionKey); if (!collection) { return false; } return collection.everyProperty(propertyName, neededValue); }); }; /** * A computed property that returns array with values of named property on all items in the collection *
 * var o = Em.Object.create({
 *  p1: [{a: 1}, {a: 2}, {a: 3}],
 *  p2: Em.computed.everyBy('p1', 'a')
 * });
 * console.log(o.get('p2')); // [1, 2, 3]
 * o.set('p1.0.a', 2);
 * console.log(o.get('p2')); // [2, 2, 3]
 * 
* * @method mapBy * @param {string} collectionKey * @param {string} propertyName * @returns {Ember.ComputedProperty} */ computed.mapBy = function (collectionKey, propertyName) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = smartGet(this, collectionKey); if (!collection) { return []; } return collection.mapProperty(propertyName); }); }; /** * A computed property that returns array with collection's items that have needed property value *
 * var o = Em.Object.create({
 *  p1: [{a: 1}, {a: 2}, {a: 3}],
 *  p2: Em.computed.filterBy('p1', 'a', 2)
 * });
 * console.log(o.get('p2')); // [{a: 2}]
 * o.set('p1.0.a', 2);
 * console.log(o.get('p2')); // [{a: 2}, {a: 2}]
 * 
* * @method filterBy * @param {string} collectionKey * @param {string} propertyName * @param {*} neededValue * @returns {Ember.ComputedProperty} */ computed.filterBy = function (collectionKey, propertyName, neededValue) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = smartGet(this, collectionKey); if (!collection) { return []; } return collection.filterProperty(propertyName, neededValue); }); }; /** * A computed property that returns first collection's item that has needed property value *
 * var o = Em.Object.create({
 *  p1: [{a: 1, b: 1}, {a: 2, b: 2}, {a: 3, b: 3}],
 *  p2: Em.computed.findBy('p1', 'a', 2)
 * });
 * console.log(o.get('p2')); // [{a: 2, b: 2}]
 * o.set('p1.0.a', 2);
 * console.log(o.get('p2')); // [{a: 2, b: 1}]
 * 
* * @method findBy * @param {string} collectionKey * @param {string} propertyName * @param {*} neededValue * @returns {Ember.ComputedProperty} */ computed.findBy = function (collectionKey, propertyName, neededValue) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = smartGet(this, collectionKey); if (!collection) { return null; } return collection.findProperty(propertyName, neededValue); }); }; /** * A computed property that returns value equal to the dependent * Should be used as 'short-name' for deeply-nested values * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: {a: {b: {c: 2}}},
 *  p2: Em.computed.alias('p1.a.b.c')
 * });
 * console.log(o.get('p2')); // 2
 * o.set('p1.a.b.c', 4);
 * console.log(o.get('p2')); // 4
 * 
* * @method alias * @param {string} dependentKey * @returns {Ember.ComputedProperty} */ computed.alias = function (dependentKey) { return computed(dependentKey, function () { return smartGet(this, dependentKey); }); }; /** * A computed property that returns true if dependent property exists in the needed values *
 * var o = Em.Object.create({
 *  p1: 2,
 *  p2: Em.computed.existsIn('p1', [1, 2, 3])
 * });
 * console.log(o.get('p2')); // true
 * o.set('p1', 4);
 * console.log(o.get('p2')); // false
 * 
* * @method existsIn * @param {string} dependentKey * @param {array} neededValues * @returns {Ember.ComputedProperty} */ computed.existsIn = function (dependentKey, neededValues) { return computed(dependentKey, function () { var value = smartGet(this, dependentKey); return makeArray(neededValues).contains(value); }); }; /** * A computed property that returns true if dependent property doesn't exist in the needed values *
 * var o = Em.Object.create({
 *  p1: 2,
 *  p2: Em.computed.notExistsIn('p1', [1, 2, 3])
 * });
 * console.log(o.get('p2')); // false
 * o.set('p1', 4);
 * console.log(o.get('p2')); // true
 * 
* * @method notExistsIn * @param {string} dependentKey * @param {array} neededValues * @returns {Ember.ComputedProperty} */ computed.notExistsIn = function (dependentKey, neededValues) { return computed(dependentKey, function () { var value = smartGet(this, dependentKey); return !makeArray(neededValues).contains(value); }); }; /** * A computed property that returns result of calculation (dependentProperty1/dependentProperty2 * 100) * If accuracy is 0 (by default), result is rounded to integer * Otherwise - result is float with provided accuracy * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 2,
 *  p2: 4,
 *  p3: Em.computed.percents('p1', 'p2')
 * });
 * console.log(o.get('p3')); // 50
 * o.set('p2', 5);
 * console.log(o.get('p3')); // 40
 * 
* * @method percents * @param {string} dependentKey1 * @param {string} dependentKey2 * @param {number} [accuracy=0] * @returns {Ember.ComputedProperty} */ computed.percents = function (dependentKey1, dependentKey2, accuracy) { if (arguments.length < 3) { accuracy = 0; } return computed(dependentKey1, dependentKey2, function () { var v1 = Number(smartGet(this, dependentKey1)); var v2 = Number(smartGet(this, dependentKey2)); var result = v1 / v2 * 100; if (0 === accuracy) { return Math.round(result); } return parseFloat(result.toFixed(accuracy)); }); }; /** * A computed property that returns result of App.format.role for dependent value *
 * var o = Em.Object.create({
 *  p1: 'SECONDARY_NAMENODE',
 *  p3: Em.computed.formatRole('p1', false)
 * });
 * console.log(o.get('p2')); // 'SNameNode'
 * o.set('p1', 'FLUME_HANDLER);
 * console.log(o.get('p2')); // 'Flume'
 * 
* * @method formatRole * @param {string} dependentKey * @param {boolean} isServiceRole * @returns {Ember.ComputedProperty} */ computed.formatRole = function (dependentKey, isServiceRole) { return computed(dependentKey, function () { var value = get(this, dependentKey); return App.format.role(value, isServiceRole); }); }; /** * A computed property that returns sum of the named property in the each collection's item *
 * var o = Em.Object.create({
 *  p1: [{a: 1}, {a: 2}, {a: 3}],
 *  p2: Em.computed.sumBy('p1', 'a')
 * });
 * console.log(o.get('p2')); // 6
 * o.set('p1.0.a', 2);
 * console.log(o.get('p2')); // 7
 * 
* * @method sumBy * @param {string} collectionKey * @param {string} propertyName * @returns {Ember.ComputedProperty} */ computed.sumBy = function (collectionKey, propertyName) { return computed(collectionKey + '.@each.' + propertyName, function () { var collection = smartGet(this, collectionKey); if (Em.isEmpty(collection)) { return 0; } var sum = 0; collection.forEach(function (item) { sum += Number(get(item, propertyName)); }); return sum; }); }; /** * A computed property that returns I18n-string formatted with dependent properties * Takes at least one argument * App.*-keys are supported * * @param {string} key key in the I18n-messages * @param {...string} dependentKeys * @method i18nFormat * @returns {Ember.ComputedProperty} */ computed.i18nFormat = generateComputedWithKey(function (key, dependentValues) { var str = Em.I18n.t(key); if (!str) { return ''; } return str.format.apply(str, dependentValues); }); /** * A computed property that returns string formatted with dependent properties * Takes at least one argument * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 'abc',
 *  p2: 'cba',
 *  p3: Em.computed.format('{0} => {1}', 'p1', 'p2')
 * });
 * console.log(o.get('p3')); // 'abc => cba'
 * o.set('p1', 'aaa');
 * console.log(o.get('p3')); // 'aaa => cba'
 * 
* * @param {string} str string to format * @param {...string} dependentKeys * @method format * @returns {Ember.ComputedProperty} */ computed.format = generateComputedWithKey(function (str, dependentValues) { if (!str) { return ''; } return str.format.apply(str, dependentValues); }); /** * A computed property that returns dependent values joined with separator * Takes at least one argument * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 'abc',
 *  p2: 'cba',
 *  p3: Em.computed.concat('|', 'p1', 'p2')
 * });
 * console.log(o.get('p3')); // 'abc|cba'
 * o.set('p1', 'aaa');
 * console.log(o.get('p3')); // 'aaa|cba'
 * 
* * @param {string} separator * @param {...string} dependentKeys * @method concat * @return {Ember.ComputedProperty} */ computed.concat = generateComputedWithKey(function (separator, dependentValues) { return dependentValues.join(separator); }); /** * A computed property that returns first not blank value from dependent values * Based on Ember.isBlank * Takes at least 1 argument * Dependent values order affects the result * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: null,
 *  p2: '',
 *  p3: 'abc'
 *  p4: Em.computed.firstNotBlank('p1', 'p2', 'p3')
 * });
 * console.log(o.get('p4')); // 'abc'
 * o.set('p1', 'aaa');
 * console.log(o.get('p4')); // 'aaa'
 * 
* * @param {...string} dependentKeys * @method firstNotBlank * @return {Ember.ComputedProperty} */ computed.firstNotBlank = generateComputedWithValues(function (values) { for (var i = 0; i < values.length; i++) { if (!Em.isBlank(values[i])) { return values[i]; } } return null; }); /** * A computed property that returns dependent value if it is truly or ('0'|0) * Returns 'n/a' otherwise * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 0,
 *  p2: Em.computed.formatUnavailable('p1')
 * });
 * console.log(o.get('p2')); // 0
 * o.set('p1', 12);
 * console.log(o.get('p2')); // 12
 * o.set('p1', 'some string');
 * console.log(o.get('p2')); // 'n/a'
 * 
* * @param {string} dependentKey * @method formatUnavailable * @returns {Ember.ComputedProperty} */ computed.formatUnavailable = function(dependentKey) { return computed(dependentKey, function () { var value = smartGet(this, dependentKey); return value || value == 0 ? value : Em.I18n.t('services.service.summary.notAvailable'); }); }; /** * A computed property that returns one of provided values basing on dependent value * If dependent value is 0, zeroMsg is returned * If dependent value is 1, oneMsg is returned * If dependent value is greater than 1, manyMsg is returned * App.*-keys are supported *
 * var o = Em.Object.create({
 *  p1: 0,
 *  p2: Em.computed.formatUnavailable('p1', '0msg', '1msg', '2+msg')
 * });
 * console.log(o.get('p2')); // '0msg'
 * o.set('p1', 1);
 * console.log(o.get('p2')); // '1msg'
 * o.set('p1', 100500);
 * console.log(o.get('p2')); // '2+msg'
 * 
* * @param {string} dependentKey * @param {string} zeroMsg * @param {string} oneMsg * @param {string} manyMsg * @returns {Ember.ComputedProperty} * @method countBasedMessage */ computed.countBasedMessage = function (dependentKey, zeroMsg, oneMsg, manyMsg) { return computed(dependentKey, function () { var value = Number(smartGet(this, dependentKey)); if (value === 0) { return zeroMsg; } if (value > 1) { return manyMsg; } return oneMsg; }); }; /** * A computed property that returns property value according to the property key and object key * App.*-keys are supported *
 *   var o = Em.Object.create({
 *    p1: {a: 1, b: 2, c: 3},
 *    p2: 'a',
 *    p3: Em.computed.getByKey('p1', 'p2')
 *   });
 *   console.log(o.get('p3')); // 1
 *   o.set('p2', 'b');
 *   console.log(o.get('p3')); // 2
 *   o.set('p2', 'c');
 *   console.log(o.get('p3')); // 3
 * 
* * With `defaultValue` *
 *   var o = Em.Object.create({
 *    p1: {a: 1, b: 2, c: 3},
 *    p2: 'd',
 *    p3: Em.computed.getByKey('p1', 'p2', 100500)
 *   });
 *   console.log(o.get('p3')); // 100500 - default value is returned, because there is no key `d` in the `p1`
 * 
* IMPORTANT! This CP SHOULD NOT be used with for object with values equal to the views (like {a: App.MyViewA, b: App.MyViewB}) * This restriction exists because views may be undefined on the moment when this CP is calculated (files are not `required` yet) * * @param {string} objectKey * @param {string} propertyKey * @param {*} [defaultValue] * @returns {Ember.ComputedProperty} */ computed.getByKey = function (objectKey, propertyKey, defaultValue) { return computed(objectKey, propertyKey, function () { var object = smartGet(this, objectKey); var property = smartGet(this, propertyKey); if (!object) { return null; } return object.hasOwnProperty(property) ? object[property] : defaultValue; }); }