Includes : Persist BETA

Persist Function

Този скрипт не може да бъде инсталиран директно. Това е библиотека за други скриптове и може да бъде използвана с мета-директива // @require https://update.greasyfork.org/scripts/7144/29377/Includes%20%3A%20Persist%20BETA.js

// ==UserScript==
// @name           Includes : Persist BETA
// @namespace      http://gm.wesley.eti.br
// @description    Persist Function
// @author         w35l3y
// @email          w35l3y@brasnet.org
// @copyright      2013+, w35l3y (http://gm.wesley.eti.br)
// @license        GNU GPL
// @homepage       http://gm.wesley.eti.br
// @version        1.0.1.0
// @language       en
// @include        nowhere
// @exclude        *
// @require        https://greasyfork.org/scripts/7145-includes-xpath/code/Includes%20:%20XPath.js?version=29376
// ==/UserScript==

/**************************************************************************

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

**************************************************************************/

var Persist = function (s) {
	var service = Persist.services[s];

	this.request = function (obj) {
		var k,
		xthis = this,
		params = function (def) {
			var list = {};

			this.add = function (vars) {
				if (vars) {
					if (vars instanceof unsafeWindow.HTMLCollection) {
						vars = Array.prototype.slice.apply(vars);
					}

					if (typeof vars == "object") {
						for (var k in vars) {
							var e = vars[k];

							if (typeof e == "object" && (!/^(?:radio|checkbox)$/i.test(e.type) || e.checked)) {
								var n = e.name || k;

								if (e.checked && /^checkbox$/i.test(e.type)) {
									if (n in list) {
										list[n].push(e.value);
									} else {
										list[n] = [e.value];
									}
								} else if ("value" in e) {
									list[n] = e.value;
								} else {
									list[n] = e;
								}
							} else {
								list[k] = e;
							}
						}
					} else {
						list = vars;
					}
				}
			};
		
			this.toString = function() {
				if (typeof list == "object") {
					var data = "";
					for (var key in list) {
						if (list[key] instanceof Array) {
							var keyarr = key.replace(/^\s+|\s+$/g, "");
							if (!/\[\w*\]$/.test(key)) keyarr += "[]";

							for (var k in list[key]) {
								var v = list[key][k];
								data += "&" + encodeURIComponent(keyarr) + "=" + encodeURIComponent(v);
							}
						} else {
							data += "&" + encodeURIComponent(key) + "=" + encodeURIComponent(list[key]);
						}
					}

					return data.substr(1);
				} else {
					return list;
				}
			};
		},
		data = new params();

		data.add(obj.pdata);
		data.add(obj.adata);
		data.add(obj.data);
		data.add(obj.odata);
	
		if (typeof obj.onload != "function") {
			obj.onload = function (obj) {
				console.log(["request.load", obj]);
			};
		}

		if (typeof obj.onerror != "function") {
			obj.onerror = function (obj) {
				console.log(["request.error", obj]);
			};
		}

		var update = function (obj, e) {
			obj.response = {
				raw	: function () {return e;},
				text	: function () {return e.responseText;},
				json	: function () {
					try {
						return JSON.parse(e.responseText);
					} catch (x) {
						return eval("(" + e.responseText + ")");
					}
				},
				doc	: function () {
					try {
						return new DOMParser().parseFromString(e.responseText, /^Content-Type: ([\w/]+)$/mi.test(e.responseHeaders) && RegExp.$1 || "text/html");
					} catch (x) {
						var doc = document.implementation.createHTMLDocument("");
						doc.documentElement.innerHTML = e.responseText;

						return doc;
					}
				},
			};
			obj.value = e.responseText;
		},
		params = {
			url		: obj.url,
			method	: obj.method,
			onload	: function (e) {
				update(obj, e);

				obj[(/^2/.test(e.status)?"onload":"onerror")].apply(xthis, [obj]);
			},
			onerror	: function (e) {
				update(obj, e);

				obj.onerror.apply(xthis, [obj]);
			}
		},
		sdata = data.toString();

		if (/^post$/i.test(obj.method)) {
			var p = {
				headers	: {
					"Content-Type"	: "application/x-www-form-urlencoded"
				},
				data	: sdata,
			};

			console.log(sdata);

			for (k in p) {
				params[k] = p[k];
			}
		} else if (sdata) {
			params.url += "?" + sdata;

		}
	
		if (typeof obj.headers == "object")
		for (k in obj.headers) {
			params.headers[k] = obj.headers[k];
		}

		return GM_xmlhttpRequest(params);
	};

	for (var k in service) {
		this[k] = service[k];
	}
};

Persist.services	= {
	LOCAL		: {
		write	: function (obj) {
			var label_keys = "persist_keys-" + obj.service,
			label_data = "persist_data-" + obj.service,
			mapping = JSON.parse(GM_getValue(label_keys, "{}")),
			data = JSON.parse(GM_getValue(label_data, "[]")),
			key = obj.key;

			if (key in mapping) {
				key = mapping[obj.key];
			}

			if (key in data) {
				var tv = typeof obj.value,
				td = typeof data[key];

				if ((td != tv) && (td == "object" || tv == "object")) {
					throw ["Incompatible types ", td, tv].toString();
				} else {
					switch (td) {
						case "string":
							if (-1 == obj.mode) {	// prepend
								data[key] = obj.value + data[key];
							} else if (1 == obj.mode) {	// append
								data[key] += obj.value;
							} else {	// overwrite (default)
								data[key] = obj.value;
							}
							break;
						case "boolean":
							if (-1 == obj.mode) {	// unused
								throw ["Reserved action"].toString();
							} else if (1 == obj.mode) {	// toggle
								data[key] = !data[key];
							} else {	// overwrite (default)
								data[key] = !!value;
							}
							break;
						case "number":
							var value = Number(obj.value);

							if (-1 == obj.mode) {	// subtract
								data[key] -= value;
							} else if (1 == obj.mode) {	// add
								data[key] += value;
							} else {	// overwrite (default)
								data[key] = value;
							}
							break;
						case "object":
							if (-1 == obj.mode) {	// prepend
								for (var k in data[key]) {
									obj.value[k] = data[key][k];
								}
								data[key] = obj.value;
							} else if (1 == obj.mode) {	// append
								for (var k in obj.value) {
									data[key][k] = obj.value[k];
								}
							} else {	// overwrite (default)
								data[key] = obj.value;
							}
							break;
						default:
							throw ["Unsupported type " + td, data[key], key].toString();
					}

					obj.value = data[key];
				}
			} else {
				var tkey = data.push(obj.value);
				
				if (--tkey != key) {
					if ("key" in obj) {
						if (key in mapping) {
							console.log(["Wrong mapping... ", tkey, key]);
						}

						mapping[key] = tkey;
						obj.key = key;

						GM_setValue(label_keys, JSON.stringify(mapping));
					} else {
						obj.key = tkey;
					}
				}
			}

			GM_setValue(label_data, JSON.stringify(data));

			if (typeof obj.onload != "function") {
				obj.onload = function (obj) {
					console.log(["write.load", obj]);
				};
			}

			return obj.onload.apply(this, [obj]);
		},
		delete	: function (obj) {
			throw ["Not implemented"].toString();
		},
		read	: function (obj) {
			var mapping = JSON.parse(GM_getValue("persist_keys-" + obj.service, "{}")),
			key = obj.key;

			if (key in mapping) {
				key = mapping[key];
			}

			obj.value = JSON.parse(GM_getValue("persist_data-" + obj.service, "[]"))[key];

			if (typeof obj.onload != "function") {
				obj.onload = function (obj) {
					console.log(["read.load", obj]);
				};
			}

			return obj.onload.apply(this, [obj]);
		},
	},
	PASTEBIN	: {
		write	: function (obj) {
			var execute = function (x) {
				var onload = x.onload,
				value = x.value,
				xthis = this,
				p = {
					url		: "http://pastebin.com/api/api_post.php",
					method	: "post",
					adata		: JSON.parse(GM_getValue("pastebin_adata", JSON.stringify({
//						api_dev_key			: "",	// required
//						api_user_key		: "",
					}))),
					pdata		: {
						api_paste_format		: "text",
						api_paste_private		: "1",
						api_paste_expire_date	: "N",
						api_paste_code		: x.value,	// required
					},
					odata		: {
						api_paste_key		: obj.key,
						api_option			: "paste"
					},
					onload	: function (y) {
						if (/^https?:\/\//i.test(y.value) && /\w+$/.test(y.value)) {
							var key = x.key;
							x.key = RegExp["$&"];

							x.onload = onload;
							x.value = value;

							x.onload.apply(xthis, [x]);

							if (x.read) {
								/* It is implemented that way because currently there isn't an EDIT option via API */
								y.key = key;
								y.onload = function (z) {
									console.log(["delete.load", z]);
								};
								y.onerror = function (z) {
									console.log(["delete.error", z]);
								};

								xthis.delete.apply(xthis, [y]);
							}
						} else {
							x.onerror.apply(xthis, [x]);
						}
					}
				};
				
				for (var i in p) {
					x[i] = p[i];
				}
				
				return this.request(x);
			};

			if (1 == Math.abs(obj.mode)) {	// prepend or append
				var value = obj.value,
				onload = obj.onload,
				xthis = this;

				obj.onload = function (x) {
					obj.onload = onload;

					if (-1 == obj.mode) {	// prepend
						obj.value = value + obj.value;
					} else {	// append
						obj.value += value;
					}
					
					return execute.apply(xthis, [obj]);
				};

				return this.read.apply(this, [obj]);
			} else {
				return execute.apply(this, [obj]);
			}
		},
		read	: function (obj) {
			if ("key" in obj) {
				var onload = obj.onload,
				xthis = this,
				p = {
					read		: false,
					url		: "http://pastebin.com/download.php",
					method	: "get",
					adata		: {
						i	: obj.key
					},
					onload	: function (x) {
						obj.onload = onload;

						if (x.response.raw().finalUrl.indexOf(x.url)) {
							obj.value = "";

							obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(this, [obj]);
						} else {
							obj.read = true;

							obj.onload.apply(xthis, [obj]);
						}
					}
				};
				for (var i in p) {
					obj[i] = p[i];
				}

				return this.request(obj);
			} else {
				obj.value = "";
				obj.read = false;

				obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(this, [obj]);
			}
		},
		delete	: function (obj) {
			var onload = obj.onload,
			value = obj.value,
			xthis = this,
			p = {
				url		: "http://pastebin.com/api/api_post.php",
				method	: "post",
				adata		: JSON.parse(GM_getValue("pastebin_adata", JSON.stringify({
//					api_dev_key			: "",	// required
//					api_user_key		: "",
				}))),
				pdata		: {},
				odata		: {
					api_paste_key		: obj.key,
					api_option			: "delete"
				},
				onload	: function (x) {
					if (/^Paste Removed$/i.test(x.value)) {
						obj.onload = onload;
						obj.value = value;

						obj.onload.apply(xthis, [obj]);
					} else {
						obj.onerror.apply(xthis, [obj]);
					}
				}
			};
		
			for (var i in p) {
				obj[i] = p[i];
			}
		
			return this.request(obj);
		},
	},
	PASTEBIN2	: {
		write	: function (obj) {
			var ovalue = obj.value,
			xthis = this,
			execute = function (x) {
				var onload = x.onload,
				nvalue = x.value,
				p = {
					method	: "post",
					adata	: JSON.parse(GM_getValue("pastebin2_adata", JSON.stringify({
//						paste_private		: "1",
					}))),
					pdata	: {
						paste_format		: "1",
						paste_private		: "2",
						paste_expire_date	: "N",
						paste_code			: x.value,	// required
					},
					odata	: {
						submit			: "Submit",
						submit_hidden	: "submit_hidden",
						item_key		: obj.key,
						post_key		: obj.key,
					},
					onload	: function (y) {
						var doc = y.response.doc(),
						url = y.response.raw().finalUrl;

						if (/warning\.php\?p=(\d+)/i.test(url)) {
							x.code = RegExp.$1 - 1;
							x.value = [
								"You have reached your limit of [10] pastes per 24 hours.",
								"You have reached your limit of [20] pastes per 24 hours.",
								"You have reached your limit of [250] pastes per 24 hours.",
							][x.code] || xpath("string(id('content_left')/div[2])", doc) || "Unknown error (WARN " + x.code + ")";

							x.onerror.apply(xthis, [x]);
						} else if ((/^https?:/i.test(url)) && (/\/(\w+)$/.test(url))) {
							x.key = RegExp.$1;

							if (xpath("string(.//text()[contains(., 'Pastebin.com is under heavy load right now')])", doc)) {
								x.onerror.apply(xthis, [x]);
							} else {
								if (xpath("id('siimage')", doc)[0]) {
									x.value = nvalue;
									GM_log(ovalue);
									alert("A new window will be opened. You must fill the captcha correctly, otherwise you will lose your data and a new paste will be created next time.");
									GM_openInTab(url);
								} else {
									var code = xpath("id('paste_code')", doc)[0];
									x.value = code && code.textContent || "";
								}
								x.onload = onload;
								x.onload.apply(xthis, [x]);
							}
						} else {
							x.value = [
								"You have exceeded the maximum file size of [500] kilobytes per paste.",
								"You cannot create an empty paste.",
								"You have reached the maximum number of [25] unlisted pastes.",
								"You have reached the maximum number of [10] private pastes.",
							][/index\.php\?e=(\d+)/.test(url) && (x.code = RegExp.$1 - 1)] || xpath("string(id('notice'))", doc) || "Unknown error (ERROR " + x.code + ")";

							x.onerror.apply(xthis, [x]);
						}
					}
				};
				
				for (var i in p) {
					x[i] = p[i];
				}

				return this.request(x);
			};

			if (1 == Math.abs(obj.mode)) {	// prepend or append
				var onload = obj.onload;

				if ("" != ovalue) {
					obj.onload = function (x) {
						obj.onload = onload;

						if (-1 == obj.mode) {	// prepend
							obj.value = ovalue + obj.value;
						} else {	// append
							obj.value += ovalue;
						}
					
						return execute.apply(xthis, [obj]);
					};
				}

				return xthis.read.apply(xthis, [obj]);
			} else {
				return execute.apply(xthis, [obj]);
			}
		},
		read	: function (obj) {
			var xthis = this;

			if ("key" in obj && obj.key) {
				var onload = obj.onload,
				p = {
					read		: false,
					url		: "http://pastebin.com/download.php",
					method	: "get",
					adata		: {
						i	: obj.key
					},
					onload	: function (x) {
						var url = x.response.raw().finalUrl;

						x.onload = onload;

						if (url.indexOf(x.url)) {	// Unknown Paste ID
							x.value = "";
							x.url = "http://pastebin.com/post.php";
							x.key = "";

							x[typeof x.onwarn == "function"?"onwarn":"onload"].apply(this, [x]);
						} else if (~x.value.indexOf("this is a private paste. If this is your private paste")) {	// may occur false positive
							x.value = "This is a private paste (#"+x.key+"). You must login to Pastebin first.";
							x.onerror.apply(xthis, [x]);
						} else if (~x.value.indexOf("Pastebin.com is under heavy load right now")) {
							x.value = "Pastebin.com is under heavy load right now.";
							x.onerror.apply(xthis, [x]);
						} else {
							x.read = true;
							x.url = "http://pastebin.com/edit.php";

							x.onload.apply(xthis, [x]);
						}
					}
				};
				for (var i in p) {
					obj[i] = p[i];
				}

				return this.request(obj);
			} else {
				obj.read = false;
				obj.url = "http://pastebin.com/post.php";
				obj.key = "";

				this.request({
					url		: "http://pastebin.com/",
					method	: "get",
					onload	: function (c) {
						if (xpath("boolean(id('header_bottom')//a[contains(@href, '/logout')])", c.response.doc())) {
							obj.value = "";

							obj[typeof obj.onwarn == "function"?"onwarn":"onload"].apply(xthis, [obj]);
						} else {
							obj.value = "You must login to Pastebin first.";

							obj.onerror.apply(xthis, [obj]);
						}
					},
					onerror	: function (c) {
						c.value = xpath("string(id('content_left')/div[1])", c.response.doc());

						obj.onerror(c);
					},
				});
			}
		},
		delete	: function (obj) {
			var onload = obj.onload,
			value = obj.value,
			xthis = this,
			p = {
				url		: "http://pastebin.com/delete.php",
				method	: "get",
				adata	: {},
				pdata	: {},
				odata	: {
					i	: obj.key,
					r	: "/" + obj.key
				},
				onload	: function (x) {
					if (/^Paste Removed$/i.test(x.value)) {
						obj.onload = onload;
						obj.value = value;

						obj.onload.apply(xthis, [obj]);
					} else {
						obj.onerror.apply(xthis, [obj]);
					}
				}
			};
		
			for (var i in p) {
				obj[i] = p[i];
			}
		
			return this.request(obj);
		}
	}
};

Persist.write = function (obj) {
	var p = new Persist(obj.service);

	return p.write.apply(p, [obj]);
};

Persist.delete = function (obj) {
	var p = new Persist(obj.service);

	return p.delete.apply(p, [obj]);
};

Persist.read = function (obj) {
	var p = new Persist(obj.service);

	return p.read.apply(p, [obj]);
};