├── .babelrc
├── .circleci
└── config.yml
├── .codeclimate.yml
├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github
└── FUNDING.yml
├── .gitignore
├── .hound.yml
├── .huskyrc.yml
├── .npmignore
├── .nvmrc
├── .travis.yml
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── LICENSE
├── README.md
├── bower.json
├── build
├── karma.config.js
├── karma.dev.config.js
├── karma.sauce.config.js
├── local.runner.js
├── nightwatch.browserstack.config.js
├── nightwatch.config.js
├── prerelease.sh
├── rollup.config.js
└── webpack.config.js
├── dist
├── vue-ls.js
├── vue-ls.min.js
└── vue-ls.min.js.map
├── docker-compose.yml
├── examples
└── counter
│ └── index.html
├── gulpfile.js
├── package.json
├── src
├── index.js
└── storage
│ ├── MemoryStorage.js
│ ├── WebStorage.js
│ ├── WebStorageEvent.js
│ └── index.js
├── test
├── e2e
│ └── counter.js
└── unit
│ ├── ava
│ ├── eventAttach.js
│ ├── eventWindow.js
│ ├── events.js
│ ├── helpers
│ │ ├── setupBrowserEnv.js
│ │ ├── setupIEBrowserEnv.js
│ │ └── setupOldBrowserEnv.js
│ ├── localStorage.js
│ ├── memoryFallback.js
│ ├── memoryStorage.js
│ ├── sessionStorage.js
│ └── unknownStorage.js
│ └── jasmine
│ └── index.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["@babel/preset-env", {
4 | "modules": false,
5 | "targets": {
6 | "browsers": [
7 | "> 1%",
8 | "Chrome >= 14",
9 | "Safari >= 4",
10 | "Firefox >= 4",
11 | "Opera >= 10",
12 | "Edge >= 41",
13 | "ie >= 9",
14 | "iOS >= 6",
15 | "ChromeAndroid >= 4",
16 | "OperaMobile >= 12"
17 | ]
18 | }
19 | }]
20 | ],
21 | "ignore": [
22 | "dist/*.js",
23 | "packages/**/*.js"
24 | ],
25 | "plugins": [
26 | "@babel/plugin-transform-runtime",
27 | "@babel/plugin-syntax-dynamic-import",
28 | "@babel/plugin-transform-modules-commonjs"
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: circleci/node:10
6 | working_directory: ~/repo
7 |
8 | steps:
9 | - checkout
10 | - restore_cache:
11 | keys:
12 | - v1-dependencies-{{ checksum "package.json" }}
13 | - v1-dependencies-
14 |
15 | - run: NODE_ENV=dev yarn install
16 |
17 | - save_cache:
18 | paths:
19 | - node_modules
20 | key: v1-dependencies-{{ checksum "package.json" }}
21 | - run: yarn build
22 | - run: yarn test
--------------------------------------------------------------------------------
/.codeclimate.yml:
--------------------------------------------------------------------------------
1 | engines:
2 | eslint:
3 | enabled: true
4 | duplication:
5 | enabled: true
6 | config:
7 | languages:
8 | - javascript
9 | ratings:
10 | paths:
11 | - "src/**/*"
12 | exclude_paths:
13 | - "dist/**.js"
14 | - "examples/**/*"
15 | - "test/**/*"
16 | - "build/*"
17 |
18 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 |
3 | # OS generated files #
4 | .DS_Store
5 | tests_output
6 | ehthumbs.db
7 | Icon?
8 | Thumbs.db
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | tab_width = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /test
2 | /dist
3 | /node_modules
4 | /build
5 | coverage
6 | gulpfile.js
7 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: 'babel-eslint',
4 | parserOptions: {
5 | sourceType: 'module',
6 | },
7 | env: {
8 | browser: true,
9 | },
10 | extends: 'airbnb-base',
11 | plugins: [],
12 | globals: {
13 | window: true,
14 | },
15 | rules: {
16 | 'linebreak-style': 'off',
17 | 'semi-style': 0,
18 | 'no-cond-assign': 0,
19 | 'no-plusplus': 0,
20 | 'no-restricted-syntax': 0,
21 | 'global-require': 0,
22 | 'no-continue': 0,
23 | 'no-multi-assign': 0,
24 | 'no-empty': 0,
25 | 'guard-for-in': 0,
26 | 'camelcase': 0,
27 | 'quote-props': 0,
28 | 'consistent-return': 0,
29 | 'no-confusing-arrow': 0,
30 | 'no-extra-boolean-cast': 0,
31 | 'no-lonely-if': 0,
32 | 'no-underscore-dangle': 0,
33 | 'import/prefer-default-export': 0,
34 | 'import/extensions': ['error', 'always', {
35 | js: 'never',
36 | }],
37 | },
38 | };
39 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | yarn.lock -diff
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | open_collective: vue-ls
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Thumbs.db
2 | .DS_Store
3 | .idea
4 | node_modules
5 | bower_components
6 | npm-debug.log
7 | yarn-error.log
8 | .nyc_output
9 | coverage
10 | reports
11 | selenium-debug.log
12 | selenium-server.log
13 | local.log
14 | sauce_connect.log
15 | tests_output
16 |
--------------------------------------------------------------------------------
/.hound.yml:
--------------------------------------------------------------------------------
1 | jshint:
2 | ignore_file: .jshintignore
3 | config_file: .jshintrc
4 |
--------------------------------------------------------------------------------
/.huskyrc.yml:
--------------------------------------------------------------------------------
1 | hooks:
2 | pre-commit: 'npm run lint'
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .idea
3 | .git
4 | .bowerrc
5 | .gitignore
6 | .travis.yml
7 | .babelrc
8 | .editorconfig
9 | .npmignore
10 | _config.yml
11 | circle.yml
12 | yarn.lock
13 | package.json
14 | .codeclimate.yml
15 | node_modules
16 | bower_components
17 | CHANGELOG.md
18 | test
19 | tests
20 | .hound.yml
21 | .jshintignore
22 | .jshintrc
23 | .nvmrc
24 | Dockerfile
25 | docker-compose.yml
26 | .gitattributes
27 | .dockerignore
28 | build
29 | tests_output
30 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | lts/*
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - "10"
5 | - "12"
6 |
7 | install:
8 | - npm install
9 |
10 | script:
11 | - npm run build
12 | - npm test
13 |
14 | after_success:
15 | - npm run coveralls
16 | - npm run codecov
17 |
18 | notifications:
19 | email: false
20 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 3.2.2
2 | - Upgrade dev dependencies
3 | - Fix tests
4 |
5 | ## 3.0.0
6 | - Rename class and global variable `VueLocalStorage` to `VueStorage`
7 |
8 | ## 2.4.0
9 | - Added session storage
10 | - Added memory storage
11 | - Added the ability to name a variable
12 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at ognichenko.igor@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:8.9.4-alpine as builder
2 |
3 | WORKDIR /app
4 |
5 | RUN npm install -g node-static
6 | COPY ./examples ./examples
7 | COPY ./dist ./dist
8 |
9 | CMD ["static", ".", "-p", "3000", "-a", "0.0.0.0"]
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Igor Ognichenko
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | # vue-ls
28 |
29 | [](https://greenkeeper.io/)
30 |
31 | Vue plugin for work with local storage, session storage and memory storage from Vue context
32 |
33 | [](https://nodei.co/npm/vue-ls/)
34 |
35 | ## jsFiddle Example
36 |
37 | [Vue 1.x](https://jsfiddle.net/Robin_ck/Lvb2ah5p/)
38 |
39 | [Vue 2.x](https://jsfiddle.net/Robin_ck/6x1akv1L/)
40 |
41 | ## Install
42 | #### CDN
43 |
44 | Recommended: https://unpkg.com/vue-ls, which will reflect the latest version as soon as it is published to npm. You can also browse the source of the npm package at https://unpkg.com/vue-ls/
45 |
46 | Also available on jsDelivr or cdnjs, but these two services take some time to sync so the latest release may not be available yet.
47 |
48 | #### NPM
49 |
50 | ``` bash
51 | npm install vue-ls --save
52 | ```
53 |
54 | #### Yarn
55 |
56 | ``` bash
57 | yarn add vue-ls
58 | ```
59 |
60 | #### Bower
61 |
62 | ``` bash
63 | bower install vue-ls --save
64 | ```
65 |
66 | ## Development Setup
67 |
68 | ``` bash
69 | # install dependencies
70 | npm install
71 |
72 | # build dist files
73 | npm run build
74 | ```
75 |
76 | ## Usage
77 |
78 | Vue storage API.
79 |
80 | ``` js
81 | import Storage from 'vue-ls';
82 |
83 | const options = {
84 | namespace: 'vuejs__', // key prefix
85 | name: 'ls', // name variable Vue.[ls] or this.[$ls],
86 | storage: 'local', // storage name session, local, memory
87 | };
88 |
89 | Vue.use(Storage, options);
90 |
91 | //or
92 | //Vue.use(Storage);
93 |
94 | new Vue({
95 | el: '#app',
96 | mounted: function() {
97 | Vue.ls.set('foo', 'boo');
98 | //Set expire for item
99 | Vue.ls.set('foo', 'boo', 60 * 60 * 1000); //expiry 1 hour
100 | Vue.ls.get('foo');
101 | Vue.ls.get('boo', 10); //if not set boo returned default 10
102 |
103 | let callback = (val, oldVal, uri) => {
104 | console.log('localStorage change', val);
105 | }
106 |
107 | Vue.ls.on('foo', callback) //watch change foo key and triggered callback
108 | Vue.ls.off('foo', callback) //unwatch
109 |
110 | Vue.ls.remove('foo');
111 | }
112 | });
113 | ```
114 | Use in js file
115 | ``` js
116 | // localStore.js
117 | import Storage from 'vue-ls';
118 | const options = {
119 | namespace: 'vuejs__', // key prefix
120 | name: 'ls', // name variable Vue.[ls] or this.[$ls],
121 | storage: 'local', // storage name session, local, memory
122 | };
123 |
124 | const { ls } = Storage.useStorage(options)
125 |
126 | export default ls
127 |
128 | // somefile.js
129 | import ls from 'localStore.js';
130 |
131 | ls.set('foo', 'boo');
132 | ls.get('foo');
133 | ```
134 |
135 | #### Global
136 |
137 | - `Vue.ls`
138 |
139 | #### Context
140 | - `this.$ls`
141 |
142 | ## API
143 |
144 | #### `Vue.ls.get(name, def)`
145 |
146 | Returns value under `name` in storage. Internally parses the value from JSON before returning it.
147 |
148 | - `def`: default null, returned if not set `name`.
149 |
150 | #### `Vue.ls.set(name, value, expire)`
151 |
152 | Persists `value` under `name` in storage. Internally converts the `value` to JSON.
153 |
154 | - `expire`: default null, life time in milliseconds `name`
155 |
156 | #### `Vue.ls.remove(name)`
157 |
158 | Removes `name` from storage. Returns `true` if the property was successfully deleted, and `false` otherwise.
159 |
160 | #### `Vue.ls.clear()`
161 |
162 | Clears storage.
163 |
164 | #### `Vue.ls.on(name, callback)`
165 |
166 | Listen for changes persisted against `name` on other tabs. Triggers `callback` when a change occurs, passing the following arguments.
167 |
168 | - `newValue`: the current value for `name` in storage, parsed from the persisted JSON
169 | - `oldValue`: the old value for `name` in storage, parsed from the persisted JSON
170 | - `url`: the url for the tab where the modification came from
171 |
172 | #### `Vue.ls.off(name, callback)`
173 |
174 | Removes a listener previously attached with `Vue.ls.on(name, callback)`.
175 |
176 | ## Testing
177 |
178 | - `npm run test` - run unit test
179 | - `npm run test:browserstack` - run browser test
180 | - `npm run test:browserstack:chrome`
181 | - `npm run test:browserstack:ie`
182 | - `npm run test:browserstack:edge`
183 | - `npm run test:browserstack:firefox`
184 | - `npm run test:browserstack:safari`
185 | - `npm run test:chrome` - run browser test in chrome
186 |
187 | Testing Supported By
188 |
189 |
190 | ## Note
191 | Some browsers don't support the storage event, and most of the browsers that do support it will only call it when the storage is changed by a different window. So, open your page up in two windows. Click the links in one window and you will probably see the event in the other.
192 |
193 | The assumption is that your page will already know all interactions with localStorage in its own window and only needs notification when a different window changes things. This, of course, is a foolish assumption. But.
194 |
195 | ## Other my Vue JS plugins
196 |
197 | | Project | Status | Description |
198 | |---------|--------|-------------|
199 | | [vue-gallery](https://github.com/RobinCK/vue-gallery) |  | VueJS responsive and customizable image and video gallery |
200 | | [vue-popper](https://github.com/RobinCK/vue-popper) |  | VueJS popover component based on popper.js |
201 |
202 | ## Contributors
203 |
204 | ### Code Contributors
205 |
206 | This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
207 |
208 |
209 | ### Financial Contributors
210 |
211 | Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/vue-ls/contribute)]
212 |
213 | #### Individuals
214 |
215 |
216 |
217 | #### Organizations
218 |
219 | Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/vue-ls/contribute)]
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 | ## License
233 | [](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2FRobinCK%2Fvue-ls?ref=badge_large)
234 |
235 | MIT © [Igor Ognichenko](https://github.com/RobinCK)
236 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-ls",
3 | "version": "3.1.0",
4 | "description": "Vue plugin for work with LocalStorage from Vue context",
5 | "main": "dist/vue-ls.js",
6 | "authors": [
7 | "Igor Ognichenko "
8 | ],
9 | "license": "MIT",
10 | "keywords": [
11 | "storage",
12 | "localstorage",
13 | "local-storage",
14 | "vue-localstorage",
15 | "vuejs-localstorage",
16 | "vue-local-storage",
17 | "vuejs-local-storage",
18 | "memorystroage",
19 | "sessionstorage",
20 | "session-storage",
21 | "vue-sessionstorage",
22 | "vuejs-sessionstorage",
23 | "vue-session-storage",
24 | "vuejs-session-storage",
25 | "memory-stroage",
26 | "vue-ls",
27 | "vue",
28 | "vuejs",
29 | "vue-plugin",
30 | "watch",
31 | "es6-modules"
32 | ],
33 | "homepage": "https://github.com/RobinCK/vue-ls",
34 | "ignore": [
35 | ".idea",
36 | ".git",
37 | ".bowerrc",
38 | ".gitignore",
39 | ".travis.yml",
40 | ".babelrc",
41 | ".editorconfig",
42 | ".npmignore",
43 | "_config.yml",
44 | "circle.yml",
45 | "yarn.lock",
46 | "package.json",
47 | ".codeclimate.yml",
48 | "node_modules",
49 | "bower_components",
50 | "CHANGELOG.md",
51 | "test",
52 | "tests",
53 | ".hound.yml",
54 | ".jshintignore",
55 | ".jshintrc",
56 | ".nvmrc",
57 | "Dockerfile",
58 | "docker-compose.yml",
59 | ".gitattributes",
60 | ".dockerignore",
61 | "build"
62 | ]
63 | }
64 |
--------------------------------------------------------------------------------
/build/karma.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | frameworks: ['jasmine'],
3 | basePath: '../',
4 | files: [
5 | 'test/unit/jasmine/*.js'
6 | ],
7 | preprocessors: {
8 | 'src/**/*.js': ['webpack'],
9 | 'test/**/*.js': ['webpack']
10 | },
11 | webpack: require('./webpack.config.js'),
12 | webpackMiddleware: {
13 | noInfo: true
14 | },
15 | plugins: [
16 | 'karma-webpack',
17 | 'karma-chrome-launcher',
18 | 'karma-jasmine'
19 | ]
20 | };
21 |
--------------------------------------------------------------------------------
/build/karma.dev.config.js:
--------------------------------------------------------------------------------
1 | const base = require('./karma.config.js');
2 |
3 | module.exports = function (config) {
4 | config.set(Object.assign(base, {
5 | singleRun: true,
6 | browsers: ['Chrome'],
7 | reporters: ['progress'],
8 | plugins: base.plugins.concat([
9 | 'karma-chrome-launcher'
10 | ])
11 | }))
12 | };
13 |
--------------------------------------------------------------------------------
/build/karma.sauce.config.js:
--------------------------------------------------------------------------------
1 | const base = require('./karma.config.js');
2 | const batches = {
3 | sl_edge_13: {
4 | base: 'SauceLabs',
5 | browserName: 'MicrosoftEdge',
6 | platform: 'Windows 10',
7 | version: '13'
8 | },
9 | sl_chrome: {
10 | base: 'SauceLabs',
11 | browserName: 'chrome',
12 | platform: 'Windows 10'
13 | },
14 | sl_firefox: {
15 | base: 'SauceLabs',
16 | browserName: 'firefox'
17 | },
18 | sl_mac_safari: {
19 | base: 'SauceLabs',
20 | browserName: 'safari',
21 | platform: 'OS X 10.15'
22 | }
23 | };
24 |
25 | module.exports = function(config) {
26 | config.set(Object.assign(base, {
27 | singleRun: true,
28 | browsers: Object.keys(batches),
29 | customLaunchers: batches,
30 | reporters: process.env.CI ? ['dots', 'saucelabs'] : ['progress', 'saucelabs'],
31 | sauceLabs: {
32 | testName: 'vue-ls',
33 | username: process.env.SAUCE_USERNAME,
34 | accessKey: process.env.SAUCE_ACCESS_KEY,
35 | recordScreenshots: false,
36 | sauceLabs: {
37 | testName: 'Vue.js unit tests',
38 | recordScreenshots: false,
39 | connectOptions: {
40 | 'no-ssl-bump-domains': 'all' // Ignore SSL error on Android emulator
41 | },
42 | build: process.env.CIRCLE_BUILD_NUM || process.env.SAUCE_BUILD_ID || Date.now()
43 | },
44 | public: 'public',
45 | build: process.env.BUILD_NUMBER || process.env.BUILD_TAG || process.env.CI_BUILD_NUMBER ||
46 | process.env.CI_BUILD_TAG || process.env.TRAVIS_BUILD_NUMBER || process.env.CIRCLE_BUILD_NUM ||
47 | process.env.DRONE_BUILD_NUMBER|| Date.now()
48 | },
49 | plugins: base.plugins.concat([
50 | 'karma-sauce-launcher'
51 | ])
52 | }))
53 | };
54 |
--------------------------------------------------------------------------------
/build/local.runner.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const Nightwatch = require('nightwatch');
4 | const browserstack = require('browserstack-local');
5 | const serveStatic = require('serve-static');
6 | const connect = require('connect');
7 | const http = require('http');
8 | const path = require('path');
9 | let bs_local;
10 | let httpServer;
11 |
12 | // eslint-disable-next-line
13 | const logger = console.log;
14 |
15 | try {
16 | logger("Start server");
17 |
18 | const app = connect().use(serveStatic(path.resolve('./')));
19 | httpServer = http.createServer(app).listen(9000, () => {
20 | process.mainModule.filename = "./node_modules/nightwatch/bin/nightwatch"
21 | // Code to start browserstack local before start of test
22 |
23 | logger("Connecting local");
24 | Nightwatch.bs_local = bs_local = new browserstack.Local();
25 |
26 | bs_local.start({'key': process.env.BROWSERSTACK_ACCESS_KEY }, (error) => {
27 | if (error) {
28 | throw error;
29 | }
30 |
31 | logger('Connected. Now testing...');
32 |
33 | Nightwatch.cli((argv) => {
34 | Nightwatch.CliRunner(argv)
35 | .setup(null, () => {
36 | // Code to stop browserstack local after end of parallel test
37 | bs_local.stop(() => {});
38 | })
39 | .runTests(() => {
40 | // Code to stop browserstack local after end of single test
41 | bs_local.stop(() => {
42 | logger("Stop Server");
43 | httpServer.close();
44 | });
45 | });
46 | });
47 | });
48 | });
49 | } catch (ex) {
50 | logger('There was an error while starting the test runner:\n\n');
51 | process.stderr.write(ex.stack + '\n');
52 | process.exit(2);
53 | }
54 |
--------------------------------------------------------------------------------
/build/nightwatch.browserstack.config.js:
--------------------------------------------------------------------------------
1 | const nightwatch_config = {
2 | src_folders : [ "test/e2e" ],
3 |
4 | selenium : {
5 | "start_process" : false,
6 | "host" : "hub-cloud.browserstack.com",
7 | "port" : 80
8 | },
9 |
10 | test_settings: {
11 | default: {
12 | desiredCapabilities: {
13 | 'build': 'nightwatch-browserstack',
14 | 'browserstack.user': process.env.BROWSERSTACK_USERNAME || 'BROWSERSTACK_USERNAME',
15 | 'browserstack.key': process.env.BROWSERSTACK_ACCESS_KEY || 'BROWSERSTACK_ACCESS_KEY',
16 | 'browserstack.debug': true,
17 | 'browserstack.local': true,
18 | 'browser': 'chrome'
19 | }
20 | },
21 | bstack_edge: {
22 | 'desiredCapabilities': {
23 | 'browserName': 'MicrosoftEdge',
24 | 'os': 'Windows',
25 | 'os_version': '10',
26 | 'browser': 'Edge',
27 | 'resolution': '1024x768'
28 | }
29 | },
30 | bstack_chrome: {
31 | desiredCapabilities: {
32 | 'browserName': 'Chrome',
33 | 'os': 'Windows',
34 | 'os_version': '10',
35 | 'browser': 'Chrome',
36 | 'resolution': '1024x768'
37 | }
38 | },
39 | bstack_firefox: {
40 | desiredCapabilities: {
41 | 'browserName': 'Firefox',
42 | 'os': 'Windows',
43 | 'os_version': '7',
44 | 'browser': 'Firefox',
45 | 'resolution': '1024x768'
46 | }
47 | },
48 | bstack_firefox_osx: {
49 | desiredCapabilities: {
50 | 'browserName': 'Firefox',
51 | 'os': 'OS X',
52 | 'os_version': 'El Capitan',
53 | 'browser': 'Firefox',
54 | 'resolution': '1024x768'
55 | }
56 | },
57 | bstack_safari: {
58 | desiredCapabilities: {
59 | 'browserName': 'Safari',
60 | 'os': 'OS X',
61 | 'os_version': 'Sierra',
62 | 'browser': 'Safari',
63 | 'resolution': '1024x768'
64 | }
65 | }
66 | }
67 | };
68 |
69 | // Code to copy seleniumhost/port into test settings
70 | for (let i in nightwatch_config.test_settings) {
71 | const config = nightwatch_config.test_settings[i];
72 |
73 | config['selenium_host'] = nightwatch_config.selenium.host;
74 | config['selenium_port'] = nightwatch_config.selenium.port;
75 | }
76 |
77 | module.exports = nightwatch_config;
78 |
--------------------------------------------------------------------------------
/build/nightwatch.config.js:
--------------------------------------------------------------------------------
1 | const seleniumServer = require('selenium-server');
2 |
3 | module.exports = {
4 | 'src_folders': [
5 | 'test/e2e'
6 | ],
7 | 'output_folder': 'reports',
8 | 'test_workers': false,
9 |
10 | 'selenium' : {
11 | 'start_process' : true,
12 | 'server_path' : seleniumServer.path,
13 | 'port' : 4444,
14 | 'cli_args' : {
15 | 'webdriver.chrome.driver' : './node_modules/.bin/chromedriver',
16 | }
17 | },
18 |
19 | 'test_settings': {
20 | 'default': {
21 | 'selenium_port': 4444,
22 | 'selenium_host': '127.0.0.1',
23 | 'silent': true,
24 | 'desiredCapabilities': {
25 | 'build': 'nightwatch',
26 | 'project': 'vue-ls'
27 | }
28 | },
29 | 'chrome': {
30 | 'desiredCapabilities': {
31 | 'browserName': 'chrome',
32 | 'resolution': '1024x768'
33 | }
34 | },
35 | }
36 | };
37 |
--------------------------------------------------------------------------------
/build/prerelease.sh:
--------------------------------------------------------------------------------
1 | npm run lint
2 | npm run test
3 | npm run test:unit
4 | npm run test:e2e
5 | npm run build
6 |
--------------------------------------------------------------------------------
/build/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import {uglify} from 'rollup-plugin-uglify';
3 | import localResolve from 'rollup-plugin-local-resolve';
4 |
5 | export default {
6 | input: 'src/index.js',
7 | plugins: [
8 | localResolve(),
9 | babel({
10 | babelrc: false,
11 | presets: [
12 | ["@babel/preset-env", {
13 | modules: false,
14 | targets: {
15 | browsers: [
16 | "> 1%",
17 | "Chrome >= 14",
18 | "Safari >= 4",
19 | "Firefox >= 4",
20 | "Opera >= 10",
21 | "Edge >= 41",
22 | "ie >= 9",
23 | "iOS >= 6",
24 | "ChromeAndroid >= 4",
25 | "OperaMobile >= 12"
26 | ]
27 | }
28 | }]
29 | ],
30 | runtimeHelpers: true,
31 | externalHelpers: false,
32 | exclude: 'node_modules/**',
33 | }),
34 | (process.env.NODE_ENV === 'production' && uglify())
35 | ],
36 | output: {
37 | file: process.env.NODE_ENV === 'production' ? 'dist/vue-ls.min.js' : 'dist/vue-ls.js',
38 | format: 'umd',
39 | name: 'VueStorage',
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/build/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 |
3 | module.exports = {
4 | mode: 'production',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.js$/,
9 | loader: 'babel-loader',
10 | exclude: /node_modules/
11 | }
12 | ]
13 | },
14 | plugins: [
15 | new webpack.DefinePlugin({
16 | 'process.env': {
17 | NODE_ENV: '"development"',
18 | TRANSITION_DURATION: 50,
19 | TRANSITION_BUFFER: 10
20 | }
21 | })
22 | ],
23 | devtool: 'inline-source-map'
24 | };
25 |
--------------------------------------------------------------------------------
/dist/vue-ls.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3 | typeof define === 'function' && define.amd ? define(factory) :
4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.VueStorage = factory());
5 | }(this, (function () { 'use strict';
6 |
7 | function _classCallCheck(instance, Constructor) {
8 | if (!(instance instanceof Constructor)) {
9 | throw new TypeError("Cannot call a class as a function");
10 | }
11 | }
12 |
13 | function _defineProperties(target, props) {
14 | for (var i = 0; i < props.length; i++) {
15 | var descriptor = props[i];
16 | descriptor.enumerable = descriptor.enumerable || false;
17 | descriptor.configurable = true;
18 | if ("value" in descriptor) descriptor.writable = true;
19 | Object.defineProperty(target, descriptor.key, descriptor);
20 | }
21 | }
22 |
23 | function _createClass(Constructor, protoProps, staticProps) {
24 | if (protoProps) _defineProperties(Constructor.prototype, protoProps);
25 | if (staticProps) _defineProperties(Constructor, staticProps);
26 | return Constructor;
27 | }
28 |
29 | function _defineProperty(obj, key, value) {
30 | if (key in obj) {
31 | Object.defineProperty(obj, key, {
32 | value: value,
33 | enumerable: true,
34 | configurable: true,
35 | writable: true
36 | });
37 | } else {
38 | obj[key] = value;
39 | }
40 |
41 | return obj;
42 | }
43 |
44 | function ownKeys(object, enumerableOnly) {
45 | var keys = Object.keys(object);
46 |
47 | if (Object.getOwnPropertySymbols) {
48 | var symbols = Object.getOwnPropertySymbols(object);
49 | if (enumerableOnly) symbols = symbols.filter(function (sym) {
50 | return Object.getOwnPropertyDescriptor(object, sym).enumerable;
51 | });
52 | keys.push.apply(keys, symbols);
53 | }
54 |
55 | return keys;
56 | }
57 |
58 | function _objectSpread2(target) {
59 | for (var i = 1; i < arguments.length; i++) {
60 | var source = arguments[i] != null ? arguments[i] : {};
61 |
62 | if (i % 2) {
63 | ownKeys(Object(source), true).forEach(function (key) {
64 | _defineProperty(target, key, source[key]);
65 | });
66 | } else if (Object.getOwnPropertyDescriptors) {
67 | Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
68 | } else {
69 | ownKeys(Object(source)).forEach(function (key) {
70 | Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
71 | });
72 | }
73 | }
74 |
75 | return target;
76 | }
77 |
78 | /* eslint class-methods-use-this: off */
79 | var ls = {};
80 |
81 | var MemoryStorageInterface =
82 | /*#__PURE__*/
83 | function () {
84 | function MemoryStorageInterface() {
85 | _classCallCheck(this, MemoryStorageInterface);
86 |
87 | Object.defineProperty(this, 'length', {
88 | /**
89 | * Define length property
90 | *
91 | * @return {number}
92 | */
93 | get: function get() {
94 | return Object.keys(ls).length;
95 | }
96 | });
97 | }
98 | /**
99 | * Get item
100 | *
101 | * @param {string} name
102 | * @returns {*}
103 | */
104 |
105 |
106 | _createClass(MemoryStorageInterface, [{
107 | key: "getItem",
108 | value: function getItem(name) {
109 | return name in ls ? ls[name] : null;
110 | }
111 | /**
112 | * Set item
113 | *
114 | * @param {string} name
115 | * @param {*} value
116 | * @returns {boolean}
117 | */
118 |
119 | }, {
120 | key: "setItem",
121 | value: function setItem(name, value) {
122 | ls[name] = value;
123 | return true;
124 | }
125 | /**
126 | * Remove item
127 | *
128 | * @param {string} name
129 | * @returns {boolean}
130 | */
131 |
132 | }, {
133 | key: "removeItem",
134 | value: function removeItem(name) {
135 | var found = name in ls;
136 |
137 | if (found) {
138 | return delete ls[name];
139 | }
140 |
141 | return false;
142 | }
143 | /**
144 | * Clear storage
145 | *
146 | * @returns {boolean}
147 | */
148 |
149 | }, {
150 | key: "clear",
151 | value: function clear() {
152 | ls = {};
153 | return true;
154 | }
155 | /**
156 | * Get item by key
157 | *
158 | * @param {number} index
159 | * @returns {*}
160 | */
161 |
162 | }, {
163 | key: "key",
164 | value: function key(index) {
165 | var keys = Object.keys(ls);
166 | return typeof keys[index] !== 'undefined' ? keys[index] : null;
167 | }
168 | }]);
169 |
170 | return MemoryStorageInterface;
171 | }();
172 |
173 | var MemoryStorage = new MemoryStorageInterface();
174 |
175 | var listeners = {};
176 | /**
177 | * Event class
178 | */
179 |
180 | var WebStorageEvent =
181 | /*#__PURE__*/
182 | function () {
183 | function WebStorageEvent() {
184 | _classCallCheck(this, WebStorageEvent);
185 | }
186 |
187 | _createClass(WebStorageEvent, null, [{
188 | key: "on",
189 |
190 | /**
191 | * Add storage change event
192 | *
193 | * @param {string} name
194 | * @param {Function} callback
195 | */
196 | value: function on(name, callback) {
197 | if (typeof listeners[name] === 'undefined') {
198 | listeners[name] = [];
199 | }
200 |
201 | listeners[name].push(callback);
202 | }
203 | /**
204 | * Remove storage change event
205 | *
206 | * @param {string} name
207 | * @param {Function} callback
208 | */
209 |
210 | }, {
211 | key: "off",
212 | value: function off(name, callback) {
213 | if (listeners[name].length) {
214 | listeners[name].splice(listeners[name].indexOf(callback), 1);
215 | } else {
216 | listeners[name] = [];
217 | }
218 | }
219 | /**
220 | * Emit event
221 | *
222 | * @param {Object} event
223 | */
224 |
225 | }, {
226 | key: "emit",
227 | value: function emit(event) {
228 | var e = event || window.event;
229 |
230 | var getValue = function getValue(data) {
231 | try {
232 | return JSON.parse(data).value;
233 | } catch (err) {
234 | return data;
235 | }
236 | };
237 |
238 | var fire = function fire(listener) {
239 | var newValue = getValue(e.newValue);
240 | var oldValue = getValue(e.oldValue);
241 | listener(newValue, oldValue, e.url || e.uri);
242 | };
243 |
244 | if (typeof e === 'undefined' || typeof e.key === 'undefined') {
245 | return;
246 | }
247 |
248 | var all = listeners[e.key];
249 |
250 | if (typeof all !== 'undefined') {
251 | all.forEach(fire);
252 | }
253 | }
254 | }]);
255 |
256 | return WebStorageEvent;
257 | }();
258 |
259 | /**
260 | * Storage Bridge
261 | */
262 |
263 | var WebStorage =
264 | /*#__PURE__*/
265 | function () {
266 | /**
267 | * @param {Object} storage
268 | */
269 | function WebStorage(storage) {
270 | _classCallCheck(this, WebStorage);
271 |
272 | this.storage = storage;
273 | this.options = {
274 | namespace: '',
275 | events: ['storage']
276 | };
277 | Object.defineProperty(this, 'length', {
278 | /**
279 | * Define length property
280 | *
281 | * @return {number}
282 | */
283 | get: function get() {
284 | return this.storage.length;
285 | }
286 | });
287 |
288 | if (typeof window !== 'undefined') {
289 | for (var i in this.options.events) {
290 | if (window.addEventListener) {
291 | window.addEventListener(this.options.events[i], WebStorageEvent.emit, false);
292 | } else if (window.attachEvent) {
293 | window.attachEvent("on".concat(this.options.events[i]), WebStorageEvent.emit);
294 | } else {
295 | window["on".concat(this.options.events[i])] = WebStorageEvent.emit;
296 | }
297 | }
298 | }
299 | }
300 | /**
301 | * Set Options
302 | *
303 | * @param {Object} options
304 | */
305 |
306 |
307 | _createClass(WebStorage, [{
308 | key: "setOptions",
309 | value: function setOptions() {
310 | var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
311 | this.options = Object.assign(this.options, options);
312 | }
313 | /**
314 | * Set item
315 | *
316 | * @param {string} name
317 | * @param {*} value
318 | * @param {number} expire - seconds
319 | */
320 |
321 | }, {
322 | key: "set",
323 | value: function set(name, value) {
324 | var expire = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
325 | var stringifyValue = JSON.stringify({
326 | value: value,
327 | expire: expire !== null ? new Date().getTime() + expire : null
328 | });
329 | this.storage.setItem(this.options.namespace + name, stringifyValue);
330 | }
331 | /**
332 | * Get item
333 | *
334 | * @param {string} name
335 | * @param {*} def - default value
336 | * @returns {*}
337 | */
338 |
339 | }, {
340 | key: "get",
341 | value: function get(name) {
342 | var def = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
343 | var item = this.storage.getItem(this.options.namespace + name);
344 |
345 | if (item !== null) {
346 | try {
347 | var data = JSON.parse(item);
348 |
349 | if (data.expire === null) {
350 | return data.value;
351 | }
352 |
353 | if (data.expire >= new Date().getTime()) {
354 | return data.value;
355 | }
356 |
357 | this.remove(name);
358 | } catch (err) {
359 | return def;
360 | }
361 | }
362 |
363 | return def;
364 | }
365 | /**
366 | * Get item by key
367 | *
368 | * @param {number} index
369 | * @return {*}
370 | */
371 |
372 | }, {
373 | key: "key",
374 | value: function key(index) {
375 | return this.storage.key(index);
376 | }
377 | /**
378 | * Remove item
379 | *
380 | * @param {string} name
381 | * @return {boolean}
382 | */
383 |
384 | }, {
385 | key: "remove",
386 | value: function remove(name) {
387 | return this.storage.removeItem(this.options.namespace + name);
388 | }
389 | /**
390 | * Clear storage
391 | */
392 |
393 | }, {
394 | key: "clear",
395 | value: function clear() {
396 | if (this.length === 0) {
397 | return;
398 | }
399 |
400 | var removedKeys = [];
401 |
402 | for (var i = 0; i < this.length; i++) {
403 | var key = this.storage.key(i);
404 | var regexp = new RegExp("^".concat(this.options.namespace, ".+"), 'i');
405 |
406 | if (regexp.test(key) === false) {
407 | continue;
408 | }
409 |
410 | removedKeys.push(key);
411 | }
412 |
413 | for (var _key in removedKeys) {
414 | this.storage.removeItem(removedKeys[_key]);
415 | }
416 | }
417 | /**
418 | * Add storage change event
419 | *
420 | * @param {string} name
421 | * @param {Function} callback
422 | */
423 |
424 | }, {
425 | key: "on",
426 | value: function on(name, callback) {
427 | WebStorageEvent.on(this.options.namespace + name, callback);
428 | }
429 | /**
430 | * Remove storage change event
431 | *
432 | * @param {string} name
433 | * @param {Function} callback
434 | */
435 |
436 | }, {
437 | key: "off",
438 | value: function off(name, callback) {
439 | WebStorageEvent.off(this.options.namespace + name, callback);
440 | }
441 | }]);
442 |
443 | return WebStorage;
444 | }();
445 |
446 | var _global = typeof window !== 'undefined' ? window : global || {};
447 | /**
448 | * @type {{install: (function(Object, Object): WebStorage)}}
449 | */
450 |
451 |
452 | var VueStorage = {
453 | /**
454 | * use storage
455 | *
456 | * @param {Object} options
457 | * @returns {WebStorage}
458 | */
459 | useStorage: function useStorage(options) {
460 | var _options = _objectSpread2(_objectSpread2({}, options), {}, {
461 | storage: options.storage || 'local',
462 | name: options.name || 'ls'
463 | });
464 |
465 | if (_options.storage && ['memory', 'local', 'session'].indexOf(_options.storage) === -1) {
466 | throw new Error("Vue-ls: Storage \"".concat(_options.storage, "\" is not supported"));
467 | }
468 |
469 | var store = null;
470 |
471 | switch (_options.storage) {
472 | // eslint-disable-line
473 | case 'local':
474 | try {
475 | store = 'localStorage' in _global ? _global.localStorage : null;
476 | } catch (e) {// In some situations the browser will throw a security exception when attempting to access
477 | }
478 |
479 | break;
480 |
481 | case 'session':
482 | try {
483 | store = 'sessionStorage' in _global ? _global.sessionStorage : null;
484 | } catch (e) {// In some situations the browser will throw a security exception when attempting to access
485 | }
486 |
487 | break;
488 |
489 | case 'memory':
490 | store = MemoryStorage;
491 | break;
492 | }
493 |
494 | if (!store) {
495 | store = MemoryStorage; // eslint-disable-next-line
496 |
497 | console.error("Vue-ls: Storage \"".concat(_options.storage, "\" is not supported your system, use memory storage"));
498 | }
499 |
500 | var ls = new WebStorage(store);
501 | ls.setOptions(Object.assign(ls.options, {
502 | namespace: ''
503 | }, _options || {}));
504 | return {
505 | ls: ls,
506 | _options: _options
507 | };
508 | },
509 |
510 | /**
511 | * Install plugin
512 | *
513 | * @param {Object} Vue
514 | * @param {Object} options
515 | * @returns {WebStorage}
516 | */
517 | install: function install(Vue) {
518 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
519 |
520 | var _this$useStorage = this.useStorage(options),
521 | ls = _this$useStorage.ls,
522 | _options = _this$useStorage._options;
523 |
524 | Vue[_options.name] = ls; // eslint-disable-line
525 |
526 | Object.defineProperty(Vue.prototype || Vue.config.globalProperties, "$".concat(_options.name), {
527 | /**
528 | * Define $ls property
529 | *
530 | * @return {WebStorage}
531 | */
532 | get: function get() {
533 | return ls;
534 | }
535 | });
536 | }
537 | }; // eslint-disable-next-line
538 |
539 | _global.VueStorage = VueStorage;
540 |
541 | return VueStorage;
542 |
543 | })));
544 |
--------------------------------------------------------------------------------
/dist/vue-ls.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).VueStorage=t()}(this,function(){"use strict";function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){for(var n=0;n=(new Date).getTime())return o.value;this.remove(e)}catch(e){return t}return t}},{key:"key",value:function(e){return this.storage.key(e)}},{key:"remove",value:function(e){return this.storage.removeItem(this.options.namespace+e)}},{key:"clear",value:function(){if(0!==this.length){for(var e=[],t=0;t
2 |
3 |
4 |
5 |
6 |
7 | Vue-ls Synchronized counter example
8 |
9 |
10 | Synchronized tab counter
11 |
12 | localStorage:
{{localCounter}}
13 | sessionCounter: {{sessionCounter}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp');
2 | const http = require('http');
3 | const connect = require('connect');
4 | const serveStatic = require('serve-static');
5 | const nightwatch = require('gulp-nightwatch');
6 | const gutil = require('gulp-util');
7 | const args = require('get-gulp-args')();
8 |
9 | let httpServer;
10 |
11 | function logger (message) {
12 | gutil.log(gutil.colors.green(message));
13 | }
14 |
15 | gulp.task('http:start', (done) => {
16 | logger('Start http server');
17 |
18 | const app = connect().use(serveStatic('./'));
19 | httpServer = http.createServer(app).listen(9000, done);
20 | });
21 |
22 | gulp.task('http:stop', (done) => {
23 | httpServer.close();
24 | logger('Shutdown http server');
25 | done();
26 | });
27 |
28 | gulp.task('e2e', gulp.series(['http:start'], () => {
29 | const env = args.env;
30 |
31 | return gulp.src('./build/nightwatch.config.js')
32 | .pipe(nightwatch({
33 | configFile: './build/nightwatch.config.js',
34 | cliArgs: ['--env ' + env]
35 | }));
36 | }));
37 |
38 | gulp.task('test', gulp.series(['e2e', 'http:stop']));
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-ls",
3 | "version": "4.2.0",
4 | "description": "Vue plugin for work with LocalStorage from Vue context",
5 | "main": "dist/vue-ls.js",
6 | "jsnext:main": "src/index.js",
7 | "unpkg": "dist/vue-ls.min.js",
8 | "files": [
9 | "src",
10 | "dist/*.js"
11 | ],
12 | "scripts": {
13 | "build": "rollup -c ./build/rollup.config.js --name VueStorage && NODE_ENV=production rollup -c ./build/rollup.config.js --name VueStorage",
14 | "test": "NODE_ENV=test nyc ava",
15 | "test:browserstack": "node ./build/local.runner.js -c ./build/nightwatch.browserstack.config.js",
16 | "test:browserstack:chrome": "npm run test:browserstack --env bstack_chrome",
17 | "test:browserstack:edge": "npm run test:browserstack --env bstack_edge",
18 | "test:browserstack:firefox": "npm run test:browserstack --env bstack_firefox,bstack_firefox_osx",
19 | "test:browserstack:safari": "npm run test:browserstack --env bstack_safari",
20 | "test:browserstack:all": "npm run test:browserstack -- --env bstack_safari,bstack_chrome,bstack_firefox,bstack_firefox_osx,bstack_edge",
21 | "test:e2e": "gulp test --env chrome",
22 | "test:unit": "karma start build/karma.dev.config.js",
23 | "test:sauce": "karma start build/karma.sauce.config.js",
24 | "lint": "eslint ./",
25 | "report": "npm test && nyc report --reporter=html",
26 | "coveralls": "nyc report --reporter=text-lcov | coveralls",
27 | "codecov": "nyc report --reporter=lcovonly && codecov -t $CODECOV_TOKEN",
28 | "postinstall": "opencollective-postinstall || true"
29 | },
30 | "keywords": [
31 | "storage",
32 | "localstorage",
33 | "local-storage",
34 | "vue-localstorage",
35 | "vuejs-localstorage",
36 | "vue-local-storage",
37 | "vuejs-local-storage",
38 | "memorystroage",
39 | "sessionstorage",
40 | "session-storage",
41 | "vue-sessionstorage",
42 | "vuejs-sessionstorage",
43 | "vue-session-storage",
44 | "vuejs-session-storage",
45 | "memory-stroage",
46 | "vue-ls",
47 | "vue",
48 | "vuejs",
49 | "vue-plugin",
50 | "watch",
51 | "es6-modules"
52 | ],
53 | "repository": {
54 | "type": "git",
55 | "url": "git+https://github.com/RobinCK/vue-ls.git"
56 | },
57 | "author": "Igor Ognichenko ",
58 | "bugs": {
59 | "url": "https://github.com/RobinCK/vue-ls/issues"
60 | },
61 | "engines": {
62 | "node": ">=6.11.5"
63 | },
64 | "homepage": "https://github.com/RobinCK/vue-ls#readme",
65 | "license": "MIT",
66 | "devDependencies": {
67 | "@ava/babel": "^1.0.1",
68 | "@babel/core": "^7.12.10",
69 | "@babel/plugin-syntax-dynamic-import": "^7.8.3",
70 | "@babel/plugin-transform-modules-commonjs": "^7.12.1",
71 | "@babel/plugin-transform-runtime": "^7.12.10",
72 | "@babel/polyfill": "^7.12.1",
73 | "@babel/preset-env": "^7.12.11",
74 | "@babel/register": "^7.12.10",
75 | "@babel/runtime": "^7.12.5",
76 | "ava": "^3.15.0",
77 | "babel-eslint": "^10.1.0",
78 | "babel-loader": "^8.2.2",
79 | "browserstack-local": "^1.4.8",
80 | "chromedriver": "^87.0.5",
81 | "connect": "^3.7.0",
82 | "coveralls": "^3.1.0",
83 | "eslint": "^7.17.0",
84 | "eslint-config-airbnb-base": "^14.2.1",
85 | "eslint-plugin-import": "^2.22.1",
86 | "eslint-plugin-node": "^11.1.0",
87 | "get-gulp-args": "^0.0.1",
88 | "gulp": "4.0.2",
89 | "gulp-nightwatch": "1.1.0",
90 | "gulp-util": "^3.0.8",
91 | "husky": "^4.3.7",
92 | "jasmine": "^3.6.3",
93 | "jasmine-core": "^3.6.0",
94 | "karma": "^5.2.3",
95 | "karma-chrome-launcher": "^3.1.0",
96 | "karma-jasmine": "^4.0.1",
97 | "karma-sauce-launcher": "^4.3.4",
98 | "karma-webpack": "^4.0.2",
99 | "mock-browser": "^0.92.14",
100 | "nightwatch": "^1.5.1",
101 | "nyc": "^15.1.0",
102 | "rollup": "^2.36.1",
103 | "rollup-plugin-babel": "^4.4.0",
104 | "rollup-plugin-local-resolve": "^1.0.7",
105 | "rollup-plugin-uglify": "^6.0.4",
106 | "selenium-server": "^3.14.0",
107 | "serve-static": "^1.14.1",
108 | "trim-right": "^1.0.1",
109 | "vue": "^2.6.12",
110 | "webpack": "^4.29.3"
111 | },
112 | "semistandard": {
113 | "ignore": [
114 | "node_modules",
115 | "bower_components",
116 | "build",
117 | "dist",
118 | "test"
119 | ]
120 | },
121 | "ava": {
122 | "babel": {
123 | "extensions": [
124 | "js"
125 | ]
126 | },
127 | "tap": true,
128 | "files": [
129 | "./test/unit/ava/*.js"
130 | ],
131 | "require": [
132 | "@babel/register",
133 | "@babel/polyfill"
134 | ]
135 | },
136 | "dependencies": {
137 | "opencollective-postinstall": "^2.0.2"
138 | },
139 | "collective": {
140 | "type": "opencollective",
141 | "url": "https://opencollective.com/vue-ls"
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { MemoryStorage, WebStorage } from './storage';
2 |
3 | // eslint-disable-next-line
4 | const _global = (typeof window !== 'undefined' ? window : global || {});
5 |
6 | /**
7 | * @type {{install: (function(Object, Object): WebStorage)}}
8 | */
9 | const VueStorage = {
10 | /**
11 | * use storage
12 | *
13 | * @param {Object} options
14 | * @returns {WebStorage}
15 | */
16 | useStorage(options) {
17 | const _options = {
18 | ...options,
19 | storage: options.storage || 'local',
20 | name: options.name || 'ls',
21 | };
22 |
23 | if (_options.storage && ['memory', 'local', 'session'].indexOf(_options.storage) === -1) {
24 | throw new Error(`Vue-ls: Storage "${_options.storage}" is not supported`);
25 | }
26 |
27 | let store = null;
28 |
29 | switch(_options.storage) { // eslint-disable-line
30 | case 'local':
31 | try {
32 | store = 'localStorage' in _global
33 | ? _global.localStorage
34 | : null
35 | ;
36 | } catch (e) {
37 | // In some situations the browser will
38 | // throw a security exception when attempting to access
39 | }
40 | break;
41 |
42 | case 'session':
43 | try {
44 | store = 'sessionStorage' in _global
45 | ? _global.sessionStorage
46 | : null
47 | ;
48 | } catch (e) {
49 | // In some situations the browser will
50 | // throw a security exception when attempting to access
51 | }
52 | break;
53 | case 'memory':
54 | store = MemoryStorage;
55 | break;
56 | }
57 |
58 | if (!store) {
59 | store = MemoryStorage;
60 | // eslint-disable-next-line
61 | console.error(`Vue-ls: Storage "${_options.storage}" is not supported your system, use memory storage`);
62 | }
63 |
64 | const ls = new WebStorage(store);
65 |
66 | ls.setOptions(Object.assign(ls.options, {
67 | namespace: '',
68 | }, _options || {}));
69 |
70 | return { ls, _options };
71 | },
72 | /**
73 | * Install plugin
74 | *
75 | * @param {Object} Vue
76 | * @param {Object} options
77 | * @returns {WebStorage}
78 | */
79 | install(Vue, options = {}) {
80 | const { ls, _options } = this.useStorage(options);
81 | Vue[_options.name] = ls; // eslint-disable-line
82 |
83 | Object.defineProperty(Vue.prototype || Vue.config.globalProperties, `$${_options.name}`, {
84 | /**
85 | * Define $ls property
86 | *
87 | * @return {WebStorage}
88 | */
89 | get() {
90 | return ls;
91 | },
92 | });
93 | },
94 | };
95 |
96 | // eslint-disable-next-line
97 | _global.VueStorage = VueStorage;
98 |
99 | export default VueStorage;
100 |
--------------------------------------------------------------------------------
/src/storage/MemoryStorage.js:
--------------------------------------------------------------------------------
1 | /* eslint class-methods-use-this: off */
2 |
3 | let ls = {};
4 |
5 | class MemoryStorageInterface {
6 | constructor() {
7 | Object.defineProperty(this, 'length', {
8 | /**
9 | * Define length property
10 | *
11 | * @return {number}
12 | */
13 | get() {
14 | return Object.keys(ls).length;
15 | },
16 | });
17 | }
18 |
19 | /**
20 | * Get item
21 | *
22 | * @param {string} name
23 | * @returns {*}
24 | */
25 | getItem(name) {
26 | return name in ls ? ls[name] : null;
27 | }
28 |
29 | /**
30 | * Set item
31 | *
32 | * @param {string} name
33 | * @param {*} value
34 | * @returns {boolean}
35 | */
36 | setItem(name, value) {
37 | ls[name] = value;
38 |
39 | return true;
40 | }
41 |
42 | /**
43 | * Remove item
44 | *
45 | * @param {string} name
46 | * @returns {boolean}
47 | */
48 | removeItem(name) {
49 | const found = name in ls;
50 |
51 | if (found) {
52 | return delete ls[name];
53 | }
54 |
55 | return false;
56 | }
57 |
58 | /**
59 | * Clear storage
60 | *
61 | * @returns {boolean}
62 | */
63 | clear() {
64 | ls = {};
65 |
66 | return true;
67 | }
68 |
69 | /**
70 | * Get item by key
71 | *
72 | * @param {number} index
73 | * @returns {*}
74 | */
75 | key(index) {
76 | const keys = Object.keys(ls);
77 |
78 | return typeof keys[index] !== 'undefined' ? keys[index] : null;
79 | }
80 | }
81 |
82 | const MemoryStorage = new MemoryStorageInterface();
83 |
84 | export { MemoryStorage };
85 |
--------------------------------------------------------------------------------
/src/storage/WebStorage.js:
--------------------------------------------------------------------------------
1 | import { WebStorageEvent } from './WebStorageEvent';
2 |
3 | /**
4 | * Storage Bridge
5 | */
6 | export class WebStorage {
7 | /**
8 | * @param {Object} storage
9 | */
10 | constructor(storage) {
11 | this.storage = storage;
12 | this.options = {
13 | namespace: '',
14 | events: ['storage'],
15 | };
16 |
17 | Object.defineProperty(this, 'length', {
18 | /**
19 | * Define length property
20 | *
21 | * @return {number}
22 | */
23 | get() {
24 | return this.storage.length;
25 | },
26 | });
27 |
28 | if (typeof window !== 'undefined') {
29 | for (const i in this.options.events) {
30 | if (window.addEventListener) {
31 | window.addEventListener(this.options.events[i], WebStorageEvent.emit, false);
32 | } else if (window.attachEvent) {
33 | window.attachEvent(`on${this.options.events[i]}`, WebStorageEvent.emit);
34 | } else {
35 | window[`on${this.options.events[i]}`] = WebStorageEvent.emit;
36 | }
37 | }
38 | }
39 | }
40 |
41 | /**
42 | * Set Options
43 | *
44 | * @param {Object} options
45 | */
46 | setOptions(options = {}) {
47 | this.options = Object.assign(this.options, options);
48 | }
49 |
50 | /**
51 | * Set item
52 | *
53 | * @param {string} name
54 | * @param {*} value
55 | * @param {number} expire - seconds
56 | */
57 | set(name, value, expire = null) {
58 | const stringifyValue = JSON.stringify({
59 | value,
60 | expire: expire !== null ? new Date().getTime() + expire : null,
61 | });
62 |
63 | this.storage.setItem(this.options.namespace + name, stringifyValue);
64 | }
65 |
66 | /**
67 | * Get item
68 | *
69 | * @param {string} name
70 | * @param {*} def - default value
71 | * @returns {*}
72 | */
73 | get(name, def = null) {
74 | const item = this.storage.getItem(this.options.namespace + name);
75 |
76 | if (item !== null) {
77 | try {
78 | const data = JSON.parse(item);
79 |
80 | if (data.expire === null) {
81 | return data.value;
82 | }
83 |
84 | if (data.expire >= new Date().getTime()) {
85 | return data.value;
86 | }
87 |
88 | this.remove(name);
89 | } catch (err) {
90 | return def;
91 | }
92 | }
93 |
94 | return def;
95 | }
96 |
97 | /**
98 | * Get item by key
99 | *
100 | * @param {number} index
101 | * @return {*}
102 | */
103 | key(index) {
104 | return this.storage.key(index);
105 | }
106 |
107 | /**
108 | * Remove item
109 | *
110 | * @param {string} name
111 | * @return {boolean}
112 | */
113 | remove(name) {
114 | return this.storage.removeItem(this.options.namespace + name);
115 | }
116 |
117 | /**
118 | * Clear storage
119 | */
120 | clear() {
121 | if (this.length === 0) {
122 | return;
123 | }
124 |
125 | const removedKeys = [];
126 |
127 | for (let i = 0; i < this.length; i++) {
128 | const key = this.storage.key(i);
129 | const regexp = new RegExp(`^${this.options.namespace}.+`, 'i');
130 |
131 | if (regexp.test(key) === false) {
132 | continue;
133 | }
134 |
135 | removedKeys.push(key);
136 | }
137 |
138 | for (const key in removedKeys) {
139 | this.storage.removeItem(removedKeys[key]);
140 | }
141 | }
142 |
143 | /**
144 | * Add storage change event
145 | *
146 | * @param {string} name
147 | * @param {Function} callback
148 | */
149 | on(name, callback) {
150 | WebStorageEvent.on(this.options.namespace + name, callback);
151 | }
152 |
153 | /**
154 | * Remove storage change event
155 | *
156 | * @param {string} name
157 | * @param {Function} callback
158 | */
159 | off(name, callback) {
160 | WebStorageEvent.off(this.options.namespace + name, callback);
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/storage/WebStorageEvent.js:
--------------------------------------------------------------------------------
1 | const listeners = {};
2 |
3 | /**
4 | * Event class
5 | */
6 | export class WebStorageEvent {
7 | /**
8 | * Add storage change event
9 | *
10 | * @param {string} name
11 | * @param {Function} callback
12 | */
13 | static on(name, callback) {
14 | if (typeof listeners[name] === 'undefined') {
15 | listeners[name] = [];
16 | }
17 |
18 | listeners[name].push(callback);
19 | }
20 |
21 | /**
22 | * Remove storage change event
23 | *
24 | * @param {string} name
25 | * @param {Function} callback
26 | */
27 | static off(name, callback) {
28 | if (listeners[name].length) {
29 | listeners[name].splice(listeners[name].indexOf(callback), 1);
30 | } else {
31 | listeners[name] = [];
32 | }
33 | }
34 |
35 | /**
36 | * Emit event
37 | *
38 | * @param {Object} event
39 | */
40 | static emit(event) {
41 | const e = event || window.event;
42 |
43 | const getValue = (data) => {
44 | try {
45 | return JSON.parse(data).value;
46 | } catch (err) {
47 | return data;
48 | }
49 | };
50 |
51 | const fire = (listener) => {
52 | const newValue = getValue(e.newValue);
53 | const oldValue = getValue(e.oldValue);
54 |
55 | listener(newValue, oldValue, e.url || e.uri);
56 | };
57 |
58 | if (typeof e === 'undefined' || typeof e.key === 'undefined') {
59 | return;
60 | }
61 |
62 | const all = listeners[e.key];
63 |
64 | if (typeof all !== 'undefined') {
65 | all.forEach(fire);
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/storage/index.js:
--------------------------------------------------------------------------------
1 | export * from './MemoryStorage';
2 | export * from './WebStorage';
3 | export * from './WebStorageEvent';
4 |
--------------------------------------------------------------------------------
/test/e2e/counter.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'Counter test' : function (browser) {
3 | browser
4 | .url("http://localhost:9000/examples/counter/index.html")
5 | .assert.containsText("#count", "0", "Start value: 0")
6 | .click('#increment')
7 | .assert.containsText("#count", "1", "Value after increment: 0 -> 1")
8 | .click('#increment')
9 | .assert.containsText("#count", "2", "Value after increment: 1 -> 2")
10 | .click('#decrement')
11 | .assert.containsText("#count", "1", "Value after decrement: 2 -> 1")
12 | .end();
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/test/unit/ava/eventAttach.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import './helpers/setupIEBrowserEnv'
5 | import Ls from '../../../src/index';
6 | import { WebStorageEvent } from '../../../src/storage';
7 |
8 | Vue.use(Ls);
9 |
10 | test('Add/Remove event', (t) => {
11 | t.plan(2);
12 |
13 | Vue.ls.on('item_one_test', () => {});
14 | Vue.ls.on('item_two_test', () => {});
15 | Vue.ls.on('item_two_test', () => {});
16 | Vue.ls.on('item_three_test', (val, oldVal) => {
17 | t.is(val, 'val');
18 | t.is(oldVal, 'old_val');
19 | });
20 | Vue.ls.off('item_two_test', () => {});
21 | Vue.ls.off('item_one_test', () => {});
22 |
23 | WebStorageEvent.emit({
24 | key: 'item_three_test',
25 | newValue: JSON.stringify({ value: 'val', expire: null }),
26 | oldValue: JSON.stringify({ value: 'old_val', expire: null }),
27 | });
28 | WebStorageEvent.emit({
29 | key: 'item_undefined_test',
30 | newValue: JSON.stringify({ value: 'val', expire: null }),
31 | oldValue: JSON.stringify({ value: 'old_val', expire: null }),
32 | });
33 | WebStorageEvent.emit();
34 | });
35 |
36 |
--------------------------------------------------------------------------------
/test/unit/ava/eventWindow.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import './helpers/setupOldBrowserEnv'
5 | import Ls from '../../../src/index';
6 | import { WebStorageEvent } from '../../../src/storage';
7 |
8 | Vue.use(Ls);
9 |
10 | test('Add/Remove event', (t) => {
11 | t.plan(2);
12 |
13 | Vue.ls.on('item_one_test', () => {});
14 | Vue.ls.on('item_two_test', () => {});
15 | Vue.ls.on('item_two_test', () => {});
16 | Vue.ls.on('item_three_test', (val, oldVal) => {
17 | t.is(val, 'val');
18 | t.is(oldVal, 'old_val');
19 | });
20 | Vue.ls.off('item_two_test', () => {});
21 | Vue.ls.off('item_one_test', () => {});
22 |
23 | WebStorageEvent.emit({
24 | key: 'item_three_test',
25 | newValue: JSON.stringify({ value: 'val', expire: null }),
26 | oldValue: JSON.stringify({ value: 'old_val', expire: null }),
27 | });
28 | WebStorageEvent.emit({
29 | key: 'item_undefined_test',
30 | newValue: JSON.stringify({ value: 'val', expire: null }),
31 | oldValue: JSON.stringify({ value: 'old_val', expire: null }),
32 | });
33 | WebStorageEvent.emit();
34 | });
35 |
36 |
--------------------------------------------------------------------------------
/test/unit/ava/events.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import './helpers/setupBrowserEnv'
5 | import Ls from '../../../src/index';
6 | import { WebStorageEvent } from '../../../src/storage';
7 |
8 | Vue.use(Ls);
9 |
10 | test.beforeEach(() => {
11 | window.localStorage.clear();
12 | });
13 |
14 | //mock-browser not supported storage event
15 | test('Add/Remove event', (t) => {
16 | t.plan(4);
17 |
18 | Vue.ls.on('item_one_test', () => {});
19 | Vue.ls.on('item_two_test', () => {});
20 | Vue.ls.on('item_two_test', () => {});
21 | Vue.ls.on('item_three_test', (val, oldVal) => {
22 | t.is(val, 'val');
23 | t.is(oldVal, 'old_val');
24 | });
25 | Vue.ls.off('item_two_test', () => {});
26 | Vue.ls.off('item_one_test', () => {});
27 | Vue.ls.off('item_one_test', () => {});
28 |
29 | WebStorageEvent.emit({
30 | key: 'item_three_test',
31 | newValue: JSON.stringify({ value: 'val', expire: null }),
32 | oldValue: JSON.stringify({ value: 'old_val', expire: null }),
33 | });
34 | WebStorageEvent.emit({
35 | key: 'item_undefined_test',
36 | newValue: JSON.stringify({ value: 'val', expire: null }),
37 | oldValue: JSON.stringify({ value: 'old_val', expire: null }),
38 | });
39 | WebStorageEvent.emit({
40 | key: 'item_three_test',
41 | newValue: 'val',
42 | oldValue: 'old_val',
43 | });
44 | WebStorageEvent.emit();
45 | });
46 |
47 |
--------------------------------------------------------------------------------
/test/unit/ava/helpers/setupBrowserEnv.js:
--------------------------------------------------------------------------------
1 | const MockBrowser = require('mock-browser').mocks.MockBrowser;
2 |
3 | global.document = MockBrowser.createDocument();
4 | global.window = MockBrowser.createWindow();
5 |
--------------------------------------------------------------------------------
/test/unit/ava/helpers/setupIEBrowserEnv.js:
--------------------------------------------------------------------------------
1 | const MockBrowser = require('mock-browser').mocks.MockBrowser;
2 |
3 | global.document = MockBrowser.createDocument();
4 | global.window = MockBrowser.createWindow();
5 | global.window.addEventListener = null;
6 | global.window.attachEvent = function(name, callback) {
7 | callback.call();
8 | };
9 |
--------------------------------------------------------------------------------
/test/unit/ava/helpers/setupOldBrowserEnv.js:
--------------------------------------------------------------------------------
1 | const MockBrowser = require('mock-browser').mocks.MockBrowser;
2 |
3 | global.document = MockBrowser.createDocument();
4 | global.window = MockBrowser.createWindow();
5 | global.window.addEventListener = null;
6 |
--------------------------------------------------------------------------------
/test/unit/ava/localStorage.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import './helpers/setupBrowserEnv'
5 | import Ls from '../../../src/index';
6 |
7 | const namespace = 'test__';
8 |
9 | Vue.use(Ls, {
10 | namespace: namespace,
11 | storage: 'local',
12 | });
13 |
14 | test.beforeEach(() => {
15 | window.localStorage.clear();
16 | });
17 |
18 | test('Set item', (t) => {
19 | window.localStorage.clear(); // fix for ava-beta-8
20 | Vue.ls.set('set_item_test', 'val');
21 |
22 | t.is(JSON.parse(window.localStorage.getItem(`${namespace}set_item_test`)).value, 'val');
23 | });
24 |
25 | test('Get key by index', (t) => {
26 | window.localStorage.clear(); // fix for ava-beta-8
27 | Vue.ls.set('key_item_one_test', 'val_one');
28 | Vue.ls.set('key_item_two_test', 'val_two');
29 |
30 | t.is(Vue.ls.key(1), `${namespace}key_item_two_test`);
31 | });
32 |
33 | test('Get item', (t) => {
34 | window.localStorage.clear(); // fix for ava-beta-8
35 | window.localStorage.setItem(`${namespace}get_item_test`, JSON.stringify({value: 'val', expire: null}));
36 |
37 | t.is(Vue.ls.get('get_item_test'), 'val');
38 | });
39 |
40 | test('Get item try', (t) => {
41 | window.localStorage.clear(); // fix for ava-beta-8
42 | window.localStorage.setItem(`${namespace}get_item_test`, ';');
43 |
44 | t.is(Vue.ls.get('get_item_test', 1), 1);
45 | });
46 |
47 | test('Get default value', (t) => {
48 | window.localStorage.clear(); // fix for ava-beta-8
49 | t.is(Vue.ls.get('undefined_item_test', 10), 10);
50 | });
51 |
52 | test('Expired item', (t) => {
53 | window.localStorage.clear(); // fix for ava-beta-8
54 | Vue.ls.set('expired_item_test', 'val', -1);
55 |
56 | t.is(Vue.ls.get('expired_item_test'), null);
57 | });
58 |
59 | test('Not expired item', (t) => {
60 | window.localStorage.clear(); // fix for ava-beta-8
61 | Vue.ls.set('expired_item_test', 'val', 1);
62 |
63 | t.is(Vue.ls.get('expired_item_test'), 'val');
64 | });
65 |
66 | test('Remove item', (t) => {
67 | window.localStorage.clear(); // fix for ava-beta-8
68 | window.localStorage.setItem(`${namespace}remove_item_test`, JSON.stringify({value: 'val', expire: null}));
69 | Vue.ls.remove('remove_item_test');
70 |
71 | t.is(window.localStorage.getItem(`${namespace}remove_item_test`), null);
72 | });
73 |
74 | test('Clear', (t) => {
75 | window.localStorage.clear(); // fix for ava-beta-8
76 | Vue.ls.set('item_test', 'val');
77 | Vue.ls.clear();
78 |
79 | t.is(Vue.ls.get('item_test'), null);
80 | });
81 |
82 | test('Empty clear', (t) => {
83 | window.localStorage.clear(); // fix for ava-beta-8
84 | Vue.ls.clear();
85 | t.is(Vue.ls.length, 0);
86 | });
87 |
88 | test('Clear namespace', (t) => {
89 | window.localStorage.clear(); // fix for ava-beta-8
90 | t.plan(2);
91 |
92 | Vue.ls.set('item_test', 'val');
93 | window.localStorage.setItem('item_test', JSON.stringify({value: 'val', expire: null}));
94 |
95 | Vue.ls.clear();
96 |
97 | t.is(Vue.ls.get('item_test'), null);
98 | t.is(JSON.parse(window.localStorage.getItem(`item_test`)).value, 'val');
99 | });
100 |
101 | test('Get length', (t) => {
102 | window.localStorage.clear(); // fix for ava-beta-8
103 | Vue.ls.set('item_one_test', 'val');
104 | Vue.ls.set('item_two_test', 'val');
105 |
106 | t.is(Vue.ls.length, 2);
107 | });
108 |
109 | test('Serialized data', (t) => {
110 | window.localStorage.clear(); // fix for ava-beta-8
111 | t.plan(5);
112 |
113 | Vue.ls.set('item_object', {foo: 'boo'});
114 | Vue.ls.set('item_array', [2, 3, 4, 5]);
115 | Vue.ls.set('item_number', 6);
116 | Vue.ls.set('item_string', '7');
117 | Vue.ls.set('item_boolean', false);
118 |
119 | t.deepEqual(Vue.ls.get('item_object'), {foo: 'boo'});
120 | t.deepEqual(Vue.ls.get('item_array'), [2, 3, 4, 5]);
121 | t.is(Vue.ls.get('item_number'), 6);
122 | t.is(Vue.ls.get('item_string'), '7');
123 | t.is(Vue.ls.get('item_boolean'), false);
124 | });
125 |
126 | //mock-browser not supported storage event
127 | test('Add/Remove event', (t) => {
128 | window.localStorage.clear(); // fix for ava-beta-8
129 | Vue.ls.on('item_one_test', () => {});
130 | Vue.ls.on('item_two_test', () => {});
131 | Vue.ls.on('item_two_test', () => {});
132 | Vue.ls.off('item_two_test', () => {});
133 | Vue.ls.off('item_one_test', () => {});
134 | t.is(true, true);
135 | });
136 |
137 | test('Plugin context', (t) => {
138 | window.localStorage.clear(); // fix for ava-beta-8
139 | new Vue({
140 | created () {
141 | this.$ls.set('item_test', 'val');
142 |
143 | t.is(this.$ls.get('item_test'), 'val');
144 | }
145 | });
146 | });
147 |
--------------------------------------------------------------------------------
/test/unit/ava/memoryFallback.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import Ls from '../../../src/index';
5 |
6 | const namespace = 'test__';
7 |
8 | Vue.use(Ls, {
9 | namespace: namespace
10 | });
11 |
12 | test.beforeEach(() => {
13 | Vue.ls.storage.clear();
14 | });
15 |
16 | test('Set/Get item', (t) => {
17 | Vue.ls.storage.clear(); // fix for ava-beta-8
18 | Vue.ls.set('set_item_test', 'val');
19 |
20 | t.is(Vue.ls.get('set_item_test'), 'val');
21 | });
22 |
23 | test('Remove item', (t) => {
24 | Vue.ls.storage.clear(); // fix for ava-beta-8
25 | Vue.ls.set('remove_item_test', 'val');
26 | Vue.ls.remove('remove_item_test');
27 |
28 | t.is(Vue.ls.get('remove_item_test'), null);
29 | });
30 |
31 | test('Removing non-existent itset_item_testen', (t) => {
32 | Vue.ls.storage.clear(); // fix for ava-beta-8
33 | t.is(Vue.ls.remove('remove_item_test'), false);
34 | });
35 |
36 | test('Get key by index', (t) => {
37 | Vue.ls.storage.clear(); // fix for ava-beta-8
38 | t.plan(2);
39 |
40 | Vue.ls.set('key_item_one_test', 'val_one');
41 | Vue.ls.set('key_item_two_test', 'val_two');
42 |
43 | t.is(Vue.ls.key(1), `${namespace}key_item_two_test`);
44 | t.is(Vue.ls.key(100), null);
45 | });
46 |
47 | test('Clear', (t) => {
48 | Vue.ls.storage.clear(); // fix for ava-beta-8
49 | Vue.ls.set('item_test', 'val');
50 | Vue.ls.clear();
51 |
52 | t.is(Vue.ls.get('item_test'), null);
53 | });
54 |
--------------------------------------------------------------------------------
/test/unit/ava/memoryStorage.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import './helpers/setupBrowserEnv'
5 | import Ls from '../../../src/index';
6 |
7 | const namespace = 'test__';
8 |
9 | Vue.use(Ls, {
10 | namespace: namespace,
11 | storage: 'memory',
12 | name: 'memory'
13 | });
14 |
15 | test.beforeEach(() => {
16 | Vue.memory.storage.clear();
17 | });
18 |
19 | test('Set item', (t) => {
20 | Vue.memory.storage.clear(); // fix for ava-beta-8
21 | Vue.memory.set('set_item_test', 'val');
22 |
23 | t.is(JSON.parse(Vue.memory.storage.getItem(`${namespace}set_item_test`)).value, 'val');
24 | });
25 |
26 | test('Get key by index', (t) => {
27 | Vue.memory.storage.clear(); // fix for ava-beta-8
28 | Vue.memory.set('key_item_one_test', 'val_one');
29 | Vue.memory.set('key_item_two_test', 'val_two');
30 |
31 | t.is(Vue.memory.key(1), `${namespace}key_item_two_test`);
32 | });
33 |
34 | test('Get item', (t) => {
35 | Vue.memory.storage.clear(); // fix for ava-beta-8
36 | Vue.memory.storage.setItem(`${namespace}get_item_test`, JSON.stringify({value: 'val', expire: null}));
37 |
38 | t.is(Vue.memory.get('get_item_test'), 'val');
39 | });
40 |
41 | test('Get item try', (t) => {
42 | Vue.memory.storage.clear(); // fix for ava-beta-8
43 | Vue.memory.storage.setItem(`${namespace}get_item_test`, ';');
44 |
45 | t.is(Vue.memory.get('get_item_test', 1), 1);
46 | });
47 |
48 | test('Get default value', (t) => {
49 | Vue.memory.storage.clear(); // fix for ava-beta-8
50 | t.is(Vue.memory.get('undefined_item_test', 10), 10);
51 | });
52 |
53 | test('Expired item', (t) => {
54 | Vue.memory.storage.clear(); // fix for ava-beta-8
55 | Vue.memory.set('expired_item_test', 'val', -1);
56 |
57 | t.is(Vue.memory.get('expired_item_test'), null);
58 | });
59 |
60 | test('Not expired item', (t) => {
61 | Vue.memory.storage.clear(); // fix for ava-beta-8
62 | Vue.memory.set('expired_item_test', 'val', 1);
63 |
64 | t.is(Vue.memory.get('expired_item_test'), 'val');
65 | });
66 |
67 | test('Remove item', (t) => {
68 | Vue.memory.storage.clear(); // fix for ava-beta-8
69 | Vue.memory.storage.setItem(`${namespace}remove_item_test`, JSON.stringify({value: 'val', expire: null}));
70 | Vue.memory.remove('remove_item_test');
71 |
72 | t.is(Vue.memory.storage.getItem(`${namespace}remove_item_test`), null);
73 | });
74 |
75 | test('Clear', (t) => {
76 | Vue.memory.storage.clear(); // fix for ava-beta-8
77 | Vue.memory.set('item_test', 'val');
78 | Vue.memory.clear();
79 |
80 | t.is(Vue.memory.get('item_test'), null);
81 | });
82 |
83 | test('Empty clear', (t) => {
84 | Vue.memory.storage.clear(); // fix for ava-beta-8
85 | Vue.memory.clear();
86 | t.is(Vue.memory.length, 0);
87 | });
88 |
89 | test('Clear namespace', (t) => {
90 | Vue.memory.storage.clear(); // fix for ava-beta-8
91 | t.plan(2);
92 |
93 | Vue.memory.set('item_test', 'val');
94 | Vue.memory.storage.setItem('item_test', JSON.stringify({value: 'val', expire: null}));
95 |
96 | Vue.memory.clear();
97 |
98 | t.is(Vue.memory.get('item_test'), null);
99 | t.is(JSON.parse(Vue.memory.storage.getItem(`item_test`)).value, 'val');
100 | });
101 |
102 | test('Get length', (t) => {
103 | Vue.memory.storage.clear(); // fix for ava-beta-8
104 | Vue.memory.set('item_one_test', 'val');
105 | Vue.memory.set('item_two_test', 'val');
106 |
107 | t.is(Vue.memory.length, 2);
108 | });
109 |
110 | test('Serialized data', (t) => {
111 | Vue.memory.storage.clear(); // fix for ava-beta-8
112 | t.plan(5);
113 |
114 | Vue.memory.set('item_object', {foo: 'boo'});
115 | Vue.memory.set('item_array', [2, 3, 4, 5]);
116 | Vue.memory.set('item_number', 6);
117 | Vue.memory.set('item_string', '7');
118 | Vue.memory.set('item_boolean', false);
119 |
120 | t.deepEqual(Vue.memory.get('item_object'), {foo: 'boo'});
121 | t.deepEqual(Vue.memory.get('item_array'), [2, 3, 4, 5]);
122 | t.is(Vue.memory.get('item_number'), 6);
123 | t.is(Vue.memory.get('item_string'), '7');
124 | t.is(Vue.memory.get('item_boolean'), false);
125 | });
126 |
127 | test('Plugin context', (t) => {
128 | Vue.memory.storage.clear(); // fix for ava-beta-8
129 | new Vue({
130 | created () {
131 | this.$memory.set('item_test', 'val');
132 |
133 | t.is(this.$memory.get('item_test'), 'val');
134 | }
135 | });
136 | });
137 |
--------------------------------------------------------------------------------
/test/unit/ava/sessionStorage.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import './helpers/setupBrowserEnv'
5 | import Ls from '../../../src/index';
6 |
7 | const namespace = 'test__';
8 |
9 | Vue.use(Ls, {
10 | namespace: namespace,
11 | storage: 'session',
12 | name: 'session'
13 | });
14 |
15 | test.beforeEach(() => {
16 | window.sessionStorage.clear();
17 | });
18 |
19 | test('Set item', (t) => {
20 | window.sessionStorage.clear(); // fix for ava-beta-8
21 | Vue.session.set('set_item_test', 'val');
22 |
23 | t.is(JSON.parse(window.sessionStorage.getItem(`${namespace}set_item_test`)).value, 'val');
24 | });
25 |
26 | test('Get key by index', (t) => {
27 | window.sessionStorage.clear(); // fix for ava-beta-8
28 | Vue.session.set('key_item_one_test', 'val_one');
29 | Vue.session.set('key_item_two_test', 'val_two');
30 |
31 | t.is(Vue.session.key(1), `${namespace}key_item_two_test`);
32 | });
33 |
34 | test('Get item', (t) => {
35 | window.sessionStorage.clear(); // fix for ava-beta-8
36 | window.sessionStorage.setItem(`${namespace}get_item_test`, JSON.stringify({value: 'val', expire: null}));
37 |
38 | t.is(Vue.session.get('get_item_test'), 'val');
39 | });
40 |
41 | test('Get item try', (t) => {
42 | window.sessionStorage.clear(); // fix for ava-beta-8
43 | window.sessionStorage.setItem(`${namespace}get_item_test`, ';');
44 |
45 | t.is(Vue.session.get('get_item_test', 1), 1);
46 | });
47 |
48 | test('Get default value', (t) => {
49 | window.sessionStorage.clear(); // fix for ava-beta-8
50 | t.is(Vue.session.get('undefined_item_test', 10), 10);
51 | });
52 |
53 | test('Expired item', (t) => {
54 | window.sessionStorage.clear(); // fix for ava-beta-8
55 | Vue.session.set('expired_item_test', 'val', -1);
56 |
57 | t.is(Vue.session.get('expired_item_test'), null);
58 | });
59 |
60 | test('Not expired item', (t) => {
61 | window.sessionStorage.clear(); // fix for ava-beta-8
62 | Vue.session.set('expired_item_test', 'val', 1);
63 |
64 | t.is(Vue.session.get('expired_item_test'), 'val');
65 | });
66 |
67 | test('Remove item', (t) => {
68 | window.sessionStorage.clear(); // fix for ava-beta-8
69 | window.sessionStorage.setItem(`${namespace}remove_item_test`, JSON.stringify({value: 'val', expire: null}));
70 | Vue.session.remove('remove_item_test');
71 |
72 | t.is(window.sessionStorage.getItem(`${namespace}remove_item_test`), null);
73 | });
74 |
75 | test('Clear', (t) => {
76 | window.sessionStorage.clear(); // fix for ava-beta-8
77 | Vue.session.set('item_test', 'val');
78 | Vue.session.clear();
79 |
80 | t.is(Vue.session.get('item_test'), null);
81 | });
82 |
83 | test('Empty clear', (t) => {
84 | window.sessionStorage.clear(); // fix for ava-beta-8
85 | Vue.session.clear();
86 | t.is(Vue.session.length, 0);
87 | });
88 |
89 | test('Clear namespace', (t) => {
90 | window.sessionStorage.clear(); // fix for ava-beta-8
91 | t.plan(2);
92 |
93 | Vue.session.set('item_test', 'val');
94 | window.sessionStorage.setItem('item_test', JSON.stringify({value: 'val', expire: null}));
95 |
96 | Vue.session.clear();
97 |
98 | t.is(Vue.session.get('item_test'), null);
99 | t.is(JSON.parse(window.sessionStorage.getItem(`item_test`)).value, 'val');
100 | });
101 |
102 | test('Get length', (t) => {
103 | window.sessionStorage.clear(); // fix for ava-beta-8
104 | Vue.session.set('item_one_test', 'val');
105 | Vue.session.set('item_two_test', 'val');
106 |
107 | t.is(Vue.session.length, 2);
108 | });
109 |
110 | test('Serialized data', (t) => {
111 | window.sessionStorage.clear(); // fix for ava-beta-8
112 | t.plan(5);
113 |
114 | Vue.session.set('item_object', {foo: 'boo'});
115 | Vue.session.set('item_array', [2, 3, 4, 5]);
116 | Vue.session.set('item_number', 6);
117 | Vue.session.set('item_string', '7');
118 | Vue.session.set('item_boolean', false);
119 |
120 | t.deepEqual(Vue.session.get('item_object'), {foo: 'boo'});
121 | t.deepEqual(Vue.session.get('item_array'), [2, 3, 4, 5]);
122 | t.is(Vue.session.get('item_number'), 6);
123 | t.is(Vue.session.get('item_string'), '7');
124 | t.is(Vue.session.get('item_boolean'), false);
125 | });
126 |
127 | test('Plugin context', (t) => {
128 | window.sessionStorage.clear(); // fix for ava-beta-8
129 | new Vue({
130 | created () {
131 | this.$session.set('item_test', 'val');
132 |
133 | t.is(this.$session.get('item_test'), 'val');
134 | }
135 | });
136 | });
137 |
--------------------------------------------------------------------------------
/test/unit/ava/unknownStorage.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import test from 'ava';
3 |
4 | import Ls from '../../../src/index';
5 |
6 | test('Test exception storage', (t) => {
7 | try {
8 | Vue.use(Ls, {
9 | storage: 'unknown',
10 | });
11 | } catch(err) {
12 | t.is(err.message, 'Vue-ls: Storage "unknown" is not supported');
13 | }
14 | });
15 |
--------------------------------------------------------------------------------
/test/unit/jasmine/index.js:
--------------------------------------------------------------------------------
1 | import Ls from '../../../src/index';
2 | import Vue from 'vue';
3 |
4 | const namespace = 'test__';
5 |
6 | Vue.use(Ls, {
7 | namespace: namespace
8 | });
9 |
10 | describe("Plugin test", () => {
11 | beforeEach(() => {
12 | window.localStorage.clear();
13 | });
14 |
15 | it("Set item", () => {
16 | Vue.ls.set('set_item_test', 'val');
17 |
18 | expect(JSON.parse(window.localStorage.getItem(`${namespace}set_item_test`)).value).toBe('val');
19 | });
20 |
21 | it('Get item', () => {
22 | window.localStorage.setItem(`${namespace}get_item_test`, JSON.stringify({value: 'val', expire: null}));
23 |
24 | expect(Vue.ls.get('get_item_test')).toBe('val');
25 | });
26 |
27 | it('Get default value', () => {
28 | expect(Vue.ls.get('undefined_item_test', 10)).toBe(10);
29 | });
30 |
31 | it('Expired item', () => {
32 | Vue.ls.set('expired_item_test', 'val', -1);
33 |
34 | expect(Vue.ls.get('expired_item_test')).toBe(null);
35 | });
36 |
37 | it('Not expired item', () => {
38 | Vue.ls.set('expired_item_test', 'val', 1);
39 |
40 | expect(Vue.ls.get('expired_item_test')).toBe('val');
41 | });
42 |
43 | it('Remove item', () => {
44 | window.localStorage.setItem(`${namespace}remove_item_test`, JSON.stringify({value: 'val', expire: null}));
45 | Vue.ls.remove('remove_item_test');
46 |
47 | expect(window.localStorage.getItem(`${namespace}remove_item_test`)).toBe(null);
48 | });
49 |
50 |
51 | it('Clear', () => {
52 | Vue.ls.set('item_test', 'val');
53 | Vue.ls.clear();
54 |
55 | expect(Vue.ls.get('item_test')).toBe(null);
56 | });
57 |
58 | it('Empty clear', () => {
59 | Vue.ls.clear();
60 | expect(Vue.ls.length).toBe(0);
61 | });
62 |
63 | it('Clear namespace', () => {
64 | Vue.ls.set('item_test', 'val');
65 | window.localStorage.setItem('item_test', JSON.stringify({value: 'val', expire: null}));
66 |
67 | Vue.ls.clear();
68 |
69 | expect(Vue.ls.get('item_test')).toBe(null);
70 | expect(JSON.parse(window.localStorage.getItem(`item_test`)).value).toBe('val');
71 | });
72 |
73 | it('Get length', () => {
74 | Vue.ls.set('item_one_test', 'val');
75 | Vue.ls.set('item_two_test', 'val');
76 |
77 | expect(Vue.ls.length).toBe(2);
78 | });
79 |
80 | it('Serialized data', () => {
81 | Vue.ls.set('item_object', {foo: 'boo'});
82 | Vue.ls.set('item_array', [2, 3, 4, 5]);
83 | Vue.ls.set('item_number', 6);
84 | Vue.ls.set('item_string', '7');
85 | Vue.ls.set('item_boolean', false);
86 |
87 | expect(Vue.ls.get('item_object')).toEqual({foo: 'boo'});
88 | expect(Vue.ls.get('item_array')).toEqual([2, 3, 4, 5]);
89 | expect(Vue.ls.get('item_number')).toEqual(6);
90 | expect(Vue.ls.get('item_string')).toEqual('7');
91 | expect(Vue.ls.get('item_boolean')).toEqual(false);
92 | });
93 | });
94 |
--------------------------------------------------------------------------------