Commit 8b26ab2b by taufikyu

Merge branch 'latest' of https://git.opensipkd.com/aa.gusti/opensipkd-base into latest

2 parents 278b71c4 575f7515
Showing 58 changed files with 7870 additions and 320 deletions
......@@ -15,14 +15,14 @@ Biasanya pada home directory::
$ ~/env/bin/pip install --upgrade pip setuptools
$ ~/env/bin/pip install wheel
##Instalasi
## Instalasi
###Production:
### Production:
$ ~/env/bin/pip install git+https://git.opensipkd.com/aa.gusti/base.git@latest
$ cp ~/env/etc/live_opensipkd.tpl ~/env/etc/live_opensipkd.ini
###Install Development::
### Install Development::
$ source ~/env/bin/activate
$ mkdir apps
$ cd apps
......@@ -30,11 +30,11 @@ Biasanya pada home directory::
$ env/bin/pip install -e base[dev]
$ cp ~/env/etc/test_opensipkd.tpl ~/env/etc/test_opensipkd.ini
##Sesuaikan konfigurasi
## Sesuaikan konfigurasi
Konfigurasi tergantung pada jenis instalasi ``test_opensipkd.ini`` atau
``live_opensipkd.ini``pada baris berikut ini::
###Database Koneksi:
### Database Koneksi:
[app:main]
sqlalchemy.url = postgresql://user:password@localhost:5432/db
session.url = postgresql://user:password@localhost:5432/db
......@@ -48,7 +48,7 @@ Konfigurasi tergantung pada jenis instalasi ``test_opensipkd.ini`` atau
sqlalchemy.url = postgresql://user:password@localhost:5432/db
script_location = opensipkd.base:alembic
###Login/Register:
### Login/Register:
[app:main]
captcha_files=
# static folder untuk image captcha
......@@ -65,7 +65,7 @@ Konfigurasi tergantung pada jenis instalasi ``test_opensipkd.ini`` atau
# diisi nama template login apabila akan menggunakan template yang berbeda
###Handling Log File:
### Handling Log File:
Logging dapat dilakukan console, file atau tabel
......@@ -100,7 +100,7 @@ Logging dapat dilakukan console, file atau tabel
sqlalchemy.url = postgresql://user:password@localhost:5432/db
script_location = alembic
```
###Google Integrated dan Custom Register Form
### Google Integrated dan Custom Register Form
Aplikasi sudah bisa terintegrsi dengan google oauth2
Konfigurasi merupakan bagian dari "main"
......@@ -112,7 +112,7 @@ Konfigurasi merupakan bagian dari "main"
```
##Buat tabelnya::
## Buat tabelnya::
Perintah untuk membuat tabel
......
......@@ -40,7 +40,7 @@ from opensipkd.tools import (
from deform import ZPTRendererFactory, Form
from pkg_resources import resource_filename
from deform.widget import default_resource_registry
import os
from opensipkd.models.handlers import LogDBSession
......@@ -148,6 +148,7 @@ def add_global(event):
event['allow_register'] = allow_register
event['change_unit'] = change_unit
event['get_params'] = get_params
event['get_urls'] = get_urls
def get_params(params, alternate=None, settings=None):
......@@ -380,15 +381,18 @@ def json_rpc():
# if user is not None:
# return user.id
def get_urls(url):
home = get_params('_host', "")
if home:
urls = url.split(":")
homes = home.split(":")
if urls[0] != homes[0]:
return ":".join([homes[0], ":".join(urls[1:])])
return url
def get_host(request):
host = get_params('_host', "")
# if not host:
# host = request.route_url('home')[:-1]
# proto = 'HTTP_X_FORWARDED_PROTO' in request.environ \
# and request.environ['HTTP_X_FORWARDED_PROTO'] \
# or "http"
# host = f"{proto}://{request.host}"
return host and host or get_home(request)
......@@ -419,8 +423,11 @@ partner_idcard_url = 'partner/idcard'
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
default_resource_registry.registry['jquery.maskMoney'] = {
None: {"js": "opensipkd.base:static/jquery/jquery.maskMoney.min.js"}}
engine = engine_from_config(settings, 'sqlalchemy.')
engine = engine_from_config(
settings, 'sqlalchemy.', client_encoding='utf8', convert_unicode=True)
DBSession.configure(bind=engine)
LogDBSession.configure(bind=engine)
Base.metadata.bind = engine
......@@ -467,7 +474,8 @@ def main(global_config, **settings):
config.add_request_method(thousand, 'thousand', reify=True)
config.add_request_method(is_devel, 'devel', reify=True)
config.add_request_method(get_host, '_host', reify=True)
config.add_request_method(get_home, 'home', reify=True)
config.add_request_method(get_host, 'home', reify=True)
# config.add_request_method(get_urls, 'route_urls', reify=True)
config.add_request_method(google_signin_client_id,
'google_signin_client_id', reify=True)
config.add_request_method(google_signin_client_ids,
......
Generic single-database configuration.
alembic -c config -n section_name revision -m "notes "
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.20.0.final using JasperReports Library version 6.20.0-2bc7ab61c56f459e8176eb05c7705e145cd400ad -->
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="users" language="groovy" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="cc1a9dab-bb8a-4181-94ac-73c3dc91137c">
<property name="ireport.zoom" value="1.3310000000000004"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="0"/>
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="New Data Adapter"/>
<queryString>
<![CDATA[SELECT * FROM users]]>
</queryString>
<field name="userid" class="java.lang.String"/>
<field name="nama" class="java.lang.String"/>
<field name="created" class="java.sql.Timestamp"/>
<field name="disabled" class="java.lang.Integer"/>
<field name="passwd" class="java.lang.String"/>
<field name="id" class="java.lang.Integer"/>
<field name="kd_kantor" class="java.lang.String"/>
<field name="kd_kanwil" class="java.lang.String"/>
<field name="kd_tp" class="java.lang.String"/>
<field name="kd_kanwil_bank" class="java.lang.String"/>
<field name="kd_kppbb_bank" class="java.lang.String"/>
<field name="kd_bank_tunggal" class="java.lang.String"/>
<field name="kd_bank_persepsi" class="java.lang.String"/>
<field name="nip" class="java.lang.String"/>
<field name="jabatan" class="java.lang.String"/>
<field name="handphone" class="java.lang.String"/>
<field name="token" class="java.lang.String"/>
<field name="security_code" class="java.lang.String"/>
<field name="last_login_date" class="java.sql.Timestamp"/>
<field name="user_name" class="java.lang.String"/>
<field name="user_password" class="java.lang.String"/>
<field name="email" class="java.lang.String"/>
<field name="status" class="java.lang.Integer"/>
<field name="registered_date" class="java.sql.Timestamp"/>
<field name="security_code_date" class="java.sql.Timestamp"/>
<field name="api_key" class="java.lang.String"/>
<field name="partner_id" class="java.lang.Integer"/>
<field name="company_id" class="java.lang.Integer"/>
<background>
<band splitType="Stretch"/>
</background>
<title>
<band height="21" splitType="Stretch"/>
</title>
<pageHeader>
<band height="35" splitType="Stretch"/>
</pageHeader>
<columnHeader>
<band height="20" splitType="Stretch">
<staticText>
<reportElement x="0" y="0" width="100" height="20" uuid="45c2cace-4a3f-495c-9002-be2f2ac8eca4"/>
<textElement>
<font isBold="true" isUnderline="true"/>
</textElement>
<text><![CDATA[User Name]]></text>
</staticText>
<staticText>
<reportElement x="100" y="0" width="255" height="20" uuid="3a03e8b0-96f7-4754-b00e-ceae1a0e5aa9"/>
<textElement>
<font isBold="true" isUnderline="true"/>
</textElement>
<text><![CDATA[Email]]></text>
</staticText>
<staticText>
<reportElement x="355" y="0" width="100" height="20" uuid="f19e05c8-f1bf-4d94-927d-07111ed068df"/>
<textElement>
<font isBold="true" isUnderline="true"/>
</textElement>
<text><![CDATA[Status]]></text>
</staticText>
<staticText>
<reportElement x="455" y="0" width="100" height="20" uuid="8a8040c2-e6ba-4473-835f-c9cfe3568fb9"/>
<textElement>
<font isBold="true" isUnderline="true"/>
</textElement>
<text><![CDATA[Last Login]]></text>
</staticText>
</band>
</columnHeader>
<detail>
<band height="22" splitType="Stretch">
<textField>
<reportElement x="0" y="0" width="100" height="20" uuid="aec5f07a-b9fb-4ce1-9e7e-957f6315acb0"/>
<textFieldExpression><![CDATA[$F{user_name}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="100" y="0" width="255" height="20" uuid="04eef3a7-87ca-4a27-9392-1368a6ba2fd1"/>
<textFieldExpression><![CDATA[$F{email}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="455" y="0" width="100" height="20" uuid="24a12a8f-a1e1-4ae3-adb7-bbcf450560ee"/>
<textFieldExpression><![CDATA[$F{registered_date}]]></textFieldExpression>
</textField>
<textField>
<reportElement x="355" y="2" width="100" height="20" uuid="47051f05-f634-4c32-97cc-ce9af7b8f382"/>
<textFieldExpression><![CDATA[$F{status}.equals( 1 ) ? "Aktif" : ""]]></textFieldExpression>
</textField>
</band>
</detail>
<columnFooter>
<band height="45" splitType="Stretch"/>
</columnFooter>
<pageFooter>
<band height="54" splitType="Stretch"/>
</pageFooter>
<summary>
<band height="42" splitType="Stretch"/>
</summary>
</jasperReport>
*.DS_Store
*.sublime-project
*.sublime-workspace
node_modules/*
*.log
.idea/
{
"debug": true,
"devel": true,
"browser": true,
"asi": true,
"unused": true,
"eqnull": true
}
\ No newline at end of file
language: node_js
node_js:
- 8
before_script:
- npm install -g grunt-cli
before_install: npm install -g npm@latest
install: npm ci
# Changelog
## 3.5.6
- [#667](https://github.com/amsul/pickadate.js/issues/667) Fixed issue where script was executed before `body` was loaded.
- [#648](https://github.com/amsul/pickadate.js/issues/648) Fixed re-binding events to `P.$holder` after a re-render.
- [#652](https://github.com/amsul/pickadate.js/issues/652) Added Persian translations.
- [#669](https://github.com/amsul/pickadate.js/issues/669) Fix in Chinese translations.
- [#683](https://github.com/amsul/pickadate.js/issues/683) Fix in Japanese translations.
## 3.5.5
- [#180](https://github.com/amsul/pickadate.js/issues/180) Fixed date picker to use UTC dates.
- [#503](https://github.com/amsul/pickadate.js/issues/503) Fixed time picker to use local times.
- Fixed color for “clear” button on time picker.
- Translations fixes for [Italian](https://github.com/amsul/pickadate.js/issues/507), [Slovak](https://github.com/amsul/pickadate.js/issues/505), [French](https://github.com/amsul/pickadate.js/issues/499), [Russian](https://github.com/amsul/pickadate.js/issues/484), [Spanish](https://github.com/amsul/pickadate.js/issues/482), [Hindi](https://github.com/amsul/pickadate.js/commit/4b7b7194395657b2360c335839f5b4e21f43987a), [Brazilian Portuguese](https://github.com/amsul/pickadate.js/commit/67d0f6d26aba689c31c9ad402a109b478ffdac92)
- [#437](https://github.com/amsul/pickadate.js/issues/437): Added Common JS to UMD.
- [#478](https://github.com/amsul/pickadate.js/issues/478): Added “close” button.
- [#406](https://github.com/amsul/pickadate.js/issues/406): Allow `clear` method to be `muted`.
- [#510](https://github.com/amsul/pickadate.js/issues/510): Added `valueSubmit` to get value of hidden input element.
- [#439](https://github.com/amsul/pickadate.js/issues/439): Added ability to set min/max date & time using formatted strings.
- [#451](https://github.com/amsul/pickadate.js/issues/451): Added French accessibility labels.
- [#462](https://github.com/amsul/pickadate.js/issues/462): Fixed time offset issues by using UTC based times.
- [#476](https://github.com/amsul/pickadate.js/issues/476): Fixed the `main` files in `bower.json`.
- [#442](https://github.com/amsul/pickadate.js/issues/442): Fixed flickering on webkit browsers.
- [#438](https://github.com/amsul/pickadate.js/issues/438): Fixed adding an ID to the hidden element to remain unique.
- [#456](https://github.com/amsul/pickadate.js/issues/456): Fixed “today” button to be disabled when the date is disabled.
- [#419](https://github.com/amsul/pickadate.js/issues/419): Fixed time picker not scrolling to correct position with the “classic” theme.
- [#531](https://github.com/amsul/pickadate.js/issues/531): Fixed mutation of date object passed to `normalize`.
- [#441](https://github.com/amsul/pickadate.js/issues/441): Fixed IE8 `getComputedStyle` error.
- [#465](https://github.com/amsul/pickadate.js/issues/465): Fixed IE8 error on changing input `type`.
- [#519](https://github.com/amsul/pickadate.js/issues/519): Fixed IE8 error of picker in `iframe`.
- [#523](https://github.com/amsul/pickadate.js/issues/523): Fixed iOS8 bug of picker not opening in view.
- Fixed bug where it was possible to unbind internal bindings.
- [#420](https://github.com/amsul/pickadate.js/issues/420): [Updated docs](http://amsul.github.io/pickadate.js/api.htm#method-trigger) the `trigger` method’s ability to pass data to event callbacks.
- [#562](https://github.com/amsul/pickadate.js/issues/562): Fixed hidden `input` to move into `container` when option is used.
- [#581](https://github.com/amsul/pickadate.js/issues/581): Added ARIA label for dates and times.
- [#575](https://github.com/amsul/pickadate.js/issues/575): Removed the Sizzle dependency.
- Added `closeOnSelect` and `closeOnClear` boolean options.
## 3.5.2
- [#398](https://github.com/amsul/pickadate.js/issues/398): Fixed Nepali translations.
- [#403](https://github.com/amsul/pickadate.js/issues/403): Fixed month nav pointer styling with Bootstrap (`border-box` issue).
- [#405](https://github.com/amsul/pickadate.js/issues/405): Fixed scrollbar width checker.
- [#421](https://github.com/amsul/pickadate.js/issues/421): Fixed `picker.get('select', 'yyyy-mm-dd')` when `select` is `null`.
- [#423](https://github.com/amsul/pickadate.js/issues/423): Added Vietnamese translations.
- [#427](https://github.com/amsul/pickadate.js/issues/427): Fixed enabling date when `firstDay` is set.
- [#428](https://github.com/amsul/pickadate.js/issues/428): Fixed `$` conflict in Arabic translations.
- [#430](https://github.com/amsul/pickadate.js/issues/430): Improved differentiation between “selected” and “highlighted” dates/times.
## 3.5.0
- [#162](https://github.com/amsul/pickadate.js/issues/162): Fixed page scrolling issue when modal view is open in the default theme.
- [#350](https://github.com/amsul/pickadate.js/issues/350): Fixed Hungarian translations typo.
- [#351](https://github.com/amsul/pickadate.js/issues/351) & [#388](https://github.com/amsul/pickadate.js/issues/388) & [#393](https://github.com/amsul/pickadate.js/issues/393): Fixed issue with script freezing when `min` is `true` and “today” is disabled.
- [#358](https://github.com/amsul/pickadate.js/issues/358): Fixed parsing months as 1-indexed when value is a string.
- [#360](https://github.com/amsul/pickadate.js/issues/360): Improved Grunt script to build a cleaner project.
- [#361](https://github.com/amsul/pickadate.js/issues/361): Fixed alternate API syntax not returning the correct value.
- [#367](https://github.com/amsul/pickadate.js/issues/367): [Added a note](http://amsul.github.io/pickadate.js/date.htm#formatting-rules) on how to appropriately use the `yy` format.
- [#369](https://github.com/amsul/pickadate.js/issues/369): Added Nepali translations.
- [#377](https://github.com/amsul/pickadate.js/issues/377): Added the [`hiddenName` option](http://amsul.github.io/pickadate.js/date.htm#formats_use_hidden_only) to use the visible `input`’s name as the hidden `input`’s name.
- [#381](https://github.com/amsul/pickadate.js/issues/381): Added missing semi-colon to `legacy.js`.
- [#384](https://github.com/amsul/pickadate.js/issues/384): Year selector appears *before* the month selector.
- [#387](https://github.com/amsul/pickadate.js/issues/387): Fixed issue where the `clear` method did not reset the `select` value to `null`.
- [#395](https://github.com/amsul/pickadate.js/issues/395): [Added a note](http://amsul.github.io/pickadate.js/api.htm#method-open-close) on how to use a separate button to open/close the picker.
## 3.4.0
- ARIA support added. :star2:
- [#128](https://github.com/amsul/pickadate.js/issues/128): Date parser recognizes a string value and uses month index as 1.
- [#316](https://github.com/amsul/pickadate.js/issues/316): Date and time parser fall back to default format if none is specified.
- [#326](https://github.com/amsul/pickadate.js/issues/326): Fixed `set('disable', true)` crashing with `max: true` in options.
- [#329](https://github.com/amsul/pickadate.js/issues/329): Fixed time picker not parsing midnight correcly.
- [#325](https://github.com/amsul/pickadate.js/issues/325): Fixed Firefox bug with querying for active element with `$.contains`.
- [#330](https://github.com/amsul/pickadate.js/issues/330): Fixed month selector navigation from month with more days to one with less.
- [#332](https://github.com/amsul/pickadate.js/issues/332): Fixed issue where right-clicks caused picker to close in Firefox.
- [#338](https://github.com/amsul/pickadate.js/issues/338): Fixed IE issue with month & year selector not working correctly.
- Improved time picker setting a time relative to “now”.
- Improved disabling/enabling dates and times.
- Spanish translations typo fixed.
- Added [the `off` method](http://amsul.github.io/pickadate.js/api.htm#method-off).
- Added Galician translations.
- Added Slovenian translations.
- Added Icelandic translations.
- Added option to disable [dates](http://amsul.github.io/pickadate.js/date.htm#disable-dates-use-ranges) & [times](http://amsul.github.io/pickadate.js/time.htm#disable-times-use-ranges) within a range.
- Added option to set the [`select`](http://amsul.github.io/pickadate.js/api.htm#method-set-select-date), [`highlight`](http://amsul.github.io/pickadate.js/api.htm#method-set-highlight-date), and [`view`](http://amsul.github.io/pickadate.js/api.htm#method-set-view-date) using a string and parsing format.
- Added some performance improvents.
- Added more tests and documentation.
- Fixed `picker.get('select')` when there’s no value.
## 3.3.2
- [#283](https://github.com/amsul/pickadate.js/issues/283): Adjusted font size for narrow screens.
- [#285](https://github.com/amsul/pickadate.js/issues/285): Fixed `select` menu click on Firefox.
- [#294](https://github.com/amsul/pickadate.js/issues/294): Fixed issue with `stop` method called within `onClose`.
- [#303](https://github.com/amsul/pickadate.js/issues/303): Fixed issue with `value` not being parsed when `formatSubmit` is used.
## 3.3.1
- [#260](https://github.com/amsul/pickadate.js/issues/260): Fixed border from preventing picker from opening.
- [#248](https://github.com/amsul/pickadate.js/issues/248): Added option to enable dates/times disabled within a range.
- [#255](https://github.com/amsul/pickadate.js/issues/255): Added traditional Chinese.
- [#249](https://github.com/amsul/pickadate.js/issues/249) & [#120](https://github.com/amsul/pickadate.js/issues/120): Fixed jQuery Mobile and MagnificPopup click issues.
- [#247](https://github.com/amsul/pickadate.js/issues/247): Fixed setting min limit on time picker.
- [#278](https://github.com/amsul/pickadate.js/issues/278) & [#285](https://github.com/amsul/pickadate.js/issues/285): Fixed Firefox and IE bug for finding `activeElement`.
- [#279](https://github.com/amsul/pickadate.js/issues/279): Added option to `set` things with [muted callbacks](http://amsul.github.io/pickadate.js/pickadate.js/api.htm#muted-callbacks).
- Fixed French translations capitalization.
- Fixed time picker scrolling.
- Added setting a [time using a native JavaScript date objects](http://amsul.github.io/pickadate.js/api.htm#method-set-select-time).
- Added option to keep an [editable `input`](http://amsul.github.io/pickadate.js/date.htm#editable) element.
## 3.3.0
- [#238](https://github.com/amsul/pickadate.js/issues/238): Improved disabled dates validation.
- [#236](https://github.com/amsul/pickadate.js/issues/236): Fixed transparency issue in IE8 on XP.
- [#159](https://github.com/amsul/pickadate.js/issues/159): Added functionality to reset disabled dates/times.
- [#232](https://github.com/amsul/pickadate.js/issues/232): Dropdown styling tweaked.
- [#197](https://github.com/amsul/pickadate.js/issues/197): Fixed issue with forms not submitting on Firefox.
- [#230](https://github.com/amsul/pickadate.js/issues/230): Fixed issue with selected time scrolling into view.
- [#208](https://github.com/amsul/pickadate.js/issues/208) & [#209](https://github.com/amsul/pickadate.js/issues/209): Added `hiddenPrefix` option for hidden input element’s name attribute.
- [#130](https://github.com/amsul/pickadate.js/issues/130): Fixed issue with passing focus to an element with custom jQuery builds.
- [#246](https://github.com/amsul/pickadate.js/issues/246) & [#242](https://github.com/amsul/pickadate.js/issues/242): Resolved jQuery conflict.
- [#247](https://github.com/amsul/pickadate.js/issues/247): Fixed issue with time picker intervals and the min selectable time.
- Added option to disabled/enable dates using JavaScript Date objects.
- Tweaked functionality in enabling/disabling dates and times.
- Improved support for RTL languages and keyboard navigation.
- Added `rtl.css` for styling RTL languages appropriatey.
## 3.2.2
- [#216](https://github.com/amsul/pickadate.js/issues/216): Added generic Arabic translations.
- [#210](https://github.com/amsul/pickadate.js/issues/210): Fixed jQuery conflict in picker extension files.
- [#223](https://github.com/amsul/pickadate.js/issues/223): Time picker “disabled” attribute fix.
- Fixed issue with IE losing key bindings when clicked within picker.
- Improved delegated click handling on picker elements.
## 3.2.1
- [#210](https://github.com/amsul/pickadate.js/issues/210): Wrapped files using UMD patterns.
- [#207](https://github.com/amsul/pickadate.js/issues/207): Japanese translations added.
- Some other slight improvements.
## 3.2.0
- [#178](https://github.com/amsul/pickadate.js/issues/178): Fix for flicker on iOS while changing months.
- Added `render(true)` option to render full picker or just the “face” ([read more](http://amsul.github.io/pickadate.js/api.htm#method-render)).
## 3.1.4
- Fix for Polish translation.
- Added a `container` option to specify the picker root element’s outlet.
- Fix for `$` conflict in translation files.
## 3.1.3
- Korean translations added.
## 3.1.2
- [#168](https://github.com/amsul/pickadate.js/issues/168): Fixed month navigation with disabled dates.
## 3.1.1
- [#161](https://github.com/amsul/pickadate.js/issues/161): Corrected “no-drop” cursor on input element for certain browsers.
- [#158](https://github.com/amsul/pickadate.js/issues/158): Fixed CSS for disabled dates with unfocused input.
- [#155](https://github.com/amsul/pickadate.js/issues/155): Corrected unescaped translations.
## 3.1.0
- [#140](https://github.com/amsul/pickadate.js/issues/140): Fix for freezing with unexpected date format.
- [#154](https://github.com/amsul/pickadate.js/issues/154): Fix for “mm” and “m” formats opening with incorrect month.
- Border styling adjusted for disabled times.
## v3.0.5
- [#145](https://github.com/amsul/pickadate.js/issues/145): Fix for `getFirstWordLength` not being defined.
- [#137](https://github.com/amsul/pickadate.js/issues/137): Corrected Norwegian translation.
## v3.0.4
- [#132](https://github.com/amsul/pickadate.js/issues/132): Fix for using `firstDay` with month starting on Sunday.
- Improved disabled dates validation.
## v3.0.3
- [#126](https://github.com/amsul/pickadate.js/issues/126): Fix for all dates disabled.
- [#127](https://github.com/amsul/pickadate.js/issues/127): Fix for jQuery no conflict.
- [#129](https://github.com/amsul/pickadate.js/issues/129): Fix for month nav wrapping around same year.
## v3.0.2
- [#124](https://github.com/amsul/pickadate.js/issues/124): Fixed bug with navigating past year.
## v3.0.1
- [#123](https://github.com/amsul/pickadate.js/issues/123): Removed `hiddenSuffix` extra quote character.
- Fixed issue with month navigation on the 31st date.
## v3.0.0
With this major release, the entire API has been rethought to allow the picker to be much more configurable and extensible. These are the most notable updates:
- [#20](https://github.com/amsul/pickadate.js/issues/20): Introduced a new [time picker](http://amsul.github.io/pickadate.js/time.htm).
- [#112](https://github.com/amsul/pickadate.js/issues/112): Firefox select month/year fix.
- [#84](https://github.com/amsul/pickadate.js/issues/84): Scrollbar not hidden to avoid page shift.
- [#89](https://github.com/amsul/pickadate.js/issues/89): Better event handling on clicks/focuses/keydowns within the holder.
- [#98](https://github.com/amsul/pickadate.js/issues/98): Destroy picker data from element.
- Added Grunt.js build system.
- Added QUnit test suite.
- Added Travis integration.
- Updated themes to be LESS-based.
- Removed “inline” and “inline-fixed” themes.
- Removed jam.js bindings within `package.json`.
- Removed official support for IE7. Still works but looks odd.
To enable all this goodness, some **backward-incompatible changes** have been introduced. These are the main ones:
<a name="zero-as-index"></a>
- [#85](https://github.com/amsul/pickadate.js/issues/85): Months have __zero-as-index__:
Just as in JavaScript’s native Date object, the `month` used to create dates is now based on zero as the first index. Meaning:
```
[2013,0,1] → January 01, 2013
[2013,11,1] → December 01, 2013
```
- API revised:
```
isOpen → get('open')
getDate → get('select')
getDateLimit → get('min') or get('max')
setDate → set('select', …)
setDateLimit → set('min', …) or set('max', …)
show → set('view', …)
```
- Options revised:
```
showMonthsFull → showMonthsShort
showWeekdaysShort → showWeekdaysFull
yearSelector → selectYears
monthSelector → selectMonths
dateMin → min
dateMax → max
datesDisabled → disable
onSelect → onSet
```
- Options removed:
```
monthPrev
monthNext
```
To add labels for the month navigation tabs, use CSS pseudo-elements instead.
- A few [HTML classes](http://amsul.github.io/pickadate.js/date.htm#classes) name and property changes.
- [Formatting rules](http://amsul.github.io/pickadate.js/date.htm#formats) that appear within a word need to be escaped with an exclamation mark (!).
<br>
#### Please do read the [docs](http://amsul.github.io/pickadate.js/date.htm#options) and [api](http://amsul.github.io/pickadate.js/api.htm) to see exactly how these new options and methods work.
<br>
## Older changelogs
If you’re looking for changes in older versions, please [browse the tags](https://github.com/amsul/pickadate.js/tags) for the relevant commit archive and changelog file.
# Contributing
Want to help contribute something to the project? Awesome! :smile:
Please take a moment to review this doc to make contributions easy and effective for everyone.
If there’s anything you’d like to discuss before diving in, you can find us on Gitter.
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/amsul/pickadate.js)
<a name="bugs"></a>
## Bug reports
If you believe you’ve found a bug within the repository code:
- Search the existing issues to avoid duplicates and to check if it has already been solved.
- Make sure you’re using the latest build.
- Isolate the problem and create a [reduced test case](http://css-tricks.com/6263-reduced-test-cases/) - preferably supported with a live example.
- Try to be as detailed as possible in the report (OS, browser, expected outcome vs actual outcome, etc).
- Please **do not** use the issue tracker for personal support requests. Instead try [Stack Overflow](http://stackoverflow.com/questions/tagged/pickadate) or the likes with a `pickadate` tag.
<a name="pull-requests"></a>
## Pull requests
If you’re submitting a pull request, please respect the coding standards used (indentations, comments, semi-colons, etc) as per the **Golden Rule**:
> All code in any code base should look like a single person typed it, no matter how many people contributed.
A few other things to keep in mind:
- Make sure the changes are suitable within the scope of this project.
- Discuss any significant features before endeavoring into developing them. I’d hate to have anyone spend effort on something only for me to not merge it into the main project.
- Include the relevant test coverage if any JavaScript files are involved.
- Compile the project using `grunt build --verbose` to make sure everything passes with a green flag.
- Use the Semantic Versioning guide, as mentioned in the [readme file](https://github.com/amsul/pickadate.js/#readme), in the case that a version bump is due.
#### All pull requests should be submitted to the `master` branch.
<a name="features"></a>
## Feature requests
Feature requests are welcome. But take a moment to find out whether your idea fits within the scope and aims of this project. It’s up to *you* to make a strong case to the merits of this feature. Please provide as much detail and context as possible.
/*!
* This Gruntfile is used to build the project files.
*/
/*jshint
node: true
*/
module.exports = function( grunt ) {
// Read the package manifest.
var packageJSON = grunt.file.readJSON( 'package.json' )
// Load the NPM tasks.
grunt.loadNpmTasks( 'grunt-contrib-watch' )
grunt.loadNpmTasks( 'grunt-contrib-jshint' )
grunt.loadNpmTasks( 'grunt-contrib-qunit' )
grunt.loadNpmTasks( 'grunt-contrib-less' )
grunt.loadNpmTasks( 'grunt-contrib-cssmin' )
grunt.loadNpmTasks( 'grunt-contrib-uglify' )
grunt.loadNpmTasks( 'grunt-autoprefixer' )
// Setup the initial configurations.
grunt.initConfig({
// Add the package data.
pkg: packageJSON,
// Set up the directories.
dirs: {
tests: 'tests',
lib: {
src: 'lib',
min: 'lib/compressed'
},
themes: {
src: 'lib/themes-source',
dest: 'lib/themes',
min: 'lib/compressed/themes'
},
translations: {
src: 'lib/translations',
min: 'lib/compressed/translations'
},
},
// Compile LESS into CSS.
less: {
options: {
style: 'expanded'
},
themes: {
files: {
'<%= dirs.themes.dest %>/default.css': [ '<%= dirs.themes.src %>/base.less', '<%= dirs.themes.src %>/default.less' ],
'<%= dirs.themes.dest %>/classic.css': [ '<%= dirs.themes.src %>/base.less', '<%= dirs.themes.src %>/classic.less' ],
'<%= dirs.themes.dest %>/default.date.css': [ '<%= dirs.themes.src %>/base.date.less', '<%= dirs.themes.src %>/default.date.less' ],
'<%= dirs.themes.dest %>/default.time.css': [ '<%= dirs.themes.src %>/base.time.less', '<%= dirs.themes.src %>/default.time.less' ],
'<%= dirs.themes.dest %>/classic.date.css': [ '<%= dirs.themes.src %>/base.date.less', '<%= dirs.themes.src %>/classic.date.less' ],
'<%= dirs.themes.dest %>/classic.time.css': [ '<%= dirs.themes.src %>/base.time.less', '<%= dirs.themes.src %>/classic.time.less' ],
'<%= dirs.themes.dest %>/rtl.css': [ '<%= dirs.themes.src %>/rtl.less' ]
}
}
},
// Lint the files.
jshint: {
options: {
jshintrc: true
},
gruntfile: 'Gruntfile.js',
lib: [
'<%= dirs.tests %>/units/*.js',
'<%= dirs.lib.src %>/**/*.js',
// Ignore the legacy and minified files.
'!<%= dirs.lib.src %>/legacy.js',
'!<%= dirs.lib.src %>/compressed/**/*.js'
]
},
// Minify all the things!
uglify: {
options: {
preserveComments: 'some'
},
lib: {
files: [
{
expand : true,
cwd : '<%= dirs.lib.src %>',
src : [ '**/*.js', '!compressed/**/*.js' ],
dest : '<%= dirs.lib.min %>'
}
]
}
},
cssmin: {
lib: {
expand: true,
cwd: '<%= dirs.themes.dest %>',
src: [ '**/*.css', '!compressed/**/*.css' ],
dest: '<%= dirs.themes.min %>'
}
},
// Prefix the styles.
autoprefixer: {
options: {
browsers: [ '> 5%', 'last 2 versions', 'ie 8', 'ie 9' ]
},
themes: {
src: '<%= dirs.themes.dest %>/**/*.css'
},
},
// Unit test the files.
qunit: {
lib: [ '<%= dirs.tests %>/units/all.htm' ]
},
// Watch the project files.
watch: {
develop: {
files: [
'<%= dirs.themes.src %>/**/*.less'
],
tasks: [ 'develop-once' ]
},
}
}) //grunt.initConfig
// Register the tasks.
grunt.registerTask( 'default', [ 'develop' ] )
grunt.registerTask( 'develop', [ 'develop-once', 'watch:develop' ] )
grunt.registerTask( 'develop-once', [ 'less:themes', 'autoprefixer:themes' ] )
grunt.registerTask( 'package', [ 'develop-once', 'uglify', 'cssmin' ] )
grunt.registerTask( 'test', [ 'jshint', 'qunit' ] )
} //module.exports
Copyright 2014 Amsul, http://amsul.ca
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
# pickadate [![Build status: master](https://travis-ci.org/amsul/pickadate.js.svg?branch=master)](https://travis-ci.org/amsul/pickadate.js) [![jsDelivr Hits](https://data.jsdelivr.com/v1/package/npm/pickadate/badge?style=rounded)](https://www.jsdelivr.com/package/npm/pickadate)
The mobile-friendly, responsive, and lightweight jQuery date & time input picker.
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/pickadate)
#### To get started, check out the:
[Homepage](http://amsul.ca/pickadate.js) - [Date picker](http://amsul.ca/pickadate.js/date) - [Time picker](http://amsul.ca/pickadate.js/time) - [API](http://amsul.ca/pickadate.js/api)
#### To get it:
[Download the latest stable build](https://github.com/amsul/pickadate.js/archive/master.zip)
*or*
`git clone git://github.com/amsul/pickadate.js.git`
*or*
`bower install pickadate`
<br>
## Library files
The `lib` folder includes the library files with a `compressed` folder containing the minified counter-parts. These files are minified using [Grunt](#building-with-grunt).
### Pickers
There are three picker files:
* `picker.js` The core file (required before any other picker)
* `picker.date.js` The date picker
* `picker.time.js` The time picker
_To support old browsers, namely IE8, **also include** the `legacy.js` file._
### Themes
All themes are [generated using LESS](#less-styling) and compiled from the `lib/themes-source` folder into the `lib/themes` folder.
There are two themes:
* `default.css` The default modal-style theme
* `classic.css` The classic dropdown-style theme
Based on the theme, pick the relevant picker styles:
* `default.date.css` and `default.time.css` when using the default theme
* `classic.date.css` and `classic.time.css` when using the classic theme
__**__ For languages with text flowing from right-to-left, also include the `rtl.css` stylesheet.
### Translations
The translations live in the `lib/translations` folder. There are currently [43 language translations](https://github.com/amsul/pickadate.js/tree/master/lib/translations) included.
<br>
## Building with Grunt
[Grunt](http://gruntjs.com/) `~0.4.5` is used to build the project files. To get started, clone the project and then run:
- `npm install` to get the required node modules.
- `grunt test --verbose` to confirm you have all the dependencies.
Type out `grunt --help` to see a list of all the tasks available. The generally used tasks are:
- `grunt develop` compiles the LESS files and watches for any source changes.
- `grunt package` compiles and then minifies the source files.
- `grunt test` tests the entire package.
<br>
<a name="less-styling"></a>
## Styling with LESS
The picker themes are built using [LESS](http://lesscss.org/) with Grunt. To customize the CSS output, read the `_variables.less` file in the `lib/themes-source` folder. You can specify:
- colors for the theme,
- sizes for the picker,
- media-query breakpoints,
- and a whole bunch of other stuff.
Make sure to run the `grunt develop` task before making any changes to compile it into CSS.
<br>
## Bugs
Before opening a new issue, please search the existing [Issues](https://github.com/amsul/pickadate.js/issues) for anything similar – there might already be an answer to your problem. You might also wanna check out the [Contributing](https://github.com/amsul/pickadate.js/blob/master/CONTRIBUTING.md) guide.
<br>
## Contributing
Before contributing any code to the project, please take a look at the [Contributing](https://github.com/amsul/pickadate.js/blob/master/CONTRIBUTING.md) guide.
If there’s anything you’d like to discuss, we like to hang out on Spectrum.
[![Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/pickadate)
<br>
## Support
If you find this library useful and would like to see further development, consider [supporting it](http://selz.co/1g80kCZ).
<br><br>
---
© 2014 [Amsul](http://twitter.com/amsul_)
Licensed under [MIT](http://amsul.ca/MIT)
{
"name": "pickadate",
"description": "The mobile-friendly, responsive, and lightweight jQuery date & time input picker.",
"main": [
"lib/picker.js",
"lib/picker.date.js",
"lib/picker.time.js",
"lib/themes/default.css",
"lib/themes/default.date.css",
"lib/themes/default.time.css"
],
"license": "MIT",
"ignore": [
"*.md",
"*.htm",
"_docs",
"demo"
],
"keywords": [
"date",
"time",
"picker",
"input",
"responsive"
],
"authors": {
"name": "Amsul",
"email": "reach@amsul.ca",
"homepage": "http://amsul.ca"
},
"homepage": "http://amsul.ca/pickadate.js",
"repository": {
"type": "git",
"url": "git://github.com/amsul/pickadate.js.git"
},
"dependencies": {
"jquery": ">=1.7"
},
"devDependencies": {
"grunt": "^0.4.5",
"grunt-autoprefixer": "^1.0.1",
"grunt-contrib-copy": "^0.5.0",
"grunt-contrib-cssmin": "^0.9.0",
"grunt-contrib-jshint": "^0.10.0",
"grunt-contrib-less": "^0.11.4",
"grunt-contrib-qunit": "^0.4.0",
"grunt-contrib-uglify": "^0.4.1",
"grunt-contrib-watch": "^0.6.1",
"phantomjs": "^1.9.7-5",
"zlib-browserify": "0.0.3"
}
}
\ No newline at end of file
{
"name": "pickadate",
"version": "3.6.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
},
"ajv": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
"dev": true,
"requires": {
"co": "^4.6.0",
"json-stable-stringify": "^1.0.1"
}
},
"align-text": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
"dev": true,
"requires": {
"kind-of": "^3.0.2",
"longest": "^1.0.1",
"repeat-string": "^1.5.2"
}
},
"amdefine": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
"ansi-regex": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz",
"integrity": "sha1-QchHGUZGN15qGl0Qw8oFTvn8mA0=",
"dev": true
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"argparse": {
"version": "0.1.16",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz",
"integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=",
"dev": true,
"requires": {
"underscore": "~1.7.0",
"underscore.string": "~2.4.0"
},
"dependencies": {
"underscore.string": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz",
"integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=",
"dev": true
}
}
},
"array-find-index": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
"integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
"dev": true
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
"dev": true,
"optional": true
},
"asn1": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
"dev": true
},
"assert-plus": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
"integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=",
"dev": true
},
"async": {
"version": "0.1.22",
"resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz",
"integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=",
"dev": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"dev": true
},
"autoprefixer-core": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/autoprefixer-core/-/autoprefixer-core-5.2.1.tgz",
"integrity": "sha1-5kDEFK5Bmq4hwa1DyOoPPbgqVm0=",
"dev": true,
"requires": {
"browserslist": "~0.4.0",
"caniuse-db": "^1.0.30000214",
"num2fraction": "^1.1.0",
"postcss": "~4.1.12"
}
},
"aws-sign2": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
"integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
"dev": true
},
"aws4": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
"dev": true
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true
},
"bcrypt-pbkdf": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
"dev": true,
"optional": true,
"requires": {
"tweetnacl": "^0.14.3"
}
},
"boom": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
"dev": true,
"requires": {
"hoek": "2.x.x"
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"browserify-zlib": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
"integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
"dev": true,
"requires": {
"pako": "~0.2.0"
}
},
"browserslist": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-0.4.0.tgz",
"integrity": "sha1-O9SrkZncG5FQ1NbbpNnTqrvIbdQ=",
"dev": true,
"requires": {
"caniuse-db": "^1.0.30000153"
}
},
"builtin-modules": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
"dev": true
},
"camelcase": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
"integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
"dev": true
},
"camelcase-keys": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
"integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
"dev": true,
"requires": {
"camelcase": "^2.0.0",
"map-obj": "^1.0.0"
}
},
"caniuse-db": {
"version": "1.0.30000809",
"resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000809.tgz",
"integrity": "sha1-sLiENKWY9AtUbUak29g5sP95j00=",
"dev": true
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
},
"center-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
"dev": true,
"requires": {
"align-text": "^0.1.3",
"lazy-cache": "^1.0.3"
}
},
"chalk": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.0.0.tgz",
"integrity": "sha1-s89O0P9Tl8mcdbj2edsvUoMfltw=",
"dev": true,
"requires": {
"ansi-styles": "^2.0.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^1.0.3",
"strip-ansi": "^2.0.1",
"supports-color": "^1.3.0"
}
},
"clean-css": {
"version": "3.4.28",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
"integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
"dev": true,
"requires": {
"commander": "2.8.x",
"source-map": "0.4.x"
},
"dependencies": {
"commander": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"dev": true,
"requires": {
"graceful-readlink": ">= 1.0.0"
}
}
}
},
"cli": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/cli/-/cli-0.6.6.tgz",
"integrity": "sha1-Aq1Eo4Cr8nraxebwzdewQ9dMU+M=",
"dev": true,
"requires": {
"exit": "0.1.2",
"glob": "~ 3.2.1"
},
"dependencies": {
"glob": {
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz",
"integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=",
"dev": true,
"requires": {
"inherits": "2",
"minimatch": "0.3"
}
},
"minimatch": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
"integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=",
"dev": true,
"requires": {
"lru-cache": "2",
"sigmund": "~1.0.0"
}
}
}
},
"cliui": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
"integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
"dev": true,
"requires": {
"center-align": "^0.1.1",
"right-align": "^0.1.1",
"wordwrap": "0.0.2"
}
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
"dev": true
},
"coffee-script": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz",
"integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=",
"dev": true
},
"colors": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
"integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=",
"dev": true
},
"combined-stream": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz",
"integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=",
"dev": true,
"requires": {
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz",
"integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"concat-stream": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
"dev": true,
"requires": {
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"console-browserify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
"integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
"dev": true,
"requires": {
"date-now": "^0.1.4"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true
},
"cryptiles": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
"dev": true,
"requires": {
"boom": "2.x.x"
}
},
"currently-unhandled": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
"integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
"dev": true,
"requires": {
"array-find-index": "^1.0.1"
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
}
}
},
"date-now": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
"integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
"dev": true
},
"dateformat": {
"version": "1.0.2-1.2.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz",
"integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=",
"dev": true
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
"deep-equal": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-0.0.0.tgz",
"integrity": "sha1-mWedO70EcVb81FDT0B7rkGhpHoM=",
"dev": true
},
"defined": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/defined/-/defined-0.0.0.tgz",
"integrity": "sha1-817qfXBekzuvE7LwOz+D2SFAOz4=",
"dev": true
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"dev": true
},
"diff": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-1.3.2.tgz",
"integrity": "sha1-/Qeh8fiRUZ2ZBaTJqJ3PWnC2YDc=",
"dev": true
},
"dom-serializer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
"dev": true,
"requires": {
"domelementtype": "~1.1.1",
"entities": "~1.1.1"
},
"dependencies": {
"domelementtype": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=",
"dev": true
},
"entities": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=",
"dev": true
}
}
},
"domelementtype": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=",
"dev": true
},
"domhandler": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
"integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=",
"dev": true,
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
"dev": true,
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"ecc-jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
"dev": true,
"optional": true,
"requires": {
"jsbn": "~0.1.0"
}
},
"entities": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
"integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=",
"dev": true
},
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
"integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
"dev": true,
"optional": true,
"requires": {
"prr": "~1.0.1"
}
},
"error-ex": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
"integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
"dev": true,
"requires": {
"is-arrayish": "^0.2.1"
}
},
"es6-promise": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz",
"integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"esprima": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
"integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=",
"dev": true
},
"eventemitter2": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
"integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
"dev": true
},
"exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
"integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
"dev": true
},
"extend": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
"integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
"dev": true
},
"extract-zip": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz",
"integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=",
"dev": true,
"requires": {
"concat-stream": "1.6.0",
"debug": "2.6.9",
"mkdirp": "0.5.0",
"yauzl": "2.4.1"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"mkdirp": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
"integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=",
"dev": true,
"requires": {
"minimist": "0.0.8"
}
}
}
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
},
"faye-websocket": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.4.4.tgz",
"integrity": "sha1-wUxbO/FNdBf/v9mQwKdJXNnzN7w=",
"dev": true
},
"fd-slicer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
"dev": true,
"requires": {
"pend": "~1.2.0"
}
},
"figures": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
"integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5",
"object-assign": "^4.1.0"
}
},
"file-sync-cmp": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz",
"integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=",
"dev": true
},
"find-up": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
"dev": true,
"requires": {
"path-exists": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"findup-sync": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz",
"integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=",
"dev": true,
"requires": {
"glob": "~3.2.9",
"lodash": "~2.4.1"
},
"dependencies": {
"glob": {
"version": "3.2.11",
"resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz",
"integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=",
"dev": true,
"requires": {
"inherits": "2",
"minimatch": "0.3"
}
},
"lodash": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
"dev": true
},
"minimatch": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
"integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=",
"dev": true,
"requires": {
"lru-cache": "2",
"sigmund": "~1.0.0"
}
}
}
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
"dev": true
},
"form-data": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
"integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
"dev": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.5",
"mime-types": "^2.1.12"
}
},
"fs-extra": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
"integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^2.1.0",
"klaw": "^1.0.0"
},
"dependencies": {
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
}
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"gaze": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz",
"integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=",
"dev": true,
"requires": {
"globule": "~0.1.0"
}
},
"get-stdin": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
"dev": true
},
"getobject": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
"integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
"dev": true
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
}
}
},
"glob": {
"version": "5.0.15",
"resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
"integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
"dev": true,
"requires": {
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "2 || 3",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"globule": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
"integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=",
"dev": true,
"requires": {
"glob": "~3.1.21",
"lodash": "~1.0.1",
"minimatch": "~0.2.11"
},
"dependencies": {
"glob": {
"version": "3.1.21",
"resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
"integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=",
"dev": true,
"requires": {
"graceful-fs": "~1.2.0",
"inherits": "1",
"minimatch": "~0.2.11"
}
},
"inherits": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz",
"integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=",
"dev": true
},
"lodash": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz",
"integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=",
"dev": true
},
"minimatch": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
"integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=",
"dev": true,
"requires": {
"lru-cache": "2",
"sigmund": "~1.0.0"
}
}
}
},
"graceful-fs": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz",
"integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=",
"dev": true
},
"graceful-readlink": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
"dev": true
},
"grunt": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz",
"integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=",
"dev": true,
"requires": {
"async": "~0.1.22",
"coffee-script": "~1.3.3",
"colors": "~0.6.2",
"dateformat": "1.0.2-1.2.3",
"eventemitter2": "~0.4.13",
"exit": "~0.1.1",
"findup-sync": "~0.1.2",
"getobject": "~0.1.0",
"glob": "~3.1.21",
"grunt-legacy-log": "~0.1.0",
"grunt-legacy-util": "~0.2.0",
"hooker": "~0.2.3",
"iconv-lite": "~0.2.11",
"js-yaml": "~2.0.5",
"lodash": "~0.9.2",
"minimatch": "~0.2.12",
"nopt": "~1.0.10",
"rimraf": "~2.2.8",
"underscore.string": "~2.2.1",
"which": "~1.0.5"
},
"dependencies": {
"glob": {
"version": "3.1.21",
"resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
"integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=",
"dev": true,
"requires": {
"graceful-fs": "~1.2.0",
"inherits": "1",
"minimatch": "~0.2.11"
}
},
"inherits": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz",
"integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=",
"dev": true
},
"minimatch": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
"integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=",
"dev": true,
"requires": {
"lru-cache": "2",
"sigmund": "~1.0.0"
}
}
}
},
"grunt-autoprefixer": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/grunt-autoprefixer/-/grunt-autoprefixer-3.0.4.tgz",
"integrity": "sha1-/kLiR7z6ucKSoSwGLa1PNb3pAsU=",
"dev": true,
"requires": {
"autoprefixer-core": "^5.1.7",
"chalk": "~1.0.0",
"diff": "~1.3.0",
"postcss": "^4.1.11"
}
},
"grunt-contrib-copy": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-0.8.2.tgz",
"integrity": "sha1-3zHJD/zECbyfr+ROwN0eQlmRb+o=",
"dev": true,
"requires": {
"chalk": "^1.1.1",
"file-sync-cmp": "^0.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
}
}
},
"grunt-contrib-cssmin": {
"version": "0.12.3",
"resolved": "https://registry.npmjs.org/grunt-contrib-cssmin/-/grunt-contrib-cssmin-0.12.3.tgz",
"integrity": "sha1-QVdZYJb7dlb8RktMx7B0beHzkBQ=",
"dev": true,
"requires": {
"chalk": "^1.0.0",
"clean-css": "^3.1.0",
"maxmin": "^1.1.0"
}
},
"grunt-contrib-jshint": {
"version": "0.11.3",
"resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-0.11.3.tgz",
"integrity": "sha1-gDaBgdzNVRGG5bg4XAEc7iTWQKA=",
"dev": true,
"requires": {
"hooker": "^0.2.3",
"jshint": "~2.8.0"
}
},
"grunt-contrib-less": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/grunt-contrib-less/-/grunt-contrib-less-1.4.1.tgz",
"integrity": "sha1-O73sC3XRLOqlXWKUNiXAsIYc328=",
"dev": true,
"requires": {
"async": "^2.0.0",
"chalk": "^1.0.0",
"less": "~2.7.1",
"lodash": "^4.8.2"
},
"dependencies": {
"async": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz",
"integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==",
"dev": true,
"requires": {
"lodash": "^4.14.0"
}
},
"lodash": {
"version": "4.17.5",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
"integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==",
"dev": true
}
}
},
"grunt-contrib-qunit": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/grunt-contrib-qunit/-/grunt-contrib-qunit-2.0.0.tgz",
"integrity": "sha1-VKUbSyyE/uYsO34AFFySjR7Ct+w=",
"dev": true,
"requires": {
"grunt-lib-phantomjs": "^1.0.0"
}
},
"grunt-contrib-uglify": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-0.9.2.tgz",
"integrity": "sha1-GmHG8hJBDkq7T3yJFTcXsQFWAmA=",
"dev": true,
"requires": {
"chalk": "^1.0.0",
"lodash": "^3.2.0",
"maxmin": "^1.0.0",
"uglify-js": "^2.4.24",
"uri-path": "0.0.2"
},
"dependencies": {
"lodash": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
"integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
"dev": true
}
}
},
"grunt-contrib-watch": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-0.6.1.tgz",
"integrity": "sha1-ZP3LolpjX1tNobbOb5DaCutuPxU=",
"dev": true,
"requires": {
"async": "~0.2.9",
"gaze": "~0.5.1",
"lodash": "~2.4.1",
"tiny-lr-fork": "0.0.5"
},
"dependencies": {
"async": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
"integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
"dev": true
},
"lodash": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
"dev": true
}
}
},
"grunt-legacy-log": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz",
"integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=",
"dev": true,
"requires": {
"colors": "~0.6.2",
"grunt-legacy-log-utils": "~0.1.1",
"hooker": "~0.2.3",
"lodash": "~2.4.1",
"underscore.string": "~2.3.3"
},
"dependencies": {
"lodash": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
"dev": true
},
"underscore.string": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz",
"integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=",
"dev": true
}
}
},
"grunt-legacy-log-utils": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz",
"integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=",
"dev": true,
"requires": {
"colors": "~0.6.2",
"lodash": "~2.4.1",
"underscore.string": "~2.3.3"
},
"dependencies": {
"lodash": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
"integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
"dev": true
},
"underscore.string": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz",
"integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=",
"dev": true
}
}
},
"grunt-legacy-util": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz",
"integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=",
"dev": true,
"requires": {
"async": "~0.1.22",
"exit": "~0.1.1",
"getobject": "~0.1.0",
"hooker": "~0.2.3",
"lodash": "~0.9.2",
"underscore.string": "~2.2.1",
"which": "~1.0.5"
}
},
"grunt-lib-phantomjs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/grunt-lib-phantomjs/-/grunt-lib-phantomjs-1.1.0.tgz",
"integrity": "sha1-np7c3Z/S3UDgwYHJQ3HVcqpe6tI=",
"dev": true,
"requires": {
"eventemitter2": "^0.4.9",
"phantomjs-prebuilt": "^2.1.3",
"rimraf": "^2.5.2",
"semver": "^5.1.0",
"temporary": "^0.0.8"
},
"dependencies": {
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"requires": {
"glob": "^7.0.5"
}
},
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
"dev": true
}
}
},
"gzip-size": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-1.0.0.tgz",
"integrity": "sha1-Zs+LEBBHInuVus5uodoMF37Vwi8=",
"dev": true,
"requires": {
"browserify-zlib": "^0.1.4",
"concat-stream": "^1.4.1"
}
},
"har-schema": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
"integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=",
"dev": true
},
"har-validator": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
"integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
"dev": true,
"requires": {
"ajv": "^4.9.1",
"har-schema": "^1.0.5"
}
},
"has-ansi": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-1.0.3.tgz",
"integrity": "sha1-wLWxYV2eOCsP9nFp2We0JeSMpTg=",
"dev": true,
"requires": {
"ansi-regex": "^1.1.0",
"get-stdin": "^4.0.1"
}
},
"hasha": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz",
"integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=",
"dev": true,
"requires": {
"is-stream": "^1.0.1",
"pinkie-promise": "^2.0.0"
}
},
"hawk": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
"dev": true,
"requires": {
"boom": "2.x.x",
"cryptiles": "2.x.x",
"hoek": "2.x.x",
"sntp": "1.x.x"
}
},
"hoek": {
"version": "2.16.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
"integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
"dev": true
},
"hooker": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
"integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
"dev": true
},
"hosted-git-info": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
"integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==",
"dev": true
},
"htmlparser2": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
"integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=",
"dev": true,
"requires": {
"domelementtype": "1",
"domhandler": "2.3",
"domutils": "1.5",
"entities": "1.0",
"readable-stream": "1.1"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"dev": true
}
}
},
"http-signature": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
"dev": true,
"requires": {
"assert-plus": "^0.2.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"iconv-lite": {
"version": "0.2.11",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz",
"integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=",
"dev": true
},
"image-size": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
"integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
"dev": true,
"optional": true
},
"indent-string": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
"integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
"dev": true,
"requires": {
"repeating": "^2.0.0"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true
},
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
"dev": true
},
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"dev": true
},
"is-builtin-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
"dev": true,
"requires": {
"builtin-modules": "^1.0.0"
}
},
"is-finite": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
"integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
"dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"dev": true
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
"dev": true
},
"is-utf8": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
"dev": true
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
},
"js-base64": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.1.9.tgz",
"integrity": "sha1-8OgK4DmkvWVLXygfyT8EqRSn/M4=",
"dev": true
},
"js-yaml": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz",
"integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=",
"dev": true,
"requires": {
"argparse": "~ 0.1.11",
"esprima": "~ 1.0.2"
}
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"dev": true,
"optional": true
},
"jshint": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/jshint/-/jshint-2.8.0.tgz",
"integrity": "sha1-HQmjvZE8TK36gb8Y1YK9hb/+DUQ=",
"dev": true,
"requires": {
"cli": "0.6.x",
"console-browserify": "1.1.x",
"exit": "0.1.x",
"htmlparser2": "3.8.x",
"lodash": "3.7.x",
"minimatch": "2.0.x",
"shelljs": "0.3.x",
"strip-json-comments": "1.0.x"
},
"dependencies": {
"lodash": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz",
"integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=",
"dev": true
},
"minimatch": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz",
"integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=",
"dev": true,
"requires": {
"brace-expansion": "^1.0.0"
}
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=",
"dev": true
}
}
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true
},
"json-stable-stringify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
"dev": true,
"requires": {
"jsonify": "~0.0.0"
}
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
"dev": true
},
"jsonfile": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
},
"dependencies": {
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true,
"optional": true
}
}
},
"jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
"dev": true
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
}
}
},
"kew": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz",
"integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=",
"dev": true
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"requires": {
"is-buffer": "^1.1.5"
}
},
"klaw": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
"integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.9"
},
"dependencies": {
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true,
"optional": true
}
}
},
"lazy-cache": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
"dev": true
},
"less": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz",
"integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==",
"dev": true,
"requires": {
"errno": "^0.1.1",
"graceful-fs": "^4.1.2",
"image-size": "~0.5.0",
"mime": "^1.2.11",
"mkdirp": "^0.5.0",
"promise": "^7.1.1",
"request": "2.81.0",
"source-map": "^0.5.3"
},
"dependencies": {
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true,
"optional": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true,
"optional": true
}
}
},
"load-json-file": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"parse-json": "^2.2.0",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0",
"strip-bom": "^2.0.0"
},
"dependencies": {
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
}
}
},
"lodash": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz",
"integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=",
"dev": true
},
"longest": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
"dev": true
},
"loud-rejection": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
"integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
"dev": true,
"requires": {
"currently-unhandled": "^0.4.1",
"signal-exit": "^3.0.0"
}
},
"lru-cache": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
"dev": true
},
"map-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
"integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
"dev": true
},
"maxmin": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/maxmin/-/maxmin-1.1.0.tgz",
"integrity": "sha1-cTZehKmd2Piz99X94vANHn9zvmE=",
"dev": true,
"requires": {
"chalk": "^1.0.0",
"figures": "^1.0.1",
"gzip-size": "^1.0.0",
"pretty-bytes": "^1.0.0"
}
},
"meow": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
"integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
"dev": true,
"requires": {
"camelcase-keys": "^2.0.0",
"decamelize": "^1.1.2",
"loud-rejection": "^1.0.0",
"map-obj": "^1.0.1",
"minimist": "^1.1.3",
"normalize-package-data": "^2.3.4",
"object-assign": "^4.0.1",
"read-pkg-up": "^1.0.1",
"redent": "^1.0.0",
"trim-newlines": "^1.0.0"
}
},
"mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"dev": true,
"optional": true
},
"mime-db": {
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==",
"dev": true
},
"mime-types": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
"dev": true,
"requires": {
"mime-db": "~1.33.0"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
},
"dependencies": {
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
}
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
"nopt": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
"dev": true,
"requires": {
"abbrev": "1"
}
},
"noptify": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/noptify/-/noptify-0.0.3.tgz",
"integrity": "sha1-WPZUpz2XU98MUdlobckhBKZ/S7s=",
"dev": true,
"requires": {
"nopt": "~2.0.0"
},
"dependencies": {
"nopt": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-2.0.0.tgz",
"integrity": "sha1-ynQW8gpeP5w7hhgPlilfo9C1Lg0=",
"dev": true,
"requires": {
"abbrev": "1"
}
}
}
},
"normalize-package-data": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
"dev": true,
"requires": {
"hosted-git-info": "^2.1.4",
"is-builtin-module": "^1.0.0",
"semver": "2 || 3 || 4 || 5",
"validate-npm-package-license": "^3.0.1"
}
},
"num2fraction": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
"integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
"dev": true
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true
},
"oauth-sign": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
"dev": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"package": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package/-/package-1.0.1.tgz",
"integrity": "sha1-0lofmeJQbcsn1nBLg9yooxLk7cw=",
"dev": true
},
"pako": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
"integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
"dev": true
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
"dev": true,
"requires": {
"error-ex": "^1.2.0"
}
},
"path-exists": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
"dev": true,
"requires": {
"pinkie-promise": "^2.0.0"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-type": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
},
"dependencies": {
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
}
}
},
"pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
"integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
"dev": true
},
"performance-now": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
"integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=",
"dev": true
},
"phantomjs-prebuilt": {
"version": "2.1.16",
"resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz",
"integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=",
"dev": true,
"requires": {
"es6-promise": "^4.0.3",
"extract-zip": "^1.6.5",
"fs-extra": "^1.0.0",
"hasha": "^2.2.0",
"kew": "^0.7.0",
"progress": "^1.1.8",
"request": "^2.81.0",
"request-progress": "^2.0.1",
"which": "^1.2.10"
},
"dependencies": {
"es6-promise": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz",
"integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==",
"dev": true
},
"which": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
"integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
}
}
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
"dev": true
},
"pinkie-promise": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"dev": true,
"requires": {
"pinkie": "^2.0.0"
}
},
"postcss": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-4.1.16.tgz",
"integrity": "sha1-TESbTIr53zyvbTf44eV10DYXWNw=",
"dev": true,
"requires": {
"es6-promise": "~2.3.0",
"js-base64": "~2.1.8",
"source-map": "~0.4.2"
}
},
"pretty-bytes": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz",
"integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=",
"dev": true,
"requires": {
"get-stdin": "^4.0.1",
"meow": "^3.1.0"
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true
},
"progress": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
"integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
"dev": true
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"dev": true,
"optional": true,
"requires": {
"asap": "~2.0.3"
}
},
"prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
"dev": true,
"optional": true
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
"dev": true
},
"qs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
"integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=",
"dev": true
},
"qunitjs": {
"version": "1.23.1",
"resolved": "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz",
"integrity": "sha1-GXHPl6yb4Bpk0jFVCNLkjm/U5xk=",
"dev": true
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
"dev": true,
"requires": {
"load-json-file": "^1.0.0",
"normalize-package-data": "^2.3.2",
"path-type": "^1.0.0"
}
},
"read-pkg-up": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
"dev": true,
"requires": {
"find-up": "^1.0.0",
"read-pkg": "^1.0.0"
}
},
"readable-stream": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz",
"integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.0.3",
"util-deprecate": "~1.0.1"
}
},
"redent": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
"integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
"dev": true,
"requires": {
"indent-string": "^2.1.0",
"strip-indent": "^1.0.1"
}
},
"repeat-string": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
"dev": true
},
"repeating": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
"integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
"dev": true,
"requires": {
"is-finite": "^1.0.0"
}
},
"request": {
"version": "2.81.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
"integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
"dev": true,
"requires": {
"aws-sign2": "~0.6.0",
"aws4": "^1.2.1",
"caseless": "~0.12.0",
"combined-stream": "~1.0.5",
"extend": "~3.0.0",
"forever-agent": "~0.6.1",
"form-data": "~2.1.1",
"har-validator": "~4.2.1",
"hawk": "~3.1.3",
"http-signature": "~1.1.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.7",
"oauth-sign": "~0.8.1",
"performance-now": "^0.2.0",
"qs": "~6.4.0",
"safe-buffer": "^5.0.1",
"stringstream": "~0.0.4",
"tough-cookie": "~2.3.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.0.0"
}
},
"request-progress": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz",
"integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=",
"dev": true,
"requires": {
"throttleit": "^1.0.0"
}
},
"right-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
"dev": true,
"requires": {
"align-text": "^0.1.1"
}
},
"rimraf": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
"integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
"dev": true
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"dev": true
},
"semver": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
"integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
"dev": true
},
"shelljs": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.4.0.tgz",
"integrity": "sha1-GZ/p4t43nv0D00X/FAYlJeSzHsI=",
"dev": true
},
"sigmund": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
"dev": true
},
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
"sntp": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
"dev": true,
"requires": {
"hoek": "2.x.x"
}
},
"source-map": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
"integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
"dev": true,
"requires": {
"amdefine": ">=0.0.4"
}
},
"spdx-correct": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
"integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
"dev": true,
"requires": {
"spdx-license-ids": "^1.0.2"
}
},
"spdx-expression-parse": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz",
"integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=",
"dev": true
},
"spdx-license-ids": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",
"integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=",
"dev": true
},
"sshpk": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
"dev": true,
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"tweetnacl": "~0.14.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
}
}
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
},
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
"dev": true
},
"strip-ansi": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz",
"integrity": "sha1-32LBqpTtLxFOHQ8h/R1QSCt5pg4=",
"dev": true,
"requires": {
"ansi-regex": "^1.0.0"
}
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
"dev": true,
"requires": {
"is-utf8": "^0.2.0"
}
},
"strip-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
"integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
"dev": true,
"requires": {
"get-stdin": "^4.0.1"
}
},
"strip-json-comments": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
"integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=",
"dev": true
},
"supports-color": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz",
"integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0=",
"dev": true
},
"tape": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/tape/-/tape-0.2.2.tgz",
"integrity": "sha1-ZMz6S37PSgBgAH5hcW1CR4FnFjc=",
"dev": true,
"requires": {
"deep-equal": "~0.0.0",
"defined": "~0.0.0",
"jsonify": "~0.0.0"
}
},
"temporary": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/temporary/-/temporary-0.0.8.tgz",
"integrity": "sha1-oYqYHSi6jKNgJ/s8MFOMPst0CsA=",
"dev": true,
"requires": {
"package": ">= 1.0.0 < 1.2.0"
}
},
"throttleit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
"integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=",
"dev": true
},
"tiny-lr-fork": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/tiny-lr-fork/-/tiny-lr-fork-0.0.5.tgz",
"integrity": "sha1-Hpnh4qhGm3NquX2X7vqYxx927Qo=",
"dev": true,
"requires": {
"debug": "~0.7.0",
"faye-websocket": "~0.4.3",
"noptify": "~0.0.3",
"qs": "~0.5.2"
},
"dependencies": {
"debug": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz",
"integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=",
"dev": true
},
"qs": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/qs/-/qs-0.5.6.tgz",
"integrity": "sha1-MbGtBYVnZRxSaSFQa5qHk5EaA4Q=",
"dev": true
}
}
},
"tough-cookie": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
"dev": true,
"requires": {
"punycode": "^1.4.1"
}
},
"trim-newlines": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
"integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
"dev": true
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"dev": true,
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"dev": true,
"optional": true
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"uglify-js": {
"version": "2.8.29",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
"integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
"dev": true,
"requires": {
"source-map": "~0.5.1",
"uglify-to-browserify": "~1.0.0",
"yargs": "~3.10.0"
},
"dependencies": {
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"uglify-to-browserify": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
"dev": true,
"optional": true
},
"underscore": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",
"integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=",
"dev": true
},
"underscore.string": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz",
"integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=",
"dev": true
},
"uri-path": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/uri-path/-/uri-path-0.0.2.tgz",
"integrity": "sha1-gD6wHy/rF5J9zOD2GH5yt19T9VQ=",
"dev": true
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true
},
"uuid": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz",
"integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==",
"dev": true
},
"validate-npm-package-license": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
"integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
"dev": true,
"requires": {
"spdx-correct": "~1.0.0",
"spdx-expression-parse": "~1.0.0"
}
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"dev": true,
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
},
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"dev": true
}
}
},
"which": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz",
"integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=",
"dev": true
},
"window-size": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
"dev": true
},
"wordwrap": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
"dev": true
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"yargs": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
"dev": true,
"requires": {
"camelcase": "^1.0.2",
"cliui": "^2.1.0",
"decamelize": "^1.0.0",
"window-size": "0.1.0"
},
"dependencies": {
"camelcase": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
"integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
"dev": true
}
}
},
"yauzl": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
"integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
"dev": true,
"requires": {
"fd-slicer": "~1.0.1"
}
},
"zlib-browserify": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/zlib-browserify/-/zlib-browserify-0.0.3.tgz",
"integrity": "sha1-JAzNv9AgP6hCsTDe77FBQSLIzFA=",
"dev": true,
"requires": {
"tape": "~0.2.2"
}
}
}
}
{
"name": "pickadate",
"version": "3.6.4",
"title": "pickadate.js",
"description": "The mobile-friendly, responsive, and lightweight jQuery date & time input picker.",
"keywords": [
"date",
"time",
"picker",
"input",
"responsive"
],
"homepage": "http://amsul.ca/pickadate.js",
"bugs": "https://github.com/amsul/pickadate.js/issues",
"license": "MIT",
"author": {
"name": "Amsul",
"email": "reach@amsul.ca",
"url": "http://amsul.ca"
},
"files": [
"lib",
"tests",
"README.md",
"Gruntfile.js"
],
"repository": {
"type": "git",
"url": "https://github.com/amsul/pickadate.js.git"
},
"scripts": {
"prebump": "npm test",
"bump": "node ./version-bump.js",
"postbump": "npx grunt package && node ./version-commit.js",
"push": "git push && git push origin --tags && npm publish",
"test": "npx grunt test --verbose"
},
"dependencies": {
"jquery": ">=1.7"
},
"devDependencies": {
"commander": "^2.8.0",
"glob": "^5.0.5",
"grunt": "^0.4.5",
"grunt-autoprefixer": "^3.0.0",
"grunt-contrib-copy": "^0.8.0",
"grunt-contrib-cssmin": "^0.12.2",
"grunt-contrib-jshint": "^0.11.2",
"grunt-contrib-less": "^1.0.1",
"grunt-contrib-qunit": "^2.0.0",
"grunt-contrib-uglify": "^0.9.1",
"grunt-contrib-watch": "^0.6.1",
"qunitjs": "1.x",
"semver": "^4.3.3",
"shelljs": "^0.4.0",
"zlib-browserify": "0.0.3"
}
}
\ No newline at end of file
<!doctype html>
<html>
<meta charset="utf-8">
<meta name="author" content="Amsul - http://amsul.ca">
<meta name="viewport" content="width=device-width,user-scalable=no">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>Pickadate.js</title>
<link rel="stylesheet" href="../../lib/themes/default.css">
<link rel="stylesheet" href="../../lib/themes/default.date.css">
<!--[if lt IE 9]>
<script>document.createElement('section')</script>
<style type="text/css">
.holder {
position: relative;
z-index: 10000;
}
.datepicker {
display: block;
}
</style>
<![endif]-->
<body>
<section class="section">
<form>
<fieldset>
<h3><label for="input_01">Pick a date. Go ahead...</label></h3>
<input
id="input_01"
class="datepicker"
name="date"
type="text"
autofocus
value="14 August, 2014"
data-value="2014-08-08">
<br><br><br><br><br>
<!-- <button type="button">Disable all dates</button>
<input class="button" type="submit" value="open"> -->
</fieldset>
</form>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<div id="container"></div>
</section>
<script src="../../node_modules/jquery/dist/jquery.js"></script>
<script src="../../lib/picker.js"></script>
<script src="../../lib/picker.date.js"></script>
<script src="../../lib/legacy.js"></script>
<script type="text/javascript">
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth()+1; //January is 0!
var yyyy = today.getFullYear();
if(dd<10) {
dd='0'+dd;
}
if(mm<10) {
mm='0'+mm;
}
today = dd+'/'+mm+'/'+yyyy;
var $input = $( '.datepicker' ).pickadate({
formatSubmit: 'yyyy/mm/dd',
// min: [2015, 7, 14],
container: '#container',
// editable: true,
closeOnSelect: false,
closeOnClear: false,
})
var picker = $input.pickadate('picker')
// picker.set('select', '14 October, 2014')
// picker.open()
// $('button').on('click', function() {
// picker.set('disable', true);
// });
</script>
</body>
</html>
<!doctype html>
<html>
<meta charset="utf-8">
<meta name="author" content="Amsul - http://amsul.ca">
<meta name="viewport" content="width=device-width">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>Pickadate.js</title>
<link rel="stylesheet" href="../../lib/themes/default.css">
<link rel="stylesheet" href="../../lib/themes/default.time.css">
<!--[if lt IE 9]>
<script>document.createElement('section')</script>
<style type="text/css">
.holder {
position: relative;
z-index: 10000;
}
.datepicker {
display: block;
}
</style>
<![endif]-->
<body>
<section class="section">
<form>
<fieldset>
<h3><label for="input_01">Pick a time. Go ahead...</label></h3>
<input
id="input_from"
class="datepicker"
type="time"
name="time"
autofocus>
<!-- valuee="2:30 AM"
data-value="0:00" -->
</fieldset>
</form>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
</section>
<script src="../../node_modules/jquery/dist/jquery.js"></script>
<script src="../../lib/picker.js"></script>
<script src="../../lib/picker.time.js"></script>
<script src="../../lib/legacy.js"></script>
<script type="text/javascript">
var $input = $( '.datepicker' ).pickatime({
})
var picker = $input.pickatime('picker')
picker.open()
</script>
</body>
</html>
<!doctype html>
<meta charset="utf-8">
<title>pickadate.js &#8226; QUnit testing</title>
<link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css">
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="../../node_modules/jquery/dist/jquery.js"></script>
<script src="../../lib/picker.js"></script>
<script src="../../lib/picker.date.js"></script>
<script src="../../lib/picker.time.js"></script>
<script src="../../node_modules/qunitjs/qunit/qunit.js"></script>
<script src="base.js"></script>
<script src="date.js"></script>
<script src="time.js"></script>
</body>
\ No newline at end of file
/*jshint
debug: true,
devel: true,
browser: true,
asi: true,
unused: true,
eqnull: true,
eqeqeq: true
*/
var $DOM = $( '#qunit-fixture' ),
$INPUT = $( '<input type=password>' ),
isInteger = function( value ) {
return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0
}
/* ==========================================================================
Base picker tests
========================================================================== */
module( 'Base setup', {
setup: function() {
$DOM.append( $INPUT.clone() )
this.$input = $DOM.find( 'input' ).pickadate()
this.picker = this.$input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Input stage and attributes', function() {
var input = this.picker.$node[ 0 ]
ok( input.type === 'text', 'Type updated' )
ok( input.readOnly === true, 'Readonly set' )
ok( input.value === '', 'No value' )
ok( this.picker.$root.length, 'Root holder exists' )
ok( !this.picker._hidden, 'Hidden input doesn’t exist' )
})
test( 'Picker states', function() {
var picker = this.picker
ok( picker.get( 'start' ) === true, 'Started' )
ok( picker.get( 'open' ) === false, 'Closed to start with' )
picker.open()
ok( picker.get( 'open' ) === true, 'Opened with trigger' )
picker.$root.find( 'button' )[0].focus()
ok( picker.get( 'open' ) === true, 'Remains open with focus within' )
picker.$root.find( 'div' ).eq(3).click()
ok( picker.get( 'open' ) === true, 'Remains open with click within' )
picker.close()
ok( picker.get( 'open' ) === false, 'Closed with trigger' )
picker.stop()
ok( picker.get( 'start' ) === false, 'Stopped with trigger' )
picker.start()
ok( picker.get( 'start' ) === true, 'Started with trigger' )
})
test( 'Picker properties', function() {
var picker = this.picker
strictEqual( picker.get( 'type' ), 'password', 'Original type is saved' )
notStrictEqual( picker.get( 'min' ).pick, null, 'Has “min”' )
notStrictEqual( picker.get( 'max' ).pick, null, 'Has “max”' )
strictEqual( picker.get( 'select' ), null, 'Has no “select”' )
ok( isInteger( picker.get( 'highlight' ).pick ), 'Has “highlight”' )
ok( isInteger( picker.get( 'view' ).pick ), 'Has “view”' )
ok( isInteger( picker.get( 'now' ).pick ), 'Has “now”' )
deepEqual( picker.get( 'disable' ), [], 'Default “disable” collection is empty' )
})
test( 'Picker alternate API', function() {
var $input = this.$input
var picker = this.picker
strictEqual( $input.pickadate( 'get', 'start' ), picker.get( 'start' ), 'Methods are passed forward' )
strictEqual( $input.pickadate( 'component' ), picker.component, 'Objects are passed forward' )
})
module( 'Formatting setup', {
setup: function() {
$DOM.append( $INPUT.clone().attr( 'name', 'picker' ) )
var $input = $DOM.find( 'input' ).pickadate({
formatSubmit: 'yyyy/mm/dd'
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Default hidden prefix & suffix', function() {
var picker = this.picker
strictEqual( picker.$node[0].name + '_submit', picker._hidden.name, 'Correct hidden element `name`' )
})
module( 'Formatting setup', {
setup: function() {
$DOM.append( $INPUT.clone().attr( 'name', 'picker' ) )
var $input = $DOM.find( 'input' ).pickadate({
formatSubmit: 'yyyy/mm/dd',
hiddenPrefix: 'prefixed__',
hiddenSuffix: '__suffixed'
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Custom hidden prefix & suffix', function() {
var picker = this.picker
strictEqual( 'prefixed__' + picker.$node[0].name + '__suffixed', picker._hidden.name, 'Correct hidden element `name`' )
})
module( 'Formatting setup', {
setup: function() {
$DOM.append( $INPUT.clone().attr( 'name', 'picker' ) )
var $input = $DOM.find( 'input' ).pickadate({
formatSubmit: 'yyyy/mm/dd',
hiddenPrefix: '',
hiddenSuffix: ''
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'No hidden prefix & suffix', function() {
var picker = this.picker
strictEqual( picker.$node[0].name, picker._hidden.name, 'Correct hidden element `name`' )
})
module( 'Formatting setup', {
setup: function() {
$DOM.append( $INPUT.clone().attr( 'name', 'picker' ) )
var $input = $DOM.find( 'input' ).pickadate({
formatSubmit: 'yyyy/mm/dd',
hiddenName: true
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Hidden name replaces visible name', function() {
var picker = this.picker
strictEqual( picker.$node[0].name, '', 'Visible element has no `name`')
strictEqual(picker._hidden.name, 'picker', 'Correct hidden element `name`' )
})
module( 'Container setup', {
setup: function() {
$DOM.append( $INPUT.clone().attr( 'name', 'picker' ), $( '<div id="outlet"/>' ) )
var $input = $DOM.find( 'input' ).pickadate({
formatSubmit: 'yyyy/mm/dd',
container: '#outlet'
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Picker root outlet', function() {
var picker = this.picker
strictEqual( picker.$root[0].parentNode.id, 'outlet', 'Correct root outlet' )
})
module( 'Base events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var thisModule = this,
$input = $DOM.find( 'input' ).pickadate({
onStart: function() {
thisModule.started = true
thisModule.restarted = true
thisModule.inputType = this.$node[ 0 ].type
},
onRender: function() {
thisModule.rendered = true
},
onOpen: function() {
thisModule.opened = true
},
onClose: function() {
thisModule.closed = true
},
onStop: function() {
thisModule.stopped = true
thisModule.inputType = this.$node[ 0 ].type
},
onSet: function( thing ) {
thisModule.selected = thing
}
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'As options', function() {
var thisModule = this,
picker = thisModule.picker
strictEqual( thisModule.started, picker.get( 'start' ) === true, 'Fired: `onStart`' )
strictEqual( thisModule.inputType, 'text', 'Updated input type' )
strictEqual( thisModule.rendered, picker.get( 'start' ) === true, 'Fired: `onRender`' )
picker.open()
strictEqual( thisModule.opened, picker.get( 'open' ) === true, 'Fired: `onOpen`' )
picker.close()
strictEqual( thisModule.closed, picker.get( 'open' ) === false, 'Fired: `onClose`' )
picker.stop()
strictEqual( thisModule.stopped, picker.get( 'start' ) === false, 'Fired: `onStop`' )
strictEqual( thisModule.inputType, $INPUT[ 0 ].type, 'Restored input type' )
picker.start()
strictEqual( thisModule.restarted, picker.get( 'start' ) === true, 'Restarted: `onStart`' )
picker.set()
deepEqual( thisModule.selected, {}, 'Fired: `onSet`' )
})
test( 'As individual methods', 6, function() {
var picker = this.picker
// Register the events
picker.
on( 'open', function() {
ok( true, 'Opened' )
}).
on( 'close', function() {
ok( true, 'Closed' )
}).
on( 'render', function() {
ok( true, 'Rendered' )
}).
on( 'set', function() {
ok( true, 'Set' )
}).
on( 'stop', function() {
ok( true, 'Stopped' )
}).
on( 'start', function() {
ok( true, 'Started' )
})
picker.
trigger( 'start' ).
trigger( 'open' ).
trigger( 'render' ).
trigger( 'set' ).
trigger( 'close' )
})
test( 'As multiple methods', 6, function() {
var picker = this.picker
// Register the events
picker.on({
open: function() {
ok( true, 'Opened' )
},
close: function() {
ok( true, 'Closed' )
},
render: function() {
ok( true, 'Rendered' )
},
set: function() {
ok( true, 'Set' )
},
stop: function() {
ok( true, 'Stopped' )
},
start: function() {
ok( true, 'Started' )
}
})
picker.
trigger( 'start' ).
trigger( 'open' ).
trigger( 'render' ).
trigger( 'set' ).
trigger( 'close' )
})
test( 'As muted methods', 1, function() {
var picker = this.picker
// Bind the callback.
picker.on('set', function() {
ok( true, 'An outspoken method' )
})
// Do the selections.
picker.set('select', new Date())
picker.set('select', new Date(), { muted: true })
picker.set({ select: new Date() }, { muted: true })
})
test( 'Clear as muted', function() {
var picker = this.picker
var called = false
// Bind the callback.
picker.on('set', function() {
called = true
})
picker.clear({ muted: true })
ok( !called, 'Callback not called' )
})
test( 'Open with alternate focus', function() {
var picker = this.picker,
klasses = Picker.klasses()
stop()
picker.open( false )
setTimeout( function() {
ok( !picker.get( 'open' ) && picker.$node[0].className === klasses.input + ' ' + klasses.active && picker.$root[0].className === klasses.picker + ' ' + klasses.opened && document.activeElement !== picker.$node[0], 'Opened without focus' )
start()
}, 0 )
})
test( 'Close with alternate focus', function() {
var picker = this.picker
stop()
picker.close( true )
setTimeout( function() {
var isClosed = !picker.get( 'open' )
var hasCorrectActiveElement = document.activeElement === picker.$holder[0]
ok( isClosed && hasCorrectActiveElement, 'Closed with focus' )
start()
}, 0 )
})
test( 'Switch off', function() {
var truthy = true,
picker = this.picker
picker.on('open', function() {
truthy = false
})
picker.off('open')
strictEqual( truthy, true, 'Method turned off' )
})
module( 'Base mouse events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate()
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Open and close', function() {
var picker = this.picker
picker.$node.click()
ok( picker.get( 'open' ) === true, 'Opened with click in' )
$( 'body' ).click()
ok( picker.get( 'open' ) === false, 'Closed with click out' )
})
test( 'Open and close', function() {
var picker = this.picker
picker.$node.click()
strictEqual( picker.get( 'open' ), true, 'Opened with click in' )
picker.$root.find( '.' + $.fn.pickadate.defaults.klass.buttonClose ).click();
strictEqual( picker.get( 'open' ), false, 'Closed by clicking “close”' )
})
asyncTest( 'Open with a slower click', function() {
// This test ensures that behaviour in chrome as described in PR 1145
// https://github.com/amsul/pickadate.js/pull/1145
// is handled correctly
var picker = this.picker
// The sequence of events fired by chrome are:
// - focus on the input
// - mousedown on the input
// - mouseup on the input
// - click on the common ancestor (in this case $DOM)
picker.$node.focus()
setTimeout(function () {
ok(picker.get('open') === true, 'Opened due to focus change')
picker.$node.trigger({
type: 'mousedown'
})
setTimeout(function () {
ok(picker.get('open') === true, 'Still open after mousedown')
// The mouseup and the click happen one after the other with no pause
picker.$node.trigger({
type: 'mouseup'
})
$DOM.trigger({
type: 'click'
})
setTimeout(function () {
ok(picker.get('open') === true, 'Still open after final click event')
QUnit.start();
}, 200)
}, 200)
}, 200)
})
module( 'Base keyboard events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate()
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Open and close', function() {
var picker = this.picker
picker.$node.focus()
ok(picker.get('open') === true, 'Opened with key in')
picker.$node.blur()
$DOM.focusin()
ok(picker.get('open') === false, 'Closed with key out')
picker.$node.trigger({
type: 'keydown',
keyCode: 40
})
ok(picker.get('open') === true, 'Opened after arrow “down”')
picker.$node.trigger({
type: 'keydown',
keyCode: 27
})
ok(picker.get('open') === false, 'Closed after “escape”')
picker.$node.trigger({
type: 'keydown',
keyCode: 38
})
ok(picker.get('open') === true, 'Opened after arrow “up”')
picker.$node.trigger({
type: 'keydown',
keyCode: 8
})
ok(picker.get('open') === false, 'Closed after “backspace”')
picker.$node.trigger({
type: 'keydown',
keyCode: 37
})
ok(picker.get('open') === true, 'Opened after arrow “left”')
picker.$node.trigger({
type: 'keydown',
keyCode: 46
})
ok(picker.get('open') === false, 'Closed after “alt. backspace”')
picker.$node.trigger({
type: 'keydown',
keyCode: 39
})
ok(picker.get('open') === true, 'Opened after arrow “right”')
})
test( 'Set and clear', function() {
var picker = this.picker
picker.open()
picker.$node.trigger({ type: 'keydown', keyCode: 13 })
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickadate.defaults.format ), 'Set value as default selection after “enter”' )
picker.$node.trigger({ type: 'keydown', keyCode: 8 })
strictEqual( picker.get( 'value' ), '', 'Clear input value after “backspace”' )
})
/*jshint
debug: true,
devel: true,
browser: true,
asi: true,
unused: true,
eqnull: true,
eqeqeq: true
*/
var $DOM = $( '#qunit-fixture' ),
$INPUT = $( '<input type=password>' )
/* ==========================================================================
Date picker tests
========================================================================== */
module( 'Date picker setup', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate()
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Calendar stage', function() {
strictEqual( this.picker.$root.find( '.' + $.fn.pickadate.defaults.klass.table + ' [data-pick]' ).length, 42, '42 selectables dates' )
})
test( 'Properties', function() {
var picker = this.picker,
today = new Date()
today.setHours( 0, 0, 0, 0 )
strictEqual( picker.get( 'min' ).pick, -Infinity, 'Default “min” is -Infinity' )
strictEqual( picker.get( 'max' ).pick, Infinity, 'Default “max’ is +Infinity' )
strictEqual( picker.get( 'now' ).pick, today.getTime(), 'Default “now” is ' + picker.get( 'now', 'yyyy/mm/dd' ) )
deepEqual( picker.get( 'select' ), null, 'Default “select” is `null`' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), 'Default “highlight” is “now”' )
strictEqual( picker.get( 'view' ).pick, today.setDate( 1 ), 'Default “view” is ' + picker.get( 'view', 'yyyy/mm/dd' ) )
})
test( 'First weekday', function() {
var picker = this.picker,
$input = picker.$node
strictEqual( picker.$root.find( '.' + $.fn.pickadate.defaults.klass.weekdays ).first().text(), $.fn.pickadate.defaults.weekdaysShort[0], 'Sunday is first day' )
picker.stop().$node.pickadate({ firstDay: 1 })
strictEqual( $input.pickadate( 'picker' ).$root.find( '.' + $.fn.pickadate.defaults.klass.weekdays ).first().text(), $.fn.pickadate.defaults.weekdaysShort[1], 'Monday is first day' )
picker.set( 'select', [ 2013, 8, 14 ] )
strictEqual( picker.$root.find( 'td' ).first().text(), '1', 'Months starting on Sunday shift back a week' )
})
test( 'Formats', function() {
var picker = this.picker,
today = new Date(),
leadZero = function( number ) {
return ( number < 10 ? '0' : '' ) + number
},
formats = {
d: function() {
return '' + today.getDate()
},
dd: function() {
return leadZero( today.getDate() )
},
ddd: function() {
return $.fn.pickadate.defaults.weekdaysShort[ today.getDay() ]
},
dddd: function() {
return $.fn.pickadate.defaults.weekdaysFull[ today.getDay() ]
},
m: function() {
return '' + ( today.getMonth() + 1 )
},
mm: function() {
return leadZero( ( today.getMonth() + 1 ) )
},
mmm: function() {
return $.fn.pickadate.defaults.monthsShort[ today.getMonth() ]
},
mmmm: function() {
return $.fn.pickadate.defaults.monthsFull[ today.getMonth() ]
},
yy: function() {
return ( '' + today.getFullYear() ).slice(2)
},
yyyy: function() {
return '' + today.getFullYear()
}
}
today.setHours(0,0,0,0)
;([ 'd', 'dd', 'ddd', 'dddd', 'm', 'mm', 'mmm', 'mmmm', 'yy', 'yyyy' ]).forEach( function( format ) {
var expect = formats[ format ]()
deepEqual( picker.get( 'now', format ), expect, '`' + format + '`: ' + expect )
})
})
module( 'Date picker setup', {
teardown: function() {
$DOM.empty()
}
})
test( 'Editable', function() {
$DOM.append( $INPUT.clone() ).append( $INPUT.clone() )
var $input1 = $DOM.find( 'input' ).eq(0).pickadate()
var $input2 = $DOM.find( 'input' ).eq(1).pickadate({
editable: true
})
strictEqual( $input1[0].readOnly, true, 'Editable: false' )
strictEqual( $input2[0].readOnly, false, 'Editable: true' )
})
test( 'Disable today with `min` as `true`', function() {
$DOM.append( $INPUT.clone() )
var today = new Date()
var $input = $DOM.find( 'input' ).pickadate({
min: true,
disable: [ today ]
})
var picker = $input.pickadate('picker')
var highlighted = picker.get('highlight')
var playdate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 1)
deepEqual(
[playdate.getFullYear(), playdate.getMonth(), playdate.getDate()],
[highlighted.year, highlighted.month, highlighted.date],
'Able to disable today'
)
})
test( 'Disable today with `max` as `true`', function() {
$DOM.append( $INPUT.clone() )
var today = new Date()
var $input = $DOM.find( 'input' ).pickadate({
max: true,
disable: [ today ]
})
var picker = $input.pickadate('picker')
var highlighted = picker.get('highlight')
var playdate = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 1)
deepEqual(
[playdate.getFullYear(), playdate.getMonth(), playdate.getDate()],
[highlighted.year, highlighted.month, highlighted.date],
'Able to disable today'
)
})
module( 'Date picker `set`', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate()
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`clear`', function() {
var picker = this.picker
strictEqual( picker.get('select'), null, 'Starts off without a selection' )
picker.set('select', new Date())
notStrictEqual( picker.get('select'), null, 'A selection has been added' )
picker.clear()
strictEqual( picker.get('select'), null, 'Clears out selection' )
})
test( '`select`', function() {
var picker = this.picker,
today = new Date(),
playdate = new Date( today.getFullYear(), today.getMonth(), today.getDate() + 40 )
today.setHours(0,0,0,0)
// Using numbers
picker.set( 'select', playdate.getTime() )
deepEqual( picker.get( 'select' ).obj, playdate, '`select` using a number: ' + playdate )
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickadate.defaults.format ), '`value` matches' )
deepEqual( picker.get( 'highlight' ), picker.get( 'select' ), '`highlight` updated' )
strictEqual( picker.get( 'view', 'yyyy/mm/dd' ), picker.get( 'highlight', 'yyyy/mm/01' ), '`view` updated' )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using arrays
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'select', [playdate.getFullYear(),playdate.getMonth(),playdate.getDate()] )
deepEqual( picker.get( 'select' ).obj, playdate, '`select` using an array: ' + playdate )
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickadate.defaults.format ), '`value` matches' )
deepEqual( picker.get( 'highlight' ), picker.get( 'select' ), '`highlight` updated' )
strictEqual( picker.get( 'view', 'yyyy/mm/dd' ), picker.get( 'highlight', 'yyyy/mm/01' ), '`view` updated' )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using JavaScript date objects
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'select', playdate )
deepEqual( picker.get( 'select' ).obj, playdate, '`select` using a JS date object: ' + playdate )
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickadate.defaults.format ), '`value` matches' )
deepEqual( picker.get( 'highlight' ), picker.get( 'select' ), '`highlight` updated' )
strictEqual( picker.get( 'view', 'yyyy/mm/dd' ), picker.get( 'highlight', 'yyyy/mm/01' ), '`view` updated' )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
})
test( '`highlight`', function() {
var picker = this.picker,
today = new Date(),
playdate = new Date( today.getFullYear(), today.getMonth(), today.getDate() + 40 )
today.setHours(0,0,0,0)
// Using numbers
picker.set( 'highlight', playdate.getTime() )
deepEqual( picker.get( 'highlight' ).obj, playdate, '`highlight` using a number: ' + playdate )
strictEqual( picker.get( 'view', 'yyyy/mm/dd' ), picker.get( 'highlight', 'yyyy/mm/01' ), '`view` updated: ' + picker.get( 'view', 'yyyy/mm/dd' ) )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using arrays
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'highlight', [playdate.getFullYear(),playdate.getMonth(),playdate.getDate()] )
deepEqual( picker.get( 'highlight' ).obj, playdate, '`highlight` using an array: ' + playdate )
strictEqual( picker.get( 'view', 'yyyy/mm/dd' ), picker.get( 'highlight', 'yyyy/mm/01' ), '`view` updated: ' + picker.get( 'view', 'yyyy/mm/dd' ) )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using JavaScript date objects
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'highlight', playdate )
deepEqual( picker.get( 'highlight' ).obj, playdate, '`highlight` using a JS date object: ' + playdate )
strictEqual( picker.get( 'view', 'yyyy/mm/dd' ), picker.get( 'highlight', 'yyyy/mm/01' ), '`view` updated: ' + picker.get( 'view', 'yyyy/mm/dd' ) )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
})
test( '`view`', function() {
var picker = this.picker,
today = new Date(),
playdate = new Date( today.getFullYear(), today.getMonth(), today.getDate() + 40 )
today.setHours(0,0,0,0)
// Using numbers
picker.set( 'view', playdate.getTime() )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` using a number: ' + playdate )
deepEqual( picker.get( 'highlight' ).obj, today, '`highlight` unaffected' )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using arrays
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'view', [playdate.getFullYear(),playdate.getMonth(),playdate.getDate()] )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` using a number: ' + playdate )
deepEqual( picker.get( 'highlight' ).obj, today, '`highlight` unaffected' )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using JavaScript date objects
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'view', playdate )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` using a JS date object: ' + playdate )
deepEqual( picker.get( 'highlight' ).obj, today, '`highlight` unaffected' )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
})
test( '`min`', function() {
var picker = this.picker,
today = new Date(),
playdate = new Date( today.getFullYear(), today.getMonth(), today.getDate() - 40 )
today.setHours(0,0,0,0)
// Using negative numbers
picker.set( 'min', -40 )
deepEqual( picker.get( 'min' ).obj, playdate, '`min` using a negative number: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
playdate.setDate( 1 )
playdate.setMonth( today.getMonth() )
playdate.setFullYear( today.getFullYear() )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using positive numbers
picker.set( 'min', 40 )
playdate.setDate( today.getDate() + 40 )
deepEqual( picker.get( 'min' ).obj, playdate, '`min` using a positive number: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), '`highlight` updated' )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` updated' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using arrays
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'min', [playdate.getFullYear(),playdate.getMonth(),playdate.getDate()] )
deepEqual( picker.get( 'min' ).obj, playdate, '`min` using an array: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), '`highlight` updated' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` updated' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using JavaScript date objects
playdate.setDate( playdate.getDate() + 40 )
picker.set( 'min', playdate )
deepEqual( picker.get( 'min' ).obj, playdate, '`min` using a JS date object: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), '`highlight` updated' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` updated' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
})
test( '`min` using booleans', function() {
var picker = this.picker,
today = new Date(),
playdate = new Date( today.getFullYear(), today.getMonth(), 1 )
today.setHours(0,0,0,0)
// Using `true`
picker.set( 'min', true )
deepEqual( picker.get( 'min' ).obj, today, '`min` using `true`: ' + today )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
// Using `false`
picker.set( 'min', false )
deepEqual( picker.get( 'min' ).obj, -Infinity, '`min` using `false`: ' + -Infinity )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'max' ).pick, Infinity, '`max` unaffected' )
})
test( '`min` using strings', function() {
var picker = this.picker
var min = picker.get('min')
strictEqual( min.pick, -Infinity, 'No `min` date' )
picker.set( 'min', '8 January, 2013' )
min = picker.get('min')
deepEqual( [min.year, min.month, min.date], [2013, 0, 8], '`min` updated' )
})
test( '`max`', function() {
var picker = this.picker,
today = new Date(),
playdate = new Date( today.getFullYear(), today.getMonth(), today.getDate() + 40 )
today.setHours(0,0,0,0)
// Using positive numbers
picker.set( 'max', 40 )
deepEqual( picker.get( 'max' ).obj, playdate, '`max` using a positive number: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
playdate.setYear( today.getFullYear() )
playdate.setMonth( today.getMonth(), 1 )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
// Using negative numbers
picker.set( 'max', -40 )
playdate.setDate( today.getDate() - 40 )
deepEqual( picker.get( 'max' ).obj, playdate, '`max` using a negative number: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), '`highlight` updated' )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
// Using arrays
playdate.setDate( playdate.getDate() - 40 )
picker.set( 'max', [playdate.getFullYear(),playdate.getMonth(),playdate.getDate()] )
deepEqual( picker.get( 'max' ).obj, playdate, '`max` using an array: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), '`highlight` updated' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` updated' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
// Using JavaScript date objects
playdate.setDate( playdate.getDate() - 40 )
picker.set( 'max', playdate )
deepEqual( picker.get( 'max' ).obj, playdate, '`max` using a JS date object: ' + playdate )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), '`highlight` updated' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` updated' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
})
test( '`max` using booleans', function() {
var picker = this.picker,
today = new Date(),
playdate = new Date( today.getFullYear(), today.getMonth(), 1 )
today.setHours(0,0,0,0)
// Using `true`
picker.set( 'max', true )
deepEqual( picker.get( 'max' ).obj, today, '`max` using `true`: ' + today )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
// Using `false`
picker.set( 'max', false )
deepEqual( picker.get( 'max' ).obj, Infinity, '`max` using `false`: ' + Infinity )
deepEqual( picker.get( 'now' ).obj, today, '`now` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ).obj, playdate, '`view` unaffected' )
strictEqual( picker.get( 'value' ), '', '`value` unaffected' )
deepEqual( picker.get( 'min' ).pick, -Infinity, '`min` unaffected' )
})
test( '`max` using strings', function() {
var picker = this.picker
var max = picker.get('max')
strictEqual( max.pick, Infinity, 'No `max` date' )
picker.set( 'max', '8 January, 2013' )
max = picker.get('max')
deepEqual( [max.year, max.month, max.date], [2013, 0, 8], '`max` updated' )
})
test( '`disable` and `enable` using integers', function() {
var today = new Date(),
disableCollection = [1,4,7],
picker = this.picker,
$root = picker.$root
today.setHours(0,0,0,0)
picker.set( 'disable', disableCollection )
if ( disableCollection.indexOf( today.getDay() + 1 ) > -1 ) {
notDeepEqual( picker.get( 'highlight' ), picker.get( 'now' ), 'Shifted disabled `highlight`: ' + picker.get( 'highlight' ).obj )
}
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled dates added to collection' )
$root.find( 'tr' ).each( function( indexRow, tableRow ) {
$( tableRow ).find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( disableCollection.indexOf( indexCell + 1 ) > -1 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Disabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Enabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
})
})
picker.set( 'enable', [1] )
deepEqual( picker.get( 'disable' ), [4,7], 'Disabled date removed from collection' )
$root.find( 'tr' ).each( function( indexRow, tableRow ) {
$( tableRow ).find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( [4,7].indexOf( indexCell + 1 ) > -1 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Disabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Enabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
})
})
picker.set( 'enable', 'flip' )
deepEqual( picker.get( 'disable' ), [4,7], 'Disabled collection `enable` flipped' )
strictEqual( picker.get( 'enable' ), -1, 'Inverted `enable`')
$root.find( 'tr' ).each( function( indexRow, tableRow ) {
$( tableRow ).find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( [4,7].indexOf( indexCell + 1 ) < 0 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Disabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Enabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
})
})
picker.set( 'disable', 'flip' )
deepEqual( picker.get( 'disable' ), [4,7], 'Disabled collection `disable` flipped' )
strictEqual( picker.get( 'enable' ), 1, 'Inverted back `enable`')
$root.find( 'tr' ).each( function( indexRow, tableRow ) {
$( tableRow ).find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( [4,7].indexOf( indexCell + 1 ) > -1 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Disabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Enabled as day of week: ' + ( indexCell + 1 ) + '. Date: ' + tableCell.innerHTML )
}
})
})
})
test( '`disable` and `enable` using arrays', function() {
var today = new Date(),
nowYear = today.getFullYear(),
nowMonth = today.getMonth(),
disableCollection = [ [nowYear,nowMonth,1],[nowYear,nowMonth,25],[nowYear,nowMonth,17] ],
picker = this.picker,
viewday = picker.get( 'view' ).day,
$root = picker.$root
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled dates added to collection' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index === 1 || index === 17 || index === 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', [ [nowYear,nowMonth,17] ] )
disableCollection = [ [nowYear,nowMonth,1],[nowYear,nowMonth,25] ]
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled date removed from collection' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index === 1 || index === 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', 'flip' )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled collection `enable` flipped' )
deepEqual( picker.get( 'enable' ), -1, 'Base state disabled' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index !== 1 && index !== 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'disable', 'flip' )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled collection `disable` flipped' )
deepEqual( picker.get( 'enable' ), 1, 'Base state enabled' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index === 1 || index === 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
})
test( '`disable` and `enable` using JS dates', function() {
var now = new Date(),
nowYear = now.getFullYear(),
nowMonth = now.getMonth(),
disableCollection = [ new Date(nowYear,nowMonth,1), new Date(nowYear,nowMonth,17), new Date(nowYear,nowMonth,25) ],
picker = this.picker,
viewday = picker.get( 'view' ).day,
$root = picker.$root
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled dates added to collection' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index === 1 || index === 17 || index === 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', [ new Date(nowYear,nowMonth,17) ] )
deepEqual( picker.get( 'disable' ), [ new Date(nowYear,nowMonth,1), new Date(nowYear,nowMonth,25) ], 'Disabled date removed from collection' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index === 1 || index === 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', 'flip' )
deepEqual( picker.get( 'disable' ), [ new Date(nowYear,nowMonth,1), new Date(nowYear,nowMonth,25) ], 'Disabled collection `enable` flipped' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index !== 1 && index !== 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'disable', 'flip' )
deepEqual( picker.get( 'disable' ), [ new Date(nowYear,nowMonth,1), new Date(nowYear,nowMonth,25) ], 'Disabled collection `disable` flipped' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday + 1
if ( index === 1 || index === 25 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
})
test( '`disable` and `enable` using booleans', function() {
var now = new Date(),
nowYear = now.getFullYear(),
nowMonth = now.getMonth(),
disableCollection = [ [nowYear,nowMonth,1],[nowYear,nowMonth,17],[nowYear,nowMonth,25] ],
picker = this.picker,
$root = picker.$root
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled dates added to collection' )
picker.set('disable', false)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
strictEqual( $root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 0, 'No dates disabled' )
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled dates added to collection' )
picker.set('disable', true)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
deepEqual( picker.get('enable'), -1, 'Disabled collection `enable` flipped' )
strictEqual( $root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 42, 'All dates disabled' )
picker.set( 'enable', 'flip' )
deepEqual( picker.get('enable'), 1, 'Disabled collection `enable` flipped' )
picker.set( 'disable', disableCollection )
deepEqual( picker.get('disable'), disableCollection, 'Disabled dates added to collection' )
picker.set('enable', true)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
strictEqual( $root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 0, 'No dates disabled' )
picker.set( 'disable', disableCollection )
deepEqual( picker.get('disable'), disableCollection, 'Disabled dates added to collection' )
picker.set('enable', false)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
deepEqual( picker.get('enable'), -1, 'Disabled collection `enable` flipped' )
strictEqual( $root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 42, 'All dates disabled' )
})
test( '`disable` and `enable` using ranges', function() {
var picker = this.picker,
$root = picker.$root,
disableCollection, viewday
picker.set( 'view', [2014,2,1] )
viewday = picker.get( 'view' ).day + 1
disableCollection = [ { from: [2014,2,4], to: [2014,2,14] } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday
if ( index >= 2 && index <= 12 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', disableCollection )
deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
strictEqual( $root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 0, 'No dates disabled' )
disableCollection = [ { from: new Date(2014,2,7), to: new Date(2014,2,17) } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range updated' )
$root.find( 'td [data-pick]' ).each( function( indexCell, tableCell ) {
var index = indexCell - viewday
if ( index >= 5 && index <= 15 ) {
ok( $( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickadate.defaults.klass.disabled ), 'Date is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', disableCollection )
deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
strictEqual( $root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 0, 'No dates disabled' )
})
// test( '`disable` and `enable` using relative ranges', function() {
//
// var picker = this.picker,
// $root = picker.$root,
// today = picker.get( 'now' ).obj,
// yearToday = today.getFullYear(),
// monthToday = today.getMonth(),
// dateToday = today.getDate(),
// backDay = [ yearToday, monthToday, dateToday - 10 ],
// forwardDay = new Date( yearToday, monthToday, dateToday + 10 ),
// disableCollection, index, $dates, disabledDate, previousMonth
//
// disableCollection = [ { from: true, to: forwardDay } ]
// picker.set( 'disable', disableCollection )
// deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to today with date object' )
//
// $dates = $root.find('.' + $.fn.pickadate.defaults.klass.disabled)
// for ( index = 0, datesCount = $dates.length; index < datesCount; index += 1 ) {
// disabledDate = +$dates[index].innerHTML
// disabledDate = new Date(yearToday, monthToday, disabledDate)
// ok( disabledDate >= today &&
// disabledDate <= new Date(yearToday, monthToday, dateToday + 10),
// 'Date is disabled: ' + disabledDate
// );
// }
//
// picker.set( 'enable', disableCollection )
// deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
// ok( !$root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 'No dates disabled' )
//
// disableCollection = [ { from: backDay, to: true } ]
// picker.set( 'disable', disableCollection )
// deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to today with array' )
//
// $dates = $root.find('.' + $.fn.pickadate.defaults.klass.disabled)
// for ( index = 0, datesCount = $dates.length; index < datesCount; index += 1 ) {
// disabledDate = +$dates[index].innerHTML
// previousMonth = disabledDate > dateToday ? 1 : 0
// disabledDate = new Date(yearToday, monthToday - previousMonth, disabledDate)
// ok( disabledDate <= today &&
// disabledDate >= new Date(yearToday, monthToday, dateToday - 10),
// 'Date is disabled: ' + disabledDate
// );
// }
//
// picker.set( 'enable', disableCollection )
// deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
// ok( !$root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 'No dates disabled' )
//
// disableCollection = [ { from: true, to: 10 } ]
// picker.set( 'disable', disableCollection )
// deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to today with positive integer' )
//
// $dates = $root.find('.' + $.fn.pickadate.defaults.klass.disabled)
// for ( index = 0, datesCount = $dates.length; index < datesCount; index += 1 ) {
// disabledDate = +$dates[index].innerHTML
// disabledDate = new Date(yearToday, monthToday, disabledDate)
// ok( disabledDate >= today &&
// disabledDate <= new Date(yearToday, monthToday, dateToday + 10),
// 'Date is disabled: ' + disabledDate
// );
// }
//
// picker.set( 'enable', disableCollection )
// deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
// ok( !$root.find( '.' + $.fn.pickadate.defaults.klass.disabled ).length, 'No dates disabled' )
//
// disableCollection = [ { from: -10, to: true } ]
// picker.set( 'disable', disableCollection )
// deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to today with negative integer' )
//
// $dates = $root.find('.' + $.fn.pickadate.defaults.klass.disabled)
// for ( index = 0, datesCount = $dates.length; index < datesCount; index += 1 ) {
// disabledDate = +$dates[index].innerHTML
// previousMonth = disabledDate > dateToday ? 1 : 0
// disabledDate = new Date(yearToday, monthToday - previousMonth, disabledDate)
// ok( disabledDate <= today &&
// disabledDate >= new Date(yearToday, monthToday, dateToday - 10),
// 'Date is disabled: ' + disabledDate
// );
// }
// });
test( '`disable` and `enable` using overlapping ranges', function() {
var picker = this.picker,
$root = picker.$root,
disableCollection
picker.set( 'view', [2014,2,1] )
picker.set( 'disable', [
{ from: [2014,2,4], to: [2014,2,28] }
])
picker.set( 'enable', [
{ from: [2014,2,14], to: [2014,2,18] }
])
disableCollection = [
{ from: [2014,2,4], to: [2014,2,28] },
{ from: [2014,2,14], to: [2014,2,18], inverted: true }
]
deepEqual( picker.get( 'disable' ), disableCollection, 'Inverted range within disabled range' )
$dates = $root.find('.' + $.fn.pickadate.defaults.klass.disabled)
for ( index = 0, datesCount = $dates.length; index < datesCount; index += 1 ) {
disabledDate = +$dates[index].innerHTML
ok( disabledDate >= 4 && disabledDate < 14 ||
disabledDate > 18 && disabledDate <= 28,
'Date is disabled: ' + disabledDate
);
}
picker.set( 'disable', false )
picker.set( 'disable', [
{ from: [2014,2,4], to: [2014,2,28] }
])
picker.set( 'enable', [
{ from: [2014,2,1], to: [2014,2,14] }
])
disableCollection = [
{ from: [2014,2,4], to: [2014,2,28] },
{ from: [2014,2,1], to: [2014,2,14], inverted: true }
]
deepEqual( picker.get( 'disable' ), disableCollection, 'Inverted range before and within disabled range' )
$dates = $root.find('.' + $.fn.pickadate.defaults.klass.disabled)
for ( index = 0, datesCount = $dates.length; index < datesCount; index += 1 ) {
disabledDate = +$dates[index].innerHTML
ok( disabledDate >= 14 && disabledDate <= 28,
'Date is disabled: ' + disabledDate
);
}
picker.set( 'disable', false )
picker.set( 'disable', [
{ from: [2014,2,4], to: [2014,2,20] }
])
picker.set( 'enable', [
{ from: [2014,2,16], to: [2014,2,24] }
])
disableCollection = [
{ from: [2014,2,4], to: [2014,2,20] },
{ from: [2014,2,16], to: [2014,2,24], inverted: true }
]
deepEqual( picker.get( 'disable' ), disableCollection, 'Inverted range after and within disabled range' )
$dates = $root.find('.' + $.fn.pickadate.defaults.klass.disabled)
for ( index = 0, datesCount = $dates.length; index < datesCount; index += 1 ) {
disabledDate = +$dates[index].innerHTML
ok( disabledDate >= 4 && disabledDate < 16,
'Date is disabled: ' + disabledDate
);
}
})
test( '`disable` and `enable` repeatedly', function() {
var now = new Date(2014,3,6),
nowYear = now.getFullYear(),
nowMonth = now.getMonth(),
nowDate = now.getDate(),
picker = this.picker,
disabledCollection = [
[nowYear,nowMonth,1],
[nowYear,nowMonth,17],
new Date(nowYear,nowMonth,25),
1,
{ from: [nowYear,nowMonth,4], to: [nowYear,nowMonth,10] },
{ from: [nowYear,nowMonth,8], to: [nowYear,nowMonth,12] }
],
collectionToEnable
picker.set( 'disable', disabledCollection )
picker.set( 'disable', disabledCollection )
deepEqual( picker.get( 'disable' ), disabledCollection, 'Collection without duplicates' )
collectionToEnable = [
[nowYear,nowMonth,17],
[nowYear,nowMonth,25],
now,
{ from: [nowYear,nowMonth,8], to: [nowYear,nowMonth,12] }
]
picker.set( 'enable', collectionToEnable )
disabledCollection = [
[nowYear,nowMonth,1],
1,
{ from: [nowYear,nowMonth,4], to: [nowYear,nowMonth,10] },
[nowYear,nowMonth,nowDate,'inverted'],
{ from: [nowYear,nowMonth,8], to: [nowYear,nowMonth,12], inverted: true }
]
deepEqual( picker.get( 'disable' ), disabledCollection, 'Collection enabled various values' )
picker.set( 'enable', collectionToEnable )
deepEqual( picker.get( 'disable' ), disabledCollection, 'Collection without duplicates' )
collectionToEnable = disabledCollection
picker.set( 'enable', collectionToEnable )
deepEqual( picker.get( 'disable' ), [], 'Collection cleared - including inverted range overlaps' )
picker.set( 'enable', collectionToEnable )
deepEqual( picker.get( 'disable' ), [], 'Collection kept clear' )
})
module( 'Date picker `set` beyond limits', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate({
min: -40,
max: 40
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`select`', function() {
var picker = this.picker,
today = new Date()
today.setHours(0,0,0,0)
picker.set( 'select', new Date( today.getFullYear(), today.getMonth(), today.getDate() - 60 ) )
deepEqual( picker.get( 'select' ), picker.get( 'min' ), 'Able to not `select` beyond lower limit' )
picker.set( 'select', new Date( today.getFullYear(), today.getMonth(), today.getDate() + 60 ) )
deepEqual( picker.get( 'select' ), picker.get( 'max' ), 'Able to not `select` beyond upper limit' )
})
test( '`highlight`', function() {
var picker = this.picker,
today = new Date()
today.setHours(0,0,0,0)
picker.set( 'highlight', new Date( today.getFullYear(), today.getMonth(), today.getDate() - 60 ) )
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), 'Able to not `highlight` beyond lower limit' )
picker.set( 'highlight', new Date( today.getFullYear(), today.getMonth(), today.getDate() + 60 ) )
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), 'Able to not `highlight` beyond upper limit' )
})
test( '`view`', function() {
var picker = this.picker,
today = new Date(),
viewset,
min = picker.get( 'min' ),
max = picker.get( 'max' )
today.setHours(0,0,0,0)
picker.set( 'view', new Date( today.getFullYear(), today.getMonth(), today.getDate() - 60 ) )
viewset = picker.get( 'view' )
deepEqual( [viewset.year,viewset.month,viewset.date], [min.year,min.month,1], 'Able to not `view` beyond lower limit' )
picker.set( 'view', new Date( today.getFullYear(), today.getMonth(), today.getDate() + 60 ) )
viewset = picker.get( 'view' )
deepEqual( [viewset.year,viewset.month,viewset.date], [max.year,max.month,1], 'Able to not `view` beyond upper limit' )
})
module( 'Date picker mouse events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate()
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Select', function() {
var picker = this.picker,
$root = picker.$root,
viewsetObject = picker.get( 'view' ),
monthStartDay = viewsetObject.day,
monthEndDate = new Date( viewsetObject.year, viewsetObject.month + 1, 0 ).getDate()
for ( var i = monthStartDay; i < monthStartDay + monthEndDate; i += 1 ) {
$root.find( '.' + $.fn.pickadate.defaults.klass.day ).eq( i ).click()
strictEqual( picker.get( 'select' ).pick, new Date( viewsetObject.year, viewsetObject.month, viewsetObject.date + i - monthStartDay ).getTime(), 'Selected ' + picker.get( 'select', 'yyyy/mm/dd' ) )
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickadate.defaults.format ), 'Input value updated to ' + picker.get( 'value' ) )
}
})
test( 'Highlight', function() {
var picker = this.picker,
$root = picker.$root,
today = new Date(),
playdate = new Date()
today.setHours(0,0,0,0)
playdate.setHours(0,0,0,0)
$root.find( '.' + $.fn.pickadate.defaults.klass.navPrev ).click()
playdate.setMonth( playdate.getMonth() - 1 )
if ( playdate.getMonth() === today.getMonth() ) {
playdate.setDate( 0 )
}
deepEqual( picker.get( 'highlight' ).obj, playdate, 'Previous month: ' + playdate )
deepEqual( picker.get( 'select' ), null, 'Select unaffected' )
var day = playdate.getDate()
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, 'View updated' )
$root.find( '.' + $.fn.pickadate.defaults.klass.navNext ).click()
$root.find( '.' + $.fn.pickadate.defaults.klass.navNext ).click()
playdate.setMonth( today.getMonth() + 1 )
playdate = new Date(today.getFullYear(), today.getMonth() + 1, day)
if ( playdate.getDate() < day ) {
playdate.setDate( 0 )
}
deepEqual( picker.get( 'highlight' ).obj, playdate, 'Next month: ' + playdate )
deepEqual( picker.get( 'select' ), null, 'Select unaffected' )
playdate.setDate( 1 )
deepEqual( picker.get( 'view' ).obj, playdate, 'View updated' )
})
test( 'Today', function() {
var picker = this.picker
picker.open()
picker.$root.find( '.' + $.fn.pickadate.defaults.klass.buttonToday ).click()
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickadate.defaults.format ), 'Value set to today' )
})
test( 'Clear', function() {
var picker = this.picker
picker.open()
picker.set( 'select', new Date() )
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickadate.defaults.format ), 'Value updated' )
picker.$root.find( '.' + $.fn.pickadate.defaults.klass.buttonClear ).click()
strictEqual( picker.get( 'value' ), '', 'Value cleared' )
})
test( 'Closes upon selection', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-pick]').click()
ok( !picker.get('open'), 'Closed after selection' )
})
test( 'Closes upon clearing', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-clear]').click()
ok( !picker.get('open'), 'Closed after clearing' )
})
module( 'Date picker mouse events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate({
closeOnSelect: false,
closeOnClear: false
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Remains open upon selection with option', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-pick]').click()
ok( picker.get('open'), 'Remains open after selection' )
})
test( 'Closes upon clearing', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-clear]').click()
ok( picker.get('open'), 'Remains open after clearing' )
})
module( 'Date picker keyboard events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate()
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Select', function() {
var picker = this.picker,
$input = picker.$holder,
playdate = new Date()
playdate.setHours(0,0,0,0)
for ( var i = 0; i < 10; i += 1 ) {
// Open the picker.
picker.open()
// Update the playdate.
playdate.setDate( playdate.getDate() + 10 )
// Set the highlight.
picker.set( 'highlight', playdate )
// Keydown to select the highlighted item.
$input.trigger({ type: 'keydown', keyCode: 13 })
// Check if the select is the same as the highlight.
deepEqual( picker.get( 'select' ), picker.get( 'highlight' ), 'Select updated to: ' + picker.get( 'select' ).obj )
}
})
test( 'Highlight', function() {
var picker = this.picker,
$input = picker.$holder,
playdate = new Date()
// Open the picker
picker.open()
// Down
for ( var i = 0; i < 10; i += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 40 })
playdate.setDate( playdate.getDate() + 7 )
strictEqual( picker.get( 'highlight' ).date, playdate.getDate(), 'Keyed "down" to: ' + picker.get( 'highlight', 'yyyy/mm/dd' ) )
strictEqual( picker.get( 'view' ).month, picker.get( 'highlight' ).month, 'Updated "view" to: ' + picker.get( 'view', 'yyyy/mm/dd' ) )
}
// Up
for ( var j = 0; j < 10; j += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 38 })
playdate.setDate( playdate.getDate() - 7 )
strictEqual( picker.get( 'highlight' ).date, playdate.getDate(), 'Keyed "up" to: ' + picker.get( 'highlight', 'yyyy/mm/dd' ) )
strictEqual( picker.get( 'view' ).month, picker.get( 'highlight' ).month, 'Updated "view" to: ' + picker.get( 'view', 'yyyy/mm/dd' ) )
}
// Left
for ( var k = 0; k < 10; k += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 37 })
playdate.setDate( playdate.getDate() - 1 )
ok( picker.get( 'highlight' ).date === playdate.getDate() && picker.get( 'highlight' ).day === playdate.getDay(), 'Keyed "left" to: ' + picker.get( 'highlight', 'yyyy/mm/dd' ) )
strictEqual( picker.get( 'view' ).month, picker.get( 'highlight' ).month, 'Updated "view" to: ' + picker.get( 'view', 'yyyy/mm/dd' ) )
}
// Right
for ( var l = 0; l < 10; l += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 39 })
playdate.setDate( playdate.getDate() + 1 )
ok( picker.get( 'highlight' ).date === playdate.getDate() && picker.get( 'highlight' ).day === playdate.getDay(), 'Keyed "right" to: ' + picker.get( 'highlight', 'yyyy/mm/dd' ) )
strictEqual( picker.get( 'view' ).month, picker.get( 'highlight' ).month, 'Updated "view" to: ' + picker.get( 'view', 'yyyy/mm/dd' ) )
}
})
test( 'Closes upon selection', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-pick]').focus()
picker.$holder.trigger({ type: 'keydown', keyCode: 13 })
ok( !picker.get('open'), 'Closed after selection' )
})
test( 'Closes upon clearing', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-clear]').focus()
picker.$holder.trigger({ type: 'keydown', keyCode: 13 })
ok( !picker.get('open'), 'Closed after clearing' )
})
module( 'Date picker keyboard events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickadate({
closeOnSelect: false,
closeOnClear: false
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Remains open upon selection with option', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-pick]').focus()
picker.$holder.trigger({ type: 'keydown', keyCode: 13 })
ok( picker.get('open'), 'Remains open after selection' )
})
test( 'Closes upon clearing', function() {
var picker = this.picker
picker.open()
ok( picker.get('open'), 'Opened to start off' )
picker.$holder.find('[data-clear]').focus()
picker.$holder.trigger({ type: 'keydown', keyCode: 13 })
ok( picker.get('open'), 'Remains open after clearing' )
})
module( 'Date picker with a visible value', {
setup: function() {
$DOM.append( $INPUT.clone().val( '14 August, 1988' ) )
var $input = $DOM.find( 'input' ).pickadate()
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`value` to select, highlight, and view', function() {
var picker = this.picker
ok( !picker._hidden, 'No hidden input' )
deepEqual( picker.get( 'select' ).obj, new Date(1988,7,14), 'Selects date' )
deepEqual( picker.get( 'highlight' ).obj, new Date(1988,7,14), 'Highlights date' )
deepEqual( picker.get( 'view' ).obj, new Date(1988,7,1), 'Viewsets date' )
})
module( 'Date picker with a simple format', {
setup: function() {
$DOM.append( $INPUT.clone().val( '1988-08-14' ) )
var $input = $DOM.find( 'input' ).pickadate({
format: 'yyyy-mm-dd'
})
this.picker = $input.pickadate( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`value` to select, highlight, and view', function() {
var picker = this.picker
ok( !picker._hidden, 'No hidden input' )
deepEqual( picker.get( 'select' ).obj, new Date(1988,7,14), 'Selects date' )
deepEqual( picker.get( 'highlight' ).obj, new Date(1988,7,14), 'Highlights date' )
deepEqual( picker.get( 'view' ).obj, new Date(1988,7,1), 'Viewsets date' )
})
module( 'Date picker with a hidden value', {
teardown: function() {
$DOM.empty()
}
})
test( '`value` to select, highlight, and view', function() {
$DOM.append( $INPUT.clone().val( '14 August, 1988' ) )
var $input = $DOM.find( 'input' ).pickadate({
formatSubmit: 'yyyy/mm/dd'
})
var picker = $input.pickadate( 'picker' )
ok( picker._hidden, 'Has hidden input' )
strictEqual( picker._hidden.value, '1988/08/14', 'Hidden input value' )
deepEqual( picker.get( 'select' ).obj, new Date(1988,7,14), 'Selects date' )
deepEqual( picker.get( 'highlight' ).obj, new Date(1988,7,14), 'Highlights date' )
deepEqual( picker.get( 'view' ).obj, new Date(1988,7,1), 'Viewsets date' )
})
test( '`data-value` to select, highlight, and view', function() {
$DOM.append( $INPUT.clone().data( 'value', '1988/08/14' ) )
var $input = $DOM.find( 'input' ).pickadate({
formatSubmit: 'yyyy/mm/dd'
})
var picker = $input.pickadate( 'picker' )
ok( picker._hidden, 'Has hidden input' )
strictEqual( picker._hidden.value, '1988/08/14', 'Hidden input value' )
deepEqual( picker.get( 'select' ).obj, new Date(1988,7,14), 'Selects date' )
deepEqual( picker.get( 'highlight' ).obj, new Date(1988,7,14), 'Highlights date' )
deepEqual( picker.get( 'view' ).obj, new Date(1988,7,1), 'Viewsets date' )
})
test( 'the pre-filled `value` selected is no longer "active"', function() {
var $input = $( '<input type="text" value="14 August, 2014">' ).pickadate({
formatSubmit: 'yyyy/mm/dd',
min: [2015, 7, 14]
})
var picker = $input.pickadate( 'picker' )
strictEqual( picker.get( 'value' ), '14 August, 2014', 'Sets the default value' )
strictEqual( picker.get( 'valueSubmit' ), '2014/08/14', 'Sets the default value to submit' )
var select = picker.get('select')
deepEqual( [select.year, select.month, select.date], [2014, 7, 14], 'Sets the default select' )
})
/*jshint
debug: true,
devel: true,
browser: true,
asi: true,
unused: true,
eqnull: true,
eqeqeq: true
*/
var $DOM = $( '#qunit-fixture' ),
$INPUT = $( '<input type=password>' )
/* ==========================================================================
Time picker tests
========================================================================== */
module( 'Time picker setup', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickatime()
this.picker = $input.pickatime( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Clock stage', function() {
strictEqual( this.picker.$root.find( '[data-pick]' ).length, 48, '48 selectable times' )
})
test( 'Properties', function() {
var picker = this.picker,
today = new Date(),
interval = picker.get( 'interval' ),
nowMinutes = today.getHours() * 60 + today.getMinutes()
strictEqual( interval, 30, 'Default interval is 30' )
strictEqual( picker.get( 'min' ).pick, 0, 'Default “min” is midnight' )
strictEqual( picker.get( 'max' ).pick, 1410, 'Default “max” is 23:30' )
strictEqual( picker.get( 'now' ).pick, (interval + nowMinutes - ( nowMinutes % interval )) % 1440, 'Default “now” is: ' + picker.get( 'now', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, 'Default “select” is `null`' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), 'Default “highlight” is “now”' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), 'Default “view” is “highlight”' )
})
test( 'Formats', function() {
var picker = this.picker,
interval = $.fn.pickatime.defaults.interval,
today = new Date(),
minutes = today.getHours() * 60 + today.getMinutes(),
leadZero = function( number ) {
return ( number < 10 ? '0' : '' ) + number
},
toHours = function( mins ) {
var hours = ~~( mins/60 ) % 12
return hours ? hours : 12
},
formats = {
h: function() {
return '' + toHours( minutes )
},
hh: function() {
return leadZero( toHours( minutes ) )
},
H: function() {
return '' + ( ~~( minutes/60 ) % 24 )
},
HH: function() {
return leadZero( ~~( minutes/60 ) % 24 )
},
i: function() {
return leadZero( minutes%60 )
},
a: function() {
return ~~( minutes/60 ) % 24 >= 12 ? 'p.m.' : 'a.m.'
},
A: function() {
return ~~( minutes/60 ) % 24 >= 12 ? 'PM' : 'AM'
}
}
minutes = interval + minutes - minutes % interval
;([ 'h', 'hh', 'H', 'HH', 'i', 'a', 'A' ]).forEach( function( format ) {
var expect = formats[ format ]()
deepEqual( picker.get( 'now', format ), expect, '`' + format + '`: ' + expect )
})
})
module( 'Time picker setup', {
teardown: function() {
$DOM.empty()
}
})
test( 'Editable', function() {
$DOM.append( $INPUT.clone()).append( $INPUT.clone() )
var $input1 = $DOM.find( 'input' ).eq(0).pickatime()
var $input2 = $DOM.find( 'input' ).eq(1).pickatime({
editable: true
})
strictEqual( $input1[0].readOnly, true, 'Editable: false' )
strictEqual( $input2[0].readOnly, false, 'Editable: true' )
})
module( 'Time picker `set`', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickatime()
this.picker = $input.pickatime( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`interval`', function() {
var picker = this.picker,
$root = picker.$root
picker.set( 'interval', 120 )
strictEqual( picker.get( 'interval' ), 120, '`interval` updated' )
strictEqual( picker.get( 'min' ).pick % 120, 0, '`min` updated' )
strictEqual( picker.get( 'max' ).pick % 120, 0, '`max` updated' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.listItem ).length, 12, '12 selectable times' )
picker.set( 'interval', 'lol' )
strictEqual( picker.get( 'interval' ), 120, 'Interval unaffected by non-integer' )
})
test( '`clear`', function() {
var picker = this.picker
strictEqual( picker.get('select'), null, 'Starts off without a selection' )
picker.set('select', new Date())
notStrictEqual( picker.get('select'), null, 'A selection has been added' )
picker.clear()
strictEqual( picker.get('select'), null, 'Clears out selection' )
})
test( '`select`', function() {
var picker = this.picker
// Using numbers
picker.set( 'select', 180 )
strictEqual( picker.get( 'select' ).pick, 180, '`select` using a number: ' + picker.get( 'select', 'HH:i' ) )
strictEqual( picker.get( 'highlight' ).pick, 180, '`highlight` updated' )
strictEqual( picker.get( 'view' ).pick, 180, '`view` updated' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
// Using JavaScript date objects
var dateObject = new Date()
dateObject.setHours(4,20)
picker.set( 'select', dateObject )
strictEqual( picker.get('select').pick, 270, '`select` using a JS date object: ' + picker.get( 'select', 'HH:i' ) )
strictEqual( picker.get( 'highlight' ).pick, 270, '`highlight` updated' )
strictEqual( picker.get( 'view' ).pick, 270, '`view` updated' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
// Using arrays
picker.set( 'select', [9,0] )
strictEqual( picker.get( 'select' ).pick, 540, '`select` using an array: ' + picker.get( 'select', 'HH:i' ) )
strictEqual( picker.get( 'highlight' ).pick, 540, '`highlight` updated' )
strictEqual( picker.get( 'view' ).pick, 540, '`view` updated' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
})
test( '`highlight`', function() {
var picker = this.picker
// Using numbers
picker.set( 'highlight', 180 )
strictEqual( picker.get( 'highlight' ).pick, 180, '`highlight` using a number: ' + picker.get( 'highlight', 'HH:i' ) )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` updated' )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
// Using JavaScript date objects
var dateObject = new Date()
dateObject.setHours(4,20)
picker.set( 'highlight', dateObject )
strictEqual( picker.get('highlight').pick, 270, '`highlight` using a JS date object: ' + picker.get( 'highlight', 'HH:i' ) )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` updated' )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
// Using arrays
picker.set( 'highlight', [9,0] )
strictEqual( picker.get( 'highlight' ).pick, 540, '`highlight` using an array: ' + picker.get( 'highlight', 'HH:i' ) )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` updated' )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
})
test( '`view`', function() {
var picker = this.picker
// Using numbers
picker.set( 'view', 180 )
strictEqual( picker.get( 'view' ).pick, 180, '`view` using a number: ' + picker.get( 'view', 'HH:i' ) )
strictEqual( picker.get( 'highlight' ).pick, picker.get( 'now' ).pick, '`highlight` unaffected' )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
// Using JavaScript date objects
var dateObject = new Date()
dateObject.setHours(4,20)
picker.set( 'view', dateObject )
strictEqual( picker.get('view').pick, 270, '`view` using a JS date object: ' + picker.get( 'view', 'HH:i' ) )
strictEqual( picker.get( 'highlight' ).pick, picker.get( 'now' ).pick, '`highlight` unaffected' )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
// Using arrays
picker.set( 'view', [9,0] )
strictEqual( picker.get( 'view' ).pick, 540, '`view` using an array: ' + picker.get( 'view', 'HH:i' ) )
strictEqual( picker.get( 'highlight' ).pick, picker.get( 'now' ).pick, '`highlight` unaffected' )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
})
test( '`min` using integers', function() {
var picker = this.picker,
interval = 30
// Using negative numbers
picker.set( 'min', -3 )
strictEqual( (picker.get( 'min' ).pick + ( interval * 3 )) % 1440, picker.get( 'now' ).pick , '`min` using a negative number: ' + picker.get( 'min', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
if ( picker.get( 'min' ).pick > picker.get( 'now' ).pick ) {
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'min' ), '`view` updated' )
}
else {
strictEqual( picker.get( 'highlight' ).pick, picker.get( 'now' ).pick, '`highlight` unaffected' )
strictEqual( picker.get( 'view' ).pick, picker.get( 'now' ).pick, '`view` unaffected' )
}
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
var previousHighlight = picker.get( 'highlight' )
var previousView = picker.get( 'view' )
// Using positive numbers
picker.set( 'min', 3 )
strictEqual( picker.get( 'min' ).pick, (picker.get( 'now' ).pick + ( interval * 3 )) % 1440, '`min` using a positive number: ' + picker.get( 'min', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
if ( picker.get( 'highlight' ).pick !== previousHighlight.pick ) {
deepEqual( picker.get( 'highlight' ).pick, picker.get( 'min' ).pick, '`highlight` updated' )
deepEqual( picker.get( 'view' ).pick, picker.get( 'min' ).pick, '`view` updated' )
}
else {
deepEqual( picker.get( 'highlight' ).pick, previousHighlight.pick, '`highlight` unaffected' )
deepEqual( picker.get( 'view' ).pick, previousView.pick, '`view` unaffected' )
}
})
test( '`min` using booleans', function() {
var picker = this.picker
// Boolean true
picker.set( 'min', true )
deepEqual( picker.get( 'min' ), picker.get( 'now' ), '`min` using `true`: ' + picker.get( 'min', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'min' ), '`view` updated' )
deepEqual( picker.get( 'max' ).time, 1410, '`max` unaffected' )
// Boolean false
picker.set( 'min', false )
strictEqual( picker.get( 'min' ).time, 0, '`min` using `false`: ' + picker.get( 'min', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'now' ), '`view` unaffected' )
deepEqual( picker.get( 'max' ).time, 1410, '`max` unaffected' )
})
test( '`min` using arrays', function() {
var picker = this.picker
// Using arrays
picker.set( 'min', [2,0] )
strictEqual( picker.get( 'min' ).pick, 120, '`min` using an array: ' + picker.get( 'min', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
if ( picker.get( 'min' ).pick > picker.get( 'now' ).pick ) {
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'min' ), '`view` updated' )
}
else {
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` updated' )
}
deepEqual( picker.get( 'max' ).pick, 1410, '`max` unaffected' )
})
test( '`min` using JS dates', function() {
var picker = this.picker
// Using JavaScript date objects
var dateObject = new Date()
dateObject.setHours(4,30)
picker.set( 'min', dateObject )
strictEqual( picker.get( 'min' ).pick, 270, '`min` using a JS date: ' + picker.get( 'min', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
if ( picker.get( 'min' ).pick > picker.get( 'now' ).pick ) {
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'min' ), '`view` updated' )
}
else {
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` updated' )
}
deepEqual( picker.get( 'max' ).pick, 1410, '`max` updated' )
})
test( '`min` using strings', function() {
var picker = this.picker
var min = picker.get('min')
strictEqual( min.pick, 0, 'No `min` time' )
picker.set( 'min', '3:30 PM' )
min = picker.get('min')
deepEqual( [min.hour, min.mins], [15, 30], '`min` updated' )
})
test( '`max` using integers', function() {
var picker = this.picker,
interval = 30
// Using positive numbers
picker.set( 'max', 3 )
strictEqual( picker.get( 'max' ).pick, (picker.get( 'now' ).pick + ( interval * 3 )) % 1440, '`max` using a positive number: ' + picker.get( 'max', 'HH:i' ) )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
if ( picker.get( 'max' ).pick < picker.get( 'now' ).pick ) {
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'max' ), '`view` updated' )
}
else {
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'now' ), '`view` unaffected' )
}
var previousHighlight = picker.get( 'highlight' )
// Using negative numbers
picker.set( 'max', -3 )
var maxPickTime = picker.get( 'now' ).pick + ( interval * -3 )
// If it's less than `min` time, add a day.
maxPickTime += maxPickTime < 0 ? 1440 : 0
strictEqual( picker.get( 'max' ).pick, maxPickTime, '`max` using a negative number: ' + picker.get( 'max', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
if ( picker.get( 'highlight' ).pick === maxPickTime ) {
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'max' ), '`view` updated' )
}
else {
deepEqual( picker.get( 'highlight' ), previousHighlight, '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), previousHighlight, '`view` unaffected' )
}
})
test( '`max` using booleans', function() {
var picker = this.picker
// Boolean true
picker.set( 'max', true )
deepEqual( picker.get( 'max' ), picker.get( 'now' ), '`max` using `true`: ' + picker.get( 'max', 'HH:i' ) )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'highlight' ).pick, picker.get( 'now' ).pick, '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
// Boolean false
picker.set( 'max', false )
deepEqual( picker.get( 'max' ).pick, 1410, '`max` using `false`: ' + picker.get( 'max', 'HH:i' ) )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
strictEqual( picker.get( 'highlight' ).pick, picker.get( 'now' ).pick, '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` unaffected' )
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
})
test( '`max` using arrays', function() {
var picker = this.picker
// Using arrays
picker.set( 'max', [14,30] )
strictEqual( picker.get( 'max' ).pick, 870, '`max` using an array: ' + picker.get( 'max', 'HH:i' ) )
strictEqual( picker.get( 'select' ), null, '`select` unaffected' )
if ( picker.get( 'max' ).pick < picker.get( 'now' ).pick ) {
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` updated' )
}
else {
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` unaffected' )
}
strictEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
})
test( '`max` using JS dates', function() {
var picker = this.picker
// Using JavaScript date objects
var dateObject = new Date()
dateObject.setHours(16,20)
picker.set( 'max', dateObject )
strictEqual( picker.get( 'max' ).pick, 960, '`max` using a JS date: ' + picker.get( 'max', 'HH:i' ) )
deepEqual( picker.get( 'select' ), null, '`select` unaffected' )
if ( picker.get( 'max' ).pick < picker.get( 'now' ).pick ) {
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), '`highlight` updated' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` updated' )
}
else {
deepEqual( picker.get( 'highlight' ), picker.get( 'now' ), '`highlight` unaffected' )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), '`view` unaffected' )
}
deepEqual( picker.get( 'min' ).pick, 0, '`min` unaffected' )
})
test( '`max` using strings', function() {
var picker = this.picker
var max = picker.get('max')
strictEqual( max.pick, 1410, 'No `max` time' )
picker.set( 'max', '3:30 PM' )
max = picker.get('max')
deepEqual( [max.hour, max.mins], [15, 30], '`max` updated' )
})
test( '`disable` and `enable` using integers', function() {
var disableCollection = [1,4,7],
picker = this.picker,
$root = picker.$root
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled times added' )
$root.find( '[data-pick]' ).each( function() {
var $this = $( this ),
hour = ~~( $this.data('pick')/60 )
if ( disableCollection.indexOf( hour ) > -1 ) {
ok( $this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Disabled time: ' + $this.html() )
}
else {
ok( !$this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Enabled time: ' + $this.html() )
}
})
picker.set( 'enable', [1] )
deepEqual( picker.get( 'disable' ), [4,7], 'Disabled time removed' )
$root.find( '[data-pick]' ).each( function() {
var $this = $( this ),
hour = ~~( $this.data('pick')/60 )
if ( [4,7].indexOf( hour ) > -1 ) {
ok( $this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Disabled time: ' + $this.html() )
}
else {
ok( !$this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Enabled time: ' + $this.html() )
}
})
picker.set( 'enable', 'flip' )
deepEqual( picker.get( 'disable' ), [4,7], 'Disabled collection `enable` flipped' )
$root.find( '[data-pick]' ).each( function() {
var $this = $( this ),
hour = ~~( $this.data('pick')/60 )
if ( [4,7].indexOf( hour ) < 0 ) {
ok( $this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Disabled time: ' + $this.html() )
}
else {
ok( !$this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Enabled time: ' + $this.html() )
}
})
picker.set( 'disable', 'flip' )
deepEqual( picker.get( 'disable' ), [4,7], 'Disabled collection `disable` flipped' )
$root.find( '[data-pick]' ).each( function() {
var $this = $( this ),
hour = ~~( $this.data('pick')/60 )
if ( [4,7].indexOf( hour ) > -1 ) {
ok( $this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Disabled time: ' + $this.html() )
}
else {
ok( !$this.hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Enabled time: ' + $this.html() )
}
})
})
test( '`disable` and `enable` using arrays', function() {
var picker = this.picker,
$root = picker.$root,
disableCollection = [ [1,0],[18,0],[23,30],[4,30] ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled times added' )
$root.find( '.' + $.fn.pickatime.defaults.klass.listItem ).each( function( index, item ) {
if ( index === 2 || index === 9 || index === 36 || index === 47 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
disableCollection.pop()
picker.set( 'enable', [ [4,30] ] )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled time removed' )
$root.find( '.' + $.fn.pickatime.defaults.klass.listItem ).each( function( index, item ) {
if ( index === 2 || index === 36 || index === 47 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
picker.set( 'enable', 'flip' )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled collection `enable` flipped' )
deepEqual( picker.get( 'enable' ), -1, 'Base state disabled' )
$root.find( '[data-pick]' ).each( function( index, item ) {
if ( index !== 2 && index !== 36 && index !== 47 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
picker.set( 'disable', 'flip' )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled collection `disable` flipped' )
deepEqual( picker.get( 'enable' ), 1, 'Base state enabled' )
$root.find( '[data-pick]' ).each( function( index, item ) {
if ( index === 2 || index === 36 || index === 47 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
picker.set( 'disable', [1] )
var disabledTimeArray = [ 1, 30 ]
picker.set( 'enable', [ disabledTimeArray ] )
disabledTimeArray.push( 'inverted' )
disableCollection = disableCollection.concat([ 1, disabledTimeArray ])
deepEqual( picker.get('disable'), disableCollection, 'Disabled collection with specified time inverted' )
})
test( '`disable` and `enable` using JS times', function() {
var disableCollection = [ new Date(2014,2,2,1), new Date(2014,2,2,17,30), new Date(2014,2,2,3) ],
picker = this.picker,
$root = picker.$root
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled times added' )
$root.find( '.' + $.fn.pickatime.defaults.klass.listItem ).each( function( index, item ) {
if ( index === 2 || index === 6 || index === 35 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
picker.set( 'enable', [ new Date(2014,2,2,17,30) ] )
deepEqual( picker.get( 'disable' ), [ new Date(2014,2,2,1), new Date(2014,2,2,3) ], 'Disabled time removed' )
$root.find( '.' + $.fn.pickatime.defaults.klass.listItem ).each( function( index, item ) {
if ( index === 2 || index === 6 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
picker.set( 'enable', 'flip' )
deepEqual( picker.get( 'disable' ), [ new Date(2014,2,2,1), new Date(2014,2,2,3) ], 'Disabled collection `enable` flipped' )
$root.find( '[data-pick]' ).each( function( index, item ) {
if ( index !== 2 && index !== 6 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
picker.set( 'disable', 'flip' )
deepEqual( picker.get( 'disable' ), [ new Date(2014,2,2,1), new Date(2014,2,2,3) ], 'Disabled collection `disable` flipped' )
$root.find( '[data-pick]' ).each( function( index, item ) {
if ( index === 2 || index === 6 ) {
ok( $( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + item.innerHTML )
}
else {
ok( !$( item ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + item.innerHTML )
}
})
})
test( '`disable` and `enable` using booleans', function() {
var picker = this.picker,
$root = picker.$root,
disableCollection = [ [1,0],[4,30],[18,0],[23,30] ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled times added to collection' )
picker.set('disable', false)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 0, 'No times disabled' )
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled times added to collection' )
picker.set('disable', true)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
deepEqual( picker.get('enable'), -1, 'Disabled collection `enable` flipped' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 48, 'All times disabled' )
picker.set( 'enable', 'flip' )
deepEqual( picker.get('enable'), 1, 'Disabled collection `enable` flipped' )
picker.set( 'disable', disableCollection )
deepEqual( picker.get('disable'), disableCollection, 'Disabled times added to collection' )
picker.set('enable', true)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 0, 'No times disabled' )
picker.set( 'disable', disableCollection )
deepEqual( picker.get('disable'), disableCollection, 'Disabled times added to collection' )
picker.set('enable', false)
deepEqual( picker.get('disable'), [], 'Disabled collection reset' )
deepEqual( picker.get('enable'), -1, 'Disabled collection `enable` flipped' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 48, 'All times disabled' )
})
test( '`disable` and `enable` using ranges', function() {
var picker = this.picker,
$root = picker.$root,
disableCollection
disableCollection = [ { from: [2,0], to: [14,30] } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range' )
$root.find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( indexCell >= 4 && indexCell <= 29 ) {
ok( $( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', disableCollection )
deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 0, 'No times disabled' )
disableCollection = [ { from: new Date(2014,2,7,5,30), to: new Date(2014,2,7,19) } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range updated' )
$root.find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( indexCell >= 11 && indexCell <= 38 ) {
ok( $( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'enable', disableCollection )
deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 0, 'No times disabled' )
})
test( '`disable` and `enable` using relative ranges', function() {
var picker = this.picker,
$root = picker.$root,
now = picker.get( 'now' ),
interval = picker.get( 'interval' ),
backTime = [ now.hour, now.mins - (10*interval) ],
forwardTime = [ now.hour, now.mins + (10*interval) ],
disableCollection
disableCollection = [ { from: true, to: forwardTime } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to now with date object' )
picker.set( 'enable', disableCollection )
deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 0, 'No times disabled' )
disableCollection = [ { from: backTime, to: true } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to now with array' )
picker.set( 'enable', disableCollection )
deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 0, 'No times disabled' )
disableCollection = [ { from: true, to: 10 } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to now with positive integer' )
picker.set( 'enable', disableCollection )
deepEqual( picker.get( 'disable' ), [], 'Cleared disabled range' )
strictEqual( $root.find( '.' + $.fn.pickatime.defaults.klass.disabled ).length, 0, 'No times disabled' )
disableCollection = [ { from: -10, to: true } ]
picker.set( 'disable', disableCollection )
deepEqual( picker.get( 'disable' ), disableCollection, 'Disabled range relative to now with negative integer' )
})
test( '`disable` and `enable` using overlapping ranges', function() {
var picker = this.picker,
$root = picker.$root
picker.set( 'disable', [
{ from: [2,0], to: [10,30] }
])
picker.set( 'enable', [
{ from: [5,30], to: [7,30] }
])
disableCollection = [
{ from: [2,0], to: [10,30] },
{ from: [5,30], to: [7,30], inverted: true }
]
deepEqual( picker.get( 'disable' ), disableCollection, 'Inverted range within disabled range' )
$root.find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( indexCell >= 4 && indexCell < 11 || indexCell > 15 && indexCell <= 21 ) {
ok( $( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'disable', false )
picker.set( 'disable', [
{ from: [2,0], to: [10,30] }
])
picker.set( 'enable', [
{ from: [0,30], to: [7,30] }
])
disableCollection = [
{ from: [2,0], to: [10,30] },
{ from: [0,30], to: [7,30], inverted: true }
]
deepEqual( picker.get( 'disable' ), disableCollection, 'Inverted range before and within disabled range' )
$root.find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( indexCell > 15 && indexCell <= 21 ) {
ok( $( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + tableCell.innerHTML )
}
})
picker.set( 'disable', false )
picker.set( 'disable', [
{ from: [2,0], to: [10,30] }
])
picker.set( 'enable', [
{ from: [7,30], to: [14,0] }
])
disableCollection = [
{ from: [2,0], to: [10,30] },
{ from: [7,30], to: [14,0], inverted: true }
]
deepEqual( picker.get( 'disable' ), disableCollection, 'Inverted range after and within disabled range' )
$root.find( '[data-pick]' ).each( function( indexCell, tableCell ) {
if ( indexCell >= 4 && indexCell < 15 ) {
ok( $( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is disabled: ' + tableCell.innerHTML )
}
else {
ok( !$( tableCell ).hasClass( $.fn.pickatime.defaults.klass.disabled ), 'Time is enabled: ' + tableCell.innerHTML )
}
})
})
test( '`disable` and `enable` repeatedly', function() {
var now = new Date(2014,3,20,4,30),
picker = this.picker,
disabledCollection = [
[14,0],
[16,30],
new Date(2014,3,20,22),
1,
{ from: [3,0], to: [7,30] },
{ from: [6,0], to: [11,30] }
],
collectionToEnable
picker.set( 'disable', disabledCollection )
picker.set( 'disable', disabledCollection )
deepEqual( picker.get( 'disable' ), disabledCollection, 'Collection without duplicates' )
collectionToEnable = [
[16,30],
[22,0],
now,
[1,30],
{ from: [6,0], to: [11,30] }
]
picker.set( 'enable', collectionToEnable )
disabledCollection = [
[14,0],
1,
{ from: [3,0], to: [7,30] },
[1,30,'inverted'],
{ from: [6,0], to: [11,30], inverted: true }
]
deepEqual( picker.get( 'disable' ), disabledCollection, 'Collection enabled various values' )
picker.set( 'enable', collectionToEnable )
deepEqual( picker.get( 'disable' ), disabledCollection, 'Collection without duplicates' )
collectionToEnable = disabledCollection
picker.set( 'enable', collectionToEnable )
deepEqual( picker.get( 'disable' ), [], 'Collection cleared - including inverted range overlaps' )
picker.set( 'enable', collectionToEnable )
deepEqual( picker.get( 'disable' ), [], 'Collection kept clear' )
})
module( 'Time picker `set` beyond limits', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).val( '5:30 a.m.' ).pickatime({
min: [2,30],
max: [17,0]
})
this.picker = $input.pickatime( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`select`', function() {
var picker = this.picker
picker.set( 'select', [1,0] )
deepEqual( picker.get( 'select' ), picker.get( 'min' ), 'Able to not `select` beyond lower limit' )
picker.set( 'select', [19,0] )
deepEqual( picker.get( 'select' ), picker.get( 'max' ), 'Able to not `select` beyond upper limit' )
})
test( '`highlight`', function() {
var picker = this.picker
picker.set( 'highlight', [1,0] )
deepEqual( picker.get( 'highlight' ), picker.get( 'min' ), 'Able to not `highlight` beyond lower limit' )
picker.set( 'highlight', [19,0] )
deepEqual( picker.get( 'highlight' ), picker.get( 'max' ), 'Able to not `highlight` beyond upper limit' )
})
test( '`view`', function() {
var picker = this.picker
picker.set( 'view', [1,0] )
deepEqual( picker.get( 'view' ), picker.get( 'min' ), 'Able to not `view` beyond lower limit' )
picker.set( 'view', [19,0] )
deepEqual( picker.get( 'view' ), picker.get( 'max' ), 'Able to not `view` beyond upper limit' )
})
module( 'Time picker `set` outsite interval scope', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickatime()
this.picker = $input.pickatime( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`select`', function() {
var picker = this.picker
picker.set( 'select', [1,10] )
var selected = picker.get('select')
deepEqual( [selected.hour, selected.mins], [1,30], 'Scoped `select` into interval range' )
picker.set( 'select', [19,49] )
selected = picker.get('select')
deepEqual( [selected.hour, selected.mins], [20,0], 'Scoped `select` into interval range' )
})
test( '`highlight`', function() {
var picker = this.picker
picker.set( 'highlight', [1,10] )
var highlighted = picker.get('highlight')
deepEqual( [highlighted.hour, highlighted.mins], [1,30], 'Scoped `highlight` into interval range' )
picker.set( 'highlight', [19,49] )
highlighted = picker.get('highlight')
deepEqual( [highlighted.hour, highlighted.mins], [20,0], 'Scoped `highlight` into interval range' )
})
test( '`view`', function() {
var picker = this.picker
picker.set( 'view', [1,10] )
var viewset = picker.get('view')
deepEqual( [viewset.hour, viewset.mins], [1,30], 'Scoped `view` into interval range' )
picker.set( 'view', [19,49] )
viewset = picker.get('view')
deepEqual( [viewset.hour, viewset.mins], [20,0], 'Scoped `view` into interval range' )
})
module( 'Time picker mouse events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickatime()
this.picker = $input.pickatime( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Select', function() {
var picker = this.picker,
$root = picker.$root,
interval = picker.get( 'interval' )
for ( var i = 0; i < 48; i += 1 ) {
$root.find( '.' + $.fn.pickatime.defaults.klass.listItem ).eq( i ).click()
strictEqual( picker.get( 'select' ).pick, i * interval, 'Selected ' + picker.get( 'select', 'h:i A' ) )
strictEqual( picker.get( 'value' ), picker.get( 'select', 'h:i A' ), 'Input value updated to ' + picker.get( 'value' ) )
}
})
test( 'Clear', function() {
var picker = this.picker
picker.set( 'select', [2,0] )
strictEqual( picker.get( 'value' ), picker.get( 'select', $.fn.pickatime.defaults.format ), 'Value updated' )
picker.open()
picker.$root.find( '.' + $.fn.pickatime.defaults.klass.buttonClear ).click()
strictEqual( picker.get( 'value' ), '', 'Value cleared' )
})
module( 'Time picker keyboard events', {
setup: function() {
$DOM.append( $INPUT.clone() )
var $input = $DOM.find( 'input' ).pickatime()
this.picker = $input.pickatime( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( 'Select', function() {
var picker = this.picker,
$input = picker.$holder
for ( var i = 0; i < 48; i += 1 ) {
// Open the picker.
picker.open()
// Set the highlight.
picker.set( 'highlight', i * 30 )
// Keydown to select the highlighted item.
$input.trigger({ type: 'keydown', keyCode: 13 })
// Check if the select is the same as the highlight.
deepEqual( picker.get( 'select' ), picker.get( 'highlight' ), 'Select updated to: ' + picker.get( 'select', 'HH:i' ) )
}
})
test( 'Highlight', function() {
var picker = this.picker,
$input = picker.$holder
// Open the picker
picker.open()
// Set the highlight to the start.
picker.set('highlight', 0)
// Down
for ( var i = 1; i < 48; i += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 40 })
strictEqual( picker.get( 'highlight' ).pick, 30 * i, 'Key “down” to `highlight`: ' + picker.get( 'highlight', 'h:i A' ) )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), 'Updated `view`' )
}
// Up
for ( var j = 2; j < 49; j += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 38 })
strictEqual( picker.get( 'highlight' ).pick, 1440 - 30 * j, 'Key “up” to `highlight`: ' + picker.get( 'highlight', 'h:i A' ) )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), 'Updated `view`' )
}
// Right
for ( var k = 1; k < 48; k += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 39 })
strictEqual( picker.get( 'highlight' ).pick, 30 * k, 'Key “right” to `highlight`: ' + picker.get( 'highlight', 'h:i A' ) )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), 'Updated `view`' )
}
// Left
for ( var l = 2; l < 49; l += 1 ) {
$input.trigger({ type: 'keydown', keyCode: 37 })
strictEqual( picker.get( 'highlight' ).pick, 1440 - 30 * l, 'Key “up” to `highlight`: ' + picker.get( 'highlight', 'h:i A' ) )
deepEqual( picker.get( 'view' ), picker.get( 'highlight' ), 'Updated `view`' )
}
})
module( 'Time picker with a visible value', {
setup: function() {
$DOM.append( $INPUT.clone().val( '2:00 p.m.' ) )
var $input = $DOM.find( 'input' ).pickatime()
this.picker = $input.pickatime( 'picker' )
},
teardown: function() {
this.picker.stop()
$DOM.empty()
}
})
test( '`value` to select, highlight, and view', function() {
var picker = this.picker
ok( !picker._hidden, 'No hidden input' )
strictEqual( picker.get( 'select' ).pick, 840, 'Selects time' )
strictEqual( picker.get( 'highlight' ).pick, 840, 'Highlights time' )
strictEqual( picker.get( 'view' ).pick, 840, 'Viewsets time' )
})
module( 'Time picker with a hidden value', {
teardown: function() {
$DOM.empty()
}
})
test( '`value` to select, highlight, and view', function() {
$DOM.append( $INPUT.clone().val( '2:00 p.m.' ) )
var $input = $DOM.find( 'input' ).pickatime({
formatSubmit: 'HH:i'
})
var picker = $input.pickatime( 'picker' )
ok( picker._hidden, 'Has hidden input' )
strictEqual( picker._hidden.value, '14:00', 'Hidden input value' )
strictEqual( picker.get( 'select' ).pick, 840, 'Selects time' )
strictEqual( picker.get( 'highlight' ).pick, 840, 'Highlights time' )
strictEqual( picker.get( 'view' ).pick, 840, 'Viewsets time' )
})
test( '`data-value` to select, highlight, and view', function() {
$DOM.append( $INPUT.clone().data( 'value', '14:00' ) )
var $input = $DOM.find( 'input' ).pickatime({
formatSubmit: 'HH:i'
})
var picker = $input.pickatime( 'picker' )
ok( picker._hidden, 'Has hidden input' )
strictEqual( picker._hidden.value, '14:00', 'Hidden input value' )
strictEqual( picker.get( 'select' ).pick, 840, 'Selects time' )
strictEqual( picker.get( 'highlight' ).pick, 840, 'Highlights time' )
strictEqual( picker.get( 'view' ).pick, 840, 'Viewsets time' )
})
/*jshint node: true*/
var program = require('commander')
var semver = require('semver')
var grunt = require('grunt')
var glob = require('glob').sync
program
.option('-p, --patch', 'set the version as the next patch')
.option('-m, --minor', 'set the version as the next minor')
.option('-M, --major', 'set the version as the next major')
.parse(process.argv)
if (program.patch) {
bumpVersion('patch')
return
}
if (program.minor) {
bumpVersion('minor')
return
}
if (program.major) {
bumpVersion('major')
return
}
grunt.fail.fatal('No release type specified')
return
function bumpVersion(release) {
grunt.log.writeln('Bumping package version by a ' + release)
var version = readPackageVersion()
grunt.log.writeln('Current package version: ' + version)
version = semver.inc(version, release)
grunt.log.writeln('Updated package version: ' + version)
writePackageVersion(version)
grunt.log.writeln('Done updating the package version')
updateLibraryFiles(version)
grunt.log.writeln('Done updating the library files')
}
function readPackageVersion() {
var pkg = require('./package')
return pkg.version
}
function writePackageVersion(version) {
var pkg = require('./package')
pkg.version = version
grunt.file.write('./package.json', JSON.stringify(pkg, null, ' '))
}
function updateLibraryFiles(version) {
var versionRegex = /^(\s*\/\*![^\/]+?v)(\d+\.\d+\.\d+)(([^\n]+?)(\d+\/\d+\/\d+))?/
var today = grunt.template.today('yyyy/mm/dd')
var files = glob('lib/*.js')
files.forEach(updateLibraryFile)
function updateLibraryFile(filePath) {
var content = grunt.file.read(filePath)
if (versionRegex.test(content)) {
content = content.split(versionRegex)
content = content[1] + version + (content[4] || '') + (content[5] ? today : '') + (content[6] || '')
}
grunt.file.write(filePath, content)
}
}
\ No newline at end of file
/*jshint node: true*/
var grunt = require('grunt')
var exec = require('shelljs').exec
var pkg = require('./package')
var isSuccessful = commitAndTag(pkg.version)
if (!isSuccessful) {
grunt.fail.fatal('Unable to commit and tag version')
}
return
function commitAndTag(version) {
var code = exec([
'git add .',
'git commit -m "Release v' + version + '"',
'git tag ' + version,
].join(' && ')).code
return !code
}
\ No newline at end of file
......@@ -477,7 +477,7 @@ div.col-md-6 {
padding: 7px !important;
}
.form-horizontal .checkbox, .form-horizontal .radio {
.form-horizontal .checkbox, .form-horizontal .radio, .form-horizontal .radio-inline{
padding: 0px;
}
......@@ -515,7 +515,7 @@ div.col-md-6 {
}
.checkbox label, .radio label {
.checkbox label, .radio label, .radio-inline {
font-size: 10px !important;
}
......
......@@ -32,6 +32,16 @@ $(document).ready(function () {
*/
});
jQuery.browser = {};
(function () {
jQuery.browser.msie = false;
jQuery.browser.version = 0;
if (navigator.userAgent.match(/MSIE ([0-9]+)\./)) {
jQuery.browser.msie = true;
jQuery.browser.version = RegExp.$1;
}
})();
function number_format(number, decimals, dec_point, thousands_sep) {
// Strip all characters but numerical ones.
number = (number + '').replace(/[^0-9+\-Ee.]/g, '');
......
from pyreportjasper import PyReportJasper
from opensipkd.base.tools import get_random_string
from opensipkd.base import get_settings, get_params
from platform import python_version
import os
from opensipkd.tools.report import *
from opensipkd.base import log
log.warning("Opensipkd.base.tools.pbb depreciated use opensipkd.tools.pbb")
# -*- coding: utf-8 -*-
db_driver_port = {
"postgresql": ["postgres", "5432", "org.postgresql.Driver", "jdbc:postgresql://localhost:5432/pjdl_ciamis"],
"oracle": ["oracle", "1512", "oracle.jdbc.driver.OracleDriver"],
}
def jasper_compile(input_file):
# REPORTS_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'reports')
# input_file = os.path.join(input_file)
# file_ext = os.path.splitext(input_file)
# output_file = os.path.join(REPORTS_DIR, 'csv')
pyreportjasper = PyReportJasper()
pyreportjasper.compile(write_jasper=True)
def jasper_export(input_file, output_file=None, schema=None,
output_formats=["pdf"], dburl="sqlalchemy.url",
parameters={}, db_schema=None):
db = get_params(dburl).split("@")
db_driver, db_user, db_password = db[0].split(':')
db_servers, db_name = db[1].split('/')
# db_user, db_password = db_users.split(":")
if db_servers.find(':') > 1:
db_host, db_port = db_servers.split(":")
else:
db_host = db_servers
db_port = db_driver_port[db_driver][1]
# db_host = db_server
jdbc_dir = get_params("jdbc_dir", "")
# if not jdbc_dir:
# java_home = os.getenv("JAVA_HOME")
# jdbc_dir = os.path.join(java_home, 'lib', db_driver_port[db_driver][2])
jdbc_driver = db_driver_port[db_driver][2]
db_driver = db_driver_port[db_driver][0]
log.info(jdbc_dir)
input_file = input_file.split(":")
if len(input_file) > 1:
path = __import__(input_file[0])
path = os.path.dirname(path.__file__)
input_file = os.path.join(path, input_file[1])
else:
input_file=input_file[0]
if not output_file:
output_file = get_params("tmp_report", "/tmp")
output_file = os.path.join(output_file, get_random_string(32))
conn = {
'driver': db_driver,
'username': db_user.strip('/'),
'password': db_password,
'host': db_host,
'database': db_name,
'schema': db_schema,
'port': db_port,
'jdbc_dir': jdbc_dir,
'jdbc_driver': jdbc_driver,
}
pyreportjasper = PyReportJasper()
# log.info(input_file)
# log.info(output_file)
# log.info(conn)
# log.info(output_formats)
parameters.update({'python_version': python_version()})
pyreportjasper.config(
input_file,
output_file,
db_connection=conn,
output_formats=output_formats,
parameters=parameters,
locale='en_US'
)
# pyreportjasper.compile(write_jasper=True)
pyreportjasper.process_report()
output_files = [".".join([output_file, f]) for f in output_formats]
log.info(output_files)
return output_files
......@@ -15,7 +15,7 @@ from pyramid.response import Response
from pyramid.security import remember
from pyramid.view import view_config
from opensipkd.base import get_params
from opensipkd.base import get_params, get_urls
from opensipkd.base.tools.api import rpc_auth
from .base_views import BaseView
......@@ -68,11 +68,11 @@ class Home(BaseView):
log.info(request.session.peek_flash())
if modules_default:
if request.user and request.has_permission(modules_default):
return HTTPFound(location=request.route_url(modules_default))
return HTTPFound(location=get_urls(request.route_url(modules_default)))
elif request.user and len(request.session.peek_flash('error')) < 2:
return HTTPFound(location=request.route_url(modules_default))
return HTTPFound(location=get_urls(request.route_url(modules_default)))
elif not request.user:
return HTTPFound(location=request.route_url(modules_default))
return HTTPFound(location=get_urls(request.route_url(modules_default)))
logo = get_params('logo', "static/img/logo.png")
home_tpl = get_params("home_tpl")
if home_tpl:
......@@ -87,7 +87,7 @@ class Home(BaseView):
@view_config(context=HTTPForbidden, renderer='templates/403.pt')
def http_forbidden(request):
if not request.is_authenticated:
next_url = request.route_url('login', _query={'next': request.url})
next_url = get_urls(request.route_url('login', _query={'next': request.url}))
return HTTPSeeOther(location=next_url)
request.response.status = 403
......@@ -125,7 +125,7 @@ def view_password(request):
if not request.POST:
return dict(form=form.render())
if 'save' not in request.POST:
return HTTPFound(location=request.route_url('home'))
return HTTPFound(location=request._host)
schema.request = request
controls = request.POST.items()
try:
......@@ -135,7 +135,7 @@ def view_password(request):
UserService.set_password(request.user, c['new_password'])
DBSession.add(request.user)
request.session.flash('Password baru Anda sudah disimpan.')
return HTTPFound(location=request.route_url('home'))
return HTTPFound(location=request._host)
######################################
......
......@@ -8,12 +8,13 @@ from dateutil.relativedelta import relativedelta
from opensipkd.base.views.upload import tmpstore
from opensipkd.tools.captcha import get_captcha
from pyramid.httpexceptions import HTTPFound
from opensipkd.tools.report import csv_response, file_response
from pyramid.httpexceptions import HTTPFound, HTTPNotFound
from .common import DataTables
from .. import DBSession, get_params
from .. import DBSession, get_params, get_urls
from opensipkd.tools import dmy, date_from_str, get_settings, get_ext, \
date_from_str
date_from_str, get_random_string
import colander
from deform import (widget, Form, ValidationFailure, Button, FileData, )
from email.utils import parseaddr
......@@ -69,7 +70,8 @@ class BaseView(object):
self.bulan = self.params['bulan'].strip().zfill(2)
dt_awal = date_from_str(
'{d}-{m}-{y}'.format(y=self.tahun, m=self.bulan, d='01'))
dt_akhir = dt_awal + relativedelta(months=1) - relativedelta(days=1)
dt_akhir = dt_awal + \
relativedelta(months=1) - relativedelta(days=1)
self.ses['awal'] = dmy(dt_awal)
self.ses['akhir'] = dmy(dt_akhir)
......@@ -152,25 +154,31 @@ class BaseView(object):
self.add_schema = ""
self.upload_schema = UploadSchema
self.table = ""
self.home = self.req.route_url('home')[:-1]
self.home = self.req._host
self.buttons = None
self.headers = None
self.bindings = {}
self.autocomplete = 'on'
self.action_suffix = "/grid/act"
self.upload_keys = ["kode"]
self.report_file = ""
self.query_register = ""
def delete_msg(self, row):
return f'Data ID {row.id} sudah dihapus.'
def route_list(self, msg=None, error=""):
def route_list(self, msg=None, error="", **kwargs):
if msg:
self.ses.flash(msg, error)
list_url = kwargs.get("list_url", None)
if not list_url:
list_url = self.req.route_url(self.list_route)
if self.headers:
return HTTPFound(location=self.req.route_url(self.list_route),
return HTTPFound(location=get_urls(list_url),
headers=self.headers)
else:
return HTTPFound(location=self.req.route_url(self.list_route))
return HTTPFound(location=get_urls(list_url))
def form_validator(self, form, value):
pass
......@@ -183,13 +191,23 @@ class BaseView(object):
buttons = self.buttons and self.buttons or buttons
if "bindings" in kwargs and kwargs["bindings"]:
bindings = kwargs["bindings"]
else:
elif self.bindings:
bindings = self.bindings
else:
bindings = self.get_bindings(row)
form_params = {}
# form_params["after_bind"] = after_bind
if "validator" in kwargs and kwargs["validator"]:
schema = class_form(validator=kwargs["validator"])
form_params["validator"] = kwargs["validator"]
# schema = class_form(validator=kwargs["validator"])
else:
schema = class_form(validator=self.form_validator)
form_params["validator"] = self.form_validator
# schema = class_form(validator=self.form_validator)
if "after_bind" in kwargs and kwargs["after_bind"]:
form_params["after_bind"] = kwargs["after_bind"]
# schema = class_form(validator=kwargs["validator"])
schema = class_form(**form_params)
schema = schema.bind(request=self.req, **bindings)
schema.request = self.req
......@@ -206,15 +224,20 @@ class BaseView(object):
if self.list_schema:
allow_edit = kwargs.get("allow_edit", True)
allow_delete = kwargs.get("allow_delete", True)
state_save = kwargs.get("state_save", False)
schema = self.list_schema()
schema = schema.bind(request=self.req)
list_url = kwargs.get("list_url", None)
if not list_url:
list_url = self.req.route_url(self.list_route)
table = DeTable(schema,
action=self.req.route_url(self.list_route),
action=list_url,
action_suffix="/grid/act",
buttons=self.list_buttons,
request=self.req,
allow_edit=allow_edit,
allow_delete=allow_delete)
allow_delete=allow_delete,
state_save=state_save)
resources = table.get_widget_resources()
# resources=dict(css="", js="")
return dict(form=table.render(), scripts="", css=resources["css"],
......@@ -246,7 +269,7 @@ class BaseView(object):
result = self.next_view(form, row=row)
if result:
return result
return self.route_list()
return self.after_view(row=row)
values = self.get_values(row)
if not values:
......@@ -316,14 +339,39 @@ class BaseView(object):
def validation_failure(self, value):
return value
def cancel_act(self):
return self.route_list()
def cancel_act(self, **kwargs):
return self.route_list(**kwargs)
def after_add(self, row, values):
return
def after_add(self, **kwargs):
return self.route_list(**kwargs)
def after_edit(self, **kwargs):
return self.route_list(**kwargs)
def after_view(self, **kwargs):
return self.route_list(**kwargs)
def next_act(self):
raise NotImplementedError
url_dict = self.req.matchdict
raise HTTPNotFound
def jasper_response(self, **kwargs):
from opensipkd.base.tools.report import jasper_export
filename = jasper_export(self.report_file)
return file_response(self.req, filename=filename[0])
def csv_response(self):
query = self.table.query_register()
row = query.first()
header = row.keys()
rows = [list(item) for item in query.all()]
filename = f"{get_random_string(16)}.csv"
value = {
'header': header,
'rows': rows,
}
return csv_response(self.req, value, filename)
def list_join(self, query):
return query
......@@ -338,9 +386,11 @@ class BaseView(object):
if not self.columns:
columns = []
for d in self.list_schema():
global_search = hasattr(d, "searchable") and \
hasattr(d, "searchable") == False and False \
or True
global_search = True
if hasattr(d, "searchable"):
if d.searchable == False:
global_search = False
if hasattr(d, "field"):
if type(d.field) == str:
columns.append(
......@@ -348,10 +398,14 @@ class BaseView(object):
mData=d.name,
global_search=global_search))
else:
columns.append(ColumnDT(d.field, mData=d.name))
columns.append(
ColumnDT(d.field, mData=d.name,
global_search=global_search
))
else:
columns.append(
ColumnDT(getattr(self.table, d.name), mData=d.name))
ColumnDT(getattr(self.table, d.name), mData=d.name,
global_search=global_search))
if hasattr(d, "url"):
url.append(d.name)
else:
......@@ -372,19 +426,24 @@ class BaseView(object):
# link = "/".join([self.home, nik_url, v])
# d[k] =f'<a href="{link}" target="_blank">View</a>'
return result
elif url_dict['act'] == 'csv':
return self.csv_response()
elif url_dict['act'] == 'pdf':
return self.jasper_response()
else:
return self.next_act()
def view_add(self):
bindings = self.get_bindings()
form = self.get_form(self.add_schema, bindings=bindings)
table = self.get_item_table()
def view_add(self, **kwargs):
# bindings = self.get_bindings()
form = self.get_form(self.add_schema, **kwargs)
table = self.get_item_table(**kwargs)
resources = form.get_widget_resources()
if self.req.POST:
if 'save' in self.req.POST:
controls = self.req.POST.items()
log.debug(self.req.POST.items())
log.debug(dict(self.req.POST.items()))
try:
c = form.validate(controls)
except ValidationFailure as e:
......@@ -396,7 +455,8 @@ class BaseView(object):
# efield = e.field
for f in e.field.children:
if isinstance(f.typ, colander.Date):
e.cstruct[f.name] = date_from_str(e.cstruct[f.name])
e.cstruct[f.name] = date_from_str(
e.cstruct[f.name])
# for k, v in e.cstruct.items():
# log.debug(hasattr(e.field, k))
......@@ -409,13 +469,13 @@ class BaseView(object):
js=resources["js"])
values = dict(c)
row = self.save_request(values)
self.after_add(row, values)
return self.after_add(row=row, **kwargs)
elif "cancel" in self.req.POST or 'batal' in self.req.POST or "close" in self.req.POST:
self.cancel_act()
else:
return self.next_add(form, table=table, resources=resources)
return self.route_list()
return self.route_list(**kwargs)
values = self.before_add()
form.set_appstruct(values)
return dict(form=form.render(), table=table and table.render() or None,
......@@ -454,11 +514,11 @@ class BaseView(object):
values[k] = v
return self.save(values, self.req.user, row)
def id_not_found(self):
def id_not_found(self, **kwargs):
msg = f"Data yang dicari Tidak Ditemukan ID:" \
f" {self.req.matchdict['id']}."
self.req.session.flash(msg, 'error')
return self.route_list()
return self.route_list(**kwargs)
def get_values(self, row, istime=False):
d = row.to_dict()
......@@ -469,27 +529,27 @@ class BaseView(object):
d[f] = d[f].strip()
return d
def get_item_table(self, row=None):
def get_item_table(self, row=None, **kwargs):
return
def before_edit(self, form):
return form
def view_edit(self):
def view_edit(self, **kwargs):
request = self.req
row = self.query_id().first()
if not row:
return self.id_not_found()
return self.id_not_found(**kwargs)
if not self.bindings:
self.bindings = self.get_bindings(row)
form = self.get_form(self.edit_schema)
form = self.get_form(self.edit_schema, **kwargs)
table = self.get_item_table(row)
resources = form.get_widget_resources()
if request.POST:
if 'save' in request.POST:
log.debug("Save Edit")
log.debug(dict(request.POST.items()))
log.debug(request.POST)
# log.debug("Save Edit")
# log.debug(dict(request.POST.items()))
# log.debug(request.POST)
controls = request.POST.items()
log.debug(controls)
# log.debug(dict(controls))
......@@ -497,8 +557,8 @@ class BaseView(object):
try:
controls = form.validate(controls)
except ValidationFailure as e:
log.debug(f"Edit Error: {str(e.error)}")
log.debug(f"Edit Data: {e.cstruct}")
# log.debug(f"Edit Error: {str(e.error)}")
# log.debug(f"Edit Data: {e.cstruct}")
form.set_appstruct(e.cstruct)
return dict(form=form.render(),
table=table and table.render() or None,
......@@ -506,10 +566,10 @@ class BaseView(object):
js=resources["js"])
c = dict(controls)
self.save_request(c, row)
else:
return self.after_edit(row=row, **kwargs)
return self.next_edit(form, row=row)
return self.route_list()
values = self.get_values(row)
form.set_appstruct(values)
form = self.before_edit(form)
......@@ -609,4 +669,4 @@ def need_verify():
def get_url_captcha(request):
captcha = get_captcha(request)
return os.path.join(request.route_url('home'), 'captcha', captcha)
return os.path.join(get_urls(request.route_url('home')), 'captcha', captcha)
......@@ -13,7 +13,7 @@ from sqlalchemy.orm import aliased
from .company import company_widget
from .upload import AddSchema as UploadSchema
from opensipkd.models import DBSession, Departemen, Partner, PartnerDepartemen
from ..views import ColumnDT, DataTables, BaseView
from ..views import ColumnDT, DataTables, BaseView, get_urls
SESS_ADD_FAILED = 'Tambah departemen gagal'
SESS_EDIT_FAILED = 'Edit departemen gagal'
......@@ -87,7 +87,7 @@ class AddSchema(colander.Schema):
size=60, min_length=3,
requirements=(("typeahead", None), ("deform", None),
{"js": "opensipkd.base:static/js/form/departemen.js"}),
values=f"{request.route_url('departemen')}/hon/act")
values=get_urls(f"{request.route_url('departemen')}/hon/act"))
if request.user.company_id:
self["company_id"].widget = widget.HiddenWidget()
self["company_id"].default = request.user.company_id
......
......@@ -7,7 +7,7 @@ from pyramid.view import (view_config, )
from sqlalchemy.orm import aliased
from ..views import ColumnDT, DataTables, BaseView
from .. import get_urls
_ = TranslationStringFactory("opensipkd")
SESS_ADD_FAILED = 'Tambah menu gagal'
......
......@@ -7,6 +7,7 @@ from opensipkd.base.views.kecamatan import kecamatan_widget
from opensipkd.base.views.provinsi import provinsi_widget
from opensipkd.tools import mem_tmp_store
from .. import get_urls
class NamaSchema(colander.Schema):
......@@ -132,8 +133,7 @@ class PartnerSchema(NamaSchema):
def after_bind(self, schema, kwargs):
request = kwargs["request"]
prefix = request.route_url("home")
self["provinsi_id"].slave_url=f"{prefix}/dati2/select/act?provinsi_id="
self["dati2_id"].slave_url=f"{prefix}/kecamatan/select/act?dati2_id="
prefix = get_urls(request.route_url("home"))
self["provinsi_id"].slave_url = f"{prefix}/dati2/select/act?provinsi_id="
self["dati2_id"].slave_url = f"{prefix}/kecamatan/select/act?dati2_id="
self["kecamatan_id"].slave_url = f"{prefix}/desa/select/act?kecamatan_id="
......@@ -47,6 +47,7 @@ from . import widget_os
from .base_views import need_captcha, get_url_captcha
from .user_login import regenerate_security_code, send_email_security_code
from ..views import BaseView
from .. import get_urls
_ = TranslationStringFactory('user')
......@@ -146,7 +147,7 @@ def _show_error(request, msg):
def show_error(request, msg):
_show_error(request, msg)
return HTTPFound(location=request.route_url('home'))
return HTTPFound(location=get_urls(request.route_url('home')))
# def reg_buttons():
......@@ -310,16 +311,16 @@ class Registrasi(BaseView):
def view_register(self):
if "g_state" in self.req.cookies:
if "id_info" not in self.ses or not self.ses["id_info"]:
return HTTPFound(location=self.req.route_url("login"))
return HTTPFound(location=get_urls(self.req.route_url("login")))
request = self.req
reg_form = get_params("reg_form")
if reg_form:
return HTTPFound(location=self.req.route_url(reg_form))
return HTTPFound(location=get_urls(self.req.route_url(reg_form)))
self.bindings = dict(user=None)
if request.user:
return HTTPFound(location=request.route_url("profile"))
return HTTPFound(location=get_urls(request.route_url("profile")))
return super(Registrasi, self).view_add()
......@@ -365,7 +366,7 @@ class Registrasi(BaseView):
self.buttons = (btn_save, btn_cancel)
reg_form = get_params("reg_form")
if reg_form:
return HTTPFound(location=self.req.route_url(reg_form))
return HTTPFound(location=get_urls(self.req.route_url(reg_form)))
self.bindings = dict(user=self.req.user)
resp = super(Registrasi, self).view_edit()
if not resp:
......
<html tal:define="home request.route_url('home')[:-1];">
<html tal:define="home request._host;">
<body>
<div class="well">
<h3>Forbidden</h3>
......
<html tal:define="home request.route_url('home')[:-1];">
<html tal:define="home request._host;">
<body>
<div class="well">
<h2>${request.app_name}</h2>
......
<script src="${home}/static/v3/js/plugin/datatables/jquery.dataTables.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatables/dataTables.colVis.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatables/dataTables.tableTools.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatables/dataTables.bootstrap.min.js"></script>
<script src="${home}/static/v3/js/plugin/datatable-responsive/datatables.responsive.min.js"></script>
<!DOCTYPE html>
<html lang="en" tal:define="home request.route_url('home');">
<html lang="en" tal:define="home request._host;">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="${home}static/img/favicon.png">
<link rel="shortcut icon" href="${home}/static/img/favicon.png">
<title tal:content="request.title" />
<!-- SmartAdmin Styles : Caution! DO NOT change the order -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/smartadmin-production-plugins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/smartadmin-production.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/smartadmin-skins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-production-plugins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-production.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-skins.min.css">
<!-- Bootstrap core CSS -->
<link href="${home}static/v3/css/bootstrap.min.css" rel="stylesheet">
<link href="${home}/static/v3/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/font-awesome.min.css">
<!-- Jquery CSS -->
<link href="${home}static/v3/plugin/jqueryui/themes/base/jquery-ui.min.css" rel="stylesheet">
<link href="${home}/static/v3/plugin/jqueryui/themes/base/jquery-ui.min.css" rel="stylesheet">
<!-- DataTables -->
<link href="${home}static/v3/plugin/datatables/1.10/media/css/dataTables.bootstrap.css" rel="stylesheet">
<link href="${home}/static/v3/plugin/datatables/1.10/media/css/dataTables.bootstrap.css" rel="stylesheet">
<link href="${home}deform_static/css/form.css" rel="stylesheet">
<link href="${home}deform_static/css/typeahead.css" rel="stylesheet">
<link href="${home}static/css/theme.css" rel="stylesheet">
<link href="${home}static/css/navbar-fixed-top.css" rel="stylesheet">
<link href="${home}/deform_static/css/form.css" rel="stylesheet">
<link href="${home}/deform_static/css/typeahead.css" rel="stylesheet">
<link href="${home}/static/css/theme.css" rel="stylesheet">
<link href="${home}/static/css/navbar-fixed-top.css" rel="stylesheet">
<!-- Home CSS -->
<link href="${home}static/css/custom.css" rel="stylesheet" type="text/css">
<link href="${home}/static/css/custom.css" rel="stylesheet" type="text/css">
<metal:css define-slot="css_files"></metal:css>
<style>
#content {
......@@ -58,12 +58,12 @@
<!-- <div class="navbar-collapse collapse" tal.condition="not request.user"> -->
<!-- <ul class="nav navbar-nav"> -->
<!-- <li><a href="${home}eis/sipkd" class="navbar-brand txt-color-white"><strong>${request.company}</strong></a></li> -->
<!-- <li><a href="${home}/eis/sipkd" class="navbar-brand txt-color-white"><strong>${request.company}</strong></a></li> -->
<!-- </ul> -->
<!-- <ul class="nav navbar-nav navbar-right" style="margin-right:0px;"> -->
<!-- <li class="dropdown"> -->
<!-- <a href="${home}login" class="button txt-color-white"><i class="fa fa-user"></i> Masuk</a> -->
<!-- <a href="${home}/login" class="button txt-color-white"><i class="fa fa-user"></i> Masuk</a> -->
<!-- </li> -->
<!-- </ul> -->
<!-- </div> -->
......@@ -81,21 +81,21 @@
<a href="#" class="dropdown-toggle txt-color-white" data-toggle="dropdown">Admin <b class="caret"></b></a>
<ul class="dropdown-menu">
<li tal:condition="has_permission(request, ['user-view', 'user-edit'])">
<a href="${home}user">User</a>
<a href="${home}/user">User</a>
</li>
<li tal:condition="has_permission(request, ['user-view', 'user-edit'])">
<a href="${home}group">Group</a>
<a href="${home}/group">Group</a>
</li>
<li tal:condition="has_permission(request, 'routes')"><a href="${home}routes">Routes</a></li>
<li tal:condition="has_permission(request, 'upload-logo')"><a href="${home}upload/logo">Upload Logo</a></li>
<li tal:condition="has_permission(request, 'routes')"><a href="${home}/routes">Routes</a></li>
<li tal:condition="has_permission(request, 'upload-logo')"><a href="${home}/upload/logo">Upload Logo</a></li>
<li tal:condition="has_permission(request, 'parameter')">
<a href="${home}parameter">Parameter</a></li>
<a href="${home}/parameter">Parameter</a></li>
<li tal:condition="has_permission(request, 'departemen')">
<a href="${home}departemen">Departemen</a></li>
<a href="${home}/departemen">Departemen</a></li>
<li tal:condition="has_permission(request, 'partner')">
<a href="${home}partner">Partner</a></li>
<a href="${home}/partner">Partner</a></li>
<li tal:condition="has_permission(request, 'parameter')">
<a href="${home}parameter">Parameter</a></li>
<a href="${home}/parameter">Parameter</a></li>
</ul>
</li>
......@@ -104,15 +104,15 @@
['/password', '/recreate-api-key'] and 'active'">
<a href="#" class="dropdown-toggle txt-color-white" data-toggle="dropdown">My Account <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a style="text-transform:capitalize" href="${home}logout">${request.user.nice_username()} Logout</a></li>
<li><a style="text-transform:capitalize" href="${home}profile">Profile</a></li>
<li><a style="text-transform:capitalize" href="${home}password">Ubah password</a></li>
<li><a style="text-transform:capitalize" href="${home}/logout">${request.user.nice_username()} Logout</a></li>
<li><a style="text-transform:capitalize" href="${home}/profile">Profile</a></li>
<li><a style="text-transform:capitalize" href="${home}/password">Ubah password</a></li>
<li tal:condition="request.user.api_key">
<a style="text-transform:capitalize" href="${home}recreate-api-key">
<a style="text-transform:capitalize" href="${home}/recreate-api-key">
API Key
</a>
</li>
<li tal:condition="'core' in request.modules and change_unit(request)"><a style="text-transform:capitalize" href="${home}departemen/chg">Ubah Organisasi</a></li>
<li tal:condition="'core' in request.modules and change_unit(request)"><a style="text-transform:capitalize" href="${home}/departemen/chg">Ubah Organisasi</a></li>
</ul>
</li>
</ul>
......@@ -140,20 +140,20 @@
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="${home}static/v3/js/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="${home}static/v3/js/jquery-ui-1.10.3.min.js"></script>
<script type="text/javascript" src="${home}/static/v3/js/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="${home}/static/v3/js/jquery-ui-1.10.3.min.js"></script>
<script type="text/javascript">
// Change JQueryUI plugin names to fix name collision with Bootstrap.
$.widget.bridge('uitooltip', $.ui.tooltip);
$.widget.bridge('uibutton', $.ui.button);
</script>
<script type="text/javascript" src="${home}static/v3/js/bootstrap/bootstrap.min.js"></script>
<script type="text/javascript" src="${home}static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="${home}static/v3/plugin/datatables/1.10/media/js/dataTables.bootstrap.js"></script>
<script type="text/javascript" src="${home}static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.ext.js"></script>
<script type="text/javascript" src="${home}deform_static/scripts/deform.js"></script>
<script type="text/javascript" src="${home}deform_static/scripts/typeahead.min.js"></script>
<script type="text/javascript" src="${home}static/js/tools.js"></script>
<script type="text/javascript" src="${home}/static/v3/js/bootstrap/bootstrap.min.js"></script>
<script type="text/javascript" src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="${home}/static/v3/plugin/datatables/1.10/media/js/dataTables.bootstrap.js"></script>
<script type="text/javascript" src="${home}/static/v3/plugin/datatables/1.10/media/js/jquery.dataTables.ext.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/deform.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/typeahead.min.js"></script>
<script type="text/javascript" src="${home}/static/js/tools.js"></script>
<metal:js define-slot="js_files"></metal:js>
<script metal:define-slot="scripts"></script>
......
<!DOCTYPE html>
<html lang="en-us"
tal:define="
home request.route_url('home')[:-1];
home request._host;
user_path ['user', 'user-add', 'user-edit', 'user-view', 'user-delete'];
user_ext_path ['user-ext', 'user-ext-view', 'user-ext-delete'];
group_path ['group', 'group-add', 'group-edit', 'group-view', 'group-delete'];
......
......@@ -40,7 +40,7 @@
<div class="col-sm-12 padding-thin">
<div class="box appname">
<div class="col-sm-3 padding-medium" align="center">
<img src="${home}${logo}" alt="">
<img src="${home}/${logo}" alt="">
</div>
<div class="col-sm-9 padding-high">
<span class="about-appname">${request.app_name}</span><br>
......@@ -53,14 +53,14 @@
<div class="col-sm-12 no-padding" align="center">
<div tal:repeat="modul modules" class="col-sm-3 col-xs-6 module padding-thin">
<a tal:condition="modul.find('://')<0"
href="${home}${modul}" icon="${modul.replace('/','_')}" class="box">
<img alt="" class="icon-modul" src="${home}static/icon/${modul.replace('/','_')}.png">
href="${home}/${modul}" icon="${modul.replace('/','_')}" class="box">
<img alt="" class="icon-modul" src="${home}/static/icon/${modul.replace('/','_')}.png">
<span>${modules[modul]}</span>
</a>
<a tal:condition="modul.find('://')>-1" target="_blank"
href="${modul}" class="box">
<img alt="" class="icon-modul"
src="${home}static/icon/${modul.replace('://','').replace('https','').replace('http','')}.png">
src="${home}/static/icon/${modul.replace('://','').replace('https','').replace('http','')}.png">
<span>${modules[modul]}</span>
</a>
</div>
......@@ -74,21 +74,21 @@
<div class="modal-content">
<div class="modal-body">
<h1>ABOUT <span class="bold">OPENSIPKD</span></h1>
<img src="${home}static/img/slide-home-3.jpg" alt="">
<img src="${home}/static/img/slide-home-3.jpg" alt="">
Kami adalah perusahaan yang bergerak di bidang perancangan dan pembuatan aplikasi keuangan yang telah digunakan oleh Pemerintah Daerah.<br>
Aplikasi ini dibangun dengan menggunakan platform Open Source yang terdiri dari :
<div class="clearfix" style="margin-top:20px"></div>
<div class="col-sm-6">
<img class="powered" src="${home}static/img/python.png" alt=""> <a href="https://www.python.org/">Python</a><br>
<img class="powered" src="${home}static/img/pyramid.png" alt=""> <a href="http://pylonsproject.org/">Pyramid</a><br>
<img class="powered" src="${home}/static/img/python.png" alt=""> <a href="https://www.python.org/">Python</a><br>
<img class="powered" src="${home}/static/img/pyramid.png" alt=""> <a href="http://pylonsproject.org/">Pyramid</a><br>
<a href="https://pypi.python.org/pypi/ziggurat-foundations">Ziggurat Foundations</a><br>
<a href="http://docs.pylonsproject.org/projects/pyramid-chameleon/en/latest/">Chameleon</a><br>
<a href="http://docs.pylonsproject.org/projects/deform/">Deform</a>
</div>
<div class="col-sm-6">
<img class="powered" src="${home}static/img/bootstrap.png" alt=""> <a href="http://getbootstrap.com">Bootstrap</a><br>
<img class="powered" src="${home}static/img/smartadmin.png" alt=""> <a href="https://github.com/kalichaudhary/SmartAdmin">Smart Admin</a><br>
<img class="powered" src="${home}static/img/postgree.png" alt=""> <a href="http://postgresql.org">Postgres SQL</a>
<img class="powered" src="${home}/static/img/bootstrap.png" alt=""> <a href="http://getbootstrap.com">Bootstrap</a><br>
<img class="powered" src="${home}/static/img/smartadmin.png" alt=""> <a href="https://github.com/kalichaudhary/SmartAdmin">Smart Admin</a><br>
<img class="powered" src="${home}/static/img/postgree.png" alt=""> <a href="http://postgresql.org">Postgres SQL</a>
</div>
<div class="clearfix"></div>
</div>
......@@ -101,11 +101,11 @@ $( ".module a" ).each(function() {
var modul = $(this);
var modulenm = modul.attr('icon');
$.ajax({
url:'${home}static/icon/'+ modulenm+'.png',
url:'${home}/static/icon/'+ modulenm+'.png',
type:'HEAD',
error: function()
{
modul.find('img.icon-modul').attr('src','${home}static/icon/default.png');
modul.find('img.icon-modul').attr('src','${home}/static/icon/default.png');
},
});
});
......
<html metal:use-macro="load: ./base3.1.pt"
tal:define="
home request.route_url('home');">
home request._host;">
<div metal:fill-slot="content">
<div class="jarviswidget jarviswidget-color-blueLight"> <!-- jarviswidget -->
<div tal:content="structure table"></div>
......
<!DOCTYPE html>
<html lang="en"
tal:define="home request.route_url('home')[:-1];">
tal:define="home request._host;">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
......
<!DOCTYPE html>
<html lang="en" tal:define="home request.route_url('home');">
<html lang="en" tal:define="home request._host;">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
......@@ -10,22 +10,22 @@
<meta tal:condition="request.google_signin_client_id"
name="google-signin-client_id"
content="${request.google_signin_client_id}">
<link rel="shortcut icon" href="${home}static/img/favicon.png">
<link rel="shortcut icon" href="${home}/static/img/favicon.png">
<title>Logout</title>
<!-- Basic Styles -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/font-awesome.min.css">
<!-- SmartAdmin Styles : Caution! DO NOT change the order -->
<link rel="stylesheet" type="text/css" media="screen"
href="${home}static/v3/css/smartadmin-production-plugins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/smartadmin-production.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/smartadmin-skins.min.css">
href="${home}/static/v3/css/smartadmin-production-plugins.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-production.min.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-skins.min.css">
<!-- SmartAdmin RTL Support -->
<link rel="stylesheet" type="text/css" media="screen" href="${home}static/v3/css/smartadmin-rtl.min.css">
<link rel="stylesheet" type="text/css" href="${home}static/css/home.css">
<link rel="stylesheet" type="text/css" media="screen" href="${home}/static/v3/css/smartadmin-rtl.min.css">
<link rel="stylesheet" type="text/css" href="${home}/static/css/home.css">
</head>
......@@ -54,7 +54,7 @@
tal:repeat="message request.session.pop_flash('error')">${message}</div>
</div>
<div class="col-md-12" align="center">
<img src="${home}static/img/logo.png"
<img src="${home}/static/img/logo.png"
class="img-float img-thumbnail" style="height:50px;width:auto;border:none;"/>
</div>
<div class="clearfix"></div>
......@@ -83,9 +83,9 @@
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="${home}deform_static/scripts/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="${home}deform_static/scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="${home}deform_static/scripts/deform.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/bootstrap.min.js"></script>
<script type="text/javascript" src="${home}/deform_static/scripts/deform.js"></script>
<!--?<script tal:condition="request.google_signin_client_id"-->
<!--? src="https://apis.google.com/js/platform.js" async defer></script>-->
<!--?<script tal:condition="request.google_signin_client_id">-->
......
<!DOCTYPE html>
<html lang="en"
tal:define="
home request.route_url('home');">
home request._host;">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="${home}static/img/favicon.png">
<link rel="shortcut icon" href="${home}/static/img/favicon.png">
<title tal:content="request.title"/>
<link rel="stylesheet" type="text/css"
href="${home}static/v3/css/bootstrap.min.css">
href="${home}/static/v3/css/bootstrap.min.css">
</link>
<link rel="stylesheet" type="text/css"
href="${home}static/bootstrap/css/font-awesome.min.css"/>
<link rel="stylesheet" type="text/css" href="${home}deform_static/css/typeahead.css">
<link rel="stylesheet" type="text/css" href="${home}static_map/lib/ol4/ol.css"/>
<link rel="stylesheet" type="text/css" href="${home}static_map/lib/ol4/ext/ol3-layerswitcher.css"/>
<link rel="stylesheet" type="text/css" href="${home}static_map/lib/ol4/ext/ol3gm.css"/>
<link rel="stylesheet" type="text/css" href="${home}static_map/lib/ol4/ext/ol-geocoder.css"/>
<link rel="stylesheet" type="text/css" href="${home}static/css/theme.css">
<link rel="stylesheet" type="text/css" href="${home}static/css/navbar-fixed-top.css">
href="${home}/static/bootstrap/css/font-awesome.min.css"/>
<link rel="stylesheet" type="text/css" href="${home}/deform_static/css/typeahead.css">
<link rel="stylesheet" type="text/css" href="${home}/static_map/lib/ol4/ol.css"/>
<link rel="stylesheet" type="text/css" href="${home}/static_map/lib/ol4/ext/ol3-layerswitcher.css"/>
<link rel="stylesheet" type="text/css" href="${home}/static_map/lib/ol4/ext/ol3gm.css"/>
<link rel="stylesheet" type="text/css" href="${home}/static_map/lib/ol4/ext/ol-geocoder.css"/>
<link rel="stylesheet" type="text/css" href="${home}/static/css/theme.css">
<link rel="stylesheet" type="text/css" href="${home}/static/css/navbar-fixed-top.css">
<link metal:define-slot="link"/>
<style>
html{ height:100%;}
......@@ -66,7 +66,7 @@ var gmapKey = '${request.gmap_key}';
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="${home}login" class="button">Masuk</a>
<a href="${home}/login" class="button">Masuk</a>
</li>
</ul>
</div>
......@@ -83,30 +83,30 @@ var gmapKey = '${request.gmap_key}';
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Admin <b class="caret"></b></a>
<ul class="dropdown-menu">
<li tal:condition="has_permission(request, 'user')">
<a href="${home}user">User</a></li>
<a href="${home}/user">User</a></li>
<li tal:condition="has_permission(request, 'group')">
<a href="${home}group">Group</a></li>
<a href="${home}/group">Group</a></li>
<li tal:condition="has_permission(request, 'user-group')">
<a href="${home}user/group">User Group</a></li>
<a href="${home}/user/group">User Group</a></li>
<li tal:condition="has_permission(request, 'routes')">
<a href="${home}routes">Routes</a></li>
<a href="${home}/routes">Routes</a></li>
<li tal:condition="has_permission(request, 'group-routes')">
<a href="${home}group/routes">Group Permission</a></li>
<a href="${home}/group/routes">Group Permission</a></li>
<li tal:condition="has_permission(request, 'upload-logo')">
<a href="${home}upload/logo">Upload Logo</a></li>
<a href="${home}/upload/logo">Upload Logo</a></li>
<li tal:condition="has_permission(request, 'user-ws')">
<a href="${home}user/ws">User Web Service</a></li>
<a href="${home}/user/ws">User Web Service</a></li>
</ul>
</li>
<!-- User Login Menu-->
<li class="dropdown" tal:attributes="class request.path in ['${home}password'] and 'active'">
<li class="dropdown" tal:attributes="class request.path in ['${home}/password'] and 'active'">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">My Account <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="${home}logout">${request.user.nice_username()} Logout</a></li>
<li><a href="${home}password">Ubah password</a></li>
<li><a href="${home}/logout">${request.user.nice_username()} Logout</a></li>
<li><a href="${home}/password">Ubah password</a></li>
<li tal:condition="'core' in request.modules">
<a href="${home}departemen/chg">Ubah Organisasi</a></li>
<a href="${home}/departemen/chg">Ubah Organisasi</a></li>
</ul>
</li>
</ul>
......@@ -134,16 +134,16 @@ var gmapKey = '${request.gmap_key}';
</div>
</div>
<script type="text/javascript"
src="${home}static/v3/js/jquery-2.1.1.min.js"></script>
src="${home}/static/v3/js/jquery-2.1.1.min.js"></script>
<script type="text/javascript"
src="${home}static/v3/js/bootstrap/bootstrap.min.js"></script>
src="${home}/static/v3/js/bootstrap/bootstrap.min.js"></script>
<script type="text/javascript"
src="${home}deform_static/scripts/typeahead.min.js"></script>
src="${home}/deform_static/scripts/typeahead.min.js"></script>
<script src="${home}static_map/lib/ol4/ol.js" type="text/javascript"></script>
<script src="${home}/static_map/lib/ol4/ol.js" type="text/javascript"></script>
<!-- <script src="${home}static_map/lib/ol4/ol-debug.js" type="text/javascript"></script> -->
<script type="text/javascript" src="${home}static_map/lib/ol4/ext/ol3-layerswitcher.js"></script>
<script type="text/javascript" src="${home}static_map/lib/ol4/ext/ol-geocoder.js"></script>
<script type="text/javascript" src="${home}/static_map/lib/ol4/ext/ol3-layerswitcher.js"></script>
<script type="text/javascript" src="${home}/static_map/lib/ol4/ext/ol-geocoder.js"></script>
<script type="text/javascript">
if (ol.Map.prototype.getLayer === undefined) {
ol.Map.prototype.getLayer = function (id) {
......
<html metal:use-macro="load: form_input.pt"
tal:define="home request.route_url('home')[:-1];">
tal:define="home request._host;">
<div metal:fill-slot="scripts">
<script tal:condition="${captcha}">
......
......@@ -13,12 +13,12 @@ from opensipkd.tools import (
)
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config
from .. import get_urls
# from unggah import DbUpload
def route_list(request, p={}):
q = dict_to_str(p)
return HTTPFound(location=request.route_url('upload-logo', _query=q))
return HTTPFound(location=get_urls(request.route_url('upload-logo', _query=q)))
##########
......
......@@ -47,6 +47,10 @@ class Views(BaseView):
self.edit_schema = EditSchema
self.add_schema = AddSchema
self.list_buttons = self.list_buttons + self.list_report
path = os.path.dirname(__file__)
path = os.path.dirname(path)
self.report_file = os.path.join(path, 'reports', 'users.jrxml')
def get_bindings(self, row=None):
status_list = (
......@@ -76,38 +80,38 @@ class Views(BaseView):
@view_config(
route_name='user-act', renderer='json', permission='user-view')
def view_act(self):
url_dict = self.req.matchdict
if url_dict['act'] == 'csv':
query = query_register()
row = query.first()
header = row.keys()
rows = [list(item) for item in query.all()]
filename = 'user.csv'
value = {
'header': header,
'rows': rows,
}
return csv_response(self.req, value, filename)
elif url_dict['act'] == 'pdf':
query = query_register()
import opensipkd.base
base_path = os.path.dirname(opensipkd.base.__file__)
path = os.path.join(base_path, 'reports')
rml_row = open_rml_row(path + '/user.row.rml')
rows = [rml_row.format(user_name=r.user_name, email=r.email,
registered_date=r.registered_date) for r in
query.all()]
pdf, filename = open_rml_pdf(path + '/user.rml', rows=rows,
company=self.req.company,
departement=self.req.departement,
address=self.req.address,
base_path=base_path)
filename = os.path.basename(filename)
resp = pdf_response(self.req, pdf, filename)
if resp.content_length < 10:
resp.content_length = len(resp.body)
return resp
# url_dict = self.req.matchdict
# if url_dict['act'] == 'csv':
# query = query_register()
# row = query.first()
# header = row.keys()
# rows = [list(item) for item in query.all()]
# filename = 'user.csv'
# value = {
# 'header': header,
# 'rows': rows,
# }
# return csv_response(self.req, value, filename)
#
# elif url_dict['act'] == 'pdf':
# query = query_register()
# import opensipkd.base
# base_path = os.path.dirname(opensipkd.base.__file__)
# path = os.path.join(base_path, 'reports')
# rml_row = open_rml_row(path + '/user.row.rml')
# rows = [rml_row.format(user_name=r.user_name, email=r.email,
# registered_date=r.registered_date) for r in
# query.all()]
# pdf, filename = open_rml_pdf(path + '/user.rml', rows=rows,
# company=self.req.company,
# departement=self.req.departement,
# address=self.req.address,
# base_path=base_path)
# filename = os.path.basename(filename)
# resp = pdf_response(self.req, pdf, filename)
# if resp.content_length < 10:
# resp.content_length = len(resp.body)
# return resp
return super(Views, self).view_act()
......@@ -347,7 +351,7 @@ class AddSchema(colander.Schema):
class EditSchema(AddSchema):
status = colander.SchemaNode(
colander.String(), widget=status_widget, title=_('Status'))
colander.String(), widget=widget.CheckboxWidget(true_val="1", false_val="0"), title=_('Status'))
def get_group_list():
......@@ -387,3 +391,33 @@ def query_register():
"DD-MM-YYYY").label(
"registered_date")).order_by(
User.user_name)
def user_list():
qry = User.query().order_by(User.user_name)
return [(r.id, r.user_name) for r in qry]
def user_select():
result = user_list()
result.insert(0, ('', 'Pilih User'))
return result
@colander.deferred
def user_widget(node, kw):
values = kw.get('user_list', [])
request = kw.get("request")
return widget.SelectWidget(values=values,
placeholder="Pilih User",
style="width:300px;")
class UserFilterSchema(colander.Schema):
user_id = colander.SchemaNode(
colander.Integer(),
widget=user_widget,
oid="user_id",
title="User",
missing=colander.drop,
)
......@@ -19,7 +19,7 @@ from opensipkd.models import (
UserGroup, )
from datatables import ColumnDT, DataTables
from .. import get_urls
SESS_ADD_FAILED = 'Tambah user gagal'
SESS_EDIT_FAILED = 'Edit user gagal'
......@@ -160,7 +160,7 @@ def save_request(values, request, row=None):
def route_list(request):
return HTTPFound(location=request.route_url('user-group'))
return HTTPFound(location=get_urls(request.route_url('user-group')))
def session_failed(request, session_name):
......@@ -186,7 +186,7 @@ def view_add(request):
c = form.validate(controls)
except ValidationFailure as e:
request.session[SESS_ADD_FAILED] = e.render()
return HTTPFound(location=request.route_url('user-group-add'))
return HTTPFound(location=get_urls(request.route_url('user-group-add')))
save_request(controls_dicted, request)
return route_list(request)
elif SESS_ADD_FAILED in request.session:
......@@ -225,8 +225,8 @@ def view_edit(request):
c = form.validate(controls)
except ValidationFailure as e:
request.session[SESS_EDIT_FAILED] = e.render()
return HTTPFound(location=request.route_url('user-group-edit',
id=row.id))
return HTTPFound(location=get_urls(request.route_url('user-group-edit',
id=row.id)))
save_request(dict(controls), request, row)
return route_list(request)
elif SESS_EDIT_FAILED in request.session:
......
......@@ -44,7 +44,7 @@ from pyramid_mailer.message import Message
from opensipkd.tools.buttons import btn_cancel
from opensipkd.tools.form_api import formfield2dict
from .. import get_urls
log = __import__("logging").getLogger(__name__)
......@@ -168,11 +168,11 @@ class ViewLogin(BaseView):
next_url = request.params.get('next', request.referrer)
login_tpl = get_params('login_tpl', 'templates/login.pt')
if not next_url:
next_url = request.route_url('home')
next_url = get_urls(request.route_url('home'))
if request.authenticated_userid: # (request):
request.session.flash('Anda sudah login', 'error')
return HTTPFound(location=f"{request.route_url('home')}")
return HTTPFound(location=get_urls(f"{request.route_url('home')}"))
schema = Login(validator=login_validator)
form = Form(schema, buttons=('login',))
......@@ -187,7 +187,7 @@ class ViewLogin(BaseView):
msg = 'Login gagal'
set_user_log(msg, request, log, identity)
request.session.flash(msg, 'error')
return HTTPFound(location=request.route_url('login'))
return HTTPFound(location=get_urls(request.route_url('login')))
values = dict(c)
# start cek external module
......@@ -206,19 +206,19 @@ class ViewLogin(BaseView):
except Exception as e:
log.warn(str(e))
request.session.flash(str(e), "error")
return HTTPFound(location=request.route_url('login'))
return HTTPFound(location=get_urls(request.route_url('login')))
else:
login = LoginUser(self.req)
if not login.login(values, user):
request.session.flash(login.message, "error")
next_url = f"{request.route_url('login')}?next={next_url}"
next_url = get_urls(f"{request.route_url('login')}?next={next_url}")
return HTTPFound(location=next_url)
return redirect_login(request, user)
elif 'register' in request.POST:
register_form = get_params("register_form", 'register')
return HTTPFound(location=request.route_url(register_form))
return HTTPFound(location=get_urls(request.route_url(register_form)))
elif 'login failed' in request.session:
r = dict(form=request.session['login failed'])
......@@ -236,13 +236,13 @@ class ViewLogin(BaseView):
login_tpl, dict(
form=form.render(),
message=message,
url=request.route_url('login'),
url=get_urls(request.route_url('login')),
next_url=next_url,
login=login, ),
request=request)
except Oauth2UserExc as e:
request.session.flash(str(e), 'error')
return HTTPFound(location=request.route_url('login'))
return HTTPFound(location=get_urls(request.route_url('login')))
if user and user.status == 1:
return redirect_login(request, user)
......@@ -250,7 +250,7 @@ class ViewLogin(BaseView):
if login_tpl == 'templates/login.pt':
return dict(form=form.render(),
message=message,
url=request.route_url('login'),
url=get_urls(request.route_url('login')),
next_url=next_url,
login=login, )
......@@ -259,7 +259,7 @@ class ViewLogin(BaseView):
request=request,
value=dict(form=form.render(),
message=message,
url=request.route_url('login'),
url=get_urls(request.route_url('login')),
next_url=next_url,
login=login, ),
)
......@@ -272,7 +272,7 @@ def redirect_login(request, user):
next_url = request.params.get('next')
if not next_url and request.matched_route.name == 'login':
url = get_params('modules_default', 'home')
return HTTPFound(location=request.route_url(url),
return HTTPFound(location=get_urls(request.route_url(url)),
headers=headers)
return HTTPFound(location=next_url, headers=headers)
......@@ -299,8 +299,8 @@ class Logout(BaseView):
form = self.get_form(LogoutSchema, buttons=(btn_cancel, btn_logout))
if 'cancel' in request.POST or "home" in request.POST:
log.info(request.route_url('home'))
return HTTPFound(location=f"{request.route_url('home')}", )
log.info(get_urls(request.route_url('home')))
return HTTPFound(location=get_urls(f"{request.route_url('home')}", ))
elif "logout" in request.POST:
form = self.get_form(LogoutSchema, buttons=(btn_home,))
......@@ -343,7 +343,7 @@ def change_password_validator(form, value):
def view_change_password(request):
if request.authenticated_userid:
request.session.flash('Anda sudah login', 'error')
return HTTPFound(location=f"{request.route_url('home')}")
return HTTPFound(location=get_urls(f"{request.route_url('home')}"))
schema = ChangePassword(validator=change_password_validator)
btn_save = Button('save', _('Simpan'))
......@@ -353,7 +353,7 @@ def view_change_password(request):
if not request.POST:
return dict(form=form.render())
if 'save' not in request.POST:
return HTTPFound(location=request.route_url('login'))
return HTTPFound(location=get_urls(request.route_url('login')))
items = request.POST.items()
try:
c = form.validate(items)
......@@ -365,7 +365,7 @@ def view_change_password(request):
if not user or \
create_now() - user.security_code_date > one_hour:
request.session.flash('Security code expired', 'error')
return HTTPFound(location=request.route_url('login'))
return HTTPFound(location=get_urls(request.route_url('login')))
user.security_code = None
UserService.set_password(user, c['new_password'])
......@@ -373,7 +373,7 @@ def view_change_password(request):
headers = get_login_headers(request, user)
request.session.flash('Password baru Anda sudah disimpan.')
set_user_log("Change Password", request, log)
return HTTPFound(location=f"{request.route_url('home')}", headers=headers)
return HTTPFound(location=get_urls(f"{request.route_url('home')}"), headers=headers)
######################
......@@ -403,12 +403,12 @@ def view_recreate_api_key(request):
d = dict(api_key=request.user.api_key)
return dict(form=form.render(appstruct=d))
if 'recreate' not in request.POST:
return HTTPFound(location=f"{request.route_url('home')}")
return HTTPFound(location=get_urls(f"{request.route_url('home')}"))
request.user.api_key = api_key = generate_api_key()
DBSession.add(request.user)
msg = 'API Key Anda yang baru {}'.format(api_key)
request.session.flash(msg)
return HTTPFound(location=f"{request.route_url('home')}")
return HTTPFound(location=get_urls(f"{request.route_url('home')}"))
##################
......@@ -432,7 +432,9 @@ def reset_password_validator(form, value):
def security_code_age(user):
now = create_now()
if user.security_code_date:
return now - user.security_code_date
return timedelta(minutes=1)
def send_email_security_code(
......@@ -508,7 +510,7 @@ def regenerate_security_code(user, hour=1.0):
renderer='templates/reset-password.pt')
def view_reset_password(request):
if request.authenticated_userid:
return HTTPFound(location=f"{request.route_url('home')}")
return HTTPFound(location=get_urls(f"{request.route_url('home')}"))
resp = dict(title=_('Reset password'))
schema = ResetPassword(validator=reset_password_validator)
......@@ -530,7 +532,7 @@ def view_reset_password(request):
send_email_security_code(
request, user, remain, 'Reset password', 'reset-password-body',
'reset-password-body.tpl')
return HTTPFound(location=request.route_url('reset-password-sent'))
return HTTPFound(location=get_urls(request.route_url('reset-password-sent')))
resp['form'] = form.render()
return resp
......
......@@ -3,8 +3,12 @@ import logging
from deform.widget import (
SchemaType,
DateInputWidget as DeformDateInputWidget)
from colander import null, Invalid
DateInputWidget as DeformDateInputWidget,
default_resources, ResourceRegistry, default_resource_registry, _StrippedString, Widget)
from colander import null, Invalid, SchemaNode, Mapping
_logging = logging.getLogger(__name__)
class _FieldStorage(SchemaType):
def deserialize(self, node, cstruct):
......@@ -16,52 +20,48 @@ class _FieldStorage(SchemaType):
return cstruct
class DateInputWidget(DeformDateInputWidget):
"""
Renders a date picker widget.
The default rendering is as a native HTML5 date input widget,
falling back to pickadate (https://github.com/amsul/pickadate.js.)
Most useful when the schema node is a ``colander.Date`` object.
**Attributes/Arguments**
options
Dictionary of options for configuring the widget (eg: date format)
template
The template name used to render the widget. Default:
``dateinput``.
readonly_template
The template name used to render the widget in read-only mode.
Default: ``readonly/textinput``.
"""
default_options = (
("format", "yyyy-mm-dd"),
("selectMonths", True),
("selectYears", True),
("formatSubmit", "yyyy-mm-dd"),
)
def serialize(self, field, cstruct, **kw):
if cstruct in (null, None):
cstruct = ""
readonly = kw.get("readonly", self.readonly)
template = readonly and self.readonly_template or self.template
options = dict(
kw.get("options") or self.options or self.default_options
)
kw.setdefault("options_json", json.dumps(options))
values = self.get_template_values(field, cstruct, kw)
return field.renderer(template, **values)
def deserialize(self, field, pstruct):
logging.debug(f"widget: {field} {pstruct}")
if pstruct in ("", null):
return null
try:
validated = self._pstruct_schema.deserialize(pstruct)
except Invalid as exc:
raise Invalid(field.schema, "Invalid pstruct: %s" % exc)
return validated["date_submit"] or validated["date"]
# default_resources = {
# "jquery.form": {None: {"js": "deform:static/scripts/jquery.form-3.09.js"}},
# "jquery.maskedinput": {
# None: {"js": "deform:static/scripts/jquery.maskedinput-1.3.1.min.js"}
# },
# "jquery.maskMoney": {
# None: {"js": "deform:static/scripts/jquery.maskMoney-3.1.1.min.js"}
# },
# "deform": {
# None: {
# "js": (
# "deform:static/scripts/jquery.form-3.09.js",
# "deform:static/scripts/deform.js",
# )
# }
# },
# "typeahead": {
# None: {
# "js": "deform:static/scripts/typeahead.min.js",
# "css": "deform:static/css/typeahead.css",
# }
# },
# "modernizr": {
# None: {
# "js": "deform:static/scripts/modernizr.custom.input-types-and-atts.js" # noQA
# }
# },
# "pickadate": {
# None: {
# "js": (
# "static/pickadate/lib/picker.js",
# "static/pickadate/lib/picker.date.js",
# "static/pickadate/lib/picker.time.js",
# "static/pickadate/lib/legacy.js",
# ),
# "css": (
# "static/pickadate/lib/themes/default.css",
# "static/pickadate/lib/themes/default.date.css",
# "static/pickadate/lib/themes/default.time.css",
# ),
# }
# },
# }
#
# default_resource_registry = ResourceRegistry()
import json
import logging
from colander import SchemaNode, null, Mapping, Invalid, text_, string_types
from deform.widget import Widget, _StrippedString, Select2Widget
from colander import SchemaNode, null, Mapping, Invalid, string_types
from deform.widget import Widget, _StrippedString, Select2Widget, default_resources, \
ResourceRegistry, default_resource_registry
from deform.form import Button
from iso8601.iso8601 import ISO8601_REGEX
from deform.i18n import _
from colander import compat
from deform import widget
_logging = logging.getLogger(__name__)
......@@ -46,7 +51,7 @@ class DokumenWidget(Widget):
try:
validated = self._pstruct_schema.deserialize(pstruct)
except Invalid as exc:
raise Invalid(field.schema, text_("Invalid pstruct: %s" % exc))
raise Invalid(field.schema, f"Invalid pstruct: {exc}")
jenis = validated["jenis"]
year = validated["year"]
bundle = validated["bundle"]
......@@ -101,7 +106,7 @@ class FormulirWidget(Widget):
try:
validated = self._pstruct_schema.deserialize(pstruct)
except Invalid as exc:
raise Invalid(field.schema, text_("Invalid pstruct: %s" % exc))
raise Invalid(field.schema, f"Invalid pstruct: {exc}")
year = validated["year"]
bundle = validated["bundle"]
seq = validated["seq"]
......@@ -154,7 +159,7 @@ class BlokKavNoWidget(Widget):
try:
validated = self._pstruct_schema.deserialize(pstruct)
except Invalid as exc:
raise Invalid(field.schema, text_("Invalid pstruct: %s" % exc))
raise Invalid(field.schema, f"Invalid pstruct: {exc}")
blok_kav_no = validated["blok_kav_no"]
rt = validated["rt"]
rw = validated["rw"]
......@@ -187,6 +192,8 @@ class Select2MsWidget(Select2Widget):
"""
url = ""
slave = ""
template = "select2_ms.pt"
......@@ -221,7 +228,7 @@ class QtyWidget(Widget):
try:
validated = self._pstruct_schema.deserialize(pstruct)
except Invalid as exc:
raise Invalid(field.schema, text_("Invalid pstruct: %s" % exc))
raise Invalid(field.schema, f"Invalid pstruct: {exc}")
qty = validated["qty"]
measure = validated["measure"]
......@@ -493,3 +500,206 @@ class LeafMapWidget(Widget):
if not pstruct:
return null
return pstruct
class BootStrapDateInputWidget(Widget):
"""
Renders a date picker widget.
The default rendering is as a native HTML5 date input widget,
falling back to pickadate (https://github.com/amsul/pickadate.js.)
Most useful when the schema node is a ``colander.Date`` object.
**Attributes/Arguments**
options
Dictionary of options for configuring the widget (eg: date format)
template
The template name used to render the widget. Default:
``dateinput``.
readonly_template
The template name used to render the widget in read-only mode.
Default: ``readonly/textinput``.
"""
template = "bootstrapdateinput"
readonly_template = "readonly/textinput"
type_name = "text"
req_path = "opensipkd.base:static/v3/js/plugin"
requirements = (
('deform', None),
{
"js": (
f"{req_path}/bootstrap-datepicker/js/bootstrap-datepicker.min.js",
f"{req_path}/bootstrap-timepicker/bootstrap-timepicker.min.js",
f"{req_path}/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js",
),
"css": (
f"{req_path}/bootstrap-datepicker/css/bootstrap-datepicker.min.css",
# f"{req_path}/bootstrap-timepicker/css/bootstrap-timepicker.min.css",
f"{req_path}/bootstrap-datetimepicker/css/bootstrap-datetimepicker.min.css",
),
}
)
default_options = (
("format", "yyyy-mm-dd"),
)
# ("selectMonths", True),
# ("selectYears", True),
options = None
_pstruct_schema = SchemaNode(
Mapping(),
SchemaNode(_StrippedString(), name="date"),
SchemaNode(_StrippedString(), name="date_submit", missing=""),
)
def serialize(self, field, cstruct, **kw):
if cstruct in (null, None):
cstruct = ""
readonly = kw.get("readonly", self.readonly)
template = readonly and self.readonly_template or self.template
options = dict(
kw.get("options") or self.options or self.default_options
)
options["formatSubmit"] = "yyyy-mm-dd"
kw.setdefault("options_json", json.dumps(options))
values = self.get_template_values(field, cstruct, kw)
return field.renderer(template, **values)
def deserialize(self, field, pstruct):
if pstruct in ("", null):
return null
try:
validated = self._pstruct_schema.deserialize(pstruct)
except Invalid as exc:
raise Invalid(field.schema, "Invalid pstruct: %s" % exc)
return validated["date_submit"] or validated["date"]
class BootStrapDateTimeInputWidget(Widget):
"""
Renders a datetime picker widget.
The default rendering is as a pair of inputs (a date and a time) using
pickadate.js (https://github.com/amsul/pickadate.js).
Used for ``colander.DateTime`` schema nodes.
**Attributes/Arguments**
date_options
A dictionary of date options passed to pickadate.
time_options
A dictionary of time options passed to pickadate.
template
The template name used to render the widget. Default:
``dateinput``.
readonly_template
The template name used to render the widget in read-only mode.
Default: ``readonly/textinput``.
"""
template = "datetimeinput"
readonly_template = "readonly/datetimeinput"
type_name = "datetime"
requirements = (("modernizr", None), ("pickadate", None))
default_date_options = (
("format", "yyyy-mm-dd"),
("selectMonths", True),
("selectYears", True),
)
date_options = None
default_time_options = (("format", "h:i A"), ("interval", 30))
time_options = None
_pstruct_schema = SchemaNode(
Mapping(),
SchemaNode(_StrippedString(), name="date"),
SchemaNode(_StrippedString(), name="time"),
SchemaNode(_StrippedString(), name="date_submit", missing=""),
SchemaNode(_StrippedString(), name="time_submit", missing=""),
)
def serialize(self, field, cstruct, **kw):
if cstruct in (null, None):
cstruct = ""
readonly = kw.get("readonly", self.readonly)
if cstruct:
parsed = ISO8601_REGEX.match(cstruct)
if parsed: # strip timezone if it's there
timezone = parsed.groupdict()["timezone"]
if timezone and cstruct.endswith(timezone):
cstruct = cstruct[: -len(timezone)]
try:
date, time = cstruct.split("T", 1)
try:
# get rid of milliseconds
time, _ = time.split(".", 1)
except ValueError:
pass
kw["date"], kw["time"] = date, time
except ValueError: # need more than one item to unpack
kw["date"] = kw["time"] = ""
date_options = dict(
kw.get("date_options")
or self.date_options
or self.default_date_options
)
date_options["formatSubmit"] = "yyyy-mm-dd"
kw["date_options_json"] = json.dumps(date_options)
time_options = dict(
kw.get("time_options")
or self.time_options
or self.default_time_options
)
time_options["formatSubmit"] = "HH:i"
kw["time_options_json"] = json.dumps(time_options)
values = self.get_template_values(field, cstruct, kw)
template = readonly and self.readonly_template or self.template
return field.renderer(template, **values)
def deserialize(self, field, pstruct):
if pstruct is null:
return null
else:
try:
validated = self._pstruct_schema.deserialize(pstruct)
except Invalid as exc:
raise Invalid(field.schema, "Invalid pstruct: %s" % exc)
# seriously pickadate? oh. right. i forgot. you're javascript.
date = validated["date_submit"] or validated["date"]
time = validated["time_submit"] or validated["time"]
if not time and not date:
return null
result = "T".join([date, time])
if not date:
raise Invalid(field.schema, _("Incomplete date"), result)
if not time:
raise Invalid(field.schema, _("Incomplete time"), result)
return result
class TextInputWidget(widget.TextInputWidget):
template = "textinput_btn"
button = None
def __init__(self, **kw):
super(TextInputWidget, self).__init__(**kw)
if isinstance(self.button, compat.string_types):
self.button = Button(self.button, type="button")
<div tal:define="css_class css_class|field.widget.css_class;
oid oid|field.oid;
style style|field.widget.style;
type_name type_name|field.widget.type_name;"
tal:omit-tag="">
${field.start_mapping()}
<input type="${type_name}"
name="date"
value="${cstruct}"
tal:attributes="class string: ${css_class or ''} form-control hasDatepicker;
style style;
attributes|field.widget.attributes|{'readonly':'true'};"
id="${oid}"/>
${field.end_mapping()}
<script type="text/javascript">
deform.addCallback(
'${oid}',
function deform_cb(oid) {
$('#'+oid).datepicker(${options_json});
//if (!Modernizr.inputtypes['date'] ||"${type_name}" != "date" || window.forceDateTimePolyfill){
// $('#' + oid).pickadate(${options_json});
//}
}
);
</script>
</div>
......@@ -2,12 +2,12 @@
oid oid|field.oid;
true_val true_val|field.widget.true_val;"
i18n:domain="deform">
<p class="deform-readonly-true form-control-static"
<p class="deform-readonly-true"
id="${oid}"
tal:condition="cstruct == true_val"
i18n:translate="">True</p>
<p class="deform-readonly-false form-control-static"
i18n:translate=""><i class="fas fa-check-square" aria-hidden="true"></i></p>
<p class="deform-readonly-false"
id="${oid}"
tal:condition="cstruct != true_val"
i18n:translate="">False</p>
i18n:translate=""><i class="fas fa-window-close" aria-hidden="true"></i></p>
</div>
......@@ -55,10 +55,10 @@
<script type="text/javascript">
deform.addCallback(
'${field.oid}',
function(oid) {
function (oid) {
$('#' + oid).select2({
containerCssClass: 'form-control',
placeholder: "${str(field.widget.placeholder).replace('"','\\"')|""}" || undefined,
placeholder: "${str(field.widget.placeholder).replace('"','\\"')|""}" || undefined,
allowClear: "${hasattr(field.widget, 'placeholder')}",
tags: ${str(getattr(field.widget, 'tags', 'undefined')).lower()}
});
......@@ -68,7 +68,7 @@
<script type="text/javascript" tal:condition="url and slave">
deform.addCallback(
'${field.oid}',
function(oid) {
function (oid) {
$('#' + oid).change(function () {
$("#${slave}").val("");
$("#${slave}").empty();
......
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
mask mask|field.widget.mask;
button button|field.widget.button;
mask_placeholder mask_placeholder|field.widget.mask_placeholder;
style style|field.widget.style;
" tal:omit-tag="">
<input type="text" tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};" id="${oid}" name="${name}" value="${cstruct}"
tal:condition="not button" />
<div class="input-group" tal:condition="button">
<input type="text" name="${name}" value="${cstruct}" tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};" id="${oid}" />
<span class="input-group-btn">
<button tal:define="btn_disposition 'btn-default';" tal:attributes="disabled button.disabled if button.disabled else None;
attributes|button.attributes|{};" id="${oid+button.name}" name="${button.name}"
type="${button.type}" class="btn ${button.css_class or btn_disposition}" value="${button.value}"
tal:condition="button.type != 'link'">
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span>
${button.title}
</button>
<a tal:define="btn_disposition 'btn-default';
btn_href button.value|''" class="btn ${button.css_class or btn_disposition}" id="${oid + button.name}"
href="${btn_href}" tal:condition="button.type == 'link'">
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span>
${button.title}
</a>
</span>
</div><!-- /input-group -->
<script tal:condition="mask" type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).mask("${mask}",
{ placeholder: "${mask_placeholder}" });
});
</script>
</span>
\ No newline at end of file
......@@ -109,6 +109,7 @@ class DeTable(field.Field):
paginates='true',
params="",
server_side='true',
state_save=True,
data=[],
allow_edit=True,
allow_delete=True,
......@@ -246,6 +247,7 @@ class DeTable(field.Field):
self.sorts = sorts
self.paginates = paginates
self.filters = filters
self.state_save = json.dumps(state_save)
class Button(object):
......
......@@ -19,6 +19,7 @@
allow_edit allow_edit|field.allow_edit;
allow_delete allow_delete|field.allow_delete;
allow_view allow_view|field.allow_view;
state_save state_save|field.state_save;
"
tal:attributes="style style; class css_class; attributes|field.widget.attributes|{};"
i18n:domain="detable"
......@@ -68,6 +69,10 @@
return 'Archived';
}
function render_checklist(value) {
return '<input type="checkbox" checked="'+{value}+'"></input>';
}
for (let co in ${tableid}Columns) {
if (${tableid}Columns[co].checkbox === true) {
${tableid}Columns[co].className = "text-center";
......@@ -77,7 +82,8 @@
return render_checkbox(true);
} else return render_checkbox(false);
}
} else if (${tableid}Columns[co].hasOwnProperty("url")) {
}
else if (${tableid}Columns[co].hasOwnProperty("url")) {
let url = ${tableid}Columns[co].url;
${tableid}Columns[co].render = function (data) {
let result = "No Data"
......@@ -86,7 +92,8 @@
}
return result;
}
} else if (${tableid}Columns[co].data === "id" && ${tableid}Columns[co].action === true) {
}
else if (${tableid}Columns[co].data === "id" && ${tableid}Columns[co].action === true) {
${tableid}Columns[co].render = function (id) {
let result = ""
if (${allow_view}) {
......@@ -108,6 +115,7 @@
}
}
let ${tableid}Language = {
"search": "Cari: ",
"paginate": {
......@@ -122,7 +130,7 @@
dom: '<"row"<"col-md-8"<"toolbar">Bl><"col-md-4"fr>>tip',
processing: true,
serverSide: ${server_side},
stateSave: false,
stateSave: ${state_save},
scrollCollapse: true,
sort: ${sorts},
info: false,
......@@ -141,7 +149,8 @@
}
if (!${server_side}) {
${tableid}Params.data = ${data};
} else {
}
else {
${tableid}Params.ajax = o${tableid}Url;
}
o${tableid} = $('#${tableid}').DataTable(${tableid}Params);
......
......@@ -99,6 +99,13 @@ class DefaultModel(CommonModel):
return query
@classmethod
def query_from(cls, db_session=DBSession, columns=None, filters=None):
query = db_session.query().select_from(cls)
for c in columns:
query = query.add_columns(c)
return query
@classmethod
def query_id(cls, row_id, db_session=DBSession):
return cls.query(db_session).filter_by(id=row_id)
......@@ -106,6 +113,11 @@ class DefaultModel(CommonModel):
def delete(cls, row_id, db_session=DBSession):
cls.query_id(row_id, db_session).delete()
@classmethod
def flush(cls, row, db_session=DBSession):
db_session.add(row)
db_session.flush()
class StandarModel(DefaultModel):
status = Column(SmallInteger, nullable=False, default=0)
......
......@@ -67,7 +67,7 @@ class UserResourcePermission(UserResourcePermissionMixin, Base):
pass
class User(UserMixin, BaseModel, CommonModel, Base):
class User(UserMixin, BaseModel, DefaultModel, Base):
last_login_date = Column(DateTime(timezone=True), nullable=True)
registered_date = Column(DateTime(timezone=True),
nullable=False,
......@@ -107,9 +107,9 @@ class User(UserMixin, BaseModel, CommonModel, Base):
def kode(self):
pass
@classmethod
def query(cls):
return DBSession.query(cls)
# @classmethod
# def query(cls):
# return DBSession.query(cls)
@classmethod
def get_by_email(cls, email):
......@@ -129,6 +129,11 @@ class User(UserMixin, BaseModel, CommonModel, Base):
def get_by_token(cls, token):
return DBSession.query(cls).filter_by(security_code=token)
@classmethod
def query_register(cls):
return cls.query_from(columns=[cls.email, cls.user_name, cls.registered_date,
cls.last_login_date])
# @classmethod
# def get_departemen_id(cls, user_id):
......@@ -172,6 +177,9 @@ class ExternalIdentity(ExternalIdentityMixin, CommonModel, Base):
return cls.query().filter_by(local_user_id=user.id)
@classmethod
@classmethod
def external(cls, user):
return cls.query_user(user).count()>0
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!