├── .gitignore
├── .jshintrc
├── .project
├── .travis.yml
├── CONTRIBUTING.md
├── GruntFile.js
├── LICENSE
├── README.md
├── demo
├── demo.js
├── index.html
└── trialtool.html
├── dist
├── jquery.indexeddb.js
├── jquery.indexeddb.min.js
└── jquery.indexeddb.min.map
├── docs
└── README.md
├── example
├── catalog.json
├── index.html
└── style.css
├── index.html
├── indexeddb.jquery.json
├── lib
├── demoer
│ ├── beautify.js
│ ├── demoer.css
│ ├── demoer.html
│ ├── demoer.js
│ └── jquery.min.js
├── firebug-lite.js
├── jquery.min.js
└── queuedUnit.js
├── package.json
├── src
└── jquery.indexeddb.js
├── style.css
├── test
├── api.txt
├── index.html
├── sample.html
└── sampleData.js
└── travis.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | sauce_connect.log
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "camelcase": true,
3 | "nonew": true,
4 | "curly": true,
5 | "eqeqeq": true,
6 | "immed": true,
7 | "latedef": true,
8 | "newcap": true,
9 | "undef": true,
10 | "regexp": true,
11 | "evil": true,
12 | "eqnull": true,
13 | "expr": true,
14 | "browser": true,
15 | "globalstrict": true,
16 | "predef": ["DEBUG",
17 | "console",
18 | "require",
19 | "jQuery",
20 | "module",
21 |
22 | "_",
23 | "asyncTest",
24 | "DB",
25 | "dbVersion",
26 | "deepEqual",
27 | "equal",
28 | "expect",
29 | "fail",
30 | "module",
31 | "nextTest",
32 | "notEqual",
33 | "ok",
34 | "sample",
35 | "start",
36 | "stop",
37 | "queuedAsyncTest",
38 | "queuedModule",
39 | "unescapse",
40 | "process"]
41 | }
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | jquery-indexeddb
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | ---
2 | notifications:
3 | email: false
4 | after_failure:
5 | - ./travis.sh revert
6 | env:
7 | global:
8 | - secure: |-
9 | df2x3+OG30XluETYS3EM0bsZna6k4uu099FMzfnod7noFB5gBoIz4ygYyXR6
10 | NQS2iSwslZWsYIupEnDBH9cMqqRHlASExon8RxLGRYiChTLSsRSMlcd8SDMD
11 | ngGwSTq8hqtzCb0A0K6A93RppussTmoR1aRMUnBoxSeXwD0o4no=
12 | - secure: |-
13 | IBhbudcrXXb546jV6ANg2BLFdhM5sv/klEgdmRbH/kq44h4UcBZ6e07/GCoI
14 | RjiNBn8lavPVvC6l8wOpidbWbvg2n99Lhe0hdL0hZjVPj2afjHNBcOchnhJ5
15 | FJdsP3PlXuJhQetAfRktPzXyL4z8zhIp/0k9ptk4Vk5nWbOCCXI=
16 | after_success:
17 | - ./travis.sh merge
18 | node_js:
19 | - 0.8
20 | before_script:
21 | - ./travis.sh before
22 | - npm install -g grunt-cli
23 | language: node_js
24 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Please send all pull requests to the __incoming-pr__ branch.
2 |
3 | This repository uses [travis-ci](https://travis-ci.org/axemclion/jquery-indexeddb) for running the continuous integration (CI) tests. It uses [saucelabs](http://saucelabs.com) to run automated test cases on different browsers. The saucelabs server can be only accessed using a secure environment variable that is not accessible in pull requests.
4 |
5 | The Pull-Request lifecycle
6 | ------------------------
7 |
8 | Thank you for submitting a patch to this project, we really appretiate it. Here is a quick overview of the process used to ensure that pull requests do not break existing functionality. You just have to do Step 1, all others are done by travis.
9 |
10 | 1. Send a pull request with your changes to `incoming-pr` branch
11 | 2. Travis runs only jslint on your pull request.
12 | * If the pull request tests fail, please correct the lint errors
13 | 3. Once the pull request passes the lint test, you pull request is merged into `incoming-pr` branch.
14 | 4. Travis runs *ALL* tests on `incoming-pr` branch. Since `incoming-pr` has access to the secure environment variables, it runs the saucelabs tests also.
15 | * If the saucelabs tests fail, `incoming-pr` is reverted to its original state.
16 | * Your changes are preserved in a separate branch. Please take a look at this branch and fix any failing tests
17 | 5. Once travis on the `incoming-pr` branch succeeds, your commits are automatically merged into `master`.
--------------------------------------------------------------------------------
/GruntFile.js:
--------------------------------------------------------------------------------
1 | /* global module:false */
2 | "use strict";
3 | module.exports = function(grunt) {
4 | grunt.initConfig({
5 | pkg: grunt.file.readJSON('package.json'),
6 | connect: {
7 | server: {
8 | options: {
9 | base: '.',
10 | port: 8080
11 | }
12 | }
13 | },
14 |
15 | 'saucelabs-qunit': {
16 | all: {
17 | options: {
18 | username: 'indexeddbshim',
19 | key: process.env.SAUCE_ACCESS_KEY || '',
20 | tags: ['master'],
21 | urls: ['http://127.0.0.1:8080/test/index.html'],
22 | browsers: [{
23 | browserName: 'chrome'
24 | }, {
25 | browserName: 'internet explorer',
26 | platform: 'Windows 2012',
27 | version: '10'
28 | }
29 | ]
30 | }
31 | }
32 | },
33 |
34 | jshint: {
35 | all: {
36 | files: {
37 | src: ['Gruntfile.js', 'test/**/*.js']
38 | },
39 | options: {
40 | jshintrc: '.jshintrc'
41 | }
42 | }
43 | },
44 |
45 | groundskeeper: {
46 | main: {
47 | files: {
48 | 'dist/jquery.indexeddb.js': ['src/jquery.indexeddb.js']
49 | },
50 | options: {
51 | 'console': false,
52 | 'debugger': false
53 | }
54 | }
55 | },
56 |
57 | uglify: {
58 | options: {
59 | report: 'gzip',
60 | banner: '/*! <%= pkg.name %> v<%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
61 | sourceMap: 'dist/<%= (pkg.name).replace(/-/g, ".") %>.min.map',
62 | sourceMapRoot: 'http://nparashuram.com/jquery-indexeddb/',
63 | sourceMappingURL: 'http://nparashuram.com/jquery-indexeddb/dist/<%=pkg.name%>.min.map'
64 | },
65 | main: {
66 | files: {
67 | 'dist/<%= (pkg.name).replace(/-/g, ".")%>.min.js': ['dist/jquery.indexeddb.js']
68 | }
69 | }
70 | },
71 | watch: {
72 | all: {
73 | files: ['src/*.js'],
74 | tasks: ['uglify']
75 | }
76 | },
77 | clean: {
78 | dist: ['./dist']
79 | }
80 | });
81 |
82 | // Loading dependencies
83 | for (var key in grunt.file.readJSON('package.json').devDependencies) {
84 | if (key !== 'grunt' && key.indexOf('grunt') === 0) {
85 | grunt.loadNpmTasks(key);
86 | }
87 | }
88 |
89 | var testJobs = ["build", "connect"];
90 | if (typeof process.env.SAUCE_ACCESS_KEY !== 'undefined') {
91 | testJobs.push("saucelabs-qunit");
92 | }
93 |
94 | grunt.registerTask('build', ['jshint', 'groundskeeper', 'uglify']);
95 | grunt.registerTask('test', testJobs);
96 | grunt.registerTask('default', 'build');
97 | grunt.registerTask('dev', ['build', 'connect', 'watch']);
98 | };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2012 Parashuram N and other contributors
2 | http://nparashuram.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Jquery Plugin for the IndexedDB API [](https://travis-ci.org/axemclion/jquery-indexeddb)
2 | ===============================================================================================================================================================================
3 |
4 | IndexedDB is a database inside a browser to save and retrieve objects on the browser/client. The JQuery IndexedDB Plugin is a wrapper on the IndexedDB API for JQuery.
5 |
6 | Links
7 | ------
8 |
9 | * Home page - http://nparashuram.com/jquery-indexeddb/index.html
10 | * Download the plugin - http://nparashuram.com/jquery-indexeddb/jquery.indexeddb.js
11 | * Sample application - http://nparashuram.com/jquery-indexeddb/example/index.html
12 | * API Documentation - https://github.com/axemclion/jquery-indexeddb/blob/gh-pages/docs/README.md
13 |
14 | Summary
15 | -------
16 | The Jquery IndexedDB Plugin brings to goodness of Jquery to the browser's native IndexedDB API. It supports method chaining, promises and smart defaults, enabling you to get more done with less code. It also abstracts out differences in browser implementations.
17 |
18 | Code
19 | ----
20 | The code written with the jQuery plugin is pretty simple. It looks something like
21 |
22 | ```javascript
23 | $.indexeddb("BookShop-1").objectStore("BookList").openCursor().each(write);
24 | ```
25 |
26 |
27 | A typical operation using the IndexedDB API would involve using the request model, creating transactions, checking for existence of object store using error responses and exceptions and then finally getting to the part where the data is actually iterated over.
28 |
29 | ```javascript
30 | var request = window.indexedDB.open("BookShop-1");
31 | request.onsuccess = function(event){
32 | var db = request.result;
33 | var transaction = db.transaction(["BookList"], IDBTransaction.READ_WRITE);
34 | var objectStore = transaction.objectStore("BookList");
35 | var request = DAO.objectStore.openCursor();
36 | request.onsuccess = function(event){
37 | var cursor = request.result;
38 | if (cursor) {
39 | write(cursor.key + "" + cursor.value);
40 | cursor["continue"]();
41 | }
42 | };
43 | };
44 |
45 | ```
46 |
47 | Read more about the API syntax in the [documentation](https://github.com/axemclion/jquery-indexeddb/blob/master/docs/README.md).
48 |
49 |
50 | Building
51 | --------
52 |
53 | Node is required to build this project.
54 |
55 | * `npm insall -g grunt-cli` # to install the grunt command line
56 | * `npm install` # to install all other dependencies from the package.json
57 | * Run one of the following grunt commands
58 | * `grunt` # to just minify, lint and build the source. Final file available in `dist/` folder
59 | * `grunt dev` # to start a web server. Navigate to `http://127.0.0.1:8080/test/` to run Qunit tests
60 |
61 |
--------------------------------------------------------------------------------
/demo/demo.js:
--------------------------------------------------------------------------------
1 | function data(){
2 | return {
3 | "bookName": "bookName-" + parseInt(Math.random() * 100),
4 | "price": parseInt(Math.random() * 1000),
5 | "checkedOut": new Date()
6 | }
7 | };
8 |
9 | window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB;
10 | window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
11 | window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
12 |
13 | var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
14 | var dbDeleteRequest = indexedDB.deleteDatabase("BookShop1");
15 | dbDeleteRequest.onsuccess = function(e){
16 | };
17 |
18 | $.indexedDB("BookShop1", {
19 | "schema": {
20 | 1: function(versionTransaction){
21 | versionTransaction.createObjectStore("OldBookList", {
22 | "autoIncrement": true
23 | });
24 | versionTransaction.createObjectStore("TempBookList");
25 | }
26 | }
27 | });
28 |
29 | var jqueryIndexedDB_Test = {
30 | "Create Object Store": {
31 | "code": function(){
32 | $.indexedDB("BookShop1", {
33 | "schema": {
34 | 2: function(v){
35 | var objectStore = v.createObjectStore("BookList", {
36 | "keyPath": "id",
37 | "autoIncrement": true
38 | });
39 | objectStore.createIndex("price");
40 | console.info("Created new object store");
41 | }
42 | }
43 | }).then(console.info, console.error);
44 | },
45 |
46 | "alternate": function(){
47 | var request = window.indexedDB.open("BookShop1");
48 | request.onsuccess = function(event){
49 | var db = request.result;
50 | var req = db.setVersion((isNaN(parseInt(db.version, 10)) ? 0 : parseInt(db.version, 10) + 1));
51 | req.onsuccess = function(){
52 | var transaction = req.result;
53 | var objectStore = transaction.db.createObjectStore("BookList", {
54 | "keyPath": "id",
55 | "autoIncrement": true
56 | });
57 | objectStore.createIndex("price");
58 | console.info(objectStore);
59 | };
60 | req.onerror = function(e){
61 | console.error(e, req);
62 | };
63 | };
64 | request.onerror = function(e){
65 | console.error(e, request);
66 | };
67 | }
68 | },
69 |
70 | "Delete Object Store": {
71 | "code": function(){
72 | $.indexedDB("BookShop1", 3).then(console.info, console.error, function(v){
73 | v.deleteObjectStore("TempBookList");
74 | console.info("Object Store deleted");
75 | });
76 | },
77 | "alternate": function(){
78 | var request = window.indexedDB.open("BookShop1");
79 | request.onsuccess = function(event){
80 | var db = request.result;
81 | var req = db.setVersion((isNaN(parseInt(db.version, 10)) ? 0 : parseInt(db.version, 10) + 1));
82 | req.onsuccess = function(){
83 | var transaction = req.result;
84 | transaction.db.deleteObjectStore("TempBookList");
85 | console.info(transaction.db);
86 | };
87 | req.onerror = function(e){
88 | console.error(e, req);
89 | };
90 | };
91 | request.onerror = function(e){
92 | console.error(e, request);
93 | };
94 | }
95 | },
96 |
97 | "Transaction": {
98 | "code": function(){
99 | var transaction = $.indexedDB("BookShop1").transaction(["OldBookList", "BookList"], $.indexedDB.IDBTransaction.READ_WRITE);
100 | transaction.then(console.info, console.error);
101 | transaction.progress(function(t){
102 | t.objectStore("BookList").add(data()).then(console.info, console.error);
103 | t.objectStore("OldBookList").add(data(), new Date().getTime()).then(console.info, console.error);
104 | });
105 | },
106 | "alternate": function(){
107 | var request = window.indexedDB.open("BookShop1");
108 | request.onsuccess = function(event){
109 | var db = request.result;
110 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
111 | console.info(transaction);
112 | var bookList = transaction.objectStore("BookList");
113 | var oldBookList = transaction.objectStore("OldBookList");
114 | var req1 = bookList.add(data());
115 | var req2 = oldBookList.add(data(), new Date().getTime());
116 | req1.onsuccess = function(){
117 | console.info(req1.result);
118 | };
119 | req1.onerror = function(e){
120 | console.error(e, req1);
121 | };
122 | req2.onsuccess = function(){
123 | console.info(req2.result);
124 | };
125 | req2.onerror = function(e){
126 | console.error(e, req2);
127 | };
128 | };
129 | request.onerror = function(e){
130 | console.error(e, request);
131 | };
132 | }
133 | },
134 |
135 | "Open Object Store, but dont create if does not exist": {
136 | "code": function(){
137 | $.indexedDB("BookShop1").objectStore("BookList", false);
138 | },
139 | "alternate": function(){
140 | var request = window.indexedDB.open("BookShop1");
141 | request.onsuccess = function(event){
142 | var db = request.result;
143 | try {
144 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
145 | var objectStore = transaction.objectStore("BookList");
146 | console.info(objectStore);
147 | } catch (e) {
148 | console.error(e, request);
149 | }
150 | };
151 | request.onerror = function(e){
152 | console.error(e, request);
153 | };
154 | }
155 | },
156 |
157 | "Open Object Store, or create if does not exist": {
158 | "code": function(){
159 | $.indexedDB("BookShop1").objectStore("BookList", {
160 | "keyPath": "id",
161 | "autoIncrement": true
162 | });
163 | },
164 | "alternate": function(){
165 | var request = window.indexedDB.open("BookShop1");
166 | request.onsuccess = function(event){
167 | var db = request.result;
168 | try {
169 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
170 | var objectStore = transaction.objectStore("BookList");
171 | console.info(objectStore);
172 | } catch (e) {
173 | var req = db.setVersion((isNaN(parseInt(db.version, 10)) ? 0 : parseInt(db.version, 10) + 1));
174 | req.onsuccess = function(){
175 | var transaction = req.result;
176 | var objectStore = transaction.db.createObjectStore("BookList", {
177 | "autoIncrement": true
178 | });
179 | console.info(objectStore);
180 | };
181 | req.onerror = function(e){
182 | console.error(e, req);
183 | };
184 | }
185 |
186 | };
187 | request.onerror = function(e){
188 | console.error(e, request);
189 | };
190 | }
191 | },
192 |
193 | "Add Data to Object Store": {
194 | "code": function(){
195 | window.book = data();
196 | $.indexedDB("BookShop1").objectStore("BookList", true).add(book).then(function(val){
197 | book.id = val;
198 | console.info(val);
199 | }, console.error);
200 | },
201 | "alternate": function(){
202 | window.book = data();
203 | var request = window.indexedDB.open("BookShop1");
204 | request.onsuccess = function(event){
205 | var db = request.result;
206 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
207 | var bookList = transaction.objectStore("BookList");
208 | var req = bookList.add(data());
209 | req.onsuccess = function(){
210 | book.id = req.result;
211 | console.info(req.result);
212 | };
213 | req.onerror = function(e){
214 | console.error(e, req);
215 | };
216 | };
217 | request.onerror = function(e){
218 | console.error(e, request);
219 | };
220 | }
221 | },
222 |
223 | "Get data": {
224 | "code": function(){
225 | $.indexedDB("BookShop1").objectStore("BookList").get(book.id).then(console.info, console.error);
226 | },
227 | "alternate": function(){
228 | var request = window.indexedDB.open("BookShop1");
229 | request.onsuccess = function(event){
230 | var db = request.result;
231 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
232 | var bookList = transaction.objectStore("BookList");
233 | var req = bookList.get(book.id);
234 | req.onsuccess = function(){
235 | console.info(req.result);
236 | };
237 | req.onerror = function(e){
238 | console.error(e, req);
239 | };
240 | };
241 | request.onerror = function(e){
242 | console.error(e, request);
243 | };
244 | }
245 | },
246 |
247 | "Modify Data in Object Store": {
248 | "code": function(){
249 | book["modified" + Math.random()] = true;
250 | $.indexedDB("BookShop1").objectStore("BookList").put(book, new Date().getTime()).then(console.info, console.error);
251 | },
252 | "alternate": function(){
253 | book["modified" + Math.random()] = true;
254 | var request = window.indexedDB.open("BookShop1");
255 | request.onsuccess = function(event){
256 | var db = request.result;
257 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
258 | var bookList = transaction.objectStore("BookList");
259 | var req = bookList.put(data(), new Date().getTime());
260 | req.onsuccess = function(){
261 | console.info(req.result);
262 | };
263 | req.onerror = function(e){
264 | console.error(e, req);
265 | };
266 | };
267 | request.onerror = function(e){
268 | console.error(e, request);
269 | };
270 | }
271 | },
272 |
273 | "Cursor and list all items in the object store": {
274 | "code": function(){
275 | $.indexedDB("BookShop1").objectStore("BookList").each(console.info);
276 | },
277 | "alternate": function(){
278 | var request = window.indexedDB.open("BookShop1");
279 | request.onsuccess = function(event){
280 | var db = request.result;
281 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
282 | var bookList = transaction.objectStore("BookList");
283 | var req = bookList.openCursor();
284 | req.onsuccess = function(){
285 | var cursor = req.result;
286 | if (cursor) {
287 | console.info(req.result.value);
288 | cursor["continue"]();
289 | }
290 | };
291 | req.onerror = function(e){
292 | console.error(e, req);
293 | };
294 | };
295 | request.onerror = function(e){
296 | console.error(e, request);
297 | };
298 | }
299 | },
300 |
301 | "Cursor and delete items with price that is an odd number": {
302 | "code": function(){
303 | $.indexedDB("BookShop1").objectStore("BookList").each(function(elem){
304 | if (elem.value && elem.value.price % 2) {
305 | console.info("Deleting", elem.value);
306 | elem["delete"]();
307 | return true;
308 | }
309 | });
310 | },
311 | "alternate": function(){
312 | var request = window.indexedDB.open("BookShop1");
313 | request.onsuccess = function(event){
314 | var db = request.result;
315 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
316 | var bookList = transaction.objectStore("BookList");
317 | var req = bookList.openCursor();
318 | req.onsuccess = function(){
319 | var cursor = req.result;
320 | if (cursor) {
321 | if (cursor.value && cursor.value.price % 2) {
322 | console.info("Deleting", cursor.value);
323 | cursor["delete"]();
324 | }
325 | cursor["continue"]();
326 | }
327 | };
328 | req.onerror = function(e){
329 | console.error(e, req);
330 | };
331 | };
332 | request.onerror = function(e){
333 | console.error(e, request);
334 | };
335 | }
336 | },
337 |
338 | "Cursor and update items with price that is an even number": {
339 | "code": function(){
340 | $.indexedDB("BookShop1").objectStore("BookList").each(function(elem){
341 | if (elem.value && elem.value.price % 2) {
342 | console.info("Updating", elem.value);
343 | elem.value["modifiedCursor-" + Math.random()] = true;
344 | elem.update(elem.value);
345 | }
346 | });
347 | },
348 | "alternate": function(){
349 | var request = window.indexedDB.open("BookShop1");
350 | request.onsuccess = function(event){
351 | var db = request.result;
352 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
353 | var bookList = transaction.objectStore("BookList");
354 | var req = bookList.openCursor();
355 | req.onsuccess = function(){
356 | var cursor = req.result;
357 | if (cursor) {
358 | if (cursor.value && cursor.value.price % 2) {
359 | cursor.value["modified-" + Math.random()] = true;
360 | console.info("Updating", cursor.value);
361 | cursor.update(cursor.value);
362 | }
363 | cursor["continue"]();
364 | }
365 | };
366 | req.onerror = function(e){
367 | console.error(e, req);
368 | };
369 | };
370 | request.onerror = function(e){
371 | console.error(e, request);
372 | };
373 | }
374 | },
375 | "Open an Index and iterate over its objects": {
376 | "code": function(){
377 | $.indexedDB("BookShop1").objectStore("BookList").index("price").each(console.info);
378 | },
379 | "alternate": function(){
380 | var request = window.indexedDB.open("BookShop1");
381 | request.onsuccess = function(event){
382 | var db = request.result;
383 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
384 | var bookList = transaction.objectStore("BookList");
385 | // Assuming that index exists
386 | var index = bookList.index("price-index");
387 | var req = index.openCursor();
388 | req.onsuccess = function(){
389 | var cursor = req.result;
390 | if (cursor) {
391 | console.info(cursor.value);
392 | cursor["continue"]();
393 | }
394 | };
395 | req.onerror = function(e){
396 | console.error(e, req);
397 | };
398 | };
399 | request.onerror = function(e){
400 | console.error(e, request);
401 | };
402 | }
403 | },
404 |
405 | "Open a key cursor on an Index and iterate over its objects": {
406 | "code": function(){
407 | $.indexedDB("BookShop1").objectStore("BookList").index("price").eachKey(console.info, [200, 500]);
408 | },
409 | "alternate": function(){
410 | var request = window.indexedDB.open("BookShop1");
411 | request.onsuccess = function(event){
412 | var db = request.result;
413 | var transaction = db.transaction([], IDBTransaction.READ_WRITE);
414 | var bookList = transaction.objectStore("BookList");
415 | var index = bookList.index("price-index");
416 | var range = new IDBKeyRange.bound(200, 500, true, true);
417 | var req = index.openKeyCursor(range);
418 | req.onsuccess = function(){
419 | var cursor = req.result;
420 | if (cursor) {
421 | console.info(cursor.value, cursor.key);
422 | cursor["continue"]();
423 | }
424 |
425 | };
426 | req.onerror = function(e){
427 | console.error(e, req);
428 | };
429 | };
430 | request.onerror = function(e){
431 | console.error(e, request);
432 | };
433 | }
434 | }
435 | };
436 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | IndexedDB Jquery Plugin
5 |
6 |
8 |
9 |
10 |
11 |
12 |
JQuery IndexedDB Plugin- API Demo
13 |
14 |
15 |
16 |
18 |
20 |
22 |
24 |
27 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/demo/trialtool.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Jquery IndexedDB Plugin
4 |
13 |
15 |
16 |
17 |
18 |
Jquery IndexedDB Plugin
19 |
20 | The examples listed here illustrate the use of IndexedDB Jquery plugin.
21 |
22 |
23 |
24 |
25 | Database
26 |
27 |
28 | Open Database
29 |
32 |
33 |
Open Database
34 | The Jquery IndexedDB Plugin is available off the global Jquery object under the property 'indexeddb'. The first argument passed to this is the name of the database that should be opened. Among other things, this object also returns a $.Deferred().promise() object that can be used to monitor the status of the opereation.
35 |
36 |
37 |
38 | Database properties
39 |
45 |
46 |
Database Properties
47 |
48 | The indexeddb() method returns a promise among other things. The "resolve-callback" of the promise has the database object that can be used to query the various properties of the database.
49 |
50 |
51 |
52 |
53 | Set Version
54 |
55 |
Set Version The setVersion method changes the version of the database. It returns a promise object.
56 |
57 | Note that the version number is optional; if not specified, the version of the database is incremented by 1.
58 |
59 |
60 |
61 |
64 |
65 |
66 |
67 |
68 | Object Store
69 |
70 |
71 | Transaction
72 |
73 |
Transaction The transaction object allows operations to be performed inside a transaction scope. The arguments that the transaction method takes are
74 |
75 |
76 |
77 | Array of object stores on which the transaction should exist. If a null array is specified, the transaction is on all object stores on the database.
78 |
79 |
80 |
81 | The type of transaction; one of READ and READ_WRITE on the IDBTransaction Object.
82 |
83 |
84 |
85 | After all operations on the transaction are complete, the transaction is closed automatically.
86 |
87 |
88 |
94 |
95 |
96 | Open Object Store, but don't create
97 |
98 |
Open Object Store (Don't Create) The objectStore() method opens an object store for saving or fetching objects. It takes the following arguments.
99 |
100 |
101 |
102 | Name of the ObjectStore
103 |
104 |
105 | Optional Second Argument
106 |
107 |
108 |
109 | true, undefined or not specified: Create an object store with keyPath=id and autoIncrement the keyPath.
110 |
111 |
112 |
113 | false: If the object store does not exist, don't create it. Throw an error instead.
114 |
115 |
116 | Any other object: Use the keyPath and autoIncrement properties of the object to create the object.
117 |
118 |
119 | Among other things, it returns a promise that can use used to get a handle to the objectStore
120 |
121 |
122 |
123 |
127 |
128 |
129 | Create or Open Object Store
130 |
131 |
Create Object Store Create an object store. It takes 2 arguments
132 |
133 |
134 |
135 | Name of the object store
136 |
137 |
138 | Object with a keyPath and if the keyPath should be autoIncremented or not
139 |
140 | If the object store already exists, this fails. If returns a promise to track the status of the operation.
141 |
142 | The version of the database in incremented by 1 automatically since IndexedDB requires the version of the database to change when this operation occurs.
143 |
144 |
145 |
146 |
153 |
154 |
155 | Delete object Store
156 |
157 |
Delete Object Store Deletes the object store specified.
158 |
159 | The version of the database in incremented by 1 automatically since
160 | IndexedDB requires the version of the database to change when this
161 | operation occurs.
162 |
163 | Hence, this may be blocked if other transactions are in progress.
164 |
165 |
166 |
167 |
171 |
172 |
173 | CRUD on Object Store
174 |
175 |
176 | Add data to object store
177 |
178 |
Add Data Adds a data to the object store specified. The data must follow the rules defined in the keyPath and autoIncrement properties when the object store was created.
179 |
180 | It returns a promise.
181 |
182 |
183 |
184 |
191 |
192 |
193 | Get data from object store
194 |
195 |
Get Object Fetches the object given its keyPath value.
196 |
197 | It returns a promise.
198 |
199 |
200 |
203 |
204 |
205 | Modify data in object store
206 |
207 |
Modify data Modifies the data in the object store. If the object with the keyPath value does not exist, it fails.
208 |
209 | put() and update() methods are used for modifying the data.
210 |
211 | It returns a promise.
212 |
213 |
214 |
215 |
219 |
220 |
221 | Removes object from object store
222 |
223 |
Delete Data Deletes data from the object store based on the keyPath value specified.
224 |
225 | delete() or remove() can be used to perform this operation.
226 |
227 | It returns a promise.
228 |
229 |
230 |
231 |
234 |
235 |
236 |
237 |
238 |
239 |
240 | Cursors
241 |
242 |
243 | Iterate over all objects using cursors
244 |
245 |
Iterate using Cursors Opens a cursor on the object store. The each() method is like the JQuery each method, allowing iteration over the various objects opened as a part of the cursor.
246 |
247 | The cursor can take IDBKeyRange, or an array for defining cursors. The array should be of the format
248 |
249 | [lowerBound, upperBound, includeLowerValue, includeUpperValue].
250 |
251 | If value for lowerBound is not defined, the ranged cursor defined only has an upper bound.
252 |
253 | If value for upperBound is not defined, the ranged cursor defined only has an lower bound.
254 |
255 |
258 |
259 |
260 | Update some objects
261 |
262 |
Updating objects in a cursor The updateEach() method is like the each() method on the cursor with one variation. The current object is modified with the value that is returned by the callback function.
263 |
264 |
265 |
266 |
275 |
276 |
277 | Delete some objects
278 |
279 |
Deleting in Cursor The deleteEach() method is like the each() method on the cursor with one
280 | variation. The current object is deleted if the return value of the callback is true.
281 |
282 |
283 |
284 |
292 |
293 |
294 |
295 |
296 | Indexes
297 |
298 |
299 | Open Index and iterate
300 |
301 |
Iterate on Index This method opens an index (or creates if it does not already exist)
302 |
303 | The argument is the property on which the index is to be created. The index thus created is propertyname + "-index".
304 |
305 | Once an index is opened, cursors can be used to iterate over it. Note that in case of such a cursor, the elements returned are sorted by the value in the indexed property.
306 |
307 |
308 |
309 |
312 |
313 |
314 | Key cursor on index
315 |
316 |
Key Cursor on Index The key cursor on an index return the value of the keyPath instead of the object like in the case of the openCursor() method.
317 |
318 |
319 |
320 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
--------------------------------------------------------------------------------
/dist/jquery.indexeddb.js:
--------------------------------------------------------------------------------
1 | (function($, undefined) {
2 | 'use strict';
3 | var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
4 | var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
5 | var IDBCursor = window.IDBCursor || window.webkitIDBCursor || {};
6 | if (typeof IDBCursor.PREV === "undefined") {
7 | IDBCursor.PREV = "prev";
8 | }
9 | if (typeof IDBCursor.NEXT === "undefined") {
10 | IDBCursor.NEXT = "next";
11 | }
12 |
13 | /**
14 | * Best to use the constant IDBTransaction since older version support numeric types while the latest spec
15 | * supports strings
16 | */
17 | var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
18 |
19 | function getDefaultTransaction(mode) {
20 | var result = null;
21 | switch (mode) {
22 | case 0:
23 | case 1:
24 | case "readwrite":
25 | case "readonly":
26 | result = mode;
27 | break;
28 | default:
29 | result = IDBTransaction.READ_WRITE || "readwrite";
30 | }
31 | return result;
32 | }
33 |
34 | $.extend({
35 | /**
36 | * The IndexedDB object used to open databases
37 | * @param {Object} dbName - name of the database
38 | * @param {Object} config - version, onupgradeneeded, onversionchange, schema
39 | */
40 | "indexedDB": function(dbName, config) {
41 | if (config) {
42 | // Parse the config argument
43 | if (typeof config === "number") config = {
44 | "version": config
45 | };
46 |
47 | var version = config.version;
48 | if (config.schema && !version) {
49 | var max = -1;
50 | for (var key in config.schema) {
51 | max = max > key ? max : key;
52 | }
53 | version = config.version || max;
54 | }
55 | }
56 |
57 |
58 | var wrap = {
59 | "request": function(req, args) {
60 | return $.Deferred(function(dfd) {
61 | try {
62 | var idbRequest = typeof req === "function" ? req(args) : req;
63 | idbRequest.onsuccess = function(e) {
64 |
65 | dfd.resolveWith(idbRequest, [idbRequest.result, e]);
66 | };
67 | idbRequest.onerror = function(e) {
68 |
69 | dfd.rejectWith(idbRequest, [idbRequest.error, e]);
70 | };
71 | if (typeof idbRequest.onblocked !== "undefined" && idbRequest.onblocked === null) {
72 | idbRequest.onblocked = function(e) {
73 |
74 | var res;
75 | try {
76 | res = idbRequest.result;
77 | } catch (e) {
78 | res = null; // Required for Older Chrome versions, accessing result causes error
79 | }
80 | dfd.notifyWith(idbRequest, [res, e]);
81 | };
82 | }
83 | if (typeof idbRequest.onupgradeneeded !== "undefined" && idbRequest.onupgradeneeded === null) {
84 | idbRequest.onupgradeneeded = function(e) {
85 |
86 | dfd.notifyWith(idbRequest, [idbRequest.result, e]);
87 | };
88 | }
89 | } catch (e) {
90 | e.name = "exception";
91 | dfd.rejectWith(idbRequest, ["exception", e]);
92 | }
93 | });
94 | },
95 | // Wraps the IDBTransaction to return promises, and other dependent methods
96 | "transaction": function(idbTransaction) {
97 | return {
98 | "objectStore": function(storeName) {
99 | try {
100 | return wrap.objectStore(idbTransaction.objectStore(storeName));
101 | } catch (e) {
102 | idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
103 | return wrap.objectStore(null);
104 | }
105 | },
106 | "createObjectStore": function(storeName, storeParams) {
107 | try {
108 | return wrap.objectStore(idbTransaction.db.createObjectStore(storeName, storeParams));
109 | } catch (e) {
110 | idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
111 | }
112 | },
113 | "deleteObjectStore": function(storeName) {
114 | try {
115 | idbTransaction.db.deleteObjectStore(storeName);
116 | } catch (e) {
117 | idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
118 | }
119 | },
120 | "abort": function() {
121 | idbTransaction.abort();
122 | }
123 | };
124 | },
125 | "objectStore": function(idbObjectStore) {
126 | var result = {};
127 | // Define CRUD operations
128 | var crudOps = ["add", "put", "get", "delete", "clear", "count"];
129 | for (var i = 0; i < crudOps.length; i++) {
130 | result[crudOps[i]] = (function(op) {
131 | return function() {
132 | return wrap.request(function(args) {
133 | return idbObjectStore[op].apply(idbObjectStore, args);
134 | }, arguments);
135 | };
136 | })(crudOps[i]);
137 | }
138 |
139 | result.each = function(callback, range, direction) {
140 | return wrap.cursor(function() {
141 | if (direction) {
142 | return idbObjectStore.openCursor(wrap.range(range), direction);
143 | } else {
144 | return idbObjectStore.openCursor(wrap.range(range));
145 | }
146 | }, callback);
147 | };
148 |
149 | result.index = function(name) {
150 | return wrap.index(function() {
151 | return idbObjectStore.index(name);
152 | });
153 | };
154 |
155 | result.createIndex = function(prop, options, indexName) {
156 | if (arguments.length === 2 && typeof options === "string") {
157 | indexName = arguments[1];
158 | options = null;
159 | }
160 | if (!indexName) {
161 | indexName = prop;
162 | }
163 | return wrap.index(function() {
164 | return idbObjectStore.createIndex(indexName, prop, options);
165 | });
166 | };
167 |
168 | result.deleteIndex = function(indexName) {
169 | return idbObjectStore.deleteIndex(indexName);
170 | };
171 |
172 | return result;
173 | },
174 |
175 | "range": function(r) {
176 | if ($.isArray(r)) {
177 | if (r.length === 1) {
178 | return IDBKeyRange.only(r[0]);
179 | } else {
180 | return IDBKeyRange.bound(r[0], r[1], (typeof r[2] === 'undefined') ? false : r[2], (typeof r[3] === 'undefined') ? false : r[3]);
181 | }
182 | } else if (typeof r === "undefined") {
183 | return null;
184 | } else {
185 | return r;
186 | }
187 | },
188 |
189 | "cursor": function(idbCursor, callback) {
190 | return $.Deferred(function(dfd) {
191 | try {
192 |
193 | var cursorReq = typeof idbCursor === "function" ? idbCursor() : idbCursor;
194 | cursorReq.onsuccess = function(e) {
195 |
196 | if (!cursorReq.result) {
197 | dfd.resolveWith(cursorReq, [null, e]);
198 | return;
199 | }
200 | var elem = {
201 | // Delete, update do not move
202 | "delete": function() {
203 | return wrap.request(function() {
204 | return cursorReq.result["delete"]();
205 | });
206 | },
207 | "update": function(data) {
208 | return wrap.request(function() {
209 | return cursorReq.result["update"](data);
210 | });
211 | },
212 | "next": function(key) {
213 | this.data = key;
214 | },
215 | "key": cursorReq.result.key,
216 | "value": cursorReq.result.value
217 | };
218 |
219 | dfd.notifyWith(cursorReq, [elem, e]);
220 | var result = callback.apply(cursorReq, [elem]);
221 |
222 | try {
223 | if (result === false) {
224 | dfd.resolveWith(cursorReq, [null, e]);
225 | } else if (typeof result === "number") {
226 | cursorReq.result["advance"].apply(cursorReq.result, [result]);
227 | } else {
228 | if (elem.data) cursorReq.result["continue"].apply(cursorReq.result, [elem.data]);
229 | else cursorReq.result["continue"]();
230 | }
231 | } catch (e) {
232 |
233 | dfd.rejectWith(cursorReq, [cursorReq.result, e]);
234 | }
235 | };
236 | cursorReq.onerror = function(e) {
237 |
238 | dfd.rejectWith(cursorReq, [cursorReq.result, e]);
239 | };
240 | } catch (e) {
241 |
242 | e.type = "exception";
243 | dfd.rejectWith(cursorReq, [null, e]);
244 | }
245 | });
246 | },
247 |
248 | "index": function(index) {
249 | try {
250 | var idbIndex = (typeof index === "function" ? index() : index);
251 | } catch (e) {
252 | idbIndex = null;
253 | }
254 |
255 | return {
256 | "each": function(callback, range, direction) {
257 | return wrap.cursor(function() {
258 | if (direction) {
259 | return idbIndex.openCursor(wrap.range(range), direction);
260 | } else {
261 | return idbIndex.openCursor(wrap.range(range));
262 | }
263 |
264 | }, callback);
265 | },
266 | "eachKey": function(callback, range, direction) {
267 | return wrap.cursor(function() {
268 | if (direction) {
269 | return idbIndex.openKeyCursor(wrap.range(range), direction);
270 | } else {
271 | return idbIndex.openKeyCursor(wrap.range(range));
272 | }
273 | }, callback);
274 | },
275 | "get": function(key) {
276 | if (typeof idbIndex.get === "function") {
277 | return wrap.request(idbIndex.get(key));
278 | } else {
279 | return idbIndex.openCursor(wrap.range(key));
280 | }
281 | },
282 | "count": function() {
283 | if (typeof idbIndex.count === "function") {
284 | return wrap.request(idbIndex.count());
285 | } else {
286 | throw "Count not implemented for cursors";
287 | }
288 | },
289 | "getKey": function(key) {
290 | if (typeof idbIndex.getKey === "function") {
291 | return wrap.request(idbIndex.getKey(key));
292 | } else {
293 | return idbIndex.openKeyCursor(wrap.range(key));
294 | }
295 | }
296 | };
297 | }
298 | };
299 |
300 |
301 | // Start with opening the database
302 | var dbPromise = wrap.request(function() {
303 |
304 | return version ? indexedDB.open(dbName, parseInt(version)) : indexedDB.open(dbName);
305 | });
306 | dbPromise.then(function(db, e) {
307 |
308 | db.onversionchange = function() {
309 | // Try to automatically close the database if there is a version change request
310 | if (!(config && config.onversionchange && config.onversionchange() !== false)) {
311 | db.close();
312 | }
313 | };
314 | }, function(error, e) {
315 |
316 | // Nothing much to do if an error occurs
317 | }, function(db, e) {
318 | if (e && e.type === "upgradeneeded") {
319 | if (config && config.schema) {
320 | // Assuming that version is always an integer
321 |
322 | for (var i = e.oldVersion + 1; i <= e.newVersion; i++) {
323 | typeof config.schema[i] === "function" && config.schema[i].call(this, wrap.transaction(this.transaction));
324 | }
325 | }
326 | if (config && typeof config.upgrade === "function") {
327 | config.upgrade.call(this, wrap.transaction(this.transaction));
328 | }
329 | }
330 | });
331 |
332 | return $.extend(dbPromise, {
333 | "cmp": function(key1, key2) {
334 | return indexedDB.cmp(key1, key2);
335 | },
336 | "deleteDatabase": function() {
337 | // Kinda looks ugly coz DB is opened before it needs to be deleted.
338 | // Blame it on the API
339 | return $.Deferred(function(dfd) {
340 | dbPromise.then(function(db, e) {
341 | db.close();
342 | wrap.request(function() {
343 | return indexedDB.deleteDatabase(dbName);
344 | }).then(function(result, e) {
345 | dfd.resolveWith(this, [result, e]);
346 | }, function(error, e) {
347 | dfd.rejectWith(this, [error, e]);
348 | }, function(db, e) {
349 | dfd.notifyWith(this, [db, e]);
350 | });
351 | }, function(error, e) {
352 | dfd.rejectWith(this, [error, e]);
353 | }, function(db, e) {
354 | dfd.notifyWith(this, [db, e]);
355 | });
356 | });
357 | },
358 | "transaction": function(storeNames, mode) {
359 | !$.isArray(storeNames) && (storeNames = [storeNames]);
360 | mode = getDefaultTransaction(mode);
361 | return $.Deferred(function(dfd) {
362 | dbPromise.then(function(db, e) {
363 | var idbTransaction;
364 | try {
365 |
366 | idbTransaction = db.transaction(storeNames, mode);
367 |
368 | idbTransaction.onabort = idbTransaction.onerror = function(e) {
369 | dfd.rejectWith(idbTransaction, [e]);
370 | };
371 | idbTransaction.oncomplete = function(e) {
372 | dfd.resolveWith(idbTransaction, [e]);
373 | };
374 | } catch (e) {
375 |
376 | e.type = "exception";
377 | dfd.rejectWith(this, [e]);
378 | return;
379 | }
380 | try {
381 | dfd.notifyWith(idbTransaction, [wrap.transaction(idbTransaction)]);
382 | } catch (e) {
383 | e.type = "exception";
384 | dfd.rejectWith(this, [e]);
385 | }
386 | }, function(err, e) {
387 | dfd.rejectWith(this, [e, err]);
388 | }, function(res, e) {
389 |
390 | //dfd.notifyWith(this, ["", e]);
391 | });
392 |
393 | });
394 | },
395 | "objectStore": function(storeName, mode) {
396 | var me = this,
397 | result = {};
398 |
399 | function op(callback) {
400 | return $.Deferred(function(dfd) {
401 | function onTransactionProgress(trans, callback) {
402 | try {
403 |
404 | callback(trans.objectStore(storeName)).then(function(result, e) {
405 | dfd.resolveWith(this, [result, e]);
406 | }, function(err, e) {
407 | dfd.rejectWith(this, [err, e]);
408 | });
409 | } catch (e) {
410 |
411 | e.name = "exception";
412 | dfd.rejectWith(trans, [e, e]);
413 | }
414 | }
415 | me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
416 |
417 | // Nothing to do when transaction is complete
418 | }, function(err, e) {
419 | // If transaction fails, CrudOp fails
420 | if (err.code === err.NOT_FOUND_ERR && (mode === true || typeof mode === "object")) {
421 |
422 | var db = this.result;
423 | db.close();
424 | dbPromise = wrap.request(function() {
425 |
426 | return indexedDB.open(dbName, (parseInt(db.version, 10) || 1) + 1);
427 | });
428 | dbPromise.then(function(db, e) {
429 |
430 | db.onversionchange = function() {
431 | // Try to automatically close the database if there is a version change request
432 | if (!(config && config.onversionchange && config.onversionchange() !== false)) {
433 | db.close();
434 | }
435 | };
436 | me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
437 |
438 | // Nothing much to do
439 | }, function(err, e) {
440 | dfd.rejectWith(this, [err, e]);
441 | }, function(trans, e) {
442 |
443 | onTransactionProgress(trans, callback);
444 | });
445 | }, function(err, e) {
446 | dfd.rejectWith(this, [err, e]);
447 | }, function(db, e) {
448 | if (e.type === "upgradeneeded") {
449 | try {
450 |
451 | db.createObjectStore(storeName, mode === true ? {
452 | "autoIncrement": true
453 | } : mode);
454 |
455 | } catch (ex) {
456 |
457 | dfd.rejectWith(this, [ex, e]);
458 | }
459 | }
460 | });
461 | } else {
462 | dfd.rejectWith(this, [err, e]);
463 | }
464 | }, function(trans) {
465 |
466 | onTransactionProgress(trans, callback);
467 | });
468 | });
469 | }
470 |
471 | function crudOp(opName, args) {
472 | return op(function(wrappedObjectStore) {
473 | return wrappedObjectStore[opName].apply(wrappedObjectStore, args);
474 | });
475 | }
476 |
477 | function indexOp(opName, indexName, args) {
478 | return op(function(wrappedObjectStore) {
479 | var index = wrappedObjectStore.index(indexName);
480 | return index[opName].apply(index[opName], args);
481 | });
482 | }
483 |
484 | var crud = ["add", "delete", "get", "put", "clear", "count", "each"];
485 | for (var i = 0; i < crud.length; i++) {
486 | result[crud[i]] = (function(op) {
487 | return function() {
488 | return crudOp(op, arguments);
489 | };
490 | })(crud[i]);
491 | }
492 |
493 | result.index = function(indexName) {
494 | return {
495 | "each": function(callback, range, direction) {
496 | return indexOp("each", indexName, [callback, range, direction]);
497 | },
498 | "eachKey": function(callback, range, direction) {
499 | return indexOp("eachKey", indexName, [callback, range, direction]);
500 | },
501 | "get": function(key) {
502 | return indexOp("get", indexName, [key]);
503 | },
504 | "count": function() {
505 | return indexOp("count", indexName, []);
506 | },
507 | "getKey": function(key) {
508 | return indexOp("getKey", indexName, [key]);
509 | }
510 | };
511 | };
512 |
513 | return result;
514 | }
515 | });
516 | }
517 | });
518 |
519 | $.indexedDB.IDBCursor = IDBCursor;
520 | $.indexedDB.IDBTransaction = IDBTransaction;
521 | $.idb = $.indexedDB;
522 | })(jQuery);
--------------------------------------------------------------------------------
/dist/jquery.indexeddb.min.js:
--------------------------------------------------------------------------------
1 | /*! jquery-indexeddb v1.0.0 2013-10-30 */
2 | (function(e){"use strict";function n(e){var n=null;switch(e){case 0:case 1:case"readwrite":case"readonly":n=e;break;default:n=u.READ_WRITE||"readwrite"}return n}var t=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB,r=window.IDBKeyRange||window.webkitIDBKeyRange,o=window.IDBCursor||window.webkitIDBCursor||{};o.PREV===undefined&&(o.PREV="prev"),o.NEXT===undefined&&(o.NEXT="next");var u=window.IDBTransaction||window.webkitIDBTransaction;e.extend({indexedDB:function(o,u){if(u){"number"==typeof u&&(u={version:u});var i=u.version;if(u.schema&&!i){var c=-1;for(var a in u.schema)c=c>a?c:a;i=u.version||c}}var f={request:function(n,t){return e.Deferred(function(e){try{var r="function"==typeof n?n(t):n;r.onsuccess=function(n){e.resolveWith(r,[r.result,n])},r.onerror=function(n){e.rejectWith(r,[r.error,n])},r.onblocked!==undefined&&null===r.onblocked&&(r.onblocked=function(n){var t;try{t=r.result}catch(n){t=null}e.notifyWith(r,[t,n])}),r.onupgradeneeded!==undefined&&null===r.onupgradeneeded&&(r.onupgradeneeded=function(n){e.notifyWith(r,[r.result,n])})}catch(o){o.name="exception",e.rejectWith(r,["exception",o])}})},transaction:function(e){return{objectStore:function(n){try{return f.objectStore(e.objectStore(n))}catch(t){return e.readyState!==e.DONE&&e.abort(),f.objectStore(null)}},createObjectStore:function(n,t){try{return f.objectStore(e.db.createObjectStore(n,t))}catch(r){e.readyState!==e.DONE&&e.abort()}},deleteObjectStore:function(n){try{e.db.deleteObjectStore(n)}catch(t){e.readyState!==e.DONE&&e.abort()}},abort:function(){e.abort()}}},objectStore:function(e){for(var n={},t=["add","put","get","delete","clear","count"],r=0;t.length>r;r++)n[t[r]]=function(n){return function(){return f.request(function(t){return e[n].apply(e,t)},arguments)}}(t[r]);return n.each=function(n,t,r){return f.cursor(function(){return r?e.openCursor(f.range(t),r):e.openCursor(f.range(t))},n)},n.index=function(n){return f.index(function(){return e.index(n)})},n.createIndex=function(n,t,r){return 2===arguments.length&&"string"==typeof t&&(r=arguments[1],t=null),r||(r=n),f.index(function(){return e.createIndex(r,n,t)})},n.deleteIndex=function(n){return e.deleteIndex(n)},n},range:function(n){return e.isArray(n)?1===n.length?r.only(n[0]):r.bound(n[0],n[1],n[2]===undefined?!1:n[2],n[3]===undefined?!1:n[3]):n===undefined?null:n},cursor:function(n,t){return e.Deferred(function(e){try{var r="function"==typeof n?n():n;r.onsuccess=function(n){if(!r.result)return e.resolveWith(r,[null,n]),undefined;var o={"delete":function(){return f.request(function(){return r.result["delete"]()})},update:function(e){return f.request(function(){return r.result.update(e)})},next:function(e){this.data=e},key:r.result.key,value:r.result.value};e.notifyWith(r,[o,n]);var u=t.apply(r,[o]);try{u===!1?e.resolveWith(r,[null,n]):"number"==typeof u?r.result.advance.apply(r.result,[u]):o.data?r.result["continue"].apply(r.result,[o.data]):r.result["continue"]()}catch(n){e.rejectWith(r,[r.result,n])}},r.onerror=function(n){e.rejectWith(r,[r.result,n])}}catch(o){o.type="exception",e.rejectWith(r,[null,o])}})},index:function(e){try{var n="function"==typeof e?e():e}catch(t){n=null}return{each:function(e,t,r){return f.cursor(function(){return r?n.openCursor(f.range(t),r):n.openCursor(f.range(t))},e)},eachKey:function(e,t,r){return f.cursor(function(){return r?n.openKeyCursor(f.range(t),r):n.openKeyCursor(f.range(t))},e)},get:function(e){return"function"==typeof n.get?f.request(n.get(e)):n.openCursor(f.range(e))},count:function(){if("function"==typeof n.count)return f.request(n.count());throw"Count not implemented for cursors"},getKey:function(e){return"function"==typeof n.getKey?f.request(n.getKey(e)):n.openKeyCursor(f.range(e))}}}},s=f.request(function(){return i?t.open(o,parseInt(i)):t.open(o)});return s.then(function(e){e.onversionchange=function(){u&&u.onversionchange&&u.onversionchange()!==!1||e.close()}},function(){},function(e,n){if(n&&"upgradeneeded"===n.type){if(u&&u.schema)for(var t=n.oldVersion+1;n.newVersion>=t;t++)"function"==typeof u.schema[t]&&u.schema[t].call(this,f.transaction(this.transaction));u&&"function"==typeof u.upgrade&&u.upgrade.call(this,f.transaction(this.transaction))}}),e.extend(s,{cmp:function(e,n){return t.cmp(e,n)},deleteDatabase:function(){return e.Deferred(function(e){s.then(function(n){n.close(),f.request(function(){return t.deleteDatabase(o)}).then(function(n,t){e.resolveWith(this,[n,t])},function(n,t){e.rejectWith(this,[n,t])},function(n,t){e.notifyWith(this,[n,t])})},function(n,t){e.rejectWith(this,[n,t])},function(n,t){e.notifyWith(this,[n,t])})})},transaction:function(t,r){return!e.isArray(t)&&(t=[t]),r=n(r),e.Deferred(function(e){s.then(function(n,o){var u;try{u=n.transaction(t,r),u.onabort=u.onerror=function(n){e.rejectWith(u,[n])},u.oncomplete=function(n){e.resolveWith(u,[n])}}catch(o){return o.type="exception",e.rejectWith(this,[o]),undefined}try{e.notifyWith(u,[f.transaction(u)])}catch(o){o.type="exception",e.rejectWith(this,[o])}},function(n,t){e.rejectWith(this,[t,n])},function(){})})},objectStore:function(r,i){function c(c){return e.Deferred(function(e){function a(n,t){try{t(n.objectStore(r)).then(function(n,t){e.resolveWith(this,[n,t])},function(n,t){e.rejectWith(this,[n,t])})}catch(o){o.name="exception",e.rejectWith(n,[o,o])}}h.transaction(r,n(i)).then(function(){},function(d,l){if(d.code!==d.NOT_FOUND_ERR||i!==!0&&"object"!=typeof i)e.rejectWith(this,[d,l]);else{var p=this.result;p.close(),s=f.request(function(){return t.open(o,(parseInt(p.version,10)||1)+1)}),s.then(function(t){t.onversionchange=function(){u&&u.onversionchange&&u.onversionchange()!==!1||t.close()},h.transaction(r,n(i)).then(function(){},function(n,t){e.rejectWith(this,[n,t])},function(e){a(e,c)})},function(n,t){e.rejectWith(this,[n,t])},function(n,t){if("upgradeneeded"===t.type)try{n.createObjectStore(r,i===!0?{autoIncrement:!0}:i)}catch(o){e.rejectWith(this,[o,t])}})}},function(e){a(e,c)})})}function a(e,n){return c(function(t){return t[e].apply(t,n)})}function d(e,n,t){return c(function(r){var o=r.index(n);return o[e].apply(o[e],t)})}for(var h=this,l={},p=["add","delete","get","put","clear","count","each"],y=0;p.length>y;y++)l[p[y]]=function(e){return function(){return a(e,arguments)}}(p[y]);return l.index=function(e){return{each:function(n,t,r){return d("each",e,[n,t,r])},eachKey:function(n,t,r){return d("eachKey",e,[n,t,r])},get:function(n){return d("get",e,[n])},count:function(){return d("count",e,[])},getKey:function(n){return d("getKey",e,[n])}}},l}})}}),e.indexedDB.IDBCursor=o,e.indexedDB.IDBTransaction=u,e.idb=e.indexedDB})(jQuery);
3 | //@ sourceMappingURL=http://nparashuram.com/jquery-indexeddb/dist/jquery-indexeddb.min.map
--------------------------------------------------------------------------------
/dist/jquery.indexeddb.min.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"dist/jquery.indexeddb.min.js","sources":["dist/jquery.indexeddb.js"],"names":["$","getDefaultTransaction","mode","result","IDBTransaction","READ_WRITE","indexedDB","window","mozIndexedDB","webkitIndexedDB","msIndexedDB","IDBKeyRange","webkitIDBKeyRange","IDBCursor","webkitIDBCursor","PREV","NEXT","webkitIDBTransaction","extend","dbName","config","version","schema","max","key","wrap","request","req","args","Deferred","dfd","idbRequest","onsuccess","e","resolveWith","onerror","rejectWith","error","onblocked","res","notifyWith","onupgradeneeded","name","transaction","idbTransaction","objectStore","storeName","readyState","DONE","abort","createObjectStore","storeParams","db","deleteObjectStore","idbObjectStore","crudOps","i","length","op","apply","arguments","each","callback","range","direction","cursor","openCursor","index","createIndex","prop","options","indexName","deleteIndex","r","isArray","only","bound","idbCursor","cursorReq","elem","delete","update","data","next","this","value","type","idbIndex","eachKey","openKeyCursor","get","count","getKey","dbPromise","open","parseInt","then","onversionchange","close","oldVersion","newVersion","call","upgrade","cmp","key1","key2","deleteDatabase","storeNames","onabort","oncomplete","err","onTransactionProgress","trans","me","code","NOT_FOUND_ERR","autoIncrement","ex","crudOp","opName","wrappedObjectStore","indexOp","crud","idb","jQuery"],"mappings":"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","sourceRoot":"http://nparashuram.com/jquery-indexeddb/"}
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | Jquery-IndexedDB API Reference
2 | ===============================
3 |
4 | List of APIs - Quick Reference
5 |
6 | * [$.indexedDB()](#openDatabase)
7 | * [$.indexedDB(, schema)](#openDatabaseUpgrade)
8 | * [$.indexedDB().transaction()](#transactionSec)
9 | * [$.indexedDB().objectStore()](#objectStore)
10 | * [$.indexedDB().objectStore().add()](#crud)
11 | * [$.indexedDB().objectStore().each()](#cursorEach)
12 | * [$.indexedDB().objectStore().index()](#index)
13 | * [$.indexedDB().objectStore().deleteDatabase()](#deleteDatabase)
14 |
15 | IndexedDB - Quick Intro
16 | -------------------------
17 | * [IndexedDB](http://www.w3.org/TR/IndexedDB/) is a database inside a browser to save and retrieve objects on the browser/client.
18 | * IndexedDB contains multiple `objectStores` (sort of tables) that contain data.
19 | * `objectStores` have data records in form of (key, javascript object) pairs. (key) uniquely identify records
20 | * Data can be written to, read from, or iterated over, inside and `object store`
21 | * (key, javascript object) pairs can also have indexes on a property in the (javascript object)
22 | * Data operations can be scoped into transactions.
23 |
24 | Open Database
25 | ----------------------------------------
26 | Creates a new connection to the _Indexed Database_ specified as the name.
27 |
28 | ``` javascript
29 | var dbOpenPromise = $.indexedDB("database_name", {
30 | // The second parameter is optional
31 | "version" : 3, // Integer version that the DB should be opened with
32 | "upgrade" : function(transaction){
33 | // Function called when DB is of lower version that specified in the version parameter
34 | // See transaction for details on the argument
35 | },
36 | "schema" : {
37 | "1" : function(transaction){
38 | // List of instructions to run when DB version is upgraded to 1.
39 | // See transaction for details on the argument
40 | },
41 | "2" : function(transaction){
42 | // Examples of using the transaction object
43 | var obj1 = transaction.objectStore("store1");
44 | var obj2 = transaction.createObjectStore(store2);
45 | obj1.createIndex("index");
46 | }
47 | }
48 | });
49 | ```
50 |
51 |
52 |
53 | When a `schema` parameter is specified, and if the DB is originally at version `1`, then only functions labeled `2` and above are executed.
54 | This provides a way to migrate database by creating object stores, indexes or even reading/writing data between database versions.
55 | For details on the `transaction` parameter, looks at the [Transaction](#trans) object returned during a transaction.
56 |
57 | Note that the `createObjectStore`
58 | and the `deleteObjectStore` are available only during the upgrade operations.
59 | Also, `objectStores` opened during progress can have `index` operations. See the [indexes](#index) section for more details
60 |
61 | If the optional parameter is not specified, it simply opens the database to the latest version available.
62 |
63 | It returns a [Jquery Promise]("http://api.jquery.com/category/deferred-object/") with the following
64 | [done](#dbOpenDone), [progress](#dbOpenProgress) and [fail](#dbOpenFail) event handlers.
65 |
66 | ### Handling Database open success
67 |
68 | ``` javascript
69 | dbOpenPromise.done(function(db, event){
70 | // Called when the database is successfully opened.
71 | db; // the native IndexedDB Database object (aka result of the IDBRequest) ,
72 | event; // the IndexedDB Event object.
73 | this; // Context inside the function is the native IDBRequest.
74 | });
75 | ```
76 |
77 | ### When the database open is in progress
78 | When that database is being upgraded or is blocked due to another transaction being in progress
79 |
80 | ``` javascript
81 | dbOpenPromise.progress(function(db, event){
82 | // Called when there is the database open is in progress - when it is blocked or is being upgraded
83 | error; // is the error object and has more details on what the error is
84 | event; // is the IndexedDB Event object
85 | event.type; //indicates - blocked or upgrade
86 | this; // Context inside the function is the native IDBRequest
87 | });
88 | ```
89 | When a database open operation is blocked, you can choose to close the database.
90 | When the database is being upgraded, you can perform all actions permitted in the versionChange transaction.
91 |
92 | ### Handling database open error
93 |
94 | ``` javascript
95 | dbOpenPromise.fail(function(error, event){
96 | // Called when there is an error opening the database.
97 | error; //is the error object and has more details on what the error is
98 | event; //is the IndexedDB Event object. event.type indicates the type - 'error' or 'exception'
99 | this; // Context inside the function is the native IDBRequest
100 | });
101 | ```
102 | Transactions
103 | --------------------------
104 | Once a database is opened, read and write transactions can be performed within a transaction.
105 |
106 | ```javascript
107 | var transactionPromise = $.indexedDB("dbName").transaction(storeNames, mode);
108 | ```
109 |
110 | `storeNames` is an array of object store names (or a single string object store name) that should be under this transaction.
111 |
112 |
113 |
114 | `mode` is 0 or 1 indication *READ_ONLY* or *READ_WRITE*, similar to [modes](http://www.w3.org/TR/IndexedDB/#dfn-mode) in the IndexedDB Specification.
115 |
116 | The returned transaction promise has the following event handlers during the lifetime of the transaction.
117 |
118 | ### Transaction in progress
119 |
120 | ``` javascript
121 | transactionPromise.progress(function(trans){
122 | // Called when the transaction has started
123 | trans; // Use the methods on the trans object (see below) to perform operations
124 | });
125 | ```
126 |
127 | The transaction object passed to the callback when transaction is in progress has the following methods on it.
128 |
129 | ``` javascript
130 | var objectStore = trans.objectStore("objectStoreName");
131 | ```
132 |
133 | The following 2 methods are available only when the database is being upgraded. Look at the [Open Database Schema](#openDatabaseUpgrade) section for details.
134 |
135 | ``` javascript
136 | var objectStore = trans.createObjectStore("objectStoreName", {
137 | // Options to create object store.
138 | "autoIncrement" : true, // [detaults to true], indicating that the key for this object store should auto increment,
139 | "keyPath" : id // the path of key in the object, defaults to key that has to be specified separately
140 | });
141 |
142 | trans.deleteObjectStore(objectStoreName);
143 | ```
144 | See [object stores](#objectStore) for methods on the `objectStore` returned by the above calls.
145 |
146 | ### Transaction complete
147 |
148 | ``` javascript
149 | transactionPromise.done(function(event){
150 | // Called when transaction is completed
151 | event; // Indicated the transaction complete event.
152 | });
153 | ```
154 |
155 | ### Transaction fails or is aborted
156 |
157 | ``` javascript
158 | transactionPromise.fail(function(event){
159 | // Called when the transaction is aborted or fails
160 | event.type; // indicates the reason for failure being error, exception or abort
161 | });
162 | ```
163 |
164 | Object Stores
165 | ----------------------------------------
166 | Once the database is opened, operations need to be performed on object stores.
167 | An object store can be opened inside a [transaction that is in progress](#transInProgress) or using a shorthand on the `$.indexedDB` object like.
168 |
169 | ``` javascript
170 | var objectStore = $.indexedDB("database_name").objectStore("objectStoreName", /* Optional */ mode );
171 | ```
172 |
173 | The `mode` parameter defaults to READ_WRITE and is similar to the `mode` parameter specified during a `transaction`.
174 |
175 | As a convenience method, if the `mode` is set to `true` (instead of 0 or 1), an object store is created if it does not exist. Internally, the database is closed and opened with a higher version to trigger the version transaction where the object store can be created.
176 |
177 |
178 |
179 | The above expression internally creates a transaction for this object store. The `mode` parameter is optional and similar to the [mode parameter](#transactionMode) in transactions.
180 | The CRUD methods on the object store are
181 |
182 | ```javascript
183 | var promise = objectStore.add(/*Javascript Object*/ value, /*Optional*/ key); // Adds data to the objectStore
184 | var promise = objectStore.get(key); Gets the object with the key
185 | var promise = objectStore.put(/*Javascript Object*/ value, key); // Updates the object for the specified key
186 | var promise = objectStore.delete(key); // Deletes the object with the specified key
187 | var promise = objectStore.count(); // Gets all the objects
188 | var promise = objectStore.clear(); // Removes all data from the object store;
189 | ```
190 |
191 | The returned promise can be used to note the success or error of the operations
192 |
193 | ``` javascript
194 | promise.done(function(result, event){
195 | result; // Result of the operation. Some operations like delete will return undefined
196 | event; // Success Event
197 | });
198 |
199 | promise.fail(function(error, event){
200 | error; // Type of error that has occured
201 | event; // Error event
202 | event.type; // indicates if there was an error or an exception
203 | });
204 | ```
205 |
206 |
207 | To iterate over the objects inside an object store, use
208 |
209 | ``` javascript
210 | var iterationPromise = objectStore.each(function(item){
211 | // Called for each element during the iteration
212 | item.key, item.value; // The key and the value of current object
213 | item.delete(); // Deletes the current item
214 | item.update(newItem); // Updates the current item with newItem;
215 |
216 | return;
217 | // false - do not continue iteration
218 | // integer 'n' - n can be 1,2,... indicating skip next n objects and continue
219 | // object - continue to item with object as the next key
220 | // default - no return, or undefined return, continue iteration
221 |
222 | }, /*Optional*/ range, /*Optional*/ direction);
223 |
224 | iterationPromise.done(function(result, event){
225 | // Iteration completed
226 | result ; // null, indicating that there are no more objects for iteration
227 | event ; // Success event
228 | })
229 |
230 | iterationPromise.fail(function(error, event){
231 | error; // Error during iteration
232 | event; // Error event, can be exception or event
233 | });
234 |
235 | ```
236 | `range` limits the results and can be an array like `[lower, upper, lowerOpen, upperOpen]`.
237 | If only one element is specified in the array, it becomes an equals clause. The parameters `lowerOpen` and `upperOpen` are optional. If no value is specified for either upper or for lower bounds, they are included. These arguments behave as described in the [specification](http://www.w3.org/TR/IndexedDB/#widl-IDBKeyRange-lowerOpen)
238 |
239 | In addition to the above CURD operation, `objectStore.index` methods also allow operations using indexes. See [indexes](#index) for details.
240 |
241 | Indexes
242 | ---------------------------
243 | Once a reference to an objectStore is obtained either using `transaction.objectStore()`, `transaction.createObjectStore()` or `$.indexedDB("").objectStore()`,
244 | the index object can be used.
245 |
246 | ``` javascript
247 | var index = objectStore.index("indexName");
248 | index.each(function(item){
249 | // Iterate over objects in index
250 | // Similar to iterating over objects in an ObjectStore
251 | item; // same as iterating over objects (see above)
252 | }, /*Optional*/ range, /*Optional */ direction);
253 |
254 | index.eachKey(function(item){
255 | // Iterate over the keys of the object
256 | });
257 | ```
258 |
259 | While upgrading a database in the [version change transaction](openDatabaseUpgrade), indexes can also be created or deleted on an object store.
260 |
261 | ```javascript
262 | // trans is created when a database upgrade is in progress
263 | var objectStore = trans.objectStore("objectStoreName");
264 | var index = objectStore.createIndex("object.property" , /*Optional*/ {
265 | "unique" : false, // Uniqueness of Index, defaults to false
266 | "multiEntry" : false // see explanation below
267 | }, /* Optional */ "indexName")
268 | objectStore.deleteIndex("indexName"); //returns nothing
269 |
270 | ```
271 | If the second argument to the `createIndex` function is a string, it is considered to be the name of the index. If no indexName is specified in `createIndex`, the property name is used as indexName
272 |
273 | This multiEntry flag affects how the index behaves when the result of evaluating the index's key path yields an Array.
274 |
275 | * If the multiEntry flag is false, then a single record whose key is an Array is added to the index.
276 | * If the multiEntry flag is true, then the one record is added to the index for each item in the Array. The key for each record is the value of respective item in the Array.
277 |
278 | Delete Database
279 | -------------------------------
280 | A database can be deleted using
281 |
282 | ``` javascript
283 | var deletePromise = $.indexedDB("database_name").deleteDatabase();
284 |
285 | deletePromise.done(function(null, event){
286 | /* Called when the delete is successful*/
287 | event; // The success event
288 | });
289 | deletePromise.fail(function(error, event){
290 | /* Called when the delete is successful*/
291 | error; // Reason for the error
292 | });
293 | deletePromise.progress(function(db, event){
294 | // Called when the deleting is blocked due to another transaction
295 | db; // Database that is opened
296 | event.type // Indicates it is blocked, etc.
297 | });
298 | ```
299 |
300 | Compare Keys
301 | ---------------------
302 | A convenience method to compare keys in a database. Can be used as `$.indexedDB("dbName").cmp(key1, key2)` and return 1,0 or -1 when key1 is greater than, equal to or less than key2 respectively.
303 |
304 | Links
305 | -------
306 | Some useful links
307 |
308 | * [IndexedDB W3C Specification](http://www.w3.org/TR/IndexedDB/)
309 | * [IndexedDB API playground and examples](http://nparashuram.com/IndexedDB)
310 | * [My work on IndexedDB](http://blog.nparashuram.com/search/label/indexeddb)
311 |
--------------------------------------------------------------------------------
/example/catalog.json:
--------------------------------------------------------------------------------
1 | [{
2 | "itemId": 1001,
3 | "name": "Desktop",
4 | "description": "A normal looking desktop computer",
5 | "price": 100,
6 |
7 | "rating": 2
8 |
9 | }, {
10 | "itemId": 1002,
11 | "name": "Laptop",
12 | "description": "A laptop computer",
13 | "price": 200,
14 |
15 | "rating": 4
16 | }, {
17 | "itemId": 1003,
18 | "name": "Tablet",
19 | "description": "A tablet computer",
20 | "price": 150,
21 | "stock": 4
22 | }, {
23 | "itemId": 1004,
24 | "name": "Embedded",
25 | "description": "Whatever",
26 | "stock": 4
27 | }, {
28 | "itemId": 1005,
29 | "name": "EInk Reader",
30 | "description": "Like a tablet, but different screen",
31 | "price": 150,
32 | "stock": 4
33 | }, {
34 | "itemId": 1006,
35 | "name": "Phone",
36 | "description": "No more a computer",
37 | "price": 250,
38 | "stock": 4
39 | }, {
40 | "itemId": 1007,
41 | "name": "Music players",
42 | "description": "the outer imits ? ",
43 | "price": 10,
44 | "stock": 4
45 | }]
46 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | A self contained example for the Jquery-IndexedDB plugin
5 |
7 |
9 |
11 |
12 |
13 |
14 |
15 |
23 |
24 |
25 |
30 |
31 |
32 |
35 |
38 |
45 |
46 |
47 |
48 |
49 |
54 |
55 |
56 |
57 | Id
58 |
59 |
60 | Actions
61 |
62 |
63 | Object
64 |
68 |
69 |
70 |
71 |
72 |
73 |
78 |
79 |
80 |
81 | Id
82 |
83 |
84 | Actions
85 |
86 |
87 | Object
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
227 |
228 |
229 |
287 |
304 |
305 |
306 |
--------------------------------------------------------------------------------
/example/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-size: 14px;
3 | color: #333;
4 | font-family: Helvetica, Arial, sans-serif;
5 | background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD0AAAA1CAIAAAB9U3TTAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NjIxQjBCQkNGMTcwMTFFMEFBREJENzE1MkFDM0ExNTUiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NjIxQjBCQkJGMTcwMTFFMEFBREJENzE1MkFDM0ExNTUiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjBDN0U3RDQ4RjE0NjExRTBBQURCRDcxNTJBQzNBMTU1IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjBDN0U3RDQ5RjE0NjExRTBBQURCRDcxNTJBQzNBMTU1Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/qHfvQAACWBJREFUaN512mlW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") repeat scroll 0 0 transparent;
6 | }
7 |
8 | a {
9 | text-decoration: none;
10 | }
11 |
12 | h1, h2 {
13 | text-align: center;
14 | }
15 |
16 | .table-container {
17 | background: #ddd;
18 | -webkit-border-radius: 5px;
19 | -moz-border-radius: 5px;
20 | -ms-border-radius: 5px;
21 | -o-border-radius: 5px;
22 | border-radius: 5px;
23 | -webkit-box-shadow: inset 0 2px 2px #999;
24 | -moz-box-shadow: inset 0 2px 2px #999;
25 | box-shadow: inset 0 2px 2px #999;
26 | display: block;
27 | text-align: center;
28 | margin: 2% 1%;
29 | padding: 2%;
30 | }
31 |
32 | .controls {
33 | }
34 |
35 | .controls h2 {
36 | text-align: center;
37 | font-size: 1.1em;
38 | float: left
39 | }
40 |
41 | .controls a {
42 | display: block;
43 | float: right;
44 | margin: 2px;
45 | }
46 |
47 | table {
48 | clear: both;
49 | width: 100%;
50 | }
51 |
52 | table td, th {
53 | border: dotted 1px #777;
54 | padding: 3px;
55 | height: 2.5em;
56 | background-color: #F5F5F5;
57 | }
58 |
59 | table th {
60 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #cccccc));
61 | background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
62 | background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
63 | background-image: -ms-linear-gradient(top, #eeeeee, #cccccc);
64 | background-image: -o-linear-gradient(top, #eeeeee, #cccccc);
65 | background-image: linear-gradient(top, #eeeeee, #cccccc);
66 | }
67 |
68 | table td.key, th.key {
69 | width: 10%;
70 | text-align: center;
71 | }
72 |
73 | table td.value {
74 | text-align: left;
75 | }
76 |
77 | table td.value div.keyval{
78 | display: inline-block;
79 | padding : 5px;
80 | }
81 |
82 | @media screen and (max-width: 500px) {
83 | table td.value div.keyval{
84 | display: block;
85 | padding : 1px;
86 | width: 100%;
87 | text-overflow : ellipsis;
88 | }
89 | }
90 |
91 | table td.value div.keyval:after{
92 | content: ",";
93 | }
94 |
95 | table td.value div.keyval span.key{
96 | color: #333;
97 | }
98 |
99 | table td.value div.keyval span.key:after{
100 | content : ":";
101 | }
102 |
103 | table td.value div.keyval span.value{
104 | color: #777;
105 | }
106 |
107 |
108 | table td.action {
109 | width: 20%;
110 | min-width: 100px;
111 | }
112 |
113 | @media screen and (max-width: 1098px) {
114 | table td.action a{
115 | display: block;
116 | width: 80px;
117 | margin: 5px auto;
118 | padding-top: 10px;
119 | padding-bottom: 10px;
120 | }
121 | }
122 |
123 |
124 | #console {
125 | clear: both;
126 | }
127 | .controls a{
128 | background-color: #a5b8da;
129 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #a5b8da), color-stop(100%, #7089b3));
130 | background-image: -webkit-linear-gradient(top, #a5b8da, #7089b3);
131 | background-image: -moz-linear-gradient(top, #a5b8da, #7089b3);
132 | background-image: -ms-linear-gradient(top, #a5b8da, #7089b3);
133 | background-image: -o-linear-gradient(top, #a5b8da, #7089b3);
134 | background-image: linear-gradient(top, #a5b8da, #7089b3);
135 | border-top: 1px solid #758fba;
136 | border-right: 1px solid #6c84ab;
137 | border-bottom: 1px solid #5c6f91;
138 | border-left: 1px solid #6c84ab;
139 | -webkit-box-shadow: inset 0 1px 0 0 #aec3e5;
140 | -moz-box-shadow: inset 0 1px 0 0 #aec3e5;
141 | box-shadow: inset 0 1px 0 0 #aec3e5;
142 | color: #fff;
143 | font: bold 11px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
144 | line-height: 1;
145 | padding: 8px 10px;
146 | text-align: center;
147 | text-shadow: 0 -1px 1px #64799e;
148 | text-transform: uppercase;
149 | width: 150px;
150 | }
151 |
152 | .controls a:hover {
153 | background-color: #9badcc;
154 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #9badcc), color-stop(100%, #687fa6));
155 | background-image: -webkit-linear-gradient(top, #9badcc, #687fa6);
156 | background-image: -moz-linear-gradient(top, #9badcc, #687fa6);
157 | background-image: -ms-linear-gradient(top, #9badcc, #687fa6);
158 | background-image: -o-linear-gradient(top, #9badcc, #687fa6);
159 | background-image: linear-gradient(top, #9badcc, #687fa6);
160 | border-top: 1px solid #6d86ad;
161 | border-right: 1px solid #647a9e;
162 | border-bottom: 1px solid #546685;
163 | border-left: 1px solid #647a9e;
164 | -webkit-box-shadow: inset 0 1px 0 0 #a5b9d9;
165 | -moz-box-shadow: inset 0 1px 0 0 #a5b9d9;
166 | box-shadow: inset 0 1px 0 0 #a5b9d9;
167 | cursor: pointer;
168 | }
169 | .controls a:active {
170 | border: 1px solid #546685;
171 | -webkit-box-shadow: inset 0 0 8px 2px #7e8da6, 0 1px 0 0 #eeeeee;
172 | -moz-box-shadow: inset 0 0 8px 2px #7e8da6, 0 1px 0 0 #eeeeee;
173 | box-shadow: inset 0 0 8px 2px #7e8da6, 0 1px 0 0 #eeeeee;
174 | }
175 |
176 | .action a {
177 | vertical-align: middle;
178 | margin: 0 1%;
179 | line-height: 15px;
180 | }
181 |
182 | .action a{
183 | background-color: #52a8e8;
184 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #52a8e8), color-stop(100%, #377ad0));
185 | background-image: -webkit-linear-gradient(top, #52a8e8, #377ad0);
186 | background-image: -moz-linear-gradient(top, #52a8e8, #377ad0);
187 | background-image: -ms-linear-gradient(top, #52a8e8, #377ad0);
188 | background-image: -o-linear-gradient(top, #52a8e8, #377ad0);
189 | background-image: linear-gradient(top, #52a8e8, #377ad0);
190 | border-top: 1px solid #4081af;
191 | border-right: 1px solid #2e69a3;
192 | border-bottom: 1px solid #20559a;
193 | border-left: 1px solid #2e69a3;
194 | -webkit-border-radius: 16px;
195 | -moz-border-radius: 16px;
196 | -ms-border-radius: 16px;
197 | -o-border-radius: 16px;
198 | border-radius: 16px;
199 | -webkit-box-shadow: inset 0 1px 0 0 #72b9eb, 0 1px 2px 0 #b3b3b3;
200 | -moz-box-shadow: inset 0 1px 0 0 #72b9eb, 0 1px 2px 0 #b3b3b3;
201 | box-shadow: inset 0 1px 0 0 #72b9eb, 0 1px 2px 0 #b3b3b3;
202 | color: #fff;
203 | font: normal 11px "lucida grande", sans-serif;
204 | line-height: 1;
205 | padding: 3px 10px;
206 | text-align: center;
207 | text-shadow: 0 -1px 1px #3275bc;
208 | width: 112px;
209 | -webkit-background-clip: padding-box;
210 | }
211 |
212 | .action a.:hover {
213 | background-color: #3e9ee5;
214 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #3e9ee5), color-stop(100%, #206bcb));
215 | background-image: -webkit-linear-gradient(top, #3e9ee5 0%, #206bcb 100%);
216 | background-image: -moz-linear-gradient(top, #3e9ee5 0%, #206bcb 100%);
217 | background-image: -ms-linear-gradient(top, #3e9ee5 0%, #206bcb 100%);
218 | background-image: -o-linear-gradient(top, #3e9ee5 0%, #206bcb 100%);
219 | background-image: linear-gradient(top, #3e9ee5 0%, #206bcb 100%);
220 | border-top: 1px solid #2a73a6;
221 | border-right: 1px solid #165899;
222 | border-bottom: 1px solid #07428f;
223 | border-left: 1px solid #165899;
224 | -webkit-box-shadow: inset 0 1px 0 0 #62b1e9;
225 | -moz-box-shadow: inset 0 1px 0 0 #62b1e9;
226 | box-shadow: inset 0 1px 0 0 #62b1e9;
227 | cursor: pointer;
228 | text-shadow: 0 -1px 1px #1d62ab;
229 | -webkit-background-clip: padding-box;
230 | }
231 |
232 | .action a:active {
233 | background: #3282d3;
234 | border: 1px solid #154c8c;
235 | border-bottom: 1px solid #0e408e;
236 | -webkit-box-shadow: inset 0 0 6px 3px #1657b5, 0 1px 0 0 white;
237 | -moz-box-shadow: inset 0 0 6px 3px #1657b5, 0 1px 0 0 white;
238 | box-shadow: inset 0 0 6px 3px #1657b5, 0 1px 0 0 white;
239 | text-shadow: 0 -1px 1px #2361a4;
240 | -webkit-background-clip: padding-box;
241 | }
242 |
243 | .action a::-moz-focus-inner {
244 | border: 0;
245 | padding: 0;
246 | }
247 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Jquery IndexedDB Plugin
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
JQuery IndexedDB Plugin
13 |
14 |
17 |
18 | IndexedDB
19 | is a database inside a browser to save and retrieve objects on the browser/client.
20 |
21 |
22 | The Jquery IndexedDB Plugin is a wrapper over IndexedDB, making it easier to use with Jquery.
23 |
24 |
25 | Don't worry out browser differences (
26 | setVersion/onupgradeneeded
27 | ).
28 |
29 | Use Jquery promises in place of requests
30 | Supports chaining, less verbose syntax
31 |
32 |
33 |
34 | IndexedBD is not supported on
35 | all browsers
36 | . You can use the
37 | IndexedDB polyfill
38 | over WebSQL to get the plugin working on Opera, Safari, iPad, iPhone, etc.
39 |
40 |
Code
41 |
Typical code with the plugin looks something like this
42 |
43 | $.indexedDB("databaseName").objectStore("objectStoreName").add(data).then();
44 |
45 |
46 | Note how transactions are automatic, object stores are implicitly created and the syntax is far less verbose.
47 |
48 |
Compare IndexedDB API and jQuery Plugin code
49 |
50 | Compare the code written using the IndexedDB API vs the jQuery Plugin.
51 |
52 | Check out the differences.
53 |
54 |
55 |
56 |
57 |
API Documentation
58 |
59 | Take a look at the API on
60 | Github Readme
61 | .
62 | You can also try out the entire API in the
63 | API Playground
64 | .
65 |
66 |
77 |
78 |
79 |
80 |
Tests
81 |
82 | Try out the test suite on your browser to see the support
83 |
84 | Run the test suites now
85 |
86 |
Tested on Browsers
87 |
88 | Firefox 12.0 - 14.0a2 (2012-05-18)
89 | Chrome 18.0 - 21.0.1143.0 canary
90 |
91 |
92 |
93 |
94 |
95 |
Try it Now!
96 |
97 |
98 |
Run It
99 |
128 |
141 |
142 |
Other related links
143 |
154 |
155 |
156 |
172 |
173 |
--------------------------------------------------------------------------------
/indexeddb.jquery.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "indexeddb",
3 | "title": "Jquery-IndexedDB",
4 | "description": "A Jquery Plugin for the IndexedDB API",
5 | "version": "0.1.0",
6 | "keywords": ["indexeddb", "offline", "storage"],
7 | "homepage": "http://nparashuram.com/jquery-indexeddb",
8 | "docs": "http://nparashuram.com/jquery-indexeddb",
9 | "demo": "http://nparashuram.com/jquery-indexeddb/example/index.html",
10 | "download": "http://nparashuram.com/jquery-indexeddb/dist/jquery.indexeddb.js",
11 | "bugs": "https://github.com/axemclion/jquery-indexeddb/issues",
12 | "author": {
13 | "name": "Parashuram",
14 | "email": "code@nparashuram.com",
15 | "url": "http://nparashuram.com/"
16 | },
17 | "licenses": [{
18 | "type": "GPLv2",
19 | "url": "http://www.example.com/licenses/gpl.html"
20 | }],
21 | "dependencies": {
22 | "jquery": ">=1.8.0"
23 | }
24 | }
--------------------------------------------------------------------------------
/lib/demoer/demoer.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: Cambria, Times;
5 | }
6 |
7 | .sample {
8 | display: none;
9 | }
10 |
11 | .examples {
12 | margin: 0;
13 | padding: 1%;
14 | }
15 |
16 | .example-item {
17 | list-style: none;
18 | background-color: #FFFFFF;
19 | padding: 0.1em;
20 | margin: 0;
21 | cursor: pointer;
22 | }
23 |
24 | .example-item .snippet {
25 | display: none;
26 | width: 100%;
27 | border: 0;
28 | -webkit-transition: all 0.2s ease-in-out;
29 | -moz-transition: all 0.2s ease-in-out;
30 | -o-transition: all 0.2s ease-in-out;
31 | }
32 |
33 | .example-item .snippet .code {
34 | font-family: Monaco, Consolas, courier;
35 | font-size: 0.7em;
36 | background-color: #2A211C;
37 | color: #BDAE9D;
38 | width: 99%;
39 | height : 99%;
40 | padding : 0.5%;
41 | border: none;
42 | }
43 |
44 | .example-title {
45 | text-decoration: none;
46 | color: black;
47 | padding: 0.1em;
48 | display: block;
49 | height : 100%;
50 | line-height : 20px;
51 | }
52 |
53 | .example-item:hover {
54 | background-color: #FFFFCC;
55 | }
56 |
57 | .example-item:target{
58 | margin-bottom : 1em;
59 | }
60 |
61 | .example-item:target .example-name {
62 | background-color: #DFECFF;
63 | height : 40px;
64 | vertical-align : middle;
65 | }
66 |
67 | .example-item:target .example-title {
68 | line-height : 40px;
69 | font-weight : bold;
70 | margin : 0 0em;
71 | }
72 |
73 |
74 | .example-item:target .code-linq, .example-item:target .code-full {
75 | height: 100px;
76 | display: block;
77 | padding: 0;
78 | margin: 0;
79 | }
80 |
81 | .example-item:target .code-full{
82 | height : 200px;
83 | margin : 1em 0;
84 | }
85 |
86 | .example-more-code, .floating-button {
87 | display: none;
88 | font-size: 0.8em;
89 | padding: 0.2em 0.5em;
90 | margin: 0.6em 0.5em;
91 | float: right;
92 | vertical-align : middle;
93 | }
94 |
95 | .example-item:target .example-more-code, .example-item:target .floating-button {
96 | display: inline;
97 | }
98 |
99 | /* blue pill (inspired by iTunes)
100 | *******************************************************************************/
101 | button.blue-pill {
102 | background-color: #a5b8da;
103 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #a5b8da), color-stop(100%, #7089b3));
104 | background-image: -webkit-linear-gradient(top, #a5b8da, #7089b3);
105 | background-image: -moz-linear-gradient(top, #a5b8da, #7089b3);
106 | background-image: -ms-linear-gradient(top, #a5b8da, #7089b3);
107 | background-image: -o-linear-gradient(top, #a5b8da, #7089b3);
108 | background-image: linear-gradient(top, #a5b8da, #7089b3);
109 | border-top: 1px solid #758fba;
110 | border-right: 1px solid #6c84ab;
111 | border-bottom: 1px solid #5c6f91;
112 | border-left: 1px solid #6c84ab;
113 | -webkit-border-radius: 18px;
114 | -moz-border-radius: 18px;
115 | border-radius: 18px;
116 | -webkit-box-shadow: inset 0 1px 0 0 #aec3e5;
117 | -moz-box-shadow: inset 0 1px 0 0 #aec3e5;
118 | box-shadow: inset 0 1px 0 0 #aec3e5;
119 | color: #fff;
120 | font: bold 11px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
121 | line-height: 1;
122 | padding: 8px 0;
123 | text-align: center;
124 | text-shadow: 0 -1px 1px #64799e;
125 | text-transform: uppercase;
126 | width: 150px; }
127 | button.blue-pill:hover {
128 | background-color: #9badcc;
129 | background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #9badcc), color-stop(100%, #687fa6));
130 | background-image: -webkit-linear-gradient(top, #9badcc, #687fa6);
131 | background-image: -moz-linear-gradient(top, #9badcc, #687fa6);
132 | background-image: -ms-linear-gradient(top, #9badcc, #687fa6);
133 | background-image: -o-linear-gradient(top, #9badcc, #687fa6);
134 | background-image: linear-gradient(top, #9badcc, #687fa6);
135 | border-top: 1px solid #6d86ad;
136 | border-right: 1px solid #647a9e;
137 | border-bottom: 1px solid #546685;
138 | border-left: 1px solid #647a9e;
139 | -webkit-box-shadow: inset 0 1px 0 0 #a5b9d9;
140 | -moz-box-shadow: inset 0 1px 0 0 #a5b9d9;
141 | box-shadow: inset 0 1px 0 0 #a5b9d9;
142 | cursor: pointer; }
143 | button.blue-pill:active {
144 | border: 1px solid #546685;
145 | -webkit-box-shadow: inset 0 0 8px 2px #7e8da6, 0 1px 0 0 #eeeeee;
146 | -moz-box-shadow: inset 0 0 8px 2px #7e8da6, 0 1px 0 0 #eeeeee;
147 | box-shadow: inset 0 0 8px 2px #7e8da6, 0 1px 0 0 #eeeeee; }
--------------------------------------------------------------------------------
/lib/demoer/demoer.html:
--------------------------------------------------------------------------------
1 |
23 |
--------------------------------------------------------------------------------
/lib/demoer/demoer.js:
--------------------------------------------------------------------------------
1 | var prettyCode = function(code){
2 | if (typeof code === "function") {
3 | code = code.toString();
4 | }
5 | code = code || "";
6 | var start = "function (){";
7 | code = code.substring(code.indexOf(start) + start.length + 2, code.length - 1).replace(/(^\s+|$\s+)/g, "");
8 | return code;
9 | };
10 |
11 | /**
12 | * Load all dependent URLs
13 | */
14 | var getUrls = function(container, callback){
15 | var base = $("script[src*=demoer\\.js]").attr("src");
16 | base = base.substring(0, base.lastIndexOf("demoer.js"));
17 |
18 | // Loading Firebug
19 | var E = document.createElement('script');
20 | E.setAttribute('id', "FirebugLite");
21 | E.setAttribute('src', "https://getfirebug.com/firebug-lite.js#startOpened=true");
22 | E.setAttribute("FirebugLite", "4");
23 | document.getElementsByTagName('body')[0].appendChild(E);
24 | E.onload = function(){
25 | Firebug.DOM.addListener("onHSplitterMouseMove", function(){
26 | console.log("Resized");
27 | })
28 | }
29 | var count = 0;
30 | var timerHandle = window.setInterval(function(){
31 | count++;
32 | if (count > 10) {
33 | window.clearInterval(timerHandle);
34 | }
35 | if (typeof firebug !== "undefined") {
36 | window.clearInterval(timerHandle);
37 | window.console = firebug;
38 | }
39 | }, 1000);
40 |
41 | // Loading beautify, and then the container
42 | $.getScript(base + "beautify.js", function(){
43 | $(container).load(base + "demoer.html", function(){
44 | callback();
45 | });
46 | });
47 |
48 | $("head").append($(" ").attr({
49 | "type": "text/css",
50 | "rel": "stylesheet",
51 | "href": base + "demoer.css"
52 | }));
53 | }
54 |
55 | // Start populating the samples
56 | var loadDemoes = function(container, exampleList){
57 | getUrls(container, function(){
58 | var exampleDiv = $(container).children("ul.examples:first");
59 | var template = exampleDiv.children("li.sample:first");
60 | var list = [];
61 | for (example in exampleList) {
62 | var exampleItem = template.clone(false).attr("id", example);
63 | var html = exampleItem.html().replace(/__EXAMPLE__/g, example);
64 | html = html.replace(/\s*__EXAMPLE_CODE__\s*/g, js_beautify(prettyCode(exampleList[example].code)));
65 | html = html.replace(/\s*__EXAMPLE_ALTERNATE__\s*/g, js_beautify(prettyCode(exampleList[example].alternate)));
66 | exampleItem.html(html);
67 | exampleDiv.append(exampleItem.removeClass("sample"));
68 | }
69 | });
70 |
71 | var run = function(code, title){
72 | console.group(title);
73 | eval(code);
74 | setTimeout(function(){
75 | console.groupEnd(title);
76 | }, 1000);
77 | $(".more-code").hide();
78 | }
79 |
80 | $(".example-more-code").live("click", function(e){
81 | $(this).parent().nextAll(".code-full").toggle();
82 | return false;
83 | });
84 |
85 | $("button.code-run").live("click", function(e){
86 | var root = $(this).parent().parent();
87 | run(root.find(".code-linq").children(".code").text(), root.find("a.example-title").html());
88 | });
89 |
90 | $("#examples").css("overflow-y", "scroll");
91 | function resize(){
92 | var h = window.innerHeight - $("#FirebugUI").height() - $("h1").parent().height();
93 | $("#examples").height(h);
94 | height = h;
95 | }
96 | };
97 |
--------------------------------------------------------------------------------
/lib/queuedUnit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Ideally unit tests should be independent, but there are some cases where you really want those tests to be executed one after the other
3 | * Here is some code that does exactly that - a wrapper on top of QUnit.
4 | *
5 | * Usage
6 | * Instead of asyncTest, call queuedAsyncTest (same params)
7 | * Instead of module(), call queuedModule
8 | * After a test is over and the next test has to run, call nextTest()
9 | */
10 | (function(window, console, undefined){
11 | var testQueue = [], currentModule = null;
12 |
13 | // Filtering the tests based on the URLs
14 | var q = window.location.search.substring(1).split("&");
15 | var filteredTests = [];
16 | for (var i = 0; i < q.length; i++) {
17 | var parts = q[i].split("=");
18 | if (parts[0] === "filter") {
19 | filteredTests.push(unescape(parts[1]));
20 | }
21 | }
22 |
23 | /**
24 | * Use this method instead of asyncTest. Once the test is finished, call nextTest();
25 | * @param {Object} name
26 | * @param {Object} callback
27 | */
28 | function queuedAsyncTest(name){
29 | if (filteredTests.length === 0 || filteredTests.indexOf(currentModule + ": " + name) !== -1) {
30 | testQueue.push({
31 | "name": name,
32 | "module": currentModule,
33 | "args": arguments
34 | });
35 | }
36 | }
37 |
38 | /**
39 | * Use this in place of module(blah)
40 | * @param {Object} module
41 | */
42 | function queuedModule(module){
43 | currentModule = module;
44 | }
45 |
46 | if (typeof console.groupEnd !== "function"){
47 | console.groupEnd = function(){
48 | console.log("==================================");
49 | }
50 | }
51 |
52 | if (typeof console.groupCollapsed !== "function"){
53 | console.groupCollapsed = function(msg){
54 | console.log.apply(console, arguments);
55 | }
56 | }
57 |
58 | /**
59 | * Once the current test is over, call nextTest() to start running the next test
60 | */
61 | var timer = null;
62 | var testCount = 1;
63 | function nextTest(){
64 | window.clearTimeout(timer);
65 | if (testQueue.length <= 0) {
66 | console.groupEnd();
67 | console.log("All tests completed");
68 | return;
69 | }
70 | var current = testQueue.splice(0, 1)[0];
71 | console.groupEnd();
72 | console.groupCollapsed("=========", testCount++, current.module, ":", current.name, "============");
73 | module(current.module);
74 | // Expected asserts specified or not
75 | if (current.args.length === 2) {
76 | asyncTest(current.name, current.args[1]);
77 | } else if (current.args.length === 3) {
78 | asyncTest(current.name, current.args[1], current.args[2]);
79 | }
80 | }
81 |
82 | window.queuedAsyncTest = queuedAsyncTest;
83 | window.queuedModule = queuedModule;
84 | window.nextTest = nextTest;
85 | }(window, console));
86 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jquery-indexeddb",
3 | "preferGlobal": "false",
4 | "version": "1.0.0",
5 | "author": "Parashuram ",
6 | "description": "A Jquery plugin for the IndexedDB API",
7 | "scripts": {
8 | "start": "grunt",
9 | "test": "grunt test"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git://github.com/axemclion/jquery-indexeddb.git"
14 | },
15 | "bugs": {
16 | "url": "https://github.com/axemclion/jquery-indexeddb/issues"
17 | },
18 | "main": "grunt.js",
19 | "keywords": [
20 | "indexedDB",
21 | "database",
22 | "jquery"],
23 | "devDependencies": {
24 | "grunt": "~0.4.0",
25 | "grunt-saucelabs": "~4.0.0",
26 | "request": "~2.14.0",
27 | "grunt-contrib-uglify": "~0.1.1",
28 | "grunt-contrib-jshint": "~0.1.1",
29 | "grunt-contrib-watch": "~0.2.0",
30 | "grunt-contrib-connect": "~0.1.2",
31 | "grunt-contrib-concat": "~0.1.3",
32 | "grunt-contrib-copy": "~0.4.0",
33 | "grunt-groundskeeper": "~0.1.3",
34 | "grunt-contrib-clean": "~0.4.0"
35 | },
36 | "bundleDependencies": [],
37 | "license": "MIT",
38 | "engines": {
39 | "node": ">=0.8"
40 | }
41 | }
--------------------------------------------------------------------------------
/src/jquery.indexeddb.js:
--------------------------------------------------------------------------------
1 | (function($, undefined) {
2 | 'use strict';
3 | var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
4 | var IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange;
5 | var IDBCursor = window.IDBCursor || window.webkitIDBCursor || {};
6 | if (typeof IDBCursor.PREV === "undefined") {
7 | IDBCursor.PREV = "prev";
8 | }
9 | if (typeof IDBCursor.NEXT === "undefined") {
10 | IDBCursor.NEXT = "next";
11 | }
12 |
13 | /**
14 | * Best to use the constant IDBTransaction since older version support numeric types while the latest spec
15 | * supports strings
16 | */
17 | var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
18 |
19 | function getDefaultTransaction(mode) {
20 | var result = null;
21 | switch (mode) {
22 | case 0:
23 | case 1:
24 | case "readwrite":
25 | case "readonly":
26 | result = mode;
27 | break;
28 | default:
29 | result = IDBTransaction.READ_WRITE || "readwrite";
30 | }
31 | return result;
32 | }
33 |
34 | $.extend({
35 | /**
36 | * The IndexedDB object used to open databases
37 | * @param {Object} dbName - name of the database
38 | * @param {Object} config - version, onupgradeneeded, onversionchange, schema
39 | */
40 | "indexedDB": function(dbName, config) {
41 | if (config) {
42 | // Parse the config argument
43 | if (typeof config === "number") config = {
44 | "version": config
45 | };
46 |
47 | var version = config.version;
48 | if (config.schema && !version) {
49 | var max = -1;
50 | for (var key in config.schema) {
51 | max = max > key ? max : key;
52 | }
53 | version = config.version || max;
54 | }
55 | }
56 |
57 |
58 | var wrap = {
59 | "request": function(req, args) {
60 | return $.Deferred(function(dfd) {
61 | try {
62 | var idbRequest = typeof req === "function" ? req(args) : req;
63 | idbRequest.onsuccess = function(e) {
64 | console.log("Success", idbRequest, e, this);
65 | dfd.resolveWith(idbRequest, [idbRequest.result, e]);
66 | };
67 | idbRequest.onerror = function(e) {
68 | console.log("Error", idbRequest, e, this);
69 | dfd.rejectWith(idbRequest, [idbRequest.error, e]);
70 | };
71 | if (typeof idbRequest.onblocked !== "undefined" && idbRequest.onblocked === null) {
72 | idbRequest.onblocked = function(e) {
73 | console.log("Blocked", idbRequest, e, this);
74 | var res;
75 | try {
76 | res = idbRequest.result;
77 | } catch (e) {
78 | res = null; // Required for Older Chrome versions, accessing result causes error
79 | }
80 | dfd.notifyWith(idbRequest, [res, e]);
81 | };
82 | }
83 | if (typeof idbRequest.onupgradeneeded !== "undefined" && idbRequest.onupgradeneeded === null) {
84 | idbRequest.onupgradeneeded = function(e) {
85 | console.log("Upgrade", idbRequest, e, this);
86 | dfd.notifyWith(idbRequest, [idbRequest.result, e]);
87 | };
88 | }
89 | } catch (e) {
90 | e.name = "exception";
91 | dfd.rejectWith(idbRequest, ["exception", e]);
92 | }
93 | });
94 | },
95 | // Wraps the IDBTransaction to return promises, and other dependent methods
96 | "transaction": function(idbTransaction) {
97 | return {
98 | "objectStore": function(storeName) {
99 | try {
100 | return wrap.objectStore(idbTransaction.objectStore(storeName));
101 | } catch (e) {
102 | idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
103 | return wrap.objectStore(null);
104 | }
105 | },
106 | "createObjectStore": function(storeName, storeParams) {
107 | try {
108 | return wrap.objectStore(idbTransaction.db.createObjectStore(storeName, storeParams));
109 | } catch (e) {
110 | idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
111 | }
112 | },
113 | "deleteObjectStore": function(storeName) {
114 | try {
115 | idbTransaction.db.deleteObjectStore(storeName);
116 | } catch (e) {
117 | idbTransaction.readyState !== idbTransaction.DONE && idbTransaction.abort();
118 | }
119 | },
120 | "abort": function() {
121 | idbTransaction.abort();
122 | }
123 | };
124 | },
125 | "objectStore": function(idbObjectStore) {
126 | var result = {};
127 | // Define CRUD operations
128 | var crudOps = ["add", "put", "get", "delete", "clear", "count"];
129 | for (var i = 0; i < crudOps.length; i++) {
130 | result[crudOps[i]] = (function(op) {
131 | return function() {
132 | return wrap.request(function(args) {
133 | return idbObjectStore[op].apply(idbObjectStore, args);
134 | }, arguments);
135 | };
136 | })(crudOps[i]);
137 | }
138 |
139 | result.each = function(callback, range, direction) {
140 | return wrap.cursor(function() {
141 | if (direction) {
142 | return idbObjectStore.openCursor(wrap.range(range), direction);
143 | } else {
144 | return idbObjectStore.openCursor(wrap.range(range));
145 | }
146 | }, callback);
147 | };
148 |
149 | result.index = function(name) {
150 | return wrap.index(function() {
151 | return idbObjectStore.index(name);
152 | });
153 | };
154 |
155 | result.createIndex = function(prop, options, indexName) {
156 | if (arguments.length === 2 && typeof options === "string") {
157 | indexName = arguments[1];
158 | options = null;
159 | }
160 | if (!indexName) {
161 | indexName = prop;
162 | }
163 | return wrap.index(function() {
164 | return idbObjectStore.createIndex(indexName, prop, options);
165 | });
166 | };
167 |
168 | result.deleteIndex = function(indexName) {
169 | return idbObjectStore.deleteIndex(indexName);
170 | };
171 |
172 | return result;
173 | },
174 |
175 | "range": function(r) {
176 | if ($.isArray(r)) {
177 | if (r.length === 1) {
178 | return IDBKeyRange.only(r[0]);
179 | } else {
180 | return IDBKeyRange.bound(r[0], r[1], (typeof r[2] === 'undefined') ? false : r[2], (typeof r[3] === 'undefined') ? false : r[3]);
181 | }
182 | } else if (typeof r === "undefined") {
183 | return null;
184 | } else {
185 | return r;
186 | }
187 | },
188 |
189 | "cursor": function(idbCursor, callback) {
190 | return $.Deferred(function(dfd) {
191 | try {
192 | console.log("Cursor request created", idbCursor);
193 | var cursorReq = typeof idbCursor === "function" ? idbCursor() : idbCursor;
194 | cursorReq.onsuccess = function(e) {
195 | console.log("Cursor successful");
196 | if (!cursorReq.result) {
197 | dfd.resolveWith(cursorReq, [null, e]);
198 | return;
199 | }
200 | var elem = {
201 | // Delete, update do not move
202 | "delete": function() {
203 | return wrap.request(function() {
204 | return cursorReq.result["delete"]();
205 | });
206 | },
207 | "update": function(data) {
208 | return wrap.request(function() {
209 | return cursorReq.result["update"](data);
210 | });
211 | },
212 | "next": function(key) {
213 | this.data = key;
214 | },
215 | "key": cursorReq.result.key,
216 | "value": cursorReq.result.value
217 | };
218 | console.log("Cursor in progress", elem, e);
219 | dfd.notifyWith(cursorReq, [elem, e]);
220 | var result = callback.apply(cursorReq, [elem]);
221 | console.log("Iteration function returned", result);
222 | try {
223 | if (result === false) {
224 | dfd.resolveWith(cursorReq, [null, e]);
225 | } else if (typeof result === "number") {
226 | cursorReq.result["advance"].apply(cursorReq.result, [result]);
227 | } else {
228 | if (elem.data) cursorReq.result["continue"].apply(cursorReq.result, [elem.data]);
229 | else cursorReq.result["continue"]();
230 | }
231 | } catch (e) {
232 | console.log("Exception when trying to advance cursor", cursorReq, e);
233 | dfd.rejectWith(cursorReq, [cursorReq.result, e]);
234 | }
235 | };
236 | cursorReq.onerror = function(e) {
237 | console.log("Cursor request errored out", e);
238 | dfd.rejectWith(cursorReq, [cursorReq.result, e]);
239 | };
240 | } catch (e) {
241 | console.log("An exception occured inside cursor", cursorReq, e);
242 | e.type = "exception";
243 | dfd.rejectWith(cursorReq, [null, e]);
244 | }
245 | });
246 | },
247 |
248 | "index": function(index) {
249 | try {
250 | var idbIndex = (typeof index === "function" ? index() : index);
251 | } catch (e) {
252 | idbIndex = null;
253 | }
254 | console.log(idbIndex, index);
255 | return {
256 | "each": function(callback, range, direction) {
257 | return wrap.cursor(function() {
258 | if (direction) {
259 | return idbIndex.openCursor(wrap.range(range), direction);
260 | } else {
261 | return idbIndex.openCursor(wrap.range(range));
262 | }
263 |
264 | }, callback);
265 | },
266 | "eachKey": function(callback, range, direction) {
267 | return wrap.cursor(function() {
268 | if (direction) {
269 | return idbIndex.openKeyCursor(wrap.range(range), direction);
270 | } else {
271 | return idbIndex.openKeyCursor(wrap.range(range));
272 | }
273 | }, callback);
274 | },
275 | "get": function(key) {
276 | if (typeof idbIndex.get === "function") {
277 | return wrap.request(idbIndex.get(key));
278 | } else {
279 | return idbIndex.openCursor(wrap.range(key));
280 | }
281 | },
282 | "count": function() {
283 | if (typeof idbIndex.count === "function") {
284 | return wrap.request(idbIndex.count());
285 | } else {
286 | throw "Count not implemented for cursors";
287 | }
288 | },
289 | "getKey": function(key) {
290 | if (typeof idbIndex.getKey === "function") {
291 | return wrap.request(idbIndex.getKey(key));
292 | } else {
293 | return idbIndex.openKeyCursor(wrap.range(key));
294 | }
295 | }
296 | };
297 | }
298 | };
299 |
300 |
301 | // Start with opening the database
302 | var dbPromise = wrap.request(function() {
303 | console.log("Trying to open DB with", version);
304 | return version ? indexedDB.open(dbName, parseInt(version)) : indexedDB.open(dbName);
305 | });
306 | dbPromise.then(function(db, e) {
307 | console.log("DB opened at", db.version);
308 | db.onversionchange = function() {
309 | // Try to automatically close the database if there is a version change request
310 | if (!(config && config.onversionchange && config.onversionchange() !== false)) {
311 | db.close();
312 | }
313 | };
314 | }, function(error, e) {
315 | console.log(error, e);
316 | // Nothing much to do if an error occurs
317 | }, function(db, e) {
318 | if (e && e.type === "upgradeneeded") {
319 | if (config && config.schema) {
320 | // Assuming that version is always an integer
321 | console.log("Upgrading DB to ", db.version);
322 | for (var i = e.oldVersion + 1; i <= e.newVersion; i++) {
323 | typeof config.schema[i] === "function" && config.schema[i].call(this, wrap.transaction(this.transaction));
324 | }
325 | }
326 | if (config && typeof config.upgrade === "function") {
327 | config.upgrade.call(this, wrap.transaction(this.transaction));
328 | }
329 | }
330 | });
331 |
332 | return $.extend(dbPromise, {
333 | "cmp": function(key1, key2) {
334 | return indexedDB.cmp(key1, key2);
335 | },
336 | "deleteDatabase": function() {
337 | // Kinda looks ugly coz DB is opened before it needs to be deleted.
338 | // Blame it on the API
339 | return $.Deferred(function(dfd) {
340 | dbPromise.then(function(db, e) {
341 | db.close();
342 | wrap.request(function() {
343 | return indexedDB.deleteDatabase(dbName);
344 | }).then(function(result, e) {
345 | dfd.resolveWith(this, [result, e]);
346 | }, function(error, e) {
347 | dfd.rejectWith(this, [error, e]);
348 | }, function(db, e) {
349 | dfd.notifyWith(this, [db, e]);
350 | });
351 | }, function(error, e) {
352 | dfd.rejectWith(this, [error, e]);
353 | }, function(db, e) {
354 | dfd.notifyWith(this, [db, e]);
355 | });
356 | });
357 | },
358 | "transaction": function(storeNames, mode) {
359 | !$.isArray(storeNames) && (storeNames = [storeNames]);
360 | mode = getDefaultTransaction(mode);
361 | return $.Deferred(function(dfd) {
362 | dbPromise.then(function(db, e) {
363 | var idbTransaction;
364 | try {
365 | console.log("DB Opened, now trying to create a transaction", storeNames, mode);
366 | idbTransaction = db.transaction(storeNames, mode);
367 | console.log("Created a transaction", idbTransaction, mode, storeNames);
368 | idbTransaction.onabort = idbTransaction.onerror = function(e) {
369 | dfd.rejectWith(idbTransaction, [e]);
370 | };
371 | idbTransaction.oncomplete = function(e) {
372 | dfd.resolveWith(idbTransaction, [e]);
373 | };
374 | } catch (e) {
375 | console.log("Creating a traction failed", e, storeNames, mode, this);
376 | e.type = "exception";
377 | dfd.rejectWith(this, [e]);
378 | return;
379 | }
380 | try {
381 | dfd.notifyWith(idbTransaction, [wrap.transaction(idbTransaction)]);
382 | } catch (e) {
383 | e.type = "exception";
384 | dfd.rejectWith(this, [e]);
385 | }
386 | }, function(err, e) {
387 | dfd.rejectWith(this, [e, err]);
388 | }, function(res, e) {
389 | console.log("Database open is blocked or upgrade needed", res, e.type);
390 | //dfd.notifyWith(this, ["", e]);
391 | });
392 |
393 | });
394 | },
395 | "objectStore": function(storeName, mode) {
396 | var me = this,
397 | result = {};
398 |
399 | function op(callback) {
400 | return $.Deferred(function(dfd) {
401 | function onTransactionProgress(trans, callback) {
402 | try {
403 | console.log("Finally, returning the object store", trans);
404 | callback(trans.objectStore(storeName)).then(function(result, e) {
405 | dfd.resolveWith(this, [result, e]);
406 | }, function(err, e) {
407 | dfd.rejectWith(this, [err, e]);
408 | });
409 | } catch (e) {
410 | console.log("Duh, an exception occured", e);
411 | e.name = "exception";
412 | dfd.rejectWith(trans, [e, e]);
413 | }
414 | }
415 | me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
416 | console.log("Transaction completed");
417 | // Nothing to do when transaction is complete
418 | }, function(err, e) {
419 | // If transaction fails, CrudOp fails
420 | if (err.code === err.NOT_FOUND_ERR && (mode === true || typeof mode === "object")) {
421 | console.log("Object Not found, so will try to create one now");
422 | var db = this.result;
423 | db.close();
424 | dbPromise = wrap.request(function() {
425 | console.log("Now trying to open the database again", db.version);
426 | return indexedDB.open(dbName, (parseInt(db.version, 10) || 1) + 1);
427 | });
428 | dbPromise.then(function(db, e) {
429 | console.log("Database opened, tto open transaction", db.version);
430 | db.onversionchange = function() {
431 | // Try to automatically close the database if there is a version change request
432 | if (!(config && config.onversionchange && config.onversionchange() !== false)) {
433 | db.close();
434 | }
435 | };
436 | me.transaction(storeName, getDefaultTransaction(mode)).then(function() {
437 | console.log("Transaction completed when trying to create object store");
438 | // Nothing much to do
439 | }, function(err, e) {
440 | dfd.rejectWith(this, [err, e]);
441 | }, function(trans, e) {
442 | console.log("Transaction in progress, when object store was not found", this, trans, e);
443 | onTransactionProgress(trans, callback);
444 | });
445 | }, function(err, e) {
446 | dfd.rejectWith(this, [err, e]);
447 | }, function(db, e) {
448 | if (e.type === "upgradeneeded") {
449 | try {
450 | console.log("Now trying to create an object store", e.type);
451 | db.createObjectStore(storeName, mode === true ? {
452 | "autoIncrement": true
453 | } : mode);
454 | console.log("Object store created", storeName, db);
455 | } catch (ex) {
456 | console.log("Exception when trying ot create a new object store", ex);
457 | dfd.rejectWith(this, [ex, e]);
458 | }
459 | }
460 | });
461 | } else {
462 | dfd.rejectWith(this, [err, e]);
463 | }
464 | }, function(trans) {
465 | console.log("Transaction is in progress", trans);
466 | onTransactionProgress(trans, callback);
467 | });
468 | });
469 | }
470 |
471 | function crudOp(opName, args) {
472 | return op(function(wrappedObjectStore) {
473 | return wrappedObjectStore[opName].apply(wrappedObjectStore, args);
474 | });
475 | }
476 |
477 | function indexOp(opName, indexName, args) {
478 | return op(function(wrappedObjectStore) {
479 | var index = wrappedObjectStore.index(indexName);
480 | return index[opName].apply(index[opName], args);
481 | });
482 | }
483 |
484 | var crud = ["add", "delete", "get", "put", "clear", "count", "each"];
485 | for (var i = 0; i < crud.length; i++) {
486 | result[crud[i]] = (function(op) {
487 | return function() {
488 | return crudOp(op, arguments);
489 | };
490 | })(crud[i]);
491 | }
492 |
493 | result.index = function(indexName) {
494 | return {
495 | "each": function(callback, range, direction) {
496 | return indexOp("each", indexName, [callback, range, direction]);
497 | },
498 | "eachKey": function(callback, range, direction) {
499 | return indexOp("eachKey", indexName, [callback, range, direction]);
500 | },
501 | "get": function(key) {
502 | return indexOp("get", indexName, [key]);
503 | },
504 | "count": function() {
505 | return indexOp("count", indexName, []);
506 | },
507 | "getKey": function(key) {
508 | return indexOp("getKey", indexName, [key]);
509 | }
510 | };
511 | };
512 |
513 | return result;
514 | }
515 | });
516 | }
517 | });
518 |
519 | $.indexedDB.IDBCursor = IDBCursor;
520 | $.indexedDB.IDBTransaction = IDBTransaction;
521 | $.idb = $.indexedDB;
522 | })(jQuery);
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: Helvetica Neue, Verdana, Helvetica, Arial;
5 | font-size: 14px;
6 | color: #333;
7 | }
8 |
9 | body {
10 | overflow: auto;
11 | height: 100%;
12 | background: #6788AD;
13 | line-height : 18px;
14 | background: -moz-linear-gradient(top, #496687 0%, #6889AE 100%);
15 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #496687), color-stop(100%, #6889AE) );
16 | filter: progid : DXImageTransform.Microsoft.gradient ( startColorstr = '#496687', endColorstr = '#6889AE',GradientType = 0 );
17 | }
18 |
19 | li{
20 | margin-bottom:3px;
21 | }
22 |
23 | #content-wrap{
24 | width : 70%;
25 | margin : 0 auto;
26 | background-color : white;
27 | box-shadow : 0 0 20px #122F4B;
28 | }
29 |
30 | #download{
31 | float : right;
32 | width : 200px;
33 | text-align : center;
34 | margin-right : 10px;
35 | }
36 |
37 | h1{
38 | padding : 1%;
39 | background-color : #122F4B;
40 | color: white;
41 | font-family: Georgia, "Times New Roman", Times;
42 | font-weight : normal;
43 | text-align : center;
44 | padding : 20px 0;
45 | margin : 0;
46 | }
47 |
48 | #content{
49 | padding : 2%;
50 | }
51 |
52 | pre{
53 | border: SOLID 1px black;
54 | display : block;
55 | margin : 10px 0;
56 | padding : 10px;
57 | font-family : consolas, monaco, courier;
58 | font-size : 12px;
59 | }
60 |
61 | #log{
62 | font-family : consolas, monaco, courier;
63 | font-size : 12px;
64 | border : SOLID 1px black;
65 | margin : 10px 0;
66 | padding : 10px;
67 | }
68 |
69 | button{
70 | display : block;
71 | }
72 |
73 | h3{
74 | }
75 |
76 | .left{
77 | float : left;
78 | width : 48%;
79 | }
80 |
81 | .right{
82 | border-left : 1px dotted #CCC;
83 | padding : 1%;
84 | float : right;
85 | width : 48%;
86 | }
87 |
88 | .clear{
89 | clear:both;
90 | }
91 |
92 |
93 | /* punch
94 | *******************************************************************************/
95 | .punch {
96 | display:block;
97 | text-decoration : none;
98 | background: #4162a8;
99 | border-top: 1px solid #38538c;
100 | border-right: 1px solid #1f2d4d;
101 | border-bottom: 1px solid #151e33;
102 | border-left: 1px solid #1f2d4d;
103 | -webkit-border-radius: 4px;
104 | -moz-border-radius: 4px;
105 | border-radius: 4px;
106 | -webkit-box-shadow: inset 0 1px 10px 1px #5c8bee, 0px 1px 0 #1d2c4d, 0 6px 0px #1f3053, 0 8px 4px 1px #111111;
107 | -moz-box-shadow: inset 0 1px 10px 1px #5c8bee, 0px 1px 0 #1d2c4d, 0 6px 0px #1f3053, 0 8px 4px 1px #111111;
108 | box-shadow: inset 0 1px 10px 1px #5c8bee, 0px 1px 0 #1d2c4d, 0 6px 0px #1f3053, 0 8px 4px 1px #111111;
109 | color: #fff;
110 | font: bold 20px "helvetica neue", helvetica, arial, sans-serif;
111 | line-height: 1;
112 | margin-bottom: 10px;
113 | padding: 10px 0 12px 0;
114 | text-align: center;
115 | text-shadow: 0px -1px 1px #1e2d4d;
116 | -webkit-background-clip: padding-box; }
117 | .punch:hover {
118 | -webkit-box-shadow: inset 0 0px 20px 1px #87adff, 0px 1px 0 #1d2c4d, 0 6px 0px #1f3053, 0 8px 4px 1px #111111;
119 | -moz-box-shadow: inset 0 0px 20px 1px #87adff, 0px 1px 0 #1d2c4d, 0 6px 0px #1f3053, 0 8px 4px 1px #111111;
120 | box-shadow: inset 0 0px 20px 1px #87adff, 0px 1px 0 #1d2c4d, 0 6px 0px #1f3053, 0 8px 4px 1px #111111;
121 | cursor: pointer; }
122 | .punch:active {
123 | -webkit-box-shadow: inset 0 1px 10px 1px #5c8bee, 0 1px 0 #1d2c4d, 0 2px 0 #1f3053, 0 4px 3px 0 #111111;
124 | -moz-box-shadow: inset 0 1px 10px 1px #5c8bee, 0 1px 0 #1d2c4d, 0 2px 0 #1f3053, 0 4px 3px 0 #111111;
125 | box-shadow: inset 0 1px 10px 1px #5c8bee, 0 1px 0 #1d2c4d, 0 2px 0 #1f3053, 0 4px 3px 0 #111111;
126 | }
--------------------------------------------------------------------------------
/test/api.txt:
--------------------------------------------------------------------------------
1 | indexedDB(open)
2 | .done(function(dbRequest.result){this = dbRequest})
3 | .fail(function(dbRequest.error) {this = dbRequest})
4 | .progress(function(trans) {this = dbRequest;
5 | this = dbRequest;
6 | trans.createObjectStore
7 | trans.deleteObjectStore()
8 | trans.abort();
9 | trans.done()
10 | trans.onerror()
11 | trans.progress()
12 | }) // called on upgrade and blocked
13 |
14 | .transaction(store, mode)
15 | .progress(function(trans){
16 | this = transaction;
17 | trans.objectStore()
18 | trans.abort()
19 | })
20 | .done(function(onCompleteEvent) {this = transaction}) // transaction is complete
21 | .fail(function(onErrorEvent ) {this = transaction}) // onabort, or onerror, or exception
22 |
23 |
24 | .objectStore(storeName, mode)
25 | .add(), .delete(), .put(), .clear()
26 | .forEach(elem){this.delete(), this.update(newElem)},
27 | .index()
28 | .createIndex()
29 | .deleteIndex()
30 |
31 | .fail()
32 |
33 |
34 | .deleteDatabase() - returns a promise
35 | .cmp() - returns 1, 0, -1
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
10 |
12 |
14 |
16 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 | test markup, will be hidden
866 |
867 |
884 |
885 |
886 |
--------------------------------------------------------------------------------
/test/sample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
11 |
13 |
36 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/test/sampleData.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | var DB = {
3 | NAME : "dbName",
4 | OBJECT_STORE_1 : "objectStore1",
5 | OBJECT_STORE_2 : "objectStore2",
6 | OBJECT_STORE_3 : "objectStore3",
7 | OBJECT_STORE_4 : "objectStore4",
8 | INDEX1_ON_OBJECT_STORE_1 : "Index1_ObjectStore1",
9 | INDEX1_ON_OBJECT_STORE_2 : "Index1_ObjectStore2"
10 | };
11 |
12 | var sample = (function() {
13 |
14 | var takenValues = {};
15 | return {
16 | obj : function() {
17 | return {
18 | "String" : "Sample " + new Date(),
19 | "Int" : this.integer(),
20 | "Float" : Math.random(),
21 | "Boolean" : true
22 | };
23 | },
24 | integer : function(arg) {
25 | var res;
26 | do {
27 | res = parseInt(Math.random() * (arg || 1000), 10);
28 | } while (takenValues[res]);
29 | takenValues[res] = true;
30 | return res;
31 | }
32 | };
33 | }());
34 |
--------------------------------------------------------------------------------
/travis.sh:
--------------------------------------------------------------------------------
1 | repo="https://${GH_TOKEN}@github.com/$TRAVIS_REPO_SLUG.git"
2 |
3 | # If this is a pull request, we dont want to continue
4 | if [ "$TRAVIS_PULL_REQUEST" != "false" ] ; then
5 | echo "Nothing to do on a pull request"
6 | exit 0
7 | fi
8 |
9 | # All Pull requests are to the branch called incoming-pr
10 | # If this is not that branch, the rest of the script is irrelevant
11 | if [ "$TRAVIS_BRANCH" != "incoming-pr" ] ; then
12 | echo "Nothing to do on the master branch"
13 | exit 0
14 | fi
15 |
16 | git fetch
17 | git branch --all
18 | # This part of the script is run before installing deps or tests
19 | if [ "$1" = "before" ] ; then
20 | # So this is incoming-pr branch. Need to check if this is exactly same as the master
21 | # If it is, this branch does not have anything new, so no need to try and build it
22 | incoming_commit=$(git rev-parse HEAD)
23 | git checkout --orphan master
24 | git pull origin master --depth=1
25 | master_commit=$(git rev-parse HEAD)
26 | if [ "$incoming_commit" = "$master_commit" ] ; then
27 | echo "Not required to build this as this is same as the master branch"
28 | exit 1
29 | else
30 | git checkout incoming-pr
31 | echo "Current branch is - $(git rev-parse HEAD)"
32 | exit 0
33 | fi
34 | fi
35 |
36 | git checkout incoming-pr
37 | if [ "$1" = "merge" ] ; then
38 | # If the build was successful, travis after-success will send merge
39 | echo "Merging incoming-pr to master"
40 | git checkout master
41 | git merge incoming-pr --log
42 | git push $repo master -q 2> /dev/null
43 |
44 | echo "Merging master into gh-pages"
45 | git checkout gh-pages
46 | git merge master --log
47 | git push $repo gh-pages -q 2> /dev/null
48 | else
49 | # If build failed, travis after-failure will send ./travis.sh revert
50 | echo "Reverting dev branch to what master was"
51 | # Save the current changes to a new branch
52 | echo "Creating a new branch for failed build - incoming-pr-fail-$TRAVIS_BUILD_ID"
53 | git checkout -b incoming-pr-fail-$TRAVIS_BUILD_ID
54 | git push $repo incoming-pr-fail-$TRAVIS_BUILD_ID -q 2> /dev/null
55 | git checkout master
56 | fi
57 |
58 | echo "Making incoming-pr same as master"
59 | # Merge or revert is done, so make incoming-pr branch at par with master
60 | # This is done to make it ready for accepting the next pull request
61 | git push $repo --delete incoming-pr -q 2> /dev/null
62 | git branch -D incoming-pr
63 | git branch incoming-pr
64 | git push $repo incoming-pr -q 2> /dev/null
65 |
--------------------------------------------------------------------------------