├── .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 |
121 |
122 |
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 |
120 |
121 |
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 |
156 |
157 |
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 = '',
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 | $('') .attr(attr).appendTo(container);
146 | $('').hide().appendTo(container);
147 | }
148 | };
149 |
150 | function addValidationRules(modelField, rules) {
151 | var validation = modelField ? (modelField.validation || {}) : {},
152 | rule,
153 | descriptor;
154 |
155 | for (rule in validation) {
156 | descriptor = validation[rule];
157 |
158 | if (isPlainObject(descriptor) && descriptor.value) {
159 | descriptor = descriptor.value;
160 | }
161 |
162 | if (isFunction(descriptor)) {
163 | rules[rule] = descriptor;
164 | }
165 | }
166 | }
167 |
168 | var Editable = Widget.extend({
169 | init: function(element, options) {
170 | var that = this;
171 |
172 | if (options.target) {
173 | options.$angular = options.target.options.$angular;
174 | }
175 | Widget.fn.init.call(that, element, options);
176 | that._validateProxy = $.proxy(that._validate, that);
177 | that.refresh();
178 | },
179 |
180 | events: [CHANGE],
181 |
182 | options: {
183 | name: "Editable",
184 | editors: editors,
185 | clearContainer: true,
186 | errorTemplate: ERRORTEMPLATE
187 | },
188 |
189 | editor: function(field, modelField) {
190 | var that = this,
191 | editors = that.options.editors,
192 | isObject = isPlainObject(field),
193 | fieldName = isObject ? field.field : field,
194 | model = that.options.model || {},
195 | isValuesEditor = isObject && field.values,
196 | type = isValuesEditor ? "values" : fieldType(modelField),
197 | isCustomEditor = isObject && field.editor,
198 | editor = isCustomEditor ? field.editor : editors[type],
199 | container = that.element.find("[" + kendo.attr("container-for") + "=" + fieldName.replace(nameSpecialCharRegExp, "\\$1")+ "]");
200 |
201 | editor = editor ? editor : editors.string;
202 |
203 | if (isCustomEditor && typeof field.editor === "string") {
204 | editor = function(container) {
205 | container.append(field.editor);
206 | };
207 | }
208 |
209 | container = container.length ? container : that.element;
210 | editor(container, extend(true, {}, isObject ? field : { field: fieldName }, { model: model }));
211 | },
212 |
213 | _validate: function(e) {
214 | var that = this,
215 | input,
216 | value = e.value,
217 | preventChangeTrigger = that._validationEventInProgress,
218 | values = {},
219 | bindAttribute = kendo.attr("bind"),
220 | fieldName = e.field.replace(nameSpecialCharRegExp, "\\$1"),
221 | bindingRegex = new RegExp("(value|checked)\\s*:\\s*" + fieldName + "\\s*(,|$)");
222 |
223 | values[e.field] = e.value;
224 |
225 | input = $(':input[' + bindAttribute + '*="' + fieldName + '"]', that.element)
226 | .filter("[" + kendo.attr("validate") + "!='false']").filter(function() {
227 | return bindingRegex.test($(this).attr(bindAttribute));
228 | });
229 | if (input.length > 1) {
230 | input = input.filter(function () {
231 | var element = $(this);
232 | return !element.is(":radio") || element.val() == value;
233 | });
234 | }
235 |
236 | try {
237 | that._validationEventInProgress = true;
238 |
239 | if (!that.validatable.validateInput(input) || (!preventChangeTrigger && that.trigger(CHANGE, { values: values }))) {
240 | e.preventDefault();
241 | }
242 |
243 | } finally {
244 | that._validationEventInProgress = false;
245 | }
246 | },
247 |
248 | end: function() {
249 | return this.validatable.validate();
250 | },
251 |
252 | destroy: function() {
253 | var that = this;
254 |
255 | that.angular("cleanup", function(){
256 | return { elements: that.element };
257 | });
258 |
259 | Widget.fn.destroy.call(that);
260 |
261 | that.options.model.unbind("set", that._validateProxy);
262 |
263 | kendo.unbind(that.element);
264 |
265 | if (that.validatable) {
266 | that.validatable.destroy();
267 | }
268 | kendo.destroy(that.element);
269 |
270 | that.element.removeData("kendoValidator");
271 | },
272 |
273 | refresh: function() {
274 | var that = this,
275 | idx,
276 | length,
277 | fields = that.options.fields || [],
278 | container = that.options.clearContainer ? that.element.empty() : that.element,
279 | model = that.options.model || {},
280 | rules = {},
281 | field,
282 | isObject,
283 | fieldName,
284 | modelField,
285 | modelFields;
286 |
287 | if (!$.isArray(fields)) {
288 | fields = [fields];
289 | }
290 |
291 | for (idx = 0, length = fields.length; idx < length; idx++) {
292 | field = fields[idx];
293 | isObject = isPlainObject(field);
294 | fieldName = isObject ? field.field : field;
295 | modelField = (model.fields || model)[fieldName];
296 |
297 | addValidationRules(modelField, rules);
298 |
299 | that.editor(field, modelField);
300 | }
301 |
302 | if (that.options.target) {
303 | that.angular("compile", function(){
304 | return {
305 | elements: container,
306 | data: container.map(function() { return { dataItem: model }; })
307 | };
308 | });
309 | }
310 |
311 | if (!length) {
312 | modelFields = model.fields || model;
313 | for (fieldName in modelFields) {
314 | addValidationRules(modelFields[fieldName], rules);
315 | }
316 | }
317 |
318 | convertToValueBinding(container);
319 |
320 | if (that.validatable) {
321 | that.validatable.destroy();
322 | }
323 |
324 | kendo.bind(container, that.options.model);
325 |
326 | that.options.model.unbind("set", that._validateProxy);
327 | that.options.model.bind("set", that._validateProxy);
328 |
329 | that.validatable = new kendo.ui.Validator(container, {
330 | validateOnBlur: false,
331 | errorTemplate: that.options.errorTemplate || undefined,
332 | rules: rules });
333 |
334 | var focusable = container.find(":kendoFocusable").eq(0).focus();
335 | if (oldIE) {
336 | focusable.focus();
337 | }
338 | }
339 | });
340 |
341 | ui.plugin(Editable);
342 | })(window.kendo.jQuery);
343 |
344 | return window.kendo;
345 |
346 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); });
--------------------------------------------------------------------------------
/vendor/kendo/kendo.selectable.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 | Widget = kendo.ui.Widget,
24 | proxy = $.proxy,
25 | abs = Math.abs,
26 | ARIASELECTED = "aria-selected",
27 | SELECTED = "k-state-selected",
28 | ACTIVE = "k-state-selecting",
29 | SELECTABLE = "k-selectable",
30 | CHANGE = "change",
31 | NS = ".kendoSelectable",
32 | UNSELECTING = "k-state-unselecting",
33 | INPUTSELECTOR = "input,a,textarea,.k-multiselect-wrap,select,button,a.k-button>.k-icon,button.k-button>.k-icon,span.k-icon.k-i-expand,span.k-icon.k-i-collapse",
34 | msie = kendo.support.browser.msie,
35 | supportEventDelegation = false;
36 |
37 | (function($) {
38 | (function() {
39 | $('
')
40 | .on("click", ">*", function() {
41 | supportEventDelegation = true;
42 | })
43 | .find("span")
44 | .click()
45 | .end()
46 | .off();
47 | })();
48 | })($);
49 |
50 | var Selectable = Widget.extend({
51 | init: function(element, options) {
52 | var that = this,
53 | multiple;
54 |
55 | Widget.fn.init.call(that, element, options);
56 |
57 | that._marquee = $("");
58 | that._lastActive = null;
59 | that.element.addClass(SELECTABLE);
60 |
61 | that.relatedTarget = that.options.relatedTarget;
62 |
63 | multiple = that.options.multiple;
64 |
65 | if (this.options.aria && multiple) {
66 | that.element.attr("aria-multiselectable", true);
67 | }
68 |
69 | that.userEvents = new kendo.UserEvents(that.element, {
70 | global: true,
71 | allowSelection: true,
72 | filter: (!supportEventDelegation ? "." + SELECTABLE + " " : "") + that.options.filter,
73 | tap: proxy(that._tap, that)
74 | });
75 |
76 | if (multiple) {
77 | that.userEvents
78 | .bind("start", proxy(that._start, that))
79 | .bind("move", proxy(that._move, that))
80 | .bind("end", proxy(that._end, that))
81 | .bind("select", proxy(that._select, that));
82 | }
83 | },
84 |
85 | events: [CHANGE],
86 |
87 | options: {
88 | name: "Selectable",
89 | filter: ">*",
90 | multiple: false,
91 | relatedTarget: $.noop
92 | },
93 |
94 | _isElement: function(target) {
95 | var elements = this.element;
96 | var idx, length = elements.length, result = false;
97 |
98 | target = target[0];
99 |
100 | for (idx = 0; idx < length; idx ++) {
101 | if (elements[idx] === target) {
102 | result = true;
103 | break;
104 | }
105 | }
106 |
107 | return result;
108 | },
109 |
110 | _tap: function(e) {
111 | var target = $(e.target),
112 | that = this,
113 | ctrlKey = e.event.ctrlKey || e.event.metaKey,
114 | multiple = that.options.multiple,
115 | shiftKey = multiple && e.event.shiftKey,
116 | selected,
117 | whichCode = e.event.which,
118 | buttonCode = e.event.button;
119 |
120 | //in case of hierarchy or right-click
121 | if (!that._isElement(target.closest("." + SELECTABLE)) || whichCode && whichCode == 3 || buttonCode && buttonCode == 2) {
122 | return;
123 | }
124 |
125 | if (!this._allowSelection(e.event.target)) {
126 | return;
127 | }
128 |
129 | selected = target.hasClass(SELECTED);
130 | if (!multiple || !ctrlKey) {
131 | that.clear();
132 | }
133 |
134 | target = target.add(that.relatedTarget(target));
135 |
136 | if (shiftKey) {
137 | that.selectRange(that._firstSelectee(), target);
138 | } else {
139 | if (selected && ctrlKey) {
140 | that._unselect(target);
141 | that._notify(CHANGE);
142 | } else {
143 | that.value(target);
144 | }
145 |
146 | that._lastActive = that._downTarget = target;
147 | }
148 | },
149 |
150 | _start: function(e) {
151 | var that = this,
152 | target = $(e.target),
153 | selected = target.hasClass(SELECTED),
154 | currentElement,
155 | ctrlKey = e.event.ctrlKey || e.event.metaKey;
156 |
157 | if (!this._allowSelection(e.event.target)) {
158 | return;
159 | }
160 |
161 | that._downTarget = target;
162 |
163 | //in case of hierarchy
164 | if (!that._isElement(target.closest("." + SELECTABLE))) {
165 | that.userEvents.cancel();
166 | return;
167 | }
168 |
169 | if (that.options.useAllItems) {
170 | that._items = that.element.find(that.options.filter);
171 | } else {
172 | currentElement = target.closest(that.element);
173 | that._items = currentElement.find(that.options.filter);
174 | }
175 |
176 | e.sender.capture();
177 |
178 | that._marquee
179 | .appendTo(document.body)
180 | .css({
181 | left: e.x.client + 1,
182 | top: e.y.client + 1,
183 | width: 0,
184 | height: 0
185 | });
186 |
187 | if (!ctrlKey) {
188 | that.clear();
189 | }
190 |
191 | target = target.add(that.relatedTarget(target));
192 | if (selected) {
193 | that._selectElement(target, true);
194 | if (ctrlKey) {
195 | target.addClass(UNSELECTING);
196 | }
197 | }
198 | },
199 |
200 | _move: function(e) {
201 | var that = this,
202 | position = {
203 | left: e.x.startLocation > e.x.location ? e.x.location : e.x.startLocation,
204 | top: e.y.startLocation > e.y.location ? e.y.location : e.y.startLocation,
205 | width: abs(e.x.initialDelta),
206 | height: abs(e.y.initialDelta)
207 | };
208 |
209 | that._marquee.css(position);
210 |
211 | that._invalidateSelectables(position, (e.event.ctrlKey || e.event.metaKey));
212 |
213 | e.preventDefault();
214 | },
215 |
216 | _end: function() {
217 | var that = this;
218 |
219 | that._marquee.remove();
220 |
221 | that._unselect(that.element
222 | .find(that.options.filter + "." + UNSELECTING))
223 | .removeClass(UNSELECTING);
224 |
225 |
226 | var target = that.element.find(that.options.filter + "." + ACTIVE);
227 | target = target.add(that.relatedTarget(target));
228 |
229 | that.value(target);
230 | that._lastActive = that._downTarget;
231 | that._items = null;
232 | },
233 |
234 | _invalidateSelectables: function(position, ctrlKey) {
235 | var idx,
236 | length,
237 | target = this._downTarget[0],
238 | items = this._items,
239 | related,
240 | toSelect;
241 |
242 | for (idx = 0, length = items.length; idx < length; idx ++) {
243 | toSelect = items.eq(idx);
244 | related = toSelect.add(this.relatedTarget(toSelect));
245 |
246 | if (collision(toSelect, position)) {
247 | if(toSelect.hasClass(SELECTED)) {
248 | if(ctrlKey && target !== toSelect[0]) {
249 | related.removeClass(SELECTED).addClass(UNSELECTING);
250 | }
251 | } else if (!toSelect.hasClass(ACTIVE) && !toSelect.hasClass(UNSELECTING)) {
252 | related.addClass(ACTIVE);
253 | }
254 | } else {
255 | if (toSelect.hasClass(ACTIVE)) {
256 | related.removeClass(ACTIVE);
257 | } else if(ctrlKey && toSelect.hasClass(UNSELECTING)) {
258 | related.removeClass(UNSELECTING).addClass(SELECTED);
259 | }
260 | }
261 | }
262 | },
263 |
264 | value: function(val) {
265 | var that = this,
266 | selectElement = proxy(that._selectElement, that);
267 |
268 | if(val) {
269 | val.each(function() {
270 | selectElement(this);
271 | });
272 |
273 | that._notify(CHANGE);
274 | return;
275 | }
276 |
277 | return that.element.find(that.options.filter + "." + SELECTED);
278 | },
279 |
280 | _firstSelectee: function() {
281 | var that = this,
282 | selected;
283 |
284 | if(that._lastActive !== null) {
285 | return that._lastActive;
286 | }
287 |
288 | selected = that.value();
289 | return selected.length > 0 ?
290 | selected[0] :
291 | that.element.find(that.options.filter)[0];
292 | },
293 |
294 | _selectElement: function(element, preventNotify) {
295 | var toSelect = $(element),
296 | isPrevented = !preventNotify && this._notify("select", { element: element });
297 |
298 | toSelect.removeClass(ACTIVE);
299 | if(!isPrevented) {
300 | toSelect.addClass(SELECTED);
301 |
302 | if (this.options.aria) {
303 | toSelect.attr(ARIASELECTED, true);
304 | }
305 | }
306 | },
307 |
308 | _notify: function(name, args) {
309 | args = args || { };
310 | return this.trigger(name, args);
311 | },
312 |
313 | _unselect: function(element) {
314 | element.removeClass(SELECTED);
315 |
316 | if (this.options.aria) {
317 | element.attr(ARIASELECTED, false);
318 | }
319 |
320 | return element;
321 | },
322 |
323 | _select: function(e) {
324 | if (this._allowSelection(e.event.target)) {
325 | if (!msie || (msie && !$(kendo._activeElement()).is(INPUTSELECTOR))) {
326 | e.preventDefault();
327 | }
328 | }
329 | },
330 |
331 | _allowSelection: function(target) {
332 | if ($(target).is(INPUTSELECTOR)) {
333 | this.userEvents.cancel();
334 | this._downTarget = null;
335 | return false;
336 | }
337 |
338 | return true;
339 | },
340 |
341 | resetTouchEvents: function() {
342 | this.userEvents.cancel();
343 | },
344 |
345 | clear: function() {
346 | var items = this.element.find(this.options.filter + "." + SELECTED);
347 | this._unselect(items);
348 | },
349 |
350 | selectRange: function(start, end) {
351 | var that = this,
352 | idx,
353 | tmp,
354 | items;
355 |
356 | that.clear();
357 |
358 | if (that.element.length > 1) {
359 | items = that.options.continuousItems();
360 | }
361 |
362 | if (!items || !items.length) {
363 | items = that.element.find(that.options.filter);
364 | }
365 |
366 | start = $.inArray($(start)[0], items);
367 | end = $.inArray($(end)[0], items);
368 |
369 | if (start > end) {
370 | tmp = start;
371 | start = end;
372 | end = tmp;
373 | }
374 |
375 | if (!that.options.useAllItems) {
376 | end += that.element.length - 1;
377 | }
378 |
379 | for (idx = start; idx <= end; idx ++ ) {
380 | that._selectElement(items[idx]);
381 | }
382 |
383 | that._notify(CHANGE);
384 | },
385 |
386 | destroy: function() {
387 | var that = this;
388 |
389 | Widget.fn.destroy.call(that);
390 |
391 | that.element.off(NS);
392 |
393 | that.userEvents.destroy();
394 |
395 | that._marquee = that._lastActive = that.element = that.userEvents = null;
396 | }
397 | });
398 |
399 | Selectable.parseOptions = function(selectable) {
400 | var asLowerString = typeof selectable === "string" && selectable.toLowerCase();
401 |
402 | return {
403 | multiple: asLowerString && asLowerString.indexOf("multiple") > -1,
404 | cell: asLowerString && asLowerString.indexOf("cell") > -1
405 | };
406 | };
407 |
408 | function collision(element, position) {
409 | if (!element.is(":visible")) {
410 | return false;
411 | }
412 |
413 | var elementPosition = kendo.getOffset(element),
414 | right = position.left + position.width,
415 | bottom = position.top + position.height;
416 |
417 | elementPosition.right = elementPosition.left + element.outerWidth();
418 | elementPosition.bottom = elementPosition.top + element.outerHeight();
419 |
420 | return !(elementPosition.left > right||
421 | elementPosition.right < position.left ||
422 | elementPosition.top > bottom ||
423 | elementPosition.bottom < position.top);
424 | }
425 |
426 | kendo.ui.plugin(Selectable);
427 |
428 | })(window.kendo.jQuery);
429 |
430 | return window.kendo;
431 |
432 | }, typeof define == 'function' && define.amd ? define : function(_, f){ f(); });
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kendo-pouchdb
2 |
3 | [](https://travis-ci.org/terikon/kendo-pouchdb)
4 |
5 | [PouchDB]() is the Database that Syncs.
6 | [Kendo UI]() is a set of beautiful UI widgets.
7 | This library connects between the two, so you can bind data from database directly to Kendo and
8 | expect them to be in sync.
9 |
10 | **kendo-pouchdb** has following set of features:
11 |
12 | - Sorting and filtering.
13 | - Standard interface for Kendo UI - accessible as
14 | [kendo.data.DataSource]() object.
15 | - Bi-directional sync between DataSource object and PouchDB. For example, data change on server
16 | will automatically appear in widget.
17 | - Support of two query plugins - [Map Reduce]() and
18 | [PouchDB Find]().
19 | - Different storage scenarios are possible with PouchDB - IndexedDB, Web SQL,
20 | [CouchDB](), [Cloudant]()
21 | or [Couchbase]().
22 | - The library is thoroughly tested with test specs.
23 |
24 | # Table of contents
25 |
26 | - [Demo](#demo)
27 | - [Install](#install)
28 | - [Use](#use)
29 | - [API](#api)
30 | - [Work status](#work-status)
31 | - [Things to consider for future versions](#things-to-consider-for-future-versions)
32 | - [Use with Couchbase Mobile](#use-with-couchbase-mobile)
33 | - [Contribute](#contribute)
34 |
35 | # Demo
36 |
37 | See online demo of kendo-pouchdb:
38 |
39 | [![Demo]()]()
40 |
41 | Demo data is put into PouchDB database named *demodb*, and presented with Kendo Grid. You can create/update/delete records, and they will persist in the database. Just reload the page to see your data stored after modification.
42 |
43 | Using [PouchDB Inspector]() you can change a document in database, and the Grid will
44 | refresh itself to present your change immediately.
45 |
46 | In addition more features can be seen here:
47 |
48 | - [Sorting demo]()
49 | - [Paging demo]()
50 |
51 | Demos source code reside in [demo](https://github.com/terikon/kendo-pouchdb/tree/master/demo) folder.
52 |
53 | # Install
54 |
55 | ## with npm
56 |
57 | ```
58 | npm install kendo-pouchdb
59 | ```
60 |
61 | ## with bower
62 |
63 | ```
64 | bower install kendo-pouchdb
65 | ```
66 |
67 | ## include on page
68 |
69 | Download **kendo-pouchdb.js**,
70 | [minified](https://raw.githubusercontent.com/terikon/kendo-pouchdb/master/dist/kendo-pouchdb.min.js) or
71 | [debug](https://raw.githubusercontent.com/terikon/kendo-pouchdb/master/kendo-pouchdb.js) version.
72 |
73 | Include jQuery, Kendo UI, [pouchdb]()
74 | and [pouchdb-collate.js]().
75 | Optionally, add
76 | [pouchdb.find.js]() for more flexible sorting and filtering.
77 |
78 | ```html
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | ```
88 |
89 | ## AMD support
90 |
91 | For usage with AMD, use
92 | [kendo-pouchdb.amd.js]().
93 |
94 | Example configuration with [RequireJS]():
95 |
96 | ```js
97 | requirejs.config({
98 | paths: {
99 | "PouchDB": "lib/pouchdb/pouchdb",
100 | "pouchCollate": "lib/pouchdb/pouchdb-collate",
101 | },
102 | shim: {
103 | "kendo-pouchdb.amd": { deps: ["kendo"] }
104 | },
105 | map: {
106 | '*': {
107 | 'kendo': 'kendo-pouchdb.amd'
108 | },
109 | 'kendo-pouchdb.amd': { 'kendo': 'kendo' }
110 | }
111 | });
112 | define(['PouchDB'], function (PouchDB) {
113 | //Use PouchDB and kendo.data.PouchableDataSource.
114 | });
115 | ```
116 |
117 | # Use
118 |
119 | The library adds **kendo.data.PouchableDataSource** object to Kendo, that acts like casual
120 | kendo.data.DataSource, but can also be of "pouchdb" type.
121 |
122 | You create pouchdb datasource like this:
123 |
124 | ```js
125 | var dataSource = new kendo.data.PouchableDataSource({
126 | type: "pouchdb",
127 | transport: {
128 | pouchdb: {
129 | db: db,
130 | idField: "ProductID"
131 | }
132 | });
133 | ```
134 |
135 | Now you can do all the things you can do with DataSource, like binding it to Grid or
136 | any other widget, or perform dataSource.filter() or dataSource.sort().
137 |
138 | PouchDB database will serve as remote service for the datasource, so do not forget to call
139 | [dataSource.sync()]()
140 | method when needed.
141 |
142 | You have to provide appropriate model to use with your datasource, due to the fact that id field
143 | for data stored in PouchDB should always be named row._id. You can either define _id field in
144 | your schema, and set model's id to be "_id". Or you can use any name as id field, in which case you
145 | **should not** define model's id in model configuration, as _id field will be created as copy of
146 | if field of your choice automatically.
147 |
148 | In either option, you must tell which field is used as id field with idField option in
149 | transport configuration.
150 |
151 | Example of model configuration "Kendo-way", so _id will be created for you:
152 |
153 | ```js
154 | schema: {
155 | model: {
156 | //Do not supply id field in schema like this, as _id field will be used as id field.
157 | //In other words, do not write here 'id: "ProductID"'.
158 | //Tell the pouchdb transport that your id field is ProductID, and it even can be a number!
159 | fields: {
160 | ProductID: { type: number },
161 | ProductName: { type: string }
162 | }
163 | }
164 | }
165 | ```
166 |
167 | Example of _id field manually defined with model configuration:
168 |
169 | ```js
170 | schema: {
171 | model: {
172 | id: "_id",
173 | fields: {
174 | _id: { type: string }, //If you prefer to use _id directly, it should be string.
175 | ProductName: { type: string }
176 | }
177 | }
178 | }
179 | ```
180 |
181 | _id will be created by applying
182 | [pouchCollate.toIndexableString]()
183 | method to data provided by idField, so data will be sorted correctly, either it is of string or
184 | numeric type.
185 |
186 | ## id field
187 |
188 | id field can be of string and numeric type.
189 | Do not use field of date type as id field.
190 |
191 | ## Model class
192 |
193 | If, instead of model configuration, external model **class** is provided to schema, it **should** have _id field defined as model's id:
194 |
195 | ```js
196 | var Model = kendo.data.Model.define({
197 | id: "_id", //This should be provided when you define your model externally
198 | fields: {
199 | name: { type: "string" }
200 | }
201 | });
202 | ```
203 |
204 | ## Queries
205 |
206 | Sorting and filtering can be used, limited to PouchDB abilities. Just use standard
207 | dataSource.filter() and dataSource.sort() methods, or rely on your UI widget abilities.
208 |
209 | Queries will run directly on
210 | database. You can use two query plugins of PouchDB. Map reduce is currently default query plugin,
211 | but it only has limited set of filter/sort combination. PouchDB Find plugin is currently in
212 | beta state, but its support of data filtering much more liberating, thanks to
213 | [IBM Cloadant query language]().
214 |
215 | In either case, appropriate indexes that enable data fetching should be created in advance.
216 |
217 | ## MapReduce or PouchDB Find
218 |
219 | MapReduce will be used by default, as currently it is stable query plugin.
220 |
221 | To use pouchdb-find, use following transport configuration:
222 |
223 | ```js
224 | transport: {
225 | pouchdb: {
226 | db: db,
227 | queryPlugin: "pouchdb-find", //queryPlugin is 'mapreduce' by default
228 | idField: "_id"
229 | }
230 | });
231 | ```
232 |
233 | ## Default View (MapReduce mode)
234 |
235 | Default view can optionally be provided, so data will be fetched using provided view:
236 |
237 | ```js
238 | var dataSource = new kendo.data.PouchableDataSource({
239 | type: "pouchdb",
240 | transport: {
241 | pouchdb: {
242 | db: db,
243 | idField: "passport",
244 | defaultView: "people/withName"
245 | }
246 | });
247 |
248 | dataSource.fetch().then(function() {
249 | //The data from people/withName view will be fetched.
250 | });
251 | ```
252 |
253 | Pay attention that if sorting specified, sort view from fieldViews will be used instead of default view.
254 |
255 | ## Sorting (MapReduce mode)
256 |
257 | Without configuration, only sorting by id field will work.
258 |
259 | For sort by other fields to work, appropriate PouchDB view should be provided for each field
260 | that will be used for sorting:
261 |
262 | ```js
263 | var dataSource = new kendo.data.PouchableDataSource({
264 | type: "pouchdb",
265 | sort: { field: "name", dir: "asc"},
266 | transport: {
267 | pouchdb: {
268 | db: db,
269 | idField: "passport",
270 | fieldViews: {
271 | "name: "sortIndex/byName",
272 | "age" : "sortIndex/byAge"
273 | }
274 | }
275 | });
276 |
277 | //Now you can sort by name
278 | ```
279 |
280 | Error will be raised if you will try to sort by a field that has no index.
281 |
282 | When sorting by the _id field, do not provide view for it in fieldViews. Use defaultView instead.
283 |
284 | Note: sorting by multiple columns is not supported in map reduce mode.
285 |
286 | ## Filtering (MapReduce mode)
287 |
288 | Filtering is somewhat limited in this mode.
289 |
290 | - Multiple filters are not supported.
291 | - When filer applied to field other than id field, sort should be applied to this field either.
292 | - Currently "neq" and "gt" operators are not supported.
293 |
294 | For supported scenarios, just use
295 | [DataSource filter](). It will be used such as serverFiltering option is set to true.
296 |
297 | ## Filtering and sorting (PouchDB Find mode)
298 |
299 | Filters and sorting can be as complex as pouchdb-find supports.
300 |
301 | ```js
302 | var dataSource = new kendo.data.PouchableDataSource({
303 | type: "pouchdb",
304 | filter: { field: "series", operator: "eq", value: "Mario" },
305 | sort: [ { field: "series", dir: "desc"}, { field: "debut", dir: "desc"} ],
306 | transport: {
307 | pouchdb: {
308 | db: db,
309 | queryPlugin: "pouchdb-find", //queryPlugin is mapreduce by default
310 | idField: "_id"
311 | }
312 | });
313 | ```
314 |
315 | Indexes should be defined beforehand, or query will fail.
316 | When filtering or sorting on, say, ProductID field which is id field, add index on _id field. This
317 | is because internally ProductID will be stored inside the _id field.
318 |
319 | defaultView and fieldViews cannot be used in this mode, do not mix modes.
320 |
321 | Note: when sorting in this mode, be careful with fields that contain null values. When no filter specified when sorting, selector with *$exists=true* condition will be used, so rows with null
322 | values in sort field will not be selected. This is limitation, AFAIK, of pouchdb-find.
323 |
324 | ## More examples
325 |
326 | There is a lot of code to learn from in
327 | [test specs](). Use it to your advantage.
328 |
329 | # API
330 |
331 | In general, **kendo-pouchdb** acts as adapter between Kendo's DataSource object and PouchDB
332 | database.
333 |
334 | kendo.data.PouchableDataSource object extends kendo.data.DataSource and can be used as casual
335 | DataSource.
336 |
337 | To activate kendo-pouchdb, set type option of dataset to "pouchdb", and provide pouchdb transport
338 | in datasource configuration.
339 |
340 | ## kendo.data.PouchableDataSource
341 |
342 | - type: set to "pouchdb".
343 |
344 | ## pouchdb transport
345 |
346 | - db (mandatory). PouchDB database instance.
347 | - idField (mandatory). _id or any other field of model that will be used as id field.
348 | - queryPlugin (optional). "mapreduce" or "pouchdb-find". Default is "mapreduce".
349 | - defaultView (optional)(only in maprecude mode). If set, data will be fetched using this
350 | PouchDB view, when sorting by id.
351 | - fieldViews (optional)(only in maprecude mode). Object of 'field':'view name' pairs for
352 | sorting. View name is in format 'users/byName'.
353 |
354 | # Work status
355 |
356 | Implemented
357 | - CRUD operations on PouchDB database arrive in DataSource in form of push events.
358 | - CRUD operations on DataSource are synced with PouchDB when sync method is called.
359 | - Tests specs for implemented functionality.
360 | - Support for PouchDB Collate in _id.
361 | - Implement sorting (with reduce and db.find).
362 | - Add support for bower.
363 | - Add to npmjs.
364 | - Implement paging.
365 | - Implement filtering (with mapreduce and db.find).
366 | - Make it possible to specify default PouchDB view to work with.
367 | - Add demos.
368 | - Write documentation.
369 |
370 | # Things to consider for future versions
371 |
372 | - Implement grouping.
373 | - Batch update option support.
374 | - Add jsbin/dojo examples.
375 | - Add the lib to CDN.
376 |
377 | # Use with Couchbase Mobile
378 |
379 | There is POC project that tries to binds Kendo Grid with
380 | [Couchbase Mobile](), via
381 | [Couchbase Lite Phonegap plugin](). See [kendo-pouchdb-app]() project.
382 |
383 | Currently it's not functional due to lack of compatibility between PouchDB and Couchbase Mobile,
384 | but let's hope for
385 | [advance in this area]().
386 |
387 | # Contribute
388 |
389 | Use [GitHub issues](https://github.com/terikon/kendo-pouchdb/issues) and [Pull Requests](https://github.com/terikon/kendo-pouchdb/pulls).
390 |
391 | Ideas are welcome as well :)
392 |
393 | To build:
394 |
395 | npm run build
396 |
397 | Before committing, please run jshint:
398 |
399 | npm run jshint
400 |
401 | To run tests:
402 |
403 | npm run test
404 |
405 | Tests reside in [tests/spec](https://github.com/terikon/kendo-pouchdb/tree/master/tests/spec) folder.
406 |
407 | Tests are also runnable in browser and debuggable with [tests/SpecRunner.html](
408 | ).
--------------------------------------------------------------------------------
/vendor/kendo/kendo.pager.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($, undefined) {
22 | var kendo = window.kendo,
23 | ui = kendo.ui,
24 | Widget = ui.Widget,
25 | proxy = $.proxy,
26 | FIRST = ".k-i-seek-w",
27 | LAST = ".k-i-seek-e",
28 | PREV = ".k-i-arrow-w",
29 | NEXT = ".k-i-arrow-e",
30 | CHANGE = "change",
31 | NS = ".kendoPager",
32 | CLICK = "click",
33 | KEYDOWN = "keydown",
34 | DISABLED = "disabled",
35 | iconTemplate = kendo.template('');
36 |
37 | function button(template, idx, text, numeric, title) {
38 | return template( {
39 | idx: idx,
40 | text: text,
41 | ns: kendo.ns,
42 | numeric: numeric,
43 | title: title || ""
44 | });
45 | }
46 |
47 | function icon(className, text, wrapClassName) {
48 | return iconTemplate({
49 | className: className.substring(1),
50 | text: text,
51 | wrapClassName: wrapClassName || ""
52 | });
53 | }
54 |
55 | function update(element, selector, page, disabled) {
56 | element.find(selector)
57 | .parent()
58 | .attr(kendo.attr("page"), page)
59 | .attr("tabindex", -1)
60 | .toggleClass("k-state-disabled", disabled);
61 | }
62 |
63 | function first(element, page) {
64 | update(element, FIRST, 1, page <= 1);
65 | }
66 |
67 | function prev(element, page) {
68 | update(element, PREV, Math.max(1, page - 1), page <= 1);
69 | }
70 |
71 | function next(element, page, totalPages) {
72 | update(element, NEXT, Math.min(totalPages, page + 1), page >= totalPages);
73 | }
74 |
75 | function last(element, page, totalPages) {
76 | update(element, LAST, totalPages, page >= totalPages);
77 | }
78 |
79 | var Pager = Widget.extend( {
80 | init: function(element, options) {
81 | var that = this, page, totalPages;
82 |
83 | Widget.fn.init.call(that, element, options);
84 |
85 | options = that.options;
86 | that.dataSource = kendo.data.DataSource.create(options.dataSource);
87 | that.linkTemplate = kendo.template(that.options.linkTemplate);
88 | that.selectTemplate = kendo.template(that.options.selectTemplate);
89 | that.currentPageTemplate = kendo.template(that.options.currentPageTemplate);
90 |
91 | page = that.page();
92 | totalPages = that.totalPages();
93 |
94 | that._refreshHandler = proxy(that.refresh, that);
95 |
96 | that.dataSource.bind(CHANGE, that._refreshHandler);
97 |
98 | if (options.previousNext) {
99 | if (!that.element.find(FIRST).length) {
100 | that.element.append(icon(FIRST, options.messages.first, "k-pager-first"));
101 |
102 | first(that.element, page, totalPages);
103 | }
104 |
105 | if (!that.element.find(PREV).length) {
106 | that.element.append(icon(PREV, options.messages.previous));
107 |
108 | prev(that.element, page, totalPages);
109 | }
110 | }
111 |
112 | if (options.numeric) {
113 | that.list = that.element.find(".k-pager-numbers");
114 |
115 | if (!that.list.length) {
116 | that.list = $('').appendTo(that.element);
117 | }
118 | }
119 |
120 | if (options.input) {
121 | if (!that.element.find(".k-pager-input").length) {
122 | that.element.append('');
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 | $('")
158 | .appendTo(that.element)
159 | .find("select").html(pageItems.join("")).end()
160 | .appendTo(that.element);
161 | }
162 |
163 | that.element.find(".k-pager-sizes select").val(that.pageSize());
164 |
165 | if (kendo.ui.DropDownList) {
166 | that.element.find(".k-pager-sizes select").show().kendoDropDownList();
167 | }
168 |
169 | that.element.on(CHANGE + NS, ".k-pager-sizes select", proxy(that._change, that));
170 | }
171 |
172 | if (options.refresh) {
173 | if (!that.element.find(".k-pager-refresh").length) {
174 | that.element.append('");
176 | }
177 |
178 | that.element.on(CLICK + NS, ".k-pager-refresh", proxy(that._refreshClick, that));
179 | }
180 |
181 | if (options.info) {
182 | if (!that.element.find(".k-pager-info").length) {
183 | that.element.append('');
184 | }
185 | }
186 |
187 | that.element
188 | .on(CLICK + NS , "a", proxy(that._click, that))
189 | .addClass("k-pager-wrap k-widget k-floatwrap");
190 |
191 | that.element.on(CLICK + NS , ".k-current-page", proxy(that._toggleActive, that));
192 |
193 | if (options.autoBind) {
194 | that.refresh();
195 | }
196 |
197 | kendo.notify(that);
198 | },
199 |
200 | destroy: function() {
201 | var that = this;
202 |
203 | Widget.fn.destroy.call(that);
204 |
205 | that.element.off(NS);
206 | that.dataSource.unbind(CHANGE, that._refreshHandler);
207 | that._refreshHandler = null;
208 |
209 | kendo.destroy(that.element);
210 | that.element = that.list = null;
211 | },
212 |
213 | events: [
214 | CHANGE
215 | ],
216 |
217 | options: {
218 | name: "Pager",
219 | selectTemplate: '#=text#',
220 | currentPageTemplate: '',
221 | linkTemplate: '#=text#',
222 | buttonCount: 10,
223 | autoBind: true,
224 | numeric: true,
225 | info: true,
226 | input: false,
227 | previousNext: true,
228 | pageSizes: false,
229 | refresh: false,
230 | messages: {
231 | allPages: "All",
232 | display: "{0} - {1} of {2} items",
233 | empty: "No items to display",
234 | page: "Page",
235 | of: "of {0}",
236 | itemsPerPage: "items per page",
237 | first: "Go to the first page",
238 | previous: "Go to the previous page",
239 | next: "Go to the next page",
240 | last: "Go to the last page",
241 | refresh: "Refresh",
242 | morePages: "More pages"
243 | }
244 | },
245 |
246 | setDataSource: function(dataSource) {
247 | var that = this;
248 |
249 | that.dataSource.unbind(CHANGE, that._refreshHandler);
250 | that.dataSource = that.options.dataSource = dataSource;
251 | dataSource.bind(CHANGE, that._refreshHandler);
252 |
253 | if (that.options.autoBind) {
254 | dataSource.fetch();
255 | }
256 | },
257 |
258 | refresh: function(e) {
259 | var that = this,
260 | idx,
261 | end,
262 | start = 1,
263 | reminder,
264 | page = that.page(),
265 | html = "",
266 | options = that.options,
267 | pageSize = that.pageSize(),
268 | total = that.dataSource.total(),
269 | totalPages = that.totalPages(),
270 | linkTemplate = that.linkTemplate,
271 | buttonCount = options.buttonCount;
272 |
273 | if (e && e.action == "itemchange") {
274 | return;
275 | }
276 |
277 | if (options.numeric) {
278 |
279 | if (page > buttonCount) {
280 | reminder = (page % buttonCount);
281 |
282 | start = (reminder === 0) ? (page - buttonCount) + 1 : (page - reminder) + 1;
283 | }
284 |
285 | end = Math.min((start + buttonCount) - 1, totalPages);
286 |
287 | if (start > 1) {
288 | html += button(linkTemplate, start - 1, "...", false, options.messages.morePages);
289 | }
290 |
291 | for (idx = start; idx <= end; idx++) {
292 | html += button(idx == page ? that.selectTemplate : linkTemplate, idx, idx, true);
293 | }
294 |
295 | if (end < totalPages) {
296 | html += button(linkTemplate, idx, "...", false, options.messages.morePages);
297 | }
298 |
299 | if (html === "") {
300 | html = that.selectTemplate({ text: 0 });
301 | }
302 |
303 | html = this.currentPageTemplate({ text: page }) + html;
304 |
305 | that.list.removeClass("k-state-expanded").html(html);
306 | }
307 |
308 | if (options.info) {
309 | if (total > 0) {
310 | html = kendo.format(options.messages.display,
311 | (page - 1) * pageSize + 1, // first item in the page
312 | Math.min(page * pageSize, total), // last item in the page
313 | total);
314 | } else {
315 | html = options.messages.empty;
316 | }
317 |
318 | that.element.find(".k-pager-info").html(html);
319 | }
320 |
321 | if (options.input) {
322 | that.element
323 | .find(".k-pager-input")
324 | .html(that.options.messages.page +
325 | '' +
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(); });
--------------------------------------------------------------------------------