├── .osnft ├── LICENSE ├── angular ├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── model │ │ │ └── student.ts │ │ ├── service │ │ │ ├── base.service.spec.ts │ │ │ ├── base.service.ts │ │ │ ├── idb.service.spec.ts │ │ │ ├── idb.service.ts │ │ │ ├── student.service.spec.ts │ │ │ └── student.service.ts │ │ └── student │ │ │ ├── student.component.css │ │ │ ├── student.component.html │ │ │ ├── student.component.spec.ts │ │ │ └── student.component.ts │ ├── assets │ │ └── .gitkeep │ ├── browserslist │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tsconfig.json └── tslint.json ├── change-db-schema ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── index.html ├── readme.md ├── scripts │ ├── bootstrap.js │ ├── index.js │ ├── jquery.js │ ├── jsstore.js │ ├── jsstore.js.map │ ├── jsstore.worker.js │ └── jsstore.worker.js.map └── style │ ├── bootstrap.css │ ├── font-awesome.min.css │ └── main.css ├── electron ├── .gitignore ├── LICENSE.md ├── README.md ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── component │ │ │ └── student_grid.js │ │ ├── index.js │ │ └── storage_service │ │ │ ├── base_service.js │ │ │ ├── idb_service.js │ │ │ └── student_service.js │ ├── electron │ │ ├── electron_app.js │ │ └── index.js │ └── index.html └── webpack.config.js ├── mahal ├── .babelrc ├── .gitignore ├── assets │ └── img │ │ └── mahal-logo.png ├── config │ ├── env │ │ ├── development.js │ │ ├── index.js │ │ └── production.js │ ├── lang │ │ └── mahal.config.ts │ └── webpack │ │ ├── base.config.js │ │ ├── dev.config.js │ │ └── prod.config.js ├── package-lock.json ├── package.json ├── readme.md ├── src │ ├── app.mahal │ ├── components │ │ └── student.mahal │ ├── formatters │ │ ├── img_path.js │ │ └── index.js │ ├── index.html │ ├── index.js │ └── storage_service │ │ ├── base_service.js │ │ ├── idb_service.js │ │ └── student_service.js └── tsconfig.json ├── react ├── .babelrc ├── .gitignore ├── package-lock.json ├── package.json ├── readme.md ├── src │ ├── component │ │ ├── layout.jsx │ │ └── student_grid.jsx │ ├── index.html │ ├── index.js │ ├── model │ │ └── student.js │ └── storage_service │ │ ├── base_service.js │ │ ├── idb_service.js │ │ └── student_service.js └── webpack.config.js ├── readme.md ├── service_worker ├── README.md ├── index.html ├── script.js ├── service-worker.js └── style.css ├── simple_example ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 ├── index.html ├── readme.md ├── scripts │ ├── bootstrap.js │ ├── index.js │ ├── jquery.js │ ├── jsstore.js │ ├── jsstore.js.map │ ├── jsstore.worker.js │ └── jsstore.worker.js.map └── style │ ├── bootstrap.css │ ├── font-awesome.min.css │ └── main.css ├── svelte ├── .gitignore ├── package-lock.json ├── package.json ├── readme.md ├── src │ ├── components │ │ ├── main.svelte │ │ └── products_grid.svelte │ ├── index.html │ ├── index.js │ └── storage_services │ │ ├── base_service.js │ │ ├── idb_service.js │ │ └── product_service.js └── webpack.config.js ├── typescript ├── .gitignore ├── package-lock.json ├── package.json ├── readme.md ├── src │ ├── business │ │ └── student_logic.ts │ ├── index.html │ ├── index.ts │ ├── model │ │ └── student.ts │ ├── storage_service │ │ ├── base_service.ts │ │ ├── idb_helper.ts │ │ └── student_service.ts │ └── styles │ │ └── app.css ├── tsconfig.json ├── tslint.json └── webpack.config.js ├── typescript_without_worker ├── .gitignore ├── package-lock.json ├── package.json ├── readme.md ├── src │ ├── business │ │ └── student_logic.ts │ ├── extra │ │ └── worker.d.ts │ ├── index.html │ ├── index.ts │ ├── model │ │ └── student.ts │ ├── storage_service │ │ ├── base_service.ts │ │ ├── idb_helper.ts │ │ └── student_service.ts │ └── styles │ │ └── app.css ├── tsconfig.json ├── tslint.json └── webpack.config.js ├── vue ├── .gitignore ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html └── src │ ├── App.vue │ ├── assets │ └── logo.png │ ├── components │ └── student_grid.vue │ ├── global.js │ ├── main.js │ └── service │ ├── idb_service.js │ ├── jsstore_con.js │ └── student_service.js └── without_web_worker ├── README.md ├── fonts ├── FontAwesome.otf ├── fontawesome-webfont.eot ├── fontawesome-webfont.svg ├── fontawesome-webfont.ttf ├── fontawesome-webfont.woff └── fontawesome-webfont.woff2 ├── index.html ├── scripts ├── bootstrap.js ├── index.js ├── jquery.js ├── jsstore.js └── jsstore.worker.js └── style ├── bootstrap.css ├── font-awesome.min.css └── main.css /.osnft: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "walletAddress":"0x0FA4EA6F5A540BA18c477087007098AF954048Be" 4 | 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ujjwal Gupta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /angular/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /angular/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /angular/README.md: -------------------------------------------------------------------------------- 1 | # JsStore integration with Angular 2 | 3 | This is an example for jsstore for angular. It shows a demo of how to integrte jsstore with angular & some basic api call for a crud operation. 4 | 5 | Some important points - 6 | 7 | * The JsStore codes are inside folder service. 8 | * JsStore is initiated in `app.component.ts` in `ngOnInit` method. 9 | 10 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.3.9. 11 | 12 | ## Development server 13 | 14 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 15 | 16 | ## Code scaffolding 17 | 18 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 19 | 20 | ## Build 21 | 22 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 23 | 24 | ## Running unit tests 25 | 26 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 27 | 28 | ## Running end-to-end tests 29 | 30 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 31 | 32 | ## Further help 33 | 34 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 35 | -------------------------------------------------------------------------------- /angular/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "app", 11 | "schematics": {}, 12 | "architect": { 13 | "build": { 14 | "builder": "@angular-devkit/build-angular:browser", 15 | "options": { 16 | "outputPath": "dist/angular", 17 | "index": "src/index.html", 18 | "main": "src/main.ts", 19 | "polyfills": "src/polyfills.ts", 20 | "tsConfig": "src/tsconfig.app.json", 21 | "assets": [ 22 | "src/favicon.ico", 23 | "src/assets" 24 | ], 25 | "styles": [ 26 | "src/styles.css" 27 | ], 28 | "scripts": [], 29 | "es5BrowserSupport": true 30 | }, 31 | "configurations": { 32 | "production": { 33 | "fileReplacements": [ 34 | { 35 | "replace": "src/environments/environment.ts", 36 | "with": "src/environments/environment.prod.ts" 37 | } 38 | ], 39 | "optimization": true, 40 | "outputHashing": "all", 41 | "sourceMap": false, 42 | "extractCss": true, 43 | "namedChunks": false, 44 | "aot": true, 45 | "extractLicenses": true, 46 | "vendorChunk": false, 47 | "buildOptimizer": true, 48 | "budgets": [ 49 | { 50 | "type": "initial", 51 | "maximumWarning": "2mb", 52 | "maximumError": "5mb" 53 | } 54 | ] 55 | } 56 | } 57 | }, 58 | "serve": { 59 | "builder": "@angular-devkit/build-angular:dev-server", 60 | "options": { 61 | "browserTarget": "angular:build" 62 | }, 63 | "configurations": { 64 | "production": { 65 | "browserTarget": "angular:build:production" 66 | } 67 | } 68 | }, 69 | "extract-i18n": { 70 | "builder": "@angular-devkit/build-angular:extract-i18n", 71 | "options": { 72 | "browserTarget": "angular:build" 73 | } 74 | }, 75 | "test": { 76 | "builder": "@angular-devkit/build-angular:karma", 77 | "options": { 78 | "main": "src/test.ts", 79 | "polyfills": "src/polyfills.ts", 80 | "tsConfig": "src/tsconfig.spec.json", 81 | "karmaConfig": "src/karma.conf.js", 82 | "styles": [ 83 | "src/styles.css" 84 | ], 85 | "scripts": [], 86 | "assets": [ 87 | "src/favicon.ico", 88 | "src/assets" 89 | ] 90 | } 91 | }, 92 | "lint": { 93 | "builder": "@angular-devkit/build-angular:tslint", 94 | "options": { 95 | "tsConfig": [ 96 | "src/tsconfig.app.json", 97 | "src/tsconfig.spec.json" 98 | ], 99 | "exclude": [ 100 | "**/node_modules/**" 101 | ] 102 | } 103 | } 104 | } 105 | }, 106 | "angular-e2e": { 107 | "root": "e2e/", 108 | "projectType": "application", 109 | "prefix": "", 110 | "architect": { 111 | "e2e": { 112 | "builder": "@angular-devkit/build-angular:protractor", 113 | "options": { 114 | "protractorConfig": "e2e/protractor.conf.js", 115 | "devServerTarget": "angular:serve" 116 | }, 117 | "configurations": { 118 | "production": { 119 | "devServerTarget": "angular:serve:production" 120 | } 121 | } 122 | }, 123 | "lint": { 124 | "builder": "@angular-devkit/build-angular:tslint", 125 | "options": { 126 | "tsConfig": "e2e/tsconfig.e2e.json", 127 | "exclude": [ 128 | "**/node_modules/**" 129 | ] 130 | } 131 | } 132 | } 133 | } 134 | }, 135 | "defaultProject": "angular" 136 | } -------------------------------------------------------------------------------- /angular/e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /angular/e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to angular!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /angular/e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /angular/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /angular/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "private": true, 13 | "dependencies": { 14 | "@angular/animations": "~7.2.0", 15 | "@angular/common": "~7.2.0", 16 | "@angular/compiler": "~7.2.0", 17 | "@angular/core": "~7.2.0", 18 | "@angular/forms": "~7.2.0", 19 | "@angular/platform-browser": "~7.2.0", 20 | "@angular/platform-browser-dynamic": "~7.2.0", 21 | "@angular/router": "~7.2.0", 22 | "core-js": "^2.5.4", 23 | "jsstore": "^3.6.1", 24 | "rxjs": "~6.3.3", 25 | "tslib": "^1.9.0", 26 | "zone.js": "~0.8.26" 27 | }, 28 | "devDependencies": { 29 | "@angular-devkit/build-angular": "~0.13.0", 30 | "@angular/cli": "~7.3.9", 31 | "@angular/compiler-cli": "~7.2.0", 32 | "@angular/language-service": "~7.2.0", 33 | "@types/jasmine": "~2.8.8", 34 | "@types/jasminewd2": "~2.0.3", 35 | "@types/node": "^8.10.59", 36 | "codelyzer": "~4.5.0", 37 | "file-loader": "^5.0.2", 38 | "jasmine-core": "~2.99.1", 39 | "jasmine-spec-reporter": "~4.2.1", 40 | "karma": "~4.0.0", 41 | "karma-chrome-launcher": "~2.2.0", 42 | "karma-coverage-istanbul-reporter": "~2.0.1", 43 | "karma-jasmine": "~1.1.2", 44 | "karma-jasmine-html-reporter": "^0.2.2", 45 | "protractor": "~5.4.0", 46 | "ts-node": "~7.0.0", 47 | "tslint": "~5.11.0", 48 | "typescript": "~3.2.2" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /angular/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/angular/src/app/app.component.css -------------------------------------------------------------------------------- /angular/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | Welcome to {{ title }} tutorial for JsStore! 5 |

6 |
7 | 8 | -------------------------------------------------------------------------------- /angular/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'angular'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('angular'); 23 | }); 24 | 25 | it('should render title in a h1 tag', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to angular!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /angular/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { initJsStore } from './service/idb.service'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.css'] 8 | }) 9 | export class AppComponent implements OnInit { 10 | title = 'JsStore Angular'; 11 | 12 | async ngOnInit() { 13 | try { 14 | await initJsStore(); 15 | console.log('jsstore connected'); 16 | } catch (error) { 17 | alert(error.message); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /angular/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { AppComponent } from './app.component'; 5 | import { StudentComponent } from './student/student.component'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | AppComponent, 10 | StudentComponent 11 | ], 12 | imports: [ 13 | BrowserModule,FormsModule 14 | ], 15 | providers: [], 16 | bootstrap: [AppComponent] 17 | }) 18 | export class AppModule { } 19 | -------------------------------------------------------------------------------- /angular/src/app/model/student.ts: -------------------------------------------------------------------------------- 1 | export class IStudent { 2 | id?: number; 3 | name: string; 4 | gender: string; 5 | country: string; 6 | city: string; 7 | } 8 | 9 | export class Student implements IStudent { 10 | id ?= null; 11 | name = ''; 12 | gender = 'm'; 13 | country = ''; 14 | city = ''; 15 | } 16 | -------------------------------------------------------------------------------- /angular/src/app/service/base.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { BaseService } from './base.service'; 4 | 5 | describe('BaseService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: BaseService = TestBed.get(BaseService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /angular/src/app/service/base.service.ts: -------------------------------------------------------------------------------- 1 | import { idbCon } from './idb.service'; 2 | 3 | 4 | export class BaseService { 5 | 6 | get connection() { 7 | return idbCon; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /angular/src/app/service/idb.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { IdbService } from './idb.service'; 4 | 5 | describe('IdbService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [IdbService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([IdbService], (service: IdbService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /angular/src/app/service/idb.service.ts: -------------------------------------------------------------------------------- 1 | import * as JsStore from 'jsstore'; 2 | import { IDataBase, DATA_TYPE, ITable } from 'jsstore'; 3 | import { Student } from '../model/student'; 4 | import { environment } from 'src/environments/environment'; 5 | declare var require: any; 6 | 7 | const getWorkerPath = () => { 8 | if (environment.production) { 9 | return require('file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js'); 10 | } else { 11 | return require('file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.js'); 12 | } 13 | }; 14 | 15 | // This will ensure that we are using only one instance. 16 | // Otherwise due to multiple instance multiple worker will be created. 17 | export const idbCon = new JsStore.Connection(new Worker(getWorkerPath().default)); 18 | export const dbname = 'Angular_Demo'; 19 | 20 | 21 | const getDatabase = () => { 22 | const tblStudent: ITable = { 23 | name: 'Students', 24 | columns: { 25 | id: { 26 | primaryKey: true, 27 | autoIncrement: true 28 | }, 29 | name: { 30 | notNull: true, 31 | dataType: DATA_TYPE.String 32 | }, 33 | gender: { 34 | dataType: DATA_TYPE.String, 35 | default: 'male' 36 | }, 37 | country: { 38 | notNull: true, 39 | dataType: DATA_TYPE.String 40 | }, 41 | city: { 42 | dataType: DATA_TYPE.String, 43 | notNull: true 44 | } 45 | } 46 | }; 47 | const dataBase: IDataBase = { 48 | name: dbname, 49 | tables: [tblStudent] 50 | }; 51 | return dataBase; 52 | }; 53 | 54 | function getAvailableStudents() { 55 | const availableStudents: Student[] = [{ 56 | city: 'Bangalore', 57 | country: 'India', 58 | gender: 'Male', 59 | name: 'Ujjwal Gupta' 60 | }]; 61 | return availableStudents; 62 | } 63 | 64 | export const initJsStore = async () => { 65 | const dataBase = getDatabase(); 66 | const isDbCreated = await idbCon.initDb(dataBase); 67 | if (isDbCreated) { 68 | idbCon.insert({ 69 | into: 'Students', 70 | values: getAvailableStudents() 71 | }) 72 | } 73 | }; 74 | 75 | 76 | -------------------------------------------------------------------------------- /angular/src/app/service/student.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { StudentService } from './student.service'; 4 | 5 | describe('StudentService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: StudentService = TestBed.get(StudentService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /angular/src/app/service/student.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { BaseService } from './base.service'; 3 | import { IStudent } from '../model/student'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class StudentService extends BaseService { 9 | 10 | tableName = 'Students'; 11 | 12 | getStudents() { 13 | return this.connection.select({ 14 | from: this.tableName 15 | }); 16 | } 17 | 18 | addStudent(student: IStudent) { 19 | return this.connection.insert({ 20 | into: this.tableName, 21 | return: true, // as id is autoincrement, so we would like to get the inserted value 22 | values: [student] 23 | }); 24 | } 25 | 26 | deleteStudent(studentId: number) { 27 | return this.connection.remove({ 28 | from: this.tableName, 29 | where: { 30 | id: studentId 31 | } 32 | }); 33 | } 34 | 35 | updateStudent(studentId: number, updateValue: IStudent) { 36 | return this.connection.update({ 37 | in: this.tableName, 38 | where: { 39 | id: studentId 40 | }, 41 | set: updateValue 42 | }); 43 | } 44 | 45 | getStudentById(studentId: number) { 46 | return this.connection.select({ 47 | from: this.tableName, 48 | where: { 49 | id: studentId 50 | } 51 | }); 52 | } 53 | 54 | async clearStudents() { 55 | return await this.connection.clear(this.tableName); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /angular/src/app/student/student.component.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | } 4 | 5 | table tr td, 6 | th { 7 | border: 1px solid black; 8 | text-align: center; 9 | padding: 10px; 10 | } 11 | 12 | contenteditable { 13 | border: 2px solid blue; 14 | } 15 | -------------------------------------------------------------------------------- /angular/src/app/student/student.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 20 | 23 | 26 | 29 | 32 | 33 | 34 | 40 | 47 | 51 | 55 | 59 | 63 | 64 |
Student Namegendercountrycity
12 | 13 | 15 | 19 | 21 | 22 | 24 | 25 | 27 | 28 | 30 | 31 |
35 | 36 | 37 | {{student.name}} 38 | 39 | 41 | 45 | {{student.gender=='m'?'Male':'Female'}} 46 | 48 | 49 | {{student.country}} 50 | 52 | 53 | {{student.city}} 54 | 56 | 57 | 58 | 60 | 61 | 62 |
65 |
66 | 67 |
68 | -------------------------------------------------------------------------------- /angular/src/app/student/student.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { StudentComponent } from './student.component'; 4 | 5 | describe('StudentComponent', () => { 6 | let component: StudentComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ StudentComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(StudentComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /angular/src/app/student/student.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { StudentService } from '../service/student.service'; 3 | import { Student, IStudent } from '../model/student'; 4 | 5 | 6 | @Component({ 7 | 8 | selector: 'app-student', 9 | 10 | templateUrl: './student.component.html', 11 | 12 | styleUrls: ['./student.component.css'], 13 | 14 | providers: [StudentService] 15 | 16 | }) 17 | export class StudentComponent implements OnInit { 18 | 19 | private service: StudentService; 20 | students: Array = []; 21 | newStudent: IStudent = new Student(); 22 | oldStudent: IStudent = new Student(); 23 | 24 | editing = false; 25 | 26 | constructor(service: StudentService) { 27 | this.service = service; 28 | } 29 | 30 | 31 | ngOnInit() { 32 | this.getStudents(); 33 | } 34 | 35 | async getStudents() { 36 | try { 37 | this.students = await this.service.getStudents(); 38 | } catch (error) { 39 | console.error(error); 40 | alert(error.message); 41 | } 42 | } 43 | 44 | async addStudent() { 45 | try { 46 | const addedStudents = await this.service.addStudent(this.newStudent) as IStudent[]; 47 | if (addedStudents.length > 0) { 48 | this.students.push(addedStudents[0]); 49 | this.clearNewStudent(); 50 | alert('Successfully added'); 51 | } 52 | } catch (error) { 53 | console.error(error); 54 | alert(error.message); 55 | } 56 | } 57 | 58 | clearNewStudent() { 59 | this.newStudent = new Student(); 60 | } 61 | 62 | async deleteStudent(studentId) { 63 | try { 64 | const noOfrowsDeleted = await this.service.deleteStudent(studentId); 65 | if (noOfrowsDeleted > 0) { 66 | const index = this.students.findIndex(student => student.id === studentId); 67 | this.students.splice(index, 1); 68 | alert('Successfully deleted'); 69 | } 70 | } catch (error) { 71 | console.error(error); 72 | alert(error.message); 73 | } 74 | 75 | } 76 | 77 | clearOldStudent() { 78 | this.oldStudent = new Student(); 79 | } 80 | 81 | async getStudent(studentId) { 82 | try { 83 | const students = await this.service.getStudentById(studentId); 84 | if (students.length > 0) { 85 | this.oldStudent = students[0]; 86 | } 87 | } catch (error) { 88 | console.error(error); 89 | alert(error.message); 90 | } 91 | 92 | } 93 | 94 | async updateStudent() { 95 | const updatedValue: IStudent = { 96 | name: this.oldStudent.name, 97 | gender: this.oldStudent.gender, 98 | country: this.oldStudent.country, 99 | city: this.oldStudent.city 100 | }; 101 | try { 102 | const noOfrowsUpdated = await this.service.updateStudent(this.oldStudent.id, updatedValue); 103 | if (noOfrowsUpdated > 0) { 104 | const index = this.students.findIndex(student => student.id === this.oldStudent.id); 105 | this.students[index] = this.oldStudent; 106 | this.clearOldStudent(); 107 | alert('Successfully updated'); 108 | } 109 | } catch (error) { 110 | console.error(error); 111 | alert(error.message); 112 | } 113 | } 114 | 115 | async clearAllStudents() { 116 | try { 117 | await this.service.clearStudents(); 118 | this.students = []; 119 | alert('All students cleared'); 120 | } catch (error) { 121 | alert(error.message); 122 | } 123 | 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /angular/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/angular/src/assets/.gitkeep -------------------------------------------------------------------------------- /angular/src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /angular/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /angular/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /angular/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/angular/src/favicon.ico -------------------------------------------------------------------------------- /angular/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /angular/src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage/angular'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /angular/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /angular/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /angular/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /angular/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /angular/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /angular/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /angular/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /angular/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "es2015", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es5", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /angular/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "codelyzer" 5 | ], 6 | "rules": { 7 | "array-type": false, 8 | "arrow-parens": false, 9 | "deprecation": { 10 | "severity": "warn" 11 | }, 12 | "import-blacklist": [ 13 | true, 14 | "rxjs/Rx" 15 | ], 16 | "interface-name": false, 17 | "max-classes-per-file": false, 18 | "max-line-length": [ 19 | true, 20 | 140 21 | ], 22 | "member-access": false, 23 | "member-ordering": [ 24 | true, 25 | { 26 | "order": [ 27 | "static-field", 28 | "instance-field", 29 | "static-method", 30 | "instance-method" 31 | ] 32 | } 33 | ], 34 | "no-consecutive-blank-lines": false, 35 | "no-console": [ 36 | true, 37 | "debug", 38 | "info", 39 | "time", 40 | "timeEnd", 41 | "trace" 42 | ], 43 | "no-empty": false, 44 | "no-inferrable-types": [ 45 | true, 46 | "ignore-params" 47 | ], 48 | "no-non-null-assertion": true, 49 | "no-redundant-jsdoc": true, 50 | "no-switch-case-fall-through": true, 51 | "no-use-before-declare": true, 52 | "no-var-requires": false, 53 | "object-literal-key-quotes": [ 54 | true, 55 | "as-needed" 56 | ], 57 | "object-literal-sort-keys": false, 58 | "ordered-imports": false, 59 | "quotemark": [ 60 | true, 61 | "single" 62 | ], 63 | "trailing-comma": false, 64 | "no-output-on-prefix": true, 65 | "use-input-property-decorator": true, 66 | "use-output-property-decorator": true, 67 | "use-host-property-decorator": true, 68 | "no-input-rename": true, 69 | "no-output-rename": true, 70 | "use-life-cycle-interface": true, 71 | "use-pipe-transform-interface": true, 72 | "component-class-suffix": true, 73 | "directive-class-suffix": true 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /change-db-schema/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/change-db-schema/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /change-db-schema/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/change-db-schema/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /change-db-schema/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/change-db-schema/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /change-db-schema/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/change-db-schema/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /change-db-schema/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/change-db-schema/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /change-db-schema/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | JsStore Example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | 24 | 27 |
28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
31 | Student's Details
NameGenderCountryCity
44 | 85 |
86 |
87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /change-db-schema/readme.md: -------------------------------------------------------------------------------- 1 | ## JsStore 2 | 3 | This is a demo example for crud operation in indexeddb using jsstore. 4 | 5 | ## How to run 6 | 7 | Run this folder inside a http server otherwise you might see an error. -------------------------------------------------------------------------------- /change-db-schema/scripts/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var jsstoreCon = new JsStore.Connection(new Worker("scripts/jsstore.worker.js")); 4 | 5 | window.onload = function () { 6 | refreshTableData(); 7 | registerEvents(); 8 | initDb(getDbSchema()); 9 | }; 10 | 11 | async function initDb(dbSchema) { 12 | var isDbCreated = await jsstoreCon.initDb(dbSchema); 13 | if (isDbCreated) { 14 | localStorage.setItem("db_version", dbSchema.version); 15 | 16 | console.log('db created'); 17 | if (dbSchema.version === 2) { 18 | var datas = await jsstoreCon.select({ 19 | from: "Student" 20 | }); 21 | datas.forEach(data => { 22 | const gender = data.gender; 23 | if (!gender) { 24 | data.gender = 0; 25 | } 26 | else { 27 | data.gender = gender === "male" ? 1 : 2; 28 | } 29 | }) 30 | 31 | await jsstoreCon.insert({ 32 | into: "Student", 33 | values: datas, 34 | upsert: true 35 | }) 36 | refreshTableData(); 37 | console.log("data type updated"); 38 | } 39 | } 40 | else { 41 | console.log('db opened'); 42 | } 43 | } 44 | 45 | function getDbSchema() { 46 | var table = { 47 | name: 'Student', 48 | columns: { 49 | id: { 50 | primaryKey: true, 51 | autoIncrement: true 52 | }, 53 | name: { 54 | notNull: true, 55 | dataType: 'string' 56 | }, 57 | gender: { 58 | dataType: 'string', 59 | default: 'male' 60 | }, 61 | country: { 62 | notNull: true, 63 | dataType: 'string' 64 | }, 65 | city: { 66 | dataType: 'string', 67 | notNull: true 68 | }, 69 | }, 70 | alter: { 71 | // 2 is database version to target 72 | 2: { 73 | modify: { 74 | gender: { 75 | //1 means male, 2 means female, 0 means unknown 76 | dataType: "number" 77 | } 78 | }, 79 | } 80 | } 81 | } 82 | const dbVersion = localStorage.getItem("db_version"); 83 | var db = { 84 | name: 'My-Db', 85 | tables: [table], 86 | version: dbVersion ? Number(dbVersion) : null 87 | } 88 | return db; 89 | } 90 | 91 | function registerEvents() { 92 | $('#btnAddStudent').click(function () { 93 | showFormAndHideGrid(); 94 | }) 95 | $('#tblGrid tbody').on('click', '.edit', function () { 96 | var row = $(this).parents().eq(1); 97 | var child = row.children(); 98 | var student = { 99 | id: row.attr('itemid'), 100 | name: child.eq(0).text(), 101 | gender: child.eq(1).text(), 102 | country: child.eq(2).text(), 103 | city: child.eq(3).text() 104 | } 105 | refreshFormData(student); 106 | showFormAndHideGrid(); 107 | }); 108 | $('#tblGrid tbody').on('click', '.delete', function () { 109 | var result = confirm('Are you sure, you want to delete?'); 110 | if (result) { 111 | var studentId = $(this).parents().eq(1).attr('itemid'); 112 | deleteStudent(Number(studentId)); 113 | } 114 | }); 115 | $('#btnSubmit').click(function () { 116 | var studentId = $('form').attr('data-student-id'); 117 | if (studentId) { 118 | updateStudent(); 119 | } 120 | else { 121 | addStudent(); 122 | } 123 | }); 124 | } 125 | 126 | 127 | //This function refreshes the table 128 | async function refreshTableData() { 129 | try { 130 | var htmlString = ""; 131 | var students = await jsstoreCon.select({ 132 | from: 'Student' 133 | }); 134 | students.forEach(function (student) { 135 | htmlString += "" + 136 | student.name + "" + 137 | student.gender + "" + 138 | student.country + "" + 139 | student.city + "" + 140 | "Edit" + 141 | "Delete"; 142 | }) 143 | $('#tblGrid tbody').html(htmlString); 144 | } catch (ex) { 145 | alert(ex.message) 146 | } 147 | } 148 | 149 | 150 | 151 | async function addStudent() { 152 | var student = getStudentFromForm(); 153 | try { 154 | var noOfDataInserted = await jsstoreCon.insert({ 155 | into: 'Student', 156 | values: [student] 157 | }); 158 | if (noOfDataInserted === 1) { 159 | refreshTableData(); 160 | showGridAndHideForm(); 161 | } 162 | } catch (ex) { 163 | alert(ex.message); 164 | } 165 | 166 | } 167 | 168 | async function updateStudent() { 169 | var student = getStudentFromForm(); 170 | try { 171 | var noOfDataUpdated = await jsstoreCon.update({ 172 | in: 'Student', 173 | set: { 174 | name: student.name, 175 | gender: student.gender, 176 | country: student.country, 177 | city: student.city 178 | }, 179 | where: { 180 | id: student.id 181 | } 182 | }); 183 | console.log(`data updated ${noOfDataUpdated}`); 184 | showGridAndHideForm(); 185 | $('form').attr('data-student-id', null); 186 | refreshTableData(); 187 | refreshFormData({}); 188 | } catch (ex) { 189 | alert(ex.message); 190 | } 191 | } 192 | 193 | async function deleteStudent(id) { 194 | try { 195 | var noOfStudentRemoved = await jsstoreCon.remove({ 196 | from: 'Student', 197 | where: { 198 | id: id 199 | } 200 | }); 201 | console.log(`${noOfStudentRemoved} students removed`); 202 | refreshTableData(); 203 | } catch (ex) { 204 | alert(ex.message); 205 | } 206 | } 207 | 208 | function getStudentFromForm() { 209 | var student = { 210 | id: Number($('form').attr('data-student-id')), 211 | name: $('#txtName').val(), 212 | gender: $("input[name='gender']:checked").val(), 213 | country: $('#txtCountry').val(), 214 | city: $('#txtCity').val() 215 | }; 216 | return student; 217 | } 218 | 219 | function showFormAndHideGrid() { 220 | $('#formAddUpdate').show(); 221 | $('#tblGrid').hide(); 222 | } 223 | 224 | function showGridAndHideForm() { 225 | $('#formAddUpdate').hide(); 226 | $('#tblGrid').show(); 227 | } 228 | 229 | function refreshFormData(student) { 230 | $('form').attr('data-student-id', student.id); 231 | $('#txtName').val(student.name); 232 | $(`input[name='gender'][value=${student.gender}]`).prop('checked', true); 233 | $('#txtCountry').val(student.country); 234 | $('#txtCity').val(student.city); 235 | } 236 | 237 | 238 | 239 | function changeToV2() { 240 | const db = getDbSchema(); 241 | db.version = 2; 242 | initDb(db); 243 | } 244 | -------------------------------------------------------------------------------- /change-db-schema/style/main.css: -------------------------------------------------------------------------------- 1 | #tblGrid { 2 | margin-top: 20px; 3 | } 4 | 5 | #tblGrid tr th, 6 | table tr td { 7 | border: 1px solid black; 8 | padding: 5px 0px 5px 0px; 9 | text-align: center; 10 | } 11 | 12 | .row-centered { 13 | text-align: center; 14 | } 15 | 16 | .col-centered { 17 | display: inline-block; 18 | float: none; 19 | /* reset the text-align */ 20 | text-align: left; 21 | /* inline-block space fix */ 22 | margin-right: -4px; 23 | } -------------------------------------------------------------------------------- /electron/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /electron/LICENSE.md: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | ================== 3 | 4 | Statement of Purpose 5 | --------------------- 6 | 7 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). 8 | 9 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. 10 | 11 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 12 | 13 | 1. Copyright and Related Rights. 14 | -------------------------------- 15 | A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 16 | 17 | i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; 18 | ii. moral rights retained by the original author(s) and/or performer(s); 19 | iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; 20 | iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; 21 | v. rights protecting the extraction, dissemination, use and reuse of data in a Work; 22 | vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and 23 | vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 24 | 25 | 2. Waiver. 26 | ----------- 27 | To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 28 | 29 | 3. Public License Fallback. 30 | ---------------------------- 31 | Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 32 | 33 | 4. Limitations and Disclaimers. 34 | -------------------------------- 35 | 36 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. 37 | b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. 38 | c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. 39 | d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. 40 | -------------------------------------------------------------------------------- /electron/README.md: -------------------------------------------------------------------------------- 1 | # electron-quick-start 2 | 3 | **Clone and run for a quick way to see Electron in action.** 4 | 5 | This is a minimal Electron application based on the [Quick Start Guide](https://electronjs.org/docs/tutorial/quick-start) within the Electron documentation. 6 | 7 | **Use this app along with the [Electron API Demos](https://electronjs.org/#get-started) app for API code examples to help you get started.** 8 | 9 | A basic Electron application needs just these files: 10 | 11 | - `package.json` - Points to the app's main file and lists its details and dependencies. 12 | - `main.js` - Starts the app and creates a browser window to render HTML. This is the app's **main process**. 13 | - `index.html` - A web page to render. This is the app's **renderer process**. 14 | 15 | You can learn more about each of these components within the [Quick Start Guide](https://electronjs.org/docs/tutorial/quick-start). 16 | 17 | ## To Use 18 | 19 | To clone and run this repository you'll need [Git](https://git-scm.com) and [Node.js](https://nodejs.org/en/download/) (which comes with [npm](http://npmjs.com)) installed on your computer. From your command line: 20 | 21 | ```bash 22 | # Clone this repository 23 | git clone https://github.com/electron/electron-quick-start 24 | # Go into the repository 25 | cd electron-quick-start 26 | # Install dependencies 27 | npm install 28 | # Run the app 29 | npm start 30 | ``` 31 | 32 | Note: If you're using Linux Bash for Windows, [see this guide](https://www.howtogeek.com/261575/how-to-run-graphical-linux-desktop-applications-from-windows-10s-bash-shell/) or use `node` from the command prompt. 33 | 34 | ## Resources for Learning Electron 35 | 36 | - [electronjs.org/docs](https://electronjs.org/docs) - all of Electron's documentation 37 | - [electronjs.org/community#boilerplates](https://electronjs.org/community#boilerplates) - sample starter apps created by the community 38 | - [electron/electron-quick-start](https://github.com/electron/electron-quick-start) - a very basic starter Electron app 39 | - [electron/simple-samples](https://github.com/electron/simple-samples) - small applications with ideas for taking them further 40 | - [electron/electron-api-demos](https://github.com/electron/electron-api-demos) - an Electron app that teaches you how to use Electron 41 | - [hokein/electron-sample-apps](https://github.com/hokein/electron-sample-apps) - small demo apps for the various Electron APIs 42 | 43 | ## License 44 | 45 | [CC0 1.0 (Public Domain)](LICENSE.md) 46 | -------------------------------------------------------------------------------- /electron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-quick-start", 3 | "version": "1.0.0", 4 | "description": "A minimal Electron application", 5 | "main": "dist/scripts/app.js", 6 | "scripts": { 7 | "start": "webpack && electron .", 8 | "dev": "npm run start", 9 | "build": "webpack" 10 | }, 11 | "repository": "https://github.com/electron/electron-quick-start", 12 | "keywords": [ 13 | "Electron", 14 | "quick", 15 | "start", 16 | "tutorial", 17 | "demo" 18 | ], 19 | "author": "GitHub", 20 | "license": "CC0-1.0", 21 | "dependencies": { 22 | "jquery": "^3.3.1", 23 | "jsstore": "^4.0.0" 24 | }, 25 | "devDependencies": { 26 | "copy-webpack-plugin": "^4.5.1", 27 | "electron": "^2.0.0", 28 | "file-loader": "^6.2.0", 29 | "html-webpack-plugin": "^3.2.0", 30 | "webpack": "^4.8.1", 31 | "webpack-cli": "^2.1.3" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /electron/src/app/component/student_grid.js: -------------------------------------------------------------------------------- 1 | import { StudentService } from "../storage_service/student_service"; 2 | import * as $ from "jquery"; 3 | 4 | export class StudentGrid { 5 | 6 | constructor() { 7 | this.studentService = new StudentService(); 8 | } 9 | 10 | getHtml() { 11 | return ` 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
NameGenderCountryCity
` 33 | } 34 | 35 | async init() { 36 | var html = ''; 37 | try { 38 | const students = await this.studentService.getStudents(); 39 | students.forEach((student) => { 40 | html += this.getRowHtml(student); 41 | }) 42 | $('table tbody').html(html); 43 | this.catchEvents(); 44 | } catch (err) { 45 | alert(err.message); 46 | console.error(err); 47 | } 48 | 49 | } 50 | 51 | getRowHtml(student) { 52 | const html = ` 53 | ${student.name} 54 | ${student.gender} 55 | ${student.country} 56 | ${student.city} 57 | 58 | 59 | `; 60 | return html; 61 | } 62 | 63 | clearAddRowTextBoxValue() { 64 | $('table thead tr td input').val(''); 65 | } 66 | 67 | async addStudentIntoDb(student) { 68 | try { 69 | const addedStudents = await this.studentService.addStudent(student); 70 | if (addedStudents.length > 0) { 71 | this.clearAddRowTextBoxValue(); 72 | $('table tbody').append(this.getRowHtml(addedStudents[0])); 73 | } 74 | } catch (err) { 75 | alert(err.message); 76 | } 77 | } 78 | 79 | catchEvents() { 80 | $('#btnAdd').click(() => { 81 | const addRow = $('table thead tr')[1]; 82 | const student = { 83 | name: $(addRow.cells[0]).find('input').val(), 84 | gender: $(addRow.cells[1]).find('input').val(), 85 | country: $(addRow.cells[2]).find('input').val(), 86 | city: $(addRow.cells[3]).find('input').val() 87 | } 88 | this.addStudentIntoDb(student); 89 | }); 90 | 91 | $('#btnClear').click(() => { 92 | this.clearAddRowTextBoxValue(); 93 | }); 94 | 95 | $('body').on('click', 'table .btn-delete', async (el) => { 96 | var row = $(el.target).parents('tr'); 97 | var studentId = Number(row.data('id')); 98 | 99 | try { 100 | const noOfRowsDeleted = await this.studentService.removeStudent(studentId); 101 | if (noOfRowsDeleted > 0) { 102 | row.remove(); 103 | } 104 | } catch (err) { 105 | alert(err.message); 106 | } 107 | }); 108 | 109 | 110 | $('body').on('click', 'table .btn-edit', (el) => { 111 | var row = $(el.target).parents('tr'); 112 | row.find('td').each(function () { 113 | var $el = $(this); 114 | if ($el.find('button').length === 0) { 115 | $el.html(``); 116 | } 117 | }); 118 | row.find('td:eq(4)').html(''); 119 | row.find('td:eq(5)').html(''); 120 | }); 121 | 122 | $('body').on('click', 'table .btn-cancel-update', async (el) => { 123 | var row = $(el.target).parents('tr'); 124 | try { 125 | const students = await this.studentService.getStudentById(Number(row.data('id'))); 126 | if (students.length > 0) { 127 | const student = students[0]; 128 | row.find('td:eq(0)').html(student.name); 129 | row.find('td:eq(1)').html(student.gender); 130 | row.find('td:eq(2)').html(student.country); 131 | row.find('td:eq(3)').html(student.city); 132 | } 133 | row.find('td:eq(4)').html(''); 134 | row.find('td:eq(5)').html(''); 135 | } catch (err) { 136 | alert(err.message); 137 | } 138 | }); 139 | 140 | $('body').on('click', 'table .btn-update', async (el) => { 141 | var row = $(el.target).parents('tr'); 142 | var student = { 143 | name: row.find('td:eq(0) input').val(), 144 | gender: row.find('td:eq(1) input').val(), 145 | country: row.find('td:eq(2) input').val(), 146 | city: row.find('td:eq(3) input').val() 147 | }; 148 | 149 | var studentId = Number(row.data('id')); 150 | try { 151 | const noOfRowsUpdated = await this.studentService.updateStudentById(studentId, student); 152 | if (noOfRowsUpdated > 0) { 153 | row.find('td').each(function (index) { 154 | var $el = $(this); 155 | if ($el.find('button').length === 0) { 156 | $el.html(row.find(`td:eq(${index}) input`).val()); 157 | } 158 | }); 159 | row.find('td:eq(4)').html(''); 160 | row.find('td:eq(5)').html(''); 161 | } 162 | } catch (err) { 163 | alert(err.message); 164 | } 165 | 166 | }) 167 | } 168 | 169 | } -------------------------------------------------------------------------------- /electron/src/app/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | StudentGrid 3 | } from "./component/student_grid"; 4 | import { initJsStore } from "./storage_service/idb_service"; 5 | 6 | initJsStore(); 7 | var componentStudentGrid = new StudentGrid(); 8 | document.getElementById('app').innerHTML = componentStudentGrid.getHtml(); 9 | componentStudentGrid.init(); -------------------------------------------------------------------------------- /electron/src/app/storage_service/base_service.js: -------------------------------------------------------------------------------- 1 | import { idbCon } from "./idb_service"; 2 | export class BaseService { 3 | 4 | get connection() { 5 | return idbCon; 6 | } 7 | 8 | } -------------------------------------------------------------------------------- /electron/src/app/storage_service/idb_service.js: -------------------------------------------------------------------------------- 1 | import { DATA_TYPE, Connection } from 'jsstore'; 2 | 3 | const getWorkerPath = () => { 4 | if (process.env.NODE_ENV === 'development') { 5 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.js"); 6 | } 7 | else { 8 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js"); 9 | } 10 | }; 11 | 12 | // This will ensure that we are using only one instance. 13 | // Otherwise due to multiple instance multiple worker will be created. 14 | const workerPath = getWorkerPath().default; 15 | export const idbCon = new Connection(new Worker(workerPath)); 16 | export const dbname = 'Demo'; 17 | 18 | const getDatabase = () => { 19 | const tblStudent = { 20 | name: 'Students', 21 | columns: { 22 | id: { 23 | primaryKey: true, 24 | autoIncrement: true 25 | }, 26 | name: { 27 | notNull: true, 28 | dataType: DATA_TYPE.String 29 | }, 30 | gender: { 31 | dataType: DATA_TYPE.String, 32 | default: 'male' 33 | }, 34 | country: { 35 | notNull: true, 36 | dataType: DATA_TYPE.String 37 | }, 38 | city: { 39 | dataType: DATA_TYPE.String, 40 | notNull: true 41 | } 42 | } 43 | }; 44 | const dataBase = { 45 | name: dbname, 46 | tables: [tblStudent] 47 | }; 48 | return dataBase; 49 | }; 50 | 51 | export const initJsStore = async () => { 52 | try { 53 | const dataBase = getDatabase(); 54 | await idbCon.initDb(dataBase); 55 | } 56 | catch (ex) { 57 | alert(ex.message); 58 | console.error(ex); 59 | } 60 | }; -------------------------------------------------------------------------------- /electron/src/app/storage_service/student_service.js: -------------------------------------------------------------------------------- 1 | import { BaseService } from "./base_service"; 2 | 3 | export class StudentService extends BaseService { 4 | 5 | constructor() { 6 | super(); 7 | this.tableName = "Students"; 8 | } 9 | 10 | getStudents() { 11 | return this.connection.select({ 12 | from: this.tableName, 13 | }) 14 | } 15 | 16 | addStudent(student) { 17 | return this.connection.insert({ 18 | into: this.tableName, 19 | values: [student], 20 | return: true 21 | }) 22 | } 23 | 24 | getStudentById(id) { 25 | return this.connection.select({ 26 | from: this.tableName, 27 | where: { 28 | id: id 29 | } 30 | }) 31 | } 32 | 33 | removeStudent(id) { 34 | return this.connection.remove({ 35 | from: this.tableName, 36 | where: { 37 | id: id 38 | } 39 | }) 40 | } 41 | 42 | updateStudentById(id, updateData) { 43 | return this.connection.update({ 44 | in: this.tableName, 45 | set: updateData, 46 | where: { 47 | id: id 48 | } 49 | }) 50 | } 51 | } -------------------------------------------------------------------------------- /electron/src/electron/electron_app.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron'); 2 | const path = require('path') 3 | const url = require('url'); 4 | 5 | export class ElectronApp { 6 | constructor() { 7 | this.app_ = null; 8 | this.mainWindow_ = null; 9 | } 10 | 11 | init() { 12 | this.app_ = electron.app; 13 | // This method will be called when Electron has finished 14 | // initialization and is ready to create browser windows. 15 | // Some APIs can only be used after this event occurs. 16 | this.app_.on('ready', this.createWindow_) 17 | 18 | // Quit when all windows are closed. 19 | this.app_.on('window-all-closed', () => { 20 | // On OS X it is common for applications and their menu bar 21 | // to stay active until the user quits explicitly with Cmd + Q 22 | if (process.platform !== 'darwin') { 23 | this.app_.quit() 24 | } 25 | }) 26 | 27 | this.app_.on('activate', () => { 28 | // On OS X it's common to re-create a window in the app when the 29 | // dock icon is clicked and there are no other windows open. 30 | if (this.mainWindow_ === null) { 31 | this.createWindow_() 32 | } 33 | }) 34 | 35 | } 36 | 37 | createWindow_() { 38 | this.mainWindow_ = new electron.BrowserWindow({ 39 | fullscreen: true 40 | }); 41 | this.mainWindow_.loadURL(url.format({ 42 | pathname: path.join(__dirname, '../index.html'), 43 | protocol: 'file:' 44 | 45 | })) 46 | 47 | // Open the DevTools. 48 | // this.mainWindow_.webContents.openDevTools() 49 | 50 | // Emitted when the window is closed. 51 | this.mainWindow_.on('closed', () => { 52 | // Dereference the window object, usually you would store windows 53 | // in an array if your app supports multi windows, this is the time 54 | // when you should delete the corresponding element. 55 | this.mainWindow_ = null 56 | }) 57 | } 58 | } -------------------------------------------------------------------------------- /electron/src/electron/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | ElectronApp 3 | } from "./electron_app"; 4 | 5 | const app = new ElectronApp(); 6 | app.init(); -------------------------------------------------------------------------------- /electron/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JsStore Demo 7 | 8 | 9 | 10 |

Welcome to jsstore demo for electron

11 |
12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /electron/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = [{ 5 | entry: './src/electron/index.js', 6 | devtool: 'inline-source-map', 7 | module: { 8 | rules: [] 9 | }, 10 | resolve: { 11 | extensions: ['.js'] 12 | }, 13 | output: { 14 | filename: 'scripts/app.js', 15 | path: path.resolve(__dirname, 'dist/') 16 | }, 17 | mode: "development", 18 | target: 'electron-renderer', 19 | node: { 20 | __dirname: false, 21 | __filename: false 22 | } 23 | }, { 24 | entry: './src/app/index.js', 25 | devtool: 'inline-source-map', 26 | module: { 27 | rules: [] 28 | }, 29 | resolve: { 30 | extensions: ['.js'] 31 | }, 32 | output: { 33 | filename: 'scripts/renderer.js', 34 | path: path.resolve(__dirname, 'dist/') 35 | }, 36 | plugins: [ 37 | new HtmlWebpackPlugin({ 38 | template: 'src/index.html' 39 | }) 40 | ], 41 | mode: "development" 42 | }]; -------------------------------------------------------------------------------- /mahal/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "6.10" 8 | } 9 | } 10 | ] 11 | ], 12 | "plugins": [ 13 | [ 14 | "@babel/plugin-proposal-decorators", 15 | { 16 | "legacy": true 17 | } 18 | ], 19 | "babel-plugin-parameter-decorator-custom" 20 | ] 21 | } -------------------------------------------------------------------------------- /mahal/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bin 3 | dist 4 | build 5 | logs -------------------------------------------------------------------------------- /mahal/assets/img/mahal-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/mahal/assets/img/mahal-logo.png -------------------------------------------------------------------------------- /mahal/config/env/development.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apiUrl: "/" 3 | } -------------------------------------------------------------------------------- /mahal/config/env/index.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV == 'production') { 2 | module.exports = require('./production.js'); 3 | } 4 | else { 5 | module.exports = require('./development.js'); 6 | } -------------------------------------------------------------------------------- /mahal/config/env/production.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apiUrl: "/" 3 | } -------------------------------------------------------------------------------- /mahal/config/lang/mahal.config.ts: -------------------------------------------------------------------------------- 1 | declare module "*.mahal" { 2 | // import Vue from "vue"; 3 | // export default Vue; 4 | const value: any; // Add better type definitions here if desired. 5 | export default value; 6 | } -------------------------------------------------------------------------------- /mahal/config/webpack/base.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const MahalPlugin = require('mahal-webpack-loader/lib/plugin'); 3 | const HtmlWebPackPlugin = require('html-webpack-plugin'); 4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 5 | const CopyPlugin = require('copy-webpack-plugin'); 6 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 7 | const webpack = require('webpack'); 8 | 9 | const rootFolder = path.join(__dirname, '../../'); 10 | 11 | const isEnvProduction = process.env.NODE_ENV === "production" 12 | 13 | module.exports = { 14 | entry: './src/index.js', 15 | devtool: 'source-map', 16 | mode: process.env.NODE_ENV || "development", 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.mahal?$/, 21 | // loader: 'mahal-webpack-loader', 22 | use: { 23 | loader: require.resolve('mahal-webpack-loader') 24 | }, 25 | exclude: /node_modules/ 26 | }, 27 | { 28 | test: /\.js|.jsx?$/, 29 | exclude: /(node_modules|bower_components)/, 30 | use: { 31 | loader: 'babel-loader' 32 | } 33 | }, 34 | { 35 | test: /\.css?$/, 36 | use: [ 37 | { 38 | loader: MiniCssExtractPlugin.loader, 39 | options: { 40 | esModule: false, 41 | }, 42 | }, 43 | 'css-loader' 44 | ], 45 | }, 46 | { 47 | test: /\.s[ac]ss$/i, 48 | use: [ 49 | // Creates `style` nodes from JS strings 50 | // "style-loader", 51 | { 52 | loader: MiniCssExtractPlugin.loader, 53 | options: { 54 | esModule: false, 55 | }, 56 | }, 57 | // Translates CSS into CommonJS 58 | "css-loader", 59 | // Compiles Sass to CSS 60 | "sass-loader", 61 | ], 62 | }, 63 | // Images 64 | { 65 | test: /\.(?:ico|gif|png|jpg|jpeg)$/i, 66 | type: 'asset/resource', 67 | }, 68 | // Fonts and SVGs 69 | { 70 | test: /\.(woff(2)?|eot|ttf|otf|svg|)$/, 71 | type: 'asset/inline', 72 | }, 73 | ] 74 | }, 75 | resolve: { 76 | extensions: ['.ts', '.js', '.css', '.mahal', '.scss'], 77 | alias: { 78 | "~": rootFolder, 79 | "@": path.join(rootFolder, 'src'), 80 | "@config": path.join(rootFolder, 'config'), 81 | "@components": path.join(rootFolder, 'src', 'components'), 82 | process: "process/browser" 83 | }, 84 | }, 85 | output: { 86 | filename: isEnvProduction ? 'js/[name].[contenthash:8].js' : 'js/[name].js', 87 | chunkFilename: isEnvProduction ? 'js/[name].[contenthash:8].chunk.js' : 'js/[name].chunk.js', 88 | path: path.resolve(rootFolder, 'dist'), 89 | publicPath: '/' 90 | }, 91 | plugins: [ 92 | new MahalPlugin({ 93 | lang: 'js' 94 | }), 95 | new HtmlWebPackPlugin({ 96 | cache: true, 97 | hash: true, 98 | template: 'src/index.html', 99 | minify: { 100 | collapseWhitespace: true, 101 | removeComments: true, 102 | removeRedundantAttributes: true, 103 | removeScriptTypeAttributes: true, 104 | removeStyleLinkTypeAttributes: true 105 | } 106 | }), 107 | new CleanWebpackPlugin(), 108 | new CopyPlugin({ 109 | patterns: [{ 110 | from: './assets/', 111 | to: '' 112 | }] 113 | }), 114 | new MiniCssExtractPlugin({ 115 | filename: isEnvProduction ? 'css/[name].[contenthash:8].css' : 'css/[name].css', 116 | chunkFilename: isEnvProduction ? 'css/[name].[contenthash:8].chunk.css' : 'css/[name].chunk.css', 117 | }), 118 | 119 | ] 120 | }; -------------------------------------------------------------------------------- /mahal/config/webpack/dev.config.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const path = require('path'); 3 | const baseConfig = require('./base.config'); 4 | 5 | module.exports = merge(baseConfig, { 6 | devServer: { 7 | historyApiFallback: true, 8 | }, 9 | }); -------------------------------------------------------------------------------- /mahal/config/webpack/prod.config.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge') 2 | const baseConfig = require('./base.config') 3 | const CssMinimizerPlugin = require('css-minimizer-webpack-plugin'); 4 | 5 | const prod = merge(baseConfig, { 6 | mode: 'production', 7 | devtool: false, 8 | output: { 9 | publicPath: '/', 10 | filename: 'js/[name].[contenthash].bundle.js', 11 | }, 12 | optimization: { 13 | minimize: true, 14 | minimizer: [`...`, new CssMinimizerPlugin()], 15 | runtimeChunk: { 16 | name: 'runtime', 17 | }, 18 | splitChunks: { 19 | chunks: 'all', 20 | maxInitialRequests: Infinity, 21 | minSize: 100000, 22 | maxSize: 1000000, 23 | cacheGroups: { 24 | vendor: { 25 | test: /[\\/]node_modules[\\/]/, 26 | name(module) { 27 | // get the name. E.g. node_modules/packageName/not/this/part.js 28 | // or node_modules/packageName 29 | const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]; 30 | // console.log('package', packageName); 31 | // npm package names are URL-safe, but some servers don't like @ symbols 32 | return `npm.${packageName.replace('@', '')}`; 33 | }, 34 | }, 35 | }, 36 | }, 37 | }, 38 | performance: { 39 | hints: false, 40 | maxEntrypointSize: 512000, 41 | maxAssetSize: 512000, 42 | }, 43 | }) 44 | 45 | module.exports = prod; -------------------------------------------------------------------------------- /mahal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mahal-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack serve --open --config config/webpack/dev.config.js", 8 | "deploy": "cross-env NODE_ENV=production webpack --config config/webpack/prod.config.js", 9 | "build": "cross-env NODE_ENV=development webpack --config config/webpack/dev.config.js" 10 | }, 11 | "author": "", 12 | "license": "", 13 | "private": "true", 14 | "dependencies": { 15 | "jsstore": "^4.5.2", 16 | "mahal": "^1.4.1" 17 | }, 18 | "devDependencies": { 19 | "@babel/core": "^7.11.0", 20 | "@babel/plugin-proposal-decorators": "^7.10.5", 21 | "@babel/preset-env": "^7.11.0", 22 | "babel-loader": "^8.2.3", 23 | "babel-plugin-parameter-decorator-custom": "^1.0.0", 24 | "clean-webpack-plugin": "^4.0.0", 25 | "copy-webpack-plugin": "^10.2.4", 26 | "cross-env": "^7.0.3", 27 | "css-loader": "^6.5.1", 28 | "css-minimizer-webpack-plugin": "^3.4.1", 29 | "file-loader": "^6.2.0", 30 | "html-webpack-plugin": "^5.2.0", 31 | "mahal-webpack-loader": "^1.4.1", 32 | "mini-css-extract-plugin": "^2.5.3", 33 | "sass": "^1.49.0", 34 | "sass-loader": "^12.4.0", 35 | "style-loader": "^3.3.1", 36 | "ts-loader": "^9.2.6", 37 | "typescript": "^4.5.5", 38 | "webpack": "^5.67.0", 39 | "webpack-cli": "^4.9.2", 40 | "webpack-dev-server": "^4.7.3", 41 | "webpack-merge": "^5.8.0" 42 | }, 43 | "project": { 44 | "framework": "mahal", 45 | "language": "js" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /mahal/readme.md: -------------------------------------------------------------------------------- 1 | # mahal-app 2 | 3 | This app is generated using `mahal-creator`. 4 | 5 | # How to start 6 | 7 | 1. Install node modules by runing command - `npm ci` 8 | 2. Run dev server by runing command - `npm run dev` 9 | 10 | # Commands 11 | 12 | * `npm run dev` - start development server 13 | * `npm run build` - create build for development 14 | * `npm run deploy` - create build for production -------------------------------------------------------------------------------- /mahal/src/app.mahal: -------------------------------------------------------------------------------- 1 | --- 2 | name: app.mahal 3 | description: This component is the main parent component which is used to initiate the app. 4 | dateCreated: 5 | --- 6 | 7 | 8 | 9 | 10 | 11 | 22 | 23 | 25 | -------------------------------------------------------------------------------- /mahal/src/components/student.mahal: -------------------------------------------------------------------------------- 1 | --- 2 | name: student.mahal 3 | description: 4 | dateCreated: March 26, 2022 5 | --- 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | 40 | 41 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 56 | 59 | 60 | 61 | 62 |
NameGenderCountryCity
26 | 27 | 29 | 30 |
36 | {{student.name}} 37 | {{student.gender}}{{student.country}}{{student.city}} 42 | 43 | 45 | 46 |
54 | 55 | 57 | 58 |
63 | 64 | 65 | 170 | 171 | 173 | -------------------------------------------------------------------------------- /mahal/src/formatters/img_path.js: -------------------------------------------------------------------------------- 1 | export function imgPath(src) { 2 | return "/img/" + src; 3 | } -------------------------------------------------------------------------------- /mahal/src/formatters/index.js: -------------------------------------------------------------------------------- 1 | import { imgPath } from "./img_path"; 2 | 3 | export function registerGlobalFormatter(app) { 4 | app.extend.formatter("imgPath", imgPath); 5 | } -------------------------------------------------------------------------------- /mahal/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /mahal/src/index.js: -------------------------------------------------------------------------------- 1 | import { Mahal } from "mahal"; 2 | import App from "@/app.mahal"; 3 | import { registerGlobalFormatter } from "@/formatters"; 4 | import config from "~/config/env"; 5 | import { initJsStore } from "@/storage_service/idb_service"; 6 | 7 | 8 | const app = new Mahal(App, '#app'); 9 | // register global formatter 10 | registerGlobalFormatter(app); 11 | // set config to be available globally 12 | app.global.env = config; 13 | app.create().then(_ => { 14 | initJsStore(); 15 | }); -------------------------------------------------------------------------------- /mahal/src/storage_service/base_service.js: -------------------------------------------------------------------------------- 1 | import { 2 | idbCon 3 | } from "./idb_service"; 4 | export class BaseService { 5 | 6 | get connection() { 7 | return idbCon; 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /mahal/src/storage_service/idb_service.js: -------------------------------------------------------------------------------- 1 | import { DATA_TYPE, Connection } from 'jsstore'; 2 | 3 | const getWorkerPath = () => { 4 | if (process.env.NODE_ENV === 'development') { 5 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.js"); 6 | } 7 | else { 8 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js"); 9 | } 10 | }; 11 | 12 | // This will ensure that we are using only one instance. 13 | // Otherwise due to multiple instance multiple worker will be created. 14 | const workerPath = getWorkerPath().default; 15 | export const idbCon = new Connection(new Worker(workerPath)); 16 | export const dbname = 'Demo'; 17 | 18 | const getDatabase = () => { 19 | const tblStudent = { 20 | name: 'Students', 21 | columns: { 22 | id: { 23 | primaryKey: true, 24 | autoIncrement: true 25 | }, 26 | name: { 27 | notNull: true, 28 | dataType: DATA_TYPE.String 29 | }, 30 | gender: { 31 | dataType: DATA_TYPE.String, 32 | default: 'male' 33 | }, 34 | country: { 35 | notNull: true, 36 | dataType: DATA_TYPE.String 37 | }, 38 | city: { 39 | dataType: DATA_TYPE.String, 40 | notNull: true 41 | } 42 | } 43 | }; 44 | const dataBase = { 45 | name: dbname, 46 | tables: [tblStudent] 47 | }; 48 | return dataBase; 49 | }; 50 | 51 | export const initJsStore = () => { 52 | try { 53 | const dataBase = getDatabase(); 54 | return idbCon.initDb(dataBase); 55 | } 56 | catch (ex) { 57 | console.error(ex); 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /mahal/src/storage_service/student_service.js: -------------------------------------------------------------------------------- 1 | import { 2 | BaseService 3 | } from "./base_service"; 4 | 5 | export class StudentService extends BaseService { 6 | 7 | constructor() { 8 | super(); 9 | this.tableName = "Students"; 10 | } 11 | 12 | getStudents() { 13 | return this.connection.select({ 14 | from: this.tableName, 15 | }) 16 | } 17 | 18 | addStudent(student) { 19 | return this.connection.insert({ 20 | into: this.tableName, 21 | values: [student], 22 | return: true // since studentid is autoincrement field and we need id, 23 | // so we are making return true which will return the whole data inserted. 24 | }) 25 | } 26 | 27 | getStudentById(id) { 28 | return this.connection.select({ 29 | from: this.tableName, 30 | where: { 31 | id: id 32 | } 33 | }) 34 | } 35 | 36 | removeStudent(id) { 37 | return this.connection.remove({ 38 | from: this.tableName, 39 | where: { 40 | id: id 41 | } 42 | }) 43 | } 44 | 45 | updateStudentById(id, updateData) { 46 | return this.connection.update({ in: this.tableName, 47 | set: updateData, 48 | where: { 49 | id: id 50 | } 51 | }) 52 | } 53 | } -------------------------------------------------------------------------------- /mahal/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "", 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "es6", 9 | "dom" 10 | ], 11 | "mapRoot": "./", 12 | "module": "es6", 13 | "outDir": "bin/ts", 14 | "sourceMap": true, 15 | "target": "es6", 16 | "moduleResolution": "node", 17 | "paths": { 18 | "~/*": [ 19 | "./*" 20 | ], 21 | "@/*": [ 22 | "./src/*" 23 | ], 24 | "@components/*": [ 25 | "./src/components/*" 26 | ], 27 | "@config/*": [ 28 | "./config/*" 29 | ] 30 | }, 31 | "checkJs": false, 32 | } 33 | } -------------------------------------------------------------------------------- /react/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["@babel/preset-env", { 4 | "targets": { 5 | "browsers": [ 6 | ">0.25%", 7 | "not ie 11", 8 | "not op_mini all" 9 | ] 10 | } 11 | }], "@babel/preset-react", 12 | ] 13 | } -------------------------------------------------------------------------------- /react/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | build -------------------------------------------------------------------------------- /react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react_crud", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "webpack-dev-server --content-base src --inline --hot", 8 | "start": "npm run dev", 9 | "build:details": "webpack --display-error-details", 10 | "build": "webpack", 11 | "test": "echo \"Error: no test specified\" && exit 1" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "dependencies": { 16 | "jsstore": "^4.0.0", 17 | "react": "^16.7.0", 18 | "react-dom": "^16.7.0" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.2.2", 22 | "@babel/polyfill": "^7.2.5", 23 | "@babel/preset-env": "^7.2.3", 24 | "@babel/preset-react": "^7.0.0", 25 | "babel-loader": "^8.0.5", 26 | "file-loader": "^6.2.0", 27 | "html-webpack-plugin": "^3.2.0", 28 | "webpack": "^4.41.3", 29 | "webpack-cli": "^3.3.10", 30 | "webpack-dev-server": "^3.9.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /react/readme.md: -------------------------------------------------------------------------------- 1 | ## React JsStore Demo 2 | 3 | This is an example project of using jsstore with react framework. 4 | 5 | # How to run 6 | 7 | 1. execute `npm install` - install all dependecies 8 | 2. execute `npm run dev` - run the dev server 9 | 3. browse url - `http://localhost:8080/` -------------------------------------------------------------------------------- /react/src/component/layout.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import StudentGrid from "./student_grid"; 3 | 4 | export default class Layout extends React.Component { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | render() { 10 | return ( 11 |
12 | 13 |
14 | ) 15 | } 16 | } -------------------------------------------------------------------------------- /react/src/component/student_grid.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { StudentService } from "../storage_service/student_service"; 3 | 4 | export default class StudentGrid extends React.Component { 5 | 6 | 7 | constructor() { 8 | super(); 9 | this.service = new StudentService(); 10 | this.state = { 11 | isEditing: false, 12 | editStudentId: 0, 13 | students: [] 14 | } 15 | } 16 | 17 | componentDidMount() { 18 | this.loadStudentsFromDb(); 19 | } 20 | 21 | async loadStudentsFromDb() { 22 | try { 23 | const students = await this.service.getStudents() 24 | this.setState({ students: students }) 25 | } 26 | catch (ex) { 27 | alert(ex.message); 28 | console.error(ex); 29 | } 30 | } 31 | 32 | async add() { 33 | var student = { 34 | name: this.refs.name.value, 35 | gender: this.refs.gender.value, 36 | country: this.refs.country.value, 37 | city: this.refs.city.value 38 | } 39 | // add student into indexeddb 40 | 41 | try { 42 | const students = await this.service.addStudent(student) 43 | this.state.students.push(students[0]); 44 | this.setState({ students: this.state.students }); 45 | this.clear(); 46 | } 47 | catch (ex) { 48 | alert(ex.message); 49 | console.error(ex); 50 | } 51 | 52 | } 53 | 54 | 55 | clear() { 56 | this.refs.name.value = ""; 57 | this.refs.gender.value = ""; 58 | this.refs.country.value = ""; 59 | this.refs.city.value = ""; 60 | } 61 | 62 | async editUpdate(el) { 63 | const row = el.target.parentElement.parentElement; 64 | const studentId = Number(row.dataset.id); 65 | if (this.state.isEditing) { 66 | const updateValue = { 67 | name: row.children[0].firstChild.value, 68 | gender: row.children[1].firstChild.value, 69 | country: row.children[2].firstChild.value, 70 | city: row.children[3].firstChild.value 71 | } 72 | // update student into indexeddb 73 | 74 | try { 75 | const rowsUpdated = await this.service.updateStudentById(studentId, updateValue); 76 | if (rowsUpdated > 0) { 77 | const index = this.state.students.findIndex(value => value.id === studentId); 78 | this.state.students[index] = { id: studentId, ...updateValue }; 79 | this.setState({ student: this.state.students, isEditing: false, editStudentId: 0 }); 80 | } 81 | 82 | } 83 | catch (ex) { 84 | alert(ex.message); 85 | console.error(ex); 86 | } 87 | } 88 | else { 89 | this.setState({ isEditing: true, editStudentId: studentId }); 90 | } 91 | } 92 | 93 | async delete(el) { 94 | const row = el.target.parentElement.parentElement; 95 | const studentId = Number(row.dataset.id); 96 | // delete student from indexeddb 97 | 98 | try { 99 | const rowsDeleted = await this.service.removeStudent(studentId); 100 | if (rowsDeleted > 0) { 101 | const index = this.state.students.findIndex(value => value.id === studentId); 102 | this.state.students.splice(index, 1); 103 | this.setState({ student: this.state.students }); 104 | alert("Row Deleted"); 105 | } 106 | 107 | } 108 | catch (ex) { 109 | alert(ex.message); 110 | console.error(ex); 111 | } 112 | } 113 | 114 | 115 | render() { 116 | const getCell = (value) => { 117 | return this.state.isEditing ? 118 | : 119 | { value } 120 | } 121 | 122 | const dataRows = this.state.students.map(student => { 123 | if (student.id === this.state.editStudentId) { 124 | return ( 125 | 126 | 127 | {getCell(student.name)} 128 | 129 | {getCell(student.gender)} 130 | {getCell(student.country)} 131 | {getCell(student.city)} 132 | 133 | 135 | 136 | 137 | 139 | 140 | 141 | ) 142 | } 143 | else { 144 | return ( 145 | 146 | {student.name} 147 | {student.gender} 148 | {student.country} 149 | {student.city} 150 | 151 | 152 | 154 | 155 | 156 | ) 157 | } 158 | }); 159 | const addRow = 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | return ( 172 |
173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | {addRow} 186 | {dataRows} 187 | 188 |
NameGenderCountryCity
189 |
190 | ) 191 | } 192 | } -------------------------------------------------------------------------------- /react/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | React crud Demo using JsStore 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /react/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { initJsStore } from "./storage_service/idb_service"; 4 | import Layout from "./component/layout"; 5 | const app = document.getElementById('app'); 6 | ReactDOM.render(, app); 7 | initJsStore(); -------------------------------------------------------------------------------- /react/src/model/student.js: -------------------------------------------------------------------------------- 1 | 2 | export class Student { 3 | id; 4 | name; 5 | gender; 6 | country; 7 | city; 8 | 9 | constructor(id, name, gender, country, city) { 10 | this.id = id == null ? 0 : id; 11 | this.name = name == null ? "" : name; 12 | this.gender = gender == null ? "" : gender; 13 | this.country = country == null ? "" : country; 14 | this.city = city == null ? "" : city; 15 | } 16 | } -------------------------------------------------------------------------------- /react/src/storage_service/base_service.js: -------------------------------------------------------------------------------- 1 | import { 2 | idbCon 3 | } from "./idb_service"; 4 | export class BaseService { 5 | 6 | get connection() { 7 | return idbCon; 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /react/src/storage_service/idb_service.js: -------------------------------------------------------------------------------- 1 | import { DATA_TYPE, Connection } from 'jsstore'; 2 | 3 | const getWorkerPath = () => { 4 | if (process.env.NODE_ENV === 'development') { 5 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.js"); 6 | } 7 | else { 8 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js"); 9 | } 10 | }; 11 | 12 | // This will ensure that we are using only one instance. 13 | // Otherwise due to multiple instance multiple worker will be created. 14 | const workerPath = getWorkerPath().default; 15 | export const idbCon = new Connection(new Worker(workerPath)); 16 | export const dbname = 'Demo'; 17 | 18 | const getDatabase = () => { 19 | const tblStudent = { 20 | name: 'Students', 21 | columns: { 22 | id: { 23 | primaryKey: true, 24 | autoIncrement: true 25 | }, 26 | name: { 27 | notNull: true, 28 | dataType: DATA_TYPE.String 29 | }, 30 | gender: { 31 | dataType: DATA_TYPE.String, 32 | default: 'male' 33 | }, 34 | country: { 35 | notNull: true, 36 | dataType: DATA_TYPE.String 37 | }, 38 | city: { 39 | dataType: DATA_TYPE.String, 40 | notNull: true 41 | } 42 | } 43 | }; 44 | const dataBase = { 45 | name: dbname, 46 | tables: [tblStudent] 47 | }; 48 | return dataBase; 49 | }; 50 | 51 | export const initJsStore = () => { 52 | try { 53 | const dataBase = getDatabase(); 54 | idbCon.initDb(dataBase); 55 | } 56 | catch (ex) { 57 | console.error(ex); 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /react/src/storage_service/student_service.js: -------------------------------------------------------------------------------- 1 | import { 2 | BaseService 3 | } from "./base_service"; 4 | 5 | export class StudentService extends BaseService { 6 | 7 | constructor() { 8 | super(); 9 | this.tableName = "Students"; 10 | } 11 | 12 | getStudents() { 13 | return this.connection.select({ 14 | from: this.tableName, 15 | }) 16 | } 17 | 18 | addStudent(student) { 19 | return this.connection.insert({ 20 | into: this.tableName, 21 | values: [student], 22 | return: true // since studentid is autoincrement field and we need id, 23 | // so we are making return true which will return the whole data inserted. 24 | }) 25 | } 26 | 27 | getStudentById(id) { 28 | return this.connection.select({ 29 | from: this.tableName, 30 | where: { 31 | id: id 32 | } 33 | }) 34 | } 35 | 36 | removeStudent(id) { 37 | return this.connection.remove({ 38 | from: this.tableName, 39 | where: { 40 | id: id 41 | } 42 | }) 43 | } 44 | 45 | updateStudentById(id, updateData) { 46 | return this.connection.update({ in: this.tableName, 47 | set: updateData, 48 | where: { 49 | id: id 50 | } 51 | }) 52 | } 53 | } -------------------------------------------------------------------------------- /react/webpack.config.js: -------------------------------------------------------------------------------- 1 | var debug = process.env.NODE_ENV !== "production"; 2 | var webpack = require('webpack'); 3 | var path = require('path'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | 6 | 7 | module.exports = { 8 | devtool: "sourcemap", 9 | entry: ["@babel/polyfill", "./src/index.js"], 10 | module: { 11 | rules: [{ 12 | test: /\.js|.jsx?$/, 13 | exclude: /(node_modules|bower_components)/, 14 | use: { 15 | loader: 'babel-loader' 16 | } 17 | }] 18 | }, 19 | resolve: { 20 | extensions: ['.js', '.jsx'] // '' is needed to find modules like "jquery" 21 | }, 22 | output: { 23 | path: __dirname + "/dist/", 24 | filename: "build.min.js" 25 | }, 26 | plugins: [ 27 | new HtmlWebpackPlugin({ 28 | template: 'src/index.html' 29 | }) 30 | ] 31 | }; -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## JsStore Examples 2 | 3 | This project contains several examples for different framework and tools. 4 | 5 | ## Help 6 | 7 | Feel free to ask any questions on our [gitter](https://gitter.im/JsStore) channel. 8 | 9 | ## Contributions 10 | 11 | All contributions are welcome. -------------------------------------------------------------------------------- /service_worker/README.md: -------------------------------------------------------------------------------- 1 | This demo uses jsstore to access indexeddb. It is a very basic example. 2 | 3 | If you need help about service worker - See [Using Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers) -------------------------------------------------------------------------------- /service_worker/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Kittens!

11 | kitty1 12 | kitty2 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /service_worker/script.js: -------------------------------------------------------------------------------- 1 | 2 | if ('serviceWorker' in navigator) { 3 | navigator.serviceWorker.register(window.location.href + 'service-worker.js') 4 | .then(function() { 5 | console.log('sw registered'); 6 | }) 7 | .catch(function(e) { 8 | console.log('sw-error:', e); 9 | }); 10 | } else { 11 | console.error('this browser does not support service workers'); 12 | } 13 | 14 | fetch('https://placekitten.com/300/200').then(function(response) { 15 | if(response.ok) { 16 | response.blob().then(function(myBlob) { 17 | var objectURL = URL.createObjectURL(myBlob); 18 | var img = document.getElementById('myImage'); 19 | img.src = objectURL; 20 | }); 21 | } else { 22 | console.log('Network response was not ok.'); 23 | } 24 | }) 25 | .catch(function(error) { 26 | console.log('There has been a problem with your fetch operation: ' + error.message); 27 | }); -------------------------------------------------------------------------------- /service_worker/service-worker.js: -------------------------------------------------------------------------------- 1 | importScripts('https://cdn.jsdelivr.net/npm/jsstore@4.2.6/dist/jsstore.min.js'); 2 | importScripts('https://cdn.jsdelivr.net/npm/jsstore@4.2.6/dist/jsstore.worker.min.js'); 3 | 4 | self.addEventListener('fetch', function (event) { 5 | console.log("fetch event:", event.request.url); 6 | }); 7 | 8 | var dbName = "Demo"; 9 | 10 | async function initDb() { 11 | var connection = new JsStore.Connection(); 12 | var isDbCreated = await connection.initDb(getDbSchema()); 13 | if (isDbCreated) { 14 | console.log('db created'); 15 | } 16 | else { 17 | console.log('db opened'); 18 | } 19 | return connection; 20 | } 21 | 22 | function getDbSchema() { 23 | var table = { 24 | name: 'Student', 25 | columns: { 26 | id: { 27 | primaryKey: true, 28 | autoIncrement: true 29 | }, 30 | name: { 31 | notNull: true, 32 | dataType: 'string' 33 | }, 34 | gender: { 35 | dataType: 'string', 36 | default: 'male' 37 | }, 38 | country: { 39 | notNull: true, 40 | dataType: 'string' 41 | }, 42 | city: { 43 | dataType: 'string', 44 | notNull: true 45 | } 46 | } 47 | } 48 | 49 | var db = { 50 | name: dbName, 51 | tables: [table] 52 | } 53 | return db; 54 | } 55 | 56 | self.addEventListener('install', (event) => { 57 | event.waitUntil(initDb().then(function (connection) { 58 | return connection.terminate(); 59 | })); 60 | }); -------------------------------------------------------------------------------- /service_worker/style.css: -------------------------------------------------------------------------------- 1 | @import url(https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css); 2 | 3 | body { 4 | background: url(http://www.imagestowallpapers.com/wp-content/uploads/2015/12/CSS-Background-Image.jpg) no-repeat center center fixed; 5 | background-size: cover; 6 | } -------------------------------------------------------------------------------- /simple_example/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/simple_example/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /simple_example/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/simple_example/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /simple_example/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/simple_example/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /simple_example/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/simple_example/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /simple_example/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/simple_example/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /simple_example/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | JsStore Example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | 23 |
24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
27 | Student's Details
NameGenderCountryCity
40 | 81 |
82 |
83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /simple_example/readme.md: -------------------------------------------------------------------------------- 1 | ## JsStore 2 | 3 | This is a demo example for crud operation in indexeddb using jsstore. 4 | 5 | ## How to run 6 | 7 | Run this folder inside a http server otherwise you might see an error. -------------------------------------------------------------------------------- /simple_example/scripts/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var jsstoreCon = new JsStore.Connection(new Worker("scripts/jsstore.worker.js")); 4 | 5 | window.onload = function () { 6 | refreshTableData(); 7 | registerEvents(); 8 | initDb(); 9 | }; 10 | 11 | async function initDb() { 12 | var isDbCreated = await jsstoreCon.initDb(getDbSchema()); 13 | if (isDbCreated) { 14 | console.log('db created'); 15 | } 16 | else { 17 | console.log('db opened'); 18 | } 19 | } 20 | 21 | function getDbSchema() { 22 | var table = { 23 | name: 'Student', 24 | columns: { 25 | id: { 26 | primaryKey: true, 27 | autoIncrement: true 28 | }, 29 | name: { 30 | notNull: true, 31 | dataType: 'string' 32 | }, 33 | gender: { 34 | dataType: 'string', 35 | default: 'male' 36 | }, 37 | country: { 38 | notNull: true, 39 | dataType: 'string' 40 | }, 41 | city: { 42 | dataType: 'string', 43 | notNull: true 44 | } 45 | } 46 | } 47 | 48 | var db = { 49 | name: 'My-Db', 50 | tables: [table] 51 | } 52 | return db; 53 | } 54 | 55 | function registerEvents() { 56 | $('#btnAddStudent').click(function () { 57 | showFormAndHideGrid(); 58 | }) 59 | $('#tblGrid tbody').on('click', '.edit', function () { 60 | var row = $(this).parents().eq(1); 61 | var child = row.children(); 62 | var student = { 63 | id: row.attr('itemid'), 64 | name: child.eq(0).text(), 65 | gender: child.eq(1).text(), 66 | country: child.eq(2).text(), 67 | city: child.eq(3).text() 68 | } 69 | refreshFormData(student); 70 | showFormAndHideGrid(); 71 | }); 72 | $('#tblGrid tbody').on('click', '.delete', function () { 73 | var result = confirm('Are you sure, you want to delete?'); 74 | if (result) { 75 | var studentId = $(this).parents().eq(1).attr('itemid'); 76 | deleteStudent(Number(studentId)); 77 | } 78 | }); 79 | $('#btnSubmit').click(function () { 80 | var studentId = $('form').attr('data-student-id'); 81 | if (studentId) { 82 | updateStudent(); 83 | } 84 | else { 85 | addStudent(); 86 | } 87 | }); 88 | } 89 | 90 | 91 | //This function refreshes the table 92 | async function refreshTableData() { 93 | try { 94 | var htmlString = ""; 95 | var students = await jsstoreCon.select({ 96 | from: 'Student' 97 | }); 98 | students.forEach(function (student) { 99 | htmlString += "" + 100 | student.name + "" + 101 | student.gender + "" + 102 | student.country + "" + 103 | student.city + "" + 104 | "Edit" + 105 | "Delete"; 106 | }) 107 | $('#tblGrid tbody').html(htmlString); 108 | } catch (ex) { 109 | alert(ex.message) 110 | } 111 | } 112 | 113 | 114 | 115 | async function addStudent() { 116 | var student = getStudentFromForm(); 117 | try { 118 | var noOfDataInserted = await jsstoreCon.insert({ 119 | into: 'Student', 120 | values: [student] 121 | }); 122 | if (noOfDataInserted === 1) { 123 | refreshTableData(); 124 | showGridAndHideForm(); 125 | } 126 | } catch (ex) { 127 | alert(ex.message); 128 | } 129 | 130 | } 131 | 132 | async function updateStudent() { 133 | var student = getStudentFromForm(); 134 | try { 135 | var noOfDataUpdated = await jsstoreCon.update({ 136 | in: 'Student', 137 | set: { 138 | name: student.name, 139 | gender: student.gender, 140 | country: student.country, 141 | city: student.city 142 | }, 143 | where: { 144 | id: student.id 145 | } 146 | }); 147 | console.log(`data updated ${noOfDataUpdated}`); 148 | showGridAndHideForm(); 149 | $('form').attr('data-student-id', null); 150 | refreshTableData(); 151 | refreshFormData({}); 152 | } catch (ex) { 153 | alert(ex.message); 154 | } 155 | } 156 | 157 | async function deleteStudent(id) { 158 | try { 159 | var noOfStudentRemoved = await jsstoreCon.remove({ 160 | from: 'Student', 161 | where: { 162 | id: id 163 | } 164 | }); 165 | console.log(`${noOfStudentRemoved} students removed`); 166 | refreshTableData(); 167 | } catch (ex) { 168 | alert(ex.message); 169 | } 170 | } 171 | 172 | function getStudentFromForm() { 173 | var student = { 174 | id: Number($('form').attr('data-student-id')), 175 | name: $('#txtName').val(), 176 | gender: $("input[name='gender']:checked").val(), 177 | country: $('#txtCountry').val(), 178 | city: $('#txtCity').val() 179 | }; 180 | return student; 181 | } 182 | 183 | function showFormAndHideGrid() { 184 | $('#formAddUpdate').show(); 185 | $('#tblGrid').hide(); 186 | } 187 | 188 | function showGridAndHideForm() { 189 | $('#formAddUpdate').hide(); 190 | $('#tblGrid').show(); 191 | } 192 | 193 | function refreshFormData(student) { 194 | $('form').attr('data-student-id', student.id); 195 | $('#txtName').val(student.name); 196 | $(`input[name='gender'][value=${student.gender}]`).prop('checked', true); 197 | $('#txtCountry').val(student.country); 198 | $('#txtCity').val(student.city); 199 | } -------------------------------------------------------------------------------- /simple_example/style/main.css: -------------------------------------------------------------------------------- 1 | #tblGrid { 2 | margin-top: 20px; 3 | } 4 | 5 | #tblGrid tr th, 6 | table tr td { 7 | border: 1px solid black; 8 | padding: 5px 0px 5px 0px; 9 | text-align: center; 10 | } 11 | 12 | .row-centered { 13 | text-align: center; 14 | } 15 | 16 | .col-centered { 17 | display: inline-block; 18 | float: none; 19 | /* reset the text-align */ 20 | text-align: left; 21 | /* inline-block space fix */ 22 | margin-right: -4px; 23 | } -------------------------------------------------------------------------------- /svelte/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | build -------------------------------------------------------------------------------- /svelte/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-demo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "devDependencies": { 7 | "cross-env": "^5.2.0", 8 | "css-loader": "^2.1.1", 9 | "file-loader": "^6.2.0", 10 | "html-webpack-plugin": "^3.2.0", 11 | "mini-css-extract-plugin": "^0.6.0", 12 | "serve": "^11.0.0", 13 | "style-loader": "^0.23.1", 14 | "svelte-loader": "2.13.3", 15 | "webpack": "^4.30.0", 16 | "webpack-cli": "^3.3.0", 17 | "webpack-dev-server": "^3.3.1" 18 | }, 19 | "scripts": { 20 | "build": "cross-env NODE_ENV=production webpack", 21 | "dev": "webpack-dev-server --content-base public", 22 | "start": "npm run start" 23 | }, 24 | "author": "", 25 | "license": "ISC", 26 | "dependencies": { 27 | "jsstore": "^4.0.0", 28 | "svelte": "^3.16.4" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /svelte/readme.md: -------------------------------------------------------------------------------- 1 | ## Svelte JsStore Demo 2 | 3 | This is an example project of using jsstore with svelte framework. 4 | 5 | # How to run 6 | 7 | 1. execute `npm install` - install all dependecies 8 | 2. execute `npm run dev` - run the dev server 9 | 3. browse url - `http://localhost:8080/` -------------------------------------------------------------------------------- /svelte/src/components/main.svelte: -------------------------------------------------------------------------------- 1 | 31 | 32 | 51 | 52 |
53 |

54 | Visit the 55 | Svelte tutorial 56 | to learn how to build Svelte apps. 57 |

58 |

59 | Welcome to 60 | jsstore 61 | demo 62 |

63 | 68 |
69 | -------------------------------------------------------------------------------- /svelte/src/components/products_grid.svelte: -------------------------------------------------------------------------------- 1 | 63 | 64 | 74 | 75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 86 | 87 | 88 | 89 | 92 | 95 | 98 | 101 | 104 | 105 | {#each products as item (item.id)} 106 | {#if item.id !== productToUpdate.id} 107 | 108 | 109 | 110 | 111 | 114 | 117 | 118 | {:else} 119 | 120 | 123 | 126 | 129 | 132 | 135 | 136 | {/if} 137 | {/each} 138 | 139 |
Item NamePriceAvailable Quantity 84 | 85 |
90 | 91 | 93 | 94 | 96 | 97 | 99 | 100 | 102 | 103 |
{item.name}{item.price}{item.quantity} 112 | 113 | 115 | 116 |
121 | 122 | 124 | 125 | 127 | 128 | 130 | 131 | 133 | 134 |
140 |
141 | -------------------------------------------------------------------------------- /svelte/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /svelte/src/index.js: -------------------------------------------------------------------------------- 1 | import App from "./components/main.svelte"; 2 | 3 | const app = new App({ 4 | target: document.body 5 | }); 6 | 7 | export default app; -------------------------------------------------------------------------------- /svelte/src/storage_services/base_service.js: -------------------------------------------------------------------------------- 1 | import { idbCon } from "./idb_service"; 2 | 3 | export class BaseService { 4 | get connection () { 5 | return idbCon; 6 | } 7 | } -------------------------------------------------------------------------------- /svelte/src/storage_services/idb_service.js: -------------------------------------------------------------------------------- 1 | import { DATA_TYPE, Connection } from 'jsstore'; 2 | 3 | const getWorkerPath = () => { 4 | if (process.env.NODE_ENV === 'development') { 5 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.js"); 6 | } 7 | else { 8 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js"); 9 | } 10 | }; 11 | 12 | // This will ensure that we are using only one instance. 13 | // Otherwise due to multiple instance multiple worker will be created. 14 | const workerPath = getWorkerPath().default 15 | export const idbCon = new Connection(new Worker(workerPath)); 16 | export const dbname = 'Svelte_Demo'; 17 | 18 | const getDatabase = () => { 19 | const tblProduct = { 20 | name: 'Products', 21 | columns: { 22 | id: { 23 | primaryKey: true, 24 | autoIncrement: true 25 | }, 26 | name: { 27 | notNull: true, 28 | dataType: DATA_TYPE.String 29 | }, 30 | price: { 31 | dataType: DATA_TYPE.Number, 32 | notNull: true 33 | }, 34 | quantity: { 35 | dataType: DATA_TYPE.Number, 36 | default: 0 37 | }, 38 | } 39 | }; 40 | const dataBase = { 41 | name: dbname, 42 | tables: [tblProduct] 43 | }; 44 | return dataBase; 45 | }; 46 | 47 | export const initJsStore = async () => { 48 | try { 49 | const dataBase = getDatabase(); 50 | await idbCon.initDb(dataBase); 51 | } 52 | catch (ex) { 53 | console.error(ex); 54 | } 55 | }; -------------------------------------------------------------------------------- /svelte/src/storage_services/product_service.js: -------------------------------------------------------------------------------- 1 | import { BaseService } from "./base_service"; 2 | 3 | export class ProductService extends BaseService { 4 | 5 | constructor() { 6 | super(); 7 | this.tableName = "Products" 8 | } 9 | 10 | addItem (product) { 11 | return this.connection.insert({ 12 | into: this.tableName, 13 | return: true, 14 | values: [product] 15 | }) 16 | } 17 | 18 | removeItem (id) { 19 | return this.connection.remove({ 20 | from: this.tableName, 21 | where: { 22 | id: id 23 | } 24 | }) 25 | } 26 | 27 | updateItem (item) { 28 | return this.connection.update({ 29 | in: this.tableName, 30 | where: { 31 | id: item.id 32 | }, 33 | set: { 34 | name: item.name, 35 | price: Number(item.price), 36 | quantity: Number(item.quantity) 37 | } 38 | }) 39 | } 40 | 41 | fetchAll () { 42 | return this.connection.select({ 43 | from: this.tableName 44 | }) 45 | } 46 | } -------------------------------------------------------------------------------- /svelte/webpack.config.js: -------------------------------------------------------------------------------- 1 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 2 | const path = require('path'); 3 | 4 | const mode = process.env.NODE_ENV || 'development'; 5 | const prod = mode === 'production'; 6 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 7 | 8 | module.exports = { 9 | entry: { 10 | bundle: ['./src/index.js'] 11 | }, 12 | resolve: { 13 | alias: { 14 | svelte: path.resolve('node_modules', 'svelte') 15 | }, 16 | extensions: ['.mjs', '.js', '.svelte'], 17 | mainFields: ['svelte', 'browser', 'module', 'main'] 18 | }, 19 | output: { 20 | path: __dirname + '/build', 21 | filename: '[name].js', 22 | chunkFilename: '[name].[id].js' 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.svelte$/, 28 | use: { 29 | loader: 'svelte-loader', 30 | options: { 31 | emitCss: true, 32 | hotReload: true 33 | } 34 | } 35 | }, 36 | { 37 | test: /\.css$/, 38 | use: [ 39 | /** 40 | * MiniCssExtractPlugin doesn't support HMR. 41 | * For developing, use 'style-loader' instead. 42 | * */ 43 | prod ? MiniCssExtractPlugin.loader : 'style-loader', 44 | 'css-loader' 45 | ] 46 | } 47 | ] 48 | }, 49 | mode, 50 | plugins: [ 51 | new MiniCssExtractPlugin({ 52 | filename: '[name].css' 53 | }), 54 | new HtmlWebpackPlugin({ 55 | template: 'src/index.html' 56 | }) 57 | ], 58 | devtool: prod ? false : 'source-map' 59 | }; -------------------------------------------------------------------------------- /typescript/.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Directories 3 | ################# 4 | 5 | node_modules/ 6 | .nuxt/ 7 | output/ 8 | build/ 9 | bin/ 10 | -------------------------------------------------------------------------------- /typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsstore_typescript_example", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "webpack", 6 | "dev": "webpack-dev-server --config webpack.config.js", 7 | "start": "npm run dev" 8 | }, 9 | "dependencies": { 10 | "jquery": "^3.4.0", 11 | "jsstore": "^4.0.0" 12 | }, 13 | "devDependencies": { 14 | "css-loader": "^0.28.11", 15 | "file-loader": "^6.2.0", 16 | "html-webpack-plugin": "^3.2.0", 17 | "ts-loader": "^4.1.0", 18 | "typescript": "^2.7.2", 19 | "webpack": "^4.32.2", 20 | "webpack-cli": "^3.3.2", 21 | "webpack-dev-server": "^3.4.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /typescript/readme.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is an example of using jsstore with typescript. 4 | 5 | # How to run 6 | 7 | 1. execute `npm install` - install all dependecies 8 | 2. execute `npm run dev` - run the dev server 9 | 3. browse url - `http://localhost:8080/` -------------------------------------------------------------------------------- /typescript/src/business/student_logic.ts: -------------------------------------------------------------------------------- 1 | import * as $ from 'jquery'; 2 | import { StudentService } from '../storage_service/student_service'; 3 | import { Student } from '../model/student'; 4 | 5 | export class StudentLogic { 6 | service: StudentService; 7 | 8 | constructor() { 9 | this.registerEvents_(); 10 | this.service = new StudentService(); 11 | } 12 | 13 | private registerEvents_() { 14 | // add button 15 | $('#divContainer').on('click', 'td .btn-add', () => { 16 | this.addStudent(); 17 | }); 18 | // edit button 19 | $('#divContainer').on('click', 'td .btn-edit', (el) => { 20 | const id = $(el.target).parents('tr').attr('data-id'); 21 | this.editStudent(Number(id)); 22 | }); 23 | // delete button 24 | $('#divContainer').on('click', 'td .btn-delete', (el) => { 25 | const id = $(el.target).parents('tr').attr('data-id'); 26 | this.deleteStudent(Number(id)); 27 | }); 28 | 29 | $('#divContainer').on('click', 'td .btn-update', (el) => { 30 | const id = $(el.target).parents('tr').attr('data-id'); 31 | this.updateStudent(Number(id)); 32 | }); 33 | 34 | $('#divContainer').on('click', 'td .btn-add-cancel', (el) => { 35 | const row = $(el.target).parents('tr'); 36 | row.find('input').val(''); 37 | }); 38 | 39 | $('#divContainer').on('click', 'td .btn-update-cancel', (el) => { 40 | this.refreshStudentList(); 41 | }); 42 | 43 | } 44 | 45 | getRowWithTextbox(student?: Student) { 46 | return ` 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | `; 58 | } 59 | 60 | async deleteStudent(studentId) { 61 | 62 | try { 63 | const rowsDeleted = await this.service.deleteStudent(studentId); 64 | if (rowsDeleted > 0) { 65 | const row = $("#tblStudents tbody tr[data-id='" + studentId + "']"); 66 | row.remove(); 67 | } 68 | } 69 | catch (err) { 70 | alert(err.message); 71 | } 72 | } 73 | 74 | async updateStudent(studentId) { 75 | const columns = $("#tblStudents tbody tr[data-id='" + studentId + "']").find('td'); 76 | const updatedValue: Student = { 77 | name: columns[0].querySelector('input').value, 78 | gender: columns[1].querySelector('input').value, 79 | country: columns[2].querySelector('input').value, 80 | city: columns[3].querySelector('input').value 81 | }; 82 | 83 | try { 84 | const rowsUpdated = await this.service.updateStudent(studentId, updatedValue); 85 | if (rowsUpdated > 0) { 86 | updatedValue.id = studentId; 87 | ($("#tblStudents tbody tr[data-id='" + studentId + "']")[0] as HTMLElement).outerHTML = 88 | this.getHtmlRow(updatedValue); 89 | } 90 | } 91 | catch (err) { 92 | alert(err.message); 93 | } 94 | } 95 | 96 | async addStudent() { 97 | const columns = document.querySelectorAll('.tr-add td'); 98 | const student: Student = { 99 | name: columns[0].querySelector('input').value, 100 | gender: columns[1].querySelector('input').value, 101 | country: columns[2].querySelector('input').value, 102 | city: columns[3].querySelector('input').value 103 | }; 104 | try { 105 | const rowsAdded = await this.service.addStudent(student); 106 | if (rowsAdded > 0) { 107 | this.refreshStudentList(); 108 | alert('successfully added'); 109 | } 110 | } 111 | catch (err) { 112 | console.error(err); 113 | alert(err.message); 114 | } 115 | } 116 | 117 | async editStudent(studentId) { 118 | 119 | try { 120 | const students = await this.service.getStudent(studentId); 121 | if (students.length > 0) { 122 | const row: HTMLElement = $("#tblStudents tbody tr[data-id='" + studentId + "']")[0]; 123 | row.outerHTML = this.getRowWithTextbox(students[0]); 124 | } 125 | } 126 | catch (err) { 127 | alert(err.message); 128 | } 129 | } 130 | 131 | async refreshStudentList() { 132 | try { 133 | const results = await this.service.getStudents(); 134 | const tableBody = document.querySelector('#tblStudents tbody'); 135 | let html = this.getRowWithTextbox(); 136 | results.forEach(student => { 137 | html += this.getHtmlRow(student); 138 | }); 139 | tableBody.innerHTML = html; 140 | } 141 | catch (err) { 142 | console.error(err); 143 | alert(err.message); 144 | } 145 | } 146 | 147 | private getHtmlRow(student: Student) { 148 | return ` 149 | ${student.name} 150 | ${student.gender} 151 | ${student.country} 152 | ${student.city} 153 | 154 | 155 | `; 156 | } 157 | 158 | } -------------------------------------------------------------------------------- /typescript/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jsstore example 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 32 | 33 | 34 | 35 | 36 |
14 | Name 15 | 17 | Gender 18 | 20 | Country 21 | 23 | City 24 | 26 | 27 | 29 | 30 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | import "./styles/app.css"; 2 | import { StudentLogic } from './business/student_logic'; 3 | import { initJsStore } from "./storage_service/idb_helper"; 4 | 5 | //initiate jsstore at the start of app 6 | initJsStore(); 7 | 8 | const studentLogic = new StudentLogic(); 9 | studentLogic.refreshStudentList(); -------------------------------------------------------------------------------- /typescript/src/model/student.ts: -------------------------------------------------------------------------------- 1 | 2 | export class Student { 3 | id?= 0; 4 | name = ""; 5 | gender = "m"; 6 | country = ""; 7 | city = ""; 8 | } 9 | -------------------------------------------------------------------------------- /typescript/src/storage_service/base_service.ts: -------------------------------------------------------------------------------- 1 | import { idbCon, initJsStore } from "./idb_helper"; 2 | 3 | export class BaseService { 4 | 5 | get connection() { 6 | return idbCon; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /typescript/src/storage_service/idb_helper.ts: -------------------------------------------------------------------------------- 1 | import { IDataBase, DATA_TYPE, ITable, Connection } from 'jsstore'; 2 | 3 | const getWorkerPath = () => { 4 | if (process.env.NODE_ENV === 'development') { 5 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.js"); 6 | } 7 | else { 8 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js"); 9 | } 10 | }; 11 | 12 | // This will ensure that we are using only one instance. 13 | // Otherwise due to multiple instance multiple worker will be created. 14 | const workerPath = getWorkerPath().default; 15 | 16 | export const idbCon = new Connection(new Worker(workerPath)); 17 | export const dbname = 'Demo'; 18 | 19 | const getDatabase = () => { 20 | const tblStudent: ITable = { 21 | name: 'Students', 22 | columns: { 23 | id: { 24 | primaryKey: true, 25 | autoIncrement: true 26 | }, 27 | name: { 28 | notNull: true, 29 | dataType: DATA_TYPE.String 30 | }, 31 | gender: { 32 | dataType: DATA_TYPE.String, 33 | default: 'male' 34 | }, 35 | country: { 36 | notNull: true, 37 | dataType: DATA_TYPE.String 38 | }, 39 | city: { 40 | dataType: DATA_TYPE.String, 41 | notNull: true 42 | } 43 | } 44 | }; 45 | const dataBase: IDataBase = { 46 | name: dbname, 47 | tables: [tblStudent] 48 | }; 49 | return dataBase; 50 | }; 51 | 52 | export const initJsStore = () => { 53 | try { 54 | const dataBase = getDatabase(); 55 | idbCon.initDb(dataBase); 56 | } 57 | catch (ex) { 58 | console.error(ex); 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /typescript/src/storage_service/student_service.ts: -------------------------------------------------------------------------------- 1 | import { BaseService } from './base_service'; 2 | import { Student } from '../model/student'; 3 | 4 | export class StudentService extends BaseService { 5 | 6 | getStudents() { 7 | return this.connection.select({ 8 | from: 'Students' 9 | }); 10 | } 11 | 12 | addStudent(student: Student) { 13 | return this.connection.insert({ 14 | into: 'Students', 15 | values: [student] 16 | }); 17 | } 18 | 19 | deleteStudent(studentId: number) { 20 | return this.connection.remove({ 21 | from: 'Students', 22 | where: { 23 | id: studentId 24 | } 25 | }); 26 | } 27 | 28 | getStudent(studentId: number) { 29 | return this.connection.select({ 30 | from: 'Students', 31 | where: { 32 | id: studentId 33 | } 34 | }); 35 | } 36 | 37 | updateStudent(studentId: number, value) { 38 | return this.connection.update({ 39 | in: 'Students', 40 | set: value, 41 | where: { 42 | id: studentId 43 | } 44 | }); 45 | } 46 | } -------------------------------------------------------------------------------- /typescript/src/styles/app.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | } 4 | 5 | table tr td, 6 | th { 7 | border: 1px solid black; 8 | text-align: center; 9 | padding: 10px; 10 | } 11 | 12 | contenteditable { 13 | border: 2px solid blue; 14 | } 15 | 16 | #divContainer { 17 | text-align: center; 18 | width: 50%; 19 | margin: 0 auto; 20 | } 21 | -------------------------------------------------------------------------------- /typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "", 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "es6", 9 | "dom" 10 | ], 11 | "mapRoot": "./", 12 | "module": "es6", 13 | "moduleResolution": "node", 14 | "outDir": "dist/out-tsc", 15 | "sourceMap": true, 16 | "target": "es5" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /typescript/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "array-type": [true, "array-simple"], 4 | "arrow-return-shorthand": true, 5 | "ban": [true, 6 | {"name": "parseInt", "message": "tsstyle#type-coercion"}, 7 | {"name": "parseFloat", "message": "tsstyle#type-coercion"}, 8 | {"name": "Array", "message": "tsstyle#array-constructor"} 9 | ], 10 | "ban-types": [true, 11 | ["Object", "Use {} instead."], 12 | ["String", "Use 'string' instead."], 13 | ["Number", "Use 'number' instead."], 14 | ["Boolean", "Use 'boolean' instead."] 15 | ], 16 | "class-name": true, 17 | "curly": [true, "ignore-same-line"], 18 | // "forin": true, 19 | "interface-name": [true,"allow-prefix"], 20 | "jsdoc-format": true, 21 | "label-position": true, 22 | "member-access": [true, "no-public"], 23 | "new-parens": true, 24 | "no-angle-bracket-type-assertion": true, 25 | "no-any": false, 26 | "no-arg": true, 27 | "no-conditional-assignment": true, 28 | "no-construct": true, 29 | "no-debugger": true, 30 | "no-default-export": true, 31 | "no-duplicate-variable": true, 32 | "no-inferrable-types": true, 33 | "no-namespace": [true, "allow-declarations"], 34 | "no-reference": true, 35 | "no-string-throw": true, 36 | "no-unused-expression": true, 37 | "no-var-keyword": true, 38 | "object-literal-shorthand": false, 39 | "only-arrow-functions": [true], 40 | "prefer-const": true, 41 | "radix": true, 42 | "semicolon": [true, "always", "ignore-bound-class-methods"], 43 | // "switch-default": true, 44 | "triple-equals": [true, "allow-null-check"], 45 | "use-isnan": true, 46 | "variable-name": [ 47 | true, 48 | "check-format", 49 | "ban-keywords", 50 | "allow-leading-underscore", 51 | "allow-trailing-underscore" 52 | ], 53 | "no-shadowed-variable":true 54 | } 55 | } -------------------------------------------------------------------------------- /typescript/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebPackPlugin = require('html-webpack-plugin'); 3 | module.exports = { 4 | entry: './src/index.ts', 5 | devtool: 'inline-source-map', 6 | module: { 7 | rules: [{ 8 | test: /\.tsx?$/, 9 | use: 'ts-loader', 10 | exclude: /node_modules/ 11 | }, { 12 | test: /\.css?$/, 13 | use: 'css-loader', 14 | exclude: /node_modules/ 15 | }] 16 | }, 17 | resolve: { 18 | extensions: ['.tsx', '.ts', '.js', '.css'] 19 | }, 20 | output: { 21 | filename: 'bundle.js', 22 | path: path.resolve(__dirname, 'bin/') 23 | }, 24 | plugins: [ 25 | new HtmlWebPackPlugin({ 26 | cache: true, 27 | hash: true, 28 | template: './src/index.html', 29 | minify: { 30 | collapseWhitespace: true, 31 | removeComments: true, 32 | removeRedundantAttributes: true, 33 | removeScriptTypeAttributes: true, 34 | removeStyleLinkTypeAttributes: true 35 | } 36 | }) 37 | ] 38 | }; -------------------------------------------------------------------------------- /typescript_without_worker/.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Directories 3 | ################# 4 | 5 | node_modules/ 6 | .nuxt/ 7 | output/ 8 | build/ 9 | bin/ 10 | -------------------------------------------------------------------------------- /typescript_without_worker/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsstore_typescript_example", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build": "webpack", 6 | "start": "export NODE_OPTIONS=--openssl-legacy-provider; webpack-dev-server", 7 | "dev": "npm run start" 8 | }, 9 | "dependencies": { 10 | "jquery": "^3.3.1", 11 | "jsstore": "^4.4.4" 12 | }, 13 | "devDependencies": { 14 | "@types/jquery": "^3.5.5", 15 | "css-loader": "^0.28.11", 16 | "file-loader": "^6.2.0", 17 | "html-webpack-plugin": "^3.2.0", 18 | "ts-loader": "^4.1.0", 19 | "typescript": "^2.7.2", 20 | "webpack": "^4.32.2", 21 | "webpack-cli": "^3.3.2", 22 | "webpack-dev-server": "^3.4.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /typescript_without_worker/readme.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is an example of using jsstore without web worker in typescript. This is achieved by providing no parameter to jsstore instance. 4 | 5 | e.g - 6 | // using web worker 7 | 8 | var jsstoreCon = new JsStore.Instance(new Worker('path of worker)); 9 | 10 | // using without web worker 11 | 12 | var jsstoreCon = new JsStore.Instance(); 13 | 14 | Note : - make sure you have included jsstore.worker file in your app. 15 | 16 | # How to run 17 | 18 | 1. execute `npm install` - install all dependecies 19 | 2. execute `npm run start` - run the dev server 20 | 3. browse url - `http://localhost:8080/` -------------------------------------------------------------------------------- /typescript_without_worker/src/business/student_logic.ts: -------------------------------------------------------------------------------- 1 | import * as $ from 'jquery'; 2 | import { StudentService } from '../storage_service/student_service'; 3 | import { Student } from '../model/student'; 4 | 5 | export class StudentLogic { 6 | service: StudentService; 7 | 8 | constructor() { 9 | this.registerEvents_(); 10 | this.service = new StudentService(); 11 | } 12 | 13 | private registerEvents_() { 14 | // add button 15 | $('#divContainer').on('click', 'td .btn-add', () => { 16 | this.addStudent(); 17 | }); 18 | // edit button 19 | $('#divContainer').on('click', 'td .btn-edit', (el:any) => { 20 | const id = $(el.target).parents('tr').attr('data-id'); 21 | this.editStudent(Number(id)); 22 | }); 23 | // delete button 24 | $('#divContainer').on('click', 'td .btn-delete', (el:any) => { 25 | const id = $(el.target).parents('tr').attr('data-id'); 26 | this.deleteStudent(Number(id)); 27 | }); 28 | 29 | $('#divContainer').on('click', 'td .btn-update', (el:any) => { 30 | const id = $(el.target).parents('tr').attr('data-id'); 31 | this.updateStudent(Number(id)); 32 | }); 33 | 34 | $('#divContainer').on('click', 'td .btn-add-cancel', (el: any) => { 35 | const row = $(el.target).parents('tr'); 36 | row.find('input').val(''); 37 | }); 38 | 39 | $('#divContainer').on('click', 'td .btn-update-cancel', () => { 40 | this.refreshStudentList(); 41 | }); 42 | 43 | } 44 | 45 | getRowWithTextbox(student?: Student) { 46 | return ` 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | `; 58 | } 59 | 60 | async deleteStudent(studentId: number) { 61 | 62 | try { 63 | const rowsDeleted = await this.service.deleteStudent(studentId); 64 | if (rowsDeleted > 0) { 65 | const row = $("#tblStudents tbody tr[data-id='" + studentId + "']"); 66 | row.remove(); 67 | } 68 | } 69 | catch (err) { 70 | alert(err.message); 71 | } 72 | } 73 | 74 | async updateStudent(studentId: number) { 75 | const columns = $("#tblStudents tbody tr[data-id='" + studentId + "']").find('td'); 76 | const updatedValue: Student = { 77 | name: columns[0].querySelector('input').value, 78 | gender: columns[1].querySelector('input').value, 79 | country: columns[2].querySelector('input').value, 80 | city: columns[3].querySelector('input').value 81 | }; 82 | 83 | try { 84 | const rowsUpdated = await this.service.updateStudent(studentId, updatedValue); 85 | if (rowsUpdated > 0) { 86 | updatedValue.id = studentId; 87 | ($("#tblStudents tbody tr[data-id='" + studentId + "']")[0] as HTMLElement).outerHTML = 88 | this.getHtmlRow(updatedValue); 89 | } 90 | } 91 | catch (err) { 92 | alert(err.message); 93 | } 94 | } 95 | 96 | async addStudent() { 97 | const columns = document.querySelectorAll('.tr-add td'); 98 | const student: Student = { 99 | name: columns[0].querySelector('input').value, 100 | gender: columns[1].querySelector('input').value, 101 | country: columns[2].querySelector('input').value, 102 | city: columns[3].querySelector('input').value 103 | }; 104 | try { 105 | const rowsAdded = await this.service.addStudent(student); 106 | if (rowsAdded > 0) { 107 | this.refreshStudentList(); 108 | alert('successfully added'); 109 | } 110 | } 111 | catch (err) { 112 | console.error(err); 113 | alert(err.message); 114 | } 115 | } 116 | 117 | async editStudent(studentId: number) { 118 | 119 | try { 120 | const students = await this.service.getStudent(studentId); 121 | if (students.length > 0) { 122 | const row: HTMLElement = $("#tblStudents tbody tr[data-id='" + studentId + "']")[0]; 123 | row.outerHTML = this.getRowWithTextbox(students[0]); 124 | } 125 | } 126 | catch (err) { 127 | alert(err.message); 128 | } 129 | } 130 | 131 | async refreshStudentList() { 132 | try { 133 | const results = await this.service.getStudents(); 134 | const tableBody = document.querySelector('#tblStudents tbody'); 135 | let html = this.getRowWithTextbox(); 136 | results.forEach(student => { 137 | html += this.getHtmlRow(student); 138 | }); 139 | tableBody.innerHTML = html; 140 | } 141 | catch (err) { 142 | console.error(err); 143 | alert(err.message); 144 | } 145 | } 146 | 147 | private getHtmlRow(student: Student) { 148 | return ` 149 | ${student.name} 150 | ${student.gender} 151 | ${student.country} 152 | ${student.city} 153 | 154 | 155 | `; 156 | } 157 | 158 | } -------------------------------------------------------------------------------- /typescript_without_worker/src/extra/worker.d.ts: -------------------------------------------------------------------------------- 1 | declare module "file-loader?name=scripts/[name].[hash].js!*" { 2 | const value: string; 3 | export = value; 4 | } -------------------------------------------------------------------------------- /typescript_without_worker/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | jsstore example 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 16 | 19 | 22 | 25 | 28 | 31 | 32 | 33 | 34 | 35 | 36 |
14 | Name 15 | 17 | Gender 18 | 20 | Country 21 | 23 | City 24 | 26 | 27 | 29 | 30 |
37 |
38 | 39 | 40 | -------------------------------------------------------------------------------- /typescript_without_worker/src/index.ts: -------------------------------------------------------------------------------- 1 | import "./styles/app.css"; 2 | import { StudentLogic } from './business/student_logic'; 3 | import { initJsStore } from "./storage_service/idb_helper"; 4 | 5 | //initiate jsstore at the start of app 6 | initJsStore(); 7 | 8 | const studentLogic = new StudentLogic(); 9 | studentLogic.refreshStudentList(); -------------------------------------------------------------------------------- /typescript_without_worker/src/model/student.ts: -------------------------------------------------------------------------------- 1 | 2 | export class Student { 3 | id?= 0; 4 | name = ""; 5 | gender = "m"; 6 | country = ""; 7 | city = ""; 8 | } 9 | -------------------------------------------------------------------------------- /typescript_without_worker/src/storage_service/base_service.ts: -------------------------------------------------------------------------------- 1 | import { idbCon, initJsStore } from "./idb_helper"; 2 | 3 | export class BaseService { 4 | 5 | get connection() { 6 | return idbCon; 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /typescript_without_worker/src/storage_service/idb_helper.ts: -------------------------------------------------------------------------------- 1 | import { ITable, DATA_TYPE, IDataBase, Connection } from "jsstore"; 2 | import workerInjector from "jsstore/dist/worker_injector"; 3 | 4 | // This will ensure that we are using only one instance. 5 | // Otherwise due to multiple instance multiple worker will be created. 6 | export const idbCon = new Connection(); 7 | console.log('workerInjector', workerInjector) 8 | idbCon.addPlugin(workerInjector); 9 | 10 | export const dbname = 'Demo'; 11 | 12 | const getDatabase = () => { 13 | const tblStudent: ITable = { 14 | name: 'Students', 15 | columns: { 16 | id: { 17 | primaryKey: true, 18 | autoIncrement: true 19 | }, 20 | name: { 21 | notNull: true, 22 | dataType: DATA_TYPE.String 23 | }, 24 | gender: { 25 | dataType: DATA_TYPE.String, 26 | default: 'male' 27 | }, 28 | country: { 29 | notNull: true, 30 | dataType: DATA_TYPE.String 31 | }, 32 | city: { 33 | dataType: DATA_TYPE.String, 34 | notNull: true 35 | } 36 | } 37 | }; 38 | const dataBase: IDataBase = { 39 | name: dbname, 40 | tables: [tblStudent] 41 | }; 42 | return dataBase; 43 | }; 44 | 45 | export const initJsStore = () => { 46 | try { 47 | const dataBase = getDatabase(); 48 | return idbCon.initDb(dataBase); 49 | } 50 | catch (ex) { 51 | console.error(ex); 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /typescript_without_worker/src/storage_service/student_service.ts: -------------------------------------------------------------------------------- 1 | import { BaseService } from './base_service'; 2 | import { Student } from '../model/student'; 3 | 4 | export class StudentService extends BaseService { 5 | 6 | getStudents() { 7 | return this.connection.select({ 8 | from: 'Students' 9 | }); 10 | } 11 | 12 | addStudent(student: Student) { 13 | return this.connection.insert({ 14 | into: 'Students', 15 | values: [student] 16 | }); 17 | } 18 | 19 | deleteStudent(studentId: number) { 20 | return this.connection.remove({ 21 | from: 'Students', 22 | where: { 23 | id: studentId 24 | } 25 | }); 26 | } 27 | 28 | getStudent(studentId: number) { 29 | return this.connection.select({ 30 | from: 'Students', 31 | where: { 32 | id: studentId 33 | } 34 | }); 35 | } 36 | 37 | updateStudent(studentId: number, value: any) { 38 | return this.connection.update({ 39 | in: 'Students', 40 | set: value, 41 | where: { 42 | id: studentId 43 | } 44 | }); 45 | } 46 | } -------------------------------------------------------------------------------- /typescript_without_worker/src/styles/app.css: -------------------------------------------------------------------------------- 1 | table { 2 | border-collapse: collapse; 3 | } 4 | 5 | table tr td, 6 | th { 7 | border: 1px solid black; 8 | text-align: center; 9 | padding: 10px; 10 | } 11 | 12 | contenteditable { 13 | border: 2px solid blue; 14 | } 15 | 16 | #divContainer { 17 | text-align: center; 18 | width: 50%; 19 | margin: 0 auto; 20 | } 21 | -------------------------------------------------------------------------------- /typescript_without_worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "", 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "lib": [ 8 | "es6", 9 | "dom" 10 | ], 11 | "mapRoot": "./", 12 | "module": "es6", 13 | "moduleResolution": "node", 14 | "outDir": "dist/out-tsc", 15 | "sourceMap": true, 16 | "target": "es5", 17 | "noImplicitAny": true 18 | } 19 | } -------------------------------------------------------------------------------- /typescript_without_worker/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "array-type": [true, "array-simple"], 4 | "arrow-return-shorthand": true, 5 | "ban": [true, 6 | {"name": "parseInt", "message": "tsstyle#type-coercion"}, 7 | {"name": "parseFloat", "message": "tsstyle#type-coercion"}, 8 | {"name": "Array", "message": "tsstyle#array-constructor"} 9 | ], 10 | "ban-types": [true, 11 | ["Object", "Use {} instead."], 12 | ["String", "Use 'string' instead."], 13 | ["Number", "Use 'number' instead."], 14 | ["Boolean", "Use 'boolean' instead."] 15 | ], 16 | "class-name": true, 17 | "curly": [true, "ignore-same-line"], 18 | // "forin": true, 19 | "interface-name": [true,"allow-prefix"], 20 | "jsdoc-format": true, 21 | "label-position": true, 22 | "member-access": [true, "no-public"], 23 | "new-parens": true, 24 | "no-angle-bracket-type-assertion": true, 25 | "no-any": false, 26 | "no-arg": true, 27 | "no-conditional-assignment": true, 28 | "no-construct": true, 29 | "no-debugger": true, 30 | "no-default-export": true, 31 | "no-duplicate-variable": true, 32 | "no-inferrable-types": true, 33 | "no-namespace": [true, "allow-declarations"], 34 | "no-reference": true, 35 | "no-string-throw": true, 36 | "no-unused-expression": true, 37 | "no-var-keyword": true, 38 | "object-literal-shorthand": false, 39 | "only-arrow-functions": [true], 40 | "prefer-const": true, 41 | "radix": true, 42 | "semicolon": [true, "always", "ignore-bound-class-methods"], 43 | // "switch-default": true, 44 | "triple-equals": [true, "allow-null-check"], 45 | "use-isnan": true, 46 | "variable-name": [ 47 | true, 48 | "check-format", 49 | "ban-keywords", 50 | "allow-leading-underscore", 51 | "allow-trailing-underscore" 52 | ], 53 | "no-shadowed-variable":true 54 | } 55 | } -------------------------------------------------------------------------------- /typescript_without_worker/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebPackPlugin = require('html-webpack-plugin'); 3 | module.exports = { 4 | entry: './src/index.ts', 5 | devtool: 'inline-source-map', 6 | mode: 'development', 7 | module: { 8 | rules: [{ 9 | test: /\.tsx?$/, 10 | use: 'ts-loader', 11 | exclude: /node_modules/ 12 | }, { 13 | test: /\.css?$/, 14 | use: 'css-loader', 15 | exclude: /node_modules/ 16 | }] 17 | }, 18 | resolve: { 19 | extensions: ['.tsx', '.ts', '.js', '.css'] 20 | }, 21 | output: { 22 | filename: 'scripts/bundle.js', 23 | path: path.resolve(__dirname, 'bin/') 24 | }, 25 | plugins: [ 26 | new HtmlWebPackPlugin({ 27 | cache: true, 28 | hash: true, 29 | template: './src/index.html', 30 | minify: { 31 | collapseWhitespace: true, 32 | removeComments: true, 33 | removeRedundantAttributes: true, 34 | removeScriptTypeAttributes: true, 35 | removeStyleLinkTypeAttributes: true 36 | } 37 | }) 38 | ] 39 | }; -------------------------------------------------------------------------------- /vue/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | -------------------------------------------------------------------------------- /vue/README.md: -------------------------------------------------------------------------------- 1 | # vue-crud-demo 2 | 3 | ## Project setup 4 | ``` 5 | npm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | npm run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | npm run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | npm run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | npm run lint 26 | ``` 27 | 28 | ### Customize configuration 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /vue/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-crud-demo", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^2.6.5", 12 | "file-loader": "^6.2.0", 13 | "jsstore": "^4.2.6", 14 | "vue": "^2.6.10" 15 | }, 16 | "devDependencies": { 17 | "@vue/cli-plugin-babel": "^3.8.0", 18 | "@vue/cli-plugin-eslint": "^3.8.0", 19 | "@vue/cli-service": "^3.8.0", 20 | "babel-eslint": "^10.0.1", 21 | "eslint": "^5.16.0", 22 | "eslint-plugin-vue": "^5.0.0", 23 | "vue-template-compiler": "^2.6.10" 24 | }, 25 | "eslintConfig": { 26 | "root": true, 27 | "env": { 28 | "node": true 29 | }, 30 | "extends": [ 31 | "plugin:vue/essential", 32 | "eslint:recommended" 33 | ], 34 | "rules": {}, 35 | "parserOptions": { 36 | "parser": "babel-eslint" 37 | } 38 | }, 39 | "postcss": { 40 | "plugins": { 41 | "autoprefixer": {} 42 | } 43 | }, 44 | "browserslist": [ 45 | "> 1%", 46 | "last 2 versions" 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /vue/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/vue/public/favicon.ico -------------------------------------------------------------------------------- /vue/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vue-crud-demo 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /vue/src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 56 | 57 | 67 | -------------------------------------------------------------------------------- /vue/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/vue/src/assets/logo.png -------------------------------------------------------------------------------- /vue/src/components/student_grid.vue: -------------------------------------------------------------------------------- 1 | 65 | 134 | 135 | -------------------------------------------------------------------------------- /vue/src/global.js: -------------------------------------------------------------------------------- 1 | export class Global { 2 | static isIndexedDbSupported = true; 3 | } -------------------------------------------------------------------------------- /vue/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | 4 | Vue.config.productionTip = false 5 | 6 | new Vue({ 7 | render: h => h(App), 8 | }).$mount('#app') 9 | -------------------------------------------------------------------------------- /vue/src/service/idb_service.js: -------------------------------------------------------------------------------- 1 | import { connection } from "./jsstore_con"; 2 | import { DATA_TYPE } from "jsstore"; 3 | 4 | const getDatabase = () => { 5 | const tblStudent = { 6 | name: 'Students', 7 | columns: { 8 | id: { 9 | primaryKey: true, 10 | autoIncrement: true 11 | }, 12 | name: { 13 | notNull: true, 14 | dataType: DATA_TYPE.String 15 | }, 16 | gender: { 17 | dataType: DATA_TYPE.String, 18 | default: 'male' 19 | }, 20 | country: { 21 | notNull: true, 22 | dataType: DATA_TYPE.String 23 | }, 24 | city: { 25 | dataType: DATA_TYPE.String, 26 | notNull: true 27 | } 28 | } 29 | }; 30 | const dataBase = { 31 | name: "Vue_Demo", 32 | tables: [tblStudent] 33 | }; 34 | return dataBase; 35 | }; 36 | 37 | export const initJsStore = async () => { 38 | const dataBase = getDatabase(); 39 | return await connection.initDb(dataBase); 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /vue/src/service/jsstore_con.js: -------------------------------------------------------------------------------- 1 | import { Connection } from "jsstore"; 2 | 3 | const getWorkerPath = () => { 4 | // return dev build when env is development 5 | if (process.env.NODE_ENV === 'development') { 6 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.js"); 7 | } 8 | else { // return prod build when env is production 9 | return require("file-loader?name=scripts/[name].[hash].js!jsstore/dist/jsstore.worker.min.js"); 10 | } 11 | }; 12 | 13 | const workerPath = getWorkerPath().default; 14 | export const connection = new Connection(new Worker(workerPath)); 15 | 16 | connection.logStatus = true; -------------------------------------------------------------------------------- /vue/src/service/student_service.js: -------------------------------------------------------------------------------- 1 | import { connection } from "./jsstore_con"; 2 | 3 | export class StudentService { 4 | 5 | constructor() { 6 | 7 | this.tableName = "Students"; 8 | } 9 | 10 | getStudents() { 11 | return connection.select({ 12 | from: this.tableName, 13 | }) 14 | } 15 | 16 | addStudent(student) { 17 | return connection.insert({ 18 | into: this.tableName, 19 | values: [student], 20 | return: true 21 | }) 22 | } 23 | 24 | getStudentById(id) { 25 | return connection.select({ 26 | from: this.tableName, 27 | where: { 28 | id: id 29 | } 30 | }) 31 | } 32 | 33 | removeStudent(id) { 34 | return connection.remove({ 35 | from: this.tableName, 36 | where: { 37 | id: id 38 | } 39 | }) 40 | } 41 | 42 | updateStudentById(student) { 43 | return connection.update({ 44 | in: this.tableName, 45 | set: { 46 | name: student.name, 47 | gender: student.gender, 48 | country: student.country, 49 | city: student.city 50 | }, 51 | where: { 52 | id: student.id 53 | } 54 | }) 55 | } 56 | } -------------------------------------------------------------------------------- /without_web_worker/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This is an example of jsstore without using web worker. THis is achieved by providing no parameter to jsstore instance. 4 | 5 | e.g - 6 | //using web worker 7 | 8 | var jsstoreCon = new JsStore.Instance(new Worker('path of worker)); 9 | 10 | // using without web worker 11 | 12 | var jsstoreCon = new JsStore.Instance(); 13 | 14 | Note : - make sure you have included jsstore.worker file in your app. 15 | -------------------------------------------------------------------------------- /without_web_worker/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/without_web_worker/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /without_web_worker/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/without_web_worker/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /without_web_worker/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/without_web_worker/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /without_web_worker/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/without_web_worker/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /without_web_worker/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ujjwalguptaofficial/jsstore-examples/1193ca0fc23a4d6e0a9c186091fe4aab0552988d/without_web_worker/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /without_web_worker/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | JsStore Example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | 23 |
24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
27 | Student's Details
NameGenderCountryCity
40 | 81 |
82 |
83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /without_web_worker/scripts/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | var jsstoreCon = new JsStore.Connection(); 4 | 5 | window.onload = function () { 6 | refreshTableData(); 7 | registerEvents(); 8 | initDb(); 9 | }; 10 | 11 | async function initDb() { 12 | var isDbCreated = await jsstoreCon.initDb(getDbSchema()); 13 | if (isDbCreated) { 14 | console.log('db created'); 15 | } 16 | else { 17 | console.log('db opened'); 18 | } 19 | } 20 | 21 | function getDbSchema() { 22 | var table = { 23 | name: 'Student', 24 | columns: { 25 | id: { 26 | primaryKey: true, 27 | autoIncrement: true 28 | }, 29 | name: { 30 | notNull: true, 31 | dataType: 'string' 32 | }, 33 | gender: { 34 | dataType: 'string', 35 | default: 'male' 36 | }, 37 | country: { 38 | notNull: true, 39 | dataType: 'string' 40 | }, 41 | city: { 42 | dataType: 'string', 43 | notNull: true 44 | } 45 | } 46 | } 47 | 48 | var db = { 49 | name: 'My-Db', 50 | tables: [table] 51 | } 52 | return db; 53 | } 54 | 55 | function registerEvents() { 56 | $('#btnAddStudent').click(function () { 57 | showFormAndHideGrid(); 58 | }) 59 | $('#tblGrid tbody').on('click', '.edit', function () { 60 | var row = $(this).parents().eq(1); 61 | var child = row.children(); 62 | var student = { 63 | id: row.attr('itemid'), 64 | name: child.eq(0).text(), 65 | gender: child.eq(1).text(), 66 | country: child.eq(2).text(), 67 | city: child.eq(3).text() 68 | } 69 | refreshFormData(student); 70 | showFormAndHideGrid(); 71 | }); 72 | $('#tblGrid tbody').on('click', '.delete', function () { 73 | var result = confirm('Are you sure, you want to delete?'); 74 | if (result) { 75 | var studentId = $(this).parents().eq(1).attr('itemid'); 76 | deleteStudent(Number(studentId)); 77 | } 78 | }); 79 | $('#btnSubmit').click(function () { 80 | var studentId = $('form').attr('data-student-id'); 81 | if (studentId) { 82 | updateStudent(); 83 | } 84 | else { 85 | addStudent(); 86 | } 87 | }); 88 | } 89 | 90 | 91 | //This function refreshes the table 92 | async function refreshTableData() { 93 | try { 94 | var htmlString = ""; 95 | var students = await jsstoreCon.select({ 96 | from: 'Student' 97 | }); 98 | students.forEach(function (student) { 99 | htmlString += "" + 100 | student.name + "" + 101 | student.gender + "" + 102 | student.country + "" + 103 | student.city + "" + 104 | "Edit" + 105 | "Delete"; 106 | }) 107 | $('#tblGrid tbody').html(htmlString); 108 | } catch (ex) { 109 | alert(ex.message) 110 | } 111 | } 112 | 113 | 114 | 115 | async function addStudent() { 116 | var student = getStudentFromForm(); 117 | try { 118 | var noOfDataInserted = await jsstoreCon.insert({ 119 | into: 'Student', 120 | values: [student] 121 | }); 122 | if (noOfDataInserted === 1) { 123 | refreshTableData(); 124 | showGridAndHideForm(); 125 | } 126 | } catch (ex) { 127 | alert(ex.message); 128 | } 129 | 130 | } 131 | 132 | async function updateStudent() { 133 | var student = getStudentFromForm(); 134 | try { 135 | var noOfDataUpdated = await jsstoreCon.update({ 136 | in: 'Student', 137 | set: { 138 | name: student.name, 139 | gender: student.gender, 140 | country: student.country, 141 | city: student.city 142 | }, 143 | where: { 144 | id: student.id 145 | } 146 | }); 147 | console.log(`data updated ${noOfDataUpdated}`); 148 | showGridAndHideForm(); 149 | $('form').attr('data-student-id', null); 150 | refreshTableData(); 151 | refreshFormData({}); 152 | } catch (ex) { 153 | alert(ex.message); 154 | } 155 | } 156 | 157 | async function deleteStudent(id) { 158 | try { 159 | var noOfStudentRemoved = await jsstoreCon.remove({ 160 | from: 'Student', 161 | where: { 162 | id: id 163 | } 164 | }); 165 | console.log(`${noOfStudentRemoved} students removed`); 166 | refreshTableData(); 167 | } catch (ex) { 168 | alert(ex.message); 169 | } 170 | } 171 | 172 | function getStudentFromForm() { 173 | var student = { 174 | id: Number($('form').attr('data-student-id')), 175 | name: $('#txtName').val(), 176 | gender: $("input[name='gender']:checked").val(), 177 | country: $('#txtCountry').val(), 178 | city: $('#txtCity').val() 179 | }; 180 | return student; 181 | } 182 | 183 | function showFormAndHideGrid() { 184 | $('#formAddUpdate').show(); 185 | $('#tblGrid').hide(); 186 | } 187 | 188 | function showGridAndHideForm() { 189 | $('#formAddUpdate').hide(); 190 | $('#tblGrid').show(); 191 | } 192 | 193 | function refreshFormData(student) { 194 | $('form').attr('data-student-id', student.id); 195 | $('#txtName').val(student.name); 196 | $(`input[name='gender'][value=${student.gender}]`).prop('checked', true); 197 | $('#txtCountry').val(student.country); 198 | $('#txtCity').val(student.city); 199 | } -------------------------------------------------------------------------------- /without_web_worker/style/main.css: -------------------------------------------------------------------------------- 1 | #tblGrid { 2 | margin-top: 20px; 3 | } 4 | 5 | #tblGrid tr th, 6 | table tr td { 7 | border: 1px solid black; 8 | padding: 5px 0px 5px 0px; 9 | text-align: center; 10 | } 11 | 12 | .row-centered { 13 | text-align: center; 14 | } 15 | 16 | .col-centered { 17 | display: inline-block; 18 | float: none; 19 | /* reset the text-align */ 20 | text-align: left; 21 | /* inline-block space fix */ 22 | margin-right: -4px; 23 | } --------------------------------------------------------------------------------