├── LICENSE.txt
├── README.md
├── bower.json
├── tests
├── .gitignore
├── bower.json
├── test-amd.html
├── test-angular.html
├── test-global.html
├── test-jquery.html
└── test.html
├── xlocalstorage.html
└── xlocalstorage.js
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT LICENSE
2 | Copyright 2015 YanagiEiichi, yanagieiichi@web-tinker.com
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## XLocalStorage
2 |
3 | ###### Cross subdomain localStorage (base on JSON-RPC 2.0 protocol)
4 |
5 | #### Usage
6 |
7 | ###### First, you should copy the `xlocalstorage.html` to your root domain and root path.
8 |
9 | ##### Callback Style
10 |
11 | ```html
12 |
13 |
26 | ```
27 |
28 | ##### Promise Style (require ES6 or Angular or jQuery)
29 |
30 | ```html
31 |
32 |
45 | ```
46 |
47 | #### Install
48 |
49 | ```
50 | bower install xlocalstorage
51 | ```
52 |
53 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "XLocalStorage",
3 | "main": "XLocalStorage.js",
4 | "version": "0.1.0",
5 | "homepage": "https://github.com/YanagiEiichi/XLocalStorage",
6 | "authors": [
7 | "YanagiEiichi "
8 | ],
9 | "description": "Cross subdomain localStorage (base on JSON-RPC 2.0 protocol)",
10 | "keywords": [
11 | "localStorage",
12 | "Cross",
13 | "Origin",
14 | "Cross",
15 | "Domain"
16 | ],
17 | "license": "MIT",
18 | "ignore": [
19 | "**/.*",
20 | "node_modules",
21 | "bower_components",
22 | "test",
23 | "tests"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/tests/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components
2 |
3 |
--------------------------------------------------------------------------------
/tests/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demos",
3 | "version": "0.0.1",
4 | "homepage": "https://github.com/YanagiEiichi/XLocalStorage",
5 | "authors": [
6 | "YanagiEiichi "
7 | ],
8 | "license": "MIT",
9 | "ignore": [
10 | "**/.*",
11 | "node_modules",
12 | "bower_components",
13 | "test",
14 | "tests"
15 | ],
16 | "dependencies": {
17 | "angular": "~1.2",
18 | "requirejs": "~2.1.16",
19 | "jquery": "~2.1.3",
20 | "tester": "~0.0.0"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tests/test-amd.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
25 |
26 |
--------------------------------------------------------------------------------
/tests/test-angular.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/test-global.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
23 |
24 |
--------------------------------------------------------------------------------
/tests/test-jquery.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
25 |
26 |
--------------------------------------------------------------------------------
/tests/test.html:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
--------------------------------------------------------------------------------
/xlocalstorage.html:
--------------------------------------------------------------------------------
1 |
31 |
32 |
--------------------------------------------------------------------------------
/xlocalstorage.js:
--------------------------------------------------------------------------------
1 | void function() {
2 | 'use strict';
3 |
4 | var NAME = 'xLocalStorage';
5 | var heap = [ null ];
6 |
7 | // REFERENCE: https://github.com/YanagiEiichi/getrootdomain.js
8 | var root = location.protocol + '//' + function() {
9 | // Create a random stream
10 | var rnd = '';
11 | while(rnd.length < 32) rnd += Math.floor(Math.random() * 2821109907456).toString(36);
12 | rnd = rnd.slice(0, 32);
13 | // Split current host
14 | var chips = location.host.split('.');
15 | // Try to write cookie
16 | var result = chips.pop();
17 | while(!~document.cookie.indexOf(rnd) && chips.length) {
18 | result = chips.pop() + '.' + result;
19 | document.cookie = rnd + '=; Domain=' + result;
20 | }
21 | // Remove cookie
22 | document.cookie = rnd + '=; Domain=' + result + '; Expires=Thu, 01 Jan 1970 00:00:00 GMT';
23 | return result;
24 | }();
25 |
26 | // Install iframe to document head
27 | var head = document.documentElement.firstChild;
28 | var iframe = document.createElement('iframe');
29 | iframe.src = root + '/' + NAME.toLowerCase() + '.html';
30 | head.insertBefore(iframe, head.firstChild);
31 |
32 | // Simple Promise
33 | var SimplePromise = function(resolver) {
34 | var handler, result, isResolved;
35 | resolver(function($result) {
36 | isResolved = true;
37 | result = $result;
38 | if(handler) handler(result);
39 | });
40 | this.then = function(callback) {
41 | if(isResolved) return callback(result);
42 | handler = callback;
43 | };
44 | };
45 |
46 | // Promise for iframe.onload
47 | var proxy = {
48 | holder: new SimplePromise(function(resolve) {
49 | iframe.onload = resolve;
50 | }),
51 | postMessage: function(data, origin) {
52 | this.holder.then(function() {
53 | iframe.contentWindow.postMessage(data, origin);
54 | });
55 | }
56 | };
57 |
58 | // Post message and return a thenable object
59 | var postMessage = function(method, params) {
60 | if(typeof params[params.length - 1] === 'function') {
61 | var inlineCallback = params.pop();
62 | }
63 | var promise = new xLocalStorage.Promise(function(resolve) {
64 | proxy.postMessage(JSON.stringify({
65 | jsonrpc: '2.0',
66 | method: NAME + '.' + method,
67 | params: params,
68 | id: heap.push(resolve) - 1
69 | }), root);
70 | });
71 | promise.then(inlineCallback);
72 | // Don't return promise, because SimplePromise is not standard
73 | return promise instanceof SimplePromise ? void 0 : promise;
74 | };
75 |
76 | // Build Methods
77 | var xLocalStorage = { Promise: window.Promise || SimplePromise };
78 | var buildMethod = function(base, name) {
79 | base[name] = function() {
80 | return postMessage(name, Array.prototype.slice.call(arguments));
81 | }
82 | };
83 | var methods = [ 'setItem', 'getItem', 'removeItem', 'clear', 'key', 'length' ];
84 | for(var i = 0; i < methods.length; i++) {
85 | buildMethod(xLocalStorage, methods[i]);
86 | }
87 |
88 | // Set message listener
89 | var onmessage = function(message) {
90 | var origin = message.origin;
91 |
92 | // Permission checking
93 | if(origin !== root) throw new Error('Permission Denied');
94 |
95 | // Parse JSON-RPC 2.0
96 | var frame = JSON.parse(message.data);
97 | if(frame.jsonrpc != '2.0') return;
98 | if(frame.params) return;
99 | var names = frame.method ? frame.method.split('.') : [];
100 | if(names[0] !== NAME) return;
101 |
102 | // Call the handler function
103 | heap[frame.id](frame.result);
104 | heap[frame.id] = null;
105 | };
106 | if(window.addEventListener) {
107 | addEventListener('message', onmessage);
108 | } else if(window.attachEvent) {
109 | attachEvent('onmessage', onmessage);
110 | }
111 |
112 | switch(true) {
113 | case typeof define === 'function' && !!define.amd: // For AMD
114 | return define(function() { return xLocalStorage; });
115 | case typeof angular === 'object' && !!angular.version: // For Angular
116 | return angular.module('xLocalStorage', []).factory(NAME, ['$q', function($q) {
117 | xLocalStorage.Promise = function(resolver) {
118 | var defer = $q.defer();
119 | resolver(defer.resolve, defer.reject);
120 | return defer.promise;
121 | };
122 | return xLocalStorage;
123 | }]);
124 | case typeof jQuery === 'function' && typeof jQuery.Deferred === 'function': // For jQuery
125 | xLocalStorage.Promise = function(resolver) {
126 | var defer = new jQuery.Deferred;
127 | resolver(defer.resolve, defer.reject);
128 | return defer.promise();
129 | };
130 | jQuery.xLocalStorage = xLocalStorage;
131 | break;
132 | default: // For Global and compatible with IE8
133 | -[1,] || execScript('var ' + NAME);
134 | window[NAME] = xLocalStorage;
135 | }
136 | }();
137 |
138 |
--------------------------------------------------------------------------------