├── lib ├── pickadate-rails │ └── version.rb └── pickadate-rails.rb ├── Gemfile ├── .gitignore ├── vendor └── assets │ ├── javascripts │ └── pickadate │ │ ├── translations │ │ ├── NAMING.md │ │ ├── ja_JP.js │ │ ├── ko_KR.js │ │ ├── no_NO.js │ │ ├── zh_CN.js │ │ ├── zh_TW.js │ │ ├── lv_LV.js │ │ ├── he_IL.js │ │ ├── bg_BG.js │ │ ├── th_TH.js │ │ ├── cs_CZ.js │ │ ├── ro_RO.js │ │ ├── vi_VN.js │ │ ├── bs_BA.js │ │ ├── id_ID.js │ │ ├── ar.js │ │ ├── hu_HU.js │ │ ├── gl_ES.js │ │ ├── pt_PT.js │ │ ├── da_DK.js │ │ ├── sk_SK.js │ │ ├── tr_TR.js │ │ ├── hr_HR.js │ │ ├── uk_UA.js │ │ ├── nb_NO.js │ │ ├── sl_SI.js │ │ ├── is_IS.js │ │ ├── ru_RU.js │ │ ├── de_DE.js │ │ ├── el_GR.js │ │ ├── et_EE.js │ │ ├── eu_ES.js │ │ ├── es_ES.js │ │ ├── nl_NL.js │ │ ├── ca_ES.js │ │ ├── fi_FI.js │ │ ├── pl_PL.js │ │ ├── pt_BR.js │ │ ├── ne_NP.js │ │ ├── fa_ir.js │ │ ├── sv_SE.js │ │ ├── fr_FR.js │ │ ├── hi_IN.js │ │ ├── it_IT.js │ │ └── lt_LT.js │ │ ├── legacy.js │ │ ├── picker.time.js │ │ ├── picker.js │ │ └── picker.date.js │ └── stylesheets │ └── pickadate │ ├── rtl.css │ ├── classic.css │ ├── default.time.css │ ├── classic.time.css │ ├── default.css │ ├── classic.date.css │ └── default.date.css ├── Rakefile ├── LICENSE.txt ├── pickadate-rails.gemspec └── README.md /lib/pickadate-rails/version.rb: -------------------------------------------------------------------------------- 1 | module PickadateRails 2 | VERSION = "3.5.6.1" 3 | end 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in pickadate-rails.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /lib/pickadate-rails.rb: -------------------------------------------------------------------------------- 1 | require 'pickadate-rails/version' 2 | require 'rails' 3 | 4 | module PickadateRails 5 | class Engine < Rails::Engine 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/NAMING.md: -------------------------------------------------------------------------------- 1 | ### The following convention is used for naming the translation files: 2 | 3 | ``` 4 | LANGUAGE_COUNTRY.js 5 | ``` 6 | 7 | #### Where: 8 | 9 | ``` 10 | LANGUAGE = The lowercase ISO 639-1 language code. 11 | ``` 12 | 13 | > See http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes 14 | 15 | ``` 16 | COUNTRY = The uppercase ISO 3166-1 country code. 17 | ``` 18 | 19 | > See http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements 20 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/ja_JP.js: -------------------------------------------------------------------------------- 1 | // Japanese 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ '1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月' ], 5 | monthsShort: [ '1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月' ], 6 | weekdaysFull: [ '日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日' ], 7 | weekdaysShort: [ '日', '月', '火', '水', '木', '金', '土' ], 8 | today: '今日', 9 | clear: '消去', 10 | firstDay: 1, 11 | format: 'yyyy mm dd', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: '消去' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/ko_KR.js: -------------------------------------------------------------------------------- 1 | // Korean 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ '1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월' ], 5 | monthsShort: [ '1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월' ], 6 | weekdaysFull: [ '일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일' ], 7 | weekdaysShort: [ '일', '월', '화', '수', '목', '금', '토' ], 8 | today: '오늘', 9 | clear: '취소', 10 | firstDay: 1, 11 | format: 'yyyy 년 mm 월 dd 일', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: '취소' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/no_NO.js: -------------------------------------------------------------------------------- 1 | // Norwegian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des' ], 6 | weekdaysFull: [ 'søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag' ], 7 | weekdaysShort: [ 'søn','man','tir', 'ons', 'tor', 'fre', 'lør' ], 8 | today: 'i dag', 9 | clear: 'nullstill', 10 | firstDay: 1, 11 | format: 'dd. mmm. yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/zh_CN.js: -------------------------------------------------------------------------------- 1 | // Simplified Chinese 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ], 5 | monthsShort: [ '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二' ], 6 | weekdaysFull: [ '星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六' ], 7 | weekdaysShort: [ '日', '一', '二', '三', '四', '五', '六' ], 8 | today: '今日', 9 | clear: '清除', 10 | close: '关闭', 11 | firstDay: 1, 12 | format: 'yyyy 年 mm 月 dd 日', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: '清除' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/zh_TW.js: -------------------------------------------------------------------------------- 1 | // Traditional Chinese 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ], 5 | monthsShort: [ '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二' ], 6 | weekdaysFull: [ '星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六' ], 7 | weekdaysShort: [ '日', '一', '二', '三', '四', '五', '六' ], 8 | today: '今天', 9 | clear: '清除', 10 | close: '关闭', 11 | firstDay: 1, 12 | format: 'yyyy 年 mm 月 dd 日', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: '清除' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/pickadate/rtl.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Styling for RTL (right-to-left) languages using pickadate.js 3 | */ 4 | /** 5 | * Switch the direction - only really necessary if 6 | * it hasn’t already been applied higher up in the DOM. 7 | */ 8 | .picker { 9 | direction: rtl; 10 | } 11 | /** 12 | * Flip around the “next” and “previous” buttons. 13 | */ 14 | .picker__nav--next { 15 | right: auto; 16 | left: -1em; 17 | } 18 | .picker__nav--prev { 19 | left: auto; 20 | right: -1em; 21 | } 22 | .picker__nav--next:before { 23 | border-left: 0; 24 | border-right: 0.75em solid #000000; 25 | } 26 | .picker__nav--prev:before { 27 | border-right: 0; 28 | border-left: 0.75em solid #000000; 29 | } 30 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/lv_LV.js: -------------------------------------------------------------------------------- 1 | // Latvian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Janvāris', 'Februāris', 'Marts', 'Aprīlis', 'Maijs', 'Jūnijs', 'Jūlijs', 'Augusts', 'Septembris', 'Oktobris', 'Novembris', 'Decembris' ], 5 | monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jūn', 'Jūl', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec' ], 6 | weekdaysFull: [ 'Svētdiena', 'Pirmdiena', 'Otrdiena', 'Trešdiena', 'Ceturtdiena', 'Piektdiena', 'Sestdiena' ], 7 | weekdaysShort: [ 'Sv', 'P', 'O', 'T', 'C', 'Pk', 'S' ], 8 | today: 'Šodiena', 9 | clear: 'Atcelt', 10 | firstDay: 1, 11 | format: 'yyyy.mm.dd. dddd', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/he_IL.js: -------------------------------------------------------------------------------- 1 | // Hebrew 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר' ], 5 | monthsShort: [ 'ינו', 'פבר', 'מרץ', 'אפר', 'מאי', 'יונ', 'יול', 'אוג', 'ספט', 'אוק', 'נוב', 'דצמ' ], 6 | weekdaysFull: [ 'יום ראשון', 'יום שני', 'יום שלישי', 'יום רביעי', 'יום חמישי', 'יום ששי', 'יום שבת' ], 7 | weekdaysShort: [ 'א', 'ב', 'ג', 'ד', 'ה', 'ו', 'ש' ], 8 | today: 'היום', 9 | clear: 'למחוק', 10 | format: 'yyyy mmmmב d dddd', 11 | formatSubmit: 'yyyy/mm/dd' 12 | }); 13 | 14 | jQuery.extend( jQuery.fn.pickatime.defaults, { 15 | clear: 'למחוק' 16 | }); 17 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/bg_BG.js: -------------------------------------------------------------------------------- 1 | // Bulgarian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'януари','февруари','март','април','май','юни','юли','август','септември','октомври','ноември','декември' ], 5 | monthsShort: [ 'янр','фев','мар','апр','май','юни','юли','авг','сеп','окт','ное','дек' ], 6 | weekdaysFull: [ 'неделя', 'понеделник', 'вторник', 'сряда', 'четвъртък', 'петък', 'събота' ], 7 | weekdaysShort: [ 'нд', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб' ], 8 | today: 'днес', 9 | clear: 'изтривам', 10 | firstDay: 1, 11 | format: 'd mmmm yyyy г.', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'изтривам' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/th_TH.js: -------------------------------------------------------------------------------- 1 | // Thai 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม' ], 5 | monthsShort: [ 'ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.' ], 6 | weekdaysFull: [ 'อาทติย', 'จันทร', 'องัคาร', 'พุธ', 'พฤหสั บดี', 'ศกุร', 'เสาร' ], 7 | weekdaysShort: [ 'อ.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.' ], 8 | today: 'วันนี้', 9 | clear: 'ลบ', 10 | format: 'd mmmm yyyy', 11 | formatSubmit: 'yyyy/mm/dd' 12 | }); 13 | 14 | jQuery.extend( jQuery.fn.pickatime.defaults, { 15 | clear: 'ลบ' 16 | }); 17 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/cs_CZ.js: -------------------------------------------------------------------------------- 1 | // Czech 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'leden', 'únor', 'březen', 'duben', 'květen', 'červen', 'červenec', 'srpen', 'září', 'říjen', 'listopad', 'prosinec' ], 5 | monthsShort: [ 'led', 'úno', 'bře', 'dub', 'kvě', 'čer', 'čvc', 'srp', 'zář', 'říj', 'lis', 'pro' ], 6 | weekdaysFull: [ 'neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota' ], 7 | weekdaysShort: [ 'ne', 'po', 'út', 'st', 'čt', 'pá', 'so' ], 8 | today: 'dnes', 9 | clear: 'vymazat', 10 | firstDay: 1, 11 | format: 'd. mmmm yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'vymazat' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/ro_RO.js: -------------------------------------------------------------------------------- 1 | // Romanian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'ianuarie', 'februarie', 'martie', 'aprilie', 'mai', 'iunie', 'iulie', 'august', 'septembrie', 'octombrie', 'noiembrie', 'decembrie' ], 5 | monthsShort: [ 'ian', 'feb', 'mar', 'apr', 'mai', 'iun', 'iul', 'aug', 'sep', 'oct', 'noi', 'dec' ], 6 | weekdaysFull: [ 'duminică', 'luni', 'marţi', 'miercuri', 'joi', 'vineri', 'sâmbătă' ], 7 | weekdaysShort: [ 'D', 'L', 'Ma', 'Mi', 'J', 'V', 'S' ], 8 | today: 'azi', 9 | clear: 'șterge', 10 | firstDay: 1, 11 | format: 'dd mmmm yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'șterge' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/vi_VN.js: -------------------------------------------------------------------------------- 1 | // Vietnamese 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Tháng Một', 'Tháng Hai', 'Tháng Ba', 'Tháng Tư', 'Tháng Năm', 'Tháng Sáu', 'Tháng Bảy', 'Tháng Tám', 'Tháng Chín', 'Tháng Mười', 'Tháng Mười Một', 'Tháng Mười Hai' ], 5 | monthsShort: [ 'Một', 'Hai', 'Ba', 'Tư', 'Năm', 'Sáu', 'Bảy', 'Tám', 'Chín', 'Mưới', 'Mười Một', 'Mười Hai' ], 6 | weekdaysFull: [ 'Chủ Nhật', 'Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy' ], 7 | weekdaysShort: [ 'C.Nhật', 'T.Hai', 'T.Ba', 'T.Tư', 'T.Năm', 'T.Sáu', 'T.Bảy' ], 8 | today: 'Hôm Nay', 9 | clear: 'Xoá', 10 | firstDay: 1 11 | }); 12 | 13 | jQuery.extend( jQuery.fn.pickatime.defaults, { 14 | clear: 'Xoá' 15 | }); 16 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/bs_BA.js: -------------------------------------------------------------------------------- 1 | // Bosnian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'januar', 'februar', 'mart', 'april', 'maj', 'juni', 'juli', 'august', 'septembar', 'oktobar', 'novembar', 'decembar' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec' ], 6 | weekdaysFull: [ 'nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'cetvrtak', 'petak', 'subota' ], 7 | weekdaysShort: [ 'ne', 'po', 'ut', 'sr', 'če', 'pe', 'su' ], 8 | today: 'danas', 9 | clear: 'izbrisati', 10 | firstDay: 1, 11 | format: 'dd. mmmm yyyy.', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'izbrisati' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/id_ID.js: -------------------------------------------------------------------------------- 1 | // Indonesian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember' ], 5 | monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'Mei', 'Jun', 'Jul', 'Agu', 'Sep', 'Okt', 'Nov', 'Des' ], 6 | weekdaysFull: [ 'Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu' ], 7 | weekdaysShort: [ 'Min', 'Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab' ], 8 | today: 'hari ini', 9 | clear: 'menghapus', 10 | firstDay: 1, 11 | format: 'd mmmm yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'menghapus' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/ar.js: -------------------------------------------------------------------------------- 1 | // Arabic 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'يناير', 'فبراير', 'مارس', 'ابريل', 'مايو', 'يونيو', 'يوليو', 'اغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر' ], 5 | monthsShort: [ 'يناير', 'فبراير', 'مارس', 'ابريل', 'مايو', 'يونيو', 'يوليو', 'اغسطس', 'سبتمبر', 'اكتوبر', 'نوفمبر', 'ديسمبر' ], 6 | weekdaysFull: [ 'الاحد', 'الاثنين', 'الثلاثاء', 'الاربعاء', 'الخميس', 'الجمعة', 'السبت' ], 7 | weekdaysShort: [ 'الاحد', 'الاثنين', 'الثلاثاء', 'الاربعاء', 'الخميس', 'الجمعة', 'السبت' ], 8 | today: 'اليوم', 9 | clear: 'مسح', 10 | format: 'yyyy mmmm dd', 11 | formatSubmit: 'yyyy/mm/dd' 12 | }); 13 | 14 | jQuery.extend( jQuery.fn.pickatime.defaults, { 15 | clear: 'مسح' 16 | }); 17 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/hu_HU.js: -------------------------------------------------------------------------------- 1 | // Hungarian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december' ], 5 | monthsShort: [ 'jan', 'febr', 'márc', 'ápr', 'máj', 'jún', 'júl', 'aug', 'szept', 'okt', 'nov', 'dec' ], 6 | weekdaysFull: [ 'vasárnap', 'hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat' ], 7 | weekdaysShort: [ 'V', 'H', 'K', 'SZe', 'CS', 'P', 'SZo' ], 8 | today: 'Ma', 9 | clear: 'Törlés', 10 | firstDay: 1, 11 | format: 'yyyy. mmmm dd.', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'Törlés' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/gl_ES.js: -------------------------------------------------------------------------------- 1 | // Galician 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Xaneiro', 'Febreiro', 'Marzo', 'Abril', 'Maio', 'Xuño', 'Xullo', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Decembro' ], 5 | monthsShort: [ 'xan', 'feb', 'mar', 'abr', 'mai', 'xun', 'xul', 'ago', 'sep', 'out', 'nov', 'dec' ], 6 | weekdaysFull: [ 'domingo', 'luns', 'martes', 'mércores', 'xoves', 'venres', 'sábado' ], 7 | weekdaysShort: [ 'dom', 'lun', 'mar', 'mér', 'xov', 'ven', 'sab' ], 8 | today: 'hoxe', 9 | clear: 'borrar', 10 | firstDay: 1, 11 | format: 'dddd d !de mmmm !de yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'borrar' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/pt_PT.js: -------------------------------------------------------------------------------- 1 | // Portuguese 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro' ], 5 | monthsShort: [ 'jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez' ], 6 | weekdaysFull: [ 'Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado' ], 7 | weekdaysShort: [ 'dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sab' ], 8 | today: 'Hoje', 9 | clear: 'Limpar', 10 | close: 'Fechar', 11 | format: 'd !de mmmm !de yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'Limpar' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/da_DK.js: -------------------------------------------------------------------------------- 1 | // Danish 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec' ], 6 | weekdaysFull: [ 'søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag' ], 7 | weekdaysShort: [ 'søn', 'man', 'tir', 'ons', 'tor', 'fre', 'lør' ], 8 | today: 'i dag', 9 | clear: 'slet', 10 | close: 'luk', 11 | firstDay: 1, 12 | format: 'd. mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'slet' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/sk_SK.js: -------------------------------------------------------------------------------- 1 | // Slovak 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'január', 'február', 'marec', 'apríl', 'máj', 'jún', 'júl', 'august', 'september', 'október', 'november', 'december' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'máj', 'jún', 'júl', 'aug', 'sep', 'okt', 'nov', 'dec' ], 6 | weekdaysFull: [ 'nedeľa', 'pondelok', 'utorok', 'streda', 'štvrtok', 'piatok', 'sobota' ], 7 | weekdaysShort: [ 'Ne', 'Po', 'Ut', 'St', 'Št', 'Pi', 'So' ], 8 | today: 'dnes', 9 | clear: 'vymazať', 10 | close: 'zavrieť', 11 | firstDay: 1, 12 | format: 'd. mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'vymazať' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/tr_TR.js: -------------------------------------------------------------------------------- 1 | // Turkish 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık' ], 5 | monthsShort: [ 'Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara' ], 6 | weekdaysFull: [ 'Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi' ], 7 | weekdaysShort: [ 'Pzr', 'Pzt', 'Sal', 'Çrş', 'Prş', 'Cum', 'Cmt' ], 8 | today: 'Bugün', 9 | clear: 'Sil', 10 | close: 'Kapat', 11 | firstDay: 1, 12 | format: 'dd mmmm yyyy dddd', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'sil' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/hr_HR.js: -------------------------------------------------------------------------------- 1 | // Croatian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'sijećanj', 'veljača', 'ožujak', 'travanj', 'svibanj', 'lipanj', 'srpanj', 'kolovoz', 'rujan', 'listopad', 'studeni', 'prosinac' ], 5 | monthsShort: [ 'sij', 'velj', 'ožu', 'tra', 'svi', 'lip', 'srp', 'kol', 'ruj', 'lis', 'stu', 'pro' ], 6 | weekdaysFull: [ 'nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota' ], 7 | weekdaysShort: [ 'ned', 'pon', 'uto', 'sri', 'čet', 'pet', 'sub' ], 8 | today: 'danas', 9 | clear: 'izbrisati', 10 | firstDay: 1, 11 | format: 'd. mmmm yyyy.', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'izbrisati' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/uk_UA.js: -------------------------------------------------------------------------------- 1 | // Ukrainian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'січень', 'лютий', 'березень', 'квітень', 'травень', 'червень', 'липень', 'серпень', 'вересень', 'жовтень', 'листопад', 'грудень' ], 5 | monthsShort: [ 'січ', 'лют', 'бер', 'кві', 'тра', 'чер', 'лип', 'сер', 'вер', 'жов', 'лис', 'гру' ], 6 | weekdaysFull: [ 'неділя', 'понеділок', 'вівторок', 'середа', 'четвер', 'п‘ятниця', 'субота' ], 7 | weekdaysShort: [ 'нд', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб' ], 8 | today: 'сьогодні', 9 | clear: 'викреслити', 10 | firstDay: 1, 11 | format: 'dd mmmm yyyy p.', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'викреслити' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/nb_NO.js: -------------------------------------------------------------------------------- 1 | // Norwegian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'mai', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'des' ], 6 | weekdaysFull: [ 'søndag', 'mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag' ], 7 | weekdaysShort: [ 'søn','man','tir', 'ons', 'tor', 'fre', 'lør' ], 8 | today: 'i dag', 9 | clear: 'nullstill', 10 | close: 'lukk', 11 | firstDay: 1, 12 | format: 'dd. mmm. yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'nullstill' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/sl_SI.js: -------------------------------------------------------------------------------- 1 | // Slovenian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'januar', 'februar', 'marec', 'april', 'maj', 'junij', 'julij', 'avgust', 'september', 'oktober', 'november', 'december' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'avg', 'sep', 'okt', 'nov', 'dec' ], 6 | weekdaysFull: [ 'nedelja', 'ponedeljek', 'torek', 'sreda', 'četrtek', 'petek', 'sobota' ], 7 | weekdaysShort: [ 'ned', 'pon', 'tor', 'sre', 'čet', 'pet', 'sob' ], 8 | today: 'danes', 9 | clear: 'izbriši', 10 | close: 'zapri', 11 | firstDay: 1, 12 | format: 'd. mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'izbriši' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/is_IS.js: -------------------------------------------------------------------------------- 1 | // Icelandic 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'janúar', 'febrúar', 'mars', 'apríl', 'maí', 'júní', 'júlí', 'ágúst', 'september', 'október', 'nóvember', 'desember' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'maí', 'jún', 'júl', 'ágú', 'sep', 'okt', 'nóv', 'des' ], 6 | weekdaysFull: [ 'sunnudagur', 'mánudagur', 'þriðjudagur', 'miðvikudagur', 'fimmtudagur', 'föstudagur', 'laugardagur' ], 7 | weekdaysShort: [ 'sun', 'mán', 'þri', 'mið', 'fim', 'fös', 'lau' ], 8 | today: 'Í dag', 9 | clear: 'Hreinsa', 10 | firstDay: 1, 11 | format: 'dd. mmmm yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'Hreinsa' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/ru_RU.js: -------------------------------------------------------------------------------- 1 | // Russian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря' ], 5 | monthsShort: [ 'янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек' ], 6 | weekdaysFull: [ 'воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота' ], 7 | weekdaysShort: [ 'вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб' ], 8 | today: 'сегодня', 9 | clear: 'удалить', 10 | close: 'закрыть', 11 | firstDay: 1, 12 | format: 'd mmmm yyyy г.', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'удалить' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/de_DE.js: -------------------------------------------------------------------------------- 1 | // German 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ], 5 | monthsShort: [ 'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez' ], 6 | weekdaysFull: [ 'Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag' ], 7 | weekdaysShort: [ 'So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa' ], 8 | today: 'Heute', 9 | clear: 'Löschen', 10 | close: 'Schließen', 11 | firstDay: 1, 12 | format: 'dddd, dd. mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'Löschen' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/el_GR.js: -------------------------------------------------------------------------------- 1 | // Greek 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος' ], 5 | monthsShort: [ 'Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μαι', 'Ιουν', 'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ' ], 6 | weekdaysFull: [ 'Κυριακή', 'Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο' ], 7 | weekdaysShort: [ 'Κυρ', 'Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ' ], 8 | today: 'σήμερα', 9 | clear: 'Διαγραφή', 10 | firstDay: 1, 11 | format: 'd mmmm yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'Διαγραφή' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/et_EE.js: -------------------------------------------------------------------------------- 1 | // Estonian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'jaanuar', 'veebruar', 'märts', 'aprill', 'mai', 'juuni', 'juuli', 'august', 'september', 'oktoober', 'november', 'detsember' ], 5 | monthsShort: [ 'jaan', 'veebr', 'märts', 'apr', 'mai', 'juuni', 'juuli', 'aug', 'sept', 'okt', 'nov', 'dets' ], 6 | weekdaysFull: [ 'pühapäev', 'esmaspäev', 'teisipäev', 'kolmapäev', 'neljapäev', 'reede', 'laupäev' ], 7 | weekdaysShort: [ 'püh', 'esm', 'tei', 'kol', 'nel', 'ree', 'lau' ], 8 | today: 'täna', 9 | clear: 'kustutama', 10 | firstDay: 1, 11 | format: 'd. mmmm yyyy. a', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'kustutama' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/eu_ES.js: -------------------------------------------------------------------------------- 1 | // Basque 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'urtarrila', 'otsaila', 'martxoa', 'apirila', 'maiatza', 'ekaina', 'uztaila', 'abuztua', 'iraila', 'urria', 'azaroa', 'abendua' ], 5 | monthsShort: [ 'urt', 'ots', 'mar', 'api', 'mai', 'eka', 'uzt', 'abu', 'ira', 'urr', 'aza', 'abe' ], 6 | weekdaysFull: [ 'igandea', 'astelehena', 'asteartea', 'asteazkena', 'osteguna', 'ostirala', 'larunbata' ], 7 | weekdaysShort: [ 'ig.', 'al.', 'ar.', 'az.', 'og.', 'or.', 'lr.' ], 8 | today: 'gaur', 9 | clear: 'garbitu', 10 | firstDay: 1, 11 | format: 'dddd, yyyy(e)ko mmmmren da', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'garbitu' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/es_ES.js: -------------------------------------------------------------------------------- 1 | // Spanish 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre' ], 5 | monthsShort: [ 'ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic' ], 6 | weekdaysFull: [ 'domingo', 'lunes', 'martes', 'miércoles', 'jueves', 'viernes', 'sábado' ], 7 | weekdaysShort: [ 'dom', 'lun', 'mar', 'mié', 'jue', 'vie', 'sáb' ], 8 | today: 'hoy', 9 | clear: 'borrar', 10 | close: 'cerrar', 11 | firstDay: 1, 12 | format: 'dddd d !de mmmm !de yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'borrar' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/nl_NL.js: -------------------------------------------------------------------------------- 1 | // Dutch 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december' ], 5 | monthsShort: [ 'jan', 'feb', 'maa', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec' ], 6 | weekdaysFull: [ 'zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag' ], 7 | weekdaysShort: [ 'zo', 'ma', 'di', 'wo', 'do', 'vr', 'za' ], 8 | today: 'vandaag', 9 | clear: 'verwijderen', 10 | close: 'sluiten', 11 | firstDay: 1, 12 | format: 'dddd d mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'verwijderen' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/ca_ES.js: -------------------------------------------------------------------------------- 1 | // Catalan 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Gener', 'Febrer', 'Març', 'Abril', 'Maig', 'juny', 'Juliol', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Desembre' ], 5 | monthsShort: [ 'Gen', 'Feb', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Oct', 'Nov', 'Des' ], 6 | weekdaysFull: [ 'diumenge', 'dilluns', 'dimarts', 'dimecres', 'dijous', 'divendres', 'dissabte' ], 7 | weekdaysShort: [ 'diu', 'dil', 'dim', 'dmc', 'dij', 'div', 'dis' ], 8 | today: 'avui', 9 | clear: 'esborrar', 10 | close: 'tancar', 11 | firstDay: 1, 12 | format: 'dddd d !de mmmm !de yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'esborrar' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/fi_FI.js: -------------------------------------------------------------------------------- 1 | // Finnish 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'tammikuu', 'helmikuu', 'maaliskuu', 'huhtikuu', 'toukokuu', 'kesäkuu', 'heinäkuu', 'elokuu', 'syyskuu', 'lokakuu', 'marraskuu', 'joulukuu' ], 5 | monthsShort: [ 'tammi', 'helmi', 'maalis', 'huhti', 'touko', 'kesä', 'heinä', 'elo', 'syys', 'loka', 'marras', 'joulu' ], 6 | weekdaysFull: [ 'sunnuntai', 'maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai' ], 7 | weekdaysShort: [ 'su', 'ma', 'ti', 'ke', 'to', 'pe', 'la' ], 8 | today: 'tänään', 9 | clear: 'tyhjennä', 10 | firstDay: 1, 11 | format: 'd.m.yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'tyhjennä' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/pl_PL.js: -------------------------------------------------------------------------------- 1 | // Polish 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'styczeń', 'luty', 'marzec', 'kwiecień', 'maj', 'czerwiec', 'lipiec', 'sierpień', 'wrzesień', 'październik', 'listopad', 'grudzień' ], 5 | monthsShort: [ 'sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru' ], 6 | weekdaysFull: [ 'niedziela', 'poniedziałek', 'wtorek', 'środa', 'czwartek', 'piątek', 'sobota' ], 7 | weekdaysShort: [ 'niedz.', 'pn.', 'wt.', 'śr.', 'cz.', 'pt.', 'sob.' ], 8 | today: 'Dzisiaj', 9 | clear: 'Usuń', 10 | close: 'Zamknij', 11 | firstDay: 1, 12 | format: 'd mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd' 14 | }); 15 | 16 | jQuery.extend( jQuery.fn.pickatime.defaults, { 17 | clear: 'usunąć' 18 | }); 19 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/pt_BR.js: -------------------------------------------------------------------------------- 1 | // Brazilian Portuguese 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro' ], 5 | monthsShort: [ 'jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set', 'out', 'nov', 'dez' ], 6 | weekdaysFull: [ 'domingo', 'segunda-feira', 'terça-feira', 'quarta-feira', 'quinta-feira', 'sexta-feira', 'sábado' ], 7 | weekdaysShort: [ 'dom', 'seg', 'ter', 'qua', 'qui', 'sex', 'sab' ], 8 | today: 'hoje', 9 | clear: 'limpar', 10 | close: 'fechar', 11 | format: 'dddd, d !de mmmm !de yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'limpar' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/ne_NP.js: -------------------------------------------------------------------------------- 1 | // Nepali 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'जनवरी', 'फेब्रुअरी', 'मार्च', 'अप्रिल', 'मे', 'जुन', 'जुलाई', 'अगस्त', 'सेप्टेम्बर', 'अक्टोबर', 'नोवेम्बर', 'डिसेम्बर' ], 5 | monthsShort: [ 'जन', 'फेब्रु', 'मार्च', 'अप्रिल', 'मे', 'जुन', 'जुल', 'अग', 'सेप्टे', 'अक्टो', 'नोभे', 'डिसे' ], 6 | weekdaysFull: [ 'सोमबार', 'मङ्लबार', 'बुधबार', 'बिहीबार', 'शुक्रबार', 'शनिबार', 'आईतबार' ], 7 | weekdaysShort: [ 'सोम', 'मंगल्', 'बुध', 'बिही', 'शुक्र', 'शनि', 'आईत' ], 8 | numbers: [ '०', '१', '२', '३', '४', '५', '६', '७', '८', '९' ], 9 | today: 'आज', 10 | clear: 'मेटाउनुहोस्', 11 | format: 'dddd, dd mmmm, yyyy', 12 | formatSubmit: 'yyyy/mm/dd' 13 | }); 14 | 15 | jQuery.extend( jQuery.fn.pickatime.defaults, { 16 | clear: 'मेटाउनुहोस्' 17 | }); 18 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/fa_ir.js: -------------------------------------------------------------------------------- 1 | // Farsi 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'ژانویه', 'فوریه', 'مارس', 'آوریل', 'مه', 'ژوئن', 'ژوئیه', 'اوت', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'], 5 | monthsShort: [ 'ژانویه', 'فوریه', 'مارس', 'آوریل', 'مه', 'ژوئن', 'ژوئیه', 'اوت', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر' ], 6 | weekdaysFull: [ 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه' ], 7 | weekdaysShort: [ 'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه' ], 8 | today: 'امروز', 9 | clear: 'پاک کردن', 10 | close: 'بستن', 11 | format: 'yyyy mmmm dd', 12 | formatSubmit: 'yyyy/mm/dd', 13 | labelMonthNext: 'ماه بعدی', 14 | labelMonthPrev: 'ماه قبلی' 15 | }); 16 | 17 | jQuery.extend( jQuery.fn.pickatime.defaults, { 18 | clear: 'پاک کردن' 19 | }); 20 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/sv_SE.js: -------------------------------------------------------------------------------- 1 | // Swedish 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december' ], 5 | monthsShort: [ 'jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec' ], 6 | weekdaysFull: [ 'söndag', 'måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag' ], 7 | weekdaysShort: [ 'sön', 'mån', 'tis', 'ons', 'tor', 'fre', 'lör' ], 8 | today: 'Idag', 9 | clear: 'Rensa', 10 | close: 'Stäng', 11 | firstDay: 1, 12 | format: 'yyyy-mm-dd', 13 | formatSubmit: 'yyyy/mm/dd', 14 | labelMonthNext: 'Nästa månad', 15 | labelMonthPrev: 'Föregående månad', 16 | labelMonthSelect: 'Välj månad', 17 | labelYearSelect: 'Välj år' 18 | }); 19 | 20 | jQuery.extend( jQuery.fn.pickatime.defaults, { 21 | clear: 'Rensa' 22 | }); 23 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/fr_FR.js: -------------------------------------------------------------------------------- 1 | // French 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre' ], 5 | monthsShort: [ 'Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Aou', 'Sep', 'Oct', 'Nov', 'Dec' ], 6 | weekdaysFull: [ 'Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi' ], 7 | weekdaysShort: [ 'Dim', 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam' ], 8 | today: 'Aujourd\'hui', 9 | clear: 'Effacer', 10 | close: 'Fermer', 11 | firstDay: 1, 12 | format: 'dd mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd', 14 | labelMonthNext:"Mois suivant", 15 | labelMonthPrev:"Mois précédent", 16 | labelMonthSelect:"Sélectionner un mois", 17 | labelYearSelect:"Sélectionner une année" 18 | }); 19 | 20 | jQuery.extend( jQuery.fn.pickatime.defaults, { 21 | clear: 'Effacer' 22 | }); 23 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | namespace :pickadate do 4 | desc "Download latest assets" 5 | task :download do 6 | require 'fileutils' 7 | 8 | system "curl https://github.com/amsul/pickadate.js/archive/master.zip -f -L --create-dirs -o tmp/pickadate.zip" 9 | system "unzip -o tmp/pickadate.zip -d tmp/" 10 | system "rm tmp/pickadate.zip" 11 | 12 | Dir["tmp/pickadate*/lib/picker*.js"].each do |file| 13 | FileUtils.cp file, "vendor/assets/javascripts/pickadate/#{File.basename(file)}", preserve: false 14 | end 15 | 16 | Dir["tmp/pickadate*/lib/translations/*.js"].each do |file| 17 | FileUtils.cp file, "vendor/assets/javascripts/pickadate/translations/#{File.basename(file)}", preserve: false 18 | end 19 | 20 | Dir["tmp/pickadate*/lib/themes/*"].each do |file| 21 | FileUtils.cp file, "vendor/assets/stylesheets/pickadate/#{File.basename(file)}", preserve: false 22 | end 23 | 24 | system "rm -rf tmp/pickadate*" 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/hi_IN.js: -------------------------------------------------------------------------------- 1 | jQuery.extend( jQuery.fn.pickadate.defaults, { 2 | monthsFull: [ 'जनवरी', 'फरवरी', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जुलाई', 'अगस्त', 'सितम्बर', 'अक्टूबर', 'नवम्बर', 'दिसम्बर' ], 3 | monthsShort: [ 'जन', 'फर', 'मार्च', 'अप्रैल', 'मई', 'जून', 'जु', 'अग', 'सित', 'अक्टू', 'नव', 'दिस' ], 4 | weekdaysFull: [ 'रविवार', 'सोमवार', 'मंगलवार', 'बुधवार', 'गुरुवार', 'शुक्रवार', 'शनिवार' ], 5 | weekdaysShort: [ 'रवि', 'सोम', 'मंगल', 'बुध', 'गुरु', 'शुक्र','शनि' ], 6 | today: 'आज की तारीख चयन करें', 7 | clear: 'चुनी हुई तारीख को मिटाएँ', 8 | close: 'विंडो बंद करे', 9 | firstDay: 1, 10 | format: 'dd/mm/yyyy', 11 | formatSubmit: 'yyyy/mm/dd', 12 | labelMonthNext: 'अगले माह का चयन करें', 13 | labelMonthPrev: 'पिछले माह का चयन करें', 14 | labelMonthSelect: 'किसि एक महीने का चयन करें', 15 | labelYearSelect: 'किसि एक वर्ष का चयन करें' 16 | }); 17 | 18 | jQuery.extend( jQuery.fn.pickatime.defaults, { 19 | clear: 'चुनी हुई तारीख को मिटाएँ' 20 | }); 21 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/it_IT.js: -------------------------------------------------------------------------------- 1 | // Italian 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | monthsFull: [ 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre' ], 5 | monthsShort: [ 'gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic' ], 6 | weekdaysFull: [ 'domenica', 'lunedì', 'martedì', 'mercoledì', 'giovedì', 'venerdì', 'sabato' ], 7 | weekdaysShort: [ 'dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab' ], 8 | today: 'Oggi', 9 | clear: 'Cancella', 10 | close: 'Chiudi', 11 | firstDay: 1, 12 | format: 'dddd d mmmm yyyy', 13 | formatSubmit: 'yyyy/mm/dd', 14 | labelMonthNext: 'Mese successivo', 15 | labelMonthPrev: 'Mese precedente', 16 | labelMonthSelect: 'Seleziona un mese', 17 | labelYearSelect: 'Seleziona un anno' 18 | }); 19 | 20 | jQuery.extend( jQuery.fn.pickatime.defaults, { 21 | clear: 'Cancella', 22 | format: 'HH:i', 23 | formatSubmit: 'HH:i' 24 | }); 25 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/translations/lt_LT.js: -------------------------------------------------------------------------------- 1 | // Lietuviškai 2 | 3 | jQuery.extend( jQuery.fn.pickadate.defaults, { 4 | labelMonthNext: 'Sekantis mėnuo', 5 | labelMonthPrev: 'Ankstesnis mėnuo', 6 | labelMonthSelect: 'Pasirinkite mėnesį', 7 | labelYearSelect: 'Pasirinkite metus', 8 | monthsFull: ['Sausis', 'Vasaris', 'Kovas', 'Balandis', 'Gegužė', 'Birželis', 'Liepa', 'Rugpjūtis', 'Rugsėjis', 'Spalis', 'Lapkritis', 'Gruodis'], 9 | monthsShort: ['Sau', 'Vas', 'Kov', 'Bal', 'Geg', 'Bir', 'Lie', 'Rgp', 'Rgs', 'Spa', 'Lap', 'Grd'], 10 | weekdaysFull: ['Sekmadienis', 'Pirmadienis', 'Antradienis', 'Trečiadienis', 'Ketvirtadienis', 'Penktadienis', 'Šeštadienis'], 11 | weekdaysShort: ['Sk', 'Pr', 'An', 'Tr', 'Kt', 'Pn', 'Št'], 12 | today: 'Šiandien', 13 | clear: 'Išvalyti', 14 | close: 'Uždaryti', 15 | firstDay: 1, 16 | //format: 'yyyy !m. mmmm d !d.', // need to have diffrent case of full months name 17 | format: 'yyyy-mm-dd', 18 | formatSubmit: 'yyyy/mm/dd' 19 | }); 20 | 21 | jQuery.extend( jQuery.fn.pickatime.defaults, { 22 | clear: 'Išvalyti', 23 | format: 'HH:i' 24 | }); 25 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jeff Fraser 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /pickadate-rails.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'pickadate-rails/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "pickadate-rails" 8 | spec.version = PickadateRails::VERSION 9 | spec.authors = ["Jeff Fraser"] 10 | spec.email = ["jfraser@breuer.com"] 11 | spec.description = "Add pickadate.js to Rails 3.1+ via the asset pipeline" 12 | spec.summary = "Add pickadate.js to Rails 3.1+ via the asset pipeline. See http://amsul.ca/pickadate.js/ for more information about pickadate.js." 13 | spec.homepage = "https://github.com/veracross/pickadate-rails" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files`.split($/) 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_dependency('railties', '>= 3.1.0') 22 | 23 | spec.add_development_dependency "bundler", ">= 2.0.0" 24 | spec.add_development_dependency "rake" 25 | end 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pickadate-Rails [![Gem Version](https://badge.fury.io/rb/pickadate-rails.png)](http://badge.fury.io/rb/pickadate-rails) 2 | 3 | ## Pickadate Version: 3.5.6 4 | 5 | Easily add [pickadate.js](https://github.com/amsul/pickadate.js) to your Rails 3.1+ application using the asset pipeline. 6 | 7 | ## Installation 8 | 9 | Add this line to your application's Gemfile: 10 | 11 | gem 'pickadate-rails' 12 | 13 | And then execute: 14 | 15 | $ bundle 16 | 17 | ## Usage 18 | 19 | Pickadate has a number of files associated with it. They are documented on the [pickadate repository](https://github.com/amsul/pickadate.js). Files in this gem are namespaced into a `pickadate` folder, and otherwise match the filenames from the pickadate repo. 20 | 21 | ### Add the desired files to your javascript/coffeescript 22 | Often done in `application.js`: 23 | 24 | //= require pickadate/picker # required 25 | //= require pickadate/picker.date # for the date picker 26 | //= require pickadate/picker.time # for the time picker 27 | 28 | ### Add the stylesheets for the theme you want 29 | Often done in `application.css`. 30 | 31 | For the default theme: 32 | 33 | *= require pickadate/default 34 | *= require pickadate/default.date 35 | *= require pickadate/default.time 36 | 37 | For the classic theme: 38 | 39 | *= require pickadate/classic 40 | *= require pickadate/classic.date 41 | *= require pickadate/classic.time 42 | 43 | ### Localization 44 | 45 | Translations are available by loading them in your javascript/coffeescript file. For example, in `application.js` 46 | 47 | //= require pickadate/translations/bg_BG 48 | 49 | ## Versioning 50 | 51 | Starting with version 3.5.2.0 of this gem, we have switched to matching the gem version with pickadate's current version number. We'll use the tiny version number for changes to the gem itself. Therefore, the gem version jumps from 1.5 (bundling pickadate 3.5) to 3.5.2.0 (bundling pickadate 3.5.2). 52 | 53 | ## Updating 54 | 55 | 1. Run `rake pickadate:download` 56 | 2. Update `lib/pickadate-rails/version` 57 | 3. Update the version number in the Readme 58 | 4. Create a pull request 59 | 60 | ## License 61 | Pickadate itself and this gem are under the MIT license. 62 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/pickadate/classic.css: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-PICKER 3 | ========================================================================== */ 4 | /** 5 | * Note: the root picker element should *NOT* be styled more than what’s here. 6 | */ 7 | .picker { 8 | font-size: 16px; 9 | text-align: left; 10 | line-height: 1.2; 11 | color: #000000; 12 | position: absolute; 13 | z-index: 10000; 14 | -webkit-user-select: none; 15 | -moz-user-select: none; 16 | -ms-user-select: none; 17 | user-select: none; 18 | } 19 | /** 20 | * The picker input element. 21 | */ 22 | .picker__input { 23 | cursor: default; 24 | } 25 | /** 26 | * When the picker is opened, the input element is “activated”. 27 | */ 28 | .picker__input.picker__input--active { 29 | border-color: #0089ec; 30 | } 31 | /** 32 | * The holder is the only “scrollable” top-level container element. 33 | */ 34 | .picker__holder { 35 | width: 100%; 36 | overflow-y: auto; 37 | -webkit-overflow-scrolling: touch; 38 | } 39 | 40 | /*! 41 | * Classic picker styling for pickadate.js 42 | * Demo: http://amsul.github.io/pickadate.js 43 | */ 44 | /** 45 | * Note: the root picker element should *NOT* be styled more than what’s here. 46 | */ 47 | .picker { 48 | width: 100%; 49 | } 50 | /** 51 | * The holder is the base of the picker. 52 | */ 53 | .picker__holder { 54 | position: absolute; 55 | background: #ffffff; 56 | border: 1px solid #aaaaaa; 57 | border-top-width: 0; 58 | border-bottom-width: 0; 59 | border-radius: 0 0 5px 5px; 60 | box-sizing: border-box; 61 | min-width: 176px; 62 | max-width: 466px; 63 | max-height: 0; 64 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 65 | filter: alpha(opacity=0); 66 | -moz-opacity: 0; 67 | opacity: 0; 68 | -webkit-transform: translateY(-1em) perspective(600px) rotateX(10deg); 69 | transform: translateY(-1em) perspective(600px) rotateX(10deg); 70 | transition: -webkit-transform 0.15s ease-out, opacity 0.15s ease-out, max-height 0s 0.15s, border-width 0s 0.15s; 71 | transition: transform 0.15s ease-out, opacity 0.15s ease-out, max-height 0s 0.15s, border-width 0s 0.15s; 72 | } 73 | /** 74 | * The frame and wrap work together to ensure that 75 | * clicks within the picker don’t reach the holder. 76 | */ 77 | .picker__frame { 78 | padding: 1px; 79 | } 80 | .picker__wrap { 81 | margin: -1px; 82 | } 83 | /** 84 | * When the picker opens... 85 | */ 86 | .picker--opened .picker__holder { 87 | max-height: 25em; 88 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 89 | filter: alpha(opacity=100); 90 | -moz-opacity: 1; 91 | opacity: 1; 92 | border-top-width: 1px; 93 | border-bottom-width: 1px; 94 | -webkit-transform: translateY(0) perspective(600px) rotateX(0); 95 | transform: translateY(0) perspective(600px) rotateX(0); 96 | transition: -webkit-transform 0.15s ease-out, opacity 0.15s ease-out, max-height 0s, border-width 0s; 97 | transition: transform 0.15s ease-out, opacity 0.15s ease-out, max-height 0s, border-width 0s; 98 | box-shadow: 0 6px 18px 1px rgba(0, 0, 0, 0.12); 99 | } 100 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/pickadate/default.time.css: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-TIME-PICKER 3 | ========================================================================== */ 4 | /** 5 | * The list of times. 6 | */ 7 | .picker__list { 8 | list-style: none; 9 | padding: 0.75em 0 4.2em; 10 | margin: 0; 11 | } 12 | /** 13 | * The times on the clock. 14 | */ 15 | .picker__list-item { 16 | border-bottom: 1px solid #dddddd; 17 | border-top: 1px solid #dddddd; 18 | margin-bottom: -1px; 19 | position: relative; 20 | background: #ffffff; 21 | padding: .75em 1.25em; 22 | } 23 | @media (min-height: 46.75em) { 24 | .picker__list-item { 25 | padding: .5em 1em; 26 | } 27 | } 28 | /* Hovered time */ 29 | .picker__list-item:hover { 30 | cursor: pointer; 31 | color: #000000; 32 | background: #b1dcfb; 33 | border-color: #0089ec; 34 | z-index: 10; 35 | } 36 | /* Highlighted and hovered/focused time */ 37 | .picker__list-item--highlighted { 38 | border-color: #0089ec; 39 | z-index: 10; 40 | } 41 | .picker__list-item--highlighted:hover, 42 | .picker--focused .picker__list-item--highlighted { 43 | cursor: pointer; 44 | color: #000000; 45 | background: #b1dcfb; 46 | } 47 | /* Selected and hovered/focused time */ 48 | .picker__list-item--selected, 49 | .picker__list-item--selected:hover, 50 | .picker--focused .picker__list-item--selected { 51 | background: #0089ec; 52 | color: #ffffff; 53 | z-index: 10; 54 | } 55 | /* Disabled time */ 56 | .picker__list-item--disabled, 57 | .picker__list-item--disabled:hover, 58 | .picker--focused .picker__list-item--disabled { 59 | background: #f5f5f5; 60 | border-color: #f5f5f5; 61 | color: #dddddd; 62 | cursor: default; 63 | border-color: #dddddd; 64 | z-index: auto; 65 | } 66 | /** 67 | * The clear button 68 | */ 69 | .picker--time .picker__button--clear { 70 | display: block; 71 | width: 80%; 72 | margin: 1em auto 0; 73 | padding: 1em 1.25em; 74 | background: none; 75 | border: 0; 76 | font-weight: 500; 77 | font-size: .67em; 78 | text-align: center; 79 | text-transform: uppercase; 80 | color: #666; 81 | } 82 | .picker--time .picker__button--clear:hover, 83 | .picker--time .picker__button--clear:focus { 84 | color: #000000; 85 | background: #b1dcfb; 86 | background: #ee2200; 87 | border-color: #ee2200; 88 | cursor: pointer; 89 | color: #ffffff; 90 | outline: none; 91 | } 92 | .picker--time .picker__button--clear:before { 93 | top: -0.25em; 94 | color: #666; 95 | font-size: 1.25em; 96 | font-weight: bold; 97 | } 98 | .picker--time .picker__button--clear:hover:before, 99 | .picker--time .picker__button--clear:focus:before { 100 | color: #ffffff; 101 | border-color: #ffffff; 102 | } 103 | 104 | /* ========================================================================== 105 | $DEFAULT-TIME-PICKER 106 | ========================================================================== */ 107 | /** 108 | * The frame the bounds the time picker. 109 | */ 110 | .picker--time .picker__frame { 111 | min-width: 256px; 112 | max-width: 320px; 113 | } 114 | /** 115 | * The picker box. 116 | */ 117 | .picker--time .picker__box { 118 | font-size: 1em; 119 | background: #f2f2f2; 120 | padding: 0; 121 | } 122 | @media (min-height: 40.125em) { 123 | .picker--time .picker__box { 124 | margin-bottom: 5em; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/pickadate/classic.time.css: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-TIME-PICKER 3 | ========================================================================== */ 4 | /** 5 | * The list of times. 6 | */ 7 | .picker__list { 8 | list-style: none; 9 | padding: 0.75em 0 4.2em; 10 | margin: 0; 11 | } 12 | /** 13 | * The times on the clock. 14 | */ 15 | .picker__list-item { 16 | border-bottom: 1px solid #dddddd; 17 | border-top: 1px solid #dddddd; 18 | margin-bottom: -1px; 19 | position: relative; 20 | background: #ffffff; 21 | padding: .75em 1.25em; 22 | } 23 | @media (min-height: 46.75em) { 24 | .picker__list-item { 25 | padding: .5em 1em; 26 | } 27 | } 28 | /* Hovered time */ 29 | .picker__list-item:hover { 30 | cursor: pointer; 31 | color: #000000; 32 | background: #b1dcfb; 33 | border-color: #0089ec; 34 | z-index: 10; 35 | } 36 | /* Highlighted and hovered/focused time */ 37 | .picker__list-item--highlighted { 38 | border-color: #0089ec; 39 | z-index: 10; 40 | } 41 | .picker__list-item--highlighted:hover, 42 | .picker--focused .picker__list-item--highlighted { 43 | cursor: pointer; 44 | color: #000000; 45 | background: #b1dcfb; 46 | } 47 | /* Selected and hovered/focused time */ 48 | .picker__list-item--selected, 49 | .picker__list-item--selected:hover, 50 | .picker--focused .picker__list-item--selected { 51 | background: #0089ec; 52 | color: #ffffff; 53 | z-index: 10; 54 | } 55 | /* Disabled time */ 56 | .picker__list-item--disabled, 57 | .picker__list-item--disabled:hover, 58 | .picker--focused .picker__list-item--disabled { 59 | background: #f5f5f5; 60 | border-color: #f5f5f5; 61 | color: #dddddd; 62 | cursor: default; 63 | border-color: #dddddd; 64 | z-index: auto; 65 | } 66 | /** 67 | * The clear button 68 | */ 69 | .picker--time .picker__button--clear { 70 | display: block; 71 | width: 80%; 72 | margin: 1em auto 0; 73 | padding: 1em 1.25em; 74 | background: none; 75 | border: 0; 76 | font-weight: 500; 77 | font-size: .67em; 78 | text-align: center; 79 | text-transform: uppercase; 80 | color: #666; 81 | } 82 | .picker--time .picker__button--clear:hover, 83 | .picker--time .picker__button--clear:focus { 84 | color: #000000; 85 | background: #b1dcfb; 86 | background: #ee2200; 87 | border-color: #ee2200; 88 | cursor: pointer; 89 | color: #ffffff; 90 | outline: none; 91 | } 92 | .picker--time .picker__button--clear:before { 93 | top: -0.25em; 94 | color: #666; 95 | font-size: 1.25em; 96 | font-weight: bold; 97 | } 98 | .picker--time .picker__button--clear:hover:before, 99 | .picker--time .picker__button--clear:focus:before { 100 | color: #ffffff; 101 | border-color: #ffffff; 102 | } 103 | 104 | /* ========================================================================== 105 | $CLASSIC-TIME-PICKER 106 | ========================================================================== */ 107 | /** 108 | * Note: the root picker element should __NOT__ be styled 109 | * more than what’s here. Style the `.picker__holder` instead. 110 | */ 111 | .picker--time { 112 | min-width: 256px; 113 | max-width: 320px; 114 | } 115 | /** 116 | * The holder is the base of the picker. 117 | */ 118 | .picker--time .picker__holder { 119 | background: #f2f2f2; 120 | } 121 | @media (min-height: 40.125em) { 122 | .picker--time .picker__holder { 123 | font-size: .875em; 124 | } 125 | } 126 | /** 127 | * The box contains the list of times. 128 | */ 129 | .picker--time .picker__box { 130 | padding: 0; 131 | position: relative; 132 | } 133 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/pickadate/default.css: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-PICKER 3 | ========================================================================== */ 4 | /** 5 | * Note: the root picker element should *NOT* be styled more than what’s here. 6 | */ 7 | .picker { 8 | font-size: 16px; 9 | text-align: left; 10 | line-height: 1.2; 11 | color: #000000; 12 | position: absolute; 13 | z-index: 10000; 14 | -webkit-user-select: none; 15 | -moz-user-select: none; 16 | -ms-user-select: none; 17 | user-select: none; 18 | } 19 | /** 20 | * The picker input element. 21 | */ 22 | .picker__input { 23 | cursor: default; 24 | } 25 | /** 26 | * When the picker is opened, the input element is “activated”. 27 | */ 28 | .picker__input.picker__input--active { 29 | border-color: #0089ec; 30 | } 31 | /** 32 | * The holder is the only “scrollable” top-level container element. 33 | */ 34 | .picker__holder { 35 | width: 100%; 36 | overflow-y: auto; 37 | -webkit-overflow-scrolling: touch; 38 | } 39 | 40 | /*! 41 | * Default mobile-first, responsive styling for pickadate.js 42 | * Demo: http://amsul.github.io/pickadate.js 43 | */ 44 | /** 45 | * Note: the root picker element should *NOT* be styled more than what’s here. 46 | */ 47 | /** 48 | * Make the holder and frame fullscreen. 49 | */ 50 | .picker__holder, 51 | .picker__frame { 52 | top: 0; 53 | bottom: 0; 54 | left: 0; 55 | right: 0; 56 | -webkit-transform: translateY(100%); 57 | -ms-transform: translateY(100%); 58 | transform: translateY(100%); 59 | } 60 | /** 61 | * The holder should overlay the entire screen. 62 | */ 63 | .picker__holder { 64 | position: fixed; 65 | transition: background 0.15s ease-out, -webkit-transform 0s 0.15s; 66 | transition: background 0.15s ease-out, transform 0s 0.15s; 67 | -webkit-backface-visibility: hidden; 68 | } 69 | /** 70 | * The frame that bounds the box contents of the picker. 71 | */ 72 | .picker__frame { 73 | position: absolute; 74 | margin: 0 auto; 75 | min-width: 256px; 76 | max-width: 666px; 77 | width: 100%; 78 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; 79 | filter: alpha(opacity=0); 80 | -moz-opacity: 0; 81 | opacity: 0; 82 | transition: all 0.15s ease-out; 83 | } 84 | @media (min-height: 33.875em) { 85 | .picker__frame { 86 | overflow: visible; 87 | top: auto; 88 | bottom: -100%; 89 | max-height: 80%; 90 | } 91 | } 92 | @media (min-height: 40.125em) { 93 | .picker__frame { 94 | margin-bottom: 7.5%; 95 | } 96 | } 97 | /** 98 | * The wrapper sets the stage to vertically align the box contents. 99 | */ 100 | .picker__wrap { 101 | display: table; 102 | width: 100%; 103 | height: 100%; 104 | } 105 | @media (min-height: 33.875em) { 106 | .picker__wrap { 107 | display: block; 108 | } 109 | } 110 | /** 111 | * The box contains all the picker contents. 112 | */ 113 | .picker__box { 114 | background: #ffffff; 115 | display: table-cell; 116 | vertical-align: middle; 117 | } 118 | @media (min-height: 26.5em) { 119 | .picker__box { 120 | font-size: 1.25em; 121 | } 122 | } 123 | @media (min-height: 33.875em) { 124 | .picker__box { 125 | display: block; 126 | font-size: 1.33em; 127 | border: 1px solid #777777; 128 | border-top-color: #898989; 129 | border-bottom-width: 0; 130 | border-radius: 5px 5px 0 0; 131 | box-shadow: 0 12px 36px 16px rgba(0, 0, 0, 0.24); 132 | } 133 | } 134 | @media (min-height: 40.125em) { 135 | .picker__box { 136 | font-size: 1.5em; 137 | border-bottom-width: 1px; 138 | border-radius: 5px; 139 | } 140 | } 141 | /** 142 | * When the picker opens... 143 | */ 144 | .picker--opened .picker__holder { 145 | -webkit-transform: translateY(0); 146 | -ms-transform: translateY(0); 147 | transform: translateY(0); 148 | background: transparent; 149 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#1E000000,endColorstr=#1E000000)"; 150 | zoom: 1; 151 | background: rgba(0, 0, 0, 0.32); 152 | transition: background 0.15s ease-out; 153 | } 154 | .picker--opened .picker__frame { 155 | -webkit-transform: translateY(0); 156 | -ms-transform: translateY(0); 157 | transform: translateY(0); 158 | -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; 159 | filter: alpha(opacity=100); 160 | -moz-opacity: 1; 161 | opacity: 1; 162 | } 163 | @media (min-height: 33.875em) { 164 | .picker--opened .picker__frame { 165 | top: auto; 166 | bottom: 0; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/legacy.js: -------------------------------------------------------------------------------- 1 | 2 | /*jshint 3 | asi: true, 4 | unused: true, 5 | boss: true, 6 | loopfunc: true, 7 | eqnull: true 8 | */ 9 | 10 | 11 | /*! 12 | * Legacy browser support 13 | */ 14 | 15 | // isArray support 16 | if ( !Array.isArray ) { 17 | Array.isArray = function( value ) { 18 | return {}.toString.call( value ) == '[object Array]' 19 | } 20 | } 21 | 22 | 23 | // Map array support 24 | if ( ![].map ) { 25 | Array.prototype.map = function ( callback, self ) { 26 | var array = this, len = array.length, newArray = new Array( len ) 27 | for ( var i = 0; i < len; i++ ) { 28 | if ( i in array ) { 29 | newArray[ i ] = callback.call( self, array[ i ], i, array ) 30 | } 31 | } 32 | return newArray 33 | } 34 | } 35 | 36 | 37 | // Filter array support 38 | if ( ![].filter ) { 39 | Array.prototype.filter = function( callback ) { 40 | if ( this == null ) throw new TypeError() 41 | var t = Object( this ), len = t.length >>> 0 42 | if ( typeof callback != 'function' ) throw new TypeError() 43 | var newArray = [], thisp = arguments[ 1 ] 44 | for ( var i = 0; i < len; i++ ) { 45 | if ( i in t ) { 46 | var val = t[ i ] 47 | if ( callback.call( thisp, val, i, t ) ) newArray.push( val ) 48 | } 49 | } 50 | return newArray 51 | } 52 | } 53 | 54 | 55 | // Index of array support 56 | if ( ![].indexOf ) { 57 | Array.prototype.indexOf = function( searchElement ) { 58 | if ( this == null ) throw new TypeError() 59 | var t = Object( this ), len = t.length >>> 0 60 | if ( len === 0 ) return -1 61 | var n = 0 62 | if ( arguments.length > 1 ) { 63 | n = Number( arguments[ 1 ] ) 64 | if ( n != n ) { 65 | n = 0 66 | } 67 | else if ( n !== 0 && n != Infinity && n != -Infinity ) { 68 | n = ( n > 0 || -1 ) * Math.floor( Math.abs( n ) ) 69 | } 70 | } 71 | if ( n >= len ) return -1 72 | var k = n >= 0 ? n : Math.max( len - Math.abs( n ), 0 ) 73 | for ( ; k < len; k++ ) { 74 | if ( k in t && t[ k ] === searchElement ) return k 75 | } 76 | return -1 77 | } 78 | } 79 | 80 | 81 | /*! 82 | * Cross-Browser Split 1.1.1 83 | * Copyright 2007-2012 Steven Levithan 84 | * Available under the MIT License 85 | * http://blog.stevenlevithan.com/archives/cross-browser-split 86 | */ 87 | var nativeSplit = String.prototype.split, compliantExecNpcg = /()??/.exec('')[1] === undefined 88 | String.prototype.split = function(separator, limit) { 89 | var str = this 90 | if (Object.prototype.toString.call(separator) !== '[object RegExp]') { 91 | return nativeSplit.call(str, separator, limit) 92 | } 93 | var output = [], 94 | flags = (separator.ignoreCase ? 'i' : '') + 95 | (separator.multiline ? 'm' : '') + 96 | (separator.extended ? 'x' : '') + 97 | (separator.sticky ? 'y' : ''), 98 | lastLastIndex = 0, 99 | separator2, match, lastIndex, lastLength 100 | separator = new RegExp(separator.source, flags + 'g') 101 | str += '' 102 | if (!compliantExecNpcg) { 103 | separator2 = new RegExp('^' + separator.source + '$(?!\\s)', flags) 104 | } 105 | limit = limit === undefined ? -1 >>> 0 : limit >>> 0 106 | while (match = separator.exec(str)) { 107 | lastIndex = match.index + match[0].length 108 | if (lastIndex > lastLastIndex) { 109 | output.push(str.slice(lastLastIndex, match.index)) 110 | if (!compliantExecNpcg && match.length > 1) { 111 | match[0].replace(separator2, function () { 112 | for (var i = 1; i < arguments.length - 2; i++) { 113 | if (arguments[i] === undefined) { 114 | match[i] = undefined 115 | } 116 | } 117 | }) 118 | } 119 | if (match.length > 1 && match.index < str.length) { 120 | Array.prototype.push.apply(output, match.slice(1)) 121 | } 122 | lastLength = match[0].length 123 | lastLastIndex = lastIndex 124 | if (output.length >= limit) { 125 | break 126 | } 127 | } 128 | if (separator.lastIndex === match.index) { 129 | separator.lastIndex++ 130 | } 131 | } 132 | if (lastLastIndex === str.length) { 133 | if (lastLength || !separator.test('')) { 134 | output.push('') 135 | } 136 | } else { 137 | output.push(str.slice(lastLastIndex)) 138 | } 139 | return output.length > limit ? output.slice(0, limit) : output 140 | } 141 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/pickadate/classic.date.css: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-DATE-PICKER 3 | ========================================================================== */ 4 | /** 5 | * The picker box. 6 | */ 7 | .picker__box { 8 | padding: 0 1em; 9 | } 10 | /** 11 | * The header containing the month and year stuff. 12 | */ 13 | .picker__header { 14 | text-align: center; 15 | position: relative; 16 | margin-top: .75em; 17 | } 18 | /** 19 | * The month and year labels. 20 | */ 21 | .picker__month, 22 | .picker__year { 23 | font-weight: 500; 24 | display: inline-block; 25 | margin-left: .25em; 26 | margin-right: .25em; 27 | } 28 | .picker__year { 29 | color: #999999; 30 | font-size: .8em; 31 | font-style: italic; 32 | } 33 | /** 34 | * The month and year selectors. 35 | */ 36 | .picker__select--month, 37 | .picker__select--year { 38 | border: 1px solid #b7b7b7; 39 | height: 2em; 40 | padding: .5em; 41 | margin-left: .25em; 42 | margin-right: .25em; 43 | } 44 | @media (min-width: 24.5em) { 45 | .picker__select--month, 46 | .picker__select--year { 47 | margin-top: -0.5em; 48 | } 49 | } 50 | .picker__select--month { 51 | width: 35%; 52 | } 53 | .picker__select--year { 54 | width: 22.5%; 55 | } 56 | .picker__select--month:focus, 57 | .picker__select--year:focus { 58 | border-color: #0089ec; 59 | } 60 | /** 61 | * The month navigation buttons. 62 | */ 63 | .picker__nav--prev, 64 | .picker__nav--next { 65 | position: absolute; 66 | padding: .5em 1.25em; 67 | width: 1em; 68 | height: 1em; 69 | box-sizing: content-box; 70 | top: -0.25em; 71 | } 72 | @media (min-width: 24.5em) { 73 | .picker__nav--prev, 74 | .picker__nav--next { 75 | top: -0.33em; 76 | } 77 | } 78 | .picker__nav--prev { 79 | left: -1em; 80 | padding-right: 1.25em; 81 | } 82 | @media (min-width: 24.5em) { 83 | .picker__nav--prev { 84 | padding-right: 1.5em; 85 | } 86 | } 87 | .picker__nav--next { 88 | right: -1em; 89 | padding-left: 1.25em; 90 | } 91 | @media (min-width: 24.5em) { 92 | .picker__nav--next { 93 | padding-left: 1.5em; 94 | } 95 | } 96 | .picker__nav--prev:before, 97 | .picker__nav--next:before { 98 | content: " "; 99 | border-top: .5em solid transparent; 100 | border-bottom: .5em solid transparent; 101 | border-right: 0.75em solid #000000; 102 | width: 0; 103 | height: 0; 104 | display: block; 105 | margin: 0 auto; 106 | } 107 | .picker__nav--next:before { 108 | border-right: 0; 109 | border-left: 0.75em solid #000000; 110 | } 111 | .picker__nav--prev:hover, 112 | .picker__nav--next:hover { 113 | cursor: pointer; 114 | color: #000000; 115 | background: #b1dcfb; 116 | } 117 | .picker__nav--disabled, 118 | .picker__nav--disabled:hover, 119 | .picker__nav--disabled:before, 120 | .picker__nav--disabled:before:hover { 121 | cursor: default; 122 | background: none; 123 | border-right-color: #f5f5f5; 124 | border-left-color: #f5f5f5; 125 | } 126 | /** 127 | * The calendar table of dates 128 | */ 129 | .picker__table { 130 | text-align: center; 131 | border-collapse: collapse; 132 | border-spacing: 0; 133 | table-layout: fixed; 134 | font-size: inherit; 135 | width: 100%; 136 | margin-top: .75em; 137 | margin-bottom: .5em; 138 | } 139 | @media (min-height: 33.875em) { 140 | .picker__table { 141 | margin-bottom: .75em; 142 | } 143 | } 144 | .picker__table td { 145 | margin: 0; 146 | padding: 0; 147 | } 148 | /** 149 | * The weekday labels 150 | */ 151 | .picker__weekday { 152 | width: 14.285714286%; 153 | font-size: .75em; 154 | padding-bottom: .25em; 155 | color: #999999; 156 | font-weight: 500; 157 | /* Increase the spacing a tad */ 158 | } 159 | @media (min-height: 33.875em) { 160 | .picker__weekday { 161 | padding-bottom: .5em; 162 | } 163 | } 164 | /** 165 | * The days on the calendar 166 | */ 167 | .picker__day { 168 | padding: .3125em 0; 169 | font-weight: 200; 170 | border: 1px solid transparent; 171 | } 172 | .picker__day--today { 173 | position: relative; 174 | } 175 | .picker__day--today:before { 176 | content: " "; 177 | position: absolute; 178 | top: 2px; 179 | right: 2px; 180 | width: 0; 181 | height: 0; 182 | border-top: 0.5em solid #0059bc; 183 | border-left: .5em solid transparent; 184 | } 185 | .picker__day--disabled:before { 186 | border-top-color: #aaaaaa; 187 | } 188 | .picker__day--outfocus { 189 | color: #dddddd; 190 | } 191 | .picker__day--infocus:hover, 192 | .picker__day--outfocus:hover { 193 | cursor: pointer; 194 | color: #000000; 195 | background: #b1dcfb; 196 | } 197 | .picker__day--highlighted { 198 | border-color: #0089ec; 199 | } 200 | .picker__day--highlighted:hover, 201 | .picker--focused .picker__day--highlighted { 202 | cursor: pointer; 203 | color: #000000; 204 | background: #b1dcfb; 205 | } 206 | .picker__day--selected, 207 | .picker__day--selected:hover, 208 | .picker--focused .picker__day--selected { 209 | background: #0089ec; 210 | color: #ffffff; 211 | } 212 | .picker__day--disabled, 213 | .picker__day--disabled:hover, 214 | .picker--focused .picker__day--disabled { 215 | background: #f5f5f5; 216 | border-color: #f5f5f5; 217 | color: #dddddd; 218 | cursor: default; 219 | } 220 | .picker__day--highlighted.picker__day--disabled, 221 | .picker__day--highlighted.picker__day--disabled:hover { 222 | background: #bbbbbb; 223 | } 224 | /** 225 | * The footer containing the "today", "clear", and "close" buttons. 226 | */ 227 | .picker__footer { 228 | text-align: center; 229 | } 230 | .picker__button--today, 231 | .picker__button--clear, 232 | .picker__button--close { 233 | border: 1px solid #ffffff; 234 | background: #ffffff; 235 | font-size: .8em; 236 | padding: .66em 0; 237 | font-weight: bold; 238 | width: 33%; 239 | display: inline-block; 240 | vertical-align: bottom; 241 | } 242 | .picker__button--today:hover, 243 | .picker__button--clear:hover, 244 | .picker__button--close:hover { 245 | cursor: pointer; 246 | color: #000000; 247 | background: #b1dcfb; 248 | border-bottom-color: #b1dcfb; 249 | } 250 | .picker__button--today:focus, 251 | .picker__button--clear:focus, 252 | .picker__button--close:focus { 253 | background: #b1dcfb; 254 | border-color: #0089ec; 255 | outline: none; 256 | } 257 | .picker__button--today:before, 258 | .picker__button--clear:before, 259 | .picker__button--close:before { 260 | position: relative; 261 | display: inline-block; 262 | height: 0; 263 | } 264 | .picker__button--today:before, 265 | .picker__button--clear:before { 266 | content: " "; 267 | margin-right: .45em; 268 | } 269 | .picker__button--today:before { 270 | top: -0.05em; 271 | width: 0; 272 | border-top: 0.66em solid #0059bc; 273 | border-left: .66em solid transparent; 274 | } 275 | .picker__button--clear:before { 276 | top: -0.25em; 277 | width: .66em; 278 | border-top: 3px solid #ee2200; 279 | } 280 | .picker__button--close:before { 281 | content: "\D7"; 282 | top: -0.1em; 283 | vertical-align: top; 284 | font-size: 1.1em; 285 | margin-right: .35em; 286 | color: #777777; 287 | } 288 | .picker__button--today[disabled], 289 | .picker__button--today[disabled]:hover { 290 | background: #f5f5f5; 291 | border-color: #f5f5f5; 292 | color: #dddddd; 293 | cursor: default; 294 | } 295 | .picker__button--today[disabled]:before { 296 | border-top-color: #aaaaaa; 297 | } 298 | 299 | /* ========================================================================== 300 | $CLASSIC-DATE-PICKER 301 | ========================================================================== */ 302 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/pickadate/default.date.css: -------------------------------------------------------------------------------- 1 | /* ========================================================================== 2 | $BASE-DATE-PICKER 3 | ========================================================================== */ 4 | /** 5 | * The picker box. 6 | */ 7 | .picker__box { 8 | padding: 0 1em; 9 | } 10 | /** 11 | * The header containing the month and year stuff. 12 | */ 13 | .picker__header { 14 | text-align: center; 15 | position: relative; 16 | margin-top: .75em; 17 | } 18 | /** 19 | * The month and year labels. 20 | */ 21 | .picker__month, 22 | .picker__year { 23 | font-weight: 500; 24 | display: inline-block; 25 | margin-left: .25em; 26 | margin-right: .25em; 27 | } 28 | .picker__year { 29 | color: #999999; 30 | font-size: .8em; 31 | font-style: italic; 32 | } 33 | /** 34 | * The month and year selectors. 35 | */ 36 | .picker__select--month, 37 | .picker__select--year { 38 | border: 1px solid #b7b7b7; 39 | height: 2em; 40 | padding: .5em; 41 | margin-left: .25em; 42 | margin-right: .25em; 43 | } 44 | @media (min-width: 24.5em) { 45 | .picker__select--month, 46 | .picker__select--year { 47 | margin-top: -0.5em; 48 | } 49 | } 50 | .picker__select--month { 51 | width: 35%; 52 | } 53 | .picker__select--year { 54 | width: 22.5%; 55 | } 56 | .picker__select--month:focus, 57 | .picker__select--year:focus { 58 | border-color: #0089ec; 59 | } 60 | /** 61 | * The month navigation buttons. 62 | */ 63 | .picker__nav--prev, 64 | .picker__nav--next { 65 | position: absolute; 66 | padding: .5em 1.25em; 67 | width: 1em; 68 | height: 1em; 69 | box-sizing: content-box; 70 | top: -0.25em; 71 | } 72 | @media (min-width: 24.5em) { 73 | .picker__nav--prev, 74 | .picker__nav--next { 75 | top: -0.33em; 76 | } 77 | } 78 | .picker__nav--prev { 79 | left: -1em; 80 | padding-right: 1.25em; 81 | } 82 | @media (min-width: 24.5em) { 83 | .picker__nav--prev { 84 | padding-right: 1.5em; 85 | } 86 | } 87 | .picker__nav--next { 88 | right: -1em; 89 | padding-left: 1.25em; 90 | } 91 | @media (min-width: 24.5em) { 92 | .picker__nav--next { 93 | padding-left: 1.5em; 94 | } 95 | } 96 | .picker__nav--prev:before, 97 | .picker__nav--next:before { 98 | content: " "; 99 | border-top: .5em solid transparent; 100 | border-bottom: .5em solid transparent; 101 | border-right: 0.75em solid #000000; 102 | width: 0; 103 | height: 0; 104 | display: block; 105 | margin: 0 auto; 106 | } 107 | .picker__nav--next:before { 108 | border-right: 0; 109 | border-left: 0.75em solid #000000; 110 | } 111 | .picker__nav--prev:hover, 112 | .picker__nav--next:hover { 113 | cursor: pointer; 114 | color: #000000; 115 | background: #b1dcfb; 116 | } 117 | .picker__nav--disabled, 118 | .picker__nav--disabled:hover, 119 | .picker__nav--disabled:before, 120 | .picker__nav--disabled:before:hover { 121 | cursor: default; 122 | background: none; 123 | border-right-color: #f5f5f5; 124 | border-left-color: #f5f5f5; 125 | } 126 | /** 127 | * The calendar table of dates 128 | */ 129 | .picker__table { 130 | text-align: center; 131 | border-collapse: collapse; 132 | border-spacing: 0; 133 | table-layout: fixed; 134 | font-size: inherit; 135 | width: 100%; 136 | margin-top: .75em; 137 | margin-bottom: .5em; 138 | } 139 | @media (min-height: 33.875em) { 140 | .picker__table { 141 | margin-bottom: .75em; 142 | } 143 | } 144 | .picker__table td { 145 | margin: 0; 146 | padding: 0; 147 | } 148 | /** 149 | * The weekday labels 150 | */ 151 | .picker__weekday { 152 | width: 14.285714286%; 153 | font-size: .75em; 154 | padding-bottom: .25em; 155 | color: #999999; 156 | font-weight: 500; 157 | /* Increase the spacing a tad */ 158 | } 159 | @media (min-height: 33.875em) { 160 | .picker__weekday { 161 | padding-bottom: .5em; 162 | } 163 | } 164 | /** 165 | * The days on the calendar 166 | */ 167 | .picker__day { 168 | padding: .3125em 0; 169 | font-weight: 200; 170 | border: 1px solid transparent; 171 | } 172 | .picker__day--today { 173 | position: relative; 174 | } 175 | .picker__day--today:before { 176 | content: " "; 177 | position: absolute; 178 | top: 2px; 179 | right: 2px; 180 | width: 0; 181 | height: 0; 182 | border-top: 0.5em solid #0059bc; 183 | border-left: .5em solid transparent; 184 | } 185 | .picker__day--disabled:before { 186 | border-top-color: #aaaaaa; 187 | } 188 | .picker__day--outfocus { 189 | color: #dddddd; 190 | } 191 | .picker__day--infocus:hover, 192 | .picker__day--outfocus:hover { 193 | cursor: pointer; 194 | color: #000000; 195 | background: #b1dcfb; 196 | } 197 | .picker__day--highlighted { 198 | border-color: #0089ec; 199 | } 200 | .picker__day--highlighted:hover, 201 | .picker--focused .picker__day--highlighted { 202 | cursor: pointer; 203 | color: #000000; 204 | background: #b1dcfb; 205 | } 206 | .picker__day--selected, 207 | .picker__day--selected:hover, 208 | .picker--focused .picker__day--selected { 209 | background: #0089ec; 210 | color: #ffffff; 211 | } 212 | .picker__day--disabled, 213 | .picker__day--disabled:hover, 214 | .picker--focused .picker__day--disabled { 215 | background: #f5f5f5; 216 | border-color: #f5f5f5; 217 | color: #dddddd; 218 | cursor: default; 219 | } 220 | .picker__day--highlighted.picker__day--disabled, 221 | .picker__day--highlighted.picker__day--disabled:hover { 222 | background: #bbbbbb; 223 | } 224 | /** 225 | * The footer containing the "today", "clear", and "close" buttons. 226 | */ 227 | .picker__footer { 228 | text-align: center; 229 | } 230 | .picker__button--today, 231 | .picker__button--clear, 232 | .picker__button--close { 233 | border: 1px solid #ffffff; 234 | background: #ffffff; 235 | font-size: .8em; 236 | padding: .66em 0; 237 | font-weight: bold; 238 | width: 33%; 239 | display: inline-block; 240 | vertical-align: bottom; 241 | } 242 | .picker__button--today:hover, 243 | .picker__button--clear:hover, 244 | .picker__button--close:hover { 245 | cursor: pointer; 246 | color: #000000; 247 | background: #b1dcfb; 248 | border-bottom-color: #b1dcfb; 249 | } 250 | .picker__button--today:focus, 251 | .picker__button--clear:focus, 252 | .picker__button--close:focus { 253 | background: #b1dcfb; 254 | border-color: #0089ec; 255 | outline: none; 256 | } 257 | .picker__button--today:before, 258 | .picker__button--clear:before, 259 | .picker__button--close:before { 260 | position: relative; 261 | display: inline-block; 262 | height: 0; 263 | } 264 | .picker__button--today:before, 265 | .picker__button--clear:before { 266 | content: " "; 267 | margin-right: .45em; 268 | } 269 | .picker__button--today:before { 270 | top: -0.05em; 271 | width: 0; 272 | border-top: 0.66em solid #0059bc; 273 | border-left: .66em solid transparent; 274 | } 275 | .picker__button--clear:before { 276 | top: -0.25em; 277 | width: .66em; 278 | border-top: 3px solid #ee2200; 279 | } 280 | .picker__button--close:before { 281 | content: "\D7"; 282 | top: -0.1em; 283 | vertical-align: top; 284 | font-size: 1.1em; 285 | margin-right: .35em; 286 | color: #777777; 287 | } 288 | .picker__button--today[disabled], 289 | .picker__button--today[disabled]:hover { 290 | background: #f5f5f5; 291 | border-color: #f5f5f5; 292 | color: #dddddd; 293 | cursor: default; 294 | } 295 | .picker__button--today[disabled]:before { 296 | border-top-color: #aaaaaa; 297 | } 298 | 299 | /* ========================================================================== 300 | $DEFAULT-DATE-PICKER 301 | ========================================================================== */ 302 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/picker.time.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Time picker for pickadate.js v3.5.6 3 | * http://amsul.github.io/pickadate.js/time.htm 4 | */ 5 | 6 | (function ( factory ) { 7 | 8 | // AMD. 9 | if ( typeof define == 'function' && define.amd ) 10 | define( ['picker', 'jquery'], factory ) 11 | 12 | // Node.js/browserify. 13 | else if ( typeof exports == 'object' ) 14 | module.exports = factory( require('./picker.js'), require('jquery') ) 15 | 16 | // Browser globals. 17 | else factory( Picker, jQuery ) 18 | 19 | }(function( Picker, $ ) { 20 | 21 | 22 | /** 23 | * Globals and constants 24 | */ 25 | var HOURS_IN_DAY = 24, 26 | MINUTES_IN_HOUR = 60, 27 | HOURS_TO_NOON = 12, 28 | MINUTES_IN_DAY = HOURS_IN_DAY * MINUTES_IN_HOUR, 29 | _ = Picker._ 30 | 31 | 32 | 33 | /** 34 | * The time picker constructor 35 | */ 36 | function TimePicker( picker, settings ) { 37 | 38 | var clock = this, 39 | elementValue = picker.$node[ 0 ].value, 40 | elementDataValue = picker.$node.data( 'value' ), 41 | valueString = elementDataValue || elementValue, 42 | formatString = elementDataValue ? settings.formatSubmit : settings.format 43 | 44 | clock.settings = settings 45 | clock.$node = picker.$node 46 | 47 | // The queue of methods that will be used to build item objects. 48 | clock.queue = { 49 | interval: 'i', 50 | min: 'measure create', 51 | max: 'measure create', 52 | now: 'now create', 53 | select: 'parse create validate', 54 | highlight: 'parse create validate', 55 | view: 'parse create validate', 56 | disable: 'deactivate', 57 | enable: 'activate' 58 | } 59 | 60 | // The component's item object. 61 | clock.item = {} 62 | 63 | clock.item.clear = null 64 | clock.item.interval = settings.interval || 30 65 | clock.item.disable = ( settings.disable || [] ).slice( 0 ) 66 | clock.item.enable = -(function( collectionDisabled ) { 67 | return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 68 | })( clock.item.disable ) 69 | 70 | clock. 71 | set( 'min', settings.min ). 72 | set( 'max', settings.max ). 73 | set( 'now' ) 74 | 75 | // When there’s a value, set the `select`, which in turn 76 | // also sets the `highlight` and `view`. 77 | if ( valueString ) { 78 | clock.set( 'select', valueString, { 79 | format: formatString 80 | }) 81 | } 82 | 83 | // If there’s no value, default to highlighting “today”. 84 | else { 85 | clock. 86 | set( 'select', null ). 87 | set( 'highlight', clock.item.now ) 88 | } 89 | 90 | // The keycode to movement mapping. 91 | clock.key = { 92 | 40: 1, // Down 93 | 38: -1, // Up 94 | 39: 1, // Right 95 | 37: -1, // Left 96 | go: function( timeChange ) { 97 | clock.set( 98 | 'highlight', 99 | clock.item.highlight.pick + timeChange * clock.item.interval, 100 | { interval: timeChange * clock.item.interval } 101 | ) 102 | this.render() 103 | } 104 | } 105 | 106 | 107 | // Bind some picker events. 108 | picker. 109 | on( 'render', function() { 110 | var $pickerHolder = picker.$root.children(), 111 | $viewset = $pickerHolder.find( '.' + settings.klass.viewset ), 112 | vendors = function( prop ) { 113 | return ['webkit', 'moz', 'ms', 'o', ''].map(function( vendor ) { 114 | return ( vendor ? '-' + vendor + '-' : '' ) + prop 115 | }) 116 | }, 117 | animations = function( $el, state ) { 118 | vendors( 'transform' ).map(function( prop ) { 119 | $el.css( prop, state ) 120 | }) 121 | vendors( 'transition' ).map(function( prop ) { 122 | $el.css( prop, state ) 123 | }) 124 | } 125 | if ( $viewset.length ) { 126 | animations( $pickerHolder, 'none' ) 127 | $pickerHolder[ 0 ].scrollTop = ~~$viewset.position().top - ( $viewset[ 0 ].clientHeight * 2 ) 128 | animations( $pickerHolder, '' ) 129 | } 130 | }, 1 ). 131 | on( 'open', function() { 132 | picker.$root.find( 'button' ).attr( 'disabled', false ) 133 | }, 1 ). 134 | on( 'close', function() { 135 | picker.$root.find( 'button' ).attr( 'disabled', true ) 136 | }, 1 ) 137 | 138 | } //TimePicker 139 | 140 | 141 | /** 142 | * Set a timepicker item object. 143 | */ 144 | TimePicker.prototype.set = function( type, value, options ) { 145 | 146 | var clock = this, 147 | clockItem = clock.item 148 | 149 | // If the value is `null` just set it immediately. 150 | if ( value === null ) { 151 | if ( type == 'clear' ) type = 'select' 152 | clockItem[ type ] = value 153 | return clock 154 | } 155 | 156 | // Otherwise go through the queue of methods, and invoke the functions. 157 | // Update this as the time unit, and set the final value as this item. 158 | // * In the case of `enable`, keep the queue but set `disable` instead. 159 | // And in the case of `flip`, keep the queue but set `enable` instead. 160 | clockItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = clock.queue[ type ].split( ' ' ).map( function( method ) { 161 | value = clock[ method ]( type, value, options ) 162 | return value 163 | }).pop() 164 | 165 | // Check if we need to cascade through more updates. 166 | if ( type == 'select' ) { 167 | clock.set( 'highlight', clockItem.select, options ) 168 | } 169 | else if ( type == 'highlight' ) { 170 | clock.set( 'view', clockItem.highlight, options ) 171 | } 172 | else if ( type == 'interval' ) { 173 | clock. 174 | set( 'min', clockItem.min, options ). 175 | set( 'max', clockItem.max, options ) 176 | } 177 | else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) { 178 | if ( clockItem.select && clock.disabled( clockItem.select ) ) { 179 | clock.set( 'select', value, options ) 180 | } 181 | if ( clockItem.highlight && clock.disabled( clockItem.highlight ) ) { 182 | clock.set( 'highlight', value, options ) 183 | } 184 | if ( type == 'min' ) { 185 | clock.set( 'max', clockItem.max, options ) 186 | } 187 | } 188 | 189 | return clock 190 | } //TimePicker.prototype.set 191 | 192 | 193 | /** 194 | * Get a timepicker item object. 195 | */ 196 | TimePicker.prototype.get = function( type ) { 197 | return this.item[ type ] 198 | } //TimePicker.prototype.get 199 | 200 | 201 | /** 202 | * Create a picker time object. 203 | */ 204 | TimePicker.prototype.create = function( type, value, options ) { 205 | 206 | var clock = this 207 | 208 | // If there’s no value, use the type as the value. 209 | value = value === undefined ? type : value 210 | 211 | // If it’s a date object, convert it into an array. 212 | if ( _.isDate( value ) ) { 213 | value = [ value.getHours(), value.getMinutes() ] 214 | } 215 | 216 | // If it’s an object, use the “pick” value. 217 | if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { 218 | value = value.pick 219 | } 220 | 221 | // If it’s an array, convert it into minutes. 222 | else if ( $.isArray( value ) ) { 223 | value = +value[ 0 ] * MINUTES_IN_HOUR + (+value[ 1 ]) 224 | } 225 | 226 | // If no valid value is passed, set it to “now”. 227 | else if ( !_.isInteger( value ) ) { 228 | value = clock.now( type, value, options ) 229 | } 230 | 231 | // If we’re setting the max, make sure it’s greater than the min. 232 | if ( type == 'max' && value < clock.item.min.pick ) { 233 | value += MINUTES_IN_DAY 234 | } 235 | 236 | // If the value doesn’t fall directly on the interval, 237 | // add one interval to indicate it as “passed”. 238 | if ( type != 'min' && type != 'max' && (value - clock.item.min.pick) % clock.item.interval !== 0 ) { 239 | value += clock.item.interval 240 | } 241 | 242 | // Normalize it into a “reachable” interval. 243 | value = clock.normalize( type, value, options ) 244 | 245 | // Return the compiled object. 246 | return { 247 | 248 | // Divide to get hours from minutes. 249 | hour: ~~( HOURS_IN_DAY + value / MINUTES_IN_HOUR ) % HOURS_IN_DAY, 250 | 251 | // The remainder is the minutes. 252 | mins: ( MINUTES_IN_HOUR + value % MINUTES_IN_HOUR ) % MINUTES_IN_HOUR, 253 | 254 | // The time in total minutes. 255 | time: ( MINUTES_IN_DAY + value ) % MINUTES_IN_DAY, 256 | 257 | // Reference to the “relative” value to pick. 258 | pick: value % MINUTES_IN_DAY 259 | } 260 | } //TimePicker.prototype.create 261 | 262 | 263 | /** 264 | * Create a range limit object using an array, date object, 265 | * literal “true”, or integer relative to another time. 266 | */ 267 | TimePicker.prototype.createRange = function( from, to ) { 268 | 269 | var clock = this, 270 | createTime = function( time ) { 271 | if ( time === true || $.isArray( time ) || _.isDate( time ) ) { 272 | return clock.create( time ) 273 | } 274 | return time 275 | } 276 | 277 | // Create objects if possible. 278 | if ( !_.isInteger( from ) ) { 279 | from = createTime( from ) 280 | } 281 | if ( !_.isInteger( to ) ) { 282 | to = createTime( to ) 283 | } 284 | 285 | // Create relative times. 286 | if ( _.isInteger( from ) && $.isPlainObject( to ) ) { 287 | from = [ to.hour, to.mins + ( from * clock.settings.interval ) ]; 288 | } 289 | else if ( _.isInteger( to ) && $.isPlainObject( from ) ) { 290 | to = [ from.hour, from.mins + ( to * clock.settings.interval ) ]; 291 | } 292 | 293 | return { 294 | from: createTime( from ), 295 | to: createTime( to ) 296 | } 297 | } //TimePicker.prototype.createRange 298 | 299 | 300 | /** 301 | * Check if a time unit falls within a time range object. 302 | */ 303 | TimePicker.prototype.withinRange = function( range, timeUnit ) { 304 | range = this.createRange(range.from, range.to) 305 | return timeUnit.pick >= range.from.pick && timeUnit.pick <= range.to.pick 306 | } 307 | 308 | 309 | /** 310 | * Check if two time range objects overlap. 311 | */ 312 | TimePicker.prototype.overlapRanges = function( one, two ) { 313 | 314 | var clock = this 315 | 316 | // Convert the ranges into comparable times. 317 | one = clock.createRange( one.from, one.to ) 318 | two = clock.createRange( two.from, two.to ) 319 | 320 | return clock.withinRange( one, two.from ) || clock.withinRange( one, two.to ) || 321 | clock.withinRange( two, one.from ) || clock.withinRange( two, one.to ) 322 | } 323 | 324 | 325 | /** 326 | * Get the time relative to now. 327 | */ 328 | TimePicker.prototype.now = function( type, value/*, options*/ ) { 329 | 330 | var interval = this.item.interval, 331 | date = new Date(), 332 | nowMinutes = date.getHours() * MINUTES_IN_HOUR + date.getMinutes(), 333 | isValueInteger = _.isInteger( value ), 334 | isBelowInterval 335 | 336 | // Make sure “now” falls within the interval range. 337 | nowMinutes -= nowMinutes % interval 338 | 339 | // Check if the difference is less than the interval itself. 340 | isBelowInterval = value < 0 && interval * value + nowMinutes <= -interval 341 | 342 | // Add an interval because the time has “passed”. 343 | nowMinutes += type == 'min' && isBelowInterval ? 0 : interval 344 | 345 | // If the value is a number, adjust by that many intervals. 346 | if ( isValueInteger ) { 347 | nowMinutes += interval * ( 348 | isBelowInterval && type != 'max' ? 349 | value + 1 : 350 | value 351 | ) 352 | } 353 | 354 | // Return the final calculation. 355 | return nowMinutes 356 | } //TimePicker.prototype.now 357 | 358 | 359 | /** 360 | * Normalize minutes to be “reachable” based on the min and interval. 361 | */ 362 | TimePicker.prototype.normalize = function( type, value/*, options*/ ) { 363 | 364 | var interval = this.item.interval, 365 | minTime = this.item.min && this.item.min.pick || 0 366 | 367 | // If setting min time, don’t shift anything. 368 | // Otherwise get the value and min difference and then 369 | // normalize the difference with the interval. 370 | value -= type == 'min' ? 0 : ( value - minTime ) % interval 371 | 372 | // Return the adjusted value. 373 | return value 374 | } //TimePicker.prototype.normalize 375 | 376 | 377 | /** 378 | * Measure the range of minutes. 379 | */ 380 | TimePicker.prototype.measure = function( type, value, options ) { 381 | 382 | var clock = this 383 | 384 | // If it’s anything false-y, set it to the default. 385 | if ( !value ) { 386 | value = type == 'min' ? [ 0, 0 ] : [ HOURS_IN_DAY - 1, MINUTES_IN_HOUR - 1 ] 387 | } 388 | 389 | // If it’s a string, parse it. 390 | if ( typeof value == 'string' ) { 391 | value = clock.parse( type, value ) 392 | } 393 | 394 | // If it’s a literal true, or an integer, make it relative to now. 395 | else if ( value === true || _.isInteger( value ) ) { 396 | value = clock.now( type, value, options ) 397 | } 398 | 399 | // If it’s an object already, just normalize it. 400 | else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { 401 | value = clock.normalize( type, value.pick, options ) 402 | } 403 | 404 | return value 405 | } ///TimePicker.prototype.measure 406 | 407 | 408 | /** 409 | * Validate an object as enabled. 410 | */ 411 | TimePicker.prototype.validate = function( type, timeObject, options ) { 412 | 413 | var clock = this, 414 | interval = options && options.interval ? options.interval : clock.item.interval 415 | 416 | // Check if the object is disabled. 417 | if ( clock.disabled( timeObject ) ) { 418 | 419 | // Shift with the interval until we reach an enabled time. 420 | timeObject = clock.shift( timeObject, interval ) 421 | } 422 | 423 | // Scope the object into range. 424 | timeObject = clock.scope( timeObject ) 425 | 426 | // Do a second check to see if we landed on a disabled min/max. 427 | // In that case, shift using the opposite interval as before. 428 | if ( clock.disabled( timeObject ) ) { 429 | timeObject = clock.shift( timeObject, interval * -1 ) 430 | } 431 | 432 | // Return the final object. 433 | return timeObject 434 | } //TimePicker.prototype.validate 435 | 436 | 437 | /** 438 | * Check if an object is disabled. 439 | */ 440 | TimePicker.prototype.disabled = function( timeToVerify ) { 441 | 442 | var clock = this, 443 | 444 | // Filter through the disabled times to check if this is one. 445 | isDisabledMatch = clock.item.disable.filter( function( timeToDisable ) { 446 | 447 | // If the time is a number, match the hours. 448 | if ( _.isInteger( timeToDisable ) ) { 449 | return timeToVerify.hour == timeToDisable 450 | } 451 | 452 | // If it’s an array, create the object and match the times. 453 | if ( $.isArray( timeToDisable ) || _.isDate( timeToDisable ) ) { 454 | return timeToVerify.pick == clock.create( timeToDisable ).pick 455 | } 456 | 457 | // If it’s an object, match a time within the “from” and “to” range. 458 | if ( $.isPlainObject( timeToDisable ) ) { 459 | return clock.withinRange( timeToDisable, timeToVerify ) 460 | } 461 | }) 462 | 463 | // If this time matches a disabled time, confirm it’s not inverted. 464 | isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( timeToDisable ) { 465 | return $.isArray( timeToDisable ) && timeToDisable[2] == 'inverted' || 466 | $.isPlainObject( timeToDisable ) && timeToDisable.inverted 467 | }).length 468 | 469 | // If the clock is "enabled" flag is flipped, flip the condition. 470 | return clock.item.enable === -1 ? !isDisabledMatch : isDisabledMatch || 471 | timeToVerify.pick < clock.item.min.pick || 472 | timeToVerify.pick > clock.item.max.pick 473 | } //TimePicker.prototype.disabled 474 | 475 | 476 | /** 477 | * Shift an object by an interval until we reach an enabled object. 478 | */ 479 | TimePicker.prototype.shift = function( timeObject, interval ) { 480 | 481 | var clock = this, 482 | minLimit = clock.item.min.pick, 483 | maxLimit = clock.item.max.pick/*, 484 | safety = 1000*/ 485 | 486 | interval = interval || clock.item.interval 487 | 488 | // Keep looping as long as the time is disabled. 489 | while ( /*safety &&*/ clock.disabled( timeObject ) ) { 490 | 491 | /*safety -= 1 492 | if ( !safety ) { 493 | throw 'Fell into an infinite loop while shifting to ' + timeObject.hour + ':' + timeObject.mins + '.' 494 | }*/ 495 | 496 | // Increase/decrease the time by the interval and keep looping. 497 | timeObject = clock.create( timeObject.pick += interval ) 498 | 499 | // If we've looped beyond the limits, break out of the loop. 500 | if ( timeObject.pick <= minLimit || timeObject.pick >= maxLimit ) { 501 | break 502 | } 503 | } 504 | 505 | // Return the final object. 506 | return timeObject 507 | } //TimePicker.prototype.shift 508 | 509 | 510 | /** 511 | * Scope an object to be within range of min and max. 512 | */ 513 | TimePicker.prototype.scope = function( timeObject ) { 514 | var minLimit = this.item.min.pick, 515 | maxLimit = this.item.max.pick 516 | return this.create( timeObject.pick > maxLimit ? maxLimit : timeObject.pick < minLimit ? minLimit : timeObject ) 517 | } //TimePicker.prototype.scope 518 | 519 | 520 | /** 521 | * Parse a string into a usable type. 522 | */ 523 | TimePicker.prototype.parse = function( type, value, options ) { 524 | 525 | var hour, minutes, isPM, item, parseValue, 526 | clock = this, 527 | parsingObject = {} 528 | 529 | // If it’s already parsed, we’re good. 530 | if ( !value || typeof value != 'string' ) { 531 | return value 532 | } 533 | 534 | // We need a `.format` to parse the value with. 535 | if ( !( options && options.format ) ) { 536 | options = options || {} 537 | options.format = clock.settings.format 538 | } 539 | 540 | // Convert the format into an array and then map through it. 541 | clock.formats.toArray( options.format ).map( function( label ) { 542 | 543 | var 544 | substring, 545 | 546 | // Grab the formatting label. 547 | formattingLabel = clock.formats[ label ], 548 | 549 | // The format length is from the formatting label function or the 550 | // label length without the escaping exclamation (!) mark. 551 | formatLength = formattingLabel ? 552 | _.trigger( formattingLabel, clock, [ value, parsingObject ] ) : 553 | label.replace( /^!/, '' ).length 554 | 555 | // If there's a format label, split the value up to the format length. 556 | // Then add it to the parsing object with appropriate label. 557 | if ( formattingLabel ) { 558 | substring = value.substr( 0, formatLength ) 559 | parsingObject[ label ] = substring.match(/^\d+$/) ? +substring : substring 560 | } 561 | 562 | // Update the time value as the substring from format length to end. 563 | value = value.substr( formatLength ) 564 | }) 565 | 566 | // Grab the hour and minutes from the parsing object. 567 | for ( item in parsingObject ) { 568 | parseValue = parsingObject[item] 569 | if ( _.isInteger(parseValue) ) { 570 | if ( item.match(/^(h|hh)$/i) ) { 571 | hour = parseValue 572 | if ( item == 'h' || item == 'hh' ) { 573 | hour %= 12 574 | } 575 | } 576 | else if ( item == 'i' ) { 577 | minutes = parseValue 578 | } 579 | } 580 | else if ( item.match(/^a$/i) && parseValue.match(/^p/i) && ('h' in parsingObject || 'hh' in parsingObject) ) { 581 | isPM = true 582 | } 583 | } 584 | 585 | // Calculate it in minutes and return. 586 | return (isPM ? hour + 12 : hour) * MINUTES_IN_HOUR + minutes 587 | } //TimePicker.prototype.parse 588 | 589 | 590 | /** 591 | * Various formats to display the object in. 592 | */ 593 | TimePicker.prototype.formats = { 594 | 595 | h: function( string, timeObject ) { 596 | 597 | // If there's string, then get the digits length. 598 | // Otherwise return the selected hour in "standard" format. 599 | return string ? _.digits( string ) : timeObject.hour % HOURS_TO_NOON || HOURS_TO_NOON 600 | }, 601 | hh: function( string, timeObject ) { 602 | 603 | // If there's a string, then the length is always 2. 604 | // Otherwise return the selected hour in "standard" format with a leading zero. 605 | return string ? 2 : _.lead( timeObject.hour % HOURS_TO_NOON || HOURS_TO_NOON ) 606 | }, 607 | H: function( string, timeObject ) { 608 | 609 | // If there's string, then get the digits length. 610 | // Otherwise return the selected hour in "military" format as a string. 611 | return string ? _.digits( string ) : '' + ( timeObject.hour % 24 ) 612 | }, 613 | HH: function( string, timeObject ) { 614 | 615 | // If there's string, then get the digits length. 616 | // Otherwise return the selected hour in "military" format with a leading zero. 617 | return string ? _.digits( string ) : _.lead( timeObject.hour % 24 ) 618 | }, 619 | i: function( string, timeObject ) { 620 | 621 | // If there's a string, then the length is always 2. 622 | // Otherwise return the selected minutes. 623 | return string ? 2 : _.lead( timeObject.mins ) 624 | }, 625 | a: function( string, timeObject ) { 626 | 627 | // If there's a string, then the length is always 4. 628 | // Otherwise check if it's more than "noon" and return either am/pm. 629 | return string ? 4 : MINUTES_IN_DAY / 2 > timeObject.time % MINUTES_IN_DAY ? 'a.m.' : 'p.m.' 630 | }, 631 | A: function( string, timeObject ) { 632 | 633 | // If there's a string, then the length is always 2. 634 | // Otherwise check if it's more than "noon" and return either am/pm. 635 | return string ? 2 : MINUTES_IN_DAY / 2 > timeObject.time % MINUTES_IN_DAY ? 'AM' : 'PM' 636 | }, 637 | 638 | // Create an array by splitting the formatting string passed. 639 | toArray: function( formatString ) { return formatString.split( /(h{1,2}|H{1,2}|i|a|A|!.)/g ) }, 640 | 641 | // Format an object into a string using the formatting options. 642 | toString: function ( formatString, itemObject ) { 643 | var clock = this 644 | return clock.formats.toArray( formatString ).map( function( label ) { 645 | return _.trigger( clock.formats[ label ], clock, [ 0, itemObject ] ) || label.replace( /^!/, '' ) 646 | }).join( '' ) 647 | } 648 | } //TimePicker.prototype.formats 649 | 650 | 651 | 652 | 653 | /** 654 | * Check if two time units are the exact. 655 | */ 656 | TimePicker.prototype.isTimeExact = function( one, two ) { 657 | 658 | var clock = this 659 | 660 | // When we’re working with minutes, do a direct comparison. 661 | if ( 662 | ( _.isInteger( one ) && _.isInteger( two ) ) || 663 | ( typeof one == 'boolean' && typeof two == 'boolean' ) 664 | ) { 665 | return one === two 666 | } 667 | 668 | // When we’re working with time representations, compare the “pick” value. 669 | if ( 670 | ( _.isDate( one ) || $.isArray( one ) ) && 671 | ( _.isDate( two ) || $.isArray( two ) ) 672 | ) { 673 | return clock.create( one ).pick === clock.create( two ).pick 674 | } 675 | 676 | // When we’re working with range objects, compare the “from” and “to”. 677 | if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 678 | return clock.isTimeExact( one.from, two.from ) && clock.isTimeExact( one.to, two.to ) 679 | } 680 | 681 | return false 682 | } 683 | 684 | 685 | /** 686 | * Check if two time units overlap. 687 | */ 688 | TimePicker.prototype.isTimeOverlap = function( one, two ) { 689 | 690 | var clock = this 691 | 692 | // When we’re working with an integer, compare the hours. 693 | if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { 694 | return one === clock.create( two ).hour 695 | } 696 | if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { 697 | return two === clock.create( one ).hour 698 | } 699 | 700 | // When we’re working with range objects, check if the ranges overlap. 701 | if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 702 | return clock.overlapRanges( one, two ) 703 | } 704 | 705 | return false 706 | } 707 | 708 | 709 | /** 710 | * Flip the “enabled” state. 711 | */ 712 | TimePicker.prototype.flipEnable = function(val) { 713 | var itemObject = this.item 714 | itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) 715 | } 716 | 717 | 718 | /** 719 | * Mark a collection of times as “disabled”. 720 | */ 721 | TimePicker.prototype.deactivate = function( type, timesToDisable ) { 722 | 723 | var clock = this, 724 | disabledItems = clock.item.disable.slice(0) 725 | 726 | 727 | // If we’re flipping, that’s all we need to do. 728 | if ( timesToDisable == 'flip' ) { 729 | clock.flipEnable() 730 | } 731 | 732 | else if ( timesToDisable === false ) { 733 | clock.flipEnable(1) 734 | disabledItems = [] 735 | } 736 | 737 | else if ( timesToDisable === true ) { 738 | clock.flipEnable(-1) 739 | disabledItems = [] 740 | } 741 | 742 | // Otherwise go through the times to disable. 743 | else { 744 | 745 | timesToDisable.map(function( unitToDisable ) { 746 | 747 | var matchFound 748 | 749 | // When we have disabled items, check for matches. 750 | // If something is matched, immediately break out. 751 | for ( var index = 0; index < disabledItems.length; index += 1 ) { 752 | if ( clock.isTimeExact( unitToDisable, disabledItems[index] ) ) { 753 | matchFound = true 754 | break 755 | } 756 | } 757 | 758 | // If nothing was found, add the validated unit to the collection. 759 | if ( !matchFound ) { 760 | if ( 761 | _.isInteger( unitToDisable ) || 762 | _.isDate( unitToDisable ) || 763 | $.isArray( unitToDisable ) || 764 | ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to ) 765 | ) { 766 | disabledItems.push( unitToDisable ) 767 | } 768 | } 769 | }) 770 | } 771 | 772 | // Return the updated collection. 773 | return disabledItems 774 | } //TimePicker.prototype.deactivate 775 | 776 | 777 | /** 778 | * Mark a collection of times as “enabled”. 779 | */ 780 | TimePicker.prototype.activate = function( type, timesToEnable ) { 781 | 782 | var clock = this, 783 | disabledItems = clock.item.disable, 784 | disabledItemsCount = disabledItems.length 785 | 786 | // If we’re flipping, that’s all we need to do. 787 | if ( timesToEnable == 'flip' ) { 788 | clock.flipEnable() 789 | } 790 | 791 | else if ( timesToEnable === true ) { 792 | clock.flipEnable(1) 793 | disabledItems = [] 794 | } 795 | 796 | else if ( timesToEnable === false ) { 797 | clock.flipEnable(-1) 798 | disabledItems = [] 799 | } 800 | 801 | // Otherwise go through the disabled times. 802 | else { 803 | 804 | timesToEnable.map(function( unitToEnable ) { 805 | 806 | var matchFound, 807 | disabledUnit, 808 | index, 809 | isRangeMatched 810 | 811 | // Go through the disabled items and try to find a match. 812 | for ( index = 0; index < disabledItemsCount; index += 1 ) { 813 | 814 | disabledUnit = disabledItems[index] 815 | 816 | // When an exact match is found, remove it from the collection. 817 | if ( clock.isTimeExact( disabledUnit, unitToEnable ) ) { 818 | matchFound = disabledItems[index] = null 819 | isRangeMatched = true 820 | break 821 | } 822 | 823 | // When an overlapped match is found, add the “inverted” state to it. 824 | else if ( clock.isTimeOverlap( disabledUnit, unitToEnable ) ) { 825 | if ( $.isPlainObject( unitToEnable ) ) { 826 | unitToEnable.inverted = true 827 | matchFound = unitToEnable 828 | } 829 | else if ( $.isArray( unitToEnable ) ) { 830 | matchFound = unitToEnable 831 | if ( !matchFound[2] ) matchFound.push( 'inverted' ) 832 | } 833 | else if ( _.isDate( unitToEnable ) ) { 834 | matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ] 835 | } 836 | break 837 | } 838 | } 839 | 840 | // If a match was found, remove a previous duplicate entry. 841 | if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 842 | if ( clock.isTimeExact( disabledItems[index], unitToEnable ) ) { 843 | disabledItems[index] = null 844 | break 845 | } 846 | } 847 | 848 | // In the event that we’re dealing with an overlap of range times, 849 | // make sure there are no “inverted” times because of it. 850 | if ( isRangeMatched ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 851 | if ( clock.isTimeOverlap( disabledItems[index], unitToEnable ) ) { 852 | disabledItems[index] = null 853 | break 854 | } 855 | } 856 | 857 | // If something is still matched, add it into the collection. 858 | if ( matchFound ) { 859 | disabledItems.push( matchFound ) 860 | } 861 | }) 862 | } 863 | 864 | // Return the updated collection. 865 | return disabledItems.filter(function( val ) { return val != null }) 866 | } //TimePicker.prototype.activate 867 | 868 | 869 | /** 870 | * The division to use for the range intervals. 871 | */ 872 | TimePicker.prototype.i = function( type, value/*, options*/ ) { 873 | return _.isInteger( value ) && value > 0 ? value : this.item.interval 874 | } 875 | 876 | 877 | /** 878 | * Create a string for the nodes in the picker. 879 | */ 880 | TimePicker.prototype.nodes = function( isOpen ) { 881 | 882 | var 883 | clock = this, 884 | settings = clock.settings, 885 | selectedObject = clock.item.select, 886 | highlightedObject = clock.item.highlight, 887 | viewsetObject = clock.item.view, 888 | disabledCollection = clock.item.disable 889 | 890 | return _.node( 891 | 'ul', 892 | _.group({ 893 | min: clock.item.min.pick, 894 | max: clock.item.max.pick, 895 | i: clock.item.interval, 896 | node: 'li', 897 | item: function( loopedTime ) { 898 | loopedTime = clock.create( loopedTime ) 899 | var timeMinutes = loopedTime.pick, 900 | isSelected = selectedObject && selectedObject.pick == timeMinutes, 901 | isHighlighted = highlightedObject && highlightedObject.pick == timeMinutes, 902 | isDisabled = disabledCollection && clock.disabled( loopedTime ), 903 | formattedTime = _.trigger( clock.formats.toString, clock, [ settings.format, loopedTime ] ) 904 | return [ 905 | _.trigger( clock.formats.toString, clock, [ _.trigger( settings.formatLabel, clock, [ loopedTime ] ) || settings.format, loopedTime ] ), 906 | (function( klasses ) { 907 | 908 | if ( isSelected ) { 909 | klasses.push( settings.klass.selected ) 910 | } 911 | 912 | if ( isHighlighted ) { 913 | klasses.push( settings.klass.highlighted ) 914 | } 915 | 916 | if ( viewsetObject && viewsetObject.pick == timeMinutes ) { 917 | klasses.push( settings.klass.viewset ) 918 | } 919 | 920 | if ( isDisabled ) { 921 | klasses.push( settings.klass.disabled ) 922 | } 923 | 924 | return klasses.join( ' ' ) 925 | })( [ settings.klass.listItem ] ), 926 | 'data-pick=' + loopedTime.pick + ' ' + _.ariaAttr({ 927 | role: 'option', 928 | label: formattedTime, 929 | selected: isSelected && clock.$node.val() === formattedTime ? true : null, 930 | activedescendant: isHighlighted ? true : null, 931 | disabled: isDisabled ? true : null 932 | }) 933 | ] 934 | } 935 | }) + 936 | 937 | // * For Firefox forms to submit, make sure to set the button’s `type` attribute as “button”. 938 | _.node( 939 | 'li', 940 | _.node( 941 | 'button', 942 | settings.clear, 943 | settings.klass.buttonClear, 944 | 'type=button data-clear=1' + ( isOpen ? '' : ' disabled' ) + ' ' + 945 | _.ariaAttr({ controls: clock.$node[0].id }) 946 | ), 947 | '', _.ariaAttr({ role: 'presentation' }) 948 | ), 949 | settings.klass.list, 950 | _.ariaAttr({ role: 'listbox', controls: clock.$node[0].id }) 951 | ) 952 | } //TimePicker.prototype.nodes 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | /** 961 | * Extend the picker to add the component with the defaults. 962 | */ 963 | TimePicker.defaults = (function( prefix ) { 964 | 965 | return { 966 | 967 | // Clear 968 | clear: 'Clear', 969 | 970 | // The format to show on the `input` element 971 | format: 'h:i A', 972 | 973 | // The interval between each time 974 | interval: 30, 975 | 976 | // Picker close behavior 977 | closeOnSelect: true, 978 | closeOnClear: true, 979 | 980 | // Classes 981 | klass: { 982 | 983 | picker: prefix + ' ' + prefix + '--time', 984 | holder: prefix + '__holder', 985 | 986 | list: prefix + '__list', 987 | listItem: prefix + '__list-item', 988 | 989 | disabled: prefix + '__list-item--disabled', 990 | selected: prefix + '__list-item--selected', 991 | highlighted: prefix + '__list-item--highlighted', 992 | viewset: prefix + '__list-item--viewset', 993 | now: prefix + '__list-item--now', 994 | 995 | buttonClear: prefix + '__button--clear' 996 | } 997 | } 998 | })( Picker.klasses().picker ) 999 | 1000 | 1001 | 1002 | 1003 | 1004 | /** 1005 | * Extend the picker to add the time picker. 1006 | */ 1007 | Picker.extend( 'pickatime', TimePicker ) 1008 | 1009 | 1010 | })); 1011 | 1012 | 1013 | 1014 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/picker.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * pickadate.js v3.5.6, 2015/04/20 3 | * By Amsul, http://amsul.ca 4 | * Hosted on http://amsul.github.io/pickadate.js 5 | * Licensed under MIT 6 | */ 7 | 8 | (function ( factory ) { 9 | 10 | // AMD. 11 | if ( typeof define == 'function' && define.amd ) 12 | define( 'picker', ['jquery'], factory ) 13 | 14 | // Node.js/browserify. 15 | else if ( typeof exports == 'object' ) 16 | module.exports = factory( require('jquery') ) 17 | 18 | // Browser globals. 19 | else this.Picker = factory( jQuery ) 20 | 21 | }(function( $ ) { 22 | 23 | var $window = $( window ) 24 | var $document = $( document ) 25 | var $html = $( document.documentElement ) 26 | var supportsTransitions = document.documentElement.style.transition != null 27 | 28 | 29 | /** 30 | * The picker constructor that creates a blank picker. 31 | */ 32 | function PickerConstructor( ELEMENT, NAME, COMPONENT, OPTIONS ) { 33 | 34 | // If there’s no element, return the picker constructor. 35 | if ( !ELEMENT ) return PickerConstructor 36 | 37 | 38 | var 39 | IS_DEFAULT_THEME = false, 40 | 41 | 42 | // The state of the picker. 43 | STATE = { 44 | id: ELEMENT.id || 'P' + Math.abs( ~~(Math.random() * new Date()) ) 45 | }, 46 | 47 | 48 | // Merge the defaults and options passed. 49 | SETTINGS = COMPONENT ? $.extend( true, {}, COMPONENT.defaults, OPTIONS ) : OPTIONS || {}, 50 | 51 | 52 | // Merge the default classes with the settings classes. 53 | CLASSES = $.extend( {}, PickerConstructor.klasses(), SETTINGS.klass ), 54 | 55 | 56 | // The element node wrapper into a jQuery object. 57 | $ELEMENT = $( ELEMENT ), 58 | 59 | 60 | // Pseudo picker constructor. 61 | PickerInstance = function() { 62 | return this.start() 63 | }, 64 | 65 | 66 | // The picker prototype. 67 | P = PickerInstance.prototype = { 68 | 69 | constructor: PickerInstance, 70 | 71 | $node: $ELEMENT, 72 | 73 | 74 | /** 75 | * Initialize everything 76 | */ 77 | start: function() { 78 | 79 | // If it’s already started, do nothing. 80 | if ( STATE && STATE.start ) return P 81 | 82 | 83 | // Update the picker states. 84 | STATE.methods = {} 85 | STATE.start = true 86 | STATE.open = false 87 | STATE.type = ELEMENT.type 88 | 89 | 90 | // Confirm focus state, convert into text input to remove UA stylings, 91 | // and set as readonly to prevent keyboard popup. 92 | ELEMENT.autofocus = ELEMENT == getActiveElement() 93 | ELEMENT.readOnly = !SETTINGS.editable 94 | ELEMENT.id = ELEMENT.id || STATE.id 95 | if ( ELEMENT.type != 'text' ) { 96 | ELEMENT.type = 'text' 97 | } 98 | 99 | 100 | // Create a new picker component with the settings. 101 | P.component = new COMPONENT(P, SETTINGS) 102 | 103 | 104 | // Create the picker root and then prepare it. 105 | P.$root = $( '
' ) 106 | prepareElementRoot() 107 | 108 | 109 | // Create the picker holder and then prepare it. 110 | P.$holder = $( createWrappedComponent() ).appendTo( P.$root ) 111 | prepareElementHolder() 112 | 113 | 114 | // If there’s a format for the hidden input element, create the element. 115 | if ( SETTINGS.formatSubmit ) { 116 | prepareElementHidden() 117 | } 118 | 119 | 120 | // Prepare the input element. 121 | prepareElement() 122 | 123 | 124 | // Insert the hidden input as specified in the settings. 125 | if ( SETTINGS.containerHidden ) $( SETTINGS.containerHidden ).append( P._hidden ) 126 | else $ELEMENT.after( P._hidden ) 127 | 128 | 129 | // Insert the root as specified in the settings. 130 | if ( SETTINGS.container ) $( SETTINGS.container ).append( P.$root ) 131 | else $ELEMENT.after( P.$root ) 132 | 133 | 134 | // Bind the default component and settings events. 135 | P.on({ 136 | start: P.component.onStart, 137 | render: P.component.onRender, 138 | stop: P.component.onStop, 139 | open: P.component.onOpen, 140 | close: P.component.onClose, 141 | set: P.component.onSet 142 | }).on({ 143 | start: SETTINGS.onStart, 144 | render: SETTINGS.onRender, 145 | stop: SETTINGS.onStop, 146 | open: SETTINGS.onOpen, 147 | close: SETTINGS.onClose, 148 | set: SETTINGS.onSet 149 | }) 150 | 151 | 152 | // Once we’re all set, check the theme in use. 153 | IS_DEFAULT_THEME = isUsingDefaultTheme( P.$holder[0] ) 154 | 155 | 156 | // If the element has autofocus, open the picker. 157 | if ( ELEMENT.autofocus ) { 158 | P.open() 159 | } 160 | 161 | 162 | // Trigger queued the “start” and “render” events. 163 | return P.trigger( 'start' ).trigger( 'render' ) 164 | }, //start 165 | 166 | 167 | /** 168 | * Render a new picker 169 | */ 170 | render: function( entireComponent ) { 171 | 172 | // Insert a new component holder in the root or box. 173 | if ( entireComponent ) { 174 | P.$holder = $( createWrappedComponent() ) 175 | prepareElementHolder() 176 | P.$root.html( P.$holder ) 177 | } 178 | else P.$root.find( '.' + CLASSES.box ).html( P.component.nodes( STATE.open ) ) 179 | 180 | // Trigger the queued “render” events. 181 | return P.trigger( 'render' ) 182 | }, //render 183 | 184 | 185 | /** 186 | * Destroy everything 187 | */ 188 | stop: function() { 189 | 190 | // If it’s already stopped, do nothing. 191 | if ( !STATE.start ) return P 192 | 193 | // Then close the picker. 194 | P.close() 195 | 196 | // Remove the hidden field. 197 | if ( P._hidden ) { 198 | P._hidden.parentNode.removeChild( P._hidden ) 199 | } 200 | 201 | // Remove the root. 202 | P.$root.remove() 203 | 204 | // Remove the input class, remove the stored data, and unbind 205 | // the events (after a tick for IE - see `P.close`). 206 | $ELEMENT.removeClass( CLASSES.input ).removeData( NAME ) 207 | setTimeout( function() { 208 | $ELEMENT.off( '.' + STATE.id ) 209 | }, 0) 210 | 211 | // Restore the element state 212 | ELEMENT.type = STATE.type 213 | ELEMENT.readOnly = false 214 | 215 | // Trigger the queued “stop” events. 216 | P.trigger( 'stop' ) 217 | 218 | // Reset the picker states. 219 | STATE.methods = {} 220 | STATE.start = false 221 | 222 | return P 223 | }, //stop 224 | 225 | 226 | /** 227 | * Open up the picker 228 | */ 229 | open: function( dontGiveFocus ) { 230 | 231 | // If it’s already open, do nothing. 232 | if ( STATE.open ) return P 233 | 234 | // Add the “active” class. 235 | $ELEMENT.addClass( CLASSES.active ) 236 | aria( ELEMENT, 'expanded', true ) 237 | 238 | // * A Firefox bug, when `html` has `overflow:hidden`, results in 239 | // killing transitions :(. So add the “opened” state on the next tick. 240 | // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 241 | setTimeout( function() { 242 | 243 | // Add the “opened” class to the picker root. 244 | P.$root.addClass( CLASSES.opened ) 245 | aria( P.$root[0], 'hidden', false ) 246 | 247 | }, 0 ) 248 | 249 | // If we have to give focus, bind the element and doc events. 250 | if ( dontGiveFocus !== false ) { 251 | 252 | // Set it as open. 253 | STATE.open = true 254 | 255 | // Prevent the page from scrolling. 256 | if ( IS_DEFAULT_THEME ) { 257 | $html. 258 | css( 'overflow', 'hidden' ). 259 | css( 'padding-right', '+=' + getScrollbarWidth() ) 260 | } 261 | 262 | // Pass focus to the root element’s jQuery object. 263 | focusPickerOnceOpened() 264 | 265 | // Bind the document events. 266 | $document.on( 'click.' + STATE.id + ' focusin.' + STATE.id, function( event ) { 267 | 268 | var target = event.target 269 | 270 | // If the target of the event is not the element, close the picker picker. 271 | // * Don’t worry about clicks or focusins on the root because those don’t bubble up. 272 | // Also, for Firefox, a click on an `option` element bubbles up directly 273 | // to the doc. So make sure the target wasn't the doc. 274 | // * In Firefox stopPropagation() doesn’t prevent right-click events from bubbling, 275 | // which causes the picker to unexpectedly close when right-clicking it. So make 276 | // sure the event wasn’t a right-click. 277 | if ( target != ELEMENT && target != document && event.which != 3 ) { 278 | 279 | // If the target was the holder that covers the screen, 280 | // keep the element focused to maintain tabindex. 281 | P.close( target === P.$holder[0] ) 282 | } 283 | 284 | }).on( 'keydown.' + STATE.id, function( event ) { 285 | 286 | var 287 | // Get the keycode. 288 | keycode = event.keyCode, 289 | 290 | // Translate that to a selection change. 291 | keycodeToMove = P.component.key[ keycode ], 292 | 293 | // Grab the target. 294 | target = event.target 295 | 296 | 297 | // On escape, close the picker and give focus. 298 | if ( keycode == 27 ) { 299 | P.close( true ) 300 | } 301 | 302 | 303 | // Check if there is a key movement or “enter” keypress on the element. 304 | else if ( target == P.$holder[0] && ( keycodeToMove || keycode == 13 ) ) { 305 | 306 | // Prevent the default action to stop page movement. 307 | event.preventDefault() 308 | 309 | // Trigger the key movement action. 310 | if ( keycodeToMove ) { 311 | PickerConstructor._.trigger( P.component.key.go, P, [ PickerConstructor._.trigger( keycodeToMove ) ] ) 312 | } 313 | 314 | // On “enter”, if the highlighted item isn’t disabled, set the value and close. 315 | else if ( !P.$root.find( '.' + CLASSES.highlighted ).hasClass( CLASSES.disabled ) ) { 316 | P.set( 'select', P.component.item.highlight ) 317 | if ( SETTINGS.closeOnSelect ) { 318 | P.close( true ) 319 | } 320 | } 321 | } 322 | 323 | 324 | // If the target is within the root and “enter” is pressed, 325 | // prevent the default action and trigger a click on the target instead. 326 | else if ( $.contains( P.$root[0], target ) && keycode == 13 ) { 327 | event.preventDefault() 328 | target.click() 329 | } 330 | }) 331 | } 332 | 333 | // Trigger the queued “open” events. 334 | return P.trigger( 'open' ) 335 | }, //open 336 | 337 | 338 | /** 339 | * Close the picker 340 | */ 341 | close: function( giveFocus ) { 342 | 343 | // If we need to give focus, do it before changing states. 344 | if ( giveFocus ) { 345 | if ( SETTINGS.editable ) { 346 | ELEMENT.focus() 347 | } 348 | else { 349 | // ....ah yes! It would’ve been incomplete without a crazy workaround for IE :| 350 | // The focus is triggered *after* the close has completed - causing it 351 | // to open again. So unbind and rebind the event at the next tick. 352 | P.$holder.off( 'focus.toOpen' ).focus() 353 | setTimeout( function() { 354 | P.$holder.on( 'focus.toOpen', handleFocusToOpenEvent ) 355 | }, 0 ) 356 | } 357 | } 358 | 359 | // Remove the “active” class. 360 | $ELEMENT.removeClass( CLASSES.active ) 361 | aria( ELEMENT, 'expanded', false ) 362 | 363 | // * A Firefox bug, when `html` has `overflow:hidden`, results in 364 | // killing transitions :(. So remove the “opened” state on the next tick. 365 | // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 366 | setTimeout( function() { 367 | 368 | // Remove the “opened” and “focused” class from the picker root. 369 | P.$root.removeClass( CLASSES.opened + ' ' + CLASSES.focused ) 370 | aria( P.$root[0], 'hidden', true ) 371 | 372 | }, 0 ) 373 | 374 | // If it’s already closed, do nothing more. 375 | if ( !STATE.open ) return P 376 | 377 | // Set it as closed. 378 | STATE.open = false 379 | 380 | // Allow the page to scroll. 381 | if ( IS_DEFAULT_THEME ) { 382 | $html. 383 | css( 'overflow', '' ). 384 | css( 'padding-right', '-=' + getScrollbarWidth() ) 385 | } 386 | 387 | // Unbind the document events. 388 | $document.off( '.' + STATE.id ) 389 | 390 | // Trigger the queued “close” events. 391 | return P.trigger( 'close' ) 392 | }, //close 393 | 394 | 395 | /** 396 | * Clear the values 397 | */ 398 | clear: function( options ) { 399 | return P.set( 'clear', null, options ) 400 | }, //clear 401 | 402 | 403 | /** 404 | * Set something 405 | */ 406 | set: function( thing, value, options ) { 407 | 408 | var thingItem, thingValue, 409 | thingIsObject = $.isPlainObject( thing ), 410 | thingObject = thingIsObject ? thing : {} 411 | 412 | // Make sure we have usable options. 413 | options = thingIsObject && $.isPlainObject( value ) ? value : options || {} 414 | 415 | if ( thing ) { 416 | 417 | // If the thing isn’t an object, make it one. 418 | if ( !thingIsObject ) { 419 | thingObject[ thing ] = value 420 | } 421 | 422 | // Go through the things of items to set. 423 | for ( thingItem in thingObject ) { 424 | 425 | // Grab the value of the thing. 426 | thingValue = thingObject[ thingItem ] 427 | 428 | // First, if the item exists and there’s a value, set it. 429 | if ( thingItem in P.component.item ) { 430 | if ( thingValue === undefined ) thingValue = null 431 | P.component.set( thingItem, thingValue, options ) 432 | } 433 | 434 | // Then, check to update the element value and broadcast a change. 435 | if ( thingItem == 'select' || thingItem == 'clear' ) { 436 | $ELEMENT. 437 | val( thingItem == 'clear' ? '' : P.get( thingItem, SETTINGS.format ) ). 438 | trigger( 'change' ) 439 | } 440 | } 441 | 442 | // Render a new picker. 443 | P.render() 444 | } 445 | 446 | // When the method isn’t muted, trigger queued “set” events and pass the `thingObject`. 447 | return options.muted ? P : P.trigger( 'set', thingObject ) 448 | }, //set 449 | 450 | 451 | /** 452 | * Get something 453 | */ 454 | get: function( thing, format ) { 455 | 456 | // Make sure there’s something to get. 457 | thing = thing || 'value' 458 | 459 | // If a picker state exists, return that. 460 | if ( STATE[ thing ] != null ) { 461 | return STATE[ thing ] 462 | } 463 | 464 | // Return the submission value, if that. 465 | if ( thing == 'valueSubmit' ) { 466 | if ( P._hidden ) { 467 | return P._hidden.value 468 | } 469 | thing = 'value' 470 | } 471 | 472 | // Return the value, if that. 473 | if ( thing == 'value' ) { 474 | return ELEMENT.value 475 | } 476 | 477 | // Check if a component item exists, return that. 478 | if ( thing in P.component.item ) { 479 | if ( typeof format == 'string' ) { 480 | var thingValue = P.component.get( thing ) 481 | return thingValue ? 482 | PickerConstructor._.trigger( 483 | P.component.formats.toString, 484 | P.component, 485 | [ format, thingValue ] 486 | ) : '' 487 | } 488 | return P.component.get( thing ) 489 | } 490 | }, //get 491 | 492 | 493 | 494 | /** 495 | * Bind events on the things. 496 | */ 497 | on: function( thing, method, internal ) { 498 | 499 | var thingName, thingMethod, 500 | thingIsObject = $.isPlainObject( thing ), 501 | thingObject = thingIsObject ? thing : {} 502 | 503 | if ( thing ) { 504 | 505 | // If the thing isn’t an object, make it one. 506 | if ( !thingIsObject ) { 507 | thingObject[ thing ] = method 508 | } 509 | 510 | // Go through the things to bind to. 511 | for ( thingName in thingObject ) { 512 | 513 | // Grab the method of the thing. 514 | thingMethod = thingObject[ thingName ] 515 | 516 | // If it was an internal binding, prefix it. 517 | if ( internal ) { 518 | thingName = '_' + thingName 519 | } 520 | 521 | // Make sure the thing methods collection exists. 522 | STATE.methods[ thingName ] = STATE.methods[ thingName ] || [] 523 | 524 | // Add the method to the relative method collection. 525 | STATE.methods[ thingName ].push( thingMethod ) 526 | } 527 | } 528 | 529 | return P 530 | }, //on 531 | 532 | 533 | 534 | /** 535 | * Unbind events on the things. 536 | */ 537 | off: function() { 538 | var i, thingName, 539 | names = arguments; 540 | for ( i = 0, namesCount = names.length; i < namesCount; i += 1 ) { 541 | thingName = names[i] 542 | if ( thingName in STATE.methods ) { 543 | delete STATE.methods[thingName] 544 | } 545 | } 546 | return P 547 | }, 548 | 549 | 550 | /** 551 | * Fire off method events. 552 | */ 553 | trigger: function( name, data ) { 554 | var _trigger = function( name ) { 555 | var methodList = STATE.methods[ name ] 556 | if ( methodList ) { 557 | methodList.map( function( method ) { 558 | PickerConstructor._.trigger( method, P, [ data ] ) 559 | }) 560 | } 561 | } 562 | _trigger( '_' + name ) 563 | _trigger( name ) 564 | return P 565 | } //trigger 566 | } //PickerInstance.prototype 567 | 568 | 569 | /** 570 | * Wrap the picker holder components together. 571 | */ 572 | function createWrappedComponent() { 573 | 574 | // Create a picker wrapper holder 575 | return PickerConstructor._.node( 'div', 576 | 577 | // Create a picker wrapper node 578 | PickerConstructor._.node( 'div', 579 | 580 | // Create a picker frame 581 | PickerConstructor._.node( 'div', 582 | 583 | // Create a picker box node 584 | PickerConstructor._.node( 'div', 585 | 586 | // Create the components nodes. 587 | P.component.nodes( STATE.open ), 588 | 589 | // The picker box class 590 | CLASSES.box 591 | ), 592 | 593 | // Picker wrap class 594 | CLASSES.wrap 595 | ), 596 | 597 | // Picker frame class 598 | CLASSES.frame 599 | ), 600 | 601 | // Picker holder class 602 | CLASSES.holder, 603 | 604 | 'tabindex="-1"' 605 | ) //endreturn 606 | } //createWrappedComponent 607 | 608 | 609 | 610 | /** 611 | * Prepare the input element with all bindings. 612 | */ 613 | function prepareElement() { 614 | 615 | $ELEMENT. 616 | 617 | // Store the picker data by component name. 618 | data(NAME, P). 619 | 620 | // Add the “input” class name. 621 | addClass(CLASSES.input). 622 | 623 | // If there’s a `data-value`, update the value of the element. 624 | val( $ELEMENT.data('value') ? 625 | P.get('select', SETTINGS.format) : 626 | ELEMENT.value 627 | ) 628 | 629 | 630 | // Only bind keydown events if the element isn’t editable. 631 | if ( !SETTINGS.editable ) { 632 | 633 | $ELEMENT. 634 | 635 | // On focus/click, open the picker. 636 | on( 'focus.' + STATE.id + ' click.' + STATE.id, function(event) { 637 | event.preventDefault() 638 | P.open() 639 | }). 640 | 641 | // Handle keyboard event based on the picker being opened or not. 642 | on( 'keydown.' + STATE.id, handleKeydownEvent ) 643 | } 644 | 645 | 646 | // Update the aria attributes. 647 | aria(ELEMENT, { 648 | haspopup: true, 649 | expanded: false, 650 | readonly: false, 651 | owns: ELEMENT.id + '_root' 652 | }) 653 | } 654 | 655 | 656 | /** 657 | * Prepare the root picker element with all bindings. 658 | */ 659 | function prepareElementRoot() { 660 | aria( P.$root[0], 'hidden', true ) 661 | } 662 | 663 | 664 | /** 665 | * Prepare the holder picker element with all bindings. 666 | */ 667 | function prepareElementHolder() { 668 | 669 | P.$holder. 670 | 671 | on({ 672 | 673 | // For iOS8. 674 | keydown: handleKeydownEvent, 675 | 676 | 'focus.toOpen': handleFocusToOpenEvent, 677 | 678 | blur: function() { 679 | // Remove the “target” class. 680 | $ELEMENT.removeClass( CLASSES.target ) 681 | }, 682 | 683 | // When something within the holder is focused, stop from bubbling 684 | // to the doc and remove the “focused” state from the root. 685 | focusin: function( event ) { 686 | P.$root.removeClass( CLASSES.focused ) 687 | event.stopPropagation() 688 | }, 689 | 690 | // When something within the holder is clicked, stop it 691 | // from bubbling to the doc. 692 | 'mousedown click': function( event ) { 693 | 694 | var target = event.target 695 | 696 | // Make sure the target isn’t the root holder so it can bubble up. 697 | if ( target != P.$holder[0] ) { 698 | 699 | event.stopPropagation() 700 | 701 | // * For mousedown events, cancel the default action in order to 702 | // prevent cases where focus is shifted onto external elements 703 | // when using things like jQuery mobile or MagnificPopup (ref: #249 & #120). 704 | // Also, for Firefox, don’t prevent action on the `option` element. 705 | if ( event.type == 'mousedown' && !$( target ).is( 'input, select, textarea, button, option' )) { 706 | 707 | event.preventDefault() 708 | 709 | // Re-focus onto the holder so that users can click away 710 | // from elements focused within the picker. 711 | P.$holder[0].focus() 712 | } 713 | } 714 | } 715 | 716 | }). 717 | 718 | // If there’s a click on an actionable element, carry out the actions. 719 | on( 'click', '[data-pick], [data-nav], [data-clear], [data-close]', function() { 720 | 721 | var $target = $( this ), 722 | targetData = $target.data(), 723 | targetDisabled = $target.hasClass( CLASSES.navDisabled ) || $target.hasClass( CLASSES.disabled ), 724 | 725 | // * For IE, non-focusable elements can be active elements as well 726 | // (http://stackoverflow.com/a/2684561). 727 | activeElement = getActiveElement() 728 | activeElement = activeElement && ( activeElement.type || activeElement.href ) 729 | 730 | // If it’s disabled or nothing inside is actively focused, re-focus the element. 731 | if ( targetDisabled || activeElement && !$.contains( P.$root[0], activeElement ) ) { 732 | P.$holder[0].focus() 733 | } 734 | 735 | // If something is superficially changed, update the `highlight` based on the `nav`. 736 | if ( !targetDisabled && targetData.nav ) { 737 | P.set( 'highlight', P.component.item.highlight, { nav: targetData.nav } ) 738 | } 739 | 740 | // If something is picked, set `select` then close with focus. 741 | else if ( !targetDisabled && 'pick' in targetData ) { 742 | P.set( 'select', targetData.pick ) 743 | if ( SETTINGS.closeOnSelect ) { 744 | P.close( true ) 745 | } 746 | } 747 | 748 | // If a “clear” button is pressed, empty the values and close with focus. 749 | else if ( targetData.clear ) { 750 | P.clear() 751 | if ( SETTINGS.closeOnClear ) { 752 | P.close( true ) 753 | } 754 | } 755 | 756 | else if ( targetData.close ) { 757 | P.close( true ) 758 | } 759 | 760 | }) //P.$holder 761 | 762 | } 763 | 764 | 765 | /** 766 | * Prepare the hidden input element along with all bindings. 767 | */ 768 | function prepareElementHidden() { 769 | 770 | var name 771 | 772 | if ( SETTINGS.hiddenName === true ) { 773 | name = ELEMENT.name 774 | ELEMENT.name = '' 775 | } 776 | else { 777 | name = [ 778 | typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', 779 | typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit' 780 | ] 781 | name = name[0] + ELEMENT.name + name[1] 782 | } 783 | 784 | P._hidden = $( 785 | '' 798 | )[0] 799 | 800 | $ELEMENT. 801 | 802 | // If the value changes, update the hidden input with the correct format. 803 | on('change.' + STATE.id, function() { 804 | P._hidden.value = ELEMENT.value ? 805 | P.get('select', SETTINGS.formatSubmit) : 806 | '' 807 | }) 808 | } 809 | 810 | 811 | // Wait for transitions to end before focusing the holder. Otherwise, while 812 | // using the `container` option, the view jumps to the container. 813 | function focusPickerOnceOpened() { 814 | 815 | if (IS_DEFAULT_THEME && supportsTransitions) { 816 | P.$holder.find('.' + CLASSES.frame).one('transitionend', function() { 817 | P.$holder[0].focus() 818 | }) 819 | } 820 | else { 821 | P.$holder[0].focus() 822 | } 823 | } 824 | 825 | 826 | function handleFocusToOpenEvent(event) { 827 | 828 | // Stop the event from propagating to the doc. 829 | event.stopPropagation() 830 | 831 | // Add the “target” class. 832 | $ELEMENT.addClass( CLASSES.target ) 833 | 834 | // Add the “focused” class to the root. 835 | P.$root.addClass( CLASSES.focused ) 836 | 837 | // And then finally open the picker. 838 | P.open() 839 | } 840 | 841 | 842 | // For iOS8. 843 | function handleKeydownEvent( event ) { 844 | 845 | var keycode = event.keyCode, 846 | 847 | // Check if one of the delete keys was pressed. 848 | isKeycodeDelete = /^(8|46)$/.test(keycode) 849 | 850 | // For some reason IE clears the input value on “escape”. 851 | if ( keycode == 27 ) { 852 | P.close( true ) 853 | return false 854 | } 855 | 856 | // Check if `space` or `delete` was pressed or the picker is closed with a key movement. 857 | if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) { 858 | 859 | // Prevent it from moving the page and bubbling to doc. 860 | event.preventDefault() 861 | event.stopPropagation() 862 | 863 | // If `delete` was pressed, clear the values and close the picker. 864 | // Otherwise open the picker. 865 | if ( isKeycodeDelete ) { P.clear().close() } 866 | else { P.open() } 867 | } 868 | } 869 | 870 | 871 | // Return a new picker instance. 872 | return new PickerInstance() 873 | } //PickerConstructor 874 | 875 | 876 | 877 | /** 878 | * The default classes and prefix to use for the HTML classes. 879 | */ 880 | PickerConstructor.klasses = function( prefix ) { 881 | prefix = prefix || 'picker' 882 | return { 883 | 884 | picker: prefix, 885 | opened: prefix + '--opened', 886 | focused: prefix + '--focused', 887 | 888 | input: prefix + '__input', 889 | active: prefix + '__input--active', 890 | target: prefix + '__input--target', 891 | 892 | holder: prefix + '__holder', 893 | 894 | frame: prefix + '__frame', 895 | wrap: prefix + '__wrap', 896 | 897 | box: prefix + '__box' 898 | } 899 | } //PickerConstructor.klasses 900 | 901 | 902 | 903 | /** 904 | * Check if the default theme is being used. 905 | */ 906 | function isUsingDefaultTheme( element ) { 907 | 908 | var theme, 909 | prop = 'position' 910 | 911 | // For IE. 912 | if ( element.currentStyle ) { 913 | theme = element.currentStyle[prop] 914 | } 915 | 916 | // For normal browsers. 917 | else if ( window.getComputedStyle ) { 918 | theme = getComputedStyle( element )[prop] 919 | } 920 | 921 | return theme == 'fixed' 922 | } 923 | 924 | 925 | 926 | /** 927 | * Get the width of the browser’s scrollbar. 928 | * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js 929 | */ 930 | function getScrollbarWidth() { 931 | 932 | if ( $html.height() <= $window.height() ) { 933 | return 0 934 | } 935 | 936 | var $outer = $( '
' ). 937 | appendTo( 'body' ) 938 | 939 | // Get the width without scrollbars. 940 | var widthWithoutScroll = $outer[0].offsetWidth 941 | 942 | // Force adding scrollbars. 943 | $outer.css( 'overflow', 'scroll' ) 944 | 945 | // Add the inner div. 946 | var $inner = $( '
' ).appendTo( $outer ) 947 | 948 | // Get the width with scrollbars. 949 | var widthWithScroll = $inner[0].offsetWidth 950 | 951 | // Remove the divs. 952 | $outer.remove() 953 | 954 | // Return the difference between the widths. 955 | return widthWithoutScroll - widthWithScroll 956 | } 957 | 958 | 959 | 960 | /** 961 | * PickerConstructor helper methods. 962 | */ 963 | PickerConstructor._ = { 964 | 965 | /** 966 | * Create a group of nodes. Expects: 967 | * ` 968 | { 969 | min: {Integer}, 970 | max: {Integer}, 971 | i: {Integer}, 972 | node: {String}, 973 | item: {Function} 974 | } 975 | * ` 976 | */ 977 | group: function( groupObject ) { 978 | 979 | var 980 | // Scope for the looped object 981 | loopObjectScope, 982 | 983 | // Create the nodes list 984 | nodesList = '', 985 | 986 | // The counter starts from the `min` 987 | counter = PickerConstructor._.trigger( groupObject.min, groupObject ) 988 | 989 | 990 | // Loop from the `min` to `max`, incrementing by `i` 991 | for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) { 992 | 993 | // Trigger the `item` function within scope of the object 994 | loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] ) 995 | 996 | // Splice the subgroup and create nodes out of the sub nodes 997 | nodesList += PickerConstructor._.node( 998 | groupObject.node, 999 | loopObjectScope[ 0 ], // the node 1000 | loopObjectScope[ 1 ], // the classes 1001 | loopObjectScope[ 2 ] // the attributes 1002 | ) 1003 | } 1004 | 1005 | // Return the list of nodes 1006 | return nodesList 1007 | }, //group 1008 | 1009 | 1010 | /** 1011 | * Create a dom node string 1012 | */ 1013 | node: function( wrapper, item, klass, attribute ) { 1014 | 1015 | // If the item is false-y, just return an empty string 1016 | if ( !item ) return '' 1017 | 1018 | // If the item is an array, do a join 1019 | item = $.isArray( item ) ? item.join( '' ) : item 1020 | 1021 | // Check for the class 1022 | klass = klass ? ' class="' + klass + '"' : '' 1023 | 1024 | // Check for any attributes 1025 | attribute = attribute ? ' ' + attribute : '' 1026 | 1027 | // Return the wrapped item 1028 | return '<' + wrapper + klass + attribute + '>' + item + '' 1029 | }, //node 1030 | 1031 | 1032 | /** 1033 | * Lead numbers below 10 with a zero. 1034 | */ 1035 | lead: function( number ) { 1036 | return ( number < 10 ? '0': '' ) + number 1037 | }, 1038 | 1039 | 1040 | /** 1041 | * Trigger a function otherwise return the value. 1042 | */ 1043 | trigger: function( callback, scope, args ) { 1044 | return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback 1045 | }, 1046 | 1047 | 1048 | /** 1049 | * If the second character is a digit, length is 2 otherwise 1. 1050 | */ 1051 | digits: function( string ) { 1052 | return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1 1053 | }, 1054 | 1055 | 1056 | /** 1057 | * Tell if something is a date object. 1058 | */ 1059 | isDate: function( value ) { 1060 | return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() ) 1061 | }, 1062 | 1063 | 1064 | /** 1065 | * Tell if something is an integer. 1066 | */ 1067 | isInteger: function( value ) { 1068 | return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0 1069 | }, 1070 | 1071 | 1072 | /** 1073 | * Create ARIA attribute strings. 1074 | */ 1075 | ariaAttr: ariaAttr 1076 | } //PickerConstructor._ 1077 | 1078 | 1079 | 1080 | /** 1081 | * Extend the picker with a component and defaults. 1082 | */ 1083 | PickerConstructor.extend = function( name, Component ) { 1084 | 1085 | // Extend jQuery. 1086 | $.fn[ name ] = function( options, action ) { 1087 | 1088 | // Grab the component data. 1089 | var componentData = this.data( name ) 1090 | 1091 | // If the picker is requested, return the data object. 1092 | if ( options == 'picker' ) { 1093 | return componentData 1094 | } 1095 | 1096 | // If the component data exists and `options` is a string, carry out the action. 1097 | if ( componentData && typeof options == 'string' ) { 1098 | return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] ) 1099 | } 1100 | 1101 | // Otherwise go through each matched element and if the component 1102 | // doesn’t exist, create a new picker using `this` element 1103 | // and merging the defaults and options with a deep copy. 1104 | return this.each( function() { 1105 | var $this = $( this ) 1106 | if ( !$this.data( name ) ) { 1107 | new PickerConstructor( this, name, Component, options ) 1108 | } 1109 | }) 1110 | } 1111 | 1112 | // Set the defaults. 1113 | $.fn[ name ].defaults = Component.defaults 1114 | } //PickerConstructor.extend 1115 | 1116 | 1117 | 1118 | function aria(element, attribute, value) { 1119 | if ( $.isPlainObject(attribute) ) { 1120 | for ( var key in attribute ) { 1121 | ariaSet(element, key, attribute[key]) 1122 | } 1123 | } 1124 | else { 1125 | ariaSet(element, attribute, value) 1126 | } 1127 | } 1128 | function ariaSet(element, attribute, value) { 1129 | element.setAttribute( 1130 | (attribute == 'role' ? '' : 'aria-') + attribute, 1131 | value 1132 | ) 1133 | } 1134 | function ariaAttr(attribute, data) { 1135 | if ( !$.isPlainObject(attribute) ) { 1136 | attribute = { attribute: data } 1137 | } 1138 | data = '' 1139 | for ( var key in attribute ) { 1140 | var attr = (key == 'role' ? '' : 'aria-') + key, 1141 | attrVal = attribute[key] 1142 | data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' 1143 | } 1144 | return data 1145 | } 1146 | 1147 | // IE8 bug throws an error for activeElements within iframes. 1148 | function getActiveElement() { 1149 | try { 1150 | return document.activeElement 1151 | } catch ( err ) { } 1152 | } 1153 | 1154 | 1155 | 1156 | // Expose the picker constructor. 1157 | return PickerConstructor 1158 | 1159 | 1160 | })); 1161 | 1162 | 1163 | 1164 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/pickadate/picker.date.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Date picker for pickadate.js v3.5.6 3 | * http://amsul.github.io/pickadate.js/date.htm 4 | */ 5 | 6 | (function ( factory ) { 7 | 8 | // AMD. 9 | if ( typeof define == 'function' && define.amd ) 10 | define( ['picker', 'jquery'], factory ) 11 | 12 | // Node.js/browserify. 13 | else if ( typeof exports == 'object' ) 14 | module.exports = factory( require('./picker.js'), require('jquery') ) 15 | 16 | // Browser globals. 17 | else factory( Picker, jQuery ) 18 | 19 | }(function( Picker, $ ) { 20 | 21 | 22 | /** 23 | * Globals and constants 24 | */ 25 | var DAYS_IN_WEEK = 7, 26 | WEEKS_IN_CALENDAR = 6, 27 | _ = Picker._ 28 | 29 | 30 | 31 | /** 32 | * The date picker constructor 33 | */ 34 | function DatePicker( picker, settings ) { 35 | 36 | var calendar = this, 37 | element = picker.$node[ 0 ], 38 | elementValue = element.value, 39 | elementDataValue = picker.$node.data( 'value' ), 40 | valueString = elementDataValue || elementValue, 41 | formatString = elementDataValue ? settings.formatSubmit : settings.format, 42 | isRTL = function() { 43 | 44 | return element.currentStyle ? 45 | 46 | // For IE. 47 | element.currentStyle.direction == 'rtl' : 48 | 49 | // For normal browsers. 50 | getComputedStyle( picker.$root[0] ).direction == 'rtl' 51 | } 52 | 53 | calendar.settings = settings 54 | calendar.$node = picker.$node 55 | 56 | // The queue of methods that will be used to build item objects. 57 | calendar.queue = { 58 | min: 'measure create', 59 | max: 'measure create', 60 | now: 'now create', 61 | select: 'parse create validate', 62 | highlight: 'parse navigate create validate', 63 | view: 'parse create validate viewset', 64 | disable: 'deactivate', 65 | enable: 'activate' 66 | } 67 | 68 | // The component's item object. 69 | calendar.item = {} 70 | 71 | calendar.item.clear = null 72 | calendar.item.disable = ( settings.disable || [] ).slice( 0 ) 73 | calendar.item.enable = -(function( collectionDisabled ) { 74 | return collectionDisabled[ 0 ] === true ? collectionDisabled.shift() : -1 75 | })( calendar.item.disable ) 76 | 77 | calendar. 78 | set( 'min', settings.min ). 79 | set( 'max', settings.max ). 80 | set( 'now' ) 81 | 82 | // When there’s a value, set the `select`, which in turn 83 | // also sets the `highlight` and `view`. 84 | if ( valueString ) { 85 | calendar.set( 'select', valueString, { 86 | format: formatString, 87 | defaultValue: true 88 | }) 89 | } 90 | 91 | // If there’s no value, default to highlighting “today”. 92 | else { 93 | calendar. 94 | set( 'select', null ). 95 | set( 'highlight', calendar.item.now ) 96 | } 97 | 98 | 99 | // The keycode to movement mapping. 100 | calendar.key = { 101 | 40: 7, // Down 102 | 38: -7, // Up 103 | 39: function() { return isRTL() ? -1 : 1 }, // Right 104 | 37: function() { return isRTL() ? 1 : -1 }, // Left 105 | go: function( timeChange ) { 106 | var highlightedObject = calendar.item.highlight, 107 | targetDate = new Date( highlightedObject.year, highlightedObject.month, highlightedObject.date + timeChange ) 108 | calendar.set( 109 | 'highlight', 110 | targetDate, 111 | { interval: timeChange } 112 | ) 113 | this.render() 114 | } 115 | } 116 | 117 | 118 | // Bind some picker events. 119 | picker. 120 | on( 'render', function() { 121 | picker.$root.find( '.' + settings.klass.selectMonth ).on( 'change', function() { 122 | var value = this.value 123 | if ( value ) { 124 | picker.set( 'highlight', [ picker.get( 'view' ).year, value, picker.get( 'highlight' ).date ] ) 125 | picker.$root.find( '.' + settings.klass.selectMonth ).trigger( 'focus' ) 126 | } 127 | }) 128 | picker.$root.find( '.' + settings.klass.selectYear ).on( 'change', function() { 129 | var value = this.value 130 | if ( value ) { 131 | picker.set( 'highlight', [ value, picker.get( 'view' ).month, picker.get( 'highlight' ).date ] ) 132 | picker.$root.find( '.' + settings.klass.selectYear ).trigger( 'focus' ) 133 | } 134 | }) 135 | }, 1 ). 136 | on( 'open', function() { 137 | var includeToday = '' 138 | if ( calendar.disabled( calendar.get('now') ) ) { 139 | includeToday = ':not(.' + settings.klass.buttonToday + ')' 140 | } 141 | picker.$root.find( 'button' + includeToday + ', select' ).attr( 'disabled', false ) 142 | }, 1 ). 143 | on( 'close', function() { 144 | picker.$root.find( 'button, select' ).attr( 'disabled', true ) 145 | }, 1 ) 146 | 147 | } //DatePicker 148 | 149 | 150 | /** 151 | * Set a datepicker item object. 152 | */ 153 | DatePicker.prototype.set = function( type, value, options ) { 154 | 155 | var calendar = this, 156 | calendarItem = calendar.item 157 | 158 | // If the value is `null` just set it immediately. 159 | if ( value === null ) { 160 | if ( type == 'clear' ) type = 'select' 161 | calendarItem[ type ] = value 162 | return calendar 163 | } 164 | 165 | // Otherwise go through the queue of methods, and invoke the functions. 166 | // Update this as the time unit, and set the final value as this item. 167 | // * In the case of `enable`, keep the queue but set `disable` instead. 168 | // And in the case of `flip`, keep the queue but set `enable` instead. 169 | calendarItem[ ( type == 'enable' ? 'disable' : type == 'flip' ? 'enable' : type ) ] = calendar.queue[ type ].split( ' ' ).map( function( method ) { 170 | value = calendar[ method ]( type, value, options ) 171 | return value 172 | }).pop() 173 | 174 | // Check if we need to cascade through more updates. 175 | if ( type == 'select' ) { 176 | calendar.set( 'highlight', calendarItem.select, options ) 177 | } 178 | else if ( type == 'highlight' ) { 179 | calendar.set( 'view', calendarItem.highlight, options ) 180 | } 181 | else if ( type.match( /^(flip|min|max|disable|enable)$/ ) ) { 182 | if ( calendarItem.select && calendar.disabled( calendarItem.select ) ) { 183 | calendar.set( 'select', calendarItem.select, options ) 184 | } 185 | if ( calendarItem.highlight && calendar.disabled( calendarItem.highlight ) ) { 186 | calendar.set( 'highlight', calendarItem.highlight, options ) 187 | } 188 | } 189 | 190 | return calendar 191 | } //DatePicker.prototype.set 192 | 193 | 194 | /** 195 | * Get a datepicker item object. 196 | */ 197 | DatePicker.prototype.get = function( type ) { 198 | return this.item[ type ] 199 | } //DatePicker.prototype.get 200 | 201 | 202 | /** 203 | * Create a picker date object. 204 | */ 205 | DatePicker.prototype.create = function( type, value, options ) { 206 | 207 | var isInfiniteValue, 208 | calendar = this 209 | 210 | // If there’s no value, use the type as the value. 211 | value = value === undefined ? type : value 212 | 213 | 214 | // If it’s infinity, update the value. 215 | if ( value == -Infinity || value == Infinity ) { 216 | isInfiniteValue = value 217 | } 218 | 219 | // If it’s an object, use the native date object. 220 | else if ( $.isPlainObject( value ) && _.isInteger( value.pick ) ) { 221 | value = value.obj 222 | } 223 | 224 | // If it’s an array, convert it into a date and make sure 225 | // that it’s a valid date – otherwise default to today. 226 | else if ( $.isArray( value ) ) { 227 | value = new Date( value[ 0 ], value[ 1 ], value[ 2 ] ) 228 | value = _.isDate( value ) ? value : calendar.create().obj 229 | } 230 | 231 | // If it’s a number or date object, make a normalized date. 232 | else if ( _.isInteger( value ) || _.isDate( value ) ) { 233 | value = calendar.normalize( new Date( value ), options ) 234 | } 235 | 236 | // If it’s a literal true or any other case, set it to now. 237 | else /*if ( value === true )*/ { 238 | value = calendar.now( type, value, options ) 239 | } 240 | 241 | // Return the compiled object. 242 | return { 243 | year: isInfiniteValue || value.getFullYear(), 244 | month: isInfiniteValue || value.getMonth(), 245 | date: isInfiniteValue || value.getDate(), 246 | day: isInfiniteValue || value.getDay(), 247 | obj: isInfiniteValue || value, 248 | pick: isInfiniteValue || value.getTime() 249 | } 250 | } //DatePicker.prototype.create 251 | 252 | 253 | /** 254 | * Create a range limit object using an array, date object, 255 | * literal “true”, or integer relative to another time. 256 | */ 257 | DatePicker.prototype.createRange = function( from, to ) { 258 | 259 | var calendar = this, 260 | createDate = function( date ) { 261 | if ( date === true || $.isArray( date ) || _.isDate( date ) ) { 262 | return calendar.create( date ) 263 | } 264 | return date 265 | } 266 | 267 | // Create objects if possible. 268 | if ( !_.isInteger( from ) ) { 269 | from = createDate( from ) 270 | } 271 | if ( !_.isInteger( to ) ) { 272 | to = createDate( to ) 273 | } 274 | 275 | // Create relative dates. 276 | if ( _.isInteger( from ) && $.isPlainObject( to ) ) { 277 | from = [ to.year, to.month, to.date + from ]; 278 | } 279 | else if ( _.isInteger( to ) && $.isPlainObject( from ) ) { 280 | to = [ from.year, from.month, from.date + to ]; 281 | } 282 | 283 | return { 284 | from: createDate( from ), 285 | to: createDate( to ) 286 | } 287 | } //DatePicker.prototype.createRange 288 | 289 | 290 | /** 291 | * Check if a date unit falls within a date range object. 292 | */ 293 | DatePicker.prototype.withinRange = function( range, dateUnit ) { 294 | range = this.createRange(range.from, range.to) 295 | return dateUnit.pick >= range.from.pick && dateUnit.pick <= range.to.pick 296 | } 297 | 298 | 299 | /** 300 | * Check if two date range objects overlap. 301 | */ 302 | DatePicker.prototype.overlapRanges = function( one, two ) { 303 | 304 | var calendar = this 305 | 306 | // Convert the ranges into comparable dates. 307 | one = calendar.createRange( one.from, one.to ) 308 | two = calendar.createRange( two.from, two.to ) 309 | 310 | return calendar.withinRange( one, two.from ) || calendar.withinRange( one, two.to ) || 311 | calendar.withinRange( two, one.from ) || calendar.withinRange( two, one.to ) 312 | } 313 | 314 | 315 | /** 316 | * Get the date today. 317 | */ 318 | DatePicker.prototype.now = function( type, value, options ) { 319 | value = new Date() 320 | if ( options && options.rel ) { 321 | value.setDate( value.getDate() + options.rel ) 322 | } 323 | return this.normalize( value, options ) 324 | } 325 | 326 | 327 | /** 328 | * Navigate to next/prev month. 329 | */ 330 | DatePicker.prototype.navigate = function( type, value, options ) { 331 | 332 | var targetDateObject, 333 | targetYear, 334 | targetMonth, 335 | targetDate, 336 | isTargetArray = $.isArray( value ), 337 | isTargetObject = $.isPlainObject( value ), 338 | viewsetObject = this.item.view/*, 339 | safety = 100*/ 340 | 341 | 342 | if ( isTargetArray || isTargetObject ) { 343 | 344 | if ( isTargetObject ) { 345 | targetYear = value.year 346 | targetMonth = value.month 347 | targetDate = value.date 348 | } 349 | else { 350 | targetYear = +value[0] 351 | targetMonth = +value[1] 352 | targetDate = +value[2] 353 | } 354 | 355 | // If we’re navigating months but the view is in a different 356 | // month, navigate to the view’s year and month. 357 | if ( options && options.nav && viewsetObject && viewsetObject.month !== targetMonth ) { 358 | targetYear = viewsetObject.year 359 | targetMonth = viewsetObject.month 360 | } 361 | 362 | // Figure out the expected target year and month. 363 | targetDateObject = new Date( targetYear, targetMonth + ( options && options.nav ? options.nav : 0 ), 1 ) 364 | targetYear = targetDateObject.getFullYear() 365 | targetMonth = targetDateObject.getMonth() 366 | 367 | // If the month we’re going to doesn’t have enough days, 368 | // keep decreasing the date until we reach the month’s last date. 369 | while ( /*safety &&*/ new Date( targetYear, targetMonth, targetDate ).getMonth() !== targetMonth ) { 370 | targetDate -= 1 371 | /*safety -= 1 372 | if ( !safety ) { 373 | throw 'Fell into an infinite loop while navigating to ' + new Date( targetYear, targetMonth, targetDate ) + '.' 374 | }*/ 375 | } 376 | 377 | value = [ targetYear, targetMonth, targetDate ] 378 | } 379 | 380 | return value 381 | } //DatePicker.prototype.navigate 382 | 383 | 384 | /** 385 | * Normalize a date by setting the hours to midnight. 386 | */ 387 | DatePicker.prototype.normalize = function( value/*, options*/ ) { 388 | value.setHours( 0, 0, 0, 0 ) 389 | return value 390 | } 391 | 392 | 393 | /** 394 | * Measure the range of dates. 395 | */ 396 | DatePicker.prototype.measure = function( type, value/*, options*/ ) { 397 | 398 | var calendar = this 399 | 400 | // If it’s anything false-y, remove the limits. 401 | if ( !value ) { 402 | value = type == 'min' ? -Infinity : Infinity 403 | } 404 | 405 | // If it’s a string, parse it. 406 | else if ( typeof value == 'string' ) { 407 | value = calendar.parse( type, value ) 408 | } 409 | 410 | // If it's an integer, get a date relative to today. 411 | else if ( _.isInteger( value ) ) { 412 | value = calendar.now( type, value, { rel: value } ) 413 | } 414 | 415 | return value 416 | } ///DatePicker.prototype.measure 417 | 418 | 419 | /** 420 | * Create a viewset object based on navigation. 421 | */ 422 | DatePicker.prototype.viewset = function( type, dateObject/*, options*/ ) { 423 | return this.create([ dateObject.year, dateObject.month, 1 ]) 424 | } 425 | 426 | 427 | /** 428 | * Validate a date as enabled and shift if needed. 429 | */ 430 | DatePicker.prototype.validate = function( type, dateObject, options ) { 431 | 432 | var calendar = this, 433 | 434 | // Keep a reference to the original date. 435 | originalDateObject = dateObject, 436 | 437 | // Make sure we have an interval. 438 | interval = options && options.interval ? options.interval : 1, 439 | 440 | // Check if the calendar enabled dates are inverted. 441 | isFlippedBase = calendar.item.enable === -1, 442 | 443 | // Check if we have any enabled dates after/before now. 444 | hasEnabledBeforeTarget, hasEnabledAfterTarget, 445 | 446 | // The min & max limits. 447 | minLimitObject = calendar.item.min, 448 | maxLimitObject = calendar.item.max, 449 | 450 | // Check if we’ve reached the limit during shifting. 451 | reachedMin, reachedMax, 452 | 453 | // Check if the calendar is inverted and at least one weekday is enabled. 454 | hasEnabledWeekdays = isFlippedBase && calendar.item.disable.filter( function( value ) { 455 | 456 | // If there’s a date, check where it is relative to the target. 457 | if ( $.isArray( value ) ) { 458 | var dateTime = calendar.create( value ).pick 459 | if ( dateTime < dateObject.pick ) hasEnabledBeforeTarget = true 460 | else if ( dateTime > dateObject.pick ) hasEnabledAfterTarget = true 461 | } 462 | 463 | // Return only integers for enabled weekdays. 464 | return _.isInteger( value ) 465 | }).length/*, 466 | 467 | safety = 100*/ 468 | 469 | 470 | 471 | // Cases to validate for: 472 | // [1] Not inverted and date disabled. 473 | // [2] Inverted and some dates enabled. 474 | // [3] Not inverted and out of range. 475 | // 476 | // Cases to **not** validate for: 477 | // • Navigating months. 478 | // • Not inverted and date enabled. 479 | // • Inverted and all dates disabled. 480 | // • ..and anything else. 481 | if ( !options || (!options.nav && !options.defaultValue) ) if ( 482 | /* 1 */ ( !isFlippedBase && calendar.disabled( dateObject ) ) || 483 | /* 2 */ ( isFlippedBase && calendar.disabled( dateObject ) && ( hasEnabledWeekdays || hasEnabledBeforeTarget || hasEnabledAfterTarget ) ) || 484 | /* 3 */ ( !isFlippedBase && (dateObject.pick <= minLimitObject.pick || dateObject.pick >= maxLimitObject.pick) ) 485 | ) { 486 | 487 | 488 | // When inverted, flip the direction if there aren’t any enabled weekdays 489 | // and there are no enabled dates in the direction of the interval. 490 | if ( isFlippedBase && !hasEnabledWeekdays && ( ( !hasEnabledAfterTarget && interval > 0 ) || ( !hasEnabledBeforeTarget && interval < 0 ) ) ) { 491 | interval *= -1 492 | } 493 | 494 | 495 | // Keep looping until we reach an enabled date. 496 | while ( /*safety &&*/ calendar.disabled( dateObject ) ) { 497 | 498 | /*safety -= 1 499 | if ( !safety ) { 500 | throw 'Fell into an infinite loop while validating ' + dateObject.obj + '.' 501 | }*/ 502 | 503 | 504 | // If we’ve looped into the next/prev month with a large interval, return to the original date and flatten the interval. 505 | if ( Math.abs( interval ) > 1 && ( dateObject.month < originalDateObject.month || dateObject.month > originalDateObject.month ) ) { 506 | dateObject = originalDateObject 507 | interval = interval > 0 ? 1 : -1 508 | } 509 | 510 | 511 | // If we’ve reached the min/max limit, reverse the direction, flatten the interval and set it to the limit. 512 | if ( dateObject.pick <= minLimitObject.pick ) { 513 | reachedMin = true 514 | interval = 1 515 | dateObject = calendar.create([ 516 | minLimitObject.year, 517 | minLimitObject.month, 518 | minLimitObject.date + (dateObject.pick === minLimitObject.pick ? 0 : -1) 519 | ]) 520 | } 521 | else if ( dateObject.pick >= maxLimitObject.pick ) { 522 | reachedMax = true 523 | interval = -1 524 | dateObject = calendar.create([ 525 | maxLimitObject.year, 526 | maxLimitObject.month, 527 | maxLimitObject.date + (dateObject.pick === maxLimitObject.pick ? 0 : 1) 528 | ]) 529 | } 530 | 531 | 532 | // If we’ve reached both limits, just break out of the loop. 533 | if ( reachedMin && reachedMax ) { 534 | break 535 | } 536 | 537 | 538 | // Finally, create the shifted date using the interval and keep looping. 539 | dateObject = calendar.create([ dateObject.year, dateObject.month, dateObject.date + interval ]) 540 | } 541 | 542 | } //endif 543 | 544 | 545 | // Return the date object settled on. 546 | return dateObject 547 | } //DatePicker.prototype.validate 548 | 549 | 550 | /** 551 | * Check if a date is disabled. 552 | */ 553 | DatePicker.prototype.disabled = function( dateToVerify ) { 554 | 555 | var 556 | calendar = this, 557 | 558 | // Filter through the disabled dates to check if this is one. 559 | isDisabledMatch = calendar.item.disable.filter( function( dateToDisable ) { 560 | 561 | // If the date is a number, match the weekday with 0index and `firstDay` check. 562 | if ( _.isInteger( dateToDisable ) ) { 563 | return dateToVerify.day === ( calendar.settings.firstDay ? dateToDisable : dateToDisable - 1 ) % 7 564 | } 565 | 566 | // If it’s an array or a native JS date, create and match the exact date. 567 | if ( $.isArray( dateToDisable ) || _.isDate( dateToDisable ) ) { 568 | return dateToVerify.pick === calendar.create( dateToDisable ).pick 569 | } 570 | 571 | // If it’s an object, match a date within the “from” and “to” range. 572 | if ( $.isPlainObject( dateToDisable ) ) { 573 | return calendar.withinRange( dateToDisable, dateToVerify ) 574 | } 575 | }) 576 | 577 | // If this date matches a disabled date, confirm it’s not inverted. 578 | isDisabledMatch = isDisabledMatch.length && !isDisabledMatch.filter(function( dateToDisable ) { 579 | return $.isArray( dateToDisable ) && dateToDisable[3] == 'inverted' || 580 | $.isPlainObject( dateToDisable ) && dateToDisable.inverted 581 | }).length 582 | 583 | // Check the calendar “enabled” flag and respectively flip the 584 | // disabled state. Then also check if it’s beyond the min/max limits. 585 | return calendar.item.enable === -1 ? !isDisabledMatch : isDisabledMatch || 586 | dateToVerify.pick < calendar.item.min.pick || 587 | dateToVerify.pick > calendar.item.max.pick 588 | 589 | } //DatePicker.prototype.disabled 590 | 591 | 592 | /** 593 | * Parse a string into a usable type. 594 | */ 595 | DatePicker.prototype.parse = function( type, value, options ) { 596 | 597 | var calendar = this, 598 | parsingObject = {} 599 | 600 | // If it’s already parsed, we’re good. 601 | if ( !value || typeof value != 'string' ) { 602 | return value 603 | } 604 | 605 | // We need a `.format` to parse the value with. 606 | if ( !( options && options.format ) ) { 607 | options = options || {} 608 | options.format = calendar.settings.format 609 | } 610 | 611 | // Convert the format into an array and then map through it. 612 | calendar.formats.toArray( options.format ).map( function( label ) { 613 | 614 | var 615 | // Grab the formatting label. 616 | formattingLabel = calendar.formats[ label ], 617 | 618 | // The format length is from the formatting label function or the 619 | // label length without the escaping exclamation (!) mark. 620 | formatLength = formattingLabel ? _.trigger( formattingLabel, calendar, [ value, parsingObject ] ) : label.replace( /^!/, '' ).length 621 | 622 | // If there's a format label, split the value up to the format length. 623 | // Then add it to the parsing object with appropriate label. 624 | if ( formattingLabel ) { 625 | parsingObject[ label ] = value.substr( 0, formatLength ) 626 | } 627 | 628 | // Update the value as the substring from format length to end. 629 | value = value.substr( formatLength ) 630 | }) 631 | 632 | // Compensate for month 0index. 633 | return [ 634 | parsingObject.yyyy || parsingObject.yy, 635 | +( parsingObject.mm || parsingObject.m ) - 1, 636 | parsingObject.dd || parsingObject.d 637 | ] 638 | } //DatePicker.prototype.parse 639 | 640 | 641 | /** 642 | * Various formats to display the object in. 643 | */ 644 | DatePicker.prototype.formats = (function() { 645 | 646 | // Return the length of the first word in a collection. 647 | function getWordLengthFromCollection( string, collection, dateObject ) { 648 | 649 | // Grab the first word from the string. 650 | // Regex pattern from http://stackoverflow.com/q/150033 651 | var word = string.match( /[^\x00-\x7F]+|\w+/ )[ 0 ] 652 | 653 | // If there's no month index, add it to the date object 654 | if ( !dateObject.mm && !dateObject.m ) { 655 | dateObject.m = collection.indexOf( word ) + 1 656 | } 657 | 658 | // Return the length of the word. 659 | return word.length 660 | } 661 | 662 | // Get the length of the first word in a string. 663 | function getFirstWordLength( string ) { 664 | return string.match( /\w+/ )[ 0 ].length 665 | } 666 | 667 | return { 668 | 669 | d: function( string, dateObject ) { 670 | 671 | // If there's string, then get the digits length. 672 | // Otherwise return the selected date. 673 | return string ? _.digits( string ) : dateObject.date 674 | }, 675 | dd: function( string, dateObject ) { 676 | 677 | // If there's a string, then the length is always 2. 678 | // Otherwise return the selected date with a leading zero. 679 | return string ? 2 : _.lead( dateObject.date ) 680 | }, 681 | ddd: function( string, dateObject ) { 682 | 683 | // If there's a string, then get the length of the first word. 684 | // Otherwise return the short selected weekday. 685 | return string ? getFirstWordLength( string ) : this.settings.weekdaysShort[ dateObject.day ] 686 | }, 687 | dddd: function( string, dateObject ) { 688 | 689 | // If there's a string, then get the length of the first word. 690 | // Otherwise return the full selected weekday. 691 | return string ? getFirstWordLength( string ) : this.settings.weekdaysFull[ dateObject.day ] 692 | }, 693 | m: function( string, dateObject ) { 694 | 695 | // If there's a string, then get the length of the digits 696 | // Otherwise return the selected month with 0index compensation. 697 | return string ? _.digits( string ) : dateObject.month + 1 698 | }, 699 | mm: function( string, dateObject ) { 700 | 701 | // If there's a string, then the length is always 2. 702 | // Otherwise return the selected month with 0index and leading zero. 703 | return string ? 2 : _.lead( dateObject.month + 1 ) 704 | }, 705 | mmm: function( string, dateObject ) { 706 | 707 | var collection = this.settings.monthsShort 708 | 709 | // If there's a string, get length of the relevant month from the short 710 | // months collection. Otherwise return the selected month from that collection. 711 | return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] 712 | }, 713 | mmmm: function( string, dateObject ) { 714 | 715 | var collection = this.settings.monthsFull 716 | 717 | // If there's a string, get length of the relevant month from the full 718 | // months collection. Otherwise return the selected month from that collection. 719 | return string ? getWordLengthFromCollection( string, collection, dateObject ) : collection[ dateObject.month ] 720 | }, 721 | yy: function( string, dateObject ) { 722 | 723 | // If there's a string, then the length is always 2. 724 | // Otherwise return the selected year by slicing out the first 2 digits. 725 | return string ? 2 : ( '' + dateObject.year ).slice( 2 ) 726 | }, 727 | yyyy: function( string, dateObject ) { 728 | 729 | // If there's a string, then the length is always 4. 730 | // Otherwise return the selected year. 731 | return string ? 4 : dateObject.year 732 | }, 733 | 734 | // Create an array by splitting the formatting string passed. 735 | toArray: function( formatString ) { return formatString.split( /(d{1,4}|m{1,4}|y{4}|yy|!.)/g ) }, 736 | 737 | // Format an object into a string using the formatting options. 738 | toString: function ( formatString, itemObject ) { 739 | var calendar = this 740 | return calendar.formats.toArray( formatString ).map( function( label ) { 741 | return _.trigger( calendar.formats[ label ], calendar, [ 0, itemObject ] ) || label.replace( /^!/, '' ) 742 | }).join( '' ) 743 | } 744 | } 745 | })() //DatePicker.prototype.formats 746 | 747 | 748 | 749 | 750 | /** 751 | * Check if two date units are the exact. 752 | */ 753 | DatePicker.prototype.isDateExact = function( one, two ) { 754 | 755 | var calendar = this 756 | 757 | // When we’re working with weekdays, do a direct comparison. 758 | if ( 759 | ( _.isInteger( one ) && _.isInteger( two ) ) || 760 | ( typeof one == 'boolean' && typeof two == 'boolean' ) 761 | ) { 762 | return one === two 763 | } 764 | 765 | // When we’re working with date representations, compare the “pick” value. 766 | if ( 767 | ( _.isDate( one ) || $.isArray( one ) ) && 768 | ( _.isDate( two ) || $.isArray( two ) ) 769 | ) { 770 | return calendar.create( one ).pick === calendar.create( two ).pick 771 | } 772 | 773 | // When we’re working with range objects, compare the “from” and “to”. 774 | if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 775 | return calendar.isDateExact( one.from, two.from ) && calendar.isDateExact( one.to, two.to ) 776 | } 777 | 778 | return false 779 | } 780 | 781 | 782 | /** 783 | * Check if two date units overlap. 784 | */ 785 | DatePicker.prototype.isDateOverlap = function( one, two ) { 786 | 787 | var calendar = this, 788 | firstDay = calendar.settings.firstDay ? 1 : 0 789 | 790 | // When we’re working with a weekday index, compare the days. 791 | if ( _.isInteger( one ) && ( _.isDate( two ) || $.isArray( two ) ) ) { 792 | one = one % 7 + firstDay 793 | return one === calendar.create( two ).day + 1 794 | } 795 | if ( _.isInteger( two ) && ( _.isDate( one ) || $.isArray( one ) ) ) { 796 | two = two % 7 + firstDay 797 | return two === calendar.create( one ).day + 1 798 | } 799 | 800 | // When we’re working with range objects, check if the ranges overlap. 801 | if ( $.isPlainObject( one ) && $.isPlainObject( two ) ) { 802 | return calendar.overlapRanges( one, two ) 803 | } 804 | 805 | return false 806 | } 807 | 808 | 809 | /** 810 | * Flip the “enabled” state. 811 | */ 812 | DatePicker.prototype.flipEnable = function(val) { 813 | var itemObject = this.item 814 | itemObject.enable = val || (itemObject.enable == -1 ? 1 : -1) 815 | } 816 | 817 | 818 | /** 819 | * Mark a collection of dates as “disabled”. 820 | */ 821 | DatePicker.prototype.deactivate = function( type, datesToDisable ) { 822 | 823 | var calendar = this, 824 | disabledItems = calendar.item.disable.slice(0) 825 | 826 | 827 | // If we’re flipping, that’s all we need to do. 828 | if ( datesToDisable == 'flip' ) { 829 | calendar.flipEnable() 830 | } 831 | 832 | else if ( datesToDisable === false ) { 833 | calendar.flipEnable(1) 834 | disabledItems = [] 835 | } 836 | 837 | else if ( datesToDisable === true ) { 838 | calendar.flipEnable(-1) 839 | disabledItems = [] 840 | } 841 | 842 | // Otherwise go through the dates to disable. 843 | else { 844 | 845 | datesToDisable.map(function( unitToDisable ) { 846 | 847 | var matchFound 848 | 849 | // When we have disabled items, check for matches. 850 | // If something is matched, immediately break out. 851 | for ( var index = 0; index < disabledItems.length; index += 1 ) { 852 | if ( calendar.isDateExact( unitToDisable, disabledItems[index] ) ) { 853 | matchFound = true 854 | break 855 | } 856 | } 857 | 858 | // If nothing was found, add the validated unit to the collection. 859 | if ( !matchFound ) { 860 | if ( 861 | _.isInteger( unitToDisable ) || 862 | _.isDate( unitToDisable ) || 863 | $.isArray( unitToDisable ) || 864 | ( $.isPlainObject( unitToDisable ) && unitToDisable.from && unitToDisable.to ) 865 | ) { 866 | disabledItems.push( unitToDisable ) 867 | } 868 | } 869 | }) 870 | } 871 | 872 | // Return the updated collection. 873 | return disabledItems 874 | } //DatePicker.prototype.deactivate 875 | 876 | 877 | /** 878 | * Mark a collection of dates as “enabled”. 879 | */ 880 | DatePicker.prototype.activate = function( type, datesToEnable ) { 881 | 882 | var calendar = this, 883 | disabledItems = calendar.item.disable, 884 | disabledItemsCount = disabledItems.length 885 | 886 | // If we’re flipping, that’s all we need to do. 887 | if ( datesToEnable == 'flip' ) { 888 | calendar.flipEnable() 889 | } 890 | 891 | else if ( datesToEnable === true ) { 892 | calendar.flipEnable(1) 893 | disabledItems = [] 894 | } 895 | 896 | else if ( datesToEnable === false ) { 897 | calendar.flipEnable(-1) 898 | disabledItems = [] 899 | } 900 | 901 | // Otherwise go through the disabled dates. 902 | else { 903 | 904 | datesToEnable.map(function( unitToEnable ) { 905 | 906 | var matchFound, 907 | disabledUnit, 908 | index, 909 | isExactRange 910 | 911 | // Go through the disabled items and try to find a match. 912 | for ( index = 0; index < disabledItemsCount; index += 1 ) { 913 | 914 | disabledUnit = disabledItems[index] 915 | 916 | // When an exact match is found, remove it from the collection. 917 | if ( calendar.isDateExact( disabledUnit, unitToEnable ) ) { 918 | matchFound = disabledItems[index] = null 919 | isExactRange = true 920 | break 921 | } 922 | 923 | // When an overlapped match is found, add the “inverted” state to it. 924 | else if ( calendar.isDateOverlap( disabledUnit, unitToEnable ) ) { 925 | if ( $.isPlainObject( unitToEnable ) ) { 926 | unitToEnable.inverted = true 927 | matchFound = unitToEnable 928 | } 929 | else if ( $.isArray( unitToEnable ) ) { 930 | matchFound = unitToEnable 931 | if ( !matchFound[3] ) matchFound.push( 'inverted' ) 932 | } 933 | else if ( _.isDate( unitToEnable ) ) { 934 | matchFound = [ unitToEnable.getFullYear(), unitToEnable.getMonth(), unitToEnable.getDate(), 'inverted' ] 935 | } 936 | break 937 | } 938 | } 939 | 940 | // If a match was found, remove a previous duplicate entry. 941 | if ( matchFound ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 942 | if ( calendar.isDateExact( disabledItems[index], unitToEnable ) ) { 943 | disabledItems[index] = null 944 | break 945 | } 946 | } 947 | 948 | // In the event that we’re dealing with an exact range of dates, 949 | // make sure there are no “inverted” dates because of it. 950 | if ( isExactRange ) for ( index = 0; index < disabledItemsCount; index += 1 ) { 951 | if ( calendar.isDateOverlap( disabledItems[index], unitToEnable ) ) { 952 | disabledItems[index] = null 953 | break 954 | } 955 | } 956 | 957 | // If something is still matched, add it into the collection. 958 | if ( matchFound ) { 959 | disabledItems.push( matchFound ) 960 | } 961 | }) 962 | } 963 | 964 | // Return the updated collection. 965 | return disabledItems.filter(function( val ) { return val != null }) 966 | } //DatePicker.prototype.activate 967 | 968 | 969 | /** 970 | * Create a string for the nodes in the picker. 971 | */ 972 | DatePicker.prototype.nodes = function( isOpen ) { 973 | 974 | var 975 | calendar = this, 976 | settings = calendar.settings, 977 | calendarItem = calendar.item, 978 | nowObject = calendarItem.now, 979 | selectedObject = calendarItem.select, 980 | highlightedObject = calendarItem.highlight, 981 | viewsetObject = calendarItem.view, 982 | disabledCollection = calendarItem.disable, 983 | minLimitObject = calendarItem.min, 984 | maxLimitObject = calendarItem.max, 985 | 986 | 987 | // Create the calendar table head using a copy of weekday labels collection. 988 | // * We do a copy so we don't mutate the original array. 989 | tableHead = (function( collection, fullCollection ) { 990 | 991 | // If the first day should be Monday, move Sunday to the end. 992 | if ( settings.firstDay ) { 993 | collection.push( collection.shift() ) 994 | fullCollection.push( fullCollection.shift() ) 995 | } 996 | 997 | // Create and return the table head group. 998 | return _.node( 999 | 'thead', 1000 | _.node( 1001 | 'tr', 1002 | _.group({ 1003 | min: 0, 1004 | max: DAYS_IN_WEEK - 1, 1005 | i: 1, 1006 | node: 'th', 1007 | item: function( counter ) { 1008 | return [ 1009 | collection[ counter ], 1010 | settings.klass.weekdays, 1011 | 'scope=col title="' + fullCollection[ counter ] + '"' 1012 | ] 1013 | } 1014 | }) 1015 | ) 1016 | ) //endreturn 1017 | })( ( settings.showWeekdaysFull ? settings.weekdaysFull : settings.weekdaysShort ).slice( 0 ), settings.weekdaysFull.slice( 0 ) ), //tableHead 1018 | 1019 | 1020 | // Create the nav for next/prev month. 1021 | createMonthNav = function( next ) { 1022 | 1023 | // Otherwise, return the created month tag. 1024 | return _.node( 1025 | 'div', 1026 | ' ', 1027 | settings.klass[ 'nav' + ( next ? 'Next' : 'Prev' ) ] + ( 1028 | 1029 | // If the focused month is outside the range, disabled the button. 1030 | ( next && viewsetObject.year >= maxLimitObject.year && viewsetObject.month >= maxLimitObject.month ) || 1031 | ( !next && viewsetObject.year <= minLimitObject.year && viewsetObject.month <= minLimitObject.month ) ? 1032 | ' ' + settings.klass.navDisabled : '' 1033 | ), 1034 | 'data-nav=' + ( next || -1 ) + ' ' + 1035 | _.ariaAttr({ 1036 | role: 'button', 1037 | controls: calendar.$node[0].id + '_table' 1038 | }) + ' ' + 1039 | 'title="' + (next ? settings.labelMonthNext : settings.labelMonthPrev ) + '"' 1040 | ) //endreturn 1041 | }, //createMonthNav 1042 | 1043 | 1044 | // Create the month label. 1045 | createMonthLabel = function() { 1046 | 1047 | var monthsCollection = settings.showMonthsShort ? settings.monthsShort : settings.monthsFull 1048 | 1049 | // If there are months to select, add a dropdown menu. 1050 | if ( settings.selectMonths ) { 1051 | 1052 | return _.node( 'select', 1053 | _.group({ 1054 | min: 0, 1055 | max: 11, 1056 | i: 1, 1057 | node: 'option', 1058 | item: function( loopedMonth ) { 1059 | 1060 | return [ 1061 | 1062 | // The looped month and no classes. 1063 | monthsCollection[ loopedMonth ], 0, 1064 | 1065 | // Set the value and selected index. 1066 | 'value=' + loopedMonth + 1067 | ( viewsetObject.month == loopedMonth ? ' selected' : '' ) + 1068 | ( 1069 | ( 1070 | ( viewsetObject.year == minLimitObject.year && loopedMonth < minLimitObject.month ) || 1071 | ( viewsetObject.year == maxLimitObject.year && loopedMonth > maxLimitObject.month ) 1072 | ) ? 1073 | ' disabled' : '' 1074 | ) 1075 | ] 1076 | } 1077 | }), 1078 | settings.klass.selectMonth, 1079 | ( isOpen ? '' : 'disabled' ) + ' ' + 1080 | _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + 1081 | 'title="' + settings.labelMonthSelect + '"' 1082 | ) 1083 | } 1084 | 1085 | // If there's a need for a month selector 1086 | return _.node( 'div', monthsCollection[ viewsetObject.month ], settings.klass.month ) 1087 | }, //createMonthLabel 1088 | 1089 | 1090 | // Create the year label. 1091 | createYearLabel = function() { 1092 | 1093 | var focusedYear = viewsetObject.year, 1094 | 1095 | // If years selector is set to a literal "true", set it to 5. Otherwise 1096 | // divide in half to get half before and half after focused year. 1097 | numberYears = settings.selectYears === true ? 5 : ~~( settings.selectYears / 2 ) 1098 | 1099 | // If there are years to select, add a dropdown menu. 1100 | if ( numberYears ) { 1101 | 1102 | var 1103 | minYear = minLimitObject.year, 1104 | maxYear = maxLimitObject.year, 1105 | lowestYear = focusedYear - numberYears, 1106 | highestYear = focusedYear + numberYears 1107 | 1108 | // If the min year is greater than the lowest year, increase the highest year 1109 | // by the difference and set the lowest year to the min year. 1110 | if ( minYear > lowestYear ) { 1111 | highestYear += minYear - lowestYear 1112 | lowestYear = minYear 1113 | } 1114 | 1115 | // If the max year is less than the highest year, decrease the lowest year 1116 | // by the lower of the two: available and needed years. Then set the 1117 | // highest year to the max year. 1118 | if ( maxYear < highestYear ) { 1119 | 1120 | var availableYears = lowestYear - minYear, 1121 | neededYears = highestYear - maxYear 1122 | 1123 | lowestYear -= availableYears > neededYears ? neededYears : availableYears 1124 | highestYear = maxYear 1125 | } 1126 | 1127 | return _.node( 'select', 1128 | _.group({ 1129 | min: lowestYear, 1130 | max: highestYear, 1131 | i: 1, 1132 | node: 'option', 1133 | item: function( loopedYear ) { 1134 | return [ 1135 | 1136 | // The looped year and no classes. 1137 | loopedYear, 0, 1138 | 1139 | // Set the value and selected index. 1140 | 'value=' + loopedYear + ( focusedYear == loopedYear ? ' selected' : '' ) 1141 | ] 1142 | } 1143 | }), 1144 | settings.klass.selectYear, 1145 | ( isOpen ? '' : 'disabled' ) + ' ' + _.ariaAttr({ controls: calendar.$node[0].id + '_table' }) + ' ' + 1146 | 'title="' + settings.labelYearSelect + '"' 1147 | ) 1148 | } 1149 | 1150 | // Otherwise just return the year focused 1151 | return _.node( 'div', focusedYear, settings.klass.year ) 1152 | } //createYearLabel 1153 | 1154 | 1155 | // Create and return the entire calendar. 1156 | return _.node( 1157 | 'div', 1158 | ( settings.selectYears ? createYearLabel() + createMonthLabel() : createMonthLabel() + createYearLabel() ) + 1159 | createMonthNav() + createMonthNav( 1 ), 1160 | settings.klass.header 1161 | ) + _.node( 1162 | 'table', 1163 | tableHead + 1164 | _.node( 1165 | 'tbody', 1166 | _.group({ 1167 | min: 0, 1168 | max: WEEKS_IN_CALENDAR - 1, 1169 | i: 1, 1170 | node: 'tr', 1171 | item: function( rowCounter ) { 1172 | 1173 | // If Monday is the first day and the month starts on Sunday, shift the date back a week. 1174 | var shiftDateBy = settings.firstDay && calendar.create([ viewsetObject.year, viewsetObject.month, 1 ]).day === 0 ? -7 : 0 1175 | 1176 | return [ 1177 | _.group({ 1178 | min: DAYS_IN_WEEK * rowCounter - viewsetObject.day + shiftDateBy + 1, // Add 1 for weekday 0index 1179 | max: function() { 1180 | return this.min + DAYS_IN_WEEK - 1 1181 | }, 1182 | i: 1, 1183 | node: 'td', 1184 | item: function( targetDate ) { 1185 | 1186 | // Convert the time date from a relative date to a target date. 1187 | targetDate = calendar.create([ viewsetObject.year, viewsetObject.month, targetDate + ( settings.firstDay ? 1 : 0 ) ]) 1188 | 1189 | var isSelected = selectedObject && selectedObject.pick == targetDate.pick, 1190 | isHighlighted = highlightedObject && highlightedObject.pick == targetDate.pick, 1191 | isDisabled = disabledCollection && calendar.disabled( targetDate ) || targetDate.pick < minLimitObject.pick || targetDate.pick > maxLimitObject.pick, 1192 | formattedDate = _.trigger( calendar.formats.toString, calendar, [ settings.format, targetDate ] ) 1193 | 1194 | return [ 1195 | _.node( 1196 | 'div', 1197 | targetDate.date, 1198 | (function( klasses ) { 1199 | 1200 | // Add the `infocus` or `outfocus` classes based on month in view. 1201 | klasses.push( viewsetObject.month == targetDate.month ? settings.klass.infocus : settings.klass.outfocus ) 1202 | 1203 | // Add the `today` class if needed. 1204 | if ( nowObject.pick == targetDate.pick ) { 1205 | klasses.push( settings.klass.now ) 1206 | } 1207 | 1208 | // Add the `selected` class if something's selected and the time matches. 1209 | if ( isSelected ) { 1210 | klasses.push( settings.klass.selected ) 1211 | } 1212 | 1213 | // Add the `highlighted` class if something's highlighted and the time matches. 1214 | if ( isHighlighted ) { 1215 | klasses.push( settings.klass.highlighted ) 1216 | } 1217 | 1218 | // Add the `disabled` class if something's disabled and the object matches. 1219 | if ( isDisabled ) { 1220 | klasses.push( settings.klass.disabled ) 1221 | } 1222 | 1223 | return klasses.join( ' ' ) 1224 | })([ settings.klass.day ]), 1225 | 'data-pick=' + targetDate.pick + ' ' + _.ariaAttr({ 1226 | role: 'gridcell', 1227 | label: formattedDate, 1228 | selected: isSelected && calendar.$node.val() === formattedDate ? true : null, 1229 | activedescendant: isHighlighted ? true : null, 1230 | disabled: isDisabled ? true : null 1231 | }) 1232 | ), 1233 | '', 1234 | _.ariaAttr({ role: 'presentation' }) 1235 | ] //endreturn 1236 | } 1237 | }) 1238 | ] //endreturn 1239 | } 1240 | }) 1241 | ), 1242 | settings.klass.table, 1243 | 'id="' + calendar.$node[0].id + '_table' + '" ' + _.ariaAttr({ 1244 | role: 'grid', 1245 | controls: calendar.$node[0].id, 1246 | readonly: true 1247 | }) 1248 | ) + 1249 | 1250 | // * For Firefox forms to submit, make sure to set the buttons’ `type` attributes as “button”. 1251 | _.node( 1252 | 'div', 1253 | _.node( 'button', settings.today, settings.klass.buttonToday, 1254 | 'type=button data-pick=' + nowObject.pick + 1255 | ( isOpen && !calendar.disabled(nowObject) ? '' : ' disabled' ) + ' ' + 1256 | _.ariaAttr({ controls: calendar.$node[0].id }) ) + 1257 | _.node( 'button', settings.clear, settings.klass.buttonClear, 1258 | 'type=button data-clear=1' + 1259 | ( isOpen ? '' : ' disabled' ) + ' ' + 1260 | _.ariaAttr({ controls: calendar.$node[0].id }) ) + 1261 | _.node('button', settings.close, settings.klass.buttonClose, 1262 | 'type=button data-close=true ' + 1263 | ( isOpen ? '' : ' disabled' ) + ' ' + 1264 | _.ariaAttr({ controls: calendar.$node[0].id }) ), 1265 | settings.klass.footer 1266 | ) //endreturn 1267 | } //DatePicker.prototype.nodes 1268 | 1269 | 1270 | 1271 | 1272 | /** 1273 | * The date picker defaults. 1274 | */ 1275 | DatePicker.defaults = (function( prefix ) { 1276 | 1277 | return { 1278 | 1279 | // The title label to use for the month nav buttons 1280 | labelMonthNext: 'Next month', 1281 | labelMonthPrev: 'Previous month', 1282 | 1283 | // The title label to use for the dropdown selectors 1284 | labelMonthSelect: 'Select a month', 1285 | labelYearSelect: 'Select a year', 1286 | 1287 | // Months and weekdays 1288 | monthsFull: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], 1289 | monthsShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ], 1290 | weekdaysFull: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ], 1291 | weekdaysShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ], 1292 | 1293 | // Today and clear 1294 | today: 'Today', 1295 | clear: 'Clear', 1296 | close: 'Close', 1297 | 1298 | // Picker close behavior 1299 | closeOnSelect: true, 1300 | closeOnClear: true, 1301 | 1302 | // The format to show on the `input` element 1303 | format: 'd mmmm, yyyy', 1304 | 1305 | // Classes 1306 | klass: { 1307 | 1308 | table: prefix + 'table', 1309 | 1310 | header: prefix + 'header', 1311 | 1312 | navPrev: prefix + 'nav--prev', 1313 | navNext: prefix + 'nav--next', 1314 | navDisabled: prefix + 'nav--disabled', 1315 | 1316 | month: prefix + 'month', 1317 | year: prefix + 'year', 1318 | 1319 | selectMonth: prefix + 'select--month', 1320 | selectYear: prefix + 'select--year', 1321 | 1322 | weekdays: prefix + 'weekday', 1323 | 1324 | day: prefix + 'day', 1325 | disabled: prefix + 'day--disabled', 1326 | selected: prefix + 'day--selected', 1327 | highlighted: prefix + 'day--highlighted', 1328 | now: prefix + 'day--today', 1329 | infocus: prefix + 'day--infocus', 1330 | outfocus: prefix + 'day--outfocus', 1331 | 1332 | footer: prefix + 'footer', 1333 | 1334 | buttonClear: prefix + 'button--clear', 1335 | buttonToday: prefix + 'button--today', 1336 | buttonClose: prefix + 'button--close' 1337 | } 1338 | } 1339 | })( Picker.klasses().picker + '__' ) 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | /** 1346 | * Extend the picker to add the date picker. 1347 | */ 1348 | Picker.extend( 'pickadate', DatePicker ) 1349 | 1350 | 1351 | })); 1352 | 1353 | 1354 | 1355 | --------------------------------------------------------------------------------