├── .jshintrc ├── .gitignore ├── .travis.yml ├── dist ├── kendo-pouchdb.amd.min.js ├── kendo-pouchdb.min.js └── kendo-pouchdb.min.js.map ├── kendo-pouchdb.amd.js ├── Chutzpah.json ├── bower.json ├── LICENSE ├── package.json ├── tests ├── SpecRunner.html ├── testHelper.js └── spec │ └── pouchdb-findSpec.js ├── Gruntfile.js ├── KendoPouchDB.sln ├── vendor └── kendo │ ├── kendo.data.signalr.js │ ├── kendo.data.xml.js │ ├── kendo.data.odata.js │ ├── kendo.editable.js │ ├── kendo.selectable.js │ ├── kendo.pager.js │ ├── kendo.validator.js │ ├── kendo.userevents.js │ ├── kendo.datepicker.js │ └── kendo.numerictextbox.js ├── demo ├── kendo-pouchdb-paging.html ├── kendo-pouchdb-grid.html └── kendo-pouchdb-sort.html └── README.md /.jshintrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terikon/kendo-pouchdb/HEAD/.jshintrc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .grunt/ 4 | *.suo 5 | vwd.webinfo -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | before_script: 5 | - npm install -g grunt-cli 6 | notifications: 7 | email: false 8 | -------------------------------------------------------------------------------- /dist/kendo-pouchdb.amd.min.js: -------------------------------------------------------------------------------- 1 | /* kendo-pouchdb.amd v0.1.5 01-08-2015 (C) 2015 Terikon Apps */ 2 | define(["kendo","kendo-pouchdb"],function(a){"use strict";return a}); -------------------------------------------------------------------------------- /kendo-pouchdb.amd.js: -------------------------------------------------------------------------------- 1 | /* global define */ 2 | 3 | //Loads kendo-pouchdb after kendo library for AMD. 4 | //To be used with map option of RequireJS configuration: 5 | // shim: { 6 | // "kendo-pouchdb.amd": { deps: ["kendo"] } 7 | // }, 8 | // map: { 9 | // '*': { 10 | // 'kendo': 'kendo-pouchdb.amd' 11 | // }, 12 | // 'kendo-pouchdb.amd': { 'kendo': 'kendo' } 13 | // } 14 | define(['kendo', 'kendo-pouchdb'], function (kendo) { 15 | 'use strict'; 16 | return kendo; 17 | }); -------------------------------------------------------------------------------- /Chutzpah.json: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "http://json.schemastore.org/chutzpah", 3 | "Framework": "jasmine", 4 | "TestFileTimeout": 5000, 5 | "TestHarnessReferenceMode": "Normal", 6 | "TestHarnessLocationMode": "Custom", 7 | "TestHarnessDirectory": "node_modules/jasmine-core/lib/jasmine-core", 8 | "RootReferencePathMode": "SettingsFileDirectory", 9 | "References": [ 10 | { "Path": "node_modules/jquery/dist/jquery.min.js" }, 11 | { "Path": "node_modules/underscore/underscore-min.js" }, 12 | { "Path": "vendor/kendo/kendo.core.js" }, 13 | { "Path": "vendor/kendo/kendo.data.js" }, 14 | { "Path": "node_modules/pouchdb/dist/pouchdb.js" }, 15 | { "Path": "node_modules/pouchdb-collate/dist/pouchdb-collate.js" }, 16 | { "Path": "node_modules/pouchdb-find/dist/pouchdb.find.js" }, 17 | { "Path": "kendo-pouchdb.js" }, 18 | { "Path": "tests/testHelper.js" } 19 | ], 20 | "Tests": [ 21 | { "Path": "tests/spec", "Include": "*Spec.js" } 22 | ] 23 | } -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kendo-pouchdb", 3 | "main": "kendo-pouchdb.js", 4 | "version": "0.1.6", 5 | "description": "Kendo UI adapter for PouchDB", 6 | 7 | "homepage": "https://github.com/terikon/kendo-pouchdb", 8 | "authors": [{ 9 | "name": "Terikon Apps", 10 | "email": "npm@terikon.com", 11 | "homepage": "http://il.linkedin.com/in/romanviskin" 12 | }], 13 | 14 | "moduleType": [ 15 | "amd", 16 | "globals" 17 | ], 18 | 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/terikon/kendo-pouchdb.git" 22 | }, 23 | 24 | "keywords": [ 25 | "Kendo", 26 | "Kendo UI", 27 | "PouchDB", 28 | "DataSource", 29 | "CouchDB", 30 | "Couchbase", 31 | "Cloudant" 32 | ], 33 | 34 | "license": "MIT", 35 | 36 | "dependencies": { 37 | "jquery": "^2.1.4", 38 | "pouchdb": "^4.0.0", 39 | "pouchdb-collate": "^1.2.0", 40 | "pouchdb-find": "^0.4.0" 41 | }, 42 | 43 | "ignore": [ 44 | "**/.*", 45 | "node_modules", 46 | "bower_components", 47 | "tests" 48 | ] 49 | 50 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Terikon Software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kendo-pouchdb", 3 | "title": "kendoPouchDB", 4 | "version": "0.1.6", 5 | "description": "Kendo UI adapter for PouchDB", 6 | "main": "kendo-pouchdb.js", 7 | "scripts": { 8 | "//": "use '|| true' to prevent warning", 9 | "build": "npm install && grunt", 10 | "test": "grunt test", 11 | "jshint": "grunt jshint && grunt kendo_lint" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/terikon/kendo-pouchdb.git" 16 | }, 17 | "keywords": [ 18 | "Kendo", 19 | "Kendo UI", 20 | "PouchDB", 21 | "DataSource", 22 | "CouchDB", 23 | "Couchbase", 24 | "Cloudant" 25 | ], 26 | "author": { 27 | "name": "Terikon Apps", 28 | "email": "npm@terikon.com", 29 | "url": "http://il.linkedin.com/in/romanviskin" 30 | }, 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/terikon/kendo-pouchdb/issues" 34 | }, 35 | "homepage": "https://github.com/terikon/kendo-pouchdb", 36 | "dependencies": { 37 | "jasmine-core": "^2.3.4", 38 | "jquery": "^2.1.4", 39 | "pouchdb": "^4.0.0", 40 | "pouchdb-collate": "^1.2.0", 41 | "pouchdb-find": "^0.4.0" 42 | }, 43 | "devDependencies": { 44 | "grunt": "^0.4.5", 45 | "grunt-contrib-uglify": "^0.9.1", 46 | "grunt-contrib-jshint": "^0.11.1", 47 | "grunt-contrib-jasmine": "^0.9.0", 48 | "underscore": "^1.8.3", 49 | "grunt-kendo-lint": "~0.0.3", 50 | "load-grunt-tasks": "~3.3.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/SpecRunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jasmine Spec Runner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | // Load grunt tasks automatically 4 | require('load-grunt-tasks')(grunt); 5 | 6 | var lintFiles = ['Gruntfile.js', 'kendo-pouchdb.js', 'kendo-pouchdb.amd.js', 7 | 'tests/spec/*.js', 'tests/*.js' 8 | ]; 9 | 10 | grunt.initConfig({ 11 | 12 | pkg: grunt.file.readJSON('package.json'), 13 | 14 | uglify: { 15 | options: { 16 | sourceMap: true, 17 | banner: '/* <%= grunt.task.current.target %> v<%= pkg.version %> <%= grunt.template.today("dd-mm-yyyy") %> (C) 2015 Terikon Apps */\n' 18 | }, 19 | 'kendo-pouchdb': { 20 | src: 'kendo-pouchdb.js', 21 | dest: 'dist/kendo-pouchdb.min.js' 22 | }, 23 | 'kendo-pouchdb.amd': { 24 | options: { 25 | sourceMap: false, 26 | }, 27 | src: 'kendo-pouchdb.amd.js', 28 | dest: 'dist/kendo-pouchdb.amd.min.js' 29 | } 30 | }, 31 | 32 | jshint: { 33 | all: lintFiles 34 | }, 35 | 36 | kendo_lint: { 37 | options: { 38 | force: true 39 | }, 40 | files: lintFiles 41 | }, 42 | 43 | jasmine: { 44 | all: { 45 | src: ['kendo-pouchdb.js', 'tests/testHelper.js'], 46 | options: { 47 | specs: 'tests/spec/*Spec.js', 48 | vendor: [ 49 | 'node_modules/jquery/dist/jquery.min.js', 50 | 'node_modules/underscore/underscore-min.js', 51 | 'vendor/kendo/kendo.core.js', 52 | 'vendor/kendo/kendo.data.js', 53 | 'node_modules/pouchdb/dist/pouchdb.js', 54 | 'node_modules/pouchdb-collate/dist/pouchdb-collate.js', 55 | 'node_modules/pouchdb-find/dist/pouchdb.find.js' 56 | ] 57 | } 58 | } 59 | } 60 | 61 | }); 62 | 63 | grunt.registerTask('default', ['uglify']); 64 | grunt.registerTask('test', ['jasmine']); 65 | }; -------------------------------------------------------------------------------- /tests/testHelper.js: -------------------------------------------------------------------------------- 1 | /* global $,kendo,PouchDB */ 2 | 3 | var testHelper = testHelper || {}; 4 | 5 | //Returns event spy {events:array, dispose:function, reset:function}. 6 | //events[i] is {e:*}. 7 | testHelper.spyKendoEvent = function (instance, eventName) { 8 | 'use strict'; 9 | 10 | var handler = function (e) { 11 | var copy = $.extend(true, {}, e); 12 | result.events.push({ e: copy }); 13 | }, 14 | dispose = function () { 15 | instance.unbind(eventName, handler); 16 | this.reset(); 17 | }, 18 | reset = function () { 19 | result.events = []; 20 | }, 21 | result = { 22 | events: [], 23 | dispose: dispose, 24 | reset: reset 25 | }; 26 | 27 | instance.bind(eventName, handler); 28 | 29 | return result; 30 | }; 31 | 32 | //Returns promise that resolves when change event occurs on PouchDB specified number of times. 33 | testHelper.waitForDbChanges = function (db, numberOfChanges) { 34 | var counter = 0, 35 | deferred = new $.Deferred(), 36 | handler = function () { 37 | counter++; 38 | if (counter === numberOfChanges) { 39 | changes.removeListener("change", handler); 40 | deferred.resolve(); 41 | } 42 | }, 43 | changes = db.changes({ 44 | since: 'now', 45 | live: true 46 | }); 47 | 48 | changes.on("change", handler); 49 | 50 | return deferred.promise(); 51 | }; 52 | 53 | testHelper.addArrayToDataSource = function (dataSource, rows) { 54 | $.each(rows, function (_, row) { 55 | dataSource.add(row); 56 | }); 57 | }; 58 | -------------------------------------------------------------------------------- /KendoPouchDB.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.40629.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "kendo-pouchdb", "http://localhost:31835", "{F68DAF24-C583-4B97-8FD6-3C456A31BE00}" 7 | ProjectSection(WebsiteProperties) = preProject 8 | UseIISExpress = "true" 9 | TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.0" 10 | Debug.AspNetCompiler.VirtualPath = "/localhost_31835" 11 | Debug.AspNetCompiler.PhysicalPath = ".\" 12 | Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_31835\" 13 | Debug.AspNetCompiler.Updateable = "true" 14 | Debug.AspNetCompiler.ForceOverwrite = "true" 15 | Debug.AspNetCompiler.FixedNames = "false" 16 | Debug.AspNetCompiler.Debug = "True" 17 | Release.AspNetCompiler.VirtualPath = "/localhost_31835" 18 | Release.AspNetCompiler.PhysicalPath = ".\" 19 | Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_31835\" 20 | Release.AspNetCompiler.Updateable = "true" 21 | Release.AspNetCompiler.ForceOverwrite = "true" 22 | Release.AspNetCompiler.FixedNames = "false" 23 | Release.AspNetCompiler.Debug = "False" 24 | SlnRelativePath = ".\" 25 | EndProjectSection 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | EndGlobalSection 31 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 32 | {F68DAF24-C583-4B97-8FD6-3C456A31BE00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {F68DAF24-C583-4B97-8FD6-3C456A31BE00}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | EndGlobal 39 | -------------------------------------------------------------------------------- /vendor/kendo/kendo.data.signalr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.data" ], f); 19 | })(function(){ 20 | 21 | (function($) { 22 | var transport = kendo.data.RemoteTransport.extend({ 23 | init: function (options) { 24 | var signalr = options && options.signalr ? options.signalr : {}; 25 | 26 | var promise = signalr.promise; 27 | 28 | if (!promise) { 29 | throw new Error('The "promise" option must be set.'); 30 | } 31 | 32 | if (typeof promise.done != "function" || typeof promise.fail != "function") { 33 | throw new Error('The "promise" option must be a Promise.'); 34 | } 35 | 36 | this.promise = promise; 37 | 38 | var hub = signalr.hub; 39 | 40 | if (!hub) { 41 | throw new Error('The "hub" option must be set.'); 42 | } 43 | 44 | if (typeof hub.on != "function" || typeof hub.invoke != "function") { 45 | throw new Error('The "hub" option is not a valid SignalR hub proxy.'); 46 | } 47 | 48 | this.hub = hub; 49 | 50 | kendo.data.RemoteTransport.fn.init.call(this, options); 51 | }, 52 | 53 | push: function(callbacks) { 54 | var client = this.options.signalr.client || {}; 55 | 56 | if (client.create) { 57 | this.hub.on(client.create, callbacks.pushCreate); 58 | } 59 | 60 | if (client.update) { 61 | this.hub.on(client.update, callbacks.pushUpdate); 62 | } 63 | 64 | if (client.destroy) { 65 | this.hub.on(client.destroy, callbacks.pushDestroy); 66 | } 67 | }, 68 | 69 | _crud: function(options, type) { 70 | var hub = this.hub; 71 | 72 | var server = this.options.signalr.server; 73 | 74 | if (!server || !server[type]) { 75 | throw new Error(kendo.format('The "server.{0}" option must be set.', type)); 76 | } 77 | 78 | var args = [server[type]]; 79 | 80 | var data = this.parameterMap(options.data, type); 81 | 82 | if (!$.isEmptyObject(data)) { 83 | args.push(data); 84 | } 85 | 86 | this.promise.done(function() { 87 | hub.invoke.apply(hub, args) 88 | .done(options.success) 89 | .fail(options.error); 90 | }); 91 | }, 92 | 93 | read: function(options) { 94 | this._crud(options, "read"); 95 | }, 96 | 97 | create: function(options) { 98 | this._crud(options, "create"); 99 | }, 100 | 101 | update: function(options) { 102 | this._crud(options, "update"); 103 | }, 104 | 105 | destroy: function(options) { 106 | this._crud(options, "destroy"); 107 | } 108 | }); 109 | 110 | $.extend(true, kendo.data, { 111 | transports: { 112 | signalr: transport 113 | } 114 | }); 115 | 116 | })(window.kendo.jQuery); 117 | 118 | return window.kendo; 119 | 120 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); -------------------------------------------------------------------------------- /demo/kendo-pouchdb-paging.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | kendo-pouchdb paging demo 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 108 | 109 | 110 | 111 |
112 |

This Kendo UI Grid is bound to PouchDB database. You can use paging.

113 |
114 |
115 | 116 |
117 | 118 |
119 |
120 |
121 | 122 |
123 | Go to kendo-pouchdb github page for more information. 124 |
125 | 126 | 127 | -------------------------------------------------------------------------------- /demo/kendo-pouchdb-grid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | kendo-pouchdb demo 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 106 | 107 | 108 | 109 |
110 |

This Kendo UI Grid is bound to PouchDB database. As you modify the data, it will be persisted. Reload the page to see for yourself.

111 |

Use PouchDB inspector to modify demodb database. Modifications will appear immediately.

112 |
113 |
114 | 115 |
116 | 117 |
118 |
119 |
120 | 121 |
122 | Go to kendo-pouchdb github page for more information. 123 |
124 | 125 | 126 | -------------------------------------------------------------------------------- /demo/kendo-pouchdb-sort.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | kendo-pouchdb sort demo 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 143 | 144 | 145 | 146 |
147 |

This Kendo UI Grid is bound to PouchDB database. You can sort by clicking column name, configured PouchDB view will be used.

148 |
149 |
150 | 151 |
152 | 153 |
154 |
155 |
156 | 157 |
158 | Go to kendo-pouchdb github page for more information. 159 |
160 | 161 | 162 | -------------------------------------------------------------------------------- /tests/spec/pouchdb-findSpec.js: -------------------------------------------------------------------------------- 1 | /* global kendo,PouchDB */ 2 | 3 | describe("pouchdb-find", function () { 4 | 5 | var db; 6 | 7 | beforeEach(function (done) { 8 | new PouchDB('testdb') 9 | .then(function (dbToDestroy) { 10 | return dbToDestroy.destroy(); 11 | }) 12 | .then(function () { 13 | return new PouchDB('testdb').then(function (createdDb) { 14 | db = createdDb; 15 | done(); 16 | }); 17 | }) 18 | .catch(function (error) { 19 | console.log("PouchDB database creation error:" + error.message); 20 | }); 21 | }); 22 | 23 | describe("fill datasource with data", function () { 24 | 25 | var createDatasourceDoc = function (num, id, name, debut, series) { 26 | return { 27 | //here _id should be undefined 28 | num: num, 29 | id: id, 30 | name: name, 31 | debut: debut, 32 | series: series 33 | }; 34 | }, 35 | createDbDoc = function (idField, num, id, name, debut, series) { 36 | var doc = createDatasourceDoc(num, id, name, debut, series); 37 | doc._id = idField === "num" ? pouchCollate.toIndexableString(doc[idField]) : doc[idField]; 38 | return doc; 39 | }, 40 | docs; 41 | 42 | beforeEach(function (done) { 43 | 44 | docs = [ 45 | createDbDoc("id", 1, "falcon", "Captain Falcon", 1990, "F-Zero"), 46 | createDbDoc("id", 4, "yoshi", "Yoshi", 1990, "Mario"), 47 | createDbDoc("id", 3, "fox", "Fox", 1993, "Star Fox"), 48 | createDbDoc("id", 2, "link", "Link", 1986, "Zelda"), 49 | createDbDoc("id", 5, "ness", "Ness", 1994, "Earthbound"), 50 | createDbDoc("id", 12, "kirby", "Kirby", 1992, "Kirby"), 51 | createDbDoc("id", 11, "luigi", "Luigi", 1983, "Mario"), 52 | createDbDoc("id", 6, "puff", "Jigglypuff", 1996, "Pokemon"), 53 | createDbDoc("id", 7, "dk", "Donkey Kong", 1981, "Mario"), 54 | createDbDoc("id", 9, "samus", "Samus", 1986, "Metroid"), 55 | createDbDoc("id", 8, "mario", "Mario", 1981, "Mario"), 56 | createDbDoc("id", 10, "pikachu", "Pikachu", 1996, "Pokemon") 57 | ]; 58 | 59 | var dbChangePromise = testHelper.waitForDbChanges(db, docs.length), 60 | bulkDocsPromise = db.bulkDocs(docs); 61 | 62 | $.when(bulkDocsPromise, dbChangePromise).then(done); 63 | 64 | }); 65 | 66 | describe("operations", function () { 67 | 68 | describe("sort by _id", function () { 69 | 70 | var result; 71 | 72 | beforeEach(function (done) { 73 | 74 | db.find({ 75 | //selector: { _id: { $gt: pouchCollate.toIndexableString(4) } }, 76 | selector: { _id: { $gt: "a" } }, 77 | sort: ['_id'] 78 | }) 79 | .then(function (res) { 80 | result = res; 81 | done(); 82 | }) 83 | .catch(function (err) { 84 | console.log("Error:" + err); 85 | }); 86 | 87 | }); 88 | 89 | it("should return sorted", function () { 90 | expect(result.docs.length).toEqual(docs.length); 91 | }); 92 | 93 | }); 94 | 95 | describe("sort by name", function () { 96 | 97 | var result; 98 | 99 | beforeEach(function (done) { 100 | 101 | db.createIndex({ 102 | index: { fields: ['name'] } 103 | }).then(function () { 104 | return db.find({ 105 | selector: { name: { $exists: true } }, 106 | sort: ['name'] 107 | }) 108 | .then(function (res) { 109 | result = res; 110 | done(); 111 | }); 112 | }) 113 | .catch(function (err) { 114 | console.log("Error:" + err); 115 | }); 116 | 117 | }); 118 | 119 | it("should return sorted", function () { 120 | expect(result.docs.length).toEqual(docs.length); 121 | }); 122 | 123 | }); 124 | 125 | describe("'and'", function () { 126 | 127 | var result; 128 | 129 | beforeEach(function (done) { 130 | 131 | db.createIndex({ 132 | index: { fields: ['series', 'debut'] } 133 | }).then(function () { 134 | return db.find({ 135 | selector: { 136 | $and: [ 137 | { series: { $gt: 'Mario' } }, 138 | { debut: { $lt: 1990 } } 139 | ] 140 | } 141 | //sort: ['name'] 142 | }) 143 | .then(function (res) { 144 | result = res; 145 | done(); 146 | }); 147 | }) 148 | .catch(function (err) { 149 | console.log("Error:" + err); 150 | }); 151 | 152 | }); 153 | 154 | it("should return sorted", function () { 155 | expect(result.docs.length).toEqual(_.filter(docs, function (doc) { return doc.series > 'Mario' && doc.debut < 1990; }).length); 156 | }); 157 | 158 | }); 159 | 160 | describe("'or'", function () { 161 | 162 | var result; 163 | 164 | beforeEach(function (done) { 165 | 166 | db.createIndex({ 167 | index: { fields: ['series', 'debut'] } 168 | }).then(function () { 169 | return db.find({ 170 | selector: { 171 | //TODO: $or is not implemented in pouchdb-find 172 | $or: [ 173 | { series: { $gt: 'Mario' } }, 174 | { debut: { $lt: 1990 } } 175 | ] 176 | } 177 | //sort: ['name'] 178 | }) 179 | .then(function (res) { 180 | result = res; 181 | done(); 182 | }); 183 | }) 184 | .catch(function (err) { 185 | console.log("Error:" + err); 186 | }); 187 | 188 | }); 189 | 190 | it("should return sorted", function () { 191 | expect(result.docs.length).toEqual(_.filter(docs, function (doc) { return doc.series > 'Mario' || doc.debut < 1990; }).length); 192 | }); 193 | 194 | }); 195 | 196 | 197 | }); 198 | 199 | }); 200 | 201 | }); -------------------------------------------------------------------------------- /dist/kendo-pouchdb.min.js: -------------------------------------------------------------------------------- 1 | /* kendo-pouchdb v0.1.5 01-08-2015 (C) 2015 Terikon Apps */ 2 | 3 | !function(a,b){b(["PouchDB","pouchCollate"],a)}(function(a,b){if(!a)throw new Error('Please include "pouchdb.js" before kendo-pouchdb');if(!b)throw new Error('Please include "pouchdb-collate.js" before kendo-pouchdb');return function(c){"use strict";var d={MAPREDUCE:"mapreduce",POUCHDBFIND:"pouchdb-find"},e=kendo.data.RemoteTransport.extend({init:function(b){var e=b&&b.pouchdb?b.pouchdb:{},f=e.db,g=e.idField,h=e.queryPlugin||d.MAPREDUCE,i=e.defaultView,j=e.fieldViews;if(!f)throw new Error('The "db" option must be set.');if(!(f instanceof a))throw new Error('The "db" option must be a PouchDB object.');if(!g)throw new Error('The "idField" option must be set.');var k=c.map(d,function(a){return a});if(k.indexOf(h)<0)throw new Error(kendo.format("{0} is not supported as queryPlugin",h));if(h===d.POUCHDBFIND&&i)throw new Error(kendo.format("defaultView cannot be used when queryPlugin is '{0}'",h));if(h===d.POUCHDBFIND&&j)throw new Error(kendo.format("fieldViews cannot be used when queryPlugin is '{0}'",h));this.db=f,this.idField=g,this.queryPlugin=h,this.defaultView=i,this.fieldViews=j||{},this.dataSource=b.data.dataSource,kendo.data.RemoteTransport.fn.init.call(this,b)},push:function(a){var b=this,d=this.db.changes({since:"now",live:!0,include_docs:!0,filter:b.defaultView?"_view":void 0,view:b.defaultView});d.on("change",function(d){var e,f=b._crudPromises.slice(),g=d.doc;c.when.apply(c,f).then(function(){if(d.deleted)a.pushDestroy(g);else if(e=b.dataSource.get(g._id),void 0!==e){if(g._rev===e._rev)return;a.pushUpdate(g)}else b.dataSource.pageSize()||a.pushCreate(g)})}),d.on("error",function(a){})},read:function(b){try{var e,f,g,h,i=this,j=b.data.filter,k=b.data.sort,l=i.queryPlugin===d.MAPREDUCE,m=i.queryPlugin===d.POUCHDBFIND,n=l?i._getFieldViewAndDirForSort(k):void 0,o=m?i._kendoFilterToFindSelector(j,k):void 0,p=m?i._kendoSortToFindSort(k):void 0,q=i._isEmptyFilter(j)||l&&i._isIdRangeFilter(j),r=i._isEmptySort(k)||i._isIdSort(k),s=q&&r&&!i.defaultView&&!o,t=function(){if(l){if(!i.db.query)throw new Error("db.query is needed to use mapreduce method, but it does not exists");return i.db.query.bind(i.db,n.fieldView)}if(m){if(!i.db.find)throw new Error("db.find is needed to use mapreduce method, but it does not exists");return i.db.find}throw new Error(kendo.format("queryPlugin {0} is not supported",i.queryPlugin))},u=s?i.db.allDocs:t(),v=b.data.pageSize,w=b.data.page,x=function(){return!s||e?a.utils.Promise.resolve(0):i.db.allDocs({startkey:"_design/",endkey:"_design￿"}).then(function(a){return a.rows.length})},y=function(a){var b=[];return c.each(a,function(a,c){void 0===c&&b.push(a)}),c.each(b,function(b,c){delete a[c]}),a};i._validateFilter(b.data.filter,b.data.sort),h=s||l?this._getFilterQueryOptions(b.data.filter):void 0,e=!!h,void 0!==v?(void 0===w&&(w=1),g=v*(w-1)):g=void 0,f=void 0!==g||void 0!==v;var z=n?n.descending:void 0,A=s||l?!0:void 0,B=y(c.extend({include_docs:A,descending:z,skip:g,limit:v,selector:o,sort:p},h)),C=function(a,b){if(s&&!e)return a.total_rows-=b,a;if(m)return a.total_rows=0,a;if(l&&!f)return a.total_rows=0,c.each(a.rows,function(){0!==this.doc._id.indexOf("_design/")&&(a.total_rows+=1)}),a;if(l){var d=c.extend({include_docs:!1,reduce:"_count"},h);return u.call(i.db,d).then(function(b){return s?(a.total_rows=b.rows.length,a):(a.total_rows=b.rows.length,a)})}throw new Error(kendo.format("Does not know how to calculate total for queryPlugin '{0}'",i.queryPlugin))};x().then(function(a){return u.call(i.db,B).then(function(b){return C(b,a)})}).then(function(a){b.success(a)})["catch"](function(a){b.error(a,a.status||a.message,a)})}catch(D){b.error(D,D.message,D)}},_crudPromises:[],_crud:function(a,b,d,e){var f=this,g=new c.Deferred,h=g.promise(),i=function(){g.resolve();var a=f._crudPromises.indexOf(h);f._crudPromises.splice(a,1)};this._crudPromises.push(h),e.call(this,b).then(function(a){b._rev=a.rev,d.success(b),i()})["catch"](function(b){409===b.status&&console.log(kendo.format("kendo-pouchdb: conflict occured for {0}: {1}",a,b)),d.error(b,b.status,b),i()})},create:function(a){var c=a.data;"_id"!==this.idField&&(c._id=b.toIndexableString(c[this.idField])),this._crud("create",c,a,function(a){return this.db.put(a)})},update:function(a){var b=a.data;this._crud("update",b,a,function(a){return this.db.put(a)})},destroy:function(a){var b=a.data;this._crud("destroy",b,a,function(a){return this.db.remove(a)})},_isEmptyFilter:function(a){return!a||!a.filters||0===a.filters.length},_isIdRangeFilter:function(a){if(!a||1!==a.filters.length)return!1;var b=a.filters[0].field,c=a.filters[0].operator;return"_id"!==b&&b!==this.idField?!1:["eq","neq","lt","lte","gt","gte"].indexOf(c)>=0},_isEmptySort:function(a){return!a||0===a.length},_isIdSort:function(a){if(!a||1!==a.length)return!1;var b=a[0].field;return"_id"===b||b===this.idField},_getFieldViewAndDirForSort:function(a){var b,c,d,e=this.defaultView;if(this._isEmptySort(a))return{fieldView:e,descending:!1};if(a.length>1)throw new Error("Sorting by multiple fields is not supported with views, use find");if(c=a[0].dir&&"desc"===a[0].dir,this._isIdSort(a))return{fieldView:e,descending:c};if(b=a[0].field,d=this.fieldViews[b],!d)throw new Error("No PouchDB view provided for sorting by '"+b+"'");return{fieldView:d,descending:c}},_validateFilter:function(a,b){if(a&&0!==a.filters.length){var c=a.filters;if(this.queryPlugin===d.MAPREDUCE){if(c.length>1)throw new Error("array of filters is currently not supported");var e=c[0].field,f=b&&b.length>0?b[0].field:this.idField;if(f!=e)throw new Error("filtering by field and then sorting by another field is not supported")}else this.queryPlugin===d.POUCHDBFIND}},_getFilterQueryOptions:function(a){if(this._isEmptyFilter(a))return void 0;if(1!==a.filters.length)throw new Error("_getFilterQueryOptions currently supports only one filter");var c=a.filters[0].field,d=a.filters[0].operator,e=c===this.idField||"_id"===c?b.toIndexableString(a.filters[0].value):a.filters[0].value;if(["neq","gt"].indexOf(d)>=0)throw new Error(kendo.format("{0} operator is currently not supported for field '{1}'",d,c));switch(d){case"eq":return{key:e};case"lt":return{endkey:e,inclusive_end:!1};case"lte":return{endkey:e,inclusive_end:!0};case"gte":return{startkey:e}}return void 0},_fieldToFindField:function(a){return a===this.idField?"_id":a},_valueToIndexable:function(a,c){return"_id"!==a&&a===this.idField?b.toIndexableString(c):c},_kendoFilterToFindSelector:function(a,b){var d=this;return this._isEmptyFilter(a)&&b&&b.length>0?{$and:c.map(b,function(a){var b=d._fieldToFindField(a.field),c={};return c[b]={$exists:!0},c})}:this._kendoFilterToFindSelectorInternal(a,b)},_kendoFilterToFindSelectorInternal:function(a,b){a=a||{};var d=this,e={},f=a.logic||"and",g=a.filters||[],h="and"===f?"$and":"$or",i=[],j=function(a){switch(a){case"eq":return"$eq";case"neq":return"$ne";case"lt":return"$lt";case"lte":return"$lte";case"gt":return"$gt";case"gte":return"$gte";default:throw new Error(kendo.format("Operator {0} is not supported by kendo-pouchdb",a))}};return c.each(g,function(a,c){var e,f,g,h=d._fieldToFindField(c.field),k=d._valueToIndexable(c.field,c.value);c.filters?f=d._kendoFilterToFindSelector(c,b):(f={},e=j(c.operator),g={},g[e]=k,f[h]=g),i.push(f)}),0===i.length?void 0:(e[h]=i,e)},_kendoSortToFindSort:function(a){var b=this;return this._isEmptySort(a)?void 0:c.map(a,function(a){var c={};return c[b._fieldToFindField(a.field)]="desc"===a.dir?"desc":"asc",c})}}),f={type:"json",data:function(a){if(a.rows){var b=c.map(a.rows,function(a){return 0!==a.doc._id.indexOf("_design/")?a.doc:void 0});return b}return a.docs?a.docs:a},total:function(a){return a.total_rows}};c.extend(!0,kendo.data,{schemas:{pouchdb:f},transports:{pouchdb:e}});var g=kendo.data.DataSource.extend({init:function(a){var b=a;if(b&&b.type&&"pouchdb"===b.type){var d;if(b=c.extend(!0,{},b),this._ispouchdb=!0,b.schema&&b.schema.model&&b.schema.model.fn&&b.schema.model.fn instanceof kendo.data.Model){if(d=b.schema.model,"_id"!==d.idField)throw new Error('The Model\'s id option should be "_id"')}else if(b=c.extend(!0,{schema:{model:{id:"_id"}}},b),"_id"!==b.schema.model.id)throw new Error('The model.id option should not be provided or should be "_id"');if(b.serverPaging=void 0===b.serverPaging?!0:b.serverPaging,b.serverFiltering=void 0===b.serverFiltering?!0:b.serverFiltering,b.serverSorting=void 0===b.serverSorting?!0:b.serverSorting,b.serverGrouping=void 0===b.serverGrouping?!0:b.serverGrouping,b.serverAggregates=void 0===b.serverAggregates?!0:b.serverAggregates,b.data)throw new Error("For DataSource of type pouchdb data option should not be provided");b.data={dataSource:this}}var e=Array.prototype.slice.call(arguments,1);e.unshift(b),kendo.data.DataSource.fn.init.apply(this,e)},getByModelId:function(a){return this._ispouchdb?kendo.data.DataSource.fn.get.call(this,b.toIndexableString(a)):kendo.data.DataSource.fn.get.apply(this,arguments)}});g.create=kendo.data.DataSource.create,kendo.data.PouchableDataSource=g}(window.kendo.jQuery),window.kendo},"function"==typeof define&&define.amd?define:function(a,b){b(window.PouchDB,window.pouchCollate)}); 4 | //# sourceMappingURL=kendo-pouchdb.min.js.map -------------------------------------------------------------------------------- /vendor/kendo/kendo.data.xml.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.core" ], f); 19 | })(function(){ 20 | 21 | /*jshint eqnull: true, boss: true */ 22 | (function($, undefined) { 23 | var kendo = window.kendo, 24 | isArray = $.isArray, 25 | isPlainObject = $.isPlainObject, 26 | map = $.map, 27 | each = $.each, 28 | extend = $.extend, 29 | getter = kendo.getter, 30 | Class = kendo.Class; 31 | 32 | var XmlDataReader = Class.extend({ 33 | init: function(options) { 34 | var that = this, 35 | total = options.total, 36 | model = options.model, 37 | parse = options.parse, 38 | errors = options.errors, 39 | serialize = options.serialize, 40 | data = options.data; 41 | 42 | if (model) { 43 | if (isPlainObject(model)) { 44 | var base = options.modelBase || kendo.data.Model; 45 | 46 | if (model.fields) { 47 | each(model.fields, function(field, value) { 48 | if (isPlainObject(value) && value.field) { 49 | if (!$.isFunction(value.field)) { 50 | value = extend(value, { field: that.getter(value.field) }); 51 | } 52 | } else { 53 | value = { field: that.getter(value) }; 54 | } 55 | model.fields[field] = value; 56 | }); 57 | } 58 | 59 | var id = model.id; 60 | if (id) { 61 | var idField = {}; 62 | 63 | idField[that.xpathToMember(id, true)] = { field : that.getter(id) }; 64 | model.fields = extend(idField, model.fields); 65 | model.id = that.xpathToMember(id); 66 | } 67 | model = base.define(model); 68 | } 69 | 70 | that.model = model; 71 | } 72 | 73 | if (total) { 74 | if (typeof total == "string") { 75 | total = that.getter(total); 76 | that.total = function(data) { 77 | return parseInt(total(data), 10); 78 | }; 79 | } else if (typeof total == "function"){ 80 | that.total = total; 81 | } 82 | } 83 | 84 | if (errors) { 85 | if (typeof errors == "string") { 86 | errors = that.getter(errors); 87 | that.errors = function(data) { 88 | return errors(data) || null; 89 | }; 90 | } else if (typeof errors == "function"){ 91 | that.errors = errors; 92 | } 93 | } 94 | 95 | if (data) { 96 | if (typeof data == "string") { 97 | data = that.xpathToMember(data); 98 | that.data = function(value) { 99 | var result = that.evaluate(value, data), 100 | modelInstance; 101 | 102 | result = isArray(result) ? result : [result]; 103 | 104 | if (that.model && model.fields) { 105 | modelInstance = new that.model(); 106 | 107 | return map(result, function(value) { 108 | if (value) { 109 | var record = {}, field; 110 | 111 | for (field in model.fields) { 112 | record[field] = modelInstance._parse(field, model.fields[field].field(value)); 113 | } 114 | 115 | return record; 116 | } 117 | }); 118 | } 119 | 120 | return result; 121 | }; 122 | } else if (typeof data == "function") { 123 | that.data = data; 124 | } 125 | } 126 | 127 | if (typeof parse == "function") { 128 | var xmlParse = that.parse; 129 | 130 | that.parse = function(data) { 131 | var xml = parse.call(that, data); 132 | return xmlParse.call(that, xml); 133 | }; 134 | } 135 | 136 | if (typeof serialize == "function") { 137 | that.serialize = serialize; 138 | } 139 | }, 140 | total: function(result) { 141 | return this.data(result).length; 142 | }, 143 | errors: function(data) { 144 | return data ? data.errors : null; 145 | }, 146 | serialize: function(data) { 147 | return data; 148 | }, 149 | parseDOM: function(element) { 150 | var result = {}, 151 | parsedNode, 152 | node, 153 | nodeType, 154 | nodeName, 155 | member, 156 | attribute, 157 | attributes = element.attributes, 158 | attributeCount = attributes.length, 159 | idx; 160 | 161 | for (idx = 0; idx < attributeCount; idx++) { 162 | attribute = attributes[idx]; 163 | result["@" + attribute.nodeName] = attribute.nodeValue; 164 | } 165 | 166 | for (node = element.firstChild; node; node = node.nextSibling) { 167 | nodeType = node.nodeType; 168 | 169 | if (nodeType === 3 || nodeType === 4) { 170 | // text nodes or CDATA are stored as #text field 171 | result["#text"] = node.nodeValue; 172 | } else if (nodeType === 1) { 173 | // elements are stored as fields 174 | parsedNode = this.parseDOM(node); 175 | 176 | nodeName = node.nodeName; 177 | 178 | member = result[nodeName]; 179 | 180 | if (isArray(member)) { 181 | // elements of same nodeName are stored as array 182 | member.push(parsedNode); 183 | } else if (member !== undefined) { 184 | member = [member, parsedNode]; 185 | } else { 186 | member = parsedNode; 187 | } 188 | 189 | result[nodeName] = member; 190 | } 191 | } 192 | return result; 193 | }, 194 | 195 | evaluate: function(value, expression) { 196 | var members = expression.split("."), 197 | member, 198 | result, 199 | length, 200 | intermediateResult, 201 | idx; 202 | 203 | while (member = members.shift()) { 204 | value = value[member]; 205 | 206 | if (isArray(value)) { 207 | result = []; 208 | expression = members.join("."); 209 | 210 | for (idx = 0, length = value.length; idx < length; idx++) { 211 | intermediateResult = this.evaluate(value[idx], expression); 212 | 213 | intermediateResult = isArray(intermediateResult) ? intermediateResult : [intermediateResult]; 214 | 215 | result.push.apply(result, intermediateResult); 216 | } 217 | 218 | return result; 219 | } 220 | } 221 | 222 | return value; 223 | }, 224 | 225 | parse: function(xml) { 226 | var documentElement, 227 | tree, 228 | result = {}; 229 | 230 | documentElement = xml.documentElement || $.parseXML(xml).documentElement; 231 | 232 | tree = this.parseDOM(documentElement); 233 | 234 | result[documentElement.nodeName] = tree; 235 | 236 | return result; 237 | }, 238 | 239 | xpathToMember: function(member, raw) { 240 | if (!member) { 241 | return ""; 242 | } 243 | 244 | member = member.replace(/^\//, "") // remove the first "/" 245 | .replace(/\//g, "."); // replace all "/" with "." 246 | 247 | if (member.indexOf("@") >= 0) { 248 | // replace @attribute with '["@attribute"]' 249 | return member.replace(/\.?(@.*)/, raw? '$1':'["$1"]'); 250 | } 251 | 252 | if (member.indexOf("text()") >= 0) { 253 | // replace ".text()" with '["#text"]' 254 | return member.replace(/(\.?text\(\))/, raw? '#text':'["#text"]'); 255 | } 256 | 257 | return member; 258 | }, 259 | getter: function(member) { 260 | return getter(this.xpathToMember(member), true); 261 | } 262 | }); 263 | 264 | $.extend(true, kendo.data, { 265 | XmlDataReader: XmlDataReader, 266 | readers: { 267 | xml: XmlDataReader 268 | } 269 | }); 270 | })(window.kendo.jQuery); 271 | 272 | return window.kendo; 273 | 274 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); -------------------------------------------------------------------------------- /dist/kendo-pouchdb.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"kendo-pouchdb.min.js","sources":["../kendo-pouchdb.js"],"names":["f","define","PouchDB","pouchCollate","Error","$","queryPlugins","MAPREDUCE","POUCHDBFIND","pouchdbTransport","kendo","data","RemoteTransport","extend","init","options","pouchdb","db","idField","queryPlugin","defaultView","fieldViews","allQueryPlugins","map","plugin","indexOf","format","this","dataSource","fn","call","push","callbacks","that","changes","since","live","include_docs","filter","undefined","view","on","change","datasourceItem","currentCrudPromises","_crudPromises","slice","doc","when","apply","then","deleted","pushDestroy","get","_id","_rev","pushUpdate","pageSize","pushCreate","err","read","applyFilter","applyPaging","skip","filterQueryOptions","sort","mapreduce","pouchdbfind","fieldViewAndDir","_getFieldViewAndDirForSort","findSelector","_kendoFilterToFindSelector","findSort","_kendoSortToFindSort","filterGoodForAllDocs","_isEmptyFilter","_isIdRangeFilter","sortGoodForAllDocs","_isEmptySort","_isIdSort","useAllDocs","getQueryMethodByQueryPlugin","query","bind","fieldView","find","queryMethod","allDocs","limit","page","countDocsToSubtract","utils","Promise","resolve","startkey","endkey","result","rows","length","cleanUndefinedProperties","obj","propertiesToClean","each","key","value","index","property","_validateFilter","_getFilterQueryOptions","descending","queryOptions","selector","applyTotalRowsOnResponse","response","totalRowsToSubtract","total_rows","totalQueryOptions","reduce","totalResult","success","error","status","message","_crud","type","operation","deferred","Deferred","crudPromise","promise","resolveCrudDeferred","splice","rev","console","log","create","toIndexableString","d","put","update","destroy","remove","filters","filterField","field","filterOperator","operator","dir","sortField","filterValue","inclusive_end","_fieldToFindField","_valueToIndexable","$and","expression","$exists","_kendoFilterToFindSelectorInternal","logic","combinationOperator","conditions","convertOperator","condition","argument","order","pouchdbSchema","docs","row","total","schemas","transports","PouchableDataSource","DataSource","opts","Model","_ispouchdb","schema","model","id","serverPaging","serverFiltering","serverSorting","serverGrouping","serverAggregates","newArgs","Array","prototype","arguments","unshift","getByModelId","window","jQuery","amd","_"],"mappings":"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"} -------------------------------------------------------------------------------- /vendor/kendo/kendo.data.odata.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.core" ], f); 19 | })(function(){ 20 | 21 | (function($, undefined) { 22 | var kendo = window.kendo, 23 | extend = $.extend, 24 | odataFilters = { 25 | eq: "eq", 26 | neq: "ne", 27 | gt: "gt", 28 | gte: "ge", 29 | lt: "lt", 30 | lte: "le", 31 | contains : "substringof", 32 | doesnotcontain: "substringof", 33 | endswith: "endswith", 34 | startswith: "startswith" 35 | }, 36 | odataFiltersVersionFour = extend({}, odataFilters, { 37 | contains: "contains" 38 | }), 39 | mappers = { 40 | pageSize: $.noop, 41 | page: $.noop, 42 | filter: function(params, filter, useVersionFour) { 43 | if (filter) { 44 | filter = toOdataFilter(filter, useVersionFour); 45 | if (filter) { 46 | params.$filter = filter; 47 | } 48 | } 49 | }, 50 | sort: function(params, orderby) { 51 | var expr = $.map(orderby, function(value) { 52 | var order = value.field.replace(/\./g, "/"); 53 | 54 | if (value.dir === "desc") { 55 | order += " desc"; 56 | } 57 | 58 | return order; 59 | }).join(","); 60 | 61 | if (expr) { 62 | params.$orderby = expr; 63 | } 64 | }, 65 | skip: function(params, skip) { 66 | if (skip) { 67 | params.$skip = skip; 68 | } 69 | }, 70 | take: function(params, take) { 71 | if (take) { 72 | params.$top = take; 73 | } 74 | } 75 | }, 76 | defaultDataType = { 77 | read: { 78 | dataType: "jsonp" 79 | } 80 | }; 81 | 82 | function toOdataFilter(filter, useOdataFour) { 83 | var result = [], 84 | logic = filter.logic || "and", 85 | idx, 86 | length, 87 | field, 88 | type, 89 | format, 90 | operator, 91 | value, 92 | ignoreCase, 93 | filters = filter.filters; 94 | 95 | for (idx = 0, length = filters.length; idx < length; idx++) { 96 | filter = filters[idx]; 97 | field = filter.field; 98 | value = filter.value; 99 | operator = filter.operator; 100 | 101 | if (filter.filters) { 102 | filter = toOdataFilter(filter, useOdataFour); 103 | } else { 104 | ignoreCase = filter.ignoreCase; 105 | field = field.replace(/\./g, "/"); 106 | filter = odataFilters[operator]; 107 | if (useOdataFour) { 108 | filter = odataFiltersVersionFour[operator]; 109 | } 110 | 111 | if (filter && value !== undefined) { 112 | type = $.type(value); 113 | if (type === "string") { 114 | format = "'{1}'"; 115 | value = value.replace(/'/g, "''"); 116 | 117 | if (ignoreCase === true) { 118 | field = "tolower(" + field + ")"; 119 | } 120 | 121 | } else if (type === "date") { 122 | if (useOdataFour) { 123 | format = "{1:yyyy-MM-ddTHH:mm:ss+00:00}"; 124 | } else { 125 | format = "datetime'{1:yyyy-MM-ddTHH:mm:ss}'"; 126 | } 127 | } else { 128 | format = "{1}"; 129 | } 130 | 131 | if (filter.length > 3) { 132 | if (filter !== "substringof") { 133 | format = "{0}({2}," + format + ")"; 134 | } else { 135 | format = "{0}(" + format + ",{2})"; 136 | if (operator === "doesnotcontain") { 137 | if (useOdataFour) { 138 | format = "{0}({2},'{1}') eq -1"; 139 | filter = "indexof"; 140 | } else { 141 | format += " eq false"; 142 | } 143 | } 144 | } 145 | } else { 146 | format = "{2} {0} " + format; 147 | } 148 | 149 | filter = kendo.format(format, filter, value, field); 150 | } 151 | } 152 | 153 | result.push(filter); 154 | } 155 | 156 | filter = result.join(" " + logic + " "); 157 | 158 | if (result.length > 1) { 159 | filter = "(" + filter + ")"; 160 | } 161 | 162 | return filter; 163 | } 164 | 165 | function stripMetadata(obj) { 166 | for (var name in obj) { 167 | if(name.indexOf("@odata") === 0) { 168 | delete obj[name]; 169 | } 170 | } 171 | } 172 | 173 | extend(true, kendo.data, { 174 | schemas: { 175 | odata: { 176 | type: "json", 177 | data: function(data) { 178 | return data.d.results || [data.d]; 179 | }, 180 | total: "d.__count" 181 | } 182 | }, 183 | transports: { 184 | odata: { 185 | read: { 186 | cache: true, // to prevent jQuery from adding cache buster 187 | dataType: "jsonp", 188 | jsonp: "$callback" 189 | }, 190 | update: { 191 | cache: true, 192 | dataType: "json", 193 | contentType: "application/json", // to inform the server the the request body is JSON encoded 194 | type: "PUT" // can be PUT or MERGE 195 | }, 196 | create: { 197 | cache: true, 198 | dataType: "json", 199 | contentType: "application/json", 200 | type: "POST" // must be POST to create new entity 201 | }, 202 | destroy: { 203 | cache: true, 204 | dataType: "json", 205 | type: "DELETE" 206 | }, 207 | parameterMap: function(options, type, useVersionFour) { 208 | var params, 209 | value, 210 | option, 211 | dataType; 212 | 213 | options = options || {}; 214 | type = type || "read"; 215 | dataType = (this.options || defaultDataType)[type]; 216 | dataType = dataType ? dataType.dataType : "json"; 217 | 218 | if (type === "read") { 219 | params = { 220 | $inlinecount: "allpages" 221 | }; 222 | 223 | if (dataType != "json") { 224 | params.$format = "json"; 225 | } 226 | 227 | for (option in options) { 228 | if (mappers[option]) { 229 | mappers[option](params, options[option], useVersionFour); 230 | } else { 231 | params[option] = options[option]; 232 | } 233 | } 234 | } else { 235 | if (dataType !== "json") { 236 | throw new Error("Only json dataType can be used for " + type + " operation."); 237 | } 238 | 239 | if (type !== "destroy") { 240 | for (option in options) { 241 | value = options[option]; 242 | if (typeof value === "number") { 243 | options[option] = value + ""; 244 | } 245 | } 246 | 247 | params = kendo.stringify(options); 248 | } 249 | } 250 | 251 | return params; 252 | } 253 | } 254 | } 255 | }); 256 | 257 | extend(true, kendo.data, { 258 | schemas: { 259 | "odata-v4": { 260 | type: "json", 261 | data: function(data) { 262 | data = $.extend({}, data); 263 | stripMetadata(data); 264 | 265 | if (data.value) { 266 | return data.value; 267 | } 268 | return [data]; 269 | }, 270 | total: function(data) { 271 | return data["@odata.count"]; 272 | } 273 | } 274 | }, 275 | transports: { 276 | "odata-v4": { 277 | read: { 278 | cache: true, // to prevent jQuery from adding cache buster 279 | dataType: "json" 280 | }, 281 | update: { 282 | cache: true, 283 | dataType: "json", 284 | contentType: "application/json;IEEE754Compatible=true", // to inform the server the the request body is JSON encoded 285 | type: "PUT" // can be PUT or MERGE 286 | }, 287 | create: { 288 | cache: true, 289 | dataType: "json", 290 | contentType: "application/json;IEEE754Compatible=true", 291 | type: "POST" // must be POST to create new entity 292 | }, 293 | destroy: { 294 | cache: true, 295 | dataType: "json", 296 | type: "DELETE" 297 | }, 298 | parameterMap: function(options, type) { 299 | var result = kendo.data.transports.odata.parameterMap(options, type, true); 300 | if (type == "read") { 301 | result.$count = true; 302 | delete result.$inlinecount; 303 | } 304 | 305 | return result; 306 | } 307 | } 308 | } 309 | }); 310 | 311 | })(window.kendo.jQuery); 312 | 313 | return window.kendo; 314 | 315 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); -------------------------------------------------------------------------------- /vendor/kendo/kendo.editable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.datepicker", "./kendo.numerictextbox", "./kendo.validator", "./kendo.binder" ], f); 19 | })(function(){ 20 | 21 | /* jshint eqnull: true */ 22 | (function($, undefined) { 23 | var kendo = window.kendo, 24 | ui = kendo.ui, 25 | Widget = ui.Widget, 26 | extend = $.extend, 27 | oldIE = kendo.support.browser.msie && kendo.support.browser.version < 9, 28 | isFunction = kendo.isFunction, 29 | isPlainObject = $.isPlainObject, 30 | inArray = $.inArray, 31 | nameSpecialCharRegExp = /("|\%|'|\[|\]|\$|\.|\,|\:|\;|\+|\*|\&|\!|\#|\(|\)|<|>|\=|\?|\@|\^|\{|\}|\~|\/|\||`)/g, 32 | ERRORTEMPLATE = '
' + 33 | '#=message#
', 34 | CHANGE = "change"; 35 | 36 | var specialRules = ["url", "email", "number", "date", "boolean"]; 37 | 38 | function fieldType(field) { 39 | field = field != null ? field : ""; 40 | return field.type || $.type(field) || "string"; 41 | } 42 | 43 | function convertToValueBinding(container) { 44 | container.find(":input:not(:button, [" + kendo.attr("role") + "=upload], [" + kendo.attr("skip") + "], [type=file]), select").each(function() { 45 | var bindAttr = kendo.attr("bind"), 46 | binding = this.getAttribute(bindAttr) || "", 47 | bindingName = this.type === "checkbox" || this.type === "radio" ? "checked:" : "value:", 48 | fieldName = this.name; 49 | 50 | if (binding.indexOf(bindingName) === -1 && fieldName) { 51 | binding += (binding.length ? "," : "") + bindingName + fieldName; 52 | 53 | $(this).attr(bindAttr, binding); 54 | } 55 | }); 56 | } 57 | 58 | function createAttributes(options) { 59 | var field = (options.model.fields || options.model)[options.field], 60 | type = fieldType(field), 61 | validation = field ? field.validation : {}, 62 | ruleName, 63 | DATATYPE = kendo.attr("type"), 64 | BINDING = kendo.attr("bind"), 65 | rule, 66 | attr = { 67 | name: options.field 68 | }; 69 | 70 | for (ruleName in validation) { 71 | rule = validation[ruleName]; 72 | 73 | if (inArray(ruleName, specialRules) >= 0) { 74 | attr[DATATYPE] = ruleName; 75 | } else if (!isFunction(rule)) { 76 | attr[ruleName] = isPlainObject(rule) ? rule.value || ruleName : rule; 77 | } 78 | 79 | attr[kendo.attr(ruleName + "-msg")] = rule.message; 80 | } 81 | 82 | if (inArray(type, specialRules) >= 0) { 83 | attr[DATATYPE] = type; 84 | } 85 | 86 | attr[BINDING] = (type === "boolean" ? "checked:" : "value:") + options.field; 87 | 88 | return attr; 89 | } 90 | 91 | function convertItems(items) { 92 | var idx, 93 | length, 94 | item, 95 | value, 96 | text, 97 | result; 98 | 99 | if (items && items.length) { 100 | result = []; 101 | for (idx = 0, length = items.length; idx < length; idx++) { 102 | item = items[idx]; 103 | text = item.text || item.value || item; 104 | value = item.value == null ? (item.text || item) : item.value; 105 | 106 | result[idx] = { text: text, value: value }; 107 | } 108 | } 109 | return result; 110 | } 111 | 112 | var editors = { 113 | "number": function(container, options) { 114 | var attr = createAttributes(options); 115 | $('').attr(attr).appendTo(container).kendoNumericTextBox({ format: options.format }); 116 | $('').hide().appendTo(container); 117 | }, 118 | "date": function(container, options) { 119 | var attr = createAttributes(options), 120 | format = options.format; 121 | 122 | if (format) { 123 | format = kendo._extractFormat(format); 124 | } 125 | 126 | attr[kendo.attr("format")] = format; 127 | 128 | $('').attr(attr).appendTo(container).kendoDatePicker({ format: options.format }); 129 | $('').hide().appendTo(container); 130 | }, 131 | "string": function(container, options) { 132 | var attr = createAttributes(options); 133 | 134 | $('').attr(attr).appendTo(container); 135 | }, 136 | "boolean": function(container, options) { 137 | var attr = createAttributes(options); 138 | $('').attr(attr).appendTo(container); 139 | }, 140 | "values": function(container, options) { 141 | var attr = createAttributes(options); 142 | var items = kendo.stringify(convertItems(options.values)); 143 | $('' + 125 | kendo.format(options.messages.of, totalPages) + 126 | ''); 127 | } 128 | 129 | that.element.on(KEYDOWN + NS, ".k-pager-input input", proxy(that._keydown, that)); 130 | } 131 | 132 | if (options.previousNext) { 133 | if (!that.element.find(NEXT).length) { 134 | that.element.append(icon(NEXT, options.messages.next)); 135 | 136 | next(that.element, page, totalPages); 137 | } 138 | 139 | if (!that.element.find(LAST).length) { 140 | that.element.append(icon(LAST, options.messages.last, "k-pager-last")); 141 | 142 | last(that.element, page, totalPages); 143 | } 144 | } 145 | 146 | if (options.pageSizes){ 147 | if (!that.element.find(".k-pager-sizes").length){ 148 | var pageSizes = options.pageSizes.length ? options.pageSizes : ["all", 5, 10, 20]; 149 | var pageItems = $.map(pageSizes, function(size) { 150 | if (size.toLowerCase && size.toLowerCase() === "all") { 151 | return ""; 152 | } 153 | 154 | return ""; 155 | }); 156 | 157 | $('' + 326 | kendo.format(options.messages.of, totalPages)) 327 | .find("input") 328 | .val(page) 329 | .attr(DISABLED, total < 1) 330 | .toggleClass("k-state-disabled", total < 1); 331 | } 332 | 333 | if (options.previousNext) { 334 | first(that.element, page, totalPages); 335 | 336 | prev(that.element, page, totalPages); 337 | 338 | next(that.element, page, totalPages); 339 | 340 | last(that.element, page, totalPages); 341 | } 342 | 343 | if (options.pageSizes) { 344 | var hasAll = that.element.find(".k-pager-sizes option[value='all']").length > 0; 345 | var selectAll = hasAll && pageSize === this.dataSource.total(); 346 | var text = pageSize; 347 | if (selectAll) { 348 | pageSize = "all"; 349 | text = options.messages.allPages; 350 | } 351 | 352 | that.element 353 | .find(".k-pager-sizes select") 354 | .val(pageSize) 355 | .filter("[" + kendo.attr("role") + "=dropdownlist]") 356 | .kendoDropDownList("value", pageSize) 357 | .kendoDropDownList("text", text); // handles custom values 358 | } 359 | }, 360 | 361 | _keydown: function(e) { 362 | if (e.keyCode === kendo.keys.ENTER) { 363 | var input = this.element.find(".k-pager-input").find("input"), 364 | page = parseInt(input.val(), 10); 365 | 366 | if (isNaN(page) || page < 1 || page > this.totalPages()) { 367 | page = this.page(); 368 | } 369 | 370 | input.val(page); 371 | 372 | this.page(page); 373 | } 374 | }, 375 | 376 | _refreshClick: function(e) { 377 | e.preventDefault(); 378 | 379 | this.dataSource.read(); 380 | }, 381 | 382 | _change: function(e) { 383 | var value = e.currentTarget.value; 384 | var pageSize = parseInt(value, 10); 385 | var dataSource = this.dataSource; 386 | 387 | if (!isNaN(pageSize)){ 388 | dataSource.pageSize(pageSize); 389 | } else if ((value + "").toLowerCase() == "all") { 390 | dataSource.pageSize(dataSource.total()); 391 | } 392 | }, 393 | 394 | _toggleActive: function() { 395 | this.list.toggleClass("k-state-expanded"); 396 | }, 397 | 398 | _click: function(e) { 399 | var target = $(e.currentTarget); 400 | 401 | e.preventDefault(); 402 | 403 | if (!target.is(".k-state-disabled")) { 404 | this.page(target.attr(kendo.attr("page"))); 405 | } 406 | }, 407 | 408 | totalPages: function() { 409 | return Math.ceil((this.dataSource.total() || 0) / (this.pageSize() || 1)); 410 | }, 411 | 412 | pageSize: function() { 413 | return this.dataSource.pageSize() || this.dataSource.total(); 414 | }, 415 | 416 | page: function(page) { 417 | if (page !== undefined) { 418 | this.dataSource.page(page); 419 | 420 | this.trigger(CHANGE, { index: page }); 421 | } else { 422 | if (this.dataSource.total() > 0) { 423 | return this.dataSource.page(); 424 | } else { 425 | return 0; 426 | } 427 | } 428 | } 429 | }); 430 | 431 | ui.plugin(Pager); 432 | })(window.kendo.jQuery); 433 | 434 | return window.kendo; 435 | 436 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); -------------------------------------------------------------------------------- /vendor/kendo/kendo.validator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.core" ], f); 19 | })(function(){ 20 | 21 | /* jshint eqnull: true */ 22 | (function($, undefined) { 23 | var kendo = window.kendo, 24 | Widget = kendo.ui.Widget, 25 | NS = ".kendoValidator", 26 | INVALIDMSG = "k-invalid-msg", 27 | invalidMsgRegExp = new RegExp(INVALIDMSG,'i'), 28 | INVALIDINPUT = "k-invalid", 29 | VALIDINPUT = "k-valid", 30 | emailRegExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i, 31 | urlRegExp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i, 32 | INPUTSELECTOR = ":input:not(:button,[type=submit],[type=reset],[disabled],[readonly])", 33 | CHECKBOXSELECTOR = ":checkbox:not([disabled],[readonly])", 34 | NUMBERINPUTSELECTOR = "[type=number],[type=range]", 35 | BLUR = "blur", 36 | NAME = "name", 37 | FORM = "form", 38 | NOVALIDATE = "novalidate", 39 | proxy = $.proxy, 40 | patternMatcher = function(value, pattern) { 41 | if (typeof pattern === "string") { 42 | pattern = new RegExp('^(?:' + pattern + ')$'); 43 | } 44 | return pattern.test(value); 45 | }, 46 | matcher = function(input, selector, pattern) { 47 | var value = input.val(); 48 | 49 | if (input.filter(selector).length && value !== "") { 50 | return patternMatcher(value, pattern); 51 | } 52 | return true; 53 | }, 54 | hasAttribute = function(input, name) { 55 | if (input.length) { 56 | return input[0].attributes[name] != null; 57 | } 58 | return false; 59 | }; 60 | 61 | if (!kendo.ui.validator) { 62 | kendo.ui.validator = { rules: {}, messages: {} }; 63 | } 64 | 65 | function resolveRules(element) { 66 | var resolvers = kendo.ui.validator.ruleResolvers || {}, 67 | rules = {}, 68 | name; 69 | 70 | for (name in resolvers) { 71 | $.extend(true, rules, resolvers[name].resolve(element)); 72 | } 73 | return rules; 74 | } 75 | 76 | function decode(value) { 77 | return value.replace(/&/g, '&') 78 | .replace(/"/g, '"') 79 | .replace(/'/g, "'") 80 | .replace(/</g, '<') 81 | .replace(/>/g, '>'); 82 | } 83 | 84 | function numberOfDecimalDigits(value) { 85 | value = (value + "").split('.'); 86 | if (value.length > 1) { 87 | return value[1].length; 88 | } 89 | return 0; 90 | } 91 | 92 | function parseHtml(text) { 93 | if ($.parseHTML) { 94 | return $($.parseHTML(text)); 95 | } 96 | return $(text); 97 | } 98 | 99 | function searchForMessageContainer(elements, fieldName) { 100 | var containers = $(), 101 | element, 102 | attr; 103 | 104 | for (var idx = 0, length = elements.length; idx < length; idx++) { 105 | element = elements[idx]; 106 | if (invalidMsgRegExp.test(element.className)) { 107 | attr = element.getAttribute(kendo.attr("for")); 108 | if (attr === fieldName) { 109 | containers = containers.add(element); 110 | } 111 | } 112 | } 113 | return containers; 114 | } 115 | 116 | var Validator = Widget.extend({ 117 | init: function(element, options) { 118 | var that = this, 119 | resolved = resolveRules(element), 120 | validateAttributeSelector = "[" + kendo.attr("validate") + "!=false]"; 121 | 122 | options = options || {}; 123 | 124 | options.rules = $.extend({}, kendo.ui.validator.rules, resolved.rules, options.rules); 125 | options.messages = $.extend({}, kendo.ui.validator.messages, resolved.messages, options.messages); 126 | 127 | Widget.fn.init.call(that, element, options); 128 | 129 | that._errorTemplate = kendo.template(that.options.errorTemplate); 130 | 131 | if (that.element.is(FORM)) { 132 | that.element.attr(NOVALIDATE, NOVALIDATE); 133 | } 134 | 135 | that._inputSelector = INPUTSELECTOR + validateAttributeSelector; 136 | that._checkboxSelector = CHECKBOXSELECTOR + validateAttributeSelector; 137 | 138 | that._errors = {}; 139 | that._attachEvents(); 140 | that._isValidated = false; 141 | }, 142 | 143 | events: [ "validate", "change" ], 144 | 145 | options: { 146 | name: "Validator", 147 | errorTemplate: '' + 148 | ' #=message#', 149 | messages: { 150 | required: "{0} is required", 151 | pattern: "{0} is not valid", 152 | min: "{0} should be greater than or equal to {1}", 153 | max: "{0} should be smaller than or equal to {1}", 154 | step: "{0} is not valid", 155 | email: "{0} is not valid email", 156 | url: "{0} is not valid URL", 157 | date: "{0} is not valid date", 158 | dateCompare: "End date should be greater than or equal to the start date" 159 | }, 160 | rules: { 161 | required: function(input) { 162 | var checkbox = input.filter("[type=checkbox]").length && !input.is(":checked"), 163 | value = input.val(); 164 | 165 | return !(hasAttribute(input, "required") && (value === "" || !value || checkbox)); 166 | }, 167 | pattern: function(input) { 168 | if (input.filter("[type=text],[type=email],[type=url],[type=tel],[type=search],[type=password]").filter("[pattern]").length && input.val() !== "") { 169 | return patternMatcher(input.val(), input.attr("pattern")); 170 | } 171 | return true; 172 | }, 173 | min: function(input) { 174 | if (input.filter(NUMBERINPUTSELECTOR + ",[" + kendo.attr("type") + "=number]").filter("[min]").length && input.val() !== "") { 175 | var min = parseFloat(input.attr("min")) || 0, 176 | val = kendo.parseFloat(input.val()); 177 | 178 | return min <= val; 179 | } 180 | return true; 181 | }, 182 | max: function(input) { 183 | if (input.filter(NUMBERINPUTSELECTOR + ",[" + kendo.attr("type") + "=number]").filter("[max]").length && input.val() !== "") { 184 | var max = parseFloat(input.attr("max")) || 0, 185 | val = kendo.parseFloat(input.val()); 186 | 187 | return max >= val; 188 | } 189 | return true; 190 | }, 191 | step: function(input) { 192 | if (input.filter(NUMBERINPUTSELECTOR + ",[" + kendo.attr("type") + "=number]").filter("[step]").length && input.val() !== "") { 193 | var min = parseFloat(input.attr("min")) || 0, 194 | step = parseFloat(input.attr("step")) || 1, 195 | val = parseFloat(input.val()), 196 | decimals = numberOfDecimalDigits(step), 197 | raise; 198 | 199 | if (decimals) { 200 | raise = Math.pow(10, decimals); 201 | return ((Math.floor((val-min)*raise))%(step*raise)) / Math.pow(100, decimals) === 0; 202 | } 203 | return ((val-min)%step) === 0; 204 | } 205 | return true; 206 | }, 207 | email: function(input) { 208 | return matcher(input, "[type=email],[" + kendo.attr("type") + "=email]", emailRegExp); 209 | }, 210 | url: function(input) { 211 | return matcher(input, "[type=url],[" + kendo.attr("type") + "=url]", urlRegExp); 212 | }, 213 | date: function(input) { 214 | if (input.filter("[type^=date],[" + kendo.attr("type") + "=date]").length && input.val() !== "") { 215 | return kendo.parseDate(input.val(), input.attr(kendo.attr("format"))) !== null; 216 | } 217 | return true; 218 | } 219 | }, 220 | validateOnBlur: true 221 | }, 222 | 223 | destroy: function() { 224 | Widget.fn.destroy.call(this); 225 | 226 | this.element.off(NS); 227 | }, 228 | 229 | value: function() { 230 | if (!this._isValidated) { 231 | return false; 232 | } 233 | 234 | return this.errors().length === 0; 235 | }, 236 | 237 | _submit: function(e) { 238 | if (!this.validate()) { 239 | e.stopPropagation(); 240 | e.stopImmediatePropagation(); 241 | e.preventDefault(); 242 | return false; 243 | } 244 | return true; 245 | }, 246 | 247 | _checkElement: function(element) { 248 | var state = this.value(); 249 | 250 | this.validateInput(element); 251 | 252 | if (this.value() !== state) { 253 | this.trigger("change"); 254 | } 255 | }, 256 | 257 | _attachEvents: function() { 258 | var that = this; 259 | 260 | if (that.element.is(FORM)) { 261 | that.element.on("submit" + NS, proxy(that._submit, that)); 262 | } 263 | 264 | if (that.options.validateOnBlur) { 265 | if (!that.element.is(INPUTSELECTOR)) { 266 | that.element.on(BLUR + NS, that._inputSelector, function() { 267 | that._checkElement($(this)); 268 | }); 269 | 270 | that.element.on("click" + NS, that._checkboxSelector, function() { 271 | that._checkElement($(this)); 272 | }); 273 | } else { 274 | that.element.on(BLUR + NS, function() { 275 | that._checkElement(that.element); 276 | }); 277 | 278 | if (that.element.is(CHECKBOXSELECTOR)) { 279 | that.element.on("click" + NS, function() { 280 | that._checkElement(that.element); 281 | }); 282 | } 283 | } 284 | } 285 | }, 286 | 287 | validate: function() { 288 | var inputs; 289 | var idx; 290 | var result = false; 291 | var length; 292 | 293 | var isValid = this.value(); 294 | 295 | this._errors = {}; 296 | 297 | if (!this.element.is(INPUTSELECTOR)) { 298 | var invalid = false; 299 | 300 | inputs = this.element.find(this._inputSelector); 301 | 302 | for (idx = 0, length = inputs.length; idx < length; idx++) { 303 | if (!this.validateInput(inputs.eq(idx))) { 304 | invalid = true; 305 | } 306 | } 307 | 308 | result = !invalid; 309 | } else { 310 | result = this.validateInput(this.element); 311 | } 312 | 313 | this.trigger("validate", { valid: result }); 314 | 315 | if (isValid !== result) { 316 | this.trigger("change"); 317 | } 318 | 319 | return result; 320 | }, 321 | 322 | validateInput: function(input) { 323 | input = $(input); 324 | 325 | this._isValidated = true; 326 | 327 | var that = this, 328 | template = that._errorTemplate, 329 | result = that._checkValidity(input), 330 | valid = result.valid, 331 | className = "." + INVALIDMSG, 332 | fieldName = (input.attr(NAME) || ""), 333 | lbl = that._findMessageContainer(fieldName).add(input.next(className).filter(function() { 334 | var element = $(this); 335 | if (element.filter("[" + kendo.attr("for") + "]").length) { 336 | return element.attr(kendo.attr("for")) === fieldName; 337 | } 338 | 339 | return true; 340 | 341 | })).hide(), 342 | messageText; 343 | 344 | input.removeAttr("aria-invalid"); 345 | 346 | if (!valid) { 347 | messageText = that._extractMessage(input, result.key); 348 | that._errors[fieldName] = messageText; 349 | var messageLabel = parseHtml(template({ message: decode(messageText) })); 350 | var lblId = lbl.attr('id'); 351 | 352 | that._decorateMessageContainer(messageLabel, fieldName); 353 | 354 | if (lblId) { 355 | messageLabel.attr('id', lblId); 356 | } 357 | 358 | if (!lbl.replaceWith(messageLabel).length) { 359 | messageLabel.insertAfter(input); 360 | } 361 | messageLabel.show(); 362 | 363 | input.attr("aria-invalid", true); 364 | } else { 365 | delete that._errors[fieldName]; 366 | } 367 | 368 | input.toggleClass(INVALIDINPUT, !valid); 369 | input.toggleClass(VALIDINPUT, valid); 370 | 371 | return valid; 372 | }, 373 | 374 | hideMessages: function() { 375 | var that = this, 376 | className = "." + INVALIDMSG, 377 | element = that.element; 378 | 379 | if (!element.is(INPUTSELECTOR)) { 380 | element.find(className).hide(); 381 | } else { 382 | element.next(className).hide(); 383 | } 384 | }, 385 | 386 | _findMessageContainer: function(fieldName) { 387 | var locators = kendo.ui.validator.messageLocators, 388 | name, 389 | containers = $(); 390 | 391 | for (var idx = 0, length = this.element.length; idx < length; idx++) { 392 | containers = containers.add(searchForMessageContainer(this.element[idx].getElementsByTagName("*"), fieldName)); 393 | } 394 | 395 | for (name in locators) { 396 | containers = containers.add(locators[name].locate(this.element, fieldName)); 397 | } 398 | 399 | return containers; 400 | }, 401 | 402 | _decorateMessageContainer: function(container, fieldName) { 403 | var locators = kendo.ui.validator.messageLocators, 404 | name; 405 | 406 | container.addClass(INVALIDMSG) 407 | .attr(kendo.attr("for"), fieldName || ""); 408 | 409 | for (name in locators) { 410 | locators[name].decorate(container, fieldName); 411 | } 412 | 413 | container.attr("role", "alert"); 414 | }, 415 | 416 | _extractMessage: function(input, ruleKey) { 417 | var that = this, 418 | customMessage = that.options.messages[ruleKey], 419 | fieldName = input.attr(NAME); 420 | 421 | customMessage = kendo.isFunction(customMessage) ? customMessage(input) : customMessage; 422 | 423 | return kendo.format(input.attr(kendo.attr(ruleKey + "-msg")) || input.attr("validationMessage") || input.attr("title") || customMessage || "", fieldName, input.attr(ruleKey)); 424 | }, 425 | 426 | _checkValidity: function(input) { 427 | var rules = this.options.rules, 428 | rule; 429 | 430 | for (rule in rules) { 431 | if (!rules[rule].call(this, input)) { 432 | return { valid: false, key: rule }; 433 | } 434 | } 435 | 436 | return { valid: true }; 437 | }, 438 | 439 | errors: function() { 440 | var results = [], 441 | errors = this._errors, 442 | error; 443 | 444 | for (error in errors) { 445 | results.push(errors[error]); 446 | } 447 | return results; 448 | } 449 | }); 450 | 451 | kendo.ui.plugin(Validator); 452 | })(window.kendo.jQuery); 453 | 454 | return window.kendo; 455 | 456 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); -------------------------------------------------------------------------------- /vendor/kendo/kendo.userevents.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.core" ], f); 19 | })(function(){ 20 | 21 | (function ($, undefined) { 22 | var kendo = window.kendo, 23 | support = kendo.support, 24 | document = window.document, 25 | Class = kendo.Class, 26 | Observable = kendo.Observable, 27 | now = $.now, 28 | extend = $.extend, 29 | OS = support.mobileOS, 30 | invalidZeroEvents = OS && OS.android, 31 | DEFAULT_MIN_HOLD = 800, 32 | DEFAULT_THRESHOLD = support.browser.msie ? 5 : 0, // WP8 and W8 are very sensitive and always report move. 33 | 34 | // UserEvents events 35 | PRESS = "press", 36 | HOLD = "hold", 37 | SELECT = "select", 38 | START = "start", 39 | MOVE = "move", 40 | END = "end", 41 | CANCEL = "cancel", 42 | TAP = "tap", 43 | RELEASE = "release", 44 | GESTURESTART = "gesturestart", 45 | GESTURECHANGE = "gesturechange", 46 | GESTUREEND = "gestureend", 47 | GESTURETAP = "gesturetap"; 48 | 49 | var THRESHOLD = { 50 | "api": 0, 51 | "touch": 0, 52 | "mouse": 9, 53 | "pointer": 9 54 | }; 55 | 56 | var ENABLE_GLOBAL_SURFACE = (!support.touch || support.mouseAndTouchPresent); 57 | 58 | function touchDelta(touch1, touch2) { 59 | var x1 = touch1.x.location, 60 | y1 = touch1.y.location, 61 | x2 = touch2.x.location, 62 | y2 = touch2.y.location, 63 | dx = x1 - x2, 64 | dy = y1 - y2; 65 | 66 | return { 67 | center: { 68 | x: (x1 + x2) / 2, 69 | y: (y1 + y2) / 2 70 | }, 71 | 72 | distance: Math.sqrt(dx*dx + dy*dy) 73 | }; 74 | } 75 | 76 | function getTouches(e) { 77 | var touches = [], 78 | originalEvent = e.originalEvent, 79 | currentTarget = e.currentTarget, 80 | idx = 0, length, 81 | changedTouches, 82 | touch; 83 | 84 | if (e.api) { 85 | touches.push({ 86 | id: 2, // hardcoded ID for API call; 87 | event: e, 88 | target: e.target, 89 | currentTarget: e.target, 90 | location: e, 91 | type: "api" 92 | }); 93 | } 94 | else if (e.type.match(/touch/)) { 95 | changedTouches = originalEvent ? originalEvent.changedTouches : []; 96 | for (length = changedTouches.length; idx < length; idx ++) { 97 | touch = changedTouches[idx]; 98 | touches.push({ 99 | location: touch, 100 | event: e, 101 | target: touch.target, 102 | currentTarget: currentTarget, 103 | id: touch.identifier, 104 | type: "touch" 105 | }); 106 | } 107 | } 108 | else if (support.pointers || support.msPointers) { 109 | touches.push({ 110 | location: originalEvent, 111 | event: e, 112 | target: e.target, 113 | currentTarget: currentTarget, 114 | id: originalEvent.pointerId, 115 | type: "pointer" 116 | }); 117 | } else { 118 | touches.push({ 119 | id: 1, // hardcoded ID for mouse event; 120 | event: e, 121 | target: e.target, 122 | currentTarget: currentTarget, 123 | location: e, 124 | type: "mouse" 125 | }); 126 | } 127 | 128 | return touches; 129 | } 130 | 131 | var TouchAxis = Class.extend({ 132 | init: function(axis, location) { 133 | var that = this; 134 | 135 | that.axis = axis; 136 | 137 | that._updateLocationData(location); 138 | 139 | that.startLocation = that.location; 140 | that.velocity = that.delta = 0; 141 | that.timeStamp = now(); 142 | }, 143 | 144 | move: function(location) { 145 | var that = this, 146 | offset = location["page" + that.axis], 147 | timeStamp = now(), 148 | timeDelta = (timeStamp - that.timeStamp) || 1; // Firing manually events in tests can make this 0; 149 | 150 | if (!offset && invalidZeroEvents) { 151 | return; 152 | } 153 | 154 | that.delta = offset - that.location; 155 | 156 | that._updateLocationData(location); 157 | 158 | that.initialDelta = offset - that.startLocation; 159 | that.velocity = that.delta / timeDelta; 160 | that.timeStamp = timeStamp; 161 | }, 162 | 163 | _updateLocationData: function(location) { 164 | var that = this, axis = that.axis; 165 | 166 | that.location = location["page" + axis]; 167 | that.client = location["client" + axis]; 168 | that.screen = location["screen" + axis]; 169 | } 170 | }); 171 | 172 | var Touch = Class.extend({ 173 | init: function(userEvents, target, touchInfo) { 174 | extend(this, { 175 | x: new TouchAxis("X", touchInfo.location), 176 | y: new TouchAxis("Y", touchInfo.location), 177 | type: touchInfo.type, 178 | threshold: userEvents.threshold || THRESHOLD[touchInfo.type], 179 | userEvents: userEvents, 180 | target: target, 181 | currentTarget: touchInfo.currentTarget, 182 | initialTouch: touchInfo.target, 183 | id: touchInfo.id, 184 | pressEvent: touchInfo, 185 | _moved: false, 186 | _finished: false 187 | }); 188 | }, 189 | 190 | press: function() { 191 | this._holdTimeout = setTimeout($.proxy(this, "_hold"), this.userEvents.minHold); 192 | this._trigger(PRESS, this.pressEvent); 193 | }, 194 | 195 | _hold: function() { 196 | this._trigger(HOLD, this.pressEvent); 197 | }, 198 | 199 | move: function(touchInfo) { 200 | var that = this; 201 | 202 | if (that._finished) { return; } 203 | 204 | that.x.move(touchInfo.location); 205 | that.y.move(touchInfo.location); 206 | 207 | if (!that._moved) { 208 | if (that._withinIgnoreThreshold()) { 209 | return; 210 | } 211 | 212 | if (!UserEvents.current || UserEvents.current === that.userEvents) { 213 | that._start(touchInfo); 214 | } else { 215 | return that.dispose(); 216 | } 217 | } 218 | 219 | // Event handlers may cancel the drag in the START event handler, hence the double check for pressed. 220 | if (!that._finished) { 221 | that._trigger(MOVE, touchInfo); 222 | } 223 | }, 224 | 225 | end: function(touchInfo) { 226 | var that = this; 227 | 228 | that.endTime = now(); 229 | 230 | if (that._finished) { return; } 231 | 232 | // Mark the object as finished if there are blocking operations in the event handlers (alert/confirm) 233 | that._finished = true; 234 | 235 | that._trigger(RELEASE, touchInfo); // Release should be fired before TAP (as click is after mouseup/touchend) 236 | 237 | if (that._moved) { 238 | that._trigger(END, touchInfo); 239 | } else { 240 | that._trigger(TAP, touchInfo); 241 | } 242 | 243 | clearTimeout(that._holdTimeout); 244 | 245 | that.dispose(); 246 | }, 247 | 248 | dispose: function() { 249 | var userEvents = this.userEvents, 250 | activeTouches = userEvents.touches; 251 | 252 | this._finished = true; 253 | this.pressEvent = null; 254 | clearTimeout(this._holdTimeout); 255 | 256 | activeTouches.splice($.inArray(this, activeTouches), 1); 257 | }, 258 | 259 | skip: function() { 260 | this.dispose(); 261 | }, 262 | 263 | cancel: function() { 264 | this.dispose(); 265 | }, 266 | 267 | isMoved: function() { 268 | return this._moved; 269 | }, 270 | 271 | _start: function(touchInfo) { 272 | clearTimeout(this._holdTimeout); 273 | 274 | this.startTime = now(); 275 | this._moved = true; 276 | this._trigger(START, touchInfo); 277 | }, 278 | 279 | _trigger: function(name, touchInfo) { 280 | var that = this, 281 | jQueryEvent = touchInfo.event, 282 | data = { 283 | touch: that, 284 | x: that.x, 285 | y: that.y, 286 | target: that.target, 287 | event: jQueryEvent 288 | }; 289 | 290 | if(that.userEvents.notify(name, data)) { 291 | jQueryEvent.preventDefault(); 292 | } 293 | }, 294 | 295 | _withinIgnoreThreshold: function() { 296 | var xDelta = this.x.initialDelta, 297 | yDelta = this.y.initialDelta; 298 | 299 | return Math.sqrt(xDelta * xDelta + yDelta * yDelta) <= this.threshold; 300 | } 301 | }); 302 | 303 | function withEachUpEvent(callback) { 304 | var downEvents = kendo.eventMap.up.split(" "), 305 | idx = 0, 306 | length = downEvents.length; 307 | 308 | for(; idx < length; idx ++) { 309 | callback(downEvents[idx]); 310 | } 311 | } 312 | 313 | var UserEvents = Observable.extend({ 314 | init: function(element, options) { 315 | var that = this, 316 | filter, 317 | ns = kendo.guid(); 318 | 319 | options = options || {}; 320 | filter = that.filter = options.filter; 321 | that.threshold = options.threshold || DEFAULT_THRESHOLD; 322 | that.minHold = options.minHold || DEFAULT_MIN_HOLD; 323 | that.touches = []; 324 | that._maxTouches = options.multiTouch ? 2 : 1; 325 | that.allowSelection = options.allowSelection; 326 | that.captureUpIfMoved = options.captureUpIfMoved; 327 | that.eventNS = ns; 328 | 329 | element = $(element).handler(that); 330 | Observable.fn.init.call(that); 331 | 332 | extend(that, { 333 | element: element, 334 | // the touch events lock to the element anyway, so no need for the global setting 335 | surface: options.global && ENABLE_GLOBAL_SURFACE ? $(document.documentElement) : $(options.surface || element), 336 | stopPropagation: options.stopPropagation, 337 | pressed: false 338 | }); 339 | 340 | that.surface.handler(that) 341 | .on(kendo.applyEventMap("move", ns), "_move") 342 | .on(kendo.applyEventMap("up cancel", ns), "_end"); 343 | 344 | element.on(kendo.applyEventMap("down", ns), filter, "_start"); 345 | 346 | if (support.pointers || support.msPointers) { 347 | element.css("-ms-touch-action", "pinch-zoom double-tap-zoom"); 348 | } 349 | 350 | if (options.preventDragEvent) { 351 | element.on(kendo.applyEventMap("dragstart", ns), kendo.preventDefault); 352 | } 353 | 354 | element.on(kendo.applyEventMap("mousedown", ns), filter, { root: element }, "_select"); 355 | 356 | if (that.captureUpIfMoved && support.eventCapture) { 357 | var surfaceElement = that.surface[0], 358 | preventIfMovingProxy = $.proxy(that.preventIfMoving, that); 359 | 360 | withEachUpEvent(function(eventName) { 361 | surfaceElement.addEventListener(eventName, preventIfMovingProxy, true); 362 | }); 363 | } 364 | 365 | that.bind([ 366 | PRESS, 367 | HOLD, 368 | TAP, 369 | START, 370 | MOVE, 371 | END, 372 | RELEASE, 373 | CANCEL, 374 | GESTURESTART, 375 | GESTURECHANGE, 376 | GESTUREEND, 377 | GESTURETAP, 378 | SELECT 379 | ], options); 380 | }, 381 | 382 | preventIfMoving: function(e) { 383 | if (this._isMoved()) { 384 | e.preventDefault(); 385 | } 386 | }, 387 | 388 | destroy: function() { 389 | var that = this; 390 | 391 | if (that._destroyed) { 392 | return; 393 | } 394 | 395 | that._destroyed = true; 396 | 397 | if (that.captureUpIfMoved && support.eventCapture) { 398 | var surfaceElement = that.surface[0]; 399 | withEachUpEvent(function(eventName) { 400 | surfaceElement.removeEventListener(eventName, that.preventIfMoving); 401 | }); 402 | } 403 | 404 | that.element.kendoDestroy(that.eventNS); 405 | that.surface.kendoDestroy(that.eventNS); 406 | that.element.removeData("handler"); 407 | that.surface.removeData("handler"); 408 | that._disposeAll(); 409 | 410 | that.unbind(); 411 | delete that.surface; 412 | delete that.element; 413 | delete that.currentTarget; 414 | }, 415 | 416 | capture: function() { 417 | UserEvents.current = this; 418 | }, 419 | 420 | cancel: function() { 421 | this._disposeAll(); 422 | this.trigger(CANCEL); 423 | }, 424 | 425 | notify: function(eventName, data) { 426 | var that = this, 427 | touches = that.touches; 428 | 429 | if (this._isMultiTouch()) { 430 | switch(eventName) { 431 | case MOVE: 432 | eventName = GESTURECHANGE; 433 | break; 434 | case END: 435 | eventName = GESTUREEND; 436 | break; 437 | case TAP: 438 | eventName = GESTURETAP; 439 | break; 440 | } 441 | 442 | extend(data, {touches: touches}, touchDelta(touches[0], touches[1])); 443 | } 444 | 445 | return this.trigger(eventName, extend(data, {type: eventName})); 446 | }, 447 | 448 | // API 449 | press: function(x, y, target) { 450 | this._apiCall("_start", x, y, target); 451 | }, 452 | 453 | move: function(x, y) { 454 | this._apiCall("_move", x, y); 455 | }, 456 | 457 | end: function(x, y) { 458 | this._apiCall("_end", x, y); 459 | }, 460 | 461 | _isMultiTouch: function() { 462 | return this.touches.length > 1; 463 | }, 464 | 465 | _maxTouchesReached: function() { 466 | return this.touches.length >= this._maxTouches; 467 | }, 468 | 469 | _disposeAll: function() { 470 | var touches = this.touches; 471 | while (touches.length > 0) { 472 | touches.pop().dispose(); 473 | } 474 | }, 475 | 476 | _isMoved: function() { 477 | return $.grep(this.touches, function(touch) { 478 | return touch.isMoved(); 479 | }).length; 480 | }, 481 | 482 | _select: function(e) { 483 | if (!this.allowSelection || this.trigger(SELECT, { event: e })) { 484 | e.preventDefault(); 485 | } 486 | }, 487 | 488 | _start: function(e) { 489 | var that = this, 490 | idx = 0, 491 | filter = that.filter, 492 | target, 493 | touches = getTouches(e), 494 | length = touches.length, 495 | touch, 496 | which = e.which; 497 | 498 | if ((which && which > 1) || (that._maxTouchesReached())){ 499 | return; 500 | } 501 | 502 | UserEvents.current = null; 503 | 504 | that.currentTarget = e.currentTarget; 505 | 506 | if (that.stopPropagation) { 507 | e.stopPropagation(); 508 | } 509 | 510 | for (; idx < length; idx ++) { 511 | if (that._maxTouchesReached()) { 512 | break; 513 | } 514 | 515 | touch = touches[idx]; 516 | 517 | if (filter) { 518 | target = $(touch.currentTarget); // target.is(filter) ? target : target.closest(filter, that.element); 519 | } else { 520 | target = that.element; 521 | } 522 | 523 | if (!target.length) { 524 | continue; 525 | } 526 | 527 | touch = new Touch(that, target, touch); 528 | that.touches.push(touch); 529 | touch.press(); 530 | 531 | if (that._isMultiTouch()) { 532 | that.notify("gesturestart", {}); 533 | } 534 | } 535 | }, 536 | 537 | _move: function(e) { 538 | this._eachTouch("move", e); 539 | }, 540 | 541 | _end: function(e) { 542 | this._eachTouch("end", e); 543 | }, 544 | 545 | _eachTouch: function(methodName, e) { 546 | var that = this, 547 | dict = {}, 548 | touches = getTouches(e), 549 | activeTouches = that.touches, 550 | idx, 551 | touch, 552 | touchInfo, 553 | matchingTouch; 554 | 555 | for (idx = 0; idx < activeTouches.length; idx ++) { 556 | touch = activeTouches[idx]; 557 | dict[touch.id] = touch; 558 | } 559 | 560 | for (idx = 0; idx < touches.length; idx ++) { 561 | touchInfo = touches[idx]; 562 | matchingTouch = dict[touchInfo.id]; 563 | 564 | if (matchingTouch) { 565 | matchingTouch[methodName](touchInfo); 566 | } 567 | } 568 | }, 569 | 570 | _apiCall: function(type, x, y, target) { 571 | this[type]({ 572 | api: true, 573 | pageX: x, 574 | pageY: y, 575 | clientX: x, 576 | clientY: y, 577 | target: $(target || this.element)[0], 578 | stopPropagation: $.noop, 579 | preventDefault: $.noop 580 | }); 581 | } 582 | }); 583 | 584 | UserEvents.defaultThreshold = function(value) { 585 | DEFAULT_THRESHOLD = value; 586 | }; 587 | 588 | UserEvents.minHold = function(value) { 589 | DEFAULT_MIN_HOLD = value; 590 | }; 591 | 592 | kendo.getTouches = getTouches; 593 | kendo.touchDelta = touchDelta; 594 | kendo.UserEvents = UserEvents; 595 | })(window.kendo.jQuery); 596 | 597 | return window.kendo; 598 | 599 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); -------------------------------------------------------------------------------- /vendor/kendo/kendo.datepicker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.calendar", "./kendo.popup" ], f); 19 | })(function(){ 20 | 21 | (function($, undefined) { 22 | var kendo = window.kendo, 23 | ui = kendo.ui, 24 | Widget = ui.Widget, 25 | parse = kendo.parseDate, 26 | keys = kendo.keys, 27 | template = kendo.template, 28 | activeElement = kendo._activeElement, 29 | DIV = "
", 30 | SPAN = "", 31 | ns = ".kendoDatePicker", 32 | CLICK = "click" + ns, 33 | OPEN = "open", 34 | CLOSE = "close", 35 | CHANGE = "change", 36 | DISABLED = "disabled", 37 | READONLY = "readonly", 38 | DEFAULT = "k-state-default", 39 | FOCUSED = "k-state-focused", 40 | SELECTED = "k-state-selected", 41 | STATEDISABLED = "k-state-disabled", 42 | HOVER = "k-state-hover", 43 | HOVEREVENTS = "mouseenter" + ns + " mouseleave" + ns, 44 | MOUSEDOWN = "mousedown" + ns, 45 | ID = "id", 46 | MIN = "min", 47 | MAX = "max", 48 | MONTH = "month", 49 | ARIA_DISABLED = "aria-disabled", 50 | ARIA_EXPANDED = "aria-expanded", 51 | ARIA_HIDDEN = "aria-hidden", 52 | ARIA_READONLY = "aria-readonly", 53 | calendar = kendo.calendar, 54 | isInRange = calendar.isInRange, 55 | restrictValue = calendar.restrictValue, 56 | isEqualDatePart = calendar.isEqualDatePart, 57 | extend = $.extend, 58 | proxy = $.proxy, 59 | DATE = Date; 60 | 61 | function normalize(options) { 62 | var parseFormats = options.parseFormats, 63 | format = options.format; 64 | 65 | calendar.normalize(options); 66 | 67 | 68 | parseFormats = $.isArray(parseFormats) ? parseFormats : [parseFormats]; 69 | 70 | if (!parseFormats.length) { 71 | parseFormats.push("yyyy-MM-dd"); 72 | } 73 | 74 | if ($.inArray(format, parseFormats) === -1) { 75 | parseFormats.splice(0, 0, options.format); 76 | } 77 | 78 | options.parseFormats = parseFormats; 79 | } 80 | 81 | function preventDefault(e) { 82 | e.preventDefault(); 83 | } 84 | 85 | var DateView = function(options) { 86 | var that = this, id, 87 | body = document.body, 88 | div = $(DIV).attr(ARIA_HIDDEN, "true") 89 | .addClass("k-calendar-container") 90 | .appendTo(body); 91 | 92 | that.options = options = options || {}; 93 | id = options.id; 94 | 95 | if (id) { 96 | id += "_dateview"; 97 | 98 | div.attr(ID, id); 99 | that._dateViewID = id; 100 | } 101 | 102 | that.popup = new ui.Popup(div, extend(options.popup, options, { name: "Popup", isRtl: kendo.support.isRtl(options.anchor) })); 103 | that.div = div; 104 | 105 | that.value(options.value); 106 | }; 107 | 108 | DateView.prototype = { 109 | _calendar: function() { 110 | var that = this; 111 | var calendar = that.calendar; 112 | var options = that.options; 113 | var div; 114 | 115 | if (!calendar) { 116 | div = $(DIV).attr(ID, kendo.guid()) 117 | .appendTo(that.popup.element) 118 | .on(MOUSEDOWN, preventDefault) 119 | .on(CLICK, "td:has(.k-link)", proxy(that._click, that)); 120 | 121 | that.calendar = calendar = new ui.Calendar(div); 122 | that._setOptions(options); 123 | 124 | kendo.calendar.makeUnselectable(calendar.element); 125 | 126 | calendar.navigate(that._value || that._current, options.start); 127 | 128 | that.value(that._value); 129 | } 130 | }, 131 | 132 | _setOptions: function(options) { 133 | this.calendar.setOptions({ 134 | focusOnNav: false, 135 | change: options.change, 136 | culture: options.culture, 137 | dates: options.dates, 138 | depth: options.depth, 139 | footer: options.footer, 140 | format: options.format, 141 | max: options.max, 142 | min: options.min, 143 | month: options.month, 144 | start: options.start 145 | }); 146 | }, 147 | 148 | setOptions: function(options) { 149 | var old = this.options; 150 | 151 | this.options = extend(old, options, { 152 | change: old.change, 153 | close: old.close, 154 | open: old.open 155 | }); 156 | 157 | if (this.calendar) { 158 | this._setOptions(this.options); 159 | } 160 | }, 161 | 162 | destroy: function() { 163 | this.popup.destroy(); 164 | }, 165 | 166 | open: function() { 167 | var that = this; 168 | 169 | that._calendar(); 170 | that.popup.open(); 171 | }, 172 | 173 | close: function() { 174 | this.popup.close(); 175 | }, 176 | 177 | min: function(value) { 178 | this._option(MIN, value); 179 | }, 180 | 181 | max: function(value) { 182 | this._option(MAX, value); 183 | }, 184 | 185 | toggle: function() { 186 | var that = this; 187 | 188 | that[that.popup.visible() ? CLOSE : OPEN](); 189 | }, 190 | 191 | move: function(e) { 192 | var that = this, 193 | key = e.keyCode, 194 | calendar = that.calendar, 195 | selectIsClicked = e.ctrlKey && key == keys.DOWN || key == keys.ENTER, 196 | handled = false; 197 | 198 | if (e.altKey) { 199 | if (key == keys.DOWN) { 200 | that.open(); 201 | e.preventDefault(); 202 | handled = true; 203 | } else if (key == keys.UP) { 204 | that.close(); 205 | e.preventDefault(); 206 | handled = true; 207 | } 208 | 209 | } else if (that.popup.visible()) { 210 | 211 | if (key == keys.ESC || (selectIsClicked && calendar._cell.hasClass(SELECTED))) { 212 | that.close(); 213 | e.preventDefault(); 214 | return true; 215 | } 216 | 217 | that._current = calendar._move(e); 218 | handled = true; 219 | } 220 | 221 | return handled; 222 | }, 223 | 224 | current: function(date) { 225 | this._current = date; 226 | this.calendar._focus(date); 227 | }, 228 | 229 | value: function(value) { 230 | var that = this, 231 | calendar = that.calendar, 232 | options = that.options; 233 | 234 | that._value = value; 235 | that._current = new DATE(+restrictValue(value, options.min, options.max)); 236 | 237 | if (calendar) { 238 | calendar.value(value); 239 | } 240 | }, 241 | 242 | _click: function(e) { 243 | if (e.currentTarget.className.indexOf(SELECTED) !== -1) { 244 | this.close(); 245 | } 246 | }, 247 | 248 | _option: function(option, value) { 249 | var that = this; 250 | var calendar = that.calendar; 251 | 252 | that.options[option] = value; 253 | 254 | if (calendar) { 255 | calendar[option](value); 256 | } 257 | } 258 | }; 259 | 260 | DateView.normalize = normalize; 261 | 262 | kendo.DateView = DateView; 263 | 264 | var DatePicker = Widget.extend({ 265 | init: function(element, options) { 266 | var that = this, 267 | disabled, 268 | div; 269 | 270 | Widget.fn.init.call(that, element, options); 271 | element = that.element; 272 | options = that.options; 273 | 274 | options.min = parse(element.attr("min")) || parse(options.min); 275 | options.max = parse(element.attr("max")) || parse(options.max); 276 | 277 | normalize(options); 278 | 279 | that._initialOptions = extend({}, options); 280 | 281 | that._wrapper(); 282 | 283 | that.dateView = new DateView(extend({}, options, { 284 | id: element.attr(ID), 285 | anchor: that.wrapper, 286 | change: function() { 287 | // calendar is the current scope 288 | that._change(this.value()); 289 | that.close(); 290 | }, 291 | close: function(e) { 292 | if (that.trigger(CLOSE)) { 293 | e.preventDefault(); 294 | } else { 295 | element.attr(ARIA_EXPANDED, false); 296 | div.attr(ARIA_HIDDEN, true); 297 | } 298 | }, 299 | open: function(e) { 300 | var options = that.options, 301 | date; 302 | 303 | if (that.trigger(OPEN)) { 304 | e.preventDefault(); 305 | } else { 306 | if (that.element.val() !== that._oldText) { 307 | date = parse(element.val(), options.parseFormats, options.culture); 308 | 309 | that.dateView[date ? "current" : "value"](date); 310 | } 311 | 312 | element.attr(ARIA_EXPANDED, true); 313 | div.attr(ARIA_HIDDEN, false); 314 | 315 | that._updateARIA(date); 316 | 317 | } 318 | } 319 | })); 320 | div = that.dateView.div; 321 | 322 | that._icon(); 323 | 324 | try { 325 | element[0].setAttribute("type", "text"); 326 | } catch(e) { 327 | element[0].type = "text"; 328 | } 329 | 330 | element 331 | .addClass("k-input") 332 | .attr({ 333 | role: "combobox", 334 | "aria-expanded": false, 335 | "aria-owns": that.dateView._dateViewID 336 | }); 337 | 338 | that._reset(); 339 | that._template(); 340 | 341 | disabled = element.is("[disabled]") || $(that.element).parents("fieldset").is(':disabled'); 342 | if (disabled) { 343 | that.enable(false); 344 | } else { 345 | that.readonly(element.is("[readonly]")); 346 | } 347 | 348 | that._old = that._update(options.value || that.element.val()); 349 | that._oldText = element.val(); 350 | 351 | kendo.notify(that); 352 | }, 353 | events: [ 354 | OPEN, 355 | CLOSE, 356 | CHANGE], 357 | options: { 358 | name: "DatePicker", 359 | value: null, 360 | footer: "", 361 | format: "", 362 | culture: "", 363 | parseFormats: [], 364 | min: new Date(1900, 0, 1), 365 | max: new Date(2099, 11, 31), 366 | start: MONTH, 367 | depth: MONTH, 368 | animation: {}, 369 | month : {}, 370 | dates: [], 371 | ARIATemplate: 'Current focused date is #=kendo.toString(data.current, "D")#' 372 | }, 373 | 374 | setOptions: function(options) { 375 | var that = this; 376 | var value = that._value; 377 | 378 | Widget.fn.setOptions.call(that, options); 379 | 380 | options = that.options; 381 | 382 | options.min = parse(options.min); 383 | options.max = parse(options.max); 384 | 385 | normalize(options); 386 | 387 | that.dateView.setOptions(options); 388 | 389 | if (value) { 390 | that.element.val(kendo.toString(value, options.format, options.culture)); 391 | that._updateARIA(value); 392 | } 393 | }, 394 | 395 | _editable: function(options) { 396 | var that = this, 397 | icon = that._dateIcon.off(ns), 398 | element = that.element.off(ns), 399 | wrapper = that._inputWrapper.off(ns), 400 | readonly = options.readonly, 401 | disable = options.disable; 402 | 403 | if (!readonly && !disable) { 404 | wrapper 405 | .addClass(DEFAULT) 406 | .removeClass(STATEDISABLED) 407 | .on(HOVEREVENTS, that._toggleHover); 408 | 409 | element.removeAttr(DISABLED) 410 | .removeAttr(READONLY) 411 | .attr(ARIA_DISABLED, false) 412 | .attr(ARIA_READONLY, false) 413 | .on("keydown" + ns, proxy(that._keydown, that)) 414 | .on("focusout" + ns, proxy(that._blur, that)) 415 | .on("focus" + ns, function() { 416 | that._inputWrapper.addClass(FOCUSED); 417 | }); 418 | 419 | icon.on(CLICK, proxy(that._click, that)) 420 | .on(MOUSEDOWN, preventDefault); 421 | } else { 422 | wrapper 423 | .addClass(disable ? STATEDISABLED : DEFAULT) 424 | .removeClass(disable ? DEFAULT : STATEDISABLED); 425 | 426 | element.attr(DISABLED, disable) 427 | .attr(READONLY, readonly) 428 | .attr(ARIA_DISABLED, disable) 429 | .attr(ARIA_READONLY, readonly); 430 | } 431 | }, 432 | 433 | readonly: function(readonly) { 434 | this._editable({ 435 | readonly: readonly === undefined ? true : readonly, 436 | disable: false 437 | }); 438 | }, 439 | 440 | enable: function(enable) { 441 | this._editable({ 442 | readonly: false, 443 | disable: !(enable = enable === undefined ? true : enable) 444 | }); 445 | }, 446 | 447 | destroy: function() { 448 | var that = this; 449 | 450 | Widget.fn.destroy.call(that); 451 | 452 | that.dateView.destroy(); 453 | 454 | that.element.off(ns); 455 | that._dateIcon.off(ns); 456 | that._inputWrapper.off(ns); 457 | 458 | if (that._form) { 459 | that._form.off("reset", that._resetHandler); 460 | } 461 | }, 462 | 463 | open: function() { 464 | this.dateView.open(); 465 | }, 466 | 467 | close: function() { 468 | this.dateView.close(); 469 | }, 470 | 471 | min: function(value) { 472 | return this._option(MIN, value); 473 | }, 474 | 475 | max: function(value) { 476 | return this._option(MAX, value); 477 | }, 478 | 479 | value: function(value) { 480 | var that = this; 481 | 482 | if (value === undefined) { 483 | return that._value; 484 | } 485 | 486 | that._old = that._update(value); 487 | 488 | if (that._old === null) { 489 | that.element.val(""); 490 | } 491 | 492 | that._oldText = that.element.val(); 493 | }, 494 | 495 | _toggleHover: function(e) { 496 | $(e.currentTarget).toggleClass(HOVER, e.type === "mouseenter"); 497 | }, 498 | 499 | _blur: function() { 500 | var that = this, 501 | value = that.element.val(); 502 | 503 | that.close(); 504 | if (value !== that._oldText) { 505 | that._change(value); 506 | } 507 | 508 | that._inputWrapper.removeClass(FOCUSED); 509 | }, 510 | 511 | _click: function() { 512 | var that = this, 513 | element = that.element; 514 | 515 | that.dateView.toggle(); 516 | 517 | if (!kendo.support.touch && element[0] !== activeElement()) { 518 | element.focus(); 519 | } 520 | }, 521 | 522 | _change: function(value) { 523 | var that = this; 524 | 525 | value = that._update(value); 526 | 527 | if (+that._old != +value) { 528 | that._old = value; 529 | that._oldText = that.element.val(); 530 | 531 | if (!that._typing) { 532 | // trigger the DOM change event so any subscriber gets notified 533 | that.element.trigger(CHANGE); 534 | } 535 | 536 | that.trigger(CHANGE); 537 | } 538 | 539 | that._typing = false; 540 | }, 541 | 542 | _keydown: function(e) { 543 | var that = this, 544 | dateView = that.dateView, 545 | value = that.element.val(), 546 | handled = false; 547 | 548 | if (!dateView.popup.visible() && e.keyCode == keys.ENTER && value !== that._oldText) { 549 | that._change(value); 550 | } else { 551 | handled = dateView.move(e); 552 | that._updateARIA(dateView._current); 553 | 554 | if (!handled) { 555 | that._typing = true; 556 | } 557 | } 558 | }, 559 | 560 | _icon: function() { 561 | var that = this, 562 | element = that.element, 563 | icon; 564 | 565 | icon = element.next("span.k-select"); 566 | 567 | if (!icon[0]) { 568 | icon = $('select').insertAfter(element); 569 | } 570 | 571 | that._dateIcon = icon.attr({ 572 | "role": "button", 573 | "aria-controls": that.dateView._dateViewID 574 | }); 575 | }, 576 | 577 | _option: function(option, value) { 578 | var that = this, 579 | options = that.options; 580 | 581 | if (value === undefined) { 582 | return options[option]; 583 | } 584 | 585 | value = parse(value, options.parseFormats, options.culture); 586 | 587 | if (!value) { 588 | return; 589 | } 590 | 591 | options[option] = new DATE(+value); 592 | that.dateView[option](value); 593 | }, 594 | 595 | _update: function(value) { 596 | var that = this, 597 | options = that.options, 598 | min = options.min, 599 | max = options.max, 600 | current = that._value, 601 | date = parse(value, options.parseFormats, options.culture), 602 | isSameType = (date === null && current === null) || (date instanceof Date && current instanceof Date), 603 | formattedValue; 604 | 605 | if (+date === +current && isSameType) { 606 | formattedValue = kendo.toString(date, options.format, options.culture); 607 | 608 | if (formattedValue !== value) { 609 | that.element.val(date === null ? value : formattedValue); 610 | } 611 | 612 | return date; 613 | } 614 | 615 | if (date !== null && isEqualDatePart(date, min)) { 616 | date = restrictValue(date, min, max); 617 | } else if (!isInRange(date, min, max)) { 618 | date = null; 619 | } 620 | 621 | that._value = date; 622 | that.dateView.value(date); 623 | that.element.val(date ? kendo.toString(date, options.format, options.culture) : value); 624 | that._updateARIA(date); 625 | 626 | return date; 627 | }, 628 | 629 | _wrapper: function() { 630 | var that = this, 631 | element = that.element, 632 | wrapper; 633 | 634 | wrapper = element.parents(".k-datepicker"); 635 | 636 | if (!wrapper[0]) { 637 | wrapper = element.wrap(SPAN).parent().addClass("k-picker-wrap k-state-default"); 638 | wrapper = wrapper.wrap(SPAN).parent(); 639 | } 640 | 641 | wrapper[0].style.cssText = element[0].style.cssText; 642 | element.css({ 643 | width: "100%", 644 | height: element[0].style.height 645 | }); 646 | 647 | that.wrapper = wrapper.addClass("k-widget k-datepicker k-header") 648 | .addClass(element[0].className); 649 | 650 | that._inputWrapper = $(wrapper[0].firstChild); 651 | }, 652 | 653 | _reset: function() { 654 | var that = this, 655 | element = that.element, 656 | formId = element.attr("form"), 657 | form = formId ? $("#" + formId) : element.closest("form"); 658 | 659 | if (form[0]) { 660 | that._resetHandler = function() { 661 | that.value(element[0].defaultValue); 662 | that.max(that._initialOptions.max); 663 | that.min(that._initialOptions.min); 664 | }; 665 | 666 | that._form = form.on("reset", that._resetHandler); 667 | } 668 | }, 669 | 670 | _template: function() { 671 | this._ariaTemplate = template(this.options.ARIATemplate); 672 | }, 673 | 674 | _updateARIA: function(date) { 675 | var cell; 676 | var that = this; 677 | var calendar = that.dateView.calendar; 678 | 679 | that.element.removeAttr("aria-activedescendant"); 680 | 681 | if (calendar) { 682 | cell = calendar._cell; 683 | cell.attr("aria-label", that._ariaTemplate({ current: date || calendar.current() })); 684 | 685 | that.element.attr("aria-activedescendant", cell.attr("id")); 686 | } 687 | } 688 | }); 689 | 690 | ui.plugin(DatePicker); 691 | 692 | })(window.kendo.jQuery); 693 | 694 | return window.kendo; 695 | 696 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); -------------------------------------------------------------------------------- /vendor/kendo/kendo.numerictextbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Telerik AD 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | (function(f, define){ 18 | define([ "./kendo.core", "./kendo.userevents" ], f); 19 | })(function(){ 20 | 21 | (function($, undefined) { 22 | var kendo = window.kendo, 23 | caret = kendo.caret, 24 | keys = kendo.keys, 25 | ui = kendo.ui, 26 | Widget = ui.Widget, 27 | activeElement = kendo._activeElement, 28 | extractFormat = kendo._extractFormat, 29 | parse = kendo.parseFloat, 30 | placeholderSupported = kendo.support.placeholder, 31 | getCulture = kendo.getCulture, 32 | round = kendo._round, 33 | CHANGE = "change", 34 | DISABLED = "disabled", 35 | READONLY = "readonly", 36 | INPUT = "k-input", 37 | SPIN = "spin", 38 | ns = ".kendoNumericTextBox", 39 | TOUCHEND = "touchend", 40 | MOUSELEAVE = "mouseleave" + ns, 41 | HOVEREVENTS = "mouseenter" + ns + " " + MOUSELEAVE, 42 | DEFAULT = "k-state-default", 43 | FOCUSED = "k-state-focused", 44 | HOVER = "k-state-hover", 45 | FOCUS = "focus", 46 | POINT = ".", 47 | SELECTED = "k-state-selected", 48 | STATEDISABLED = "k-state-disabled", 49 | ARIA_DISABLED = "aria-disabled", 50 | ARIA_READONLY = "aria-readonly", 51 | INTEGER_REGEXP = /^(-)?(\d*)$/, 52 | NULL = null, 53 | proxy = $.proxy, 54 | extend = $.extend; 55 | 56 | var NumericTextBox = Widget.extend({ 57 | init: function(element, options) { 58 | var that = this, 59 | isStep = options && options.step !== undefined, 60 | min, max, step, value, disabled; 61 | 62 | Widget.fn.init.call(that, element, options); 63 | 64 | options = that.options; 65 | element = that.element 66 | .on("focusout" + ns, proxy(that._focusout, that)) 67 | .attr("role", "spinbutton"); 68 | 69 | options.placeholder = options.placeholder || element.attr("placeholder"); 70 | 71 | that._initialOptions = extend({}, options); 72 | 73 | that._reset(); 74 | that._wrapper(); 75 | that._arrows(); 76 | that._input(); 77 | 78 | if (!kendo.support.mobileOS) { 79 | that._text.on(FOCUS + ns, proxy(that._click, that)); 80 | } else { 81 | that._text.on(TOUCHEND + ns + " " + FOCUS + ns, function() { 82 | that._toggleText(false); 83 | element.focus(); 84 | }); 85 | } 86 | 87 | min = that.min(element.attr("min")); 88 | max = that.max(element.attr("max")); 89 | step = that._parse(element.attr("step")); 90 | 91 | if (options.min === NULL && min !== NULL) { 92 | options.min = min; 93 | } 94 | 95 | if (options.max === NULL && max !== NULL) { 96 | options.max = max; 97 | } 98 | 99 | if (!isStep && step !== NULL) { 100 | options.step = step; 101 | } 102 | 103 | element.attr("aria-valuemin", options.min) 104 | .attr("aria-valuemax", options.max); 105 | 106 | options.format = extractFormat(options.format); 107 | 108 | value = options.value; 109 | that.value(value !== NULL ? value : element.val()); 110 | 111 | disabled = element.is("[disabled]") || $(that.element).parents("fieldset").is(':disabled'); 112 | 113 | if (disabled) { 114 | that.enable(false); 115 | } else { 116 | that.readonly(element.is("[readonly]")); 117 | } 118 | 119 | kendo.notify(that); 120 | }, 121 | 122 | options: { 123 | name: "NumericTextBox", 124 | decimals: NULL, 125 | min: NULL, 126 | max: NULL, 127 | value: NULL, 128 | step: 1, 129 | culture: "", 130 | format: "n", 131 | spinners: true, 132 | placeholder: "", 133 | upArrowText: "Increase value", 134 | downArrowText: "Decrease value" 135 | }, 136 | events: [ 137 | CHANGE, 138 | SPIN 139 | ], 140 | 141 | _editable: function(options) { 142 | var that = this, 143 | element = that.element, 144 | disable = options.disable, 145 | readonly = options.readonly, 146 | text = that._text.add(element), 147 | wrapper = that._inputWrapper.off(HOVEREVENTS); 148 | 149 | that._toggleText(true); 150 | 151 | that._upArrowEventHandler.unbind("press"); 152 | that._downArrowEventHandler.unbind("press"); 153 | element.off("keydown" + ns).off("keypress" + ns).off("paste" + ns); 154 | 155 | if (!readonly && !disable) { 156 | wrapper 157 | .addClass(DEFAULT) 158 | .removeClass(STATEDISABLED) 159 | .on(HOVEREVENTS, that._toggleHover); 160 | 161 | text.removeAttr(DISABLED) 162 | .removeAttr(READONLY) 163 | .attr(ARIA_DISABLED, false) 164 | .attr(ARIA_READONLY, false); 165 | 166 | that._upArrowEventHandler.bind("press", function(e) { 167 | e.preventDefault(); 168 | that._spin(1); 169 | that._upArrow.addClass(SELECTED); 170 | }); 171 | 172 | that._downArrowEventHandler.bind("press", function(e) { 173 | e.preventDefault(); 174 | that._spin(-1); 175 | that._downArrow.addClass(SELECTED); 176 | }); 177 | 178 | that.element 179 | .on("keydown" + ns, proxy(that._keydown, that)) 180 | .on("keypress" + ns, proxy(that._keypress, that)) 181 | .on("paste" + ns, proxy(that._paste, that)); 182 | 183 | } else { 184 | wrapper 185 | .addClass(disable ? STATEDISABLED : DEFAULT) 186 | .removeClass(disable ? DEFAULT : STATEDISABLED); 187 | 188 | text.attr(DISABLED, disable) 189 | .attr(READONLY, readonly) 190 | .attr(ARIA_DISABLED, disable) 191 | .attr(ARIA_READONLY, readonly); 192 | } 193 | }, 194 | 195 | readonly: function(readonly) { 196 | this._editable({ 197 | readonly: readonly === undefined ? true : readonly, 198 | disable: false 199 | }); 200 | }, 201 | 202 | enable: function(enable) { 203 | this._editable({ 204 | readonly: false, 205 | disable: !(enable = enable === undefined ? true : enable) 206 | }); 207 | }, 208 | 209 | destroy: function() { 210 | var that = this; 211 | 212 | that.element 213 | .add(that._text) 214 | .add(that._upArrow) 215 | .add(that._downArrow) 216 | .add(that._inputWrapper) 217 | .off(ns); 218 | 219 | that._upArrowEventHandler.destroy(); 220 | that._downArrowEventHandler.destroy(); 221 | 222 | if (that._form) { 223 | that._form.off("reset", that._resetHandler); 224 | } 225 | 226 | Widget.fn.destroy.call(that); 227 | }, 228 | 229 | min: function(value) { 230 | return this._option("min", value); 231 | }, 232 | 233 | max: function(value) { 234 | return this._option("max", value); 235 | }, 236 | 237 | step: function(value) { 238 | return this._option("step", value); 239 | }, 240 | 241 | value: function(value) { 242 | var that = this, adjusted; 243 | 244 | if (value === undefined) { 245 | return that._value; 246 | } 247 | 248 | value = that._parse(value); 249 | adjusted = that._adjust(value); 250 | 251 | if (value !== adjusted) { 252 | return; 253 | } 254 | 255 | that._update(value); 256 | that._old = that._value; 257 | }, 258 | 259 | focus: function() { 260 | this._focusin(); 261 | }, 262 | 263 | _adjust: function(value) { 264 | var that = this, 265 | options = that.options, 266 | min = options.min, 267 | max = options.max; 268 | 269 | if (value === NULL) { 270 | return value; 271 | } 272 | 273 | if (min !== NULL && value < min) { 274 | value = min; 275 | } else if (max !== NULL && value > max) { 276 | value = max; 277 | } 278 | 279 | return value; 280 | }, 281 | 282 | _arrows: function() { 283 | var that = this, 284 | arrows, 285 | _release = function() { 286 | clearTimeout( that._spinning ); 287 | arrows.removeClass(SELECTED); 288 | }, 289 | options = that.options, 290 | spinners = options.spinners, 291 | element = that.element; 292 | 293 | arrows = element.siblings(".k-icon"); 294 | 295 | if (!arrows[0]) { 296 | arrows = $(buttonHtml("n", options.upArrowText) + buttonHtml("s", options.downArrowText)) 297 | .insertAfter(element); 298 | 299 | arrows.wrapAll(''); 300 | } 301 | 302 | if (!spinners) { 303 | arrows.parent().toggle(spinners); 304 | that._inputWrapper.addClass("k-expand-padding"); 305 | } 306 | 307 | that._upArrow = arrows.eq(0); 308 | that._upArrowEventHandler = new kendo.UserEvents(that._upArrow, { release: _release }); 309 | that._downArrow = arrows.eq(1); 310 | that._downArrowEventHandler = new kendo.UserEvents(that._downArrow, { release: _release }); 311 | }, 312 | 313 | _blur: function() { 314 | var that = this; 315 | 316 | that._toggleText(true); 317 | that._change(that.element.val()); 318 | }, 319 | 320 | _click: function(e) { 321 | var that = this; 322 | 323 | clearTimeout(that._focusing); 324 | that._focusing = setTimeout(function() { 325 | var input = e.target, 326 | idx = caret(input)[0], 327 | value = input.value.substring(0, idx), 328 | format = that._format(that.options.format), 329 | group = format[","], 330 | result, groupRegExp, extractRegExp, 331 | caretPosition = 0; 332 | 333 | if (group) { 334 | groupRegExp = new RegExp("\\" + group, "g"); 335 | extractRegExp = new RegExp("([\\d\\" + group + "]+)(\\" + format[POINT] + ")?(\\d+)?"); 336 | } 337 | 338 | if (extractRegExp) { 339 | result = extractRegExp.exec(value); 340 | } 341 | 342 | if (result) { 343 | caretPosition = result[0].replace(groupRegExp, "").length; 344 | 345 | if (value.indexOf("(") != -1 && that._value < 0) { 346 | caretPosition++; 347 | } 348 | } 349 | 350 | that._focusin(); 351 | 352 | caret(that.element[0], caretPosition); 353 | }); 354 | }, 355 | 356 | _change: function(value) { 357 | var that = this; 358 | 359 | that._update(value); 360 | value = that._value; 361 | 362 | if (that._old != value) { 363 | that._old = value; 364 | 365 | if (!that._typing) { 366 | // trigger the DOM change event so any subscriber gets notified 367 | that.element.trigger(CHANGE); 368 | } 369 | 370 | that.trigger(CHANGE); 371 | } 372 | 373 | that._typing = false; 374 | }, 375 | 376 | _culture: function(culture) { 377 | return culture || getCulture(this.options.culture); 378 | }, 379 | 380 | _focusin: function() { 381 | var that = this; 382 | that._inputWrapper.addClass(FOCUSED); 383 | that._toggleText(false); 384 | that.element[0].focus(); 385 | }, 386 | 387 | _focusout: function() { 388 | var that = this; 389 | 390 | clearTimeout(that._focusing); 391 | that._inputWrapper.removeClass(FOCUSED).removeClass(HOVER); 392 | that._blur(); 393 | }, 394 | 395 | _format: function(format, culture) { 396 | var numberFormat = this._culture(culture).numberFormat; 397 | 398 | format = format.toLowerCase(); 399 | 400 | if (format.indexOf("c") > -1) { 401 | numberFormat = numberFormat.currency; 402 | } else if (format.indexOf("p") > -1) { 403 | numberFormat = numberFormat.percent; 404 | } 405 | 406 | return numberFormat; 407 | }, 408 | 409 | _input: function() { 410 | var that = this, 411 | CLASSNAME = "k-formatted-value", 412 | element = that.element.addClass(INPUT).show()[0], 413 | accessKey = element.accessKey, 414 | wrapper = that.wrapper, 415 | text; 416 | 417 | text = wrapper.find(POINT + CLASSNAME); 418 | 419 | if (!text[0]) { 420 | text = $('').insertBefore(element).addClass(CLASSNAME); 421 | } 422 | 423 | try { 424 | element.setAttribute("type", "text"); 425 | } catch(e) { 426 | element.type = "text"; 427 | } 428 | 429 | text[0].tabIndex = element.tabIndex; 430 | text[0].style.cssText = element.style.cssText; 431 | text[0].title = element.title; 432 | text.prop("placeholder", that.options.placeholder); 433 | 434 | if (accessKey) { 435 | text.attr("accesskey", accessKey); 436 | element.accessKey = ""; 437 | } 438 | 439 | that._text = text.addClass(element.className); 440 | }, 441 | 442 | _keydown: function(e) { 443 | var that = this, 444 | key = e.keyCode; 445 | 446 | that._key = key; 447 | 448 | if (key == keys.DOWN) { 449 | that._step(-1); 450 | } else if (key == keys.UP) { 451 | that._step(1); 452 | } else if (key == keys.ENTER) { 453 | that._change(that.element.val()); 454 | } else { 455 | that._typing = true; 456 | } 457 | 458 | }, 459 | 460 | _keypress: function(e) { 461 | if (e.which === 0 || e.metaKey || e.ctrlKey || e.keyCode === keys.BACKSPACE || e.keyCode === keys.ENTER) { 462 | return; 463 | } 464 | 465 | var that = this; 466 | var min = that.options.min; 467 | var element = that.element; 468 | var selection = caret(element); 469 | var selectionStart = selection[0]; 470 | var selectionEnd = selection[1]; 471 | var character = String.fromCharCode(e.which); 472 | var numberFormat = that._format(that.options.format); 473 | var isNumPadDecimal = that._key === keys.NUMPAD_DOT; 474 | var value = element.val(); 475 | var isValid; 476 | 477 | if (isNumPadDecimal) { 478 | character = numberFormat[POINT]; 479 | } 480 | 481 | value = value.substring(0, selectionStart) + character + value.substring(selectionEnd); 482 | isValid = that._numericRegex(numberFormat).test(value); 483 | 484 | if (isValid && isNumPadDecimal) { 485 | element.val(value); 486 | caret(element, selectionStart + character.length); 487 | 488 | e.preventDefault(); 489 | } else if ((min !== null && min >= 0 && value.charAt(0) === "-") || !isValid) { 490 | e.preventDefault(); 491 | } 492 | 493 | that._key = 0; 494 | }, 495 | 496 | _numericRegex: function(numberFormat) { 497 | var that = this; 498 | var separator = numberFormat[POINT]; 499 | var precision = that.options.decimals; 500 | 501 | if (separator === POINT) { 502 | separator = "\\" + separator; 503 | } 504 | 505 | if (precision === NULL) { 506 | precision = numberFormat.decimals; 507 | } 508 | 509 | if (precision === 0) { 510 | return INTEGER_REGEXP; 511 | } 512 | 513 | if (that._separator !== separator) { 514 | that._separator = separator; 515 | that._floatRegExp = new RegExp("^(-)?(((\\d+(" + separator + "\\d*)?)|(" + separator + "\\d*)))?$"); 516 | } 517 | 518 | return that._floatRegExp; 519 | }, 520 | 521 | _paste: function(e) { 522 | var that = this, 523 | element = e.target, 524 | value = element.value; 525 | 526 | setTimeout(function() { 527 | if (that._parse(element.value) === NULL) { 528 | that._update(value); 529 | } 530 | }); 531 | }, 532 | 533 | _option: function(option, value) { 534 | var that = this, 535 | options = that.options; 536 | 537 | if (value === undefined) { 538 | return options[option]; 539 | } 540 | 541 | value = that._parse(value); 542 | 543 | if (!value && option === "step") { 544 | return; 545 | } 546 | 547 | options[option] = value; 548 | that.element 549 | .attr("aria-value" + option, value) 550 | .attr(option, value); 551 | }, 552 | 553 | _spin: function(step, timeout) { 554 | var that = this; 555 | 556 | timeout = timeout || 500; 557 | 558 | clearTimeout( that._spinning ); 559 | that._spinning = setTimeout(function() { 560 | that._spin(step, 50); 561 | }, timeout ); 562 | 563 | that._step(step); 564 | }, 565 | 566 | _step: function(step) { 567 | var that = this, 568 | element = that.element, 569 | value = that._parse(element.val()) || 0; 570 | 571 | if (activeElement() != element[0]) { 572 | that._focusin(); 573 | } 574 | 575 | value += that.options.step * step; 576 | 577 | that._update(that._adjust(value)); 578 | that._typing = false; 579 | 580 | that.trigger(SPIN); 581 | }, 582 | 583 | _toggleHover: function(e) { 584 | $(e.currentTarget).toggleClass(HOVER, e.type === "mouseenter"); 585 | }, 586 | 587 | _toggleText: function(toggle) { 588 | var that = this; 589 | 590 | that._text.toggle(toggle); 591 | that.element.toggle(!toggle); 592 | }, 593 | 594 | _parse: function(value, culture) { 595 | return parse(value, this._culture(culture), this.options.format); 596 | }, 597 | 598 | _update: function(value) { 599 | var that = this, 600 | options = that.options, 601 | format = options.format, 602 | decimals = options.decimals, 603 | culture = that._culture(), 604 | numberFormat = that._format(format, culture), 605 | isNotNull; 606 | 607 | if (decimals === NULL) { 608 | decimals = numberFormat.decimals; 609 | } 610 | 611 | value = that._parse(value, culture); 612 | 613 | isNotNull = value !== NULL; 614 | 615 | if (isNotNull) { 616 | value = parseFloat(round(value, decimals)); 617 | } 618 | 619 | that._value = value = that._adjust(value); 620 | that._placeholder(kendo.toString(value, format, culture)); 621 | 622 | if (isNotNull) { 623 | value = value.toString(); 624 | if (value.indexOf("e") !== -1) { 625 | value = round(+value, decimals); 626 | } 627 | value = value.replace(POINT, numberFormat[POINT]); 628 | } else { 629 | value = ""; 630 | } 631 | 632 | that.element.val(value).attr("aria-valuenow", value); 633 | }, 634 | 635 | _placeholder: function(value) { 636 | this._text.val(value); 637 | if (!placeholderSupported && !value) { 638 | this._text.val(this.options.placeholder); 639 | } 640 | }, 641 | 642 | _wrapper: function() { 643 | var that = this, 644 | element = that.element, 645 | DOMElement = element[0], 646 | wrapper; 647 | 648 | wrapper = element.parents(".k-numerictextbox"); 649 | 650 | if (!wrapper.is("span.k-numerictextbox")) { 651 | wrapper = element.hide().wrap('').parent(); 652 | wrapper = wrapper.wrap("").parent(); 653 | } 654 | 655 | wrapper[0].style.cssText = DOMElement.style.cssText; 656 | DOMElement.style.width = ""; 657 | that.wrapper = wrapper.addClass("k-widget k-numerictextbox") 658 | .addClass(DOMElement.className) 659 | .css("display", ""); 660 | 661 | that._inputWrapper = $(wrapper[0].firstChild); 662 | }, 663 | 664 | _reset: function() { 665 | var that = this, 666 | element = that.element, 667 | formId = element.attr("form"), 668 | form = formId ? $("#" + formId) : element.closest("form"); 669 | 670 | if (form[0]) { 671 | that._resetHandler = function() { 672 | setTimeout(function() { 673 | that.value(element[0].value); 674 | that.max(that._initialOptions.max); 675 | that.min(that._initialOptions.min); 676 | }); 677 | }; 678 | 679 | that._form = form.on("reset", that._resetHandler); 680 | } 681 | } 682 | }); 683 | 684 | function buttonHtml(className, text) { 685 | return '' + text + ''; 686 | } 687 | 688 | ui.plugin(NumericTextBox); 689 | })(window.kendo.jQuery); 690 | 691 | return window.kendo; 692 | 693 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); }); --------------------------------------------------------------------------------