From cd1cf470f0f1473d99d7a3a6a27988a5d92a562f Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Fri, 5 Dec 2014 23:53:45 -0600 Subject: [PATCH 01/10] Refactor date picker component to ember cli date picker addon. --- .bowerrc | 4 + .editorconfig | 33 ++ .ember-cli | 9 + .gitignore | 38 +- .jshintrc | 32 ++ .travis.yml | 20 + Brocfile.js | 78 +--- addon/.gitkeep | 0 app/.gitkeep | 0 app/components/.gitkeep | 0 app/components/date-picker-controls.js | 276 +++++++++++ app/components/date-picker-input.js | 40 ++ app/templates/components/.gitkeep | 0 .../components/date-picker-controls.hbs | 20 + blueprints/.gitkeep | 0 blueprints/ember-cli-date-picker/index.js | 13 + bower.json | 27 +- config/environment.js | 5 + dist/ember-date-picker.js | 428 ------------------ dist/ember-date-picker.min.css | 1 - dist/ember-date-picker.min.js | 1 - example/example.css | 6 - example/example.js | 15 - example/index.html | 33 -- index.js | 11 + lib/components/date-picker-controls.js | 284 ------------ lib/components/date-picker-input.js | 45 -- lib/main.js | 37 -- lib/templates-bottom.js | 1 - lib/templates-top.js | 10 - .../components/date-picker-controls.hbs | 20 - package.json | 46 +- testem.json | 11 + tests/.jshintrc | 74 +++ tests/app.js | 4 - tests/dummy/app/app.js | 16 + tests/dummy/app/components/.gitkeep | 0 tests/dummy/app/controllers/.gitkeep | 0 tests/dummy/app/helpers/.gitkeep | 0 tests/dummy/app/index.html | 21 + tests/dummy/app/models/.gitkeep | 0 tests/dummy/app/router.js | 11 + tests/dummy/app/routes/.gitkeep | 0 tests/dummy/app/styles/app.css | 3 + tests/dummy/app/templates/application.hbs | 3 + tests/dummy/app/templates/components/.gitkeep | 0 tests/dummy/app/views/.gitkeep | 0 tests/dummy/config/environment.js | 47 ++ tests/dummy/public/.gitkeep | 0 tests/dummy/public/crossdomain.xml | 15 + tests/dummy/public/robots.txt | 2 + tests/helpers/resolver.js | 11 + tests/helpers/start-app.js | 19 + tests/index.html | 79 ++-- tests/test-helper.js | 12 + tests/tests.js | 97 ---- tests/unit/.gitkeep | 0 vendor/.gitkeep | 0 {dist => vendor}/ember-date-picker.css | 0 {lib/styles => vendor}/ember-date-picker.less | 0 60 files changed, 825 insertions(+), 1133 deletions(-) create mode 100644 .bowerrc create mode 100644 .editorconfig create mode 100644 .ember-cli create mode 100644 .jshintrc create mode 100644 .travis.yml create mode 100644 addon/.gitkeep create mode 100644 app/.gitkeep create mode 100644 app/components/.gitkeep create mode 100644 app/components/date-picker-controls.js create mode 100644 app/components/date-picker-input.js create mode 100644 app/templates/components/.gitkeep create mode 100644 app/templates/components/date-picker-controls.hbs create mode 100644 blueprints/.gitkeep create mode 100644 blueprints/ember-cli-date-picker/index.js create mode 100644 config/environment.js delete mode 100644 dist/ember-date-picker.js delete mode 100644 dist/ember-date-picker.min.css delete mode 100644 dist/ember-date-picker.min.js delete mode 100644 example/example.css delete mode 100644 example/example.js delete mode 100644 example/index.html create mode 100644 index.js delete mode 100644 lib/components/date-picker-controls.js delete mode 100644 lib/components/date-picker-input.js delete mode 100644 lib/main.js delete mode 100644 lib/templates-bottom.js delete mode 100644 lib/templates-top.js delete mode 100644 lib/templates/components/date-picker-controls.hbs create mode 100644 testem.json create mode 100644 tests/.jshintrc delete mode 100644 tests/app.js create mode 100644 tests/dummy/app/app.js create mode 100644 tests/dummy/app/components/.gitkeep create mode 100644 tests/dummy/app/controllers/.gitkeep create mode 100644 tests/dummy/app/helpers/.gitkeep create mode 100644 tests/dummy/app/index.html create mode 100644 tests/dummy/app/models/.gitkeep create mode 100644 tests/dummy/app/router.js create mode 100644 tests/dummy/app/routes/.gitkeep create mode 100644 tests/dummy/app/styles/app.css create mode 100644 tests/dummy/app/templates/application.hbs create mode 100644 tests/dummy/app/templates/components/.gitkeep create mode 100644 tests/dummy/app/views/.gitkeep create mode 100644 tests/dummy/config/environment.js create mode 100644 tests/dummy/public/.gitkeep create mode 100644 tests/dummy/public/crossdomain.xml create mode 100644 tests/dummy/public/robots.txt create mode 100644 tests/helpers/resolver.js create mode 100644 tests/helpers/start-app.js create mode 100644 tests/test-helper.js delete mode 100644 tests/tests.js create mode 100644 tests/unit/.gitkeep create mode 100644 vendor/.gitkeep rename {dist => vendor}/ember-date-picker.css (100%) rename {lib/styles => vendor}/ember-date-picker.less (100%) diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..959e169 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,4 @@ +{ + "directory": "bower_components", + "analytics": false +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5d5dea4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,33 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[*.hbs] +indent_style = space +indent_size = 2 + +[*.css] +indent_style = space +indent_size = 2 + +[*.html] +indent_style = space +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false diff --git a/.ember-cli b/.ember-cli new file mode 100644 index 0000000..ee64cfe --- /dev/null +++ b/.ember-cli @@ -0,0 +1,9 @@ +{ + /** + Ember CLI sends analytics information by default. The data is completely + anonymous, but there are times when you might want to disable this behavior. + + Setting `disableAnalytics` to true will prevent any data from being sent. + */ + "disableAnalytics": false +} diff --git a/.gitignore b/.gitignore index 56a4259..86fceae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,17 @@ -# bower -bower_components +# See http://help.github.com/ignore-files/ for more about ignoring files. -# node -node_modules +# compiled output +/dist +/tmp -# temporary/dev files and directories -tmp +# dependencies +/node_modules +/bower_components -# sublime text -*.sublime-workspace -*.sublime-project - -# windows -Thumbs.db -ehthumbs.db -Desktop.ini - -# osx -.DS_Store -.DS_Store? -.AppleDouble -.LSOverride -.Spotlight-V100 -.Trashes -._* -Icon +# misc +/.sass-cache +/connect.lock +/coverage/* +/libpeerconnection.log +npm-debug.log +testem.log diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..08096ef --- /dev/null +++ b/.jshintrc @@ -0,0 +1,32 @@ +{ + "predef": [ + "document", + "window", + "-Promise" + ], + "browser": true, + "boss": true, + "curly": true, + "debug": false, + "devel": true, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "eqnull": true, + "esnext": true, + "unused": true +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..cf23938 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +--- +language: node_js + +sudo: false + +cache: + directories: + - node_modules + +before_install: + - "npm config set spin false" + - "npm install -g npm@^2" + +install: + - npm install -g bower + - npm install + - bower install + +script: + - npm test diff --git a/Brocfile.js b/Brocfile.js index 66aff97..042a64d 100644 --- a/Brocfile.js +++ b/Brocfile.js @@ -1,65 +1,21 @@ -var env = require('broccoli-env').getEnv(), - mergeTrees = require('broccoli-merge-trees'), - pickFiles = require('broccoli-static-compiler'), - concat = require('broccoli-concat'), - uglifyJs = require('broccoli-uglify-js'), - compileLess = require('broccoli-less-single'), - buildTemplates = require('broccoli-template-builder'), - compileTemplates = require('ember-template-compiler'), - sourceTree = 'lib', - templatesTree = 'lib/templates', - stylesTree = 'lib/styles', - templates, - js, - css, - prodJs, - prodCss; +/* jshint node: true */ +/* global require, module */ -templates = buildTemplates(templatesTree, { - extensions: ['hbs'], - outputFile: 'templates.js', - namespace: 'Ember.TEMPLATES', - compile: function(string) { - return 'Ember.Handlebars.template(' + compileTemplates.precompile(string) + ')'; - } -}); +var EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); -js = concat(mergeTrees([templates, sourceTree]), { - inputFiles: [ - 'components/**/*.js', - 'templates-top.js', - 'templates.js', - 'templates-bottom.js', - 'main.js' - ], - outputFile: '/ember-date-picker.js' -}); +var app = new EmberAddon(); -css = compileLess( - [stylesTree], - 'ember-date-picker.less', - 'ember-date-picker.css' -); +// Use `app.import` to add additional libraries to the generated +// output files. +// +// If you need to use different assets in different +// environments, specify an object as the first parameter. That +// object's keys should be the environment name and the values +// should be the asset to use in that environment. +// +// If the library that you are including contains AMD or ES6 +// modules that you would like to import into your application +// please specify an object with the list of modules as keys +// along with the exports of each module as its value. -//create minified versions for production -if(env === 'production') { - prodJs = uglifyJs(concat(mergeTrees([templates, sourceTree]), { - inputFiles: [ - 'components/**/*.js', - 'templates-top.js', - 'templates.js', - 'templates-bottom.js', - 'main.js' - ], - outputFile: '/ember-date-picker.min.js' - })); - - prodCss = compileLess( - [stylesTree], - 'ember-date-picker.less', - 'ember-date-picker.min.css', - {cleancss: true} - ); -} - -module.exports = mergeTrees(env === 'production' ? [prodJs, prodCss, js, css] : [js, css]); \ No newline at end of file +module.exports = app.toTree(); diff --git a/addon/.gitkeep b/addon/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/.gitkeep b/app/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/components/.gitkeep b/app/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/components/date-picker-controls.js b/app/components/date-picker-controls.js new file mode 100644 index 0000000..1bc23a9 --- /dev/null +++ b/app/components/date-picker-controls.js @@ -0,0 +1,276 @@ +import Ember from 'ember'; + +export default Ember.Component.extend({ + + classNames: ['datepicker-controls'], + classNameBindings: ['_isOpen:shown', '_animate:animate'], + layoutName: 'components/date-picker-controls', + animateDuration: 300, + repeatInterval: 150, + repeatDelay: 500, + + _defaults: { + minYear: false, + maxYear: false, + dateFormat: null, + i18n: { + done: "Done", + clear: "Clear", + today: "Today", + monthNames: [ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + ] + } + }, + + _isOpen: false, + _animate: false, + _currentTarget: null, + _currentMonth: null, + _currentDay: null, + _currentYear: null, + + setConfig: Ember.on('init', function() { + //sanity check provided settings/set defaults where necessary + var config = {}; + if(Ember.isEmpty(this.get('minYear'))) config.minYear = this.get('_defaults.minYear'); + if(Ember.isEmpty(this.get('maxYear'))) config.maxYear = this.get('_defaults.maxYear'); + if(Ember.isBlank(this.get('dateFormat'))) config.dateFormat = this.get('_defaults.dateFormat'); + if(Ember.isEmpty(this.get('i18n'))) config.i18n = this.get('_defaults.i18n'); + + //allow relative minYear/maxYear values to the current year (e.g. "-100", "+50") + config.minYear = this.convertRelativeYear(this.get('minYear')); + config.maxYear = this.convertRelativeYear(this.get('maxYear')); + + this.setProperties(config); + }), + + setup: Ember.on('didInsertElement', function() { + this.$el = this.$(); + Ember.$(document).on('click.date-picker-events', Ember.run.bind(this, this.handleDocClick)); + }), + + teardown: Ember.on('willDestroyElement', function() { + Ember.$(document).off('.date-picker-events'); + }), + + handleDocClick: function(e) { + if(this.get('_currentTarget') && + e.target !== this.get('_currentTarget').$el.get(0) && + !Ember.$.contains(this.$el.get(0), e.target)) { + this.closePicker(); + } + }, + + handleKeyDown: Ember.on('keyDown', function() { + switch(e.keyCode) { + //enter + case 13: + this.updateValue(); + this.closePicker(); + break; + //esc + case 27: + this.closePicker(); + break; + } + }), + + convertRelativeYear: function(relValue) { + if(typeof relValue !== 'string') { + return relValue; + } + + relValue = parseInt(relValue, 10); + return !isNaN(relValue) ? new Date().getFullYear() + relValue : false; + }, + + getMonthIndex: function(monthName) { + var months = this.get('i18n.monthNames'), + index = months.indexOf(monthName); + return index === -1 ? 0 : index; + }, + + getMonthName: function(index) { + return this.get('i18n.monthNames')[index]; + }, + + months: function() { + return this.get('i18n.monthNames'); + }.property('i18n'), + + days: function() { + var days = [], + daysInMonth = this.getDaysInMonth(this.get('_currentYear'), this.getMonthIndex(this.get('_currentMonth'))); + + for(var i=1; i<=daysInMonth; i++) { + days.push(i); + } + + return days; + }.property('_currentMonth', '_currentYear'), + + years: function() { + var min = this.get('minYear'), + max = this.get('maxYear'); + return [typeof min === 'number' ? min : 1, typeof max === 'number' ? max : 9999]; + }.property('minYear', 'maxYear'), + + openPicker: function(target) { + var date; + if(!target) return; + this.set('_currentTarget', target); + + //if the input component defines is own settings, use them instead of the control component's settings + this.setProperties({ + inputMinYear: typeof target.get('minYear') !== 'undefined' ? this.convertRelativeYear(target.get('minYear')) : undefined, + inputMaxYear: typeof target.get('maxYear') !== 'undefined' ? this.convertRelativeYear(target.get('maxYear')) : undefined, + inputDateFormat : !Ember.isBlank(target.get('dateFormat')) ? target.get('dateFormat') : undefined + }); + + try { + date = this.parseDate(target.get('value'), this.getConfig('dateFormat')); + } catch(e) { + date = null; + } + + this.setCurrentValue(date); + this.positionPicker(target.$el); + this.set('_isOpen', true); + Ember.run.next(this, function() { + this.set('_animate', true); + }); + }, + + closePicker: function() { + this.setProperties({ + _animate: false, + _currentTarget: false + }); + + Ember.run.later(this, function() { + this.set('_isOpen', false); + }, this.get('animateDuration')); + }, + + positionPicker: function(inputEl) { + if(!inputEl) return; + + var offset = inputEl.position(), + height = inputEl.outerHeight(); + + this.$el.css({ + top: (offset.top + height) + 'px', + left: offset.left + 'px' + }); + }, + + selectedDate: function() { + var month = this.getMonthIndex(this.get('_currentMonth')), + year = this.get('_currentYear'), + daysInMonth = this.getDaysInMonth(year, month), + day = this.get('_currentDay') > daysInMonth ? 1 : this.get('_currentDay'); + + return this.formatDate(new Date(year, month, day), this.getConfig('dateFormat')); + }.property('dateFormat', 'inputDateFormat', '_currentMonth', '_currentDay', '_currentYear'), + + clearValue: function() { + if(!this.get('_currentTarget')) return; + this.get('_currentTarget').set('value', null); + this.get('_currentTarget').sendAction('onUpdate', null); + }, + + updateValue: function() { + var formattedDate = this.get('selectedDate'); + if(!this.get('_currentTarget')) return; + this.get('_currentTarget').set('value', formattedDate); + this.get('_currentTarget').sendAction('onUpdate', formattedDate); + }, + + setCurrentValue: function(date, updateValue) { + //if a date is not provided or is invalid, default to the current date + date = date || new Date(); + + this.setProperties({ + _currentMonth: this.getMonthName(date.getMonth()), + _currentYear: date.getFullYear() + }); + + Ember.run.scheduleOnce('sync', this, function() { + this.set('_currentDay', date.getDate()); + if(updateValue) { + this.updateValue(); + } + }); + }, + + getConfig: function(prop) { + var inputProp = 'input' + Ember.String.capitalize(prop); + return this.get(typeof this.get(inputProp) !== 'undefined' ? inputProp : prop); + }, + + getDaysInMonth: function(year, month) { + return 32 - this.daylightSavingAdjust(new Date(year, month, 32)).getDate(); + }, + + daylightSavingAdjust: function(date) { + if(!date) { + return null; + } + + date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); + return date; + }, + + parseDate: function(dateString, format) { + var date; + if(this.get('hasMoment')) { + date = Ember.isBlank(format) ? moment(dateString) : moment(dateString, format); + date = !date.isValid() ? null : date.toDate(); + } else { + date = Date.parse(dateString); + date = isNaN(date) ? null : new Date(date); + } + + return date; + }, + + formatDate: function(date, format) { + var formattedDate = null; + + if(!Ember.isNone(date)) { + formattedDate = this.get('hasMoment') ? + moment(date).format(Ember.isBlank(format) ? 'l' : format) : + date.toLocaleDateString(); + } + + return formattedDate; + }, + + hasMoment: function() { + return typeof moment === 'function'; + }.property(), + + actions: { + clear: function() { + this.clearValue(); + this.closePicker(); + }, + + done: function() { + this.updateValue(); + this.closePicker(); + }, + + today: function() { + this.setCurrentValue(null, true); + }, + + spinBoxUpdate: function(newVal) { + this.updateValue(); + } + } + +}); + diff --git a/app/components/date-picker-input.js b/app/components/date-picker-input.js new file mode 100644 index 0000000..baf9af1 --- /dev/null +++ b/app/components/date-picker-input.js @@ -0,0 +1,40 @@ +'use strict'; + +import Ember from 'ember'; + +export default Ember.Component.extend({ + + tagName: 'input', + attributeBindings: ['type', 'value', 'readonly', 'placeholder'], + classNames: ['datepicker-input'], + type: 'text', + readonly: true, + placeholder: null, + value: null, + picker: false, + + setup: Ember.on('didInsertElement', function() { + Ember.run.later(this, function() { + var controlsCmp = Ember.View.views[this.get('controls')]; + this.$el = this.$(); + + if(controlsCmp && typeof controlsCmp.openPicker === 'function') { + this.set('picker', controlsCmp); + } + }); + }), + + click: function() { + if(!this.get('picker')) { return; } + this.get('picker').openPicker(this); + }, + + handleKeyDown: Ember.on('keyDown', function() { + if(!this.get('picker')) return; + if(e.keyCode == 27) { + this.get('picker').closePicker(); + this.$el.blur(); + } + }) + +}); diff --git a/app/templates/components/.gitkeep b/app/templates/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/app/templates/components/date-picker-controls.hbs b/app/templates/components/date-picker-controls.hbs new file mode 100644 index 0000000..22b04fa --- /dev/null +++ b/app/templates/components/date-picker-controls.hbs @@ -0,0 +1,20 @@ +
+
+ + + +
+
+
+
+ {{spin-box content=months value=_currentMonth onUpdate="spinBoxUpdate" rowHeight=32 tabindex=1}} +
+
+ {{spin-box content=days value=_currentDay onUpdate="spinBoxUpdate" rowHeight=32 tabindex=2}} +
+
+ {{spin-box range=years value=_currentYear onUpdate="spinBoxUpdate" rowHeight=32 tabindex=3}} +
+
+
+
diff --git a/blueprints/.gitkeep b/blueprints/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/blueprints/ember-cli-date-picker/index.js b/blueprints/ember-cli-date-picker/index.js new file mode 100644 index 0000000..3622590 --- /dev/null +++ b/blueprints/ember-cli-date-picker/index.js @@ -0,0 +1,13 @@ +'use strict'; + +module.exports = { + name: 'ember-date-picker', + + normalizeEntityName: function() { }, + + afterInstall: function() { + return this.addBowerPackagesToProject([ + {name: 'ember-spin-box', target: '~0.0.5'} + ]); + } +}; diff --git a/bower.json b/bower.json index bff1f47..fd08544 100644 --- a/bower.json +++ b/bower.json @@ -1,20 +1,17 @@ { "name": "ember-date-picker", - "version": "0.0.4", - "description": "A lightweight, mobile-optimized, date picker component for ember.js applications.", - "author": "Bill Dami ", - "license": "MIT", - "ignore": [ - "**/.*" - ], - "devDependencies": { - "jquery": "~2.0.3", - "handlebars": "1.3.0", - "ember": "~1.5.0", - "qunit": "~1.14.0" - }, "dependencies": { - "ember-spin-box": "~0.0.5", - "momentjs": "~2.6.0" + "handlebars": "~1.3.0", + "jquery": "^1.11.1", + "ember": "1.8.1", + "ember-data": "1.0.0-beta.11", + "ember-resolver": "~0.1.10", + "loader.js": "stefanpenner/loader.js#1.0.1", + "ember-cli-shims": "stefanpenner/ember-cli-shims#0.0.3", + "ember-cli-test-loader": "rwjblue/ember-cli-test-loader#0.0.4", + "ember-load-initializers": "stefanpenner/ember-load-initializers#0.0.2", + "ember-qunit": "0.1.8", + "ember-qunit-notifications": "0.0.4", + "qunit": "~1.15.0" } } diff --git a/config/environment.js b/config/environment.js new file mode 100644 index 0000000..0dfaed4 --- /dev/null +++ b/config/environment.js @@ -0,0 +1,5 @@ +'use strict'; + +module.exports = function(/* environment, appConfig */) { + return { }; +}; diff --git a/dist/ember-date-picker.js b/dist/ember-date-picker.js deleted file mode 100644 index 8cd1853..0000000 --- a/dist/ember-date-picker.js +++ /dev/null @@ -1,428 +0,0 @@ -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define(['ember'], function(Ember) { return factory(Ember); }); - } else if(typeof exports === 'object') { - module.exports = factory(require('ember')); - } else { - root.DatePickerControlsComponent = factory(Ember); - } -})(this, function(Ember) { - - var DatePickerControlsComponent = Ember.Component.extend({ - classNames: ['datepicker-controls'], - classNameBindings: ['_isOpen:shown', '_animate:animate'], - layoutName: 'components/date-picker-controls', - animateDuration: 300, - repeatInterval: 150, - repeatDelay: 500, - - _defaults: { - minYear: false, - maxYear: false, - dateFormat: null, - i18n: { - done: "Done", - clear: "Clear", - today: "Today", - monthNames: [ - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - ] - } - }, - - _isOpen: false, - _animate: false, - _currentTarget: null, - _currentMonth: null, - _currentDay: null, - _currentYear: null, - - setConfig: function() { - //sanity check provided settings/set defaults where necessary - var config = {}; - if(Ember.isEmpty(this.get('minYear'))) config.minYear = this.get('_defaults.minYear'); - if(Ember.isEmpty(this.get('maxYear'))) config.maxYear = this.get('_defaults.maxYear'); - if(Ember.isBlank(this.get('dateFormat'))) config.dateFormat = this.get('_defaults.dateFormat'); - if(Ember.isEmpty(this.get('i18n'))) config.i18n = this.get('_defaults.i18n'); - - //allow relative minYear/maxYear values to the current year (e.g. "-100", "+50") - config.minYear = this.convertRelativeYear(this.get('minYear')); - config.maxYear = this.convertRelativeYear(this.get('maxYear')); - - this.setProperties(config); - }.on('init'), - - setup: function() { - this.$el = this.$(); - Ember.$(document).on('click.date-picker-events', Ember.run.bind(this, this.handleDocClick)); - }.on('didInsertElement'), - - teardown: function() { - Ember.$(document).off('.date-picker-events'); - }.on('willDestroyElement'), - - handleDocClick: function(e) { - if(this.get('_currentTarget') && - e.target !== this.get('_currentTarget').$el.get(0) && - !Ember.$.contains(this.$el.get(0), e.target)) { - this.closePicker(); - } - }, - - handleKeyDown: function(e) { - switch(e.keyCode) { - //enter - case 13: - this.updateValue(); - this.closePicker(); - break; - //esc - case 27: - this.closePicker(); - break; - } - }.on('keyDown'), - - convertRelativeYear: function(relValue) { - if(typeof relValue !== 'string') { - return relValue; - } - - relValue = parseInt(relValue, 10); - return !isNaN(relValue) ? new Date().getFullYear() + relValue : false; - }, - - getMonthIndex: function(monthName) { - var months = this.get('i18n.monthNames'), - index = months.indexOf(monthName); - return index === -1 ? 0 : index; - }, - - getMonthName: function(index) { - return this.get('i18n.monthNames')[index]; - }, - - months: function() { - return this.get('i18n.monthNames'); - }.property('i18n'), - - days: function() { - var days = [], - daysInMonth = this.getDaysInMonth(this.get('_currentYear'), this.getMonthIndex(this.get('_currentMonth'))); - - for(var i=1; i<=daysInMonth; i++) { - days.push(i); - } - - return days; - }.property('_currentMonth', '_currentYear'), - - years: function() { - var min = this.get('minYear'), - max = this.get('maxYear'); - return [typeof min === 'number' ? min : 1, typeof max === 'number' ? max : 9999]; - }.property('minYear', 'maxYear'), - - openPicker: function(target) { - var date; - if(!target) return; - this.set('_currentTarget', target); - - //if the input component defines is own settings, use them instead of the control component's settings - this.setProperties({ - inputMinYear: typeof target.get('minYear') !== 'undefined' ? this.convertRelativeYear(target.get('minYear')) : undefined, - inputMaxYear: typeof target.get('maxYear') !== 'undefined' ? this.convertRelativeYear(target.get('maxYear')) : undefined, - inputDateFormat : !Ember.isBlank(target.get('dateFormat')) ? target.get('dateFormat') : undefined - }); - - try { - date = this.parseDate(target.get('value'), this.getConfig('dateFormat')); - } catch(e) { - date = null; - } - - this.setCurrentValue(date); - this.positionPicker(target.$el); - this.set('_isOpen', true); - Ember.run.next(this, function() { - this.set('_animate', true); - }); - }, - - closePicker: function() { - this.setProperties({ - _animate: false, - _currentTarget: false - }); - - Ember.run.later(this, function() { - this.set('_isOpen', false); - }, this.get('animateDuration')); - }, - - positionPicker: function(inputEl) { - if(!inputEl) return; - - var offset = inputEl.position(), - height = inputEl.outerHeight(); - - this.$el.css({ - top: (offset.top + height) + 'px', - left: offset.left + 'px' - }); - }, - - selectedDate: function() { - var month = this.getMonthIndex(this.get('_currentMonth')), - year = this.get('_currentYear'), - daysInMonth = this.getDaysInMonth(year, month), - day = this.get('_currentDay') > daysInMonth ? 1 : this.get('_currentDay'); - - return this.formatDate(new Date(year, month, day), this.getConfig('dateFormat')); - }.property('dateFormat', 'inputDateFormat', '_currentMonth', '_currentDay', '_currentYear'), - - clearValue: function() { - if(!this.get('_currentTarget')) return; - this.get('_currentTarget').set('value', null); - this.get('_currentTarget').sendAction('onUpdate', null); - }, - - updateValue: function() { - var formattedDate = this.get('selectedDate'); - if(!this.get('_currentTarget')) return; - this.get('_currentTarget').set('value', formattedDate); - this.get('_currentTarget').sendAction('onUpdate', formattedDate); - }, - - setCurrentValue: function(date, updateValue) { - //if a date is not provided or is invalid, default to the current date - date = date || new Date(); - - this.setProperties({ - _currentMonth: this.getMonthName(date.getMonth()), - _currentYear: date.getFullYear() - }); - - Ember.run.scheduleOnce('sync', this, function() { - this.set('_currentDay', date.getDate()); - if(updateValue) { - this.updateValue(); - } - }); - }, - - getConfig: function(prop) { - var inputProp = 'input' + Ember.String.capitalize(prop); - return this.get(typeof this.get(inputProp) !== 'undefined' ? inputProp : prop); - }, - - getDaysInMonth: function(year, month) { - return 32 - this.daylightSavingAdjust(new Date(year, month, 32)).getDate(); - }, - - daylightSavingAdjust: function(date) { - if(!date) { - return null; - } - - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; - }, - - parseDate: function(dateString, format) { - var date; - if(this.get('hasMoment')) { - date = Ember.isBlank(format) ? moment(dateString) : moment(dateString, format); - date = !date.isValid() ? null : date.toDate(); - } else { - date = Date.parse(dateString); - date = isNaN(date) ? null : new Date(date); - } - - return date; - }, - - formatDate: function(date, format) { - var formattedDate = null; - - if(!Ember.isNone(date)) { - formattedDate = this.get('hasMoment') ? - moment(date).format(Ember.isBlank(format) ? 'l' : format) : - date.toLocaleDateString(); - } - - return formattedDate; - }, - - hasMoment: function() { - return typeof moment === 'function'; - }.property(), - - actions: { - clear: function() { - this.clearValue(); - this.closePicker(); - }, - - done: function() { - this.updateValue(); - this.closePicker(); - }, - - today: function() { - this.setCurrentValue(null, true); - }, - - spinBoxUpdate: function(newVal) { - this.updateValue(); - } - } - }); - - return DatePickerControlsComponent; -}); -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define(['ember'], function(Ember) { return factory(Ember); }); - } else if(typeof exports === 'object') { - module.exports = factory(require('ember')); - } else { - root.DatePickerInputComponent = factory(Ember); - } -})(this, function(Ember) { - - var DatePickerInputComponent = Ember.Component.extend({ - tagName: 'input', - attributeBindings: ['type', 'value', 'readonly', 'placeholder'], - classNames: ['datepicker-input'], - type: 'text', - readonly: true, - placeholder: null, - value: null, - picker: false, - - setup: function() { - var controlsCmp = Ember.View.views[this.get('controls')]; - this.$el = this.$(); - - if(controlsCmp && typeof controlsCmp.openPicker === 'function') { - this.set('picker', controlsCmp); - } - }.on('didInsertElement'), - - handleFocusIn: function(e) { - if(!this.get('picker')) return; - this.get('picker').openPicker(this); - }.on('focusIn'), - - handleKeyDown: function(e) { - if(!this.get('picker')) return; - if(e.keyCode == 27) { - this.get('picker').closePicker(); - this.$el.blur(); - } - }.on('keyDown') - }); - - return DatePickerInputComponent; -}); -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define(['ember'], function(Ember) { return factory(Ember); }); - } else if(typeof exports === 'object') { - factory(require('ember')); - } else { - factory(Ember); - } -})(this, function(Ember) { - - -Ember.TEMPLATES["components/date-picker-controls"]=Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data) { -this.compilerInfo = [4,'>= 1.0.0']; -helpers = this.merge(helpers, Ember.Handlebars.helpers); data = data || {}; - var buffer = '', stack1, helper, options, escapeExpression=this.escapeExpression, helperMissing=helpers.helperMissing; - - - data.buffer.push("
\n
\n \n \n \n
\n
\n
\n
\n "); - data.buffer.push(escapeExpression((helper = helpers['spin-box'] || (depth0 && depth0['spin-box']),options={hash:{ - 'content': ("months"), - 'value': ("_currentMonth"), - 'onUpdate': ("spinBoxUpdate"), - 'rowHeight': (32), - 'tabindex': (1) - },hashTypes:{'content': "ID",'value': "ID",'onUpdate': "STRING",'rowHeight': "INTEGER",'tabindex': "INTEGER"},hashContexts:{'content': depth0,'value': depth0,'onUpdate': depth0,'rowHeight': depth0,'tabindex': depth0},contexts:[],types:[],data:data},helper ? helper.call(depth0, options) : helperMissing.call(depth0, "spin-box", options)))); - data.buffer.push("\n
\n
\n "); - data.buffer.push(escapeExpression((helper = helpers['spin-box'] || (depth0 && depth0['spin-box']),options={hash:{ - 'content': ("days"), - 'value': ("_currentDay"), - 'onUpdate': ("spinBoxUpdate"), - 'rowHeight': (32), - 'tabindex': (2) - },hashTypes:{'content': "ID",'value': "ID",'onUpdate': "STRING",'rowHeight': "INTEGER",'tabindex': "INTEGER"},hashContexts:{'content': depth0,'value': depth0,'onUpdate': depth0,'rowHeight': depth0,'tabindex': depth0},contexts:[],types:[],data:data},helper ? helper.call(depth0, options) : helperMissing.call(depth0, "spin-box", options)))); - data.buffer.push("\n
\n
\n "); - data.buffer.push(escapeExpression((helper = helpers['spin-box'] || (depth0 && depth0['spin-box']),options={hash:{ - 'range': ("years"), - 'value': ("_currentYear"), - 'onUpdate': ("spinBoxUpdate"), - 'rowHeight': (32), - 'tabindex': (3) - },hashTypes:{'range': "ID",'value': "ID",'onUpdate': "STRING",'rowHeight': "INTEGER",'tabindex': "INTEGER"},hashContexts:{'range': depth0,'value': depth0,'onUpdate': depth0,'rowHeight': depth0,'tabindex': depth0},contexts:[],types:[],data:data},helper ? helper.call(depth0, options) : helperMissing.call(depth0, "spin-box", options)))); - data.buffer.push("\n
\n
\n
\n
"); - return buffer; - -}); - -}); -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define([ - 'ember', - './components/date-picker-controls.js', - './components/date-picker-input.js', - ], function(Ember, Controls, Input) { - return factory(Ember, Controls, Input); - }); - } else if(typeof exports === 'object') { - module.exports = factory( - require('ember'), - require('./components/date-picker-controls.js'), - require('./components/date-picker-input.js') - ); - } else { - factory( - Ember, - root.DatePickerControlsComponent, - root.DatePickerInputComponent - ); - } -})(this, function(Ember, Controls, Input) { - - Ember.Application.initializer({ - name: 'date-picker', - initialize: function(container, application) { - container.register('component:date-picker-controls', Controls); - container.register('component:date-picker-input', Input); - } - }); - - return { - DatePickerControls: Controls, - DatePickerInput: Input - }; -}); \ No newline at end of file diff --git a/dist/ember-date-picker.min.css b/dist/ember-date-picker.min.css deleted file mode 100644 index 08300eb..0000000 --- a/dist/ember-date-picker.min.css +++ /dev/null @@ -1 +0,0 @@ -.datepicker-left{float:left}.datepicker-right{float:right}.datepicker-clearfix:before,.datepicker-clearfix:after{content:" ";display:table}.datepicker-clearfix:after{clear:both}.datepicker-input[readonly]{cursor:default;background-color:#fff}.datepicker-controls{display:none;position:absolute;z-index:1;margin-top:7px;width:260px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.datepicker-controls.shown{display:block}.datepicker-controls *,.datepicker-controls :before,.datepicker-controls :after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.datepicker-controls-inner{border:1px solid #ccc;opacity:0;filter:alpha(opacity=0);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);-moz-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);-webkit-transition:all .3s;-moz-transition:all .3s;-ms-transition:all .3s;-o-transition:all .3s;transition:all .3s}.datepicker-controls-inner:before,.datepicker-controls-inner:after{content:" ";position:absolute;top:-15px;left:20px;display:block;width:0;height:0;pointer-events:none;border-color:transparent;border-style:solid}.datepicker-controls-inner:before{border-width:8px;border-bottom-color:#ccc}.datepicker-controls-inner:after{border-width:7px;border-bottom-color:#f0f0f0;margin-top:2px;margin-left:1px}.animate .datepicker-controls-inner{opacity:1;filter:alpha(opacity=100)}.datepicker-toolbar{padding:4px;background:#f0f0f0;border-bottom:1px solid #ccc;border-top-left-radius:4px;border-top-right-radius:4px}.datepicker-toolbar .datepicker-btn{margin-left:4px}.datepicker-toolbar .datepicker-btn:first-child{margin-left:0}.datepicker-btn{padding:4px 8px}.datepicker-cols-ct{padding:8px;background-color:#f5f5f5;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.datepicker-col{float:left;position:relative;min-height:1px}.datepicker-col .spinbox{position:relative;width:auto;margin-left:-1px;margin-top:-1px;background:#fff;-webkit-box-shadow:inset 0 26px 32px -34px rgba(0,0,0,.44),inset 0 -26px 32px -34px rgba(0,0,0,.44);-moz-box-shadow:inset 0 26px 32px -34px rgba(0,0,0,.44),inset 0 -26px 32px -34px rgba(0,0,0,.44);box-shadow:inset 0 26px 32px -34px rgba(0,0,0,.44),inset 0 -26px 32px -34px rgba(0,0,0,.44)}.datepicker-col .spinbox:focus{z-index:2}.datepicker-col:first-child .spinbox{border-top-left-radius:4px;border-bottom-left-radius:4px}.datepicker-col:last-child .spinbox{border-top-right-radius:4px;border-bottom-right-radius:4px}.datepicker-col .spinbox-row{height:32px;padding:6px}.datepicker-col-month{width:40%;text-align:right}.datepicker-col-day{width:20%;text-align:center}.datepicker-col-year{width:40%;text-align:left}.datepicker-col .spinbox-selection-window{height:32px}@media (max-width:480px){.datepicker-controls{overflow:hidden;width:auto;position:fixed;top:auto!important;right:0!important;bottom:0!important;left:0!important;margin-top:0;border-width:1px 0 0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;opacity:1;filter:alpha(opacity=100)}.datepicker-controls-inner{border-radius:0;border-left:0;border-right:0;-webkit-transform:translateY(100%);-moz-transform:translateY(100%);-ms-transform:translateY(100%);-o-transform:translateY(100%);transform:translateY(100%)}.datepicker-controls-inner:before,.datepicker-controls-inner:after{content:"";border:0}.animate .datepicker-controls-inner{-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0)}.datepicker-toolbar{border-radius:0}.datepicker-cols-ct{border-radius:0;padding:10px}.datepicker-cols{margin:0 auto;max-width:360px}} \ No newline at end of file diff --git a/dist/ember-date-picker.min.js b/dist/ember-date-picker.min.js deleted file mode 100644 index 11beee6..0000000 --- a/dist/ember-date-picker.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(root,factory){if(typeof define==="function"&&define.amd){define(["ember"],function(Ember){return factory(Ember)})}else if(typeof exports==="object"){module.exports=factory(require("ember"))}else{root.DatePickerControlsComponent=factory(Ember)}})(this,function(Ember){var DatePickerControlsComponent=Ember.Component.extend({classNames:["datepicker-controls"],classNameBindings:["_isOpen:shown","_animate:animate"],layoutName:"components/date-picker-controls",animateDuration:300,repeatInterval:150,repeatDelay:500,_defaults:{minYear:false,maxYear:false,dateFormat:null,i18n:{done:"Done",clear:"Clear",today:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"]}},_isOpen:false,_animate:false,_currentTarget:null,_currentMonth:null,_currentDay:null,_currentYear:null,setConfig:function(){var config={};if(Ember.isEmpty(this.get("minYear")))config.minYear=this.get("_defaults.minYear");if(Ember.isEmpty(this.get("maxYear")))config.maxYear=this.get("_defaults.maxYear");if(Ember.isBlank(this.get("dateFormat")))config.dateFormat=this.get("_defaults.dateFormat");if(Ember.isEmpty(this.get("i18n")))config.i18n=this.get("_defaults.i18n");config.minYear=this.convertRelativeYear(this.get("minYear"));config.maxYear=this.convertRelativeYear(this.get("maxYear"));this.setProperties(config)}.on("init"),setup:function(){this.$el=this.$();Ember.$(document).on("click.date-picker-events",Ember.run.bind(this,this.handleDocClick))}.on("didInsertElement"),teardown:function(){Ember.$(document).off(".date-picker-events")}.on("willDestroyElement"),handleDocClick:function(e){if(this.get("_currentTarget")&&e.target!==this.get("_currentTarget").$el.get(0)&&!Ember.$.contains(this.$el.get(0),e.target)){this.closePicker()}},handleKeyDown:function(e){switch(e.keyCode){case 13:this.updateValue();this.closePicker();break;case 27:this.closePicker();break}}.on("keyDown"),convertRelativeYear:function(relValue){if(typeof relValue!=="string"){return relValue}relValue=parseInt(relValue,10);return!isNaN(relValue)?(new Date).getFullYear()+relValue:false},getMonthIndex:function(monthName){var months=this.get("i18n.monthNames"),index=months.indexOf(monthName);return index===-1?0:index},getMonthName:function(index){return this.get("i18n.monthNames")[index]},months:function(){return this.get("i18n.monthNames")}.property("i18n"),days:function(){var days=[],daysInMonth=this.getDaysInMonth(this.get("_currentYear"),this.getMonthIndex(this.get("_currentMonth")));for(var i=1;i<=daysInMonth;i++){days.push(i)}return days}.property("_currentMonth","_currentYear"),years:function(){var min=this.get("minYear"),max=this.get("maxYear");return[typeof min==="number"?min:1,typeof max==="number"?max:9999]}.property("minYear","maxYear"),openPicker:function(target){var date;if(!target)return;this.set("_currentTarget",target);this.setProperties({inputMinYear:typeof target.get("minYear")!=="undefined"?this.convertRelativeYear(target.get("minYear")):undefined,inputMaxYear:typeof target.get("maxYear")!=="undefined"?this.convertRelativeYear(target.get("maxYear")):undefined,inputDateFormat:!Ember.isBlank(target.get("dateFormat"))?target.get("dateFormat"):undefined});try{date=this.parseDate(target.get("value"),this.getConfig("dateFormat"))}catch(e){date=null}this.setCurrentValue(date);this.positionPicker(target.$el);this.set("_isOpen",true);Ember.run.next(this,function(){this.set("_animate",true)})},closePicker:function(){this.setProperties({_animate:false,_currentTarget:false});Ember.run.later(this,function(){this.set("_isOpen",false)},this.get("animateDuration"))},positionPicker:function(inputEl){if(!inputEl)return;var offset=inputEl.position(),height=inputEl.outerHeight();this.$el.css({top:offset.top+height+"px",left:offset.left+"px"})},selectedDate:function(){var month=this.getMonthIndex(this.get("_currentMonth")),year=this.get("_currentYear"),daysInMonth=this.getDaysInMonth(year,month),day=this.get("_currentDay")>daysInMonth?1:this.get("_currentDay");return this.formatDate(new Date(year,month,day),this.getConfig("dateFormat"))}.property("dateFormat","inputDateFormat","_currentMonth","_currentDay","_currentYear"),clearValue:function(){if(!this.get("_currentTarget"))return;this.get("_currentTarget").set("value",null);this.get("_currentTarget").sendAction("onUpdate",null)},updateValue:function(){var formattedDate=this.get("selectedDate");if(!this.get("_currentTarget"))return;this.get("_currentTarget").set("value",formattedDate);this.get("_currentTarget").sendAction("onUpdate",formattedDate)},setCurrentValue:function(date,updateValue){date=date||new Date;this.setProperties({_currentMonth:this.getMonthName(date.getMonth()),_currentYear:date.getFullYear()});Ember.run.scheduleOnce("sync",this,function(){this.set("_currentDay",date.getDate());if(updateValue){this.updateValue()}})},getConfig:function(prop){var inputProp="input"+Ember.String.capitalize(prop);return this.get(typeof this.get(inputProp)!=="undefined"?inputProp:prop)},getDaysInMonth:function(year,month){return 32-this.daylightSavingAdjust(new Date(year,month,32)).getDate()},daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},parseDate:function(dateString,format){var date;if(this.get("hasMoment")){date=Ember.isBlank(format)?moment(dateString):moment(dateString,format);date=!date.isValid()?null:date.toDate()}else{date=Date.parse(dateString);date=isNaN(date)?null:new Date(date)}return date},formatDate:function(date,format){var formattedDate=null;if(!Ember.isNone(date)){formattedDate=this.get("hasMoment")?moment(date).format(Ember.isBlank(format)?"l":format):date.toLocaleDateString()}return formattedDate},hasMoment:function(){return typeof moment==="function"}.property(),actions:{clear:function(){this.clearValue();this.closePicker()},done:function(){this.updateValue();this.closePicker()},today:function(){this.setCurrentValue(null,true)},spinBoxUpdate:function(newVal){this.updateValue()}}});return DatePickerControlsComponent});(function(root,factory){if(typeof define==="function"&&define.amd){define(["ember"],function(Ember){return factory(Ember)})}else if(typeof exports==="object"){module.exports=factory(require("ember"))}else{root.DatePickerInputComponent=factory(Ember)}})(this,function(Ember){var DatePickerInputComponent=Ember.Component.extend({tagName:"input",attributeBindings:["type","value","readonly","placeholder"],classNames:["datepicker-input"],type:"text",readonly:true,placeholder:null,value:null,picker:false,setup:function(){var controlsCmp=Ember.View.views[this.get("controls")];this.$el=this.$();if(controlsCmp&&typeof controlsCmp.openPicker==="function"){this.set("picker",controlsCmp)}}.on("didInsertElement"),handleFocusIn:function(e){if(!this.get("picker"))return;this.get("picker").openPicker(this)}.on("focusIn"),handleKeyDown:function(e){if(!this.get("picker"))return;if(e.keyCode==27){this.get("picker").closePicker();this.$el.blur()}}.on("keyDown")});return DatePickerInputComponent});(function(root,factory){if(typeof define==="function"&&define.amd){define(["ember"],function(Ember){return factory(Ember)})}else if(typeof exports==="object"){factory(require("ember"))}else{factory(Ember)}})(this,function(Ember){Ember.TEMPLATES["components/date-picker-controls"]=Ember.Handlebars.template(function anonymous(Handlebars,depth0,helpers,partials,data){this.compilerInfo=[4,">= 1.0.0"];helpers=this.merge(helpers,Ember.Handlebars.helpers);data=data||{};var buffer="",stack1,helper,options,escapeExpression=this.escapeExpression,helperMissing=helpers.helperMissing;data.buffer.push('
\n
\n \n \n \n
\n
\n
\n
\n ');data.buffer.push(escapeExpression((helper=helpers["spin-box"]||depth0&&depth0["spin-box"],options={hash:{content:"months",value:"_currentMonth",onUpdate:"spinBoxUpdate",rowHeight:32,tabindex:1},hashTypes:{content:"ID",value:"ID",onUpdate:"STRING",rowHeight:"INTEGER",tabindex:"INTEGER"},hashContexts:{content:depth0,value:depth0,onUpdate:depth0,rowHeight:depth0,tabindex:depth0},contexts:[],types:[],data:data},helper?helper.call(depth0,options):helperMissing.call(depth0,"spin-box",options))));data.buffer.push('\n
\n
\n ');data.buffer.push(escapeExpression((helper=helpers["spin-box"]||depth0&&depth0["spin-box"],options={hash:{content:"days",value:"_currentDay",onUpdate:"spinBoxUpdate",rowHeight:32,tabindex:2},hashTypes:{content:"ID",value:"ID",onUpdate:"STRING",rowHeight:"INTEGER",tabindex:"INTEGER"},hashContexts:{content:depth0,value:depth0,onUpdate:depth0,rowHeight:depth0,tabindex:depth0},contexts:[],types:[],data:data},helper?helper.call(depth0,options):helperMissing.call(depth0,"spin-box",options))));data.buffer.push('\n
\n
\n ');data.buffer.push(escapeExpression((helper=helpers["spin-box"]||depth0&&depth0["spin-box"],options={hash:{range:"years",value:"_currentYear",onUpdate:"spinBoxUpdate",rowHeight:32,tabindex:3},hashTypes:{range:"ID",value:"ID",onUpdate:"STRING",rowHeight:"INTEGER",tabindex:"INTEGER"},hashContexts:{range:depth0,value:depth0,onUpdate:depth0,rowHeight:depth0,tabindex:depth0},contexts:[],types:[],data:data},helper?helper.call(depth0,options):helperMissing.call(depth0,"spin-box",options))));data.buffer.push("\n
\n
\n
\n
");return buffer})});(function(root,factory){if(typeof define==="function"&&define.amd){define(["ember","./components/date-picker-controls.js","./components/date-picker-input.js"],function(Ember,Controls,Input){return factory(Ember,Controls,Input)})}else if(typeof exports==="object"){module.exports=factory(require("ember"),require("./components/date-picker-controls.js"),require("./components/date-picker-input.js"))}else{factory(Ember,root.DatePickerControlsComponent,root.DatePickerInputComponent)}})(this,function(Ember,Controls,Input){Ember.Application.initializer({name:"date-picker",initialize:function(container,application){container.register("component:date-picker-controls",Controls);container.register("component:date-picker-input",Input)}});return{DatePickerControls:Controls,DatePickerInput:Input}}); \ No newline at end of file diff --git a/example/example.css b/example/example.css deleted file mode 100644 index 150dd71..0000000 --- a/example/example.css +++ /dev/null @@ -1,6 +0,0 @@ -body { - padding: 40px; - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.42857143; -} \ No newline at end of file diff --git a/example/example.js b/example/example.js deleted file mode 100644 index 2fda3ad..0000000 --- a/example/example.js +++ /dev/null @@ -1,15 +0,0 @@ -var App = Ember.Application.create({ - rootElement: '#demo', - debugMode: true -}); - -App.ApplicationController = Ember.ObjectController.extend({ - date1: '3/4/2012', - date2: 'December 18th, 2008', - - actions: { - dateUpdated: function(date) { - console.log('date updated to ' + date); - } - } -}); \ No newline at end of file diff --git a/example/index.html b/example/index.html deleted file mode 100644 index dcb22d8..0000000 --- a/example/index.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - ember-date-picker example - - - - - - - - - - -
-
-
- - - - - - - - - - - - \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..c9a90db --- /dev/null +++ b/index.js @@ -0,0 +1,11 @@ +/* jshint node: true */ +'use strict'; + +module.exports = { + name: 'ember-date-picker', + + included: function(app) { + this.app = app; + app.import('vendor/ember-date-picker.css'); + } +}; diff --git a/lib/components/date-picker-controls.js b/lib/components/date-picker-controls.js deleted file mode 100644 index 7b549db..0000000 --- a/lib/components/date-picker-controls.js +++ /dev/null @@ -1,284 +0,0 @@ -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define(['ember'], function(Ember) { return factory(Ember); }); - } else if(typeof exports === 'object') { - module.exports = factory(require('ember')); - } else { - root.DatePickerControlsComponent = factory(Ember); - } -})(this, function(Ember) { - - var DatePickerControlsComponent = Ember.Component.extend({ - classNames: ['datepicker-controls'], - classNameBindings: ['_isOpen:shown', '_animate:animate'], - layoutName: 'components/date-picker-controls', - animateDuration: 300, - repeatInterval: 150, - repeatDelay: 500, - - _defaults: { - minYear: false, - maxYear: false, - dateFormat: null, - i18n: { - done: "Done", - clear: "Clear", - today: "Today", - monthNames: [ - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - ] - } - }, - - _isOpen: false, - _animate: false, - _currentTarget: null, - _currentMonth: null, - _currentDay: null, - _currentYear: null, - - setConfig: function() { - //sanity check provided settings/set defaults where necessary - var config = {}; - if(Ember.isEmpty(this.get('minYear'))) config.minYear = this.get('_defaults.minYear'); - if(Ember.isEmpty(this.get('maxYear'))) config.maxYear = this.get('_defaults.maxYear'); - if(Ember.isBlank(this.get('dateFormat'))) config.dateFormat = this.get('_defaults.dateFormat'); - if(Ember.isEmpty(this.get('i18n'))) config.i18n = this.get('_defaults.i18n'); - - //allow relative minYear/maxYear values to the current year (e.g. "-100", "+50") - config.minYear = this.convertRelativeYear(this.get('minYear')); - config.maxYear = this.convertRelativeYear(this.get('maxYear')); - - this.setProperties(config); - }.on('init'), - - setup: function() { - this.$el = this.$(); - Ember.$(document).on('click.date-picker-events', Ember.run.bind(this, this.handleDocClick)); - }.on('didInsertElement'), - - teardown: function() { - Ember.$(document).off('.date-picker-events'); - }.on('willDestroyElement'), - - handleDocClick: function(e) { - if(this.get('_currentTarget') && - e.target !== this.get('_currentTarget').$el.get(0) && - !Ember.$.contains(this.$el.get(0), e.target)) { - this.closePicker(); - } - }, - - handleKeyDown: function(e) { - switch(e.keyCode) { - //enter - case 13: - this.updateValue(); - this.closePicker(); - break; - //esc - case 27: - this.closePicker(); - break; - } - }.on('keyDown'), - - convertRelativeYear: function(relValue) { - if(typeof relValue !== 'string') { - return relValue; - } - - relValue = parseInt(relValue, 10); - return !isNaN(relValue) ? new Date().getFullYear() + relValue : false; - }, - - getMonthIndex: function(monthName) { - var months = this.get('i18n.monthNames'), - index = months.indexOf(monthName); - return index === -1 ? 0 : index; - }, - - getMonthName: function(index) { - return this.get('i18n.monthNames')[index]; - }, - - months: function() { - return this.get('i18n.monthNames'); - }.property('i18n'), - - days: function() { - var days = [], - daysInMonth = this.getDaysInMonth(this.get('_currentYear'), this.getMonthIndex(this.get('_currentMonth'))); - - for(var i=1; i<=daysInMonth; i++) { - days.push(i); - } - - return days; - }.property('_currentMonth', '_currentYear'), - - years: function() { - var min = this.get('minYear'), - max = this.get('maxYear'); - return [typeof min === 'number' ? min : 1, typeof max === 'number' ? max : 9999]; - }.property('minYear', 'maxYear'), - - openPicker: function(target) { - var date; - if(!target) return; - this.set('_currentTarget', target); - - //if the input component defines is own settings, use them instead of the control component's settings - this.setProperties({ - inputMinYear: typeof target.get('minYear') !== 'undefined' ? this.convertRelativeYear(target.get('minYear')) : undefined, - inputMaxYear: typeof target.get('maxYear') !== 'undefined' ? this.convertRelativeYear(target.get('maxYear')) : undefined, - inputDateFormat : !Ember.isBlank(target.get('dateFormat')) ? target.get('dateFormat') : undefined - }); - - try { - date = this.parseDate(target.get('value'), this.getConfig('dateFormat')); - } catch(e) { - date = null; - } - - this.setCurrentValue(date); - this.positionPicker(target.$el); - this.set('_isOpen', true); - Ember.run.next(this, function() { - this.set('_animate', true); - }); - }, - - closePicker: function() { - this.setProperties({ - _animate: false, - _currentTarget: false - }); - - Ember.run.later(this, function() { - this.set('_isOpen', false); - }, this.get('animateDuration')); - }, - - positionPicker: function(inputEl) { - if(!inputEl) return; - - var offset = inputEl.position(), - height = inputEl.outerHeight(); - - this.$el.css({ - top: (offset.top + height) + 'px', - left: offset.left + 'px' - }); - }, - - selectedDate: function() { - var month = this.getMonthIndex(this.get('_currentMonth')), - year = this.get('_currentYear'), - daysInMonth = this.getDaysInMonth(year, month), - day = this.get('_currentDay') > daysInMonth ? 1 : this.get('_currentDay'); - - return this.formatDate(new Date(year, month, day), this.getConfig('dateFormat')); - }.property('dateFormat', 'inputDateFormat', '_currentMonth', '_currentDay', '_currentYear'), - - clearValue: function() { - if(!this.get('_currentTarget')) return; - this.get('_currentTarget').set('value', null); - this.get('_currentTarget').sendAction('onUpdate', null); - }, - - updateValue: function() { - var formattedDate = this.get('selectedDate'); - if(!this.get('_currentTarget')) return; - this.get('_currentTarget').set('value', formattedDate); - this.get('_currentTarget').sendAction('onUpdate', formattedDate); - }, - - setCurrentValue: function(date, updateValue) { - //if a date is not provided or is invalid, default to the current date - date = date || new Date(); - - this.setProperties({ - _currentMonth: this.getMonthName(date.getMonth()), - _currentYear: date.getFullYear() - }); - - Ember.run.scheduleOnce('sync', this, function() { - this.set('_currentDay', date.getDate()); - if(updateValue) { - this.updateValue(); - } - }); - }, - - getConfig: function(prop) { - var inputProp = 'input' + Ember.String.capitalize(prop); - return this.get(typeof this.get(inputProp) !== 'undefined' ? inputProp : prop); - }, - - getDaysInMonth: function(year, month) { - return 32 - this.daylightSavingAdjust(new Date(year, month, 32)).getDate(); - }, - - daylightSavingAdjust: function(date) { - if(!date) { - return null; - } - - date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); - return date; - }, - - parseDate: function(dateString, format) { - var date; - if(this.get('hasMoment')) { - date = Ember.isBlank(format) ? moment(dateString) : moment(dateString, format); - date = !date.isValid() ? null : date.toDate(); - } else { - date = Date.parse(dateString); - date = isNaN(date) ? null : new Date(date); - } - - return date; - }, - - formatDate: function(date, format) { - var formattedDate = null; - - if(!Ember.isNone(date)) { - formattedDate = this.get('hasMoment') ? - moment(date).format(Ember.isBlank(format) ? 'l' : format) : - date.toLocaleDateString(); - } - - return formattedDate; - }, - - hasMoment: function() { - return typeof moment === 'function'; - }.property(), - - actions: { - clear: function() { - this.clearValue(); - this.closePicker(); - }, - - done: function() { - this.updateValue(); - this.closePicker(); - }, - - today: function() { - this.setCurrentValue(null, true); - }, - - spinBoxUpdate: function(newVal) { - this.updateValue(); - } - } - }); - - return DatePickerControlsComponent; -}); \ No newline at end of file diff --git a/lib/components/date-picker-input.js b/lib/components/date-picker-input.js deleted file mode 100644 index 59bbe19..0000000 --- a/lib/components/date-picker-input.js +++ /dev/null @@ -1,45 +0,0 @@ -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define(['ember'], function(Ember) { return factory(Ember); }); - } else if(typeof exports === 'object') { - module.exports = factory(require('ember')); - } else { - root.DatePickerInputComponent = factory(Ember); - } -})(this, function(Ember) { - - var DatePickerInputComponent = Ember.Component.extend({ - tagName: 'input', - attributeBindings: ['type', 'value', 'readonly', 'placeholder'], - classNames: ['datepicker-input'], - type: 'text', - readonly: true, - placeholder: null, - value: null, - picker: false, - - setup: function() { - var controlsCmp = Ember.View.views[this.get('controls')]; - this.$el = this.$(); - - if(controlsCmp && typeof controlsCmp.openPicker === 'function') { - this.set('picker', controlsCmp); - } - }.on('didInsertElement'), - - handleFocusIn: function(e) { - if(!this.get('picker')) return; - this.get('picker').openPicker(this); - }.on('focusIn'), - - handleKeyDown: function(e) { - if(!this.get('picker')) return; - if(e.keyCode == 27) { - this.get('picker').closePicker(); - this.$el.blur(); - } - }.on('keyDown') - }); - - return DatePickerInputComponent; -}); \ No newline at end of file diff --git a/lib/main.js b/lib/main.js deleted file mode 100644 index cf672dd..0000000 --- a/lib/main.js +++ /dev/null @@ -1,37 +0,0 @@ -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define([ - 'ember', - './components/date-picker-controls.js', - './components/date-picker-input.js', - ], function(Ember, Controls, Input) { - return factory(Ember, Controls, Input); - }); - } else if(typeof exports === 'object') { - module.exports = factory( - require('ember'), - require('./components/date-picker-controls.js'), - require('./components/date-picker-input.js') - ); - } else { - factory( - Ember, - root.DatePickerControlsComponent, - root.DatePickerInputComponent - ); - } -})(this, function(Ember, Controls, Input) { - - Ember.Application.initializer({ - name: 'date-picker', - initialize: function(container, application) { - container.register('component:date-picker-controls', Controls); - container.register('component:date-picker-input', Input); - } - }); - - return { - DatePickerControls: Controls, - DatePickerInput: Input - }; -}); \ No newline at end of file diff --git a/lib/templates-bottom.js b/lib/templates-bottom.js deleted file mode 100644 index dd78761..0000000 --- a/lib/templates-bottom.js +++ /dev/null @@ -1 +0,0 @@ -}); \ No newline at end of file diff --git a/lib/templates-top.js b/lib/templates-top.js deleted file mode 100644 index ef4269b..0000000 --- a/lib/templates-top.js +++ /dev/null @@ -1,10 +0,0 @@ -(function(root, factory) { - if(typeof define === 'function' && define.amd) { - define(['ember'], function(Ember) { return factory(Ember); }); - } else if(typeof exports === 'object') { - factory(require('ember')); - } else { - factory(Ember); - } -})(this, function(Ember) { - diff --git a/lib/templates/components/date-picker-controls.hbs b/lib/templates/components/date-picker-controls.hbs deleted file mode 100644 index 38a6b42..0000000 --- a/lib/templates/components/date-picker-controls.hbs +++ /dev/null @@ -1,20 +0,0 @@ -
-
- - - -
-
-
-
- {{spin-box content=months value=_currentMonth onUpdate="spinBoxUpdate" rowHeight=32 tabindex=1}} -
-
- {{spin-box content=days value=_currentDay onUpdate="spinBoxUpdate" rowHeight=32 tabindex=2}} -
-
- {{spin-box range=years value=_currentYear onUpdate="spinBoxUpdate" rowHeight=32 tabindex=3}} -
-
-
-
\ No newline at end of file diff --git a/package.json b/package.json index 3c6b657..5bf1532 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,39 @@ { "name": "ember-date-picker", - "version": "0.0.4", - "description": "A lightweight, mobile-optimized, date picker component for ember.js applications.", - "author": "Bill Dami ", + "version": "0.0.1", + "directories": { + "doc": "doc", + "test": "tests" + }, + "scripts": { + "start": "ember server", + "build": "ember build", + "test": "ember test" + }, + "repository": "", + "engines": { + "node": ">= 0.10.0" + }, + "author": "", "license": "MIT", "devDependencies": { - "broccoli": "~0.11.0", - "broccoli-merge-trees": "~0.1.3", - "broccoli-uglify-js": "~0.1.3", - "broccoli-concat": "0.0.5", - "broccoli-less-single": "~0.1.4", - "broccoli-template-builder": "0.0.1", - "broccoli-env": "0.0.1", - "broccoli-static-compiler": "~0.1.4", - "handlebars": "~1.3.0", - "ember-template-compiler": "~1.6.0-beta.3" + "broccoli-asset-rev": "^1.0.0", + "broccoli-ember-hbs-template-compiler": "^1.6.1", + "ember-cli": "0.1.3", + "ember-cli-esnext": "0.1.1", + "ember-cli-ic-ajax": "0.1.1", + "ember-cli-inject-live-reload": "^1.3.0", + "ember-cli-qunit": "0.1.2", + "ember-data": "1.0.0-beta.11", + "ember-export-application-global": "^1.0.0", + "express": "^4.8.5", + "glob": "^4.0.5" + }, + "description": "The default blueprint for ember-cli addons.", + "keywords": [ + "ember-addon" + ], + "ember-addon": { + "configPath": "tests/dummy/config" } } diff --git a/testem.json b/testem.json new file mode 100644 index 0000000..eff93f9 --- /dev/null +++ b/testem.json @@ -0,0 +1,11 @@ +{ + "framework": "qunit", + "test_page": "tests/index.html", + "launch_in_ci": [ + "PhantomJS" + ], + "launch_in_dev": [ + "PhantomJS", + "Chrome" + ] +} diff --git a/tests/.jshintrc b/tests/.jshintrc new file mode 100644 index 0000000..6ebf71a --- /dev/null +++ b/tests/.jshintrc @@ -0,0 +1,74 @@ +{ + "predef": [ + "document", + "window", + "location", + "setTimeout", + "$", + "-Promise", + "QUnit", + "define", + "console", + "equal", + "notEqual", + "notStrictEqual", + "test", + "asyncTest", + "testBoth", + "testWithDefault", + "raises", + "throws", + "deepEqual", + "start", + "stop", + "ok", + "strictEqual", + "module", + "moduleFor", + "moduleForComponent", + "moduleForModel", + "process", + "expect", + "visit", + "exists", + "fillIn", + "click", + "keyEvent", + "triggerEvent", + "find", + "findWithAssert", + "wait", + "DS", + "isolatedContainer", + "startApp", + "andThen", + "currentURL", + "currentPath", + "currentRouteName" + ], + "node": false, + "browser": false, + "boss": true, + "curly": false, + "debug": false, + "devel": false, + "eqeqeq": true, + "evil": true, + "forin": false, + "immed": false, + "laxbreak": false, + "newcap": true, + "noarg": true, + "noempty": false, + "nonew": false, + "nomen": false, + "onevar": false, + "plusplus": false, + "regexp": false, + "undef": true, + "sub": true, + "strict": false, + "white": false, + "eqnull": true, + "esnext": true +} diff --git a/tests/app.js b/tests/app.js deleted file mode 100644 index a947e7f..0000000 --- a/tests/app.js +++ /dev/null @@ -1,4 +0,0 @@ -App = Ember.Application.create(); -App.setupForTesting(); -App.injectTestHelpers(); -App.rootElement = '#ember-testing'; \ No newline at end of file diff --git a/tests/dummy/app/app.js b/tests/dummy/app/app.js new file mode 100644 index 0000000..757df38 --- /dev/null +++ b/tests/dummy/app/app.js @@ -0,0 +1,16 @@ +import Ember from 'ember'; +import Resolver from 'ember/resolver'; +import loadInitializers from 'ember/load-initializers'; +import config from './config/environment'; + +Ember.MODEL_FACTORY_INJECTIONS = true; + +var App = Ember.Application.extend({ + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, + Resolver: Resolver +}); + +loadInitializers(App, config.modulePrefix); + +export default App; diff --git a/tests/dummy/app/components/.gitkeep b/tests/dummy/app/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/controllers/.gitkeep b/tests/dummy/app/controllers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/helpers/.gitkeep b/tests/dummy/app/helpers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/index.html b/tests/dummy/app/index.html new file mode 100644 index 0000000..b7d8600 --- /dev/null +++ b/tests/dummy/app/index.html @@ -0,0 +1,21 @@ + + + + + + Dummy + + + + {{content-for 'head'}} + + + + + + {{content-for 'body'}} + + + + + diff --git a/tests/dummy/app/models/.gitkeep b/tests/dummy/app/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js new file mode 100644 index 0000000..cef554b --- /dev/null +++ b/tests/dummy/app/router.js @@ -0,0 +1,11 @@ +import Ember from 'ember'; +import config from './config/environment'; + +var Router = Ember.Router.extend({ + location: config.locationType +}); + +Router.map(function() { +}); + +export default Router; diff --git a/tests/dummy/app/routes/.gitkeep b/tests/dummy/app/routes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/styles/app.css b/tests/dummy/app/styles/app.css new file mode 100644 index 0000000..9adb5ad --- /dev/null +++ b/tests/dummy/app/styles/app.css @@ -0,0 +1,3 @@ +html, body { + margin: 20px; +} diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs new file mode 100644 index 0000000..d08c11f --- /dev/null +++ b/tests/dummy/app/templates/application.hbs @@ -0,0 +1,3 @@ +

Welcome to Ember.js

+ +{{outlet}} diff --git a/tests/dummy/app/templates/components/.gitkeep b/tests/dummy/app/templates/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/app/views/.gitkeep b/tests/dummy/app/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/config/environment.js b/tests/dummy/config/environment.js new file mode 100644 index 0000000..d3f169f --- /dev/null +++ b/tests/dummy/config/environment.js @@ -0,0 +1,47 @@ +/* jshint node: true */ + +module.exports = function(environment) { + var ENV = { + modulePrefix: 'dummy', + environment: environment, + baseURL: '/', + locationType: 'auto', + EmberENV: { + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. 'with-controller': true + } + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + } + }; + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + // Testem prefers this... + ENV.baseURL = '/'; + ENV.locationType = 'none'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; + } + + if (environment === 'production') { + + } + + return ENV; +}; diff --git a/tests/dummy/public/.gitkeep b/tests/dummy/public/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/dummy/public/crossdomain.xml b/tests/dummy/public/crossdomain.xml new file mode 100644 index 0000000..29a035d --- /dev/null +++ b/tests/dummy/public/crossdomain.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/tests/dummy/public/robots.txt b/tests/dummy/public/robots.txt new file mode 100644 index 0000000..5debfa4 --- /dev/null +++ b/tests/dummy/public/robots.txt @@ -0,0 +1,2 @@ +# http://www.robotstxt.org +User-agent: * diff --git a/tests/helpers/resolver.js b/tests/helpers/resolver.js new file mode 100644 index 0000000..28f4ece --- /dev/null +++ b/tests/helpers/resolver.js @@ -0,0 +1,11 @@ +import Resolver from 'ember/resolver'; +import config from '../../config/environment'; + +var resolver = Resolver.create(); + +resolver.namespace = { + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix +}; + +export default resolver; diff --git a/tests/helpers/start-app.js b/tests/helpers/start-app.js new file mode 100644 index 0000000..e087e48 --- /dev/null +++ b/tests/helpers/start-app.js @@ -0,0 +1,19 @@ +import Ember from 'ember'; +import Application from '../../app'; +import Router from '../../router'; +import config from '../../config/environment'; + +export default function startApp(attrs) { + var App; + + var attributes = Ember.merge({}, config.APP); + attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; + + Ember.run(function() { + App = Application.create(attributes); + App.setupForTesting(); + App.injectTestHelpers(); + }); + + return App; +} diff --git a/tests/index.html b/tests/index.html index 83966f1..12ade4a 100644 --- a/tests/index.html +++ b/tests/index.html @@ -1,40 +1,43 @@ - - - ember-date-picker - - - - - - - - -
-
- - + + + + + Dummy Tests + + - - - - - - - - - - - \ No newline at end of file + {{content-for 'head'}} + {{content-for 'test-head'}} + + + + + + + + + {{content-for 'body'}} + {{content-for 'test-body'}} + + + + + + + diff --git a/tests/test-helper.js b/tests/test-helper.js new file mode 100644 index 0000000..b5f6449 --- /dev/null +++ b/tests/test-helper.js @@ -0,0 +1,12 @@ +import resolver from './helpers/resolver'; +import { + setResolver +} from 'ember-qunit'; + +setResolver(resolver); + +document.write('
'); + +QUnit.config.urlConfig.push({ id: 'nocontainer', label: 'Hide container'}); +var containerVisibility = QUnit.urlParams.nocontainer ? 'hidden' : 'visible'; +document.getElementById('ember-testing-container').style.visibility = containerVisibility; diff --git a/tests/tests.js b/tests/tests.js deleted file mode 100644 index 6d4ae9d..0000000 --- a/tests/tests.js +++ /dev/null @@ -1,97 +0,0 @@ -/** - * initial component properties - * value: "May 15, 2014" - * dateFormat: "MMMM D, YYYY" - */ -module('Controls toggling', { - setup: function() { - App.reset(); - visit('/'); - } -}); - -test('focusing input shows the controls', function() { - expect(1); - openControls(); - - andThen(function() { - ok(find('div.datepicker-controls').is(':visible'), 'controls are visible'); - }); -}); - -test('clicking elsewhere in the document hides the controls', function() { - expect(1); - openControls(); - click(document); - - andThen(function() { - ok(find('div.datepicker-controls').is(':hidden'), 'controls are hidden'); - }); -}); - -module('Date selection', { - setup: function() { - App.reset(); - visit('/'); - openControls(); - } -}); - -test('controls display the current date value', function() { - expect(1); - - andThen(function() { - equal( - find('.datepicker-col-month .spinbox-row.selected').text() + ' ' + - find('.datepicker-col-day .spinbox-row.selected').text() + ', ' + - find('.datepicker-col-year .spinbox-row.selected').text(), - 'May 15, 2014' - ); - }); -}); - -test('clicking "Today" button sets current date as the selected date', function() { - var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - date = new Date(), - currentDate = monthNames[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear(); - - expect(1); - click('button.datepicker-btn-today'); - - andThen(function() { - equal( - find('.datepicker-col-month .spinbox-row.selected').text() + ' ' + - find('.datepicker-col-day .spinbox-row.selected').text() + ', ' + - find('.datepicker-col-year .spinbox-row.selected').text(), - currentDate - ); - }); -}); - -test('clicking "Clear" button clears the input\'s value', function() { - expect(1); - click('button.datepicker-btn-clear'); - - andThen(function() { - equal(find('input.datepicker-input').val(), ''); - }); -}); - -test('Changing the spin box values updates the input\'s value', function() { - expect(1); - click('.datepicker-col-month .spinbox-row:nth-of-type(5)'); - click('.datepicker-col-day .spinbox-row:nth-of-type(5)'); - click('.datepicker-col-year .spinbox-row:nth-of-type(5)'); - - - andThen(function() { - equal( - find('input.datepicker-input').val(), - 'June 16, 2015' - ); - }); -}); - -function openControls() { - triggerEvent('input.datepicker-input', 'focus'); -} \ No newline at end of file diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/vendor/.gitkeep b/vendor/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/dist/ember-date-picker.css b/vendor/ember-date-picker.css similarity index 100% rename from dist/ember-date-picker.css rename to vendor/ember-date-picker.css diff --git a/lib/styles/ember-date-picker.less b/vendor/ember-date-picker.less similarity index 100% rename from lib/styles/ember-date-picker.less rename to vendor/ember-date-picker.less From 0016ba004b96d951209f620ae649defd400fd8db Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:24:58 -0600 Subject: [PATCH 02/10] add ember-spin-box as dev dependency --- bower.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bower.json b/bower.json index fd08544..1a42722 100644 --- a/bower.json +++ b/bower.json @@ -13,5 +13,8 @@ "ember-qunit": "0.1.8", "ember-qunit-notifications": "0.0.4", "qunit": "~1.15.0" + }, + "devDependencies": { + "ember-spin-box": "~0.0.5" } } From 1fdd0ffda81c6ab8bd4fef29a261f34470586b3a Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:25:53 -0600 Subject: [PATCH 03/10] rename generator to date-picker. --- blueprints/date-picker/index.js | 11 +++++++++++ blueprints/ember-cli-date-picker/index.js | 13 ------------- 2 files changed, 11 insertions(+), 13 deletions(-) create mode 100644 blueprints/date-picker/index.js delete mode 100644 blueprints/ember-cli-date-picker/index.js diff --git a/blueprints/date-picker/index.js b/blueprints/date-picker/index.js new file mode 100644 index 0000000..75bdb0f --- /dev/null +++ b/blueprints/date-picker/index.js @@ -0,0 +1,11 @@ +'use strict'; + +module.exports = { + description: 'date-picker', + + normalizeEntityName: function() {}, + + afterInstall: function() { + return this.addBowerPackageToProject('ember-spin-box'); + } +}; diff --git a/blueprints/ember-cli-date-picker/index.js b/blueprints/ember-cli-date-picker/index.js deleted file mode 100644 index 3622590..0000000 --- a/blueprints/ember-cli-date-picker/index.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; - -module.exports = { - name: 'ember-date-picker', - - normalizeEntityName: function() { }, - - afterInstall: function() { - return this.addBowerPackagesToProject([ - {name: 'ember-spin-box', target: '~0.0.5'} - ]); - } -}; From 2a4dc6f982d7b06f519468309699aed09e22fbc2 Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:26:07 -0600 Subject: [PATCH 04/10] add blueprints generated file. --- blueprints/.jshintrc | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 blueprints/.jshintrc diff --git a/blueprints/.jshintrc b/blueprints/.jshintrc new file mode 100644 index 0000000..c189e4a --- /dev/null +++ b/blueprints/.jshintrc @@ -0,0 +1,5 @@ +{ + "predef": [ + "console" + ] +} From eb862357f690817eae204dd0e2058f467afa10ec Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:26:37 -0600 Subject: [PATCH 05/10] throw error when running ember serve if the generator has not been run. --- index.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/index.js b/index.js index c9a90db..88a7a2c 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,26 @@ /* jshint node: true */ 'use strict'; +var fs = require('fs'); + module.exports = { name: 'ember-date-picker', included: function(app) { this.app = app; app.import('vendor/ember-date-picker.css'); + + var spinBoxJsPath = app.bowerDirectory + '/ember-spin-box/dist/ember-spin-box.min.js'; + var spinBoxCssPath = app.bowerDirectory + '/ember-spin-box/dist/ember-spin-box.min.css'; + + if (!fs.existsSync(spinBoxJsPath) && !fs.existsSync(spinBoxCssPath)) { + var msg = 'ember-date-picker: You need to run ember g date-picker to '; + msg += 'install required dependencies before using this addon.'; + var err = new Error(msg); + err.stack = null; + throw err; + } + app.import(spinBoxJsPath); + app.import(spinBoxCssPath); } }; From d4937cbc47bd04e1b352d99be876fae7fafc064f Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:26:53 -0600 Subject: [PATCH 06/10] change license to .md --- LICENSE.md | 9 +++++++++ LICENSE.txt | 21 --------------------- 2 files changed, 9 insertions(+), 21 deletions(-) create mode 100644 LICENSE.md delete mode 100644 LICENSE.txt diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..3d64d59 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,9 @@ +The MIT License (MIT) + +Copyright (c) 2014 William Dami + +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: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +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. diff --git a/LICENSE.txt b/LICENSE.txt deleted file mode 100644 index 179467a..0000000 --- a/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 William Dami - -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: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -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. \ No newline at end of file From 42df02d2c9128c1df13870fc17d12b69288ea4a3 Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:27:07 -0600 Subject: [PATCH 07/10] Update README --- README.md | 65 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 56b7521..8fb419d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ember-date-picker ================= -A lightweight, mobile-optimized, date picker component for ember.js applications. +A lightweight, mobile-optimized, date picker component for ember-cli applications. **DISCLAIMER:** This is beta software and has yet to be battle tested in a wide range of environments. As such, it should be used with caution in production apps. If you encounter any bugs or browser-specific anomalies, please submit an issue or a pull request. Thanks! @@ -13,7 +13,6 @@ http://billdami.com/ember-date-picker/ Features -------- -* Lightweight (~4k javascript / ~1k css, minified and gzipped, including dependencies) * Spin box style UI for fast date selection (built using [ember-spin-box](https://github.com/billdami/ember-spin-box)) * Supports mousewheel, keyboard, and touch-based control * Mobile-optimized slide-up panel UI on small screens (480px width and below) @@ -24,10 +23,9 @@ Features Installation ------------ -1. `bower install ember-date-picker` or grab the files in `dist/`. -2. Install [ember-spin-box](https://github.com/billdami/ember-spin-box) dependency (will already be downloaded if you used bower on step 1) -2. Add `dist/ember-date-picker.min.js` to your application's javascript assets. -3. Add `dist/ember-date-picker.min.css` to your application's css assets. Or if you use LESS, and intend to customize the component's styles, you can import `lib/styles/ember-date-picker.less`. +1. Add the following to your ember-cli-project in package.json `"ember-date-picker": "billdami/ember-date-picker"`. +2. Run `npm install`. +3. Run `ember g date-picker` to install the [ember-spin-box](https://github.com/billdami/ember-spin-box) dependency. 4. **Optional:** Install [moment.js](http://momentjs.com/) to enable custom date format parsing/output. Usage @@ -45,26 +43,26 @@ The `controls` parameter of the `{{date-picker-input}}` must reference the `id` `{{date-picker-input}}` Parameters ------- -* **Any valid HTML text input element attribute** +* **Any valid HTML text input element attribute** Since `{{date-picker-input}}` renders a regular text input element, any valid HTML attribute (e.g. `value`, `class`, `placeholder`, ect) may be provided. -* **controls** (`string`, required) +* **controls** (`string`, required) The `id` of the `{{date-picker-controls}}` component that the input is associated with. -* **dateFormat** (`string`) +* **dateFormat** (`string`) The format for parsed and displayed dates (i.e. the input's value). This parameter **will only be used if moment.js is installed**, otherwise the native [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) and [Date.toLocaleDateString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString) functions will be used to parse and format dates, respectively. See the [moment.js docs](http://momentjs.com/docs/#/parsing/string-format/) for all available formatting tokens. -* **minYear** (`int|string|bool`, default: `false`) +* **minYear** (`int|string|bool`, default: `false`) The minimum selectable year. When set to `false`, there is no minimum year. A string value may be provided to specify a year relative to the current date (e.g. `"-10"`, or `"+25"`). -* **maxYear** (`int|string|bool`, default: `false`) +* **maxYear** (`int|string|bool`, default: `false`) The maximum selectable year. When set to `false`, there is no maximum year. A string value may be provided to specify a year relative to the current date (e.g. `"-10"`, or `"+25"`). -* **onUpdate** (`string`) +* **onUpdate** (`string`) The name of an action to send when the input's value has been updated. The new value is sent as the action's only parameter. `{{date-picker-controls}}` Parameters ------- -* **id** (`string`, required) +* **id** (`string`, required) A unique identifier that `{{date-picker-input}}` uses to associate with the component via its `controls` parameter. -* **i18n** (`object`) - Localized text strings for the controls UI. If provided, this parameter must match exactly the structure of the default i18n object below: +* **i18n** (`object`) + Localized text strings for the controls UI. If provided, this parameter must match exactly the structure of the default i18n object below: ``` { @@ -77,9 +75,40 @@ The `controls` parameter of the `{{date-picker-input}}` must reference the `id` ] } ``` -* **dateFormat** (`string`) +* **dateFormat** (`string`) The default date format for the `{{date-picker-controls}}` component. If an associated `{{date-picker-input}}` specifies its own `dateFormat`, it will override this setting while that input is active. -* **minYear** (`int|string|bool`, default: `false`) +* **minYear** (`int|string|bool`, default: `false`) The default minimum year for the `{{date-picker-controls}}` component. If an associated `{{date-picker-input}}` specifies its own `minYear`, it will override this setting while that input is active. -* **maxYear** (`int|string|bool`, default: `false`) +* **maxYear** (`int|string|bool`, default: `false`) The default maximum year for the `{{date-picker-controls}}` component. If an associated `{{date-picker-input}}` specifies its own `maxYear`, it will override this setting while that input is active. + +Contributors +------------ + +Created by: [William Dami](https://github.com/billdami) +Converted into Addon by: [Daniel Ochoa](https://github.com/DanyHunter) + + +This README outlines the details of collaborating on this Ember addon. + +## Installation + +* `git clone` this repository +* `npm install` +* `bower install` + +## Running + +* `ember server` +* Visit your app at http://localhost:4200. + +## Running Tests + +* `ember test` +* `ember test --server` + +## Building + +* `ember build` + +For more information on using ember-cli, visit [http://www.ember-cli.com/](http://www.ember-cli.com/). From 3522bb937cd733a4c2111056a77d178ec50640c4 Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:32:16 -0600 Subject: [PATCH 08/10] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8fb419d..97dbe10 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ The `controls` parameter of the `{{date-picker-input}}` must reference the `id` Contributors ------------ -Created by: [William Dami](https://github.com/billdami) +Created by: [William Dami](https://github.com/billdami)
Converted into Addon by: [Daniel Ochoa](https://github.com/DanyHunter) From 55c704b28d396359f3179db034f1cf47643fe497 Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Sat, 6 Dec 2014 10:42:45 -0600 Subject: [PATCH 09/10] setup dummy app for example/testing purposes. --- tests/dummy/app/templates/application.hbs | 2 +- tests/dummy/app/templates/index.hbs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/dummy/app/templates/index.hbs diff --git a/tests/dummy/app/templates/application.hbs b/tests/dummy/app/templates/application.hbs index d08c11f..09b3c47 100644 --- a/tests/dummy/app/templates/application.hbs +++ b/tests/dummy/app/templates/application.hbs @@ -1,3 +1,3 @@ -

Welcome to Ember.js

+

Ember Date Picker

{{outlet}} diff --git a/tests/dummy/app/templates/index.hbs b/tests/dummy/app/templates/index.hbs new file mode 100644 index 0000000..504d7bc --- /dev/null +++ b/tests/dummy/app/templates/index.hbs @@ -0,0 +1,6 @@ + +

Click on the input to get started.

+ +{{date-picker-input controls="my-datepicker" value=myDate}} +{{date-picker-controls id="my-datepicker"}} + From 6092b2a457e20532cbe5d231b0c8f8be4ced38a4 Mon Sep 17 00:00:00 2001 From: Daniel Ochoa Date: Mon, 8 Dec 2014 20:06:42 -0600 Subject: [PATCH 10/10] Re-add json files info. --- README.md | 6 ------ bower.json | 7 +++++++ package.json | 5 +++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 97dbe10..e39377c 100644 --- a/README.md +++ b/README.md @@ -82,12 +82,6 @@ The `controls` parameter of the `{{date-picker-input}}` must reference the `id` * **maxYear** (`int|string|bool`, default: `false`) The default maximum year for the `{{date-picker-controls}}` component. If an associated `{{date-picker-input}}` specifies its own `maxYear`, it will override this setting while that input is active. -Contributors ------------- - -Created by: [William Dami](https://github.com/billdami)
-Converted into Addon by: [Daniel Ochoa](https://github.com/DanyHunter) - This README outlines the details of collaborating on this Ember addon. diff --git a/bower.json b/bower.json index 1a42722..af90a45 100644 --- a/bower.json +++ b/bower.json @@ -1,5 +1,12 @@ { "name": "ember-date-picker", + "version": "0.0.4", + "description": "A lightweight, mobile-optimized, date picker component for ember.js applications.", + "author": "Bill Dami ", + "license": "MIT", + "ignore": [ + "**/.*" + ], "dependencies": { "handlebars": "~1.3.0", "jquery": "^1.11.1", diff --git a/package.json b/package.json index 5bf1532..ebc9156 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,8 @@ { "name": "ember-date-picker", - "version": "0.0.1", + "version": "0.0.4", + "description": "A lightweight, mobile-optimized, date picker component for ember.js applications.", + "author": "Bill Dami ", "directories": { "doc": "doc", "test": "tests" @@ -14,7 +16,6 @@ "engines": { "node": ">= 0.10.0" }, - "author": "", "license": "MIT", "devDependencies": { "broccoli-asset-rev": "^1.0.0",