├── .editorconfig ├── .ember-cli ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .travis.yml ├── .watchmanconfig ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── addon └── index.js ├── app ├── .gitkeep └── initializers │ └── sort-by.js ├── config ├── ember-try.js └── environment.js ├── ember-cli-build.js ├── index.js ├── package.json ├── testem.js ├── tests ├── .eslintrc.js ├── dummy │ ├── app │ │ ├── app.js │ │ ├── components │ │ │ └── .gitkeep │ │ ├── controllers │ │ │ └── .gitkeep │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── index.html │ │ ├── models │ │ │ └── .gitkeep │ │ ├── resolver.js │ │ ├── router.js │ │ ├── routes │ │ │ └── .gitkeep │ │ ├── styles │ │ │ └── app.css │ │ └── templates │ │ │ ├── application.hbs │ │ │ └── components │ │ │ └── .gitkeep │ ├── config │ │ ├── environment.js │ │ └── targets.js │ └── public │ │ ├── crossdomain.xml │ │ └── robots.txt ├── helpers │ ├── destroy-app.js │ ├── module-for-acceptance.js │ ├── resolver.js │ └── start-app.js ├── index.html ├── test-helper.js └── unit │ └── computed-sortby-test.js ├── vendor └── .gitkeep └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.hbs] 17 | insert_final_newline = false 18 | 19 | [*.{diff,md}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2017, 5 | sourceType: 'module' 6 | }, 7 | extends: 'eslint:recommended', 8 | env: { 9 | browser: true 10 | }, 11 | rules: { 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | /coverage/* 15 | /libpeerconnection.log 16 | npm-debug.log* 17 | testem.log 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /bower_components 2 | /config/ember-try.js 3 | /dist 4 | /tests 5 | /tmp 6 | **/.gitkeep 7 | .bowerrc 8 | .editorconfig 9 | .ember-cli 10 | .gitignore 11 | .eslintrc.js 12 | .watchmanconfig 13 | .travis.yml 14 | bower.json 15 | ember-cli-build.js 16 | testem.js 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | - "6" 5 | 6 | sudo: false 7 | 8 | cache: 9 | directories: 10 | - $HOME/.npm 11 | 12 | env: 13 | # we recommend testing LTS's and latest stable release (bonus points to beta/canary) 14 | - EMBER_TRY_SCENARIO=ember-lts-2.4 15 | - EMBER_TRY_SCENARIO=ember-lts-2.8 16 | - EMBER_TRY_SCENARIO=ember-release 17 | - EMBER_TRY_SCENARIO=ember-beta 18 | - EMBER_TRY_SCENARIO=ember-canary 19 | - EMBER_TRY_SCENARIO=ember-default 20 | 21 | matrix: 22 | fast_finish: true 23 | allow_failures: 24 | - env: EMBER_TRY_SCENARIO=ember-canary 25 | 26 | before_install: 27 | - npm config set spin false 28 | - npm install -g phantomjs-prebuilt 29 | - phantomjs --version 30 | 31 | install: 32 | - npm install 33 | 34 | 35 | script: 36 | # Usually, it's ok to finish the test scenario without reverting 37 | # to the addon's original dependency state, skipping "cleanup". 38 | - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO test --skip-cleanup 39 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ember-computed-sortby Changelog 2 | 3 | ### 0.1.0 (May 4th, 2017) 4 | 5 | - [#3](https://github.com/workmanw/ember-computed-sortby/pull/3) Modernized the addon, upgrading structure and packages. 6 | 7 | ### 0.0.4 (May 4th, 2017) 8 | 9 | - [#2](https://github.com/workmanw/ember-computed-sortby/pull/2) Fixed a bug that was exposed by Ember 2.13. 10 | 11 | ### 0.0.3 (September 14th, 2015) 12 | 13 | - [3ee219085](https://github.com/workmanw/ember-computed-sortby/commit/3ee219085) Removed `sortDefinition` array syntax. Use additional arguments when defining the macro. 14 | 15 | ### 0.0.2 (September 11th, 2015) 16 | 17 | - Initial release 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ember-computed-sortby 2 | 3 | Addon to make sorting a little easier for Ember.js when the sort order is immutable. This addon was originally a proof of concept for [emberjs/rfcs#87](https://github.com/emberjs/rfcs/pull/87). However that RFC was rejected, so this will continue to live on as an addon. 4 | 5 | ## Documentation 6 | 7 | A computed property which returns a new sorted array of content from the 8 | a dependent array. The sort order is defined by the second, and any subsequent, 9 | string arguments. Adding a suffix of ':desc' to any of those string arguments 10 | will cause that order to be applied as descending. 11 | 12 | Example: 13 | 14 | ```javascript 15 | import sortBy from 'ember-computed-sortby'; 16 | 17 | let ToDoList = Ember.Object.extend({ 18 | // using standard ascending sort 19 | sortedTodos: sortBy('todos', 'name'), 20 | 21 | // using descending sort 22 | sortedTodosDesc: sortBy('todos', 'name:desc'), 23 | 24 | // using secondary sort 25 | sortedPriority: sortBy('todos', 'priority', 'name') 26 | }); 27 | 28 | let todoList = ToDoList.create({todos: [ 29 | { name: 'Unit Test', priority: 2 }, 30 | { name: 'Documentation', priority: 3 }, 31 | { name: 'Integration Test', priority: 2 }, 32 | { name: 'Release', priority: 1 } 33 | ]}); 34 | 35 | todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name: 'Integration Test', priority: 2 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] 36 | todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name: 'Integration Test', priority: 2 }, { name:'Documentation', priority:3 }] 37 | todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name: 'Integration Test', priority: 2 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] 38 | ``` 39 | Method documentation: 40 | ``` 41 | @method sort 42 | @for Ember.computed 43 | @param {String} itemsKey 44 | @param {String} property name(s) to sort on. Append ':desc' to trigger sort to be applied as descending. 45 | @return {Ember.ComputedProperty} computes a new sorted array based on the sort property array 46 | @public 47 | ``` 48 | 49 | ## Installing this addon 50 | 51 | From within your Ember CLI project directory: 52 | ``` 53 | ember install ember-computed-sortby 54 | ``` 55 | 56 | ## Running Tests 57 | 58 | ### Setup 59 | 60 | * `git clone` this repository 61 | * `yarn install` 62 | 63 | ### Testing 64 | 65 | * `ember test` 66 | * `ember test --server` 67 | -------------------------------------------------------------------------------- /addon/index.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | const { assert, get, compare, computed } = Ember; 4 | const a_slice = Array.prototype.slice; 5 | 6 | 7 | /** 8 | A computed property which returns a new sorted array of content from the 9 | a dependent array. The sort order is defined by the second, and any subsequent, 10 | string arguments. Adding a suffix of ':desc' to any of those string arguments 11 | will cause that order to be applied as descending. 12 | 13 | Example: 14 | 15 | ```javascript 16 | import sortBy from 'ember-computed-sortby'; 17 | 18 | let ToDoList = Ember.Object.extend({ 19 | // using standard ascending sort 20 | sortedTodos: sortBy('todos', 'name'), 21 | 22 | // using descending sort 23 | sortedTodosDesc: sortBy('todos', 'name:desc'), 24 | 25 | // using secondary sort 26 | sortedPriority: sortBy('todos', 'priority', 'name') 27 | }); 28 | 29 | let todoList = ToDoList.create({todos: [ 30 | { name: 'Unit Test', priority: 2 }, 31 | { name: 'Documentation', priority: 3 }, 32 | { name: 'Integration Test', priority: 2 }, 33 | { name: 'Release', priority: 1 } 34 | ]}); 35 | 36 | todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name: 'Integration Test', priority: 2 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] 37 | todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name: 'Integration Test', priority: 2 }, { name:'Documentation', priority:3 }] 38 | todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name: 'Integration Test', priority: 2 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] 39 | ``` 40 | 41 | @method sort 42 | @for Ember.computed 43 | @param {String} itemsKey 44 | @param {String} property name(s) to sort on. Append ':desc' to trigger sort to be applied as descending. 45 | @return {Ember.ComputedProperty} computes a new sorted array based on the sort property array 46 | @public 47 | */ 48 | export default function(/*itemsKey, sortDefinitions*/) { 49 | let sortDefinitions = a_slice.call(arguments); 50 | let itemsKey = sortDefinitions.shift(0); 51 | 52 | assert('Ember.computed.sortBy expects one or more string arguments provided as the sort definition.', sortDefinitions.length > 0); 53 | sortDefinitions.forEach(s => { 54 | assert('Ember.computed.sortBy expects one or more string arguments provided as the sort definition.', typeof s === 'string'); 55 | }); 56 | 57 | // Split out the sort definitions 58 | sortDefinitions = sortDefinitions.map(p => { 59 | let [prop, direction] = p.split(':'); 60 | direction = direction || 'asc'; 61 | return [prop, direction]; 62 | }); 63 | 64 | // Map out the dependantKeys for the computed macro 65 | let args = sortDefinitions.map(sortDefinition => { 66 | let prop = sortDefinition[0]; 67 | return `${itemsKey}.@each.${prop}`; 68 | }); 69 | 70 | // Push in the actual sorting function 71 | args.push(function() { 72 | let items = itemsKey === '@this' ? this : get(this, itemsKey); 73 | if (items === null || typeof items !== 'object') { return Ember.A(); } 74 | 75 | return Ember.A(items.slice().sort((itemA, itemB) => { 76 | for (let i = 0; i < sortDefinitions.length; ++i) { 77 | let [prop, direction] = sortDefinitions[i]; 78 | let result = compare(get(itemA, prop), get(itemB, prop)); 79 | if (result !== 0) { 80 | return (direction === 'desc') ? (-1 * result) : result; 81 | } 82 | } 83 | return 0; 84 | })); 85 | }); 86 | 87 | return computed.apply(null, args).readOnly(); 88 | } 89 | -------------------------------------------------------------------------------- /app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/app/.gitkeep -------------------------------------------------------------------------------- /app/initializers/sort-by.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import sortBy from 'ember-computed-sortby'; 3 | 4 | export default { 5 | name: 'sortBy', 6 | initialize: function() { 7 | Ember.computed.sortBy = function() { 8 | Ember.deprecate('Using `Ember.computed.sortBy` is deprecated. Instead, import it directly using `import sortBy from \'ember-computed-sortby\'`.', false, { 9 | id: 'ember-computed-sortby.global-import', 10 | until: '1.0.0' 11 | }); 12 | return sortBy.apply(null, arguments); 13 | }; 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | scenarios: [ 4 | { 5 | name: 'ember-lts-2.4', 6 | bower: { 7 | dependencies: { 8 | 'ember': 'components/ember#lts-2-4' 9 | }, 10 | resolutions: { 11 | 'ember': 'lts-2-4' 12 | } 13 | }, 14 | npm: { 15 | devDependencies: { 16 | 'ember-source': null 17 | } 18 | } 19 | }, 20 | { 21 | name: 'ember-lts-2.8', 22 | bower: { 23 | dependencies: { 24 | 'ember': 'components/ember#lts-2-8' 25 | }, 26 | resolutions: { 27 | 'ember': 'lts-2-8' 28 | } 29 | }, 30 | npm: { 31 | devDependencies: { 32 | 'ember-source': null 33 | } 34 | } 35 | }, 36 | { 37 | name: 'ember-release', 38 | bower: { 39 | dependencies: { 40 | 'ember': 'components/ember#release' 41 | }, 42 | resolutions: { 43 | 'ember': 'release' 44 | } 45 | }, 46 | npm: { 47 | devDependencies: { 48 | 'ember-source': null 49 | } 50 | } 51 | }, 52 | { 53 | name: 'ember-beta', 54 | bower: { 55 | dependencies: { 56 | 'ember': 'components/ember#beta' 57 | }, 58 | resolutions: { 59 | 'ember': 'beta' 60 | } 61 | }, 62 | npm: { 63 | devDependencies: { 64 | 'ember-source': null 65 | } 66 | } 67 | }, 68 | { 69 | name: 'ember-canary', 70 | bower: { 71 | dependencies: { 72 | 'ember': 'components/ember#canary' 73 | }, 74 | resolutions: { 75 | 'ember': 'canary' 76 | } 77 | }, 78 | npm: { 79 | devDependencies: { 80 | 'ember-source': null 81 | } 82 | } 83 | }, 84 | { 85 | name: 'ember-default', 86 | npm: { 87 | devDependencies: {} 88 | } 89 | } 90 | ] 91 | }; 92 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = function(/* environment, appConfig */) { 5 | return { }; 6 | }; 7 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 3 | 4 | module.exports = function(defaults) { 5 | var app = new EmberAddon(defaults, { 6 | // Add options here 7 | }); 8 | 9 | /* 10 | This build file specifies the options for the dummy test app of this 11 | addon, located in `/tests/dummy` 12 | This build file does *not* influence how the addon or the app using it 13 | behave. You most likely want to be modifying `./index.js` or app's build file 14 | */ 15 | 16 | return app.toTree(); 17 | }; 18 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = { 5 | name: 'ember-computed-sortby' 6 | }; 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-computed-sortby", 3 | "version": "0.1.0", 4 | "description": "Computed property implementation of `Ember.Array.sortBy`.", 5 | "keywords": [ 6 | "ember-addon", 7 | "ember computed" 8 | ], 9 | "license": "MIT", 10 | "author": "", 11 | "directories": { 12 | "doc": "doc", 13 | "test": "tests" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/workmanw/ember-computed-sortby.git" 18 | }, 19 | "scripts": { 20 | "build": "ember build", 21 | "start": "ember server", 22 | "test": "ember try:each" 23 | }, 24 | "dependencies": { 25 | "ember-cli-babel": "^6.0.0" 26 | }, 27 | "devDependencies": { 28 | "broccoli-asset-rev": "^2.4.5", 29 | "ember-cli": "~2.13.0", 30 | "ember-cli-dependency-checker": "^1.3.0", 31 | "ember-cli-eslint": "^3.0.0", 32 | "ember-cli-htmlbars": "^1.1.1", 33 | "ember-cli-htmlbars-inline-precompile": "^0.4.0", 34 | "ember-cli-inject-live-reload": "^1.4.1", 35 | "ember-cli-qunit": "^4.0.0-beta.1", 36 | "ember-cli-shims": "^1.1.0", 37 | "ember-cli-uglify": "^1.2.0", 38 | "ember-disable-prototype-extensions": "^1.1.0", 39 | "ember-load-initializers": "^1.0.0", 40 | "ember-resolver": "^4.0.0", 41 | "ember-source": "~2.13.0", 42 | "loader.js": "^4.2.3" 43 | }, 44 | "engines": { 45 | "node": ">= 4" 46 | }, 47 | "ember-addon": { 48 | "configPath": "tests/dummy/config" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | "test_page": "tests/index.html?hidepassed", 4 | "disable_watching": true, 5 | "launch_in_ci": [ 6 | "PhantomJS" 7 | ], 8 | "launch_in_dev": [ 9 | "PhantomJS", 10 | "Chrome" 11 | ] 12 | }; 13 | -------------------------------------------------------------------------------- /tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | embertest: true 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Resolver from './resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from './config/environment'; 5 | 6 | let App; 7 | 8 | Ember.MODEL_FACTORY_INJECTIONS = true; 9 | 10 | App = Ember.Application.extend({ 11 | modulePrefix: config.modulePrefix, 12 | podModulePrefix: config.podModulePrefix, 13 | Resolver 14 | }); 15 | 16 | loadInitializers(App, config.modulePrefix); 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/tests/dummy/app/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/tests/dummy/app/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/tests/dummy/app/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | 12 | 13 | 14 | 15 | {{content-for "head-footer"}} 16 | 17 | 18 | {{content-for "body"}} 19 | 20 | 21 | 22 | 23 | {{content-for "body-footer"}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/tests/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember-resolver'; 2 | 3 | export default Resolver; 4 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from './config/environment'; 3 | 4 | const Router = Ember.Router.extend({ 5 | location: config.locationType, 6 | rootURL: config.rootURL 7 | }); 8 | 9 | Router.map(function() { 10 | }); 11 | 12 | export default Router; 13 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/tests/dummy/app/routes/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/tests/dummy/app/styles/app.css -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | {{!-- The following component displays Ember's default welcome message. --}} 2 | {{welcome-page}} 3 | {{!-- Feel free to remove this! --}} 4 | 5 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/tests/dummy/app/templates/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | module.exports = function(environment) { 4 | var ENV = { 5 | modulePrefix: 'dummy', 6 | environment: environment, 7 | rootURL: '/', 8 | locationType: 'auto', 9 | EmberENV: { 10 | FEATURES: { 11 | // Here you can enable experimental features on an ember canary build 12 | // e.g. 'with-controller': true 13 | }, 14 | EXTEND_PROTOTYPES: { 15 | // Prevent Ember Data from overriding Date.parse. 16 | Date: false 17 | } 18 | }, 19 | 20 | APP: { 21 | // Here you can pass flags/options to your application instance 22 | // when it is created 23 | } 24 | }; 25 | 26 | if (environment === 'development') { 27 | // ENV.APP.LOG_RESOLVER = true; 28 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 29 | // ENV.APP.LOG_TRANSITIONS = true; 30 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 31 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 32 | } 33 | 34 | if (environment === 'test') { 35 | // Testem prefers this... 36 | ENV.locationType = 'none'; 37 | 38 | // keep test console output quieter 39 | ENV.APP.LOG_ACTIVE_GENERATION = false; 40 | ENV.APP.LOG_VIEW_LOOKUPS = false; 41 | 42 | ENV.APP.rootElement = '#ember-testing'; 43 | } 44 | 45 | if (environment === 'production') { 46 | 47 | } 48 | 49 | return ENV; 50 | }; 51 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | module.exports = { 4 | browsers: [ 5 | 'ie 9', 6 | 'last 1 Chrome versions', 7 | 'last 1 Firefox versions', 8 | 'last 1 Safari versions' 9 | ] 10 | }; 11 | -------------------------------------------------------------------------------- /tests/dummy/public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/destroy-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default function destroyApp(application) { 4 | Ember.run(application, 'destroy'); 5 | } 6 | -------------------------------------------------------------------------------- /tests/helpers/module-for-acceptance.js: -------------------------------------------------------------------------------- 1 | import { module } from 'qunit'; 2 | import Ember from 'ember'; 3 | import startApp from '../helpers/start-app'; 4 | import destroyApp from '../helpers/destroy-app'; 5 | 6 | const { RSVP: { Promise } } = Ember; 7 | 8 | export default function(name, options = {}) { 9 | module(name, { 10 | beforeEach() { 11 | this.application = startApp(); 12 | 13 | if (options.beforeEach) { 14 | return options.beforeEach.apply(this, arguments); 15 | } 16 | }, 17 | 18 | afterEach() { 19 | let afterEach = options.afterEach && options.afterEach.apply(this, arguments); 20 | return Promise.resolve(afterEach).then(() => destroyApp(this.application)); 21 | } 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from '../../resolver'; 2 | import config from '../../config/environment'; 3 | 4 | const resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /tests/helpers/start-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Application from '../../app'; 3 | import config from '../../config/environment'; 4 | 5 | export default function startApp(attrs) { 6 | let attributes = Ember.merge({}, config.APP); 7 | attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; 8 | 9 | return Ember.run(() => { 10 | let application = Application.create(attributes); 11 | application.setupForTesting(); 12 | application.injectTestHelpers(); 13 | return application; 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy Tests 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | {{content-for "test-head"}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for "head-footer"}} 18 | {{content-for "test-head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | {{content-for "test-body"}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {{content-for "body-footer"}} 31 | {{content-for "test-body-footer"}} 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import resolver from './helpers/resolver'; 2 | import { 3 | setResolver 4 | } from 'ember-qunit'; 5 | import { start } from 'ember-cli-qunit'; 6 | 7 | setResolver(resolver); 8 | start(); 9 | -------------------------------------------------------------------------------- /tests/unit/computed-sortby-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import Ember from 'ember'; 3 | import sortBy from 'ember-computed-sortby'; 4 | 5 | const { set, isArray } = Ember; 6 | 7 | module('sortBy', { 8 | beforeEach() { 9 | this.obj = Ember.Object.extend({ 10 | sortedFnameUsers: sortBy('users', 'fname'), 11 | sortedLnameUsers: sortBy('users', 'lname:desc'), 12 | sortedLnameUsers2: sortBy('users', 'lname:asc'), 13 | lnameThenOldest: sortBy('users', 'lname:desc', 'age') 14 | }).create({ 15 | users: Ember.A([ 16 | { fname: 'Jaime', lname: 'Lannister', age: 34 }, 17 | { fname: 'Robb', lname: 'Stark', age: 16 }, 18 | { fname: 'Cersei', lname: 'Lannister', age: 32 }, 19 | { fname: 'Bran', lname: 'Stark', age: 8 } 20 | ]) 21 | }); 22 | }, 23 | afterEach() { 24 | Ember.run(this.obj, 'destroy'); 25 | } 26 | }); 27 | 28 | test('Single sort string property defaults to asc', function(assert) { 29 | assert.deepEqual(this.obj.get('sortedFnameUsers').mapBy('fname'), ['Bran', 'Cersei', 'Jaime', 'Robb'], 'list is sorted correctly'); 30 | 31 | this.obj.set('users.firstObject.fname', 'Tyrion'); 32 | 33 | assert.deepEqual(this.obj.get('sortedFnameUsers').mapBy('fname'), ['Bran', 'Cersei', 'Robb', 'Tyrion'], 'updating sort property resorts the list'); 34 | }); 35 | 36 | test('Single sort string property works with desc', function(assert) { 37 | assert.deepEqual(this.obj.get('sortedLnameUsers').mapBy('lname'), ['Stark', 'Stark', 'Lannister', 'Lannister'], 'list is sorted correctly'); 38 | 39 | this.obj.set('users.lastObject.lname', 'Baratheon'); 40 | 41 | assert.deepEqual(this.obj.get('sortedLnameUsers').mapBy('lname'), ['Stark', 'Lannister', 'Lannister', 'Baratheon'], 'updating sort property resorts the list'); 42 | }); 43 | 44 | test('Single valued array property', function(assert) { 45 | assert.deepEqual(this.obj.get('sortedLnameUsers2').mapBy('lname'), ['Lannister', 'Lannister', 'Stark', 'Stark'], 'list is sorted correctly'); 46 | 47 | this.obj.set('users.firstObject.lname', 'Baratheon'); 48 | 49 | assert.deepEqual(this.obj.get('sortedLnameUsers2').mapBy('lname'), ['Baratheon', 'Lannister', 'Stark', 'Stark'], 'updating sort property resorts the list'); 50 | }); 51 | 52 | test('Multi valued array property', function(assert) { 53 | assert.deepEqual(this.obj.get('lnameThenOldest').mapBy('fname'), ['Bran', 'Robb', 'Cersei', 'Jaime'], 'list is sorted correctly'); 54 | 55 | var jamie = this.obj.get('users').objectAt(0); 56 | set(jamie, 'age', 26); 57 | 58 | assert.deepEqual(this.obj.get('lnameThenOldest').mapBy('fname'), ['Bran', 'Robb', 'Jaime', 'Cersei'], 'updating the secondary sort property resorts list'); 59 | 60 | var robb = this.obj.get('users').objectAt(1); 61 | set(robb, 'lname', 'Baratheon'); 62 | 63 | assert.deepEqual(this.obj.get('lnameThenOldest').mapBy('fname'), ['Bran', 'Jaime', 'Cersei', 'Robb'], 'updating the primary sort property resorts list'); 64 | }); 65 | 66 | test('Add / Remove items from the sorted array', function(assert) { 67 | assert.deepEqual(this.obj.get('sortedFnameUsers').mapBy('fname'), ['Bran', 'Cersei', 'Jaime', 'Robb'], 'list is sorted correctly'); 68 | assert.deepEqual(this.obj.get('lnameThenOldest').mapBy('fname'), ['Bran', 'Robb', 'Cersei', 'Jaime'], 'list is sorted correctly'); 69 | 70 | this.obj.get('users').pushObject({ fname: 'Joffrey', lname: 'Baratheon', age: 15 }); 71 | this.obj.get('users').pushObject({ fname: 'Ned', lname: 'Stark', age: 54 }); 72 | 73 | assert.deepEqual(this.obj.get('sortedFnameUsers').mapBy('fname'), ['Bran', 'Cersei', 'Jaime', 'Joffrey', 'Ned', 'Robb'], 'adding items to the list should have trigger resort'); 74 | assert.deepEqual(this.obj.get('lnameThenOldest').mapBy('fname'), ['Bran', 'Robb', 'Ned', 'Cersei', 'Jaime', 'Joffrey'], 'adding items to the list should have trigger resort'); 75 | 76 | this.obj.get('users').removeAt(1); 77 | this.obj.get('users').removeAt(1); 78 | 79 | assert.deepEqual(this.obj.get('sortedFnameUsers').mapBy('fname'), ['Bran', 'Jaime', 'Joffrey', 'Ned'], 'removing items to the list should have trigger resort'); 80 | assert.deepEqual(this.obj.get('lnameThenOldest').mapBy('fname'), ['Bran', 'Ned', 'Jaime', 'Joffrey'], 'removing items to the list should have trigger resort'); 81 | }); 82 | 83 | test('Change the entire sorted array', function(assert) { 84 | assert.deepEqual(this.obj.get('sortedFnameUsers').mapBy('fname'), ['Bran', 'Cersei', 'Jaime', 'Robb'], 'list is sorted correctly'); 85 | 86 | this.obj.set('users', [ 87 | { fname: 'Daenerys', lname: 'Targaryen', age: 23 }, 88 | { fname: 'Margaery', lname: 'Tyrell', age: 25 }, 89 | { fname: 'Jon', lname: 'Snow', age: 28 } 90 | ]); 91 | 92 | assert.deepEqual(this.obj.get('sortedFnameUsers').mapBy('fname'), ['Daenerys', 'Jon', 'Margaery'], 'list should resort after being completely swapped'); 93 | }); 94 | 95 | test('Check null and empty sorting array', function(assert) { 96 | this.obj.set('users', []); 97 | var sortedList = this.obj.get('sortedFnameUsers'); 98 | assert.ok((isArray(sortedList) && sortedList.length === 0), 'an empty items list should return an empty array'); 99 | 100 | this.obj.set('users', null); 101 | sortedList = this.obj.get('sortedFnameUsers'); 102 | assert.ok((isArray(sortedList) && sortedList.length === 0), 'a null list should return an empty array'); 103 | }); 104 | 105 | test('Bad args', function(assert) { 106 | assert.throws(function() { 107 | Ember.Object.extend({ 108 | sortedUsers: sortBy('users') 109 | }).create().get('sortedUsers'); 110 | }, 'Asserted when second argument was missing.'); 111 | 112 | assert.throws(function() { 113 | Ember.Object.extend({ 114 | sortedUsers: sortBy('users', function() {}) 115 | }).create().get('sortedUsers'); 116 | }, 'Asserted when second argument was incorrect.'); 117 | 118 | assert.throws(function() { 119 | Ember.Object.extend({ 120 | sortedUsers: sortBy('users', {}) 121 | }).create().get('sortedUsers'); 122 | }, 'Asserted when second argument was incorrect.'); 123 | 124 | assert.throws(function() { 125 | Ember.Object.extend({ 126 | sortedUsers: sortBy('users', []) 127 | }).create().get('sortedUsers'); 128 | }, 'Asserted when second argument was incorrect.'); 129 | 130 | assert.throws(function() { 131 | Ember.Object.extend({ 132 | sortedUsers: sortBy('users', ['fname']) 133 | }).create().get('sortedUsers'); 134 | }, 'Asserted when second argument was incorrect.'); 135 | }); 136 | 137 | test('Setting sortBy property', function(assert) { 138 | assert.throws(function() { 139 | this.obj.set('sortedFnameUsers', Ember.A([])); 140 | }, 'Asserted when trying set read-only list.'); 141 | }); 142 | -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workmanw/ember-computed-sortby/18fbbfed3fcfad3b6532bf68b9b510fb49fb91e4/vendor/.gitkeep --------------------------------------------------------------------------------