ember_computed.js 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var computed = Em.computed;
  19. var get = Em.get;
  20. var makeArray = Em.makeArray;
  21. var slice = [].slice;
  22. var dataUtils = require('utils/data_manipulation');
  23. /**
  24. * Returns hash with values of name properties from the context
  25. * If <code>propertyName</code> starts with 'App.', <code>App</code> is used as context, <code>self</code> used otherwise
  26. * If some <code>propertyName</code> starts with '!' its value will be inverted
  27. *
  28. * @param {object} self current context
  29. * @param {string[]} propertyNames needed properties
  30. * @returns {object} hash with needed values
  31. */
  32. function getProperties(self, propertyNames) {
  33. var ret = {};
  34. for (var i = 0; i < propertyNames.length; i++) {
  35. var propertyName = propertyNames[i];
  36. var shouldBeInverted = propertyName.startsWith('!');
  37. propertyName = shouldBeInverted ? propertyName.substr(1) : propertyName;
  38. var isApp = propertyName.startsWith('App.');
  39. var name = isApp ? propertyName.replace('App.', '') : propertyName;
  40. var value = isApp ? App.get(name) : self.get(name);
  41. value = shouldBeInverted ? !value : value;
  42. ret[propertyName] = value;
  43. }
  44. return ret;
  45. }
  46. /**
  47. * Returns value of named property from the context
  48. * If <code>propertyName</code> starts with 'App.', <code>App</code> is used as context, <code>self</code> used otherwise
  49. *
  50. * @param {object} self current context
  51. * @param {string} propertyName needed property
  52. * @returns {*} needed value
  53. */
  54. function smartGet(self, propertyName) {
  55. var isApp = propertyName.startsWith('App.');
  56. var name = isApp ? propertyName.replace('App.', '') : propertyName;
  57. return isApp ? App.get(name) : self.get(name);
  58. }
  59. /**
  60. * Returns list with values of name properties from the context
  61. * If <code>propertyName</code> starts with 'App.', <code>App</code> is used as context, <code>self</code> used otherwise
  62. *
  63. * @param {object} self current context
  64. * @param {string[]} propertyNames needed properties
  65. * @returns {array} list of needed values
  66. */
  67. function getValues(self, propertyNames) {
  68. return propertyNames.map(function (propertyName) {
  69. return smartGet(self, propertyName);
  70. });
  71. }
  72. function generateComputedWithKey(macro) {
  73. return function () {
  74. var properties = slice.call(arguments, 1);
  75. var key = arguments[0];
  76. var computedFunc = computed(function () {
  77. var values = getValues(this, properties);
  78. return macro.call(this, key, values);
  79. });
  80. return computedFunc.property.apply(computedFunc, properties);
  81. }
  82. }
  83. function generateComputedWithProperties(macro) {
  84. return function () {
  85. var properties = slice.call(arguments);
  86. var computedFunc = computed(function () {
  87. return macro.apply(this, [getProperties(this, properties)]);
  88. });
  89. var realProperties = properties.slice().invoke('replace', '!', '');
  90. return computedFunc.property.apply(computedFunc, realProperties);
  91. };
  92. }
  93. function generateComputedWithValues(macro) {
  94. return function () {
  95. var properties = slice.call(arguments);
  96. var computedFunc = computed(function () {
  97. return macro.apply(this, [getValues(this, properties)]);
  98. });
  99. return computedFunc.property.apply(computedFunc, properties);
  100. };
  101. }
  102. /**
  103. *
  104. * A computed property that returns true if the provided dependent property
  105. * is equal to the given value.
  106. * App.*-keys are supported
  107. * Example*
  108. * ```javascript
  109. * var Hamster = Ember.Object.extend({
  110. * napTime: Ember.computed.equal('state', 'sleepy')
  111. * });
  112. * var hamster = Hamster.create();
  113. * hamster.get('napTime'); // false
  114. * hamster.set('state', 'sleepy');
  115. * hamster.get('napTime'); // true
  116. * hamster.set('state', 'hungry');
  117. * hamster.get('napTime'); // false
  118. * ```
  119. * @method equal
  120. * @param {String} dependentKey
  121. * @param {String|Number|Object} value
  122. * @return {Ember.ComputedProperty} computed property which returns true if
  123. * the original value for property is equal to the given value.
  124. * @public
  125. */
  126. computed.equal = function (dependentKey, value) {
  127. return computed(dependentKey, function () {
  128. return smartGet(this, dependentKey) === value;
  129. }).cacheable();
  130. };
  131. /**
  132. * A computed property that returns true if the provided dependent property is not equal to the given value
  133. * App.*-keys are supported
  134. * <pre>
  135. * var o = Em.Object.create({
  136. * p1: 'a',
  137. * p2: Em.computed.notEqual('p1', 'a')
  138. * });
  139. * console.log(o.get('p2')); // false
  140. * o.set('p1', 'b');
  141. * console.log(o.get('p2')); // true
  142. * </pre>
  143. *
  144. * @method notEqual
  145. * @param {string} dependentKey
  146. * @param {*} value
  147. * @returns {Ember.ComputedProperty}
  148. */
  149. computed.notEqual = function (dependentKey, value) {
  150. return computed(dependentKey, function () {
  151. return smartGet(this, dependentKey) !== value;
  152. });
  153. };
  154. /**
  155. * A computed property that returns true if provided dependent properties are equal to the each other
  156. * App.*-keys are supported
  157. * <pre>
  158. * var o = Em.Object.create({
  159. * p1: 'a',
  160. * p2: 'b',
  161. * p3: Em.computed.equalProperties('p1', 'p2')
  162. * });
  163. * console.log(o.get('p3')); // false
  164. * o.set('p1', 'b');
  165. * console.log(o.get('p3')); // true
  166. * </pre>
  167. *
  168. * @method equalProperties
  169. * @param {string} dependentKey1
  170. * @param {string} dependentKey2
  171. * @returns {Ember.ComputedProperty}
  172. */
  173. computed.equalProperties = function (dependentKey1, dependentKey2) {
  174. return computed(dependentKey1, dependentKey2, function () {
  175. return smartGet(this, dependentKey1) === smartGet(this, dependentKey2);
  176. });
  177. };
  178. /**
  179. * A computed property that returns true if provided dependent properties are not equal to the each other
  180. * App.*-keys are supported
  181. * <pre>
  182. * var o = Em.Object.create({
  183. * p1: 'a',
  184. * p2: 'b',
  185. * p3: Em.computed.notEqualProperties('p1', 'p2')
  186. * });
  187. * console.log(o.get('p3')); // true
  188. * o.set('p1', 'b');
  189. * console.log(o.get('p3')); // false
  190. * </pre>
  191. *
  192. * @method notEqualProperties
  193. * @param {string} dependentKey1
  194. * @param {string} dependentKey2
  195. * @returns {Ember.ComputedProperty}
  196. */
  197. computed.notEqualProperties = function (dependentKey1, dependentKey2) {
  198. return computed(dependentKey1, dependentKey2, function () {
  199. return smartGet(this, dependentKey1) !== smartGet(this, dependentKey2);
  200. });
  201. };
  202. /**
  203. * A computed property that returns grouped collection's items by propertyName-value
  204. *
  205. * @method groupBy
  206. * @param {string} collectionKey
  207. * @param {string} propertyName
  208. * @returns {Ember.ComputedProperty}
  209. */
  210. computed.groupBy = function (collectionKey, propertyName) {
  211. return computed(collectionKey + '.@each.' + propertyName, function () {
  212. var collection = get(this, collectionKey);
  213. return dataUtils.groupPropertyValues(collection, propertyName);
  214. });
  215. };
  216. /**
  217. * A computed property that returns filtered collection by propertyName values-list
  218. * Wrapper to filterProperty-method that allows using list of values to filter
  219. *
  220. * @method filterByMany
  221. * @param {string} collectionKey
  222. * @param {string} propertyName
  223. * @param {array} valuesToFilter
  224. * @returns {Ember.ComputedProperty}
  225. */
  226. computed.filterByMany = function (collectionKey, propertyName, valuesToFilter) {
  227. return computed(collectionKey + '.@each.' + propertyName, function () {
  228. var collection = get(this, collectionKey);
  229. return dataUtils.filterPropertyValues(collection, propertyName, makeArray(valuesToFilter));
  230. });
  231. };
  232. /**
  233. * A computed property that returns collection without elements with value that is in <code>valuesToReject</code>
  234. * Exclude objects from <code>collection</code> if its <code>key</code> exist in <code>valuesToReject</code>
  235. *
  236. * @method rejectMany
  237. * @param {string} collectionKey
  238. * @param {string} propertyName
  239. * @param {array} valuesToReject
  240. * @returns {Ember.ComputedProperty}
  241. */
  242. computed.rejectMany = function (collectionKey, propertyName, valuesToReject) {
  243. return computed(collectionKey + '.@each.' + propertyName, function () {
  244. var collection = get(this, collectionKey);
  245. return dataUtils.rejectPropertyValues(collection, propertyName, makeArray(valuesToReject));
  246. });
  247. };
  248. /**
  249. * A computed property that returns trueValue if dependent value is true and falseValue otherwise
  250. * App.*-keys are supported
  251. * <pre>
  252. * var o = Em.Object.create({
  253. * p1: true,
  254. * p2: Em.computed.ifThenElse('p1', 'abc', 'cba')
  255. * });
  256. * console.log(o.get('p2')); // 'abc'
  257. * o.set('p1', false);
  258. * console.log(o.get('p2')); // 'cba'
  259. * </pre>
  260. *
  261. * @method ifThenElse
  262. * @param {string} dependentKey
  263. * @param {*} trueValue
  264. * @param {*} falseValue
  265. * @returns {Ember.ComputedProperty}
  266. */
  267. computed.ifThenElse = function (dependentKey, trueValue, falseValue) {
  268. return computed(dependentKey, function () {
  269. return smartGet(this, dependentKey) ? trueValue : falseValue;
  270. });
  271. };
  272. /**
  273. * A computed property that is equal to the logical 'and'
  274. * Takes any number of arguments
  275. * Returns true if all of them are truly, false - otherwise
  276. * App.*-keys are supported
  277. * <pre>
  278. * var o = Em.Object.create({
  279. * p1: true,
  280. * p2: true,
  281. * p3: true,
  282. * p4: Em.computed.and('p1', 'p2', 'p3')
  283. * });
  284. * console.log(o.get('p4')); // true
  285. * o.set('p1', false);
  286. * console.log(o.get('p4')); // false
  287. * </pre>
  288. *
  289. * @method and
  290. * @param {...string} dependentKeys
  291. * @returns {Ember.ComputedProperty}
  292. */
  293. computed.and = generateComputedWithProperties(function (properties) {
  294. var value;
  295. for (var key in properties) {
  296. value = !!properties[key];
  297. if (properties.hasOwnProperty(key) && !value) {
  298. return false;
  299. }
  300. }
  301. return value;
  302. });
  303. /**
  304. * A computed property that is equal to the logical 'or'
  305. * Takes any number of arguments
  306. * Returns true if at least one of them is truly, false - otherwise
  307. * App.*-keys are supported
  308. * <pre>
  309. * var o = Em.Object.create({
  310. * p1: false,
  311. * p2: false,
  312. * p3: false,
  313. * p4: Em.computed.or('p1', 'p2', 'p3')
  314. * });
  315. * console.log(o.get('p4')); // false
  316. * o.set('p1', true);
  317. * console.log(o.get('p4')); // true
  318. * </pre>
  319. *
  320. * @method or
  321. * @param {...string} dependentKeys
  322. * @returns {Ember.ComputedProperty}
  323. */
  324. computed.or = generateComputedWithProperties(function (properties) {
  325. var value;
  326. for (var key in properties) {
  327. value = !!properties[key];
  328. if (properties.hasOwnProperty(key) && value) {
  329. return value;
  330. }
  331. }
  332. return value;
  333. });
  334. /**
  335. * A computed property that returns sum on the dependent properties values
  336. * Takes any number of arguments
  337. * App.*-keys are supported
  338. * <pre>
  339. * var o = Em.Object.create({
  340. * p1: 1,
  341. * p2: 2,
  342. * p3: 3,
  343. * p4: Em.computed.sumProperties('p1', 'p2', 'p3')
  344. * });
  345. * console.log(o.get('p4')); // 6
  346. * o.set('p1', 2);
  347. * console.log(o.get('p4')); // 7
  348. * </pre>
  349. *
  350. * @method sumProperties
  351. * @param {...string} dependentKeys
  352. * @returns {Ember.ComputedProperty}
  353. */
  354. computed.sumProperties = generateComputedWithProperties(function (properties) {
  355. var sum = 0;
  356. for (var key in properties) {
  357. if (properties.hasOwnProperty(key)) {
  358. sum += Number(properties[key]);
  359. }
  360. }
  361. return sum;
  362. });
  363. /**
  364. * A computed property that returns true if dependent value is greater or equal to the needed value
  365. * App.*-keys are supported
  366. * <pre>
  367. * var o = Em.Object.create({
  368. * p1: 4,
  369. * p2: Em.computed.gte('p1', 1)
  370. * });
  371. * console.log(o.get('p2')); // true
  372. * o.set('p1', 4);
  373. * console.log(o.get('p2')); // true
  374. * o.set('p1', 5);
  375. * console.log(o.get('p2')); // false
  376. * </pre>
  377. *
  378. * @method gte
  379. * @param {string} dependentKey
  380. * @param {*} value
  381. * @returns {Ember.ComputedProperty}
  382. */
  383. computed.gte = function (dependentKey, value) {
  384. return computed(dependentKey, function () {
  385. return smartGet(this, dependentKey) >= value;
  386. });
  387. };
  388. /**
  389. * A computed property that returns true if first dependent property is greater or equal to the second dependent property
  390. * App.*-keys are supported
  391. * <pre>
  392. * var o = Em.Object.create({
  393. * p1: 4,
  394. * p2: 1,
  395. * p3: Em.computed.gteProperties('p1', 'p2')
  396. * });
  397. * console.log(o.get('p3')); // true
  398. * o.set('p2', 4);
  399. * console.log(o.get('p3')); // true
  400. * o.set('p2', 5);
  401. * console.log(o.get('p3')); // false
  402. * </pre>
  403. *
  404. * @method gteProperties
  405. * @param {string} dependentKey1
  406. * @param {string} dependentKey2
  407. * @returns {Ember.ComputedProperty}
  408. */
  409. computed.gteProperties = function (dependentKey1, dependentKey2) {
  410. return computed(dependentKey1, dependentKey2, function () {
  411. return smartGet(this, dependentKey1) >= smartGet(this, dependentKey2);
  412. });
  413. };
  414. /**
  415. * A computed property that returns true if dependent property is less or equal to the needed value
  416. * App.*-keys are supported
  417. * <pre>
  418. * var o = Em.Object.create({
  419. * p1: 4,
  420. * p2: Em.computed.lte('p1', 1)
  421. * });
  422. * console.log(o.get('p2')); // false
  423. * o.set('p1', 4);
  424. * console.log(o.get('p2')); // true
  425. * o.set('p1', 5);
  426. * console.log(o.get('p2')); // true
  427. * </pre>
  428. *
  429. * @method lte
  430. * @param {string} dependentKey
  431. * @param {*} value
  432. * @returns {Ember.ComputedProperty}
  433. */
  434. computed.lte = function (dependentKey, value) {
  435. return computed(dependentKey, function () {
  436. return smartGet(this, dependentKey) <= value;
  437. });
  438. };
  439. /**
  440. * A computed property that returns true if first dependent property is less or equal to the second dependent property
  441. * App.*-keys are supported
  442. * <pre>
  443. * var o = Em.Object.create({
  444. * p1: 4,
  445. * p2: 1,
  446. * p3: Em.computed.lteProperties('p1', 'p2')
  447. * });
  448. * console.log(o.get('p3')); // false
  449. * o.set('p2', 4);
  450. * console.log(o.get('p3')); // true
  451. * o.set('p2', 5);
  452. * console.log(o.get('p3')); // true
  453. * </pre>
  454. *
  455. * @method lteProperties
  456. * @param {string} dependentKey1
  457. * @param {string} dependentKey2
  458. * @returns {Ember.ComputedProperty}
  459. */
  460. computed.lteProperties = function (dependentKey1, dependentKey2) {
  461. return computed(dependentKey1, dependentKey2, function () {
  462. return smartGet(this, dependentKey1) <= smartGet(this, dependentKey2);
  463. });
  464. };
  465. /**
  466. * A computed property that returns true if dependent value is greater than the needed value
  467. * App.*-keys are supported
  468. * <pre>
  469. * var o = Em.Object.create({
  470. * p1: 4,
  471. * p2: Em.computed.gt('p1', 1)
  472. * });
  473. * console.log(o.get('p2')); // true
  474. * o.set('p1', 4);
  475. * console.log(o.get('p2')); // false
  476. * o.set('p1', 5);
  477. * console.log(o.get('p2')); // false
  478. * </pre>
  479. *
  480. * @method gt
  481. * @param {string} dependentKey
  482. * @param {*} value
  483. * @returns {Ember.ComputedProperty}
  484. */
  485. computed.gt = function (dependentKey, value) {
  486. return computed(dependentKey, function () {
  487. return smartGet(this, dependentKey) > value;
  488. });
  489. };
  490. /**
  491. * A computed property that returns true if first dependent property is greater than the second dependent property
  492. * App.*-keys are supported
  493. * <pre>
  494. * var o = Em.Object.create({
  495. * p1: 4,
  496. * p2: 1,
  497. * p3: Em.computed.gteProperties('p1', 'p2')
  498. * });
  499. * console.log(o.get('p3')); // true
  500. * o.set('p2', 4);
  501. * console.log(o.get('p3')); // false
  502. * o.set('p2', 5);
  503. * console.log(o.get('p3')); // false
  504. * </pre>
  505. *
  506. * @method gtProperties
  507. * @param {string} dependentKey1
  508. * @param {string} dependentKey2
  509. * @returns {Ember.ComputedProperty}
  510. */
  511. computed.gtProperties = function (dependentKey1, dependentKey2) {
  512. return computed(dependentKey1, dependentKey2, function () {
  513. return smartGet(this, dependentKey1) > smartGet(this, dependentKey2);
  514. });
  515. };
  516. /**
  517. * A computed property that returns true if dependent value is less than the needed value
  518. * App.*-keys are supported
  519. * <pre>
  520. * var o = Em.Object.create({
  521. * p1: 4,
  522. * p2: Em.computed.lt('p1', 1)
  523. * });
  524. * console.log(o.get('p2')); // false
  525. * o.set('p1', 4);
  526. * console.log(o.get('p2')); // false
  527. * o.set('p1', 5);
  528. * console.log(o.get('p2')); // true
  529. * </pre>
  530. *
  531. * @method lt
  532. * @param {string} dependentKey
  533. * @param {*} value
  534. * @returns {Ember.ComputedProperty}
  535. */
  536. computed.lt = function (dependentKey, value) {
  537. return computed(dependentKey, function () {
  538. return smartGet(this, dependentKey) < value;
  539. });
  540. };
  541. /**
  542. * A computed property that returns true if first dependent property is less than the second dependent property
  543. * App.*-keys are supported
  544. * <pre>
  545. * var o = Em.Object.create({
  546. * p1: 4,
  547. * p2: 1,
  548. * p3: Em.computed.ltProperties('p1', 'p2')
  549. * });
  550. * console.log(o.get('p3')); // false
  551. * o.set('p2', 4);
  552. * console.log(o.get('p3')); // false
  553. * o.set('p2', 5);
  554. * console.log(o.get('p3')); // true
  555. * </pre>
  556. *
  557. * @method gtProperties
  558. * @param {string} dependentKey1
  559. * @param {string} dependentKey2
  560. * @returns {Ember.ComputedProperty}
  561. */
  562. computed.ltProperties = function (dependentKey1, dependentKey2) {
  563. return computed(dependentKey1, dependentKey2, function () {
  564. return smartGet(this, dependentKey1) < smartGet(this, dependentKey2);
  565. });
  566. };
  567. /**
  568. * A computed property that returns true if dependent property is match to the needed regular expression
  569. * <pre>
  570. * var o = Em.Object.create({
  571. * p1: 'abc',
  572. * p2: Em.computed.match('p1', /^a/)
  573. * });
  574. * console.log(o.get('p2')); // true
  575. * o.set('p1', 'bc');
  576. * console.log(o.get('p2')); // false
  577. * </pre>
  578. *
  579. * @method match
  580. * @param {string} dependentKey
  581. * @param {RegExp} regexp
  582. * @returns {Ember.ComputedProperty}
  583. */
  584. computed.match = function (dependentKey, regexp) {
  585. return computed(dependentKey, function () {
  586. var value = get(this, dependentKey);
  587. if (!regexp) {
  588. return false;
  589. }
  590. return regexp.test(value);
  591. });
  592. };
  593. /**
  594. * A computed property that returns true of some collection's item has property with needed value
  595. * <pre>
  596. * var o = Em.Object.create({
  597. * p1: [{a: 1}, {a: 2}, {a: 3}],
  598. * p2: Em.computed.someBy('p1', 'a', 1)
  599. * });
  600. * console.log(o.get('p2')); // true
  601. * o.set('p1.0.a', 2);
  602. * console.log(o.get('p2')); // false
  603. * </pre>
  604. *
  605. * @method someBy
  606. * @param {string} collectionKey
  607. * @param {string} propertyName
  608. * @param {*} neededValue
  609. * @returns {Ember.ComputedProperty}
  610. */
  611. computed.someBy = function (collectionKey, propertyName, neededValue) {
  612. return computed(collectionKey + '.@each.' + propertyName, function () {
  613. var collection = smartGet(this, collectionKey);
  614. if (!collection) {
  615. return false;
  616. }
  617. return collection.someProperty(propertyName, neededValue);
  618. });
  619. };
  620. /**
  621. * A computed property that returns true of some collection's item has property with needed value
  622. * Needed value is stored in the another property
  623. * <pre>
  624. * var o = Em.Object.create({
  625. * p1: [{a: 1}, {a: 2}, {a: 3}],
  626. * p2: Em.computed.someByKey('p1', 'a', 'v1'),
  627. * v1: 1
  628. * });
  629. * console.log(o.get('p2')); // true
  630. * o.set('p1.0.a', 2);
  631. * console.log(o.get('p2')); // false
  632. * </pre>
  633. *
  634. * @method someByKey
  635. * @param {string} collectionKey
  636. * @param {string} propertyName
  637. * @param {string} neededValueKey
  638. * @returns {Ember.ComputedProperty}
  639. */
  640. computed.someByKey = function (collectionKey, propertyName, neededValueKey) {
  641. return computed(collectionKey + '.@each.' + propertyName, neededValueKey, function () {
  642. var collection = smartGet(this, collectionKey);
  643. if (!collection) {
  644. return false;
  645. }
  646. var neededValue = smartGet(this, neededValueKey);
  647. return collection.someProperty(propertyName, neededValue);
  648. });
  649. };
  650. /**
  651. * A computed property that returns true of all collection's items have property with needed value
  652. * <pre>
  653. * var o = Em.Object.create({
  654. * p1: [{a: 1}, {a: 1}, {a: 1}],
  655. * p2: Em.computed.everyBy('p1', 'a', 1)
  656. * });
  657. * console.log(o.get('p2')); // true
  658. * o.set('p1.0.a', 2);
  659. * console.log(o.get('p2')); // false
  660. * </pre>
  661. *
  662. * @method everyBy
  663. * @param {string} collectionKey
  664. * @param {string} propertyName
  665. * @param {*} neededValue
  666. * @returns {Ember.ComputedProperty}
  667. */
  668. computed.everyBy = function (collectionKey, propertyName, neededValue) {
  669. return computed(collectionKey + '.@each.' + propertyName, function () {
  670. var collection = smartGet(this, collectionKey);
  671. if (!collection) {
  672. return false;
  673. }
  674. return collection.everyProperty(propertyName, neededValue);
  675. });
  676. };
  677. /**
  678. * A computed property that returns true of all collection's items have property with needed value
  679. * Needed value is stored in the another property
  680. * <pre>
  681. * var o = Em.Object.create({
  682. * p1: [{a: 1}, {a: 1}, {a: 1}],
  683. * p2: Em.computed.everyByKey('p1', 'a', 'v1'),
  684. * v1: 1
  685. * });
  686. * console.log(o.get('p2')); // true
  687. * o.set('p1.0.a', 2);
  688. * console.log(o.get('p2')); // false
  689. * </pre>
  690. *
  691. * @method everyByKey
  692. * @param {string} collectionKey
  693. * @param {string} propertyName
  694. * @param {string} neededValueKey
  695. * @returns {Ember.ComputedProperty}
  696. */
  697. computed.everyByKey = function (collectionKey, propertyName, neededValueKey) {
  698. return computed(collectionKey + '.@each.' + propertyName, neededValueKey, function () {
  699. var collection = smartGet(this, collectionKey);
  700. if (!collection) {
  701. return false;
  702. }
  703. var neededValue = smartGet(this, neededValueKey);
  704. return collection.everyProperty(propertyName, neededValue);
  705. });
  706. };
  707. /**
  708. * A computed property that returns array with values of named property on all items in the collection
  709. * <pre>
  710. * var o = Em.Object.create({
  711. * p1: [{a: 1}, {a: 2}, {a: 3}],
  712. * p2: Em.computed.everyBy('p1', 'a')
  713. * });
  714. * console.log(o.get('p2')); // [1, 2, 3]
  715. * o.set('p1.0.a', 2);
  716. * console.log(o.get('p2')); // [2, 2, 3]
  717. * </pre>
  718. *
  719. * @method mapBy
  720. * @param {string} collectionKey
  721. * @param {string} propertyName
  722. * @returns {Ember.ComputedProperty}
  723. */
  724. computed.mapBy = function (collectionKey, propertyName) {
  725. return computed(collectionKey + '.@each.' + propertyName, function () {
  726. var collection = smartGet(this, collectionKey);
  727. if (!collection) {
  728. return [];
  729. }
  730. return collection.mapProperty(propertyName);
  731. });
  732. };
  733. /**
  734. * A computed property that returns array with collection's items that have needed property value
  735. * <pre>
  736. * var o = Em.Object.create({
  737. * p1: [{a: 1}, {a: 2}, {a: 3}],
  738. * p2: Em.computed.filterBy('p1', 'a', 2)
  739. * });
  740. * console.log(o.get('p2')); // [{a: 2}]
  741. * o.set('p1.0.a', 2);
  742. * console.log(o.get('p2')); // [{a: 2}, {a: 2}]
  743. * </pre>
  744. *
  745. * @method filterBy
  746. * @param {string} collectionKey
  747. * @param {string} propertyName
  748. * @param {*} neededValue
  749. * @returns {Ember.ComputedProperty}
  750. */
  751. computed.filterBy = function (collectionKey, propertyName, neededValue) {
  752. return computed(collectionKey + '.@each.' + propertyName, function () {
  753. var collection = smartGet(this, collectionKey);
  754. if (!collection) {
  755. return [];
  756. }
  757. return collection.filterProperty(propertyName, neededValue);
  758. });
  759. };
  760. /**
  761. * A computed property that returns array with collection's items that have needed property value
  762. * Needed value is stored in the another property
  763. *
  764. * <pre>
  765. * var o = Em.Object.create({
  766. * p1: [{a: 1}, {a: 2}, {a: 3}],
  767. * p2: Em.computed.filterByKey('p1', 'a', 'v1'),
  768. * v1: 2
  769. * });
  770. * console.log(o.get('p2')); // [{a: 2}]
  771. * o.set('p1.0.a', 2);
  772. * console.log(o.get('p2')); // [{a: 2}, {a: 2}]
  773. * </pre>
  774. *
  775. * @method filterByKey
  776. * @param {string} collectionKey
  777. * @param {string} propertyName
  778. * @param {string} neededValueKey
  779. * @returns {Ember.ComputedProperty}
  780. */
  781. computed.filterByKey = function (collectionKey, propertyName, neededValueKey) {
  782. return computed(collectionKey + '.@each.' + propertyName, neededValueKey, function () {
  783. var collection = smartGet(this, collectionKey);
  784. if (!collection) {
  785. return [];
  786. }
  787. var neededValue = smartGet(this, neededValueKey);
  788. return collection.filterProperty(propertyName, neededValue);
  789. });
  790. };
  791. /**
  792. * A computed property that returns first collection's item that has needed property value
  793. * <pre>
  794. * var o = Em.Object.create({
  795. * p1: [{a: 1, b: 1}, {a: 2, b: 2}, {a: 3, b: 3}],
  796. * p2: Em.computed.findBy('p1', 'a', 2)
  797. * });
  798. * console.log(o.get('p2')); // [{a: 2, b: 2}]
  799. * o.set('p1.0.a', 2);
  800. * console.log(o.get('p2')); // [{a: 2, b: 1}]
  801. * </pre>
  802. *
  803. * @method findBy
  804. * @param {string} collectionKey
  805. * @param {string} propertyName
  806. * @param {*} neededValue
  807. * @returns {Ember.ComputedProperty}
  808. */
  809. computed.findBy = function (collectionKey, propertyName, neededValue) {
  810. return computed(collectionKey + '.@each.' + propertyName, function () {
  811. var collection = smartGet(this, collectionKey);
  812. if (!collection) {
  813. return null;
  814. }
  815. return collection.findProperty(propertyName, neededValue);
  816. });
  817. };
  818. /**
  819. * A computed property that returns first collection's item that has needed property value
  820. * Needed value is stored in the another property
  821. * <pre>
  822. * var o = Em.Object.create({
  823. * p1: [{a: 1, b: 1}, {a: 2, b: 2}, {a: 3, b: 3}],
  824. * p2: Em.computed.findByKey('p1', 'a', 'v1'),
  825. * v1: 2
  826. * });
  827. * console.log(o.get('p2')); // [{a: 2, b: 2}]
  828. * o.set('p1.0.a', 2);
  829. * console.log(o.get('p2')); // [{a: 2, b: 1}]
  830. * </pre>
  831. *
  832. * @method findByKey
  833. * @param {string} collectionKey
  834. * @param {string} propertyName
  835. * @param {string} neededValueKey
  836. * @returns {Ember.ComputedProperty}
  837. */
  838. computed.findByKey = function (collectionKey, propertyName, neededValueKey) {
  839. return computed(collectionKey + '.@each.' + propertyName, neededValueKey, function () {
  840. var collection = smartGet(this, collectionKey);
  841. if (!collection) {
  842. return null;
  843. }
  844. var neededValue = smartGet(this, neededValueKey);
  845. return collection.findProperty(propertyName, neededValue);
  846. });
  847. };
  848. /**
  849. * A computed property that returns value equal to the dependent
  850. * Should be used as 'short-name' for deeply-nested values
  851. * App.*-keys are supported
  852. * <pre>
  853. * var o = Em.Object.create({
  854. * p1: {a: {b: {c: 2}}},
  855. * p2: Em.computed.alias('p1.a.b.c')
  856. * });
  857. * console.log(o.get('p2')); // 2
  858. * o.set('p1.a.b.c', 4);
  859. * console.log(o.get('p2')); // 4
  860. * </pre>
  861. *
  862. * @method alias
  863. * @param {string} dependentKey
  864. * @returns {Ember.ComputedProperty}
  865. */
  866. computed.alias = function (dependentKey) {
  867. return computed(dependentKey, function () {
  868. return smartGet(this, dependentKey);
  869. });
  870. };
  871. /**
  872. * A computed property that returns true if dependent property exists in the needed values
  873. * <pre>
  874. * var o = Em.Object.create({
  875. * p1: 2,
  876. * p2: Em.computed.existsIn('p1', [1, 2, 3])
  877. * });
  878. * console.log(o.get('p2')); // true
  879. * o.set('p1', 4);
  880. * console.log(o.get('p2')); // false
  881. * </pre>
  882. *
  883. * @method existsIn
  884. * @param {string} dependentKey
  885. * @param {array} neededValues
  886. * @returns {Ember.ComputedProperty}
  887. */
  888. computed.existsIn = function (dependentKey, neededValues) {
  889. return computed(dependentKey, function () {
  890. var value = smartGet(this, dependentKey);
  891. return makeArray(neededValues).contains(value);
  892. });
  893. };
  894. /**
  895. * A computed property that returns true if dependent property doesn't exist in the needed values
  896. * <pre>
  897. * var o = Em.Object.create({
  898. * p1: 2,
  899. * p2: Em.computed.notExistsIn('p1', [1, 2, 3])
  900. * });
  901. * console.log(o.get('p2')); // false
  902. * o.set('p1', 4);
  903. * console.log(o.get('p2')); // true
  904. * </pre>
  905. *
  906. * @method notExistsIn
  907. * @param {string} dependentKey
  908. * @param {array} neededValues
  909. * @returns {Ember.ComputedProperty}
  910. */
  911. computed.notExistsIn = function (dependentKey, neededValues) {
  912. return computed(dependentKey, function () {
  913. var value = smartGet(this, dependentKey);
  914. return !makeArray(neededValues).contains(value);
  915. });
  916. };
  917. /**
  918. * A computed property that returns result of calculation <code>(dependentProperty1/dependentProperty2 * 100)</code>
  919. * If accuracy is 0 (by default), result is rounded to integer
  920. * Otherwise - result is float with provided accuracy
  921. * App.*-keys are supported
  922. * <pre>
  923. * var o = Em.Object.create({
  924. * p1: 2,
  925. * p2: 4,
  926. * p3: Em.computed.percents('p1', 'p2')
  927. * });
  928. * console.log(o.get('p3')); // 50
  929. * o.set('p2', 5);
  930. * console.log(o.get('p3')); // 40
  931. * </pre>
  932. *
  933. * @method percents
  934. * @param {string} dependentKey1
  935. * @param {string} dependentKey2
  936. * @param {number} [accuracy=0]
  937. * @returns {Ember.ComputedProperty}
  938. */
  939. computed.percents = function (dependentKey1, dependentKey2, accuracy) {
  940. if (arguments.length < 3) {
  941. accuracy = 0;
  942. }
  943. return computed(dependentKey1, dependentKey2, function () {
  944. var v1 = Number(smartGet(this, dependentKey1));
  945. var v2 = Number(smartGet(this, dependentKey2));
  946. var result = v1 / v2 * 100;
  947. if (0 === accuracy) {
  948. return Math.round(result);
  949. }
  950. return parseFloat(result.toFixed(accuracy));
  951. });
  952. };
  953. /**
  954. * A computed property that returns result of <code>App.format.role</code> for dependent value
  955. * <pre>
  956. * var o = Em.Object.create({
  957. * p1: 'SECONDARY_NAMENODE',
  958. * p3: Em.computed.formatRole('p1', false)
  959. * });
  960. * console.log(o.get('p2')); // 'SNameNode'
  961. * o.set('p1', 'FLUME_HANDLER);
  962. * console.log(o.get('p2')); // 'Flume'
  963. * </pre>
  964. *
  965. * @method formatRole
  966. * @param {string} dependentKey
  967. * @param {boolean} isServiceRole
  968. * @returns {Ember.ComputedProperty}
  969. */
  970. computed.formatRole = function (dependentKey, isServiceRole) {
  971. return computed(dependentKey, function () {
  972. var value = get(this, dependentKey);
  973. return App.format.role(value, isServiceRole);
  974. });
  975. };
  976. /**
  977. * A computed property that returns sum of the named property in the each collection's item
  978. * <pre>
  979. * var o = Em.Object.create({
  980. * p1: [{a: 1}, {a: 2}, {a: 3}],
  981. * p2: Em.computed.sumBy('p1', 'a')
  982. * });
  983. * console.log(o.get('p2')); // 6
  984. * o.set('p1.0.a', 2);
  985. * console.log(o.get('p2')); // 7
  986. * </pre>
  987. *
  988. * @method sumBy
  989. * @param {string} collectionKey
  990. * @param {string} propertyName
  991. * @returns {Ember.ComputedProperty}
  992. */
  993. computed.sumBy = function (collectionKey, propertyName) {
  994. return computed(collectionKey + '.@each.' + propertyName, function () {
  995. var collection = smartGet(this, collectionKey);
  996. if (Em.isEmpty(collection)) {
  997. return 0;
  998. }
  999. var sum = 0;
  1000. collection.forEach(function (item) {
  1001. sum += Number(get(item, propertyName));
  1002. });
  1003. return sum;
  1004. });
  1005. };
  1006. /**
  1007. * A computed property that returns I18n-string formatted with dependent properties
  1008. * Takes at least one argument
  1009. * App.*-keys are supported
  1010. *
  1011. * @param {string} key key in the I18n-messages
  1012. * @param {...string} dependentKeys
  1013. * @method i18nFormat
  1014. * @returns {Ember.ComputedProperty}
  1015. */
  1016. computed.i18nFormat = generateComputedWithKey(function (key, dependentValues) {
  1017. var str = Em.I18n.t(key);
  1018. if (!str) {
  1019. return '';
  1020. }
  1021. return str.format.apply(str, dependentValues);
  1022. });
  1023. /**
  1024. * A computed property that returns string formatted with dependent properties
  1025. * Takes at least one argument
  1026. * App.*-keys are supported
  1027. * <pre>
  1028. * var o = Em.Object.create({
  1029. * p1: 'abc',
  1030. * p2: 'cba',
  1031. * p3: Em.computed.format('{0} => {1}', 'p1', 'p2')
  1032. * });
  1033. * console.log(o.get('p3')); // 'abc => cba'
  1034. * o.set('p1', 'aaa');
  1035. * console.log(o.get('p3')); // 'aaa => cba'
  1036. * </pre>
  1037. *
  1038. * @param {string} str string to format
  1039. * @param {...string} dependentKeys
  1040. * @method format
  1041. * @returns {Ember.ComputedProperty}
  1042. */
  1043. computed.format = generateComputedWithKey(function (str, dependentValues) {
  1044. if (!str) {
  1045. return '';
  1046. }
  1047. return str.format.apply(str, dependentValues);
  1048. });
  1049. /**
  1050. * A computed property that returns dependent values joined with separator
  1051. * Takes at least one argument
  1052. * App.*-keys are supported
  1053. * <pre>
  1054. * var o = Em.Object.create({
  1055. * p1: 'abc',
  1056. * p2: 'cba',
  1057. * p3: Em.computed.concat('|', 'p1', 'p2')
  1058. * });
  1059. * console.log(o.get('p3')); // 'abc|cba'
  1060. * o.set('p1', 'aaa');
  1061. * console.log(o.get('p3')); // 'aaa|cba'
  1062. * </pre>
  1063. *
  1064. * @param {string} separator
  1065. * @param {...string} dependentKeys
  1066. * @method concat
  1067. * @return {Ember.ComputedProperty}
  1068. */
  1069. computed.concat = generateComputedWithKey(function (separator, dependentValues) {
  1070. return dependentValues.join(separator);
  1071. });
  1072. /**
  1073. * A computed property that returns first not blank value from dependent values
  1074. * Based on <code>Ember.isBlank</code>
  1075. * Takes at least 1 argument
  1076. * Dependent values order affects the result
  1077. * App.*-keys are supported
  1078. * <pre>
  1079. * var o = Em.Object.create({
  1080. * p1: null,
  1081. * p2: '',
  1082. * p3: 'abc'
  1083. * p4: Em.computed.firstNotBlank('p1', 'p2', 'p3')
  1084. * });
  1085. * console.log(o.get('p4')); // 'abc'
  1086. * o.set('p1', 'aaa');
  1087. * console.log(o.get('p4')); // 'aaa'
  1088. * </pre>
  1089. *
  1090. * @param {...string} dependentKeys
  1091. * @method firstNotBlank
  1092. * @return {Ember.ComputedProperty}
  1093. */
  1094. computed.firstNotBlank = generateComputedWithValues(function (values) {
  1095. for (var i = 0; i < values.length; i++) {
  1096. if (!Em.isBlank(values[i])) {
  1097. return values[i];
  1098. }
  1099. }
  1100. return null;
  1101. });
  1102. /**
  1103. * A computed property that returns dependent value if it is truly or ('0'|0)
  1104. * Returns <code>'n/a'</code> otherwise
  1105. * App.*-keys are supported
  1106. * <pre>
  1107. * var o = Em.Object.create({
  1108. * p1: 0,
  1109. * p2: Em.computed.formatUnavailable('p1')
  1110. * });
  1111. * console.log(o.get('p2')); // 0
  1112. * o.set('p1', 12);
  1113. * console.log(o.get('p2')); // 12
  1114. * o.set('p1', 'some string');
  1115. * console.log(o.get('p2')); // 'n/a'
  1116. * </pre>
  1117. *
  1118. * @param {string} dependentKey
  1119. * @method formatUnavailable
  1120. * @returns {Ember.ComputedProperty}
  1121. */
  1122. computed.formatUnavailable = function(dependentKey) {
  1123. return computed(dependentKey, function () {
  1124. var value = smartGet(this, dependentKey);
  1125. return value || value == 0 ? value : Em.I18n.t('services.service.summary.notAvailable');
  1126. });
  1127. };
  1128. /**
  1129. * A computed property that returns one of provided values basing on dependent value
  1130. * If dependent value is 0, <code>zeroMsg</code> is returned
  1131. * If dependent value is 1, <code>oneMsg</code> is returned
  1132. * If dependent value is greater than 1, <code>manyMsg</code> is returned
  1133. * App.*-keys are supported
  1134. * <pre>
  1135. * var o = Em.Object.create({
  1136. * p1: 0,
  1137. * p2: Em.computed.formatUnavailable('p1', '0msg', '1msg', '2+msg')
  1138. * });
  1139. * console.log(o.get('p2')); // '0msg'
  1140. * o.set('p1', 1);
  1141. * console.log(o.get('p2')); // '1msg'
  1142. * o.set('p1', 100500);
  1143. * console.log(o.get('p2')); // '2+msg'
  1144. * </pre>
  1145. *
  1146. * @param {string} dependentKey
  1147. * @param {string} zeroMsg
  1148. * @param {string} oneMsg
  1149. * @param {string} manyMsg
  1150. * @returns {Ember.ComputedProperty}
  1151. * @method countBasedMessage
  1152. */
  1153. computed.countBasedMessage = function (dependentKey, zeroMsg, oneMsg, manyMsg) {
  1154. return computed(dependentKey, function () {
  1155. var value = Number(smartGet(this, dependentKey));
  1156. if (value === 0) {
  1157. return zeroMsg;
  1158. }
  1159. if (value > 1) {
  1160. return manyMsg;
  1161. }
  1162. return oneMsg;
  1163. });
  1164. };
  1165. /**
  1166. * A computed property that returns property value according to the property key and object key
  1167. * App.*-keys are supported
  1168. * <pre>
  1169. * var o = Em.Object.create({
  1170. * p1: {a: 1, b: 2, c: 3},
  1171. * p2: 'a',
  1172. * p3: Em.computed.getByKey('p1', 'p2')
  1173. * });
  1174. * console.log(o.get('p3')); // 1
  1175. * o.set('p2', 'b');
  1176. * console.log(o.get('p3')); // 2
  1177. * o.set('p2', 'c');
  1178. * console.log(o.get('p3')); // 3
  1179. * </pre>
  1180. *
  1181. * With `defaultValue`
  1182. * <pre>
  1183. * var o = Em.Object.create({
  1184. * p1: {a: 1, b: 2, c: 3},
  1185. * p2: 'd',
  1186. * p3: Em.computed.getByKey('p1', 'p2', 100500)
  1187. * });
  1188. * console.log(o.get('p3')); // 100500 - default value is returned, because there is no key `d` in the `p1`
  1189. * </pre>
  1190. * <b>IMPORTANT!</b> This CP <b>SHOULD NOT</b> be used with for object with values equal to the views (like <code>{a: App.MyViewA, b: App.MyViewB}</code>)
  1191. * This restriction exists because views may be undefined on the moment when this CP is calculated (files are not `required` yet)
  1192. *
  1193. * @param {string} objectKey
  1194. * @param {string} propertyKey
  1195. * @param {*} [defaultValue]
  1196. * @returns {Ember.ComputedProperty}
  1197. */
  1198. computed.getByKey = function (objectKey, propertyKey, defaultValue) {
  1199. return computed(objectKey, propertyKey, function () {
  1200. var object = smartGet(this, objectKey);
  1201. var property = smartGet(this, propertyKey);
  1202. if (!object) {
  1203. return null;
  1204. }
  1205. return object.hasOwnProperty(property) ? object[property] : defaultValue;
  1206. });
  1207. }
  1208. /**
  1209. * A computed property that returns dependent value truncated to the `reduceTo`-size if its length is greater than `maxLength`
  1210. * Truncated part may be replaced with `replacer` if it's provided ('...' by default)
  1211. * <pre>
  1212. * var o = Em.Object.create({
  1213. * p1: Em.computed.truncate('p2', 8, 5, '###'),
  1214. * p2: 'some string',
  1215. * p3: Em.computed.truncate('p2', 8, 5)
  1216. * });
  1217. * console.log(o.get('p1')); // 'some ###'
  1218. * console.log(o.get('p3')); // 'some ...'
  1219. * o.set('p2', '123456789');
  1220. * console.log(o.get('p1')); // '12345###'
  1221. * console.log(o.get('p3')); // '12345...'
  1222. * </pre>
  1223. *
  1224. * @param {string} dependentKey
  1225. * @param {number} maxLength
  1226. * @param {number} reduceTo
  1227. * @param {string} [replacer] default - '...'
  1228. * @returns {Ember.ComputedProperty}
  1229. */
  1230. computed.truncate = function (dependentKey, maxLength, reduceTo, replacer) {
  1231. Em.assert('`reduceTo` should be <=`maxLength`', reduceTo <= maxLength);
  1232. var _replacer = arguments.length > 3 ? replacer : '...';
  1233. return computed(dependentKey, function () {
  1234. var value = smartGet(this, dependentKey) || '';
  1235. if (value.length > maxLength) {
  1236. return value.substr(0, reduceTo) + _replacer;
  1237. }
  1238. return value;
  1239. });
  1240. }