Greasy Fork is available in English.

dA_DragnFav

drag thumbs and deviations to yur favourites/collections

// ==UserScript==
// @name         dA_DragnFav
// @namespace    phi.pf-control.de/userscripts/dA_DragnFav/dA_DragnFav.user.js
// @version      2.4
// @description  drag thumbs and deviations to yur favourites/collections
// @author       Dediggefedde
// @match        https://www.deviantart.com/*
// @require    	 http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
// @require      http://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js
// @grant        GM_addStyle
// @grant        GM.xmlHttpRequest
// @grant        GM.setValue
// @grant        GM.getValue
// ==/UserScript==

/* globals $*/
/* jshint esnext:true */

// faving informations:
//	POST https://www.deviantart.com/_napi/shared_api/collections/collect
//	{"itemid":864977862,"folderids":[1468881,48232885],"csrf_token":"Jt3u9HHt4hGtMxG7.qluh26.7-qAIhS-bmbIhMbgks-rKcuE_j1y6EsqMJyonDrrjsE"}

(function() {
	'use strict';

	//# temporary variables
	let grIDs = [];
	let settingmode = false;
	let groupOrder = [];
	let hiddengroups = [];
	let headerfilled = false;
	//# resources
	//hook copied from deviantart svg
	let imgHook = '<svg width="50" height="50" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"><path d="M1.237 6.187L0 4.95l1.237-1.238L2.475 4.95l3.712-3.713 1.238 1.238-4.95 4.95-1.238-1.238z" fill-rule="evenodd"></path></svg>';
	//imgGear copied from inkscape "render gear", slightly adjusted
	let imgGear = '<svg  xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 20.444057 20.232336" > <g transform="translate(-15.480352,-5.6695418)">  <g transform="matrix(0.26458333,0,0,0.26458333,25.702381,15.78571)"  style="fill:#000000">  <path  style="fill:#000000;stroke:#000000;stroke-width:1"  d="m 28.46196,-3.25861 4.23919,-0.48535 0.51123,0.00182 4.92206,1.5536 v 4.37708 l -4.92206,1.5536 -0.51123,0.00182 -4.23919,-0.48535 -1.40476,6.15466 4.02996,1.40204 0.45982,0.22345 3.76053,3.53535 -1.89914,3.94361 -5.1087,-0.73586 -0.4614,-0.22017 -3.60879,-2.2766 -3.93605,4.93565 3.02255,3.01173 0.31732,0.40083 1.8542,4.81687 -3.42214,2.72907 -4.2835,-2.87957 -0.32017,-0.39856 -2.26364,-3.61694 -5.68776,2.73908 1.41649,4.0249 0.11198,0.49883 -0.41938,5.14435 -4.26734,0.97399 -2.6099,-4.45294 -0.11554,-0.49801 -0.47013,-4.2409 h -6.31294 l -0.47013,4.2409 -0.11554,0.49801 -2.6099,4.45294 -4.26734,-0.97399 -0.41938,-5.14435 0.11198,-0.49883 1.41649,-4.0249 -5.68776,-2.73908 -2.26364,3.61694 -0.32017,0.39856 -4.2835,2.87957 -3.42214,-2.72907 1.8542,-4.81687 0.31732,-0.40083 3.02255,-3.01173 -3.93605,-4.93565 -3.60879,2.2766 -0.4614,0.22017 -5.1087,0.73586 -1.89914,-3.94361 3.76053,-3.53535 0.45982,-0.22345 4.02996,-1.40204 -1.40476,-6.15466 -4.23919,0.48535 -0.51123,-0.00182 -4.92206,-1.5536 v -4.37708 l 4.92206,-1.5536 0.51123,-0.00182 4.23919,0.48535 1.40476,-6.15466 -4.02996,-1.40204 -0.45982,-0.22345 -3.76053,-3.53535 1.89914,-3.94361 5.1087,0.73586 0.4614,0.22017 3.60879,2.2766 3.93605,-4.93565 -3.02255,-3.01173 -0.31732,-0.40083 -1.8542,-4.81687 3.42214,-2.72907 4.2835,2.87957 0.32017,0.39856 2.26364,3.61694 5.68776,-2.73908 -1.41649,-4.0249 -0.11198,-0.49883 0.41938,-5.14435 4.26734,-0.97399 2.6099,4.45294 0.11554,0.49801 0.47013,4.2409 h 6.31294 l 0.47013,-4.2409 0.11554,-0.49801 2.6099,-4.45294 4.26734,0.97399 0.41938,5.14435 -0.11198,0.49883 -1.41649,4.0249 5.68776,2.73908 2.26364,-3.61694 0.32017,-0.39856 4.2835,-2.87957 3.42214,2.72907 -1.8542,4.81687 -0.31732,0.40083 -3.02255,3.01173 3.93605,4.93565 3.60879,-2.2766 0.4614,-0.22017 5.1087,-0.73586 1.89914,3.94361 -3.76053,3.53535 -0.45982,0.22345 -4.02996,1.40204 z"  />  <circle  style="fill:#ffffff;stroke:#000000;stroke-width:1"  cx="0"  cy="0"  r="15" />  </g>  </g> </svg>';

	//CSS styling
	//"#dA_DragnFav_header div[folderId] * {pointer-events: none;}
	GM_addStyle(`
#dA_DragnFav_header {color:var(--L8);background-color: #8fac85cc;z-index: 77;position: fixed;width: 100%;border: 2px ridge white;
display: none;padding: 20px;justify-content: center;align-items: center;flex-wrap: wrap;box-sizing: border-box;}
#dA_DragnFav_header div[folderId] {padding: 15px;border-radius: 5px;background-color: #ffffdd;border: 1px solid black;margin: 10px;
display:flex;align-items: center;flex-direction: column;position: relative;overflow:clip;}
#dA_DragnFav_header div[folderId] img {height:50px;max-width: 100px; overflow: hidden;text-overflow: ellipsis;font-size: smaller;}
#dA_DragnFav_header div.dA_DragnFav_sets{position:absolute;top:10px;right:10px;cursor:pointer;}
#dA_DragnFav_header div.dA_DragnFav_markhide{background-color:#a22;}
div.dA_DragnFav_right{right:0}
div.dA_DragnFav_groupTitle{display:inline-block;}
div.dA_DragnFav_left{left:0}
div.dA_DragnFav_over{z-index:3;position: absolute;top: 0;width: 50%;height: 100%;
background-color: #b9d9b1;display: flex;align-items: center;justify-content: center;opacity:0;text-shadow: 3px 3px 3px #0006;font-weight:bold;}
div.dA_DragnFav_over p{pointer-events: none;}
div.dA_DragnFav_inside {position:absolute;z-index:2;left:0;width:100%;top:0;height:100%;display:flex;align-items: center;justify-content: center;visibility:hidden}
div.dA_DragnFav_inside svg {fill:green;}
#dA_DragnFav_drowDown{color:var(--L8);max-height:350px;position:absolute;z-index:99;top:0;left:0;border:1px solid green;
overflow-y:scroll;border-radius:5px;background: linear-gradient(90deg,var(--L19),var(--L3),var(--L19));}
#dA_DragnFav_drowDown li{height:50px;background-color:var(--L19);position: relative;overflow:hidden;margin:2px 0;}
#dA_DragnFav_drowDown li:hover{background-color:var(--L2)}
#dA_DragnFav_drowDown img{overflow: hidden;text-overflow: ellipsis;font-size: smaller;max-width: 100px;height: 100%;}
#dA_DragnFav_drowDown div.dA_DragnFav_wrapImg{width: 100px; overflow: hidden;text-overflow: ellipsis;font-size: smaller;
display:inline-block;vertical-align:middle;position: relative;height: 100%;text-align: center;}
#dA_DragnFav_drowDown div.dA_DragnFav_groupTitle{margin:0 15px}
`.replace(/\s\s+/g, ''));

	//# https requests
	//gets your currently available collections. returns promise with json response on success. response or parse error on error
	//assumes <21 collections
	function getCollections(offset = 0) {
			let token = $("input[name=validate_token]").val();
			return new Promise(function(resolve, reject) {
					GM.xmlHttpRequest({
							method: "GET",
							url: "https://www.deviantart.com/_napi/shared_api/gallection/folders?type=collection&offset=" + offset + "&limit=20&csrf_token=" + token,
							headers: {
									"accept": 'application/json, text/plain, */*',
									"content-type": 'application/json;charset=UTF-8'
							},
							onerror: function(response) {
									console.log("error:", response);
									reject(response);
							},
							onload: async function(response) {
									let dat;
									try {
											dat = JSON.parse(response.responseText);
											if (dat.hasMore) {
													getCollections(dat.nextOffset).then(nret => {
															dat.results = dat.results.concat(nret.results);
															resolve(dat);
															return;
													});
											} else {
													resolve(dat);
											}
									} catch (e) {
											reject(e);
									}
							}
					});
			});
	}

	//get list of collection ids, this deviation id is inside already
	//returns promise with json response on success. response or parse error on error
	function inCollections(id) {
			let token = $("input[name=validate_token]").val();
			return new Promise(function(resolve, reject) {
					GM.xmlHttpRequest({
							method: "GET",
							url: "https://www.deviantart.com/_puppy/dashared/collections/collections_for_deviation?deviationid=" + id + "&csrf_token=" + token,
							headers: {
									"accept": 'application/json, text/plain, */*',
									"content-type": 'application/json;charset=UTF-8'
							},
							onerror: function(response) {
									console.log("error:", response);
									reject(response);
							},
							onload: async function(response) {
									let dat;
									try {
											dat = JSON.parse(response.responseText);
									} catch (e) {
											reject(e);
									}
									resolve(dat);
							}
					});
			});
	}

	//sets the collection of the deviation with this id to the array cols (folder ids).
	//searches for validate_token on current page
	function setCollection(id, cols) {
			let token = $("input[name=validate_token]").val();
			let dats = {
					"itemid": parseInt(id),
					"folderids": cols,
					"csrf_token": token
			};
			return new Promise(function(resolve, reject) {
					GM.xmlHttpRequest({
							method: "POST",
							url: "https://www.deviantart.com/_puppy/dashared/collections/collect",
							headers: {
									"accept": 'application/json, text/plain, */*',
									"content-type": 'application/json'
							},
							dataType: 'json',
							data: JSON.stringify(dats),
							onerror: function(response) {
									console.log("error:", response);
									reject(response);
							},
							onload: async function(response) {
									let dat;
									try {
											dat = JSON.parse(response.responseText); //returns {success:true}
									} catch (e) {
											reject(e);
									}
									resolve(dat);
							}
					});
			});
	}

	//# event listener
	//when items are dragged onto the bar
	function itemDroppedOnCol(event, add = true, mid = 0) {

			let id = mid;
			if (mid == 0) id = event.originalEvent.dataTransfer.getData('id');

			let fEl = $(event.target).closest("[folderId]");
			let fId = parseInt(fEl.attr("folderId"));

			if (!add) grIDs = [];
			if (!grIDs.includes(fId)) {
					grIDs.push(fId);
					setCollection(id, grIDs).then(ret => {
							fEl.find(".dA_DragnFav_inside").css("visibility", "visible");
					}).then(() => {
							markCollections(id);
					});
			}
	}

	function leaveSettingMode() {
			settingmode = false;
			$("#dA_DragnFav_header div.dA_DragnFav_markhide").css("display", "none");
			$("#dA_DragnFav_header div.dA_DragnFav_setDescr").remove();
			$("#dA_DragnFav_header").fadeOut();
	}

	function enterSettingMode() {
			settingmode = true;

			//show hidden
			$("#dA_DragnFav_header div.dA_DragnFav_markhide").css("display", "block");

			//make sortable
			$("#dA_DragnFav_header").sortable({
					helper: 'clone',
					forceHelperSize: true,
					forcePlaceholderSize: true,
					placeholder: "ui-state-highlight",
					items: 'div.dA_DragnFav_group',
					cursor: 'move',
					update: function(event, ui) {
							let colOrder = $(this).sortable('toArray', { attribute: 'folderId' });
							GM.setValue("groupOrder", JSON.stringify(colOrder));
					}
			}).prepend("<div class='dA_DragnFav_setDescr' style='width:100%'>Drag items to rearange them. Click an item to hide/show it. Click the gear to leave the settings mode.</div>");
	}

	//# initialization, reruns periodically for dynamic site building
	//insert fav-header
	function fillHeader(id) {
			return (new Promise(function(resolve, reject) {
					if (headerfilled) {
							resolve(id);
							return;
					}
					getCollections(0).then((ret) => {
							headerfilled = true;
							let tex = "";
							let contextTex = "";
							ret.results.forEach((el) => {
									let thumb = "";
									try{
											if (el.thumb && el.thumb.coverImage && el.thumb.coverImage.media && el.thumb.coverImage.media.types && el.thumb.coverImage.media.prettyName && el.thumb.coverImage.media.token && el.thumb.coverImage.media.types[0] && el.thumb.coverImage.media.types[0].c) { //optional chaining breaks tampermonkey syntax highlight...
													thumb += `${el.thumb.coverImage.media.baseUri}${el.thumb.coverImage.media.types[0].c.replace("<prettyName>", el.thumb.coverImage.media.prettyName)}?token=${el.thumb.coverImage.media.token[0]}`;
											} else if (el.thumb && el.thumb.media && el.thumb.media.baseUri && el.thumb.media.types && el.thumb.media.prettyName && el.thumb.media.token && el.thumb.media.types[0] && el.thumb.media.types[0].c) {
													thumb += `${el.thumb.media.baseUri}${el.thumb.media.types[0].c.replace("<prettyName>", el.thumb.media.prettyName)}?token=${el.thumb.media.token[0]}`;
											}
									}catch(ex){
											console.log("error: thumbnail not parsed",ex);
									}
									let thTitl = "no thumb";
									if (el.thumb) {
											thTitl = el.thumb.title;
									}
									tex += `
		<div class='dA_DragnFav_group ${hiddengroups.includes(el.folderId)?"dA_DragnFav_markhide":""}' folderId='${el.folderId}' ${hiddengroups.includes(el.folderId)?"style='display:none;'":""}>
			<img src='${thumb}' alt='${thTitl}' title='${thTitl}'/>
			<div class='dA_DragnFav_groupTitle'>${el.name}</div>
			<div class='dA_DragnFav_inside'>${imgHook}</div>
			<div class='dA_DragnFav_over dA_DragnFav_left'><p>Add</p></div>
			<div class='dA_DragnFav_over dA_DragnFav_right'><p>Move</p></div>
		</div>
		`.replace(/\s\s+/g, '');
									contextTex += `<li class='dA_DragnFav_group ${hiddengroups.includes(el.folderId)?"dA_DragnFav_markhide":""}' folderId='${el.folderId}' ${hiddengroups.includes(el.folderId)?"style='display:none;'":""}>
			<div class='dA_DragnFav_wrapImg'><img src='${thumb}' alt='${thTitl}' title='${thTitl}'/></div>
			<div class='dA_DragnFav_groupTitle'>${el.name}</div>
			<div class='dA_DragnFav_inside'>${imgHook}</div>
			<div class='dA_DragnFav_over dA_DragnFav_left'><p>Add</p></div>
			<div class='dA_DragnFav_over dA_DragnFav_right'><p>Move</p></div>
		</li>`.replace(/\s\s+/g, '');
							});
							let header = $("#dA_DragnFav_header");
							header.html(tex).append(`<div class='dA_DragnFav_sets'>${imgGear}</div>`);
							let context = $("#dA_DragnFav_drowDown").html(contextTex);

							$.each(groupOrder, function(i, folderid) {
									let $target = header.find(`[folderid='${folderid}']`);
									$target.appendTo(header); // or prependTo for reverse
							});

							$("#dA_DragnFav_header div.dA_DragnFav_group").click(function(ev) {
									if (settingmode && !$(this).hasClass("noClick")) { //hide toggle click in setting-mode
											let fid = parseInt($(this).attr("folderId"));
											let fhidInd = hiddengroups.indexOf(fid);
											if (fhidInd > -1) {
													hiddengroups.splice(fhidInd, 1);
													$(this).removeClass("dA_DragnFav_markhide");
											} else {
													hiddengroups.push(fid);
													$(this).addClass("dA_DragnFav_markhide");
											}
											GM.setValue("hiddengroups", JSON.stringify(hiddengroups));
									}
							});

							//fav-header drag receivable
							$("#dA_DragnFav_header div.dA_DragnFav_over").on('dragover', false).on("dragenter", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
									$(ev.target).css("opacity", "0.7");
							}).on("dragleave", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
									$(ev.target).css("opacity", "0");
							}).on("drop", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
									$(ev.target).css("opacity", "0");
									itemDroppedOnCol(ev, $(ev.target).hasClass("dA_DragnFav_left"));
							});

							$("#dA_DragnFav_drowDown div.dA_DragnFav_over").on('mouseover', false).on("mouseenter", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
									$(ev.target).css("opacity", "0.7");
							}).on("mouseleave", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
									$(ev.target).css("opacity", "0");
							}).on("click", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
									$(ev.target).css("opacity", "0");
									let id = document.getElementById("dA_DragnFav_drowDown").getAttribute("ImgId");
									itemDroppedOnCol(ev, $(ev.target).hasClass("dA_DragnFav_left"), id);
							});

							//settings open on drag, close on click
							$("#dA_DragnFav_header div.dA_DragnFav_sets").on('dragover', false).on("dragenter", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
							}).on("dragleave", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
							}).on("drop", function(ev) {
									ev.preventDefault();
									ev.stopPropagation();
									enterSettingMode();
							}).click(function(ev) {
									leaveSettingMode();
							});

							resolve(id);
							return;
					});
			})).then(markCollections);
	}

	function markCollections(id) {
			if (id == null) return;
			$(".dA_DragnFav_inside").css("visibility", "");
			$(".dA_DragnFav_group").css("background-color", "");
			// grIDs = [];
			inCollections(id).then(ret => {
					if (!ret.collectionIds) {
							console.log("error checking collections:", ret, id);
							return;
					}
					ret.collectionIds.forEach(el => {
							$("[folderId=" + el + "]").find(".dA_DragnFav_inside").css("visibility", "visible");
							$("[folderId=" + el + "]").closest(".dA_DragnFav_group").css("background-color", "rgb(180, 255, 200)");
					});
					grIDs = ret.collectionIds;
			});
	}

	function dragEnd(ev) {
			if (!settingmode) {
					$("#dA_DragnFav_header").fadeOut();
			}
	}

	function dragStart(ev) {
			$("#dA_DragnFav_header").css("display", "flex");
			$("div.dA_DragnFav_over").css("opacity", "0");

			let drEl = ev.target.closest("[devId]");
			//let mode = $(this).attr("dA_DragnFav");
			let id;

			id = drEl.getAttribute("devId");
			if (!id) {
					console.log("error: ID can not be fetched", drEl, $(this), $(ev.target), $(ev.target).attr("href"), document.querySelector("meta[property='og:url']").getAttribute("content"));
			}
			ev.originalEvent.dataTransfer.setData('id', id);

			fillHeader(id);
	}


	//make deviations draggable, passing link with ID
	function makeDraggable() {
			//thumbs in links
			let els = $("a[href^='https://www.deviantart.com/'][href*='/art/'],a[href^='https://www.deviantart.com/'][href*='/journal/']").not("[dA_DragnFav]").attr("dA_DragnFav", 1).attr("draggable", "true");
			if (els.length > 0) {
					els.each((ind, el) => {
							el.setAttribute("devId", el.href.match(/(\d+)(#[^\/]*)?$/)[1]) });
					els.on("dragstart", dragStart).on("dragend", dragEnd);
			}

			//fullview
			els = $("img[property='contentUrl'][fetchpriority='high']").not("[dA_DragnFav]").attr("dA_DragnFav", 2).attr("draggable", "true");
			if (els.length > 0) {
					els.each((ind, el) => {
							el.setAttribute("devId", location.href.match(/deviantart.com\/[^\/]*\/art\/[^\/]*?(\d+)$/)[1]
															// document.querySelector("meta[property='og:url']").getAttribute("content").match(/\d+$/)[0]
														 )
					});
					els.on("dragstart", dragStart).on("dragend", dragEnd);
			}

			//fav button on fullview
			els = $("._2mxul > button:nth-child(1)").not("[dA_DragnFav]").attr("dA_DragnFav", 1);
			if (els.length > 0) {
					els.each((ind, el) => {
							let it = el.parentNode.querySelector("a[href^='https://www.deviantart.com/'][href*='/art/'],a[href^='https://www.deviantart.com/'][href*='/journal/']");
							if (it == null) it = location.href.match(/-(\d\d+)((\D).*)?$/)[1];
							else it = it.href.match(/-(\d\d+)((\D).*)?/)[1];
							el.setAttribute("devId", it);
					});
					els.contextmenu(function(e) {
							e.preventDefault();
							let el = e.target.closest("button");
							let id = el.getAttribute("devId");
							fillHeader(id);
							$('#dA_DragnFav_drowDown').attr("ImgId", id).css({ 'top': e.pageY, 'left': e.pageX }).show();
					});

					let plusImg = document.createElementNS('http://www.w3.org/2000/svg', "path");
					plusImg.setAttribute("stroke", "#0A0");
					plusImg.setAttribute("stroke-width", "4");
					plusImg.setAttribute("stroke-opacity", "0.8");
					plusImg.setAttribute("d", "M12 18H24M18 12V24");
					els.find("svg").append(plusImg);
			}

			//overview fav button
			els = $("button").filter((i, el) => {
					return null != el.querySelector("svg path[d*='M13.71 3.408A1 1 0 0012.904 3h-1.85l-.119.007a1 1 0 00'], svg path[d*='M11.054 3a1 1 0 00-.87.506L8.123 7.134l-4.57.641a1 1 0 00']");
			}).not("[dA_DragnFav]").attr("dA_DragnFav", 1);
			if (els.length > 0) {
					els.each((ind, el) => {
							let it = el.parentNode.parentNode.querySelector("a[href^='https://www.deviantart.com/'][href*='/art/'],a[href^='https://www.deviantart.com/'][href*='/journal/']");
							if (it == null) console.log(el);//it = location.href.match(/-(\d\d+)([\?#].*)?$/)[1];
							else it = it.href.match(/-(\d\d+)((\D).*)?/)[1];
							el.setAttribute("devId", it);
					});
					els.contextmenu(function(e) {
							e.preventDefault();
							let el = e.target.closest("button");
							let id = el.getAttribute("devId");
							fillHeader(id);
							$('#dA_DragnFav_drowDown').attr("ImgId", id).css({ 'top': e.pageY, 'left': e.pageX }).show();
					});

					let plusImg = document.createElementNS('http://www.w3.org/2000/svg', "path");
					plusImg.setAttribute("stroke", "#0A0");
					plusImg.setAttribute("stroke-width", "4");
					plusImg.setAttribute("stroke-opacity", "0.8");
					plusImg.setAttribute("d", "M12 18H24M18 12V24");
					els.find("svg").append(plusImg);
			}

	}

	//runs every interval
	function init() {
			if (document.getElementById("dA_DragnFav_header") == null) {
					$("header[role='banner']").after("<div id='dA_DragnFav_header'>");
					headerfilled = false;
			}
			makeDraggable();
			if (document.getElementById("dA_DragnFav_styles") == null) {
					$("head").append(
							'<link id="dA_DragnFav_styles"' +
							'href="//ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/le-frog/jquery-ui.min.css" ' +
							'rel="stylesheet" type="text/css">'
					);
			}
			if (document.getElementById("dA_DragnFav_drowDown") == null) {
					$("body").append("<ul id='dA_DragnFav_drowDown'></ul>");
					$("#dA_DragnFav_drowDown").hide();
			}
			$(document).click(function(ev) { $("#dA_DragnFav_drowDown").hide(); })
	}

	if (window.top === window.self) {
			GM.getValue("hiddengroups", "").then(ret => {
					if (ret != "") {
							hiddengroups = JSON.parse(ret);
					}
					return GM.getValue("groupOrder", "");
			}).then(ret => {
					if (ret != "") {
							groupOrder = JSON.parse(ret);
					}
					setInterval(init, 1000); // check every second
			});
	}
})();