├── app ├── .gitkeep └── components │ └── range-slider.js ├── addon ├── .gitkeep ├── templates │ └── components │ │ └── range-slider.hbs └── components │ └── range-slider.js ├── vendor ├── .gitkeep ├── shims │ └── nouislider.js ├── prism.css └── prism.js ├── tests ├── helpers │ └── .gitkeep ├── integration │ ├── .gitkeep │ └── components │ │ └── range-slider-test.js ├── dummy │ ├── app │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── models │ │ │ └── .gitkeep │ │ ├── routes │ │ │ ├── .gitkeep │ │ │ ├── index.js │ │ │ ├── events.js │ │ │ └── options.js │ │ ├── components │ │ │ ├── .gitkeep │ │ │ └── source-code.js │ │ ├── controllers │ │ │ ├── .gitkeep │ │ │ ├── events.js │ │ │ └── options.js │ │ ├── templates │ │ │ ├── components │ │ │ │ ├── .gitkeep │ │ │ │ ├── source-code.hbs │ │ │ │ └── navigation.hbs │ │ │ ├── application.hbs │ │ │ ├── index.hbs │ │ │ ├── download.hbs │ │ │ ├── component.hbs │ │ │ ├── events.hbs │ │ │ └── options.hbs │ │ ├── resolver.js │ │ ├── styles │ │ │ ├── app.scss │ │ │ └── _base.scss │ │ ├── router.js │ │ ├── app.js │ │ └── index.html │ ├── config │ │ ├── optional-features.json │ │ ├── targets.js │ │ └── environment.js │ └── public │ │ └── robots.txt ├── test-helper.js ├── .jshintrc └── index.html ├── .watchmanconfig ├── .prettierrc.js ├── config ├── environment.js └── ember-try.js ├── .template-lintrc.js ├── .ember-cli ├── .eslintignore ├── .editorconfig ├── .gitignore ├── .npmignore ├── rebuild-demo.sh ├── testem.js ├── ember-cli-build.js ├── CONTRIBUTING.md ├── LICENSE.md ├── .eslintrc.js ├── index.js ├── .travis.yml ├── package.json ├── README.md └── CHANGELOG.md /app/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/helpers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /addon/templates/components/range-slider.hbs: -------------------------------------------------------------------------------- 1 | {{yield}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 | {{outlet}} 2 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/config/optional-features.json: -------------------------------------------------------------------------------- 1 | { 2 | "jquery-integration": false 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | module.exports = { 3 | singleQuote: true 4 | }; 5 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/source-code.hbs: -------------------------------------------------------------------------------- 1 | {{yield}} 2 | -------------------------------------------------------------------------------- /app/components/range-slider.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-nouislider/components/range-slider'; 2 | -------------------------------------------------------------------------------- /tests/dummy/app/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember-resolver'; 2 | 3 | export default Resolver; 4 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(/* environment, appConfig */) { 4 | return { }; 5 | }; 6 | -------------------------------------------------------------------------------- /.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | 6 | rules: { 7 | 'no-inline-styles': false 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /vendor/shims/nouislider.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | function vendorModule() { 3 | 'use strict'; 4 | 5 | return { 'default': self['noUiSlider'] }; 6 | } 7 | 8 | define('noUiSlider', [], vendorModule); 9 | })(); 10 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.scss: -------------------------------------------------------------------------------- 1 | // Import the base styles 2 | @import "base"; 3 | 4 | // Now we can tweak them where needed 5 | .hi { 6 | h2 { 7 | @media (min-width: 800px) { 8 | margin-top: 5px; 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import Application from '../app'; 2 | import config from '../config/environment'; 3 | import { setApplication } from '@ember/test-helpers'; 4 | import { start } from 'ember-qunit'; 5 | 6 | setApplication(Application.create(config.APP)); 7 | 8 | start(); 9 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | /vendor/ 4 | 5 | # compiled output 6 | /dist/ 7 | /tmp/ 8 | 9 | # dependencies 10 | /bower_components/ 11 | /node_modules/ 12 | 13 | # misc 14 | /coverage/ 15 | !.* 16 | 17 | # ember-try 18 | /.node_modules.ember-try/ 19 | /bower.json.ember-try 20 | /package.json.ember-try 21 | -------------------------------------------------------------------------------- /tests/dummy/config/targets.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const browsers = [ 4 | 'last 1 Chrome versions', 5 | 'last 1 Firefox versions', 6 | 'last 1 Safari versions' 7 | ]; 8 | 9 | const isCI = !!process.env.CI; 10 | const isProduction = process.env.EMBER_ENV === 'production'; 11 | 12 | if (isCI || isProduction) { 13 | browsers.push('ie 11'); 14 | } 15 | 16 | module.exports = { 17 | browsers 18 | }; 19 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import EmberRouter from '@ember/routing/router'; 2 | import config from './config/environment'; 3 | 4 | const Router = EmberRouter.extend({ 5 | location: config.locationType, 6 | rootURL: config.rootURL 7 | }); 8 | 9 | Router.map(function() { 10 | this.route('download'); 11 | this.route('component'); 12 | this.route('options'); 13 | this.route('events'); 14 | }); 15 | 16 | export default Router; 17 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/index.js: -------------------------------------------------------------------------------- 1 | import { debug } from '@ember/debug'; 2 | import Route from '@ember/routing/route'; 3 | 4 | export default Route.extend({ 5 | model: function() { 6 | return { 7 | value: [20, 80] 8 | }; 9 | }, 10 | 11 | actions: { 12 | sliderChanged: function(value) { 13 | this.set("model.value", value); 14 | debug("Slider value changed to %@".fmt(value)); 15 | } 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from './resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from './config/environment'; 5 | 6 | const App = Application.extend({ 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix, 9 | Resolver 10 | }); 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | /bower_components/ 9 | /node_modules/ 10 | 11 | # misc 12 | /.env* 13 | /.pnp* 14 | /.sass-cache 15 | /connect.lock 16 | /coverage/ 17 | /libpeerconnection.log 18 | /npm-debug.log* 19 | /testem.log 20 | /yarn-error.log 21 | 22 | # ember-try 23 | /.node_modules.ember-try/ 24 | /bower.json.ember-try 25 | /package.json.ember-try 26 | -------------------------------------------------------------------------------- /tests/dummy/app/components/source-code.js: -------------------------------------------------------------------------------- 1 | import { computed } from '@ember/object'; 2 | import Component from '@ember/component'; 3 | /* global Prism */ 4 | 5 | export default Component.extend({ 6 | tagName: "pre", 7 | language: undefined, 8 | codeClass: computed(function() { 9 | let lang = this.get("language"); 10 | return "language-" + lang; 11 | }), 12 | 13 | didInsertElement() { 14 | var code = this.element.children[0]; 15 | Prism.highlightElement(code); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # dependencies 6 | /bower_components/ 7 | 8 | # misc 9 | /.bowerrc 10 | /.editorconfig 11 | /.ember-cli 12 | /.env* 13 | /.eslintignore 14 | /.eslintrc.js 15 | /.gitignore 16 | /.template-lintrc.js 17 | /.travis.yml 18 | /.watchmanconfig 19 | /bower.json 20 | /config/ember-try.js 21 | /CONTRIBUTING.md 22 | /ember-cli-build.js 23 | /testem.js 24 | /tests/ 25 | /yarn.lock 26 | .gitkeep 27 | 28 | # ember-try 29 | /.node_modules.ember-try/ 30 | /bower.json.ember-try 31 | /package.json.ember-try 32 | -------------------------------------------------------------------------------- /tests/integration/components/range-slider-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render } from '@ember/test-helpers'; 4 | import { hbs } from 'ember-cli-htmlbars'; 5 | 6 | module('Integration | Component | range-slider', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it renders', async function(assert) { 10 | assert.expect(1); 11 | 12 | await render(hbs`{{range-slider start=20}}`); 13 | 14 | assert.dom('.noUi-base', this.element).exists(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/navigation.hbs: -------------------------------------------------------------------------------- 1 |
2 | {{#link-to "index" class="bar-link project"}}ember-cli-nouislider{{/link-to}} 3 | {{#link-to "component" class="bar-link"}}Base Component{{/link-to}} 4 | {{#link-to "options" class="bar-link"}}Options{{/link-to}} 5 | {{#link-to "events" class="bar-link"}}Events{{/link-to}} 6 | Powered by noUiSlider 7 | {{#link-to "download" class="bar-link download"}}Download{{/link-to}} 8 |
9 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/index.hbs: -------------------------------------------------------------------------------- 1 |
2 |

<range-slider>

3 |

noUiSlider Range Slider Component for Ember.js

4 | 5 |
6 | {{range-slider start=model.value min=0 max=100 connect=true}} 7 | 8 | {{!-- template-lint-disable --}} 9 | {{#source-code language="handlebars"}} 10 | \{{range-slider start=model.value 11 | min=0 12 | max=100 13 | connect=true 14 | on-change="sliderChanged" 15 | }} 16 | {{/source-code}} 17 | 18 | {{#link-to "download" class="hi-dl"}}Download ember-cli-nouislider{{/link-to}} 19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /rebuild-demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Update our gh-pages branch with the latest build. 4 | # 5 | # This is based on ember-cli-github-pages, but using an addon is overkill. 6 | 7 | set -ex 8 | 9 | SHA=$(git rev-parse --short HEAD) 10 | 11 | # Build 12 | ember build --environment=production 13 | 14 | # Switch to gh-pages branch 15 | git checkout gh-pages 16 | 17 | # Copy the generated app into the root 18 | cp -R dist/* . 19 | 20 | # Stage all changes including removed files 21 | git add . 22 | git add -u . 23 | 24 | # Commit the changes 25 | git commit -m "Rebuilt gh-pages from ${SHA}" 26 | 27 | # Go back to master 28 | git checkout - 29 | 30 | echo "gh-pages has been rebuilt and can be pushed to origin" 31 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test_page: 'tests/index.html?hidepassed', 3 | disable_watching: true, 4 | launch_in_ci: ['Chrome', 'Firefox'], 5 | launch_in_dev: ['Chrome'], 6 | browser_args: { 7 | Firefox: { 8 | mode: 'ci', 9 | args: ['-headless'] 10 | }, 11 | Chrome: { 12 | ci: [ 13 | // --no-sandbox is needed when running Chrome inside a container 14 | process.env.CI ? '--no-sandbox' : null, 15 | '--headless', 16 | '--disable-dev-shm-usage', 17 | '--disable-software-rasterizer', 18 | '--mute-audio', 19 | '--remote-debugging-port=0', 20 | '--window-size=1440,900' 21 | ].filter(Boolean) 22 | } 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /tests/dummy/app/controllers/events.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | 3 | export default Controller.extend({ 4 | actions: { 5 | update(value) { 6 | this.send("showEffect", "updating", value); 7 | }, 8 | 9 | change(value) { 10 | this.send("showEffect", "changed", value); 11 | }, 12 | 13 | setValue(value) { 14 | this.send("showEffect", "beenSet", value); 15 | }, 16 | 17 | slide(value) { 18 | this.send("showEffect", "sliding", value); 19 | }, 20 | 21 | started(value) { 22 | this.send("showEffect", "started", value); 23 | }, 24 | 25 | ended(value) { 26 | this.send("showEffect", "ended", value); 27 | } 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 4 | 5 | module.exports = function(defaults) { 6 | let app = new EmberAddon(defaults, { 7 | // Add options here 8 | vendorFiles: { 9 | // 'jquery.js': null 10 | } 11 | }); 12 | 13 | /* 14 | This build file specifies the options for the dummy test app of this 15 | addon, located in `/tests/dummy` 16 | This build file does *not* influence how the addon or the app using it 17 | behave. You most likely want to be modifying `./index.js` or app's build file 18 | */ 19 | 20 | app.import("vendor/prism.js"); 21 | app.import("vendor/prism.css"); 22 | 23 | return app.toTree(); 24 | }; 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How To Contribute 2 | 3 | ## Installation 4 | 5 | * `git clone https://github.com/kennethkalmer/ember-cli-nouislider` 6 | * `cd ember-cli-nouislider` 7 | * `yarn install` 8 | 9 | ## Linting 10 | 11 | * `npm run lint:hbs` 12 | * `npm run lint:js` 13 | * `npm run lint:js -- --fix` 14 | 15 | ## Running tests 16 | 17 | * `ember test` – Runs the test suite on the current Ember version 18 | * `ember test --server` – Runs the test suite in "watch mode" 19 | * `ember try:each` – Runs the test suite against multiple Ember versions 20 | 21 | ## Running the dummy application 22 | 23 | * `ember serve` 24 | * Visit the dummy application at [http://localhost:4200](http://localhost:4200). 25 | 26 | For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/). 27 | -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ember-cli-nouislider 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | 12 | 13 | 14 | 15 | 16 | {{content-for "head-footer"}} 17 | 18 | 19 | {{content-for "body"}} 20 | 21 | 22 | 23 | 24 | {{content-for "body-footer"}} 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "$", 8 | "-Promise", 9 | "define", 10 | "console", 11 | "visit", 12 | "exists", 13 | "fillIn", 14 | "click", 15 | "keyEvent", 16 | "triggerEvent", 17 | "find", 18 | "findWithAssert", 19 | "wait", 20 | "DS", 21 | "andThen", 22 | "currentURL", 23 | "currentPath", 24 | "currentRouteName" 25 | ], 26 | "node": false, 27 | "browser": false, 28 | "boss": true, 29 | "curly": true, 30 | "debug": false, 31 | "devel": false, 32 | "eqeqeq": true, 33 | "evil": true, 34 | "forin": false, 35 | "immed": false, 36 | "laxbreak": false, 37 | "newcap": true, 38 | "noarg": true, 39 | "noempty": false, 40 | "nonew": false, 41 | "nomen": false, 42 | "onevar": false, 43 | "plusplus": false, 44 | "regexp": false, 45 | "undef": true, 46 | "sub": true, 47 | "strict": false, 48 | "white": false, 49 | "eqnull": true, 50 | "esversion": 6, 51 | "unused": true 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 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 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/download.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Download & Install ember-cli-nouislider

5 | 6 |

ember-cli

7 |
8 |
9 |

The code is shipped as an ember-cli addon:

10 | 11 |
12 | $ ember install:addon ember-cli-nouislider
13 |       
14 | 15 |

16 | Then continue checking out the documentation to create 17 | your own base {{#link-to "component"}}range-slider{{/link-to}} component. 18 |

19 |
20 |
21 |
22 | 23 |

Repository

24 |
25 |
26 | You could visit the repository on 27 | GitHub 28 | to browse around, and to log issues. Also feel free 29 | to get in touch via @kennethkalmer 30 | if you need some help. 31 |
32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /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/dummy/app/controllers/options.js: -------------------------------------------------------------------------------- 1 | import { A } from '@ember/array'; 2 | import { computed } from '@ember/object'; 3 | import Controller from '@ember/controller'; 4 | 5 | export default Controller.extend({ 6 | marginMin: computed('model.margins.[]', function() { 7 | let margins = A(this.get('model.margins')); 8 | return margins.get('firstObject'); 9 | }), 10 | 11 | marginMax: computed('model.margins.[]', function() { 12 | let margins = A(this.get('model.margins')); 13 | return margins.get('lastObject'); 14 | }), 15 | 16 | limitMin: computed('model.limits.[]', function() { 17 | let limits = A(this.get('model.limits')); 18 | return limits.get('firstObject'); 19 | }), 20 | 21 | limitMax: computed('model.limits.[]', function() { 22 | let limits = A(this.get('model.limits')); 23 | return limits.get('lastObject'); 24 | }), 25 | 26 | paddingMin: computed('model.padding.[]', function() { 27 | let padding = A(this.get('model.padding')); 28 | return padding.get('firstObject'); 29 | }), 30 | 31 | paddingMax: computed('model.padding.[]', function() { 32 | let padding = A(this.get('model.padding')); 33 | return padding.get('lastObject'); 34 | }) 35 | }); 36 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2018, 5 | sourceType: 'module' 6 | }, 7 | plugins: [ 8 | 'ember' 9 | ], 10 | extends: [ 11 | 'eslint:recommended', 12 | 'plugin:ember/recommended' 13 | ], 14 | env: { 15 | browser: true 16 | }, 17 | rules: { 18 | 'ember/no-observers': 'warn' 19 | }, 20 | overrides: [ 21 | // node files 22 | { 23 | files: [ 24 | '.eslintrc.js', 25 | '.template-lintrc.js', 26 | 'ember-cli-build.js', 27 | 'index.js', 28 | 'testem.js', 29 | 'blueprints/*/index.js', 30 | 'config/**/*.js', 31 | 'tests/dummy/config/**/*.js' 32 | ], 33 | excludedFiles: [ 34 | 'addon/**', 35 | 'addon-test-support/**', 36 | 'app/**', 37 | 'tests/dummy/app/**' 38 | ], 39 | parserOptions: { 40 | sourceType: 'script' 41 | }, 42 | env: { 43 | browser: false, 44 | node: true 45 | }, 46 | plugins: ['node'], 47 | rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, { 48 | // add your custom rules and overrides for node files here 49 | }) 50 | } 51 | ] 52 | }; 53 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | var path = require('path'); 5 | var Funnel = require('broccoli-funnel'); 6 | var MergeTrees = require('broccoli-merge-trees'); 7 | 8 | module.exports = { 9 | name: 'ember-cli-nouislider', 10 | 11 | included: function() { 12 | this._super.included.apply(this, arguments); 13 | this._ensureThisImport(); 14 | 15 | if (!process.env.EMBER_CLI_FASTBOOT) { 16 | this.import('vendor/nouislider.js'); 17 | this.import('vendor/nouislider.min.css'); 18 | this.import('vendor/shims/nouislider.js'); 19 | } 20 | }, 21 | 22 | treeForVendor: function(vendorTree) { 23 | var nouisliderTree = new Funnel(path.dirname(require.resolve('nouislider/distribute/nouislider.js')), { 24 | files: ['nouislider.js', 'nouislider.min.css'] 25 | }); 26 | 27 | return new MergeTrees([vendorTree, nouisliderTree]); 28 | }, 29 | 30 | _ensureThisImport: function() { 31 | if (!this.import) { 32 | this._findHost = function findHostShim() { 33 | var current = this; 34 | var app; 35 | do { 36 | app = current.app || app; 37 | } while (current.parent.parent && (current = current.parent)); 38 | return app; 39 | }; 40 | this.import = function importShim(asset, options) { 41 | var app = this._findHost(); 42 | app.import(asset, options); 43 | }; 44 | } 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/events.js: -------------------------------------------------------------------------------- 1 | import { later } from '@ember/runloop'; 2 | import EmberObject from '@ember/object'; 3 | import Route from '@ember/routing/route'; 4 | 5 | export default Route.extend({ 6 | model: function() { 7 | return EmberObject.create({ 8 | start: [ 5, 15 ], 9 | range: { min: 0, max: 20 }, 10 | 11 | changed: false, 12 | sliding: false, 13 | updating: false, 14 | beenSet: false, 15 | started: false, 16 | ended: false, 17 | 18 | value: [ 5, 15 ] 19 | }); 20 | }, 21 | 22 | actions: { 23 | showEffect(property, val) { 24 | var model = this.modelFor("events"); 25 | model.set('value', val); 26 | model.set(property, true); 27 | 28 | later(model, function() { 29 | this.set(property, false); 30 | }, 500); 31 | }, 32 | 33 | update(val) { 34 | this.send("showEffect", "updating", val); 35 | }, 36 | 37 | change: function(val) { 38 | this.send("showEffect", "changed", val); 39 | }, 40 | 41 | setValue: function(val) { 42 | this.send("showEffect", "beenSet", val); 43 | }, 44 | 45 | slide: function(val) { 46 | this.send("showEffect", "sliding", val); 47 | }, 48 | 49 | started: function(val) { 50 | this.send("showEffect", "started", val); 51 | }, 52 | 53 | ended: function(val) { 54 | this.send("showEffect", "ended", val); 55 | } 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | # we recommend testing addons with the same minimum supported node version as Ember CLI 5 | # so that your addon works for all apps 6 | - "10" 7 | 8 | sudo: false 9 | dist: trusty 10 | 11 | addons: 12 | chrome: stable 13 | 14 | cache: 15 | directories: 16 | - $HOME/.npm 17 | 18 | env: 19 | global: 20 | # See https://git.io/vdao3 for details. 21 | - JOBS=1 22 | 23 | branches: 24 | only: 25 | - master 26 | # npm version tags 27 | - /^v\d+\.\d+\.\d+/ 28 | 29 | jobs: 30 | fail_fast: true 31 | allow_failures: 32 | - env: EMBER_TRY_SCENARIO=ember-canary 33 | 34 | include: 35 | # runs linting and tests with current locked deps 36 | 37 | - stage: "Tests" 38 | name: "Tests" 39 | script: 40 | - npm run lint:hbs 41 | - npm run lint:js 42 | - npm test 43 | 44 | # we recommend new addons test the current and previous LTS 45 | # as well as latest stable release (bonus points to beta/canary) 46 | - env: EMBER_TRY_SCENARIO=ember-lts-3.12 47 | - env: EMBER_TRY_SCENARIO=ember-lts-3.16 48 | - env: EMBER_TRY_SCENARIO=ember-release 49 | - env: EMBER_TRY_SCENARIO=ember-beta 50 | - env: EMBER_TRY_SCENARIO=ember-canary 51 | - env: EMBER_TRY_SCENARIO=ember-default-with-jquery 52 | - env: EMBER_TRY_SCENARIO=ember-classic 53 | 54 | script: 55 | - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO 56 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/options.js: -------------------------------------------------------------------------------- 1 | import EmberObject from '@ember/object'; 2 | import Route from '@ember/routing/route'; 3 | 4 | export default Route.extend({ 5 | model() { 6 | return EmberObject.create({ 7 | defaultRange: { min: 0, max: 100 }, 8 | defaultStart: [ 20, 80 ], 9 | 10 | margins: [ 20, 80 ], 11 | padding: [ 20, 80 ], 12 | limits: [ 20, 60 ], 13 | steps: [ 20, 80 ], 14 | direction: 20, 15 | animate: 20, 16 | disabled: false, 17 | tooltips: [ 18 | false, 19 | { 20 | to: num => { 21 | return Math.floor(num); 22 | } 23 | } 24 | ] 25 | }); 26 | }, 27 | 28 | actions: { 29 | marginChanged(val) { 30 | let model = this.modelFor("options"); 31 | model.set("margins", val); 32 | }, 33 | 34 | limitsChanged(val) { 35 | let model = this.modelFor("options"); 36 | model.set("limits", val); 37 | }, 38 | 39 | paddingChanged(val) { 40 | let model = this.modelFor("options"); 41 | model.set("padding", val); 42 | }, 43 | 44 | directionChanged(val) { 45 | let model = this.modelFor("options"); 46 | model.set("direction", val); 47 | }, 48 | 49 | animateValues() { 50 | let model = this.modelFor("options"); 51 | model.set("animate", 60); 52 | }, 53 | 54 | disableSlider() { 55 | let model = this.modelFor("options"); 56 | model.toggleProperty("disabled"); 57 | } 58 | } 59 | }); 60 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(environment) { 4 | let ENV = { 5 | modulePrefix: 'dummy', 6 | 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. EMBER_NATIVE_DECORATOR_SUPPORT: 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 | ENV.APP.autoboot = false; 44 | } 45 | 46 | if (environment === 'production') { 47 | // For github pages 48 | ENV.rootURL = '/ember-cli-nouislider'; 49 | ENV.locationType = 'hash'; 50 | } 51 | 52 | ENV.contentSecurityPolicy = { 53 | 'font-src': "'self' 'unsafe-inline' http://fonts.gstatic.com", 54 | 'style-src': "'self' 'unsafe-inline' http://fonts.googleapis.com" 55 | }; 56 | 57 | return ENV; 58 | }; 59 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/component.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Create your component

5 |
6 |
7 |

8 | Ensure you've already {{#link-to "download"}}downloaded & installed{{/link-to}} 9 | the addon 10 |

11 |
12 |
13 | 14 | § 15 |

Render

16 |
17 |
18 |

Render your range-slider where you need it

19 |
20 |
21 | {{!-- template-lint-disable --}} 22 | {{#source-code language="handlebars"}} 23 | \{{! some template }} 24 | \{{range-slider start=someValue on-change="changedAction"}} 25 | {{/source-code}} 26 |
27 |
28 | 29 | § 30 |

Action

31 |
32 |
33 |

34 | Setup an action handler in your route to catch 35 | any changes to the slider values. 36 |

37 |
38 |
39 | {{!-- template-lint-disable --}} 40 | {{#source-code language="javascript"}} 41 | // app/routes/my-route.js 42 | import Ember from 'ember'; 43 | 44 | export default Ember.Route.extend({ 45 | // ... 46 | actions: { 47 | // ... 48 | changedAction: function(value) { 49 | Ember.debug( "New slider value: %@".fmt( value ) ); 50 | } 51 | } 52 | }); 53 | {{/source-code}} 54 |
55 |
56 | 57 |

Next

58 |
59 |
60 |

Review the {{#link-to "options"}}available options{{/link-to}}...

61 |
62 |
63 |
64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-cli-nouislider", 3 | "version": "1.2.1", 4 | "description": "Ember range-slider component powered by nouislider", 5 | "author": "Kenneth Kalmer", 6 | "directories": { 7 | "doc": "doc", 8 | "test": "tests" 9 | }, 10 | "scripts": { 11 | "build": "ember build", 12 | "lint:hbs": "ember-template-lint .", 13 | "lint:js": "eslint .", 14 | "start": "ember serve", 15 | "test": "ember test", 16 | "test:all": "ember try:each" 17 | }, 18 | "dependencies": { 19 | "broccoli-funnel": "^3.0.2", 20 | "broccoli-merge-trees": "^4.0.1", 21 | "ember-cli-babel": "^7.7.3", 22 | "ember-cli-htmlbars": "^4.2.3", 23 | "nouislider": "^14.1.1" 24 | }, 25 | "devDependencies": { 26 | "@ember/optional-features": "^0.7.0", 27 | "broccoli-asset-rev": "^3.0.0", 28 | "ember-cli": "~3.12.0", 29 | "ember-cli-dependency-checker": "^3.1.0", 30 | "ember-cli-eslint": "^5.1.0", 31 | "ember-cli-inject-live-reload": "^1.8.2", 32 | "ember-cli-sass": "^10.0.0", 33 | "ember-cli-sri": "^2.1.1", 34 | "ember-cli-template-lint": "^1.0.0-beta.1", 35 | "ember-cli-uglify": "^3.0.0", 36 | "ember-disable-prototype-extensions": "^1.1.3", 37 | "ember-export-application-global": "^2.0.0", 38 | "ember-load-initializers": "^2.0.0", 39 | "ember-maybe-import-regenerator": "^0.1.6", 40 | "ember-qunit": "^4.4.1", 41 | "ember-resolver": "^5.0.1", 42 | "ember-source": "~3.12.0", 43 | "ember-source-channel-url": "^1.1.0", 44 | "ember-try": "^1.0.0", 45 | "eslint-plugin-ember": "^6.2.0", 46 | "eslint-plugin-node": "^9.0.1", 47 | "loader.js": "^4.7.0", 48 | "qunit-dom": "^0.8.4", 49 | "sass": "^1.26.1" 50 | }, 51 | "keywords": [ 52 | "ember-addon", 53 | "nouislider", 54 | "slider", 55 | "range slider", 56 | "jquery range slider", 57 | "ember-component" 58 | ], 59 | "repository": "https://github.com/kennethkalmer/ember-cli-nouislider", 60 | "license": "MIT", 61 | "engines": { 62 | "node": "10.* || >= 12" 63 | }, 64 | "ember-addon": { 65 | "configPath": "tests/dummy/config", 66 | "demoURL": "http://kennethkalmer.github.com/ember-cli-nouislider" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getChannelURL = require('ember-source-channel-url'); 4 | 5 | module.exports = async function() { 6 | return { 7 | useYarn: true, 8 | scenarios: [ 9 | { 10 | name: 'ember-lts-3.12', 11 | npm: { 12 | devDependencies: { 13 | 'ember-source': '~3.12.0' 14 | } 15 | } 16 | }, 17 | { 18 | name: 'ember-lts-3.16', 19 | npm: { 20 | devDependencies: { 21 | 'ember-source': '~3.16.0' 22 | } 23 | } 24 | }, 25 | { 26 | name: 'ember-release', 27 | npm: { 28 | devDependencies: { 29 | 'ember-source': await getChannelURL('release') 30 | } 31 | } 32 | }, 33 | { 34 | name: 'ember-beta', 35 | npm: { 36 | devDependencies: { 37 | 'ember-source': await getChannelURL('beta') 38 | } 39 | } 40 | }, 41 | { 42 | name: 'ember-canary', 43 | npm: { 44 | devDependencies: { 45 | 'ember-source': await getChannelURL('canary') 46 | } 47 | } 48 | }, 49 | // The default `.travis.yml` runs this scenario via `npm test`, 50 | // not via `ember try`. It's still included here so that running 51 | // `ember try:each` manually or from a customized CI config will run it 52 | // along with all the other scenarios. 53 | { 54 | name: 'ember-default', 55 | npm: { 56 | devDependencies: {} 57 | } 58 | }, 59 | { 60 | name: 'ember-default-with-jquery', 61 | env: { 62 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 63 | 'jquery-integration': true 64 | }) 65 | }, 66 | npm: { 67 | devDependencies: { 68 | '@ember/jquery': '^0.5.1' 69 | } 70 | } 71 | }, 72 | { 73 | name: 'ember-classic', 74 | env: { 75 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 76 | 'application-template-wrapper': true, 77 | 'template-only-glimmer-components': false 78 | }) 79 | }, 80 | npm: { 81 | ember: { 82 | edition: 'classic' 83 | } 84 | } 85 | } 86 | ] 87 | }; 88 | }; 89 | -------------------------------------------------------------------------------- /vendor/prism.css: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+handlebars */ 2 | /** 3 | * prism.js default theme for JavaScript, CSS and HTML 4 | * Based on dabblet (http://dabblet.com) 5 | * @author Lea Verou 6 | */ 7 | 8 | code[class*="language-"], 9 | pre[class*="language-"] { 10 | color: black; 11 | text-shadow: 0 1px white; 12 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 13 | direction: ltr; 14 | text-align: left; 15 | white-space: pre; 16 | word-spacing: normal; 17 | word-break: normal; 18 | line-height: 1.5; 19 | 20 | -moz-tab-size: 4; 21 | -o-tab-size: 4; 22 | tab-size: 4; 23 | 24 | -webkit-hyphens: none; 25 | -moz-hyphens: none; 26 | -ms-hyphens: none; 27 | hyphens: none; 28 | } 29 | 30 | pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, 31 | code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { 32 | text-shadow: none; 33 | background: #b3d4fc; 34 | } 35 | 36 | pre[class*="language-"]::selection, pre[class*="language-"] ::selection, 37 | code[class*="language-"]::selection, code[class*="language-"] ::selection { 38 | text-shadow: none; 39 | background: #b3d4fc; 40 | } 41 | 42 | @media print { 43 | code[class*="language-"], 44 | pre[class*="language-"] { 45 | text-shadow: none; 46 | } 47 | } 48 | 49 | /* Code blocks */ 50 | pre[class*="language-"] { 51 | padding: 1em; 52 | margin: .5em 0; 53 | overflow: auto; 54 | } 55 | 56 | :not(pre) > code[class*="language-"], 57 | pre[class*="language-"] { 58 | background: #f5f2f0; 59 | } 60 | 61 | /* Inline code */ 62 | :not(pre) > code[class*="language-"] { 63 | padding: .1em; 64 | border-radius: .3em; 65 | } 66 | 67 | .token.comment, 68 | .token.prolog, 69 | .token.doctype, 70 | .token.cdata { 71 | color: slategray; 72 | } 73 | 74 | .token.punctuation { 75 | color: #999; 76 | } 77 | 78 | .namespace { 79 | opacity: .7; 80 | } 81 | 82 | .token.property, 83 | .token.tag, 84 | .token.boolean, 85 | .token.number, 86 | .token.constant, 87 | .token.symbol, 88 | .token.deleted { 89 | color: #905; 90 | } 91 | 92 | .token.selector, 93 | .token.attr-name, 94 | .token.string, 95 | .token.char, 96 | .token.builtin, 97 | .token.inserted { 98 | color: #690; 99 | } 100 | 101 | .token.operator, 102 | .token.entity, 103 | .token.url, 104 | .language-css .token.string, 105 | .style .token.string { 106 | color: #a67f59; 107 | background: hsla(0, 0%, 100%, .5); 108 | } 109 | 110 | .token.atrule, 111 | .token.attr-value, 112 | .token.keyword { 113 | color: #07a; 114 | } 115 | 116 | .token.function { 117 | color: #DD4A68; 118 | } 119 | 120 | .token.regex, 121 | .token.important, 122 | .token.variable { 123 | color: #e90; 124 | } 125 | 126 | .token.important, 127 | .token.bold { 128 | font-weight: bold; 129 | } 130 | .token.italic { 131 | font-style: italic; 132 | } 133 | 134 | .token.entity { 135 | cursor: help; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ember-cli-nouislider 2 | 3 | [![Build Status](https://travis-ci.org/kennethkalmer/ember-cli-nouislider.svg)](https://travis-ci.org/kennethkalmer/ember-cli-nouislider) 4 | [![npm version](https://badge.fury.io/js/ember-cli-nouislider.svg)](http://badge.fury.io/js/ember-cli-nouislider) 5 | [![Code Climate](https://codeclimate.com/github/kennethkalmer/ember-cli-nouislider/badges/gpa.svg)](https://codeclimate.com/github/kennethkalmer/ember-cli-nouislider) 6 | [![Ember Observer Score](http://emberobserver.com/badges/ember-cli-nouislider.svg)](http://emberobserver.com/addons/ember-cli-nouislider) 7 | [![Open Source Helpers](https://www.codetriage.com/kennethkalmer/ember-cli-nouislider/badges/users.svg)](https://www.codetriage.com/kennethkalmer/ember-cli-nouislider) 8 | 9 | This ember-cli addon provides you with a range-slider component, based on 10 | [noUiSlider](http://refreshless.com/nouislider). It includes everything you need, 11 | and adds no extra dependencies other than noUiSlider itself (which has no external dependencies). 12 | 13 | To get started simply install the addon: 14 | 15 | ``` 16 | $ ember install ember-cli-nouislider 17 | ``` 18 | 19 | This will install `nouislider` via Bower, and will include it into your application's 20 | mergetree, so you don't need to worry about anything there. 21 | 22 | ## Compatibility 23 | 24 | * Ember.js v3.12 or above 25 | * Ember CLI v2.13 or above 26 | * Node.js v10 or above 27 | 28 | ## Demo & documentation 29 | 30 | Have a look around then [demo and documentation](http://kennethkalmer.github.com/ember-cli-nouislider) 31 | to get a feel for how to use it. 32 | 33 | ## Component 34 | 35 | You have the opportunity to customize if needed. 36 | 37 | To do this, generate your own component and re-export 38 | the one provided: 39 | 40 | ``` 41 | $ ember g component range-slider 42 | ``` 43 | 44 | ```js 45 | // app/components/range-slider.js 46 | import RangeSlider from 'ember-cli-nouislider/components/range-slider'; 47 | 48 | export default RangeSlider; 49 | ``` 50 | 51 | Include the slider into your views like this: 52 | 53 | ```handlebars 54 | {{range-slider start=someValue on-change=(action "changedAction")}} 55 | ``` 56 | 57 | And setup an action handler in your route: 58 | 59 | ```js 60 | // app/routes/my-route.js 61 | import Controller from '@ember/controller'; 62 | import { debug } from '@ember/debug'; 63 | 64 | export default Controller.extend({ 65 | // ... 66 | actions: { 67 | // ... 68 | changedAction: function(value) { 69 | debug( `New slider value: ${value}`); 70 | } 71 | } 72 | }); 73 | ``` 74 | 75 | See the [documentation](https://kennethkalmer.github.com/ember-cli-nouislider/) 76 | for more actions. 77 | 78 | ## Configuration 79 | 80 | The component has a lot of configurable options, most of them mapping directly 81 | to the [original options](http://refreshless.com/nouislider/slider-options/). 82 | To see how the slider is initialized internally, please have a look at 83 | `app/components/range-slider.js` in this project, or browse through the 84 | [documentation](https://kennethkalmer.github.com/ember-cli-nouislider). 85 | 86 | 87 | ## License 88 | 89 | This project is licensed under the [MIT License](LICENSE.md). 90 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## master 2 | 3 | ## 1.2.1 2020-03-02 4 | 5 | * Merged several security related PR's (#77, #78, #79, #80, #81, #82, #83) 6 | 7 | ## 1.2.0 2020-03-02 8 | 9 | * Update nouislider version (#75 - @crowjonah) 10 | * Don't call slider.set during dragging (#63 - @stephankaag) 11 | * Added the padding option (#62 - @sonnyt) 12 | * Upgrade ember-cli-sass and add sass to devDependencies 13 | * Upgrade to ember-cli 3.12 14 | 15 | ## 1.1.0 2018-11-09 16 | 17 | * Support closure actions because sendAction is deprecated (#68 - @scottkidder) 18 | 19 | ## 1.0.0 2018-04-28 - My First Decade on GitHub 20 | 21 | * Remove deprecated `change` & `slide` properties 22 | * Use nouislider's ability to just remove all event listeners, instead of tediously keeping track 23 | 24 | ## 1.0.0-rc.2 2018-04-14 25 | 26 | * Add cssPrefix & cssClasses options (#57 - @stephankaag) 27 | 28 | ## 1.0.0-rc.1 2018-04-14 29 | 30 | * Upgrade to Ember 3.0 (#53 - @tchak & #59 - @tchak) 31 | * Bump to nouislider 11.0 (#53 - @tchak & #59 - @tchak) 32 | * Move broccoli-funnel & broccoli-merge-trees to dependencies (from devDependencies) 33 | 34 | ## 0.14.1 2017-10-08 35 | 36 | _Version bump only because I can't NPM properly_ 37 | 38 | ## 0.14.0 2017-10-08 39 | 40 | * Expose multitouch option (#47) 41 | * Warn when component can't be initialized (#34) 42 | * Bump to nouislider 10.1.0 43 | * Bump to Ember 2.15.1 44 | 45 | 46 | ## 0.13.0 2017-03-12 47 | 48 | * Bump to nouislider 9.2.0 (#44) 49 | 50 | ## 0.12.0 2017-02-27 51 | 52 | * Fix deprecation warnings when rendering slider (#39 - @showy) 53 | * Fix incorrect behaviour with negative ranges (reporting #24 @Ramblurr, fixed #43 @eraleis) 54 | * Switch to using npm for nouislider (#44 - @bobisjan) 55 | 56 | ## 0.11.0 2016-12-16 - Happy Reconciliation Day 57 | 58 | * Bump to Ember 2.10.0 59 | * Updated docs example (#40 - @adambowles) 60 | * Update slider if component properties have changed (#38 - @renebigot) 61 | 62 | ## 0.10.0 2016-10-03 63 | 64 | * Bump to Ember 2.8.0 LTS 65 | * BETA support for tooltips (#35 - michalsnik) 66 | * Bump nouislider to 8.5.0 67 | * Support for the 'disabled' attribute (#25 - @alexspeller) 68 | 69 | ## 0.9.1 2016-07-11 70 | 71 | * Support for fastboot (#26 - @tschoartschi) 72 | * Documentation update (#29 - @sandstrom) 73 | 74 | ## 0.9.0 2016-04-14 75 | 76 | * Support for 'update', 'start' & 'end' events 77 | * Bump nouislider to 8.3.0 78 | 79 | ## 0.8.1 2016-03-26 80 | 81 | * Deprecate the old events ("change" & "slide") in favor of "on-change" & "on-slide" 82 | * Fix regression introduced by `set` action, now called `on-set` 83 | 84 | ## 0.8.0 2016-03-26 85 | 86 | * Bump nouislider to 8.0.2 87 | * Added nodejs 4 & 5 to Travis config, allow failures on Node 5 88 | * Upgrade ember-cli to 2.4.2 89 | * Added "set" action in order to use it in acceptance testing (#22 - @juliankmazo) 90 | * Include non-minified version of nouislider in development (#21 - @constantm) 91 | 92 | ## 0.7.0 2015-08-17 93 | 94 | * Add CodeClimate badge to README 95 | * Update ember-cli to 1.13.8, ember.js to 1.13.7 96 | * Bring back 'format' (#19 - @knownasilya) 97 | * Bring back 'snap' and 'pips' (#18 - @kbullaughey) 98 | 99 | ## 0.6.0 2015-07-09 - (Happy Birthday To Me) 100 | 101 | * Add demoURL to package.json 102 | * Use events instead of listeners (#14 - @knowasilya) 103 | * Add "formats" & "pips" suppor (#13 - @davidgoli) 104 | 105 | ## 0.5.0 2015-07-02 106 | 107 | * Upgrade to nouislider 8.0.1 (#10 - @blimmer) 108 | * Documentation improvements (#10 - @blimmer) 109 | * Toolchain upgrades and tlc (#10 - @blimmer) 110 | 111 | Thanks Ben Limmer for doing all this work! 112 | 113 | ## 0.4.2 2015-07-02 114 | 115 | * Pin nouislider dependency at 7.0.0 (#9 - @blimmer) 116 | 117 | ## 0.4.1 2015-06-19 118 | 119 | * Fixed an issue with actions not being called correctly (#6) 120 | 121 | ## 0.4.0 2015-05-09 122 | 123 | * Allow changing the name of the _change_ action 124 | * Allow specifying an action for when sliding (#3) 125 | 126 | ## 0.3.0 2015-04-17 127 | 128 | * Now works with prototype extensions disabled 129 | * Moved addon bits into addons/ directory so they don't conflict with application 130 | * Depend on ember-cli-htmlbars because we're shipping a template 131 | 132 | ## 0.2.0 2015-03-16 133 | 134 | * Now observe changes to `start` and pass the changes on to noUiSlider 135 | * Changed the default value of `start` to be `undefined` 136 | * Changed the default value of `step` to be `undefined` 137 | * Added missing `animate` attribute, default to `true`. 138 | 139 | ## 0.1.1 2015-03-09 140 | 141 | * Moved rimraf dependency to devDependencies 142 | 143 | ## 0.1.0 2015-03-09 144 | 145 | Initial release 146 | -------------------------------------------------------------------------------- /addon/components/range-slider.js: -------------------------------------------------------------------------------- 1 | /* eslint ember/closure-actions: 0 */ 2 | 3 | import { A } from '@ember/array'; 4 | import Component from '@ember/component'; 5 | import { run } from '@ember/runloop'; 6 | import { isEmpty } from '@ember/utils'; 7 | import { observer, computed } from '@ember/object'; 8 | import Ember from 'ember'; 9 | import noUiSlider from 'noUiSlider'; 10 | 11 | const { 12 | Logger: { warn } 13 | } = Ember; 14 | 15 | export default Component.extend({ 16 | attributeBindings: ['disabledOrUndefined:disabled'], 17 | slider: null, 18 | start: undefined, 19 | step: undefined, 20 | margin: undefined, 21 | padding: undefined, 22 | limit: undefined, 23 | pips: undefined, 24 | animate: true, 25 | snap: false, 26 | connect: false, 27 | disabled: false, 28 | orientation: 'horizontal', 29 | direction: 'ltr', 30 | behaviour: 'tap', 31 | tooltips: false, 32 | multitouch: false, 33 | keyboardSupport: true, 34 | 35 | min: 0, 36 | max: 100, 37 | 38 | range: computed('min', 'max', function() { 39 | return { 40 | min: this.get('min'), 41 | max: this.get('max') 42 | }; 43 | }), 44 | 45 | formatTo(value) { 46 | return value; 47 | }, 48 | 49 | formatFrom(value) { 50 | return +value; 51 | }, 52 | 53 | format: computed('formatTo', 'formatFrom', function() { 54 | return { 55 | to: this.get('formatTo'), 56 | from: this.get('formatFrom') 57 | }; 58 | }), 59 | 60 | didInsertElement() { 61 | this.setup(); 62 | }, 63 | 64 | setup() { 65 | let element = this.get('element'); 66 | let { noUiSlider: slider } = element; 67 | let properties = this.getProperties( 68 | 'start', 'step', 'margin', 'padding', 69 | 'limit', 'range', 'connect', 70 | 'orientation', 'direction', 71 | 'behaviour', 'animate', 'snap', 72 | 'pips', 'format', 'tooltips', 73 | 'multitouch', 'cssPrefix', 74 | 'cssClasses', 'keyboardSupport' 75 | ); 76 | let sliderEvents = A(['change', 'set', 'slide', 'update']); 77 | 78 | // We first check if the element has a slider already created 79 | if (slider && slider.destroy) { 80 | slider.destroy(); 81 | } 82 | 83 | try { 84 | slider = noUiSlider.create(element, properties, true); 85 | } catch (err) { 86 | warn(`[ember-cli-nouislider]: ${err}`); 87 | } 88 | 89 | this.slider = slider; 90 | 91 | sliderEvents.forEach(event => { 92 | const eventActionName = `on-${event}`; 93 | 94 | if (!isEmpty(this.get(eventActionName))) { 95 | slider.on(event, () => { 96 | run(this, function() { 97 | const val = this.get('slider').get(); 98 | const action = this.get(eventActionName); 99 | 100 | if (typeof(action) === 'string') { 101 | // Note that `sendAction` is deprecated and this will trigger a deprecation message. 102 | this.sendAction(eventActionName, val); 103 | } else if (typeof(action) === 'function') { 104 | action(val); 105 | } 106 | }); 107 | }); 108 | } 109 | }); 110 | 111 | slider.on('start', () => { 112 | run(this, function() { 113 | this.onStart(); 114 | if (!isEmpty(this.get(`on-start`))) { 115 | let val = this.get("slider").get(); 116 | this.sendAction(`on-start`, val); 117 | } 118 | }); 119 | }); 120 | 121 | slider.on('end', () => { 122 | run(this, function() { 123 | this.onEnd(); 124 | if (!isEmpty(this.get(`on-end`))) { 125 | let val = this.get("slider").get(); 126 | this.sendAction(`on-end`, val); 127 | } 128 | }); 129 | }); 130 | }, 131 | 132 | onStart() { 133 | this.sliding = true; 134 | }, 135 | 136 | onEnd() { 137 | delete this.sliding; 138 | }, 139 | 140 | didUpdateAttrs() { 141 | this.update(); 142 | }, 143 | 144 | update() { 145 | let { slider } = this; 146 | let properties = this.getProperties( 147 | 'margin', 'limit', 'step', 148 | 'range', 'animate', 'snap', 149 | 'start', 'padding', 'keyboardSupport' 150 | ); 151 | 152 | if (slider) { 153 | slider.updateOptions(properties); 154 | } 155 | }, 156 | 157 | willDestroyElement() { 158 | this.teardown(); 159 | }, 160 | 161 | teardown() { 162 | let { slider } = this; 163 | 164 | // Remove all event listeners 165 | slider.off(); 166 | 167 | slider.destroy(); 168 | }, 169 | 170 | setValue: observer('start', function() { 171 | let { slider } = this; 172 | 173 | if (slider && !this.sliding) { 174 | let value = this.get('start'); 175 | slider.set(value); 176 | } 177 | }), 178 | 179 | // disabled can't be just `false` - this leads to an attribute of disabled="false" 180 | disabledOrUndefined: computed('disabled', function() { 181 | if (this.get('disabled')) { 182 | return true; 183 | } 184 | return undefined; 185 | }) 186 | }); 187 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/events.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Events

5 | 6 |
7 |
8 |

9 | The range-slider component can send two actions to your route when a 10 | user interacts with the slider. You can set on-change to an 11 | action that will be called when sliding has stopped, or you can 12 | set on-slide to an action for when a user is sliding the 13 | control. 14 |

15 | 16 |
17 | {{range-slider start=model.start range=model.range 18 | on-change=(action "change") 19 | on-slide=(action "slide") 20 | on-update=(action "update") 21 | on-set=(action "setValue") 22 | on-start=(action "started") 23 | on-end=(action "ended")}} 24 |
25 |
Update
26 |
Slide
27 |
Set
28 |
Change
29 |
Start
30 |
End
31 |
32 |
33 | 34 |
35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |
 on-updateon-slideon-seton-change
A handle is released after draggingYesNoYesYes
A slider is moved by tapping itYesYesYesYes
A handle moves while draggingYesYesNoNo
The .set() method is calledYesNoYesNo
77 |
78 |
79 | {{!-- template-lint-disable --}} 80 | {{#source-code language="handlebars"}} 81 | \{{range-slider start=model.start 82 | range=model.range 83 | on-slide=(action "slide") 84 | on-change=(action "changed") 85 | on-update=(action "update") 86 | on-set=(action "setValue") 87 | on-start=(action "started") 88 | on-end=(action "ended")}} 89 | {{/source-code}} 90 | 91 | {{#source-code language="javascript"}} 92 | // app/controller/events.js 93 | import Controller from '@ember/controller'; 94 | 95 | export default Controller.extend({ 96 | actions: { 97 | update(value) { 98 | // updating 99 | }, 100 | changed(value) { 101 | // change event 102 | }, 103 | slide(value) { 104 | // sliding 105 | }, 106 | setValue(value) { 107 | // set event 108 | }, 109 | started(value) { 110 | // sliding started 111 | }, 112 | ended(value) { 113 | // sliding ended 114 | } 115 | } 116 | }); 117 | {{/source-code}} 118 |
119 |
120 | 121 | §

Change

122 |
123 |
124 |

125 | This action is great when you use the slider as 'just-another-input-type'. 126 |

127 |

128 | The name of the action can be changed 129 | by passing an action name to the change parameter 130 |

131 |
132 |
133 | {{!-- template-lint-disable --}} 134 | {{#source-code language="handlebars"}} 135 | \{{range-slider on-change=(action "myAction")}} 136 | {{/source-code}} 137 | {{#source-code language="javascript"}} 138 | // app/controller/events.js 139 | import Controller from '@ember/controller'; 140 | 141 | export default Controller.extend({ 142 | actions: { 143 | myAction(value) { 144 | // ... 145 | } 146 | } 147 | }); 148 | {{/source-code}} 149 |
150 |
151 | 152 | §

Slide

153 |
154 |
155 |

156 | This action is useful when you want to update a value or perform an 157 | action every time a handle is dragged. For example, you can use the 158 | 'slide' action to update graphs. For convenience, this function also 159 | fires on a change by 'tap'. 160 |

161 |

162 | By default no actions are sent, you need to explicitly specify an action 163 | name by setting the on-slide property. 164 |

165 |
166 |
167 | {{!-- template-lint-disable --}} 168 | {{#source-code language="handlebars"}} 169 | \{{range-slider on-slide="slidingAction"}} 170 | {{/source-code}} 171 | {{#source-code language="javascript"}} 172 | // app/controller/events.js 173 | import Controller from '@ember/controller'; 174 | 175 | export default Controller.extend({ 176 | actions: { 177 | slidingAction(value) { 178 | // ... 179 | } 180 | } 181 | }); 182 | {{/source-code}} 183 |
184 |
185 |
186 | -------------------------------------------------------------------------------- /vendor/prism.js: -------------------------------------------------------------------------------- 1 | /* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+handlebars */ 2 | self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{};var Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content),e.alias):"Array"===t.util.type(e)?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(!(d instanceof a)){u.lastIndex=0;var m=u.exec(d);if(m){c&&(f=m[1].length);var y=m.index-1+f,m=m[0].slice(f),v=m.length,k=y+v,b=d.slice(0,y+1),w=d.slice(k+1),N=[p,1];b&&N.push(b);var O=new a(l,g?t.tokenize(m,g):m,h);N.push(O),w&&N.push(w),Array.prototype.splice.apply(r,N)}}}}}return r},hooks:{all:{},add:function(e,n){var a=t.hooks.all;a[e]=a[e]||[],a[e].push(n)},run:function(e,n){var a=t.hooks.all[e];if(a&&a.length)for(var r,i=0;r=a[i++];)r(n)}}},n=t.Token=function(e,t,n){this.type=e,this.content=t,this.alias=n};if(n.stringify=function(e,a,r){if("string"==typeof e)return e;if("Array"===t.util.type(e))return e.map(function(t){return n.stringify(t,a,e)}).join("");var i={type:e.type,content:n.stringify(e.content,a,r),tag:"span",classes:["token",e.type],attributes:{},language:a,parent:r};if("comment"==i.type&&(i.attributes.spellcheck="true"),e.alias){var l="Array"===t.util.type(e.alias)?e.alias:[e.alias];Array.prototype.push.apply(i.classes,l)}t.hooks.run("wrap",i);var s="";for(var o in i.attributes)s+=o+'="'+(i.attributes[o]||"")+'"';return"<"+i.tag+' class="'+i.classes.join(" ")+'" '+s+">"+i.content+""},!self.document)return self.addEventListener?(self.addEventListener("message",function(e){var n=JSON.parse(e.data),a=n.language,r=n.code;self.postMessage(JSON.stringify(t.util.encode(t.tokenize(r,t.languages[a])))),self.close()},!1),self.Prism):self.Prism;var a=document.getElementsByTagName("script");return a=a[a.length-1],a&&(t.filename=a.src,document.addEventListener&&!a.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)),self.Prism}();"undefined"!=typeof module&&module.exports&&(module.exports=Prism);; 3 | Prism.languages.markup={comment://,prolog:/<\?.+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/i,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,inside:{punctuation:/=|>|"/}},punctuation:/\/?>/,"attr-name":{pattern:/[\w:-]+/,inside:{namespace:/^[\w-]+?:/}}}},entity:/&#?[\da-z]{1,8};/i},Prism.hooks.add("wrap",function(t){"entity"===t.type&&(t.attributes.title=t.content.replace(/&/,"&"))});; 4 | Prism.languages.css={comment:/\/\*[\w\W]*?\*\//,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*\{))/i,inside:{punctuation:/[;:]/}},url:/url\((?:(["'])(\\\n|\\?.)*?\1|.*?)\)/i,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/,string:/("|')(\\\n|\\?.)*?\1/,property:/(\b|\B)[\w-]+(?=\s*:)/i,important:/\B!important\b/i,punctuation:/[\{\};:]/,"function":/[-a-z0-9]+(?=\()/i},Prism.languages.markup&&(Prism.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/i,inside:{tag:{pattern:/|<\/style>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css},alias:"language-css"}}),Prism.languages.insertBefore("inside","attr-value",{"style-attr":{pattern:/\s*style=("|').*?\1/i,inside:{"attr-name":{pattern:/^\s*style/i,inside:Prism.languages.markup.tag.inside},punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":{pattern:/.+/i,inside:Prism.languages.css}},alias:"language-css"}},Prism.languages.markup.tag));; 5 | Prism.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\w\W]*?\*\//,lookbehind:!0},{pattern:/(^|[^\\:])\/\/.+/,lookbehind:!0}],string:/("|')(\\\n|\\?.)*?\1/,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(true|false)\b/,"function":{pattern:/[a-z0-9_]+\(/i,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|~|\^|%/,ignore:/&(lt|gt|amp);/i,punctuation:/[{}[\];(),.:]/};; 6 | Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|-?Infinity)\b/,"function":/(?!\d)[a-z0-9_$]+(?=\()/i}),Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}}),Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/i,inside:{tag:{pattern:/|<\/script>/i,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript},alias:"language-javascript"}});; 7 | !function(e){var a=/\{\{\{[\w\W]+?\}\}\}|\{\{[\w\W]+?\}\}/g;e.languages.handlebars=e.languages.extend("markup",{handlebars:{pattern:a,inside:{delimiter:{pattern:/^\{\{\{?|\}\}\}?$/i,alias:"punctuation"},string:/(["'])(\\?.)+?\1/,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/,"boolean":/\b(true|false)\b/,block:{pattern:/^(\s*~?\s*)[#\/]\w+/i,lookbehind:!0,alias:"keyword"},brackets:{pattern:/\[[^\]]+\]/,inside:{punctuation:/\[|\]/,variable:/[\w\W]+/}},punctuation:/[!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]/,variable:/[^!"#%&'()*+,.\/;<=>@\[\\\]^`{|}~]+/}}}),e.languages.insertBefore("handlebars","tag",{"handlebars-comment":{pattern:/\{\{![\w\W]*?\}\}/,alias:["handlebars","comment"]}}),e.hooks.add("before-highlight",function(e){"handlebars"===e.language&&(e.tokenStack=[],e.backupCode=e.code,e.code=e.code.replace(a,function(a){return e.tokenStack.push(a),"___HANDLEBARS"+e.tokenStack.length+"___"}))}),e.hooks.add("before-insert",function(e){"handlebars"===e.language&&(e.code=e.backupCode,delete e.backupCode)}),e.hooks.add("after-highlight",function(a){if("handlebars"===a.language){for(var n,t=0;n=a.tokenStack[t];t++)a.highlightedCode=a.highlightedCode.replace("___HANDLEBARS"+(t+1)+"___",e.highlight(n,a.grammar,"handlebars"));a.element.innerHTML=a.highlightedCode}})}(Prism);; 8 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/_base.scss: -------------------------------------------------------------------------------- 1 | // Copied verbatim from refreshless.com/nouislider 2 | 3 | * { 4 | -moz-box-sizing: border-box; 5 | box-sizing: border-box; 6 | padding: 0; 7 | margin: 0; 8 | border: 0; 9 | } 10 | html { 11 | font: 400 18px/1.75 'Open Sans'; 12 | } 13 | body { 14 | } 15 | 16 | button { 17 | background: #8ad2d3; 18 | font: 700 11px/30px Arial; 19 | text-transform: uppercase; 20 | padding: 0 15px; 21 | border-radius: 4px; 22 | border-bottom: 2px solid rgba(0,0,0,0.1); 23 | color: #fff; 24 | cursor: pointer; 25 | margin: 15px 5px 0 0; 26 | } 27 | input { 28 | padding: 10px; 29 | } 30 | input, select { 31 | border: 1px solid #bfbfbf; 32 | margin: 15px 10px 10px 0; 33 | } 34 | 35 | h1 { 36 | font: 600 50px "Open Sans"; 37 | letter-spacing: -3px; 38 | 39 | margin-bottom: 30px; 40 | } 41 | h2 { 42 | font: 400 30px "Open Sans"; 43 | letter-spacing: -2px; 44 | } 45 | h3 { 46 | font: 600 20px "Open Sans"; 47 | letter-spacing: -1px; 48 | } 49 | h4 { 50 | font: 600 20px "Open Sans"; 51 | letter-spacing: -1px; 52 | margin-bottom: 20px; 53 | } 54 | h5 { 55 | font: 400 52px "Open Sans"; 56 | letter-spacing: -3px; 57 | margin-bottom: 20px; 58 | } 59 | 60 | footer { 61 | padding: 50px 50px 150px; 62 | margin: 0 auto; 63 | max-width: 100%; 64 | width: 1400px; 65 | } 66 | footer a { 67 | display: inline-block; 68 | background: #3498db; 69 | color: #FFF; 70 | font-weight: 700; 71 | padding: 10px 20px; 72 | text-decoration: none; 73 | margin: 5px; 74 | } 75 | footer a:hover { 76 | text-decoration: underline; 77 | } 78 | footer h4 { 79 | margin: 30px 0 10px 7px; 80 | color: #333; 81 | } 82 | 83 | p { 84 | margin-bottom: 10px; 85 | max-width: 650px; 86 | } 87 | 88 | section { 89 | display: table; 90 | table-layout: fixed; 91 | width: 100%; 92 | margin-bottom: 30px; 93 | padding-bottom: 30px; 94 | border-bottom: 1px solid #ddd; 95 | } 96 | section, .jump { 97 | clear: both; 98 | overflow: hidden; 99 | } 100 | 101 | .hi { 102 | padding: 50px 30px; 103 | background: #2980b9; 104 | } 105 | .hi, .bar-group { 106 | box-shadow: 0 2px 10px 0 rgba(0, 0, 0, 0.16), 0 2px 5px 0 rgba(0, 0, 0, 0.26); 107 | } 108 | .hi h1 { 109 | text-align: center; 110 | font-weight: 700; 111 | font-size: 40px; 112 | color: #fff; 113 | margin: 0; 114 | } 115 | .hi h2 { 116 | text-align: center; 117 | color: #fff; 118 | } 119 | .hi-dl { 120 | color: #FFF; 121 | font-size: 22px; 122 | letter-spacing: -1px; 123 | text-decoration: none; 124 | display: table; 125 | border-bottom: 1px solid #FFF; 126 | margin: 30px auto 10px; 127 | text-shadow: 0 1px rgba(0,0,0,0.3); 128 | } 129 | 130 | @media ( min-width: 800px ) { 131 | 132 | .hi { 133 | padding: 100px 0 60px; 134 | } 135 | .hi h1 { 136 | line-height: 100%; 137 | font-family: Trebuchet MS; 138 | font-size: 100px; 139 | margin: 0 auto; 140 | } 141 | .hi h2 { 142 | text-align: right; 143 | font-size: 28px; 144 | margin: -10px auto 30px; 145 | padding-right: 35px; 146 | font-size: 20px; 147 | font-family: Courier; 148 | max-width: 600px; 149 | } 150 | } 151 | 152 | 153 | .bar-group { 154 | text-align: center; 155 | background: #3498db; 156 | margin-bottom: 40px; 157 | } 158 | .bar-link { 159 | color: #FFF; 160 | text-decoration: none; 161 | padding: 20px 15px; 162 | display: inline-block; 163 | } 164 | .bar-link.project { 165 | } 166 | .bar-link.download { 167 | background: #9b59b6; 168 | } 169 | .bar-link:hover { 170 | background: rgba(255,255,255,0.4); 171 | } 172 | 173 | .content { 174 | padding: 0 50px; 175 | margin: 0 auto; 176 | max-width: 100%; 177 | width: 1400px; 178 | } 179 | 180 | .viewer-header { 181 | cursor: pointer; 182 | display: block; 183 | border-bottom: 5px solid rgba(0,0,0,0.1); 184 | background: #BDCDCD; 185 | margin-top: 10px; 186 | font: 700 14px 'Open Sans'; 187 | padding: 10px; 188 | } 189 | .viewer-header:before { 190 | content: "(Click to show code) "; 191 | font: 400 12px Arial; 192 | } 193 | .viewer-content { 194 | overflow: hidden; 195 | max-height: 0; 196 | -webkit-transition: max-height 300ms; 197 | transition: max-height 300ms; 198 | } 199 | .viewer-header.open { 200 | background: #95C4B0; 201 | } 202 | .viewer-header.open:before { 203 | content: ""; 204 | } 205 | .viewer-header.open + .viewer-content { 206 | max-height: 2000px; 207 | } 208 | 209 | .options { 210 | padding: 0 30px 10px 10px; 211 | } 212 | .options > strong { 213 | display: block; 214 | margin-top: 10px; 215 | } 216 | 217 | .inputs { 218 | display: block; 219 | margin: 0 auto 10px; 220 | } 221 | 222 | .example { 223 | position: relative; 224 | padding: 20px 60px 50px 30px; 225 | margin: 20px 0; 226 | font-size: 12px; 227 | line-height: 1em; 228 | } 229 | .example-val { 230 | font: 400 12px Arial; 231 | color: #888; 232 | display: block; 233 | margin: 15px 0; 234 | } 235 | .example-val:before { 236 | content: "Value: "; 237 | font: 700 12px Arial; 238 | } 239 | .example.vertical { 240 | width: 120px; 241 | } 242 | .example.vertical .noUi-target { 243 | height: 150px; 244 | } 245 | .example.tooltips ~ .example.tooltips { 246 | margin-top: 0; 247 | } 248 | 249 | .before-example ~ .example { 250 | margin-top: 0; 251 | } 252 | .before-example ~ .example.vertical .noUi-target { 253 | height: 220px; 254 | } 255 | 256 | .quick { 257 | max-width: 500px; 258 | margin: 0 auto; 259 | } 260 | .quick .noUi-target { 261 | max-width: 300px; 262 | margin: 20px auto 30px; 263 | } 264 | .quick pre { 265 | background: #F3F3F3 !important; 266 | padding: 10px 30px 25px; 267 | margin: 10px auto; 268 | border: 1px solid #BDBDBD; 269 | } 270 | 271 | .logger { 272 | overflow: hidden; 273 | margin-top: 20px; 274 | text-align: center; 275 | } 276 | .logger div { 277 | background-color: #FFF; 278 | -webkit-transition: all 0.25s; 279 | transition: all 0.25s; 280 | padding: 0 5px; 281 | display: inline-block; 282 | margin: 0 2px; 283 | font: 700 10px/26px Arial; 284 | color: #BBB; 285 | text-transform: uppercase; 286 | text-align: center; 287 | border-radius: 4px; 288 | border: 1px solid #ddd; 289 | } 290 | .logger div.tShow { 291 | background-color: #008CBA; 292 | color: #FFF; 293 | } 294 | .logger button { 295 | display: inline-block; 296 | margin: 2px; 297 | } 298 | 299 | .pro-list { 300 | max-width: 300px; 301 | font-size: 17px; 302 | margin: 30px; 303 | list-style: none; 304 | padding: 0; 305 | } 306 | .pro-list li { 307 | margin-bottom: 5px; 308 | position: relative; 309 | } 310 | .pro-list li:before { 311 | content:"\2713\0020"; 312 | display: block; 313 | font-size: 21px; 314 | position: absolute; 315 | left: -22px; 316 | top: 50%; 317 | margin-top: -14px; 318 | color: Teal; 319 | } 320 | 321 | .data-table td { 322 | padding: 10px; 323 | vertical-align: top; 324 | } 325 | .data-table td:first-child, 326 | .data-table th:first-child { 327 | text-align: right; 328 | } 329 | .events-table { 330 | width: 100%; 331 | table-layout: fixed; 332 | text-align: center; 333 | } 334 | .styling-table { 335 | table-layout: fixed; 336 | width: 80%; 337 | text-align: left; 338 | } 339 | .styling-table th { 340 | padding: 10px; 341 | } 342 | 343 | 344 | @media ( min-width: 1100px ) { 345 | 346 | .view, .side, .view-more { 347 | display: table-cell; 348 | vertical-align: top; 349 | } 350 | .view { 351 | width: 490px; 352 | padding: 10px 70px 10px 0; 353 | } 354 | .view p { 355 | max-width: 690px; 356 | } 357 | .view-more { 358 | width: 690px; 359 | padding: 10px 70px 10px 0; 360 | } 361 | } 362 | 363 | @media ( max-width: 800px ) { 364 | 365 | /* Break inline code */ 366 | :not(pre) > code[class*="language-"] { 367 | white-space: pre-wrap; 368 | } 369 | 370 | .content { 371 | padding: 30px; 372 | } 373 | } 374 | 375 | 376 | 377 | 378 | .sect { 379 | float: left; 380 | color: #999; 381 | padding-right: 10px; 382 | display: block; 383 | font-size: 32px; 384 | text-decoration: none; 385 | } 386 | .sect:hover { 387 | color: #333; 388 | } 389 | 390 | 391 | 392 | 393 | /* ------------------------ */ 394 | 395 | #showcase { 396 | margin: 0 20px; 397 | text-align: center; 398 | } 399 | #range { 400 | height: 300px; 401 | margin: 0 auto; 402 | } 403 | #value-span, 404 | #value-input { 405 | width: 50%; 406 | float: left; 407 | display: block; 408 | text-align: center; 409 | margin: 0; 410 | } 411 | .showcase-label { 412 | font: 700 12px Arial; 413 | margin: 15px 0; 414 | display: block; 415 | color: #888; 416 | } 417 | 418 | .pill { 419 | color: #CC333F; 420 | } 421 | 422 | .button { 423 | background-color: #0093a2; 424 | background-image: linear-gradient(#00A0B0, #0093a2); 425 | border-radius: 8px; 426 | display: table; 427 | text-decoration: none; 428 | margin: 30px auto; 429 | font: 700 15px/normal sans-serif; 430 | padding: 13px 25px; 431 | text-align: center; 432 | clear: left; 433 | color: #FFF; 434 | border: 1px solid #008F9D; 435 | } 436 | .button:active { 437 | box-shadow: inset 0 3px 5px rgba(0,0,0,0.125); 438 | } 439 | 440 | .quotable { 441 | font-style: italic; 442 | color: #00A0B0; 443 | font-size: 24px; 444 | font-weight: 400; 445 | } 446 | 447 | .showHTML { 448 | border: 1px solid #bfbfbf; 449 | margin: 10px; 450 | } 451 | .Actual { 452 | padding: 15px 30px; 453 | } 454 | 455 | #moneyForm { 456 | border: 1px solid #000; 457 | padding: 10px; 458 | border-radius: 6px; 459 | } 460 | 461 | .yes { 462 | text-indent: -9999px; 463 | } 464 | .yes span { 465 | display: block; 466 | border-radius: 999px; 467 | width: 10px; 468 | height: 10px; 469 | margin: 0 auto; 470 | background: #95C4B0; 471 | } 472 | .no { 473 | color: #fff; 474 | } 475 | 476 | #red, #green, #blue { 477 | margin: 10px; 478 | display: inline-block; 479 | height: 200px; 480 | } 481 | #colorpicker { 482 | height: 240px; 483 | width: 310px; 484 | margin: 0 auto; 485 | padding: 10px; 486 | border: 1px solid #BFBFBF; 487 | } 488 | #colorpicker .result { 489 | margin: 60px 26px; 490 | height: 100px; 491 | width: 100px; 492 | display: inline-block; 493 | vertical-align: top; 494 | color: rgb(127, 127, 127); 495 | background: rgb(127, 127, 127); 496 | border: 1px solid #fff; 497 | box-shadow: 0 0 10px; 498 | } 499 | #red { 500 | background: #c0392b; 501 | } 502 | #green { 503 | background: #27ae60; 504 | } 505 | #blue { 506 | background: #2980b9; 507 | } 508 | 509 | #input-select, 510 | #input-number { 511 | padding: 7px; 512 | margin: 15px 5px 5px; 513 | width: 70px; 514 | } 515 | #input-types { 516 | width: 300px; 517 | margin: 0 auto; 518 | text-align: center; 519 | } 520 | 521 | .noUi-target.toggle { 522 | height: 50px !important; 523 | } 524 | .noUi-target.toggle.off .noUi-handle { 525 | border-color: red; 526 | } 527 | 528 | .tooltip { 529 | display: block; 530 | position: absolute; 531 | border: 1px solid #D9D9D9; 532 | font: 400 12px/12px Arial; 533 | border-radius: 3px; 534 | background: #fff; 535 | top: -43px; 536 | padding: 5px; 537 | left: -9px; 538 | text-align: center; 539 | width: 50px; 540 | } 541 | .tooltip strong { 542 | display: block; 543 | padding: 2px; 544 | } 545 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/options.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Options

5 | 6 |
7 |
8 |

9 | The range-slider component can be configured with a wide variety of options, 10 | which can be use to customize the slider in to doing exactly what you want. 11 | For options regarding the slider range, see 12 | slider values. 13 |

14 |

15 | These options match near exactly to the 16 | original options 17 | of the noUiSlider plugin. 18 |

19 |

20 | Please make use of the Ember Inspector to see that values of the model 21 | object for this route, and what the values are that gets passed into 22 | each instance of the range-slider component that we render on this 23 | page. 24 |

25 |
26 |
27 | 28 | §

Start

29 |
30 |
31 |

The start option sets the number of handles and their start positions, relative to range.

32 |
33 | {{range-slider start=model.defaultStart range=model.defaultRange}} 34 |
35 | 36 |
37 | Default 38 |
none
39 | 40 | Accepted values 41 |
42 | number,
43 | array[number],
44 | array[number, number] 45 |
46 |
47 |
48 | 49 |
50 | {{!-- template-lint-disable --}} 51 | {{#source-code language="handlebars"}} 52 | \{{range-slider start=model.defaultStart 53 | range=model.defaultRange}} 54 | {{/source-code}} 55 |
56 |
57 | 58 | §

Connect

59 |
60 |
61 |

The connect setting can be used to control the bar between the handles, or the edges of the slider. Use "lower" to connect to the lower side, or "upper" to connect to the upper side. Setting true sets the bar between the handles.

62 | 63 |
64 | {{range-slider start=40 connect="lower" range=model.defaultRange}} 65 |
66 | 67 |
68 | Default 69 |
false
70 | 71 | Accepted values 72 |
"lower", "upper", true, false
73 |
74 |
75 | 76 |
77 | {{!-- template-lint-disable --}} 78 | {{#source-code language="handlebars"}} 79 | \{{range-slider start=40 80 | connect="lower" 81 | range=model.defaultRange}} 82 | {{/source-code}} 83 |
84 |
85 | 86 | 87 | §

Margin

88 |
89 |
90 |

When using two handles, the minimum distance between the handles can be set using the margin option. The margin value is relative to the value set in 'range'. This option is only available on standard linear sliders.

91 | 92 |
93 | {{range-slider start=model.margins margin=30 range=model.defaultRange on-change="marginChanged"}} 94 | {{marginMin}} 95 | {{marginMax}} 96 |
97 | 98 |
99 | Default 100 |
none
101 | 102 | Accepted values 103 |
104 | number 105 |
106 |
107 |
108 | 109 |
110 | {{!-- template-lint-disable --}} 111 | {{#source-code language="handlebars"}} 112 | \{{range-slider start=model.margins 113 | margin=30 114 | range=model.defaultRange}} 115 | {{/source-code}} 116 |
117 |
118 | 119 | §

Limit

120 |
121 |
122 |

The limit option is the oposite of the margin option, limiting the maximum distance between two handles. As with the margin option, the limit option can only be used on linear sliders.

123 |
124 | {{range-slider start=model.limits limit=40 behaviour="drag" connect=true range=model.defaultRange on-change="limitsChanged"}} 125 |
126 | {{limitMin}} 127 | {{limitMax}} 128 |
129 | 130 |
131 | Default 132 |
none
133 | 134 | Accepted values 135 |
136 | number 137 |
138 |
139 |
140 | 141 |
142 | {{!-- template-lint-disable --}} 143 | {{#source-code language="handlebars"}} 144 | \{{range-slider start=model.limits 145 | limit=40 146 | behaviour="drag" 147 | connect=true 148 | range=model.defaultRange}} 149 | {{/source-code}} 150 |
151 |
152 | 153 | §

Padding

154 |
155 |
156 |

Padding limits how close to the slider edges handles can be.

157 |
158 | {{range-slider start=model.padding padding=10 range=model.defaultRange on-change="paddingChanged"}} 159 |
160 | {{paddingMin}} 161 | {{paddingMax}} 162 |
163 | 164 |
165 | Default 166 |
none
167 | 168 | Accepted values 169 |
170 | number,
171 | array[number],
172 | array[number, number] 173 |
174 |
175 |
176 | 177 |
178 | {{!-- template-lint-disable --}} 179 | {{#source-code language="handlebars"}} 180 | \{{range-slider start=model.padding 181 | padding=10 182 | range=model.defaultRange}} 183 | {{/source-code}} 184 |
185 |
186 | 187 | §

Step

188 |
189 |
190 |

By default, the slider slides fluently. In order to make the handles jump between intervals, you can use this option. The step option is relative to the values provided to range.

191 | 192 |
193 | {{range-slider range=model.defaultRange step=10 start=model.steps}} 194 |
195 | 196 |
197 | Default 198 |
none
199 | 200 | Accepted values 201 |
202 | number 203 |
204 |
205 |
206 | 207 |
208 | {{!-- template-lint-disable --}} 209 | {{#source-code language="handlebars"}} 210 | \{{range-slider range=model.defaultRange 211 | step=10 212 | start=model.steps}} 213 | {{/source-code}} 214 |
215 |
216 | 217 | §

Disable

218 |
219 |
220 | 221 |

Set the disable option to true to disable the slider.

222 | 223 |
224 | {{range-slider start=model.defaultStart disabled=model.disabled range=model.defaultRange}} 225 | 232 |
233 | 234 |
235 | Default 236 |
false
237 | 238 | Accepted values 239 |
true, false
240 |
241 |
242 | 243 |
244 | {{!-- template-lint-disable --}} 245 | {{#source-code language="handlebars"}} 246 | \{{range-slider start=model.defaultStart 247 | disabled=model.disabled 248 | range=model.defaultRange}} 249 | {{/source-code}} 250 |
251 |
252 | 253 | §

Orientation

254 |
255 |
256 |

The orientation setting can be used to set the slider to "vertical" or "horizontal".

257 |

Set dimensions! Vertical sliders don't assume a default height, so you'll need to set one. You can use any unit you want, including % or px.

258 | 259 |
260 | {{range-slider start=40 orientation="vertical" range=model.defaultRange}} 261 |
262 | 263 |
264 | Default 265 |
"horizontal"
266 | 267 | Accepted values 268 |
"vertical", "horizontal"
269 |
270 |
271 | 272 |
273 | {{!-- template-lint-disable --}} 274 | {{#source-code language="handlebars"}} 275 | \{{range-slider start=40 276 | orientation="vertical" 277 | range=model.defaultRange}} 278 | {{/source-code}} 279 |
280 |
281 | 282 | §

Direction

283 |
284 |
285 | 286 |

By default the sliders are top-to-bottom and left-to-right, but you can change this using the direction option, which decides where the upper side of the slider is.

287 | 288 |
289 | {{range-slider start=model.direction direction="rtl" range=model.defaultRange on-change="directionChanged"}} 290 | {{model.direction}} 291 |
292 | 293 |
294 | Default 295 |
"ltr"
296 | 297 | Accepted values 298 |
"ltr", "rtl"
299 |
300 |
301 | 302 |
303 | {{!-- template-lint-disable --}} 304 | {{#source-code language="handlebars"}} 305 | \{{range-slider start=model.direction 306 | direction="rtl" 307 | range=model.defaultRange}} 308 | {{/source-code}} 309 |
310 |
311 | 312 | §

Animate

313 |
314 |
315 | 316 |

Set the animate option to false to prevent the slider from animating to a new value with when calling .get().

317 | 318 |
319 | {{range-slider start=model.animate animate=true range=model.defaultRange}} 320 | 321 |
322 | 323 |
324 | {{range-slider start=model.animate animate=false range=model.defaultRange}} 325 |
326 | 327 |
328 | Default 329 |
true
330 | 331 | Accepted values 332 |
true, false
333 |
334 |
335 | 336 |
337 | {{!-- template-lint-disable --}} 338 | {{#source-code language="handlebars"}} 339 | \{{range-slider start=model.animate 340 | animate=true 341 | range=model.defaultRange}} 342 | 343 | \{{range-slider start=model.animate 344 | animate=false 345 | range=model.defaultRange}} 346 | {{/source-code}} 347 |
348 |
349 | 350 | §

Tooltips

351 |
352 |
353 | 354 |

noUiSlider can provide a basic tooltip without using its events system. Set the tooltips option to true to enable. This option can also accept formatting options to format the tooltips content. In that case, pass an array with a formatter for each handle, true to use the default or false to display no tooltip.

355 | 356 |
357 | {{range-slider start=model.defaultStart tooltips=true range=model.defaultRange}} 358 |
359 | 360 |
361 | {{range-slider start=model.defaultStart tooltips=model.tooltips range=model.defaultRange}} 362 |
363 | 364 |
365 | Default 366 |
false
367 | 368 | Accepted values 369 |
true, false, formatter
370 |
array[formatter or false]
371 |
372 |
373 | 374 |
375 | {{!-- template-lint-disable --}} 376 | {{#source-code language="handlebars"}} 377 | \{{range-slider start=model.defaultStart 378 | tooltips=true 379 | range=model.defaultRange}} 380 | 381 | \{{range-slider start=model.defaultStart 382 | tooltips=model.tooltips 383 | range=model.defaultRange}} 384 | {{/source-code}} 385 |
386 |
387 |
388 | --------------------------------------------------------------------------------