-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathstash.js
178 lines (169 loc) · 6.1 KB
/
stash.js
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*! Stash v1.2.4 MIT/GPL2 @rezitech */
(function (win, ls, doc) {
// Returns whether a constructor is the constructor of a value
function isType(Ctor, val) {
return val !== undefined && val !== null && val.constructor === Ctor;
}
// Returns a safely quoted string
function quoteStr(str) {
return "'" +
String(str)
.replace(/\\/g, '\\\\')
.replace(/'/g, "\\'")
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t') +
"'";
}
// Return an element from HTML
function elementFromHtml(html) {
var container = doc.createElement('_');
container.innerHTML = html;
return container.firstChild;
}
// Return HTML from an element
function HtmlFromElement(el) {
if (el.outerHTML) return el.outerHTML;
var container = doc.createElement('_');
container.appendChild(el.cloneNode(true));
return container.innerHTML;
}
// Returns a string version of JavaScript
function stringify(val) {
var callee = arguments.callee, valArr = [], valLen, i = -1, e;
// string
if (isType(String, val)) return quoteStr(val);
// boolean, function, number, regexp, undefined, null
if (
val === undefined ||
val === null ||
isType(Boolean, val) ||
isType(Number, val) ||
isType(RegExp, val) ||
(isType(Function, val) && !/^function[^\{]+\{\s*\[native code\]/.test(String(val)))
) return String(val);
// date
if (isType(Date, val)) {
return 'new Date(' + val.getTime() + ')';
}
// array
if (isType(Array, val)) {
valLen = val.length;
while (++i < valLen) valArr.push(callee(val[i]));
return '[' + valArr + ']';
}
// object
if (isType(Object, val)) {
for (e in val) valArr.push(quoteStr(e) + ':' + callee(val[e]));
return '{' + valArr + '}';
}
// native
if (val === win) return 'window';
for (e in win) if (val === win[e]) return 'window.'+e;
for (e in doc) if (val === doc[e]) return 'document.'+e;
// node
if (val.nodeName) return 'h('+quoteStr(HtmlFromElement(val))+')';
}
// Returns a JavaScript version of a string
function unstringify(str) {
return new Function('var a=arguments;h=a[0];return ' + str).apply(win,[elementFromHtml]);
}
// Returns an extended object from arguments
function extendObject() {
var extObj = {}, arg = arguments, argLen = arg.length, i = -1, e;
while (++i < argLen)
if (isType(Object, arg[i]))
for (e in arg[i])
extObj[e] = isType(Object, extObj[e]) && isType(Object, arg[i][e]) ? arg.callee(extObj[e], arg[i][e]) : arg[i][e];
return extObj;
}
// Writes to and extends local storage
function setAndReturnIfValueChanged(attr, newValue, extend) {
var rawValue = ls[attr], oldValue;
if (extend) {
oldValue = unstringify(rawValue);
// if the existing item is an array
if (isType(Array, oldValue)) newValue = oldValue.concat(newValue);
// if the existing item is a boolean
else if (isType(Boolean, oldValue)) newValue = oldValue && !!newValue;
// if the existing item is a date and the new item can be a number
else if (isType(Date, oldValue) && !isNaN(newValue * 1)) newValue = new Date(oldValue.getTime() + (newValue * 1));
// if both the existing item and the new item are a function
else if (isType(Function, oldValue) && isType(Function, newValue)) newValue = new Function('return(' + String(oldValue) + ').apply(this, arguments)&&(' + String(newValue) + ').apply(this, arguments)');
// if the existing item is a number and the new item can be a number
else if (isType(Number, oldValue) && !isNaN(newValue * 1)) newValue = oldValue + (newValue * 1);
// if both the existing item and the new item are an object
else if (isType(Object, oldValue) && isType(Object, newValue)) newValue = extendObject(oldValue, newValue);
// if both the existing item and the new item are a regular expression
else if (isType(RegExp, oldValue) && isType(RegExp, newValue)) {
var
regExpMatch = /^\/([\W\w]*)\/([a-z]*?)$/,
regExpA = String(oldValue).match(regExpMatch),
regExpB = String(newValue).match(regExpMatch);
newValue = new RegExp(regExpA[1] + regExpB[1], regExpA[2] + regExpB[2]);
}
// if the existing item is a string
else if (isType(String, oldValue)) newValue = oldValue + String(newValue);
else return 2;
}
newValue = stringify(newValue);
if (rawValue === newValue) return 2;
return (ls[attr] = newValue) && 1;
}
// Stash
win.stash = {
// returns whether a storage item exists or not
has: function () {
var args = [].concat.apply([], arguments), arg, i = -1;
//
while ((arg = args[++i])) if (ls[arg] === undefined) return false;
return true;
},
// returns a local storage item
get: function (attr) {
var args = [].concat.apply([], arguments), arg, i = -1, items = {};
//
if (args.length === 1) return unstringify(ls[attr]);
while ((arg = args[++i])) items[arg] = unstringify(ls[arg]);
return items;
},
// returns all local storage items
getAll: function () {
var e, items = {};
for (e in ls) items[e] = ls[e];
return items;
},
// sets a local storage item, returns 1 if item(s) changed and 2 if not
set: function (attr, val) {
var args = [].concat.apply([], arguments), arg, i = -1, e, returnValue = 2;
//
if (isType(String, attr)) return setAndReturnIfValueChanged(attr, val);
//
while ((arg = args[++i])) for (e in arg) returnValue = Math.min(returnValue, setAndReturnIfValueChanged(e, arg[e]));
//
return returnValue;
},
// adds to a local storage item, returns 1 if item(s) changed and 2 if not
add: function (attr, val) {
var args = [].concat.apply([], arguments), arg, i = -1, e, returnValue = 2;
//
if (isType(String, attr)) return setAndReturnIfValueChanged(attr, val, true);
//
while ((arg = args[++i])) for (e in arg) returnValue = Math.min(returnValue, setAndReturnIfValueChanged(e, arg[e], true));
//
return returnValue;
},
// removals a local storage item
cut: function (attr) {
var args = [].concat.apply([], arguments), arg, i = -1;
//
while ((arg = args[++i])) delete ls[arg];
return true;
},
// removes all items from local storage
cutAll: function () {
for (var e in ls) delete ls[e];
return true;
}
};
})(this, this.localStorage, document);