├── 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 | --------------------------------------------------------------------------------