Configuration Dialog

A enhanced configuration dialog for Userscripts.

Per 20-12-2019. Zie de nieuwste versie.

Dit script moet niet direct worden geïnstalleerd - het is een bibliotheek voor andere scripts om op te nemen met de meta-richtlijn // @require https://update.greasyfork.org/scripts/45343/759338/Configuration%20Dialog.js

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

/*
/////////////////////////////////////////////////////
#                                                   #
#          Script made by Marius Adam               #
#                ©DevForce 2019                     #
#               Code Version 0.4                    #
#                                                   #
/////////////////////////////////////////////////////
*/

var configurationWindow = {
	maximized: false,
	minimized: false,

	changed: false,

    data: undefined,
	window_id: "window",

	values: {},
	
	get : function(id){
		return this.values[id];
	},
	
	getElseSet : function(id, def, ifNone){
		var val = this.get(id);
		if(val == undefined){
			if(def == undefined){
				val = ifNone;
				this.set(id, ifNone);
			}else{
				val = def;
				this.set(id, def);
			}
		}
		return val;
	},
	
	set : function(id, value){
		this.values[id] = value;
	},
	
	save : function(){
		GM_setValue(this.window_id, JSON.stringify(this.values));
		console.debug("Saved to #" + this.window_id, this.values);
	},
	
	load : function(){
		var loaded = GM_getValue(this.window_id);
		if(loaded == undefined || loaded.length < 2) loaded = "{}";
		this.values = JSON.parse(loaded);
		console.debug("Loaded Values: ", this.values);
	},
	
	updateChanged : function() {
		this.changed = ($('[style*="border: 2px solid rgb(255, 244, 0);"]').length + $('[style*="outline: rgb(255, 244, 0) solid 3px;"]').length + $('[style*="outline: 3px solid rgb(255, 244, 0);"]').length) > 0;
		
		$('#' + this.window_id).find('#saveButton').prop("disabled", ! this.changed);
		$('#' + this.window_id).find('#revertButton').prop("disabled", ! this.changed);
	},
	
	maximize : function() {
		$('#' + this.window_id).find('#content').show();
		$('#' + this.window_id).find('#footer').show();
		$('#' + this.window_id).find('#theme_dropdown').show();
		$("#window_minimize").show();
		$('#' + this.window_id).width("calc(100% - 20px)");
		$('#' + this.window_id).height("calc(100% - 20px)");
		$('#' + this.window_id).css("top", "7px");
		$('#' + this.window_id).css("left", "7px");
		$('#' + this.window_id).css("min-height", "");

		this.maximized = true;
		this.minimized = false;
	},

	minimize : function(){
		$('#' + this.window_id).find('#content').hide();
		$('#' + this.window_id).find('#footer').hide();
		$('#' + this.window_id).find('#theme_dropdown').hide();
		$("#window_minimize").hide();
		$('#' + this.window_id).width("50%");
		$('#' + this.window_id).height("25px");
		$('#' + this.window_id).css("top", "calc(100% - 30px)");
		$('#' + this.window_id).css("left", "25%");
		$('#' + this.window_id).css("min-height", "30px");

		this.minimized = true;
	},

	normalize : function(){
		$('#' + this.window_id).find('#content').show();
		$('#' + this.window_id).find('#footer').show();
		$('#' + this.window_id).find('#theme_dropdown').show();
		$("#window_minimize").show();
		$('#' + this.window_id).width("");
		$('#' + this.window_id).height("");
		$('#' + this.window_id).css("top", "");
		$('#' + this.window_id).css("left", "");
		$('#' + this.window_id).css("min-height", "");

		this.maximized = false;
		this.minimized = false;
	},

	clearSelection : function(){
		if (window.getSelection) {
			if (window.getSelection().empty) {  // Chrome
				window.getSelection().empty();
			} else if (window.getSelection().removeAllRanges) {  // Firefox
				window.getSelection().removeAllRanges();
			}
		} else if (document.selection) {  // IE
			document.selection.empty();
		}
	},

	makeDragable : function(move, dragbox, useBorder) {
		if(dragbox == undefined) dragbox = move;
		if(useBorder == undefined) useBorder = true;

		var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0, dragged = false;

		dragbox.onmousedown = dragMouseDown;

		function dragMouseDown(e) {
			e = e || window.event;
			if(configurationWindow.minimized){
				document.onmouseup = null;
				document.onmousemove = null;
				return;
			}
			// get the mouse cursor position at startup:
			pos3 = e.clientX;
			pos4 = e.clientY;
			document.onmouseup = closeDragElement;
			// call a function whenever the cursor moves:
			document.onmousemove = elementDrag;
		}

		function elementDrag(e) {
			e = e || window.event;
			
			// calculate the new cursor position:
			pos1 = pos3 - e.clientX;
			pos2 = pos4 - e.clientY;
			pos3 = e.clientX;
			pos4 = e.clientY;
			
			// set the element's new position:
			var new_top = move.offsetTop - pos2;
			var new_left = move.offsetLeft - pos1;
			
			if(configurationWindow.maximized){
				configurationWindow.normalize();
				new_top = e.clientY;
				new_left = e.clientX;
			}
			
			if(useBorder){
				var max_width = $(window).width() - $(move).width();
				var max_height = $(window).height() - $(move).height();
				if(new_top < 0) new_top = 0;
				else if(new_top > max_height) new_top = max_height; 
				if(new_left < 0) new_left = 0;
				else if(new_left > max_width) new_left = max_width;
			}
			
			move.style.left = new_left + "px";
			move.style.top = new_top + "px";
			dragged = true;
			
			configurationWindow.clearSelection();
		}

		function closeDragElement() {
			/* stop moving when mouse button is released:*/
			if(useBorder && dragged){
				if(move.style.top.indexOf("%") == -1 && move.style.top.replace("px", "") < 2)
					configurationWindow.maximize();
			}
			document.onmouseup = null;
			document.onmousemove = null;
		}
	},

	isArray : function(what) {
		return Object.prototype.toString.call(what) === '[object Array]';
	},

	isObject : function(what) {
		return Object.prototype.toString.call(what) === '[object Object]';
	},

	join : function(labelFirst, label, element){
		return (labelFirst ? label + " " + element : element + " " + label);
	},

	replaceAll : function(target, search, replacement) {
		return target.replace(new RegExp(search, 'g'), replacement);
	},

	revertChanges : function(){
		$('#' + this.window_id).find("#content").find("input[type=text], input[type=password], input[type=number], input[type=color], textarea").each(function(){
			$(this).val($(this).attr("value"));
			$(this).css("border", "");
		});

		$('#' + this.window_id).find("#content").find("select").each(function(){
			this.value = $(this).find("option[selected]").val();
			$(this).css("border", "");
		});

		$('#' + this.window_id).find("#content").find('input[type=checkbox]:not(.toggle)').each(function() {
			this.checked = $(this).attr("default") == "true";
			$(this).css("outline", "");
		});

		$($(this)).change();
		this.updateChanged();
	},

	saveChanges : function(){
		$('#' + this.window_id).find("#content").find("input[type=text], input[type=password], input[type=number], input[type=color], textarea").each(function(){
			configurationWindow.set(this.id, this.value);
			$(this).attr("value", this.value);
			$(this).css("border", "");
		});

		$('#' + this.window_id).find("#content").find("select").each(function(){
			configurationWindow.set(this.id, this.value);

			var main_val = this.value;

			$(this).find("option[selected]").removeAttr("selected");
			$(this).find("option").filter(function() {
				return this.innerHTML == main_val;
			}).attr("selected", "selected");

			this.value = main_val;

			$(this).css("border", "");
		});

		$('#' + this.window_id).find("#content").find('input[type=checkbox]:not(.toggle)').each(function() {
			configurationWindow.set(this.id, this.checked);
			$(this).attr("default", this.checked);
			$(this).css("outline", "");
		});

		this.updateChanged();
		this.save();
	},

    ResetSettings : function(){
        if(this.isArray(this.data.content)){
			for(i = 0; i < this.data.content.length; i++){
				if(this.isObject(this.data.content[i])){
					var object = this.data.content[i];
                    object.default = (object.default == undefined ? "" : object.default);
                    
                    var elem = $('#' + this.window_id).find("#content").find("#" + object.id);
					
					var type = elem.attr("type");
					if(type == undefined && elem.is("select")) type = "select"; 
						
                    switch(type){
						case "text":
						case "number":
						case "password":
						case "select":
						case "textarea":
							$(elem).val(object.default);
							break;
						case "checkbox":
							$(elem).prop("checked", object.default);
							break;
						default: break;
					}
					$(elem).change();
                }
            }
        }
        this.updateChanged();
    },

	close : function(){
		if(this.changed){
			if(!confirm(this.data.confirm_close)){
				return false;
			}
		}
		$('#' + this.window_id).attr("style", "display: none;");
		return true;
	},
	
    open : function(data){
        $('#' + this.window_id).attr("style", "");
    },

	create : function(data){
		//var data = JSON.parse(content);

        this.data = data;
		
        if(this.window_id != undefined)
            $('#' + this.window_id).remove();

		$('#window_style').remove();
		$('#font-awesome').remove();

		if(data.id == undefined) data.id = "window";
		this.window_id = data.id;

		this.load();
	
		$('head').append('<link id="font-awesome" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">');

		if (data.theme == undefined) data.theme = "mac";
		if (!(data.theme == "mac" || data.theme == "win10" || data.theme == "winXP")) data.theme = "mac";
		
		var saved_theme = GM_getValue("config_theme");
		if(data.theme_selector == undefined || data.theme_selector == true || data.theme_selector == "true"){
			data.theme_selector = true;
			if(saved_theme != undefined) data.theme = saved_theme;
		}else{
			data.theme_selector = false;
		}
		
		if(data.width == undefined) data.width = 50;
		if(data.height == undefined) data.height = 50;
		
		var section_color = "#c9c9c9";
		var subsection_color = "#f1f1f1";
		
		var style = "<style id='window_style'>";
		if(data.theme == "mac"){
			style += `
				#` + this.window_id + ` > #top > .btn {
					height: 16px;
					width: 16px;
					background-color: #bbb;
					border-radius: 50%;
					float: right;
					margin-right: 10px;
					display: inline-block;
					font-size: 10px;
					text-align: center;
					color: white;
					cursor: pointer;
					//font-weight: bold;
				}

				#` + this.window_id + ` > #top > .title {
					margin: auto;
					font-size: 16px;
					font-weight: bold;
					cursor: move;
				}

				#` + this.window_id + ` {
					border: 3px solid #f1f1f1;
					border-top-left-radius: 3px;
					border-top-right-radius: 3px;
					height: ` + data.height + `%;
					width: ` + data.width + `%;
					top: ` + ((100 - data.height) / 2) + `%;
					left: ` + ((100 - data.width) / 2) + `%;
					position: fixed;
					z-index: 11000;
					background: white;
					min-width: 250px;
					min-height: 250px;
					resize: both;
					overflow: auto;
					line-height: unset;
					overflow-y: hidden;`
				+ (data.font != undefined ?
					 (data.font.size != undefined ? "font-size: " + data.font.size + ";" : "")  +
					 (data.font.family != undefined ? "font-family: " + data.font.family + ";" : "")
				   : "") +
				`}

				#` + this.window_id + ` > #top {
					padding: 10px;
					//height: 20px;
					background: #f1f1f1;
					border-top-left-radius: 4px;
					border-top-right-radius: 4px;
					position: absolute;
					width: calc(100% - 20px);
				}
			`;
		}else if(data.theme == "win10"){
			section_color = "#1f9cff";
			subsection_color = "#9dd4ff";
			style += `
				#` + this.window_id + ` > #top > .btn {
					height: 22px;
					width: 30px;
					float: right;
					margin-right: 5px;
					display: inline-block;
					font-size: 16px;
					text-align: center;
					color: white;
					cursor: pointer;
					color: black;
					padding: 2px;
				}
				
				#` + this.window_id + ` > #top > #window_minimize:hover, #` + this.window_id + ` > #top > #window_maximize:hover {
					background-color: #ddd;
				}
				
				#` + this.window_id + ` > #top > #window_close:hover {
					background-color: red;
				}

				#` + this.window_id + ` > #top > .title {
					margin: auto;
					font-size: 16px;
					font-weight: bold;
					cursor: move;
					padding: 10px;
				}

				#` + this.window_id + ` {
					border: 3px solid #1f9cff;
					height: ` + data.height + `%;
					width: ` + data.width + `%;
					top: ` + ((100 - data.height) / 2) + `%;
					left: ` + ((100 - data.width) / 2) + `%;
					position: fixed;
					z-index: 11000;
					background: white;
					min-width: 250px;
					min-height: 250px;
					resize: both;
					overflow: auto;
					line-height: unset;
					overflow-y: hidden;`
				+ (data.font != undefined ?
					 (data.font.size != undefined ? "font-size: " + data.font.size + ";" : "")  +
					 (data.font.family != undefined ? "font-family: " + data.font.family + ";" : "")
				   : "") +
				`}

				#` + this.window_id + ` > #top {
					//padding: 10px;
					//height: 20px;
					background: #1f9cff;
					position: absolute;
					width: 100%;
				}
			`;
		}else if(data.theme == "winXP"){
			section_color = "#226ce7";
			subsection_color = "#4094ff";
			style += `
				#` + this.window_id + ` > #top > .btn {
					height: 20px;
					width: 20px;
					float: right;
					margin-right: 5px;
					margin-top: 5px;
					display: inline-block;
					font-size: 16px;
					text-align: center;
					color: white;
					cursor: pointer;
					color: white;
					border-radius: 2px;
					padding: 2px;
					border: 1px solid white;
					background: linear-gradient(135deg, #7EAED6 0%, #1B72FF 50%, #1655BE 100%);
				}
				
				#` + this.window_id + ` > #top > #window_minimize:hover, #` + this.window_id + ` > #top > #window_maximize:hover {
					background: linear-gradient(135deg, #6a93b5 0%, #1862da 50%, #124499 100%);
				}
				
				#` + this.window_id + ` > #top > #window_close {
					background: linear-gradient(135deg, #F1A689 0%, #C0442A 50%, #C2311E 100%);
				}
				
				#` + this.window_id + ` > #top > #window_close:hover {
					background: linear-gradient(135deg, #c3846c 0%, #a43923 50%, #982415 100%);
				}

				#` + this.window_id + ` > #top > .title {
					margin: auto;
					font-size: 16px;
					font-weight: bold;
					cursor: move;
					padding: 10px;
					color: white;
				}

				#` + this.window_id + ` {
					border-left: 3px solid #0056e4;
					border-right: 3px solid #0056e4;
					border-bottom: 3px solid #0056e4;
					height: ` + data.height + `%;
					width: ` + data.width + `%;
					top: ` + ((100 - data.height) / 2) + `%;
					left: ` + ((100 - data.width) / 2) + `%;
					position: fixed;
					z-index: 11000;
					background: white;
					min-width: 250px;
					min-height: 250px;
					border-radius: 8px;
					resize: both;
					overflow: auto;
					line-height: unset;
					overflow-y: hidden;`
				+ (data.font != undefined ?
					 (data.font.size != undefined ? "font-size: " + data.font.size + ";" : "")  +
					 (data.font.family != undefined ? "font-family: " + data.font.family + ";" : "")
				   : "") +
				`}

				#` + this.window_id + ` > #top {
					//padding: 10px;
					//height: 20px;
					border-radius: 5px 5px 0px 0px;
					background: linear-gradient(to bottom, #4094ff 0%, #0056e4 13%, #0056e4 71%, #16428b 100%);
					position: absolute;
					width: 100%;
				}
			`;
		}
		
		style += `
			#` + this.window_id + ` > #footer {
				text-align: right;
				margin: 0px 0px 4px -20px;
				height: 40px;
				border-top-left-radius: 4px;
				border-top-right-radius: 4px;
				position: absolute;
				width: 100%;
				bottom: 0;
				pointer-events: none;
			}

			#` + this.window_id + ` > #footer > button {
				background-color: #f1f1f1;
				border: none;
				color: black;
				padding: 12px 40px;
				font-size: 14px;
				cursor: pointer;
				margin-left: 5px;
				pointer-events: all;
			}

			#` + this.window_id + ` > #footer > button:hover {
				background-color: RoyalBlue;
				color: white;
			}
			
			#` + this.window_id + ` > #footer > button:disabled {
				background-color: darkgrey;
				color: white;
			}
			
			#` + this.window_id + ` > #content {
				padding: 10px;
				margin-top: 40px;
				overflow-y: scroll;
				height: calc(100% - 75px);
				overflow-wrap: break-word;
			}

			#` + this.window_id + ` > #content > input,#` + this.window_id + ` > #content > select {`
				 + (data.font != undefined ?
				 (data.font.size != undefined ? "font-size: " + data.font.size + ";" : "")  +
				 (data.font.family != undefined ? "font-family: " + data.font.family + ";" : "")
			   : "") +
			`}

			#` + this.window_id + ` > #content > br {
				display: block;
				margin-top: 4px;
				content: " ";
			}

			#` + this.window_id + ` > #theme_dropdown {
				float: left;
				bottom: 5px;
				position: absolute;
				left: 5px;
				border: none;
				-webkit-appearance: none;
				-moz-appearance: none;
				appearance: none;
				color: gray;
				background-color: transparent;
			}
			
			#` + this.window_id + ` > #theme_dropdown > option {
				color: black;
			}
			
			.no-margin {
				margin: 0px;
			}
			
			.wrap-collapsible {
				margin-bottom: 1.2rem 0;
			}

			.toggle {
				display: none;
			}

			.lbl-toggle {
				display: block;
				cursor: pointer;
				
				transition: all 0.25s ease-out;
			}
			
			.lbl-toggle h2, .lbl-toggle h4 {
				display: inline;
			}

			.lbl-toggle:hover {
				color: white;
			}

			.lbl-toggle::before {
				content: ' ';
				display: inline-block;

				border-top: 5px solid transparent;
				border-bottom: 5px solid transparent;
				border-left: 5px solid currentColor;
				vertical-align: middle;
				margin-right: .7rem;
				transform: translateY(-2px);

				transition: transform .2s ease-out;
			}

			.toggle:checked + .lbl-toggle::before {
				transform: rotate(90deg) translateX(-3px);
			}

			.collapsible-content {
				max-height: 0px;
				overflow: hidden;
				transition: max-height .25s ease-in-out;
			}

			.toggle:checked + .lbl-toggle + .collapsible-content {
				max-height: unset;
			}

			.collapsible-content .content-inner {
				//background: rgba(161, 161, 161, 0.2);
				//border: 1px solid black;
			}
		`;
		
		style += "<style>";
		
		$('head').append(style);
		
		if(data.theme_section_color == undefined || data.theme_section_color == false){
			section_color = "#c9c9c9";
			subsection_color = "#f1f1f1";
		}
		
		var content = "";

		if(this.isArray(data.content)){
			var section_collapsible = false;
			var subsection_collapsible = false;
			var collapsible_id = 1;
			
			for(i = 0; i < data.content.length; i++){
				if(this.isObject(data.content[i])){
					var label_first = undefined;
					Object.keys(data.content[i]).forEach(function(key){
						if(label_first != undefined) return;

						if(key == "label") label_first = true;
						else if(key == "type") label_first = false;
					});

					var label = this.replaceAll(data.content[i].label, "  ", "&nbsp;&nbsp;");

					var object = data.content[i];

					if(object.style != undefined) object.style = " style='" + object.style + "'";
					else object.style = "";

					if(object.require != undefined) object.style += " require='" + object.require + "'";
					
					switch(object.type){
						case "p":
							content += "<p class='no-margin'" + object.style + ">" + label  + "</p>";
							break;
						case "h1":
							content += "<h1 class='no-margin'" + object.style + ">" + label + "</h1>";
							break;
						case "h2":
							content += "<h2 class='no-margin'" + object.style + ">" + label + "</h2>";
							break;
						case "h3":
							content += "<h3 class='no-margin'" + object.style + ">" + label + "</h3>";
							break;
						case "h4":
							content += "<h4 class='no-margin'" + object.style + ">" + label + "</h4>";
							break;
						case "section":
							if(object.align == undefined) object.align = "center";
							if(object.background == undefined) object.background = section_color;
							
							if(subsection_collapsible){
								content += "</div></div></div>";
								subsection_collapsible = false;
							}
							
							if(section_collapsible){
								content += "</div></div></div>";
								section_collapsible = false;
							}
							
							if(object.collapsible != undefined && object.collapsible){
								content += "<div class='wrap-collapsible'><input id='collapsible" + collapsible_id + "' class='toggle' type='checkbox' " + (object.collapsed != undefined && object.collapsed == false ? "checked" : "") + "><label style='margin: 5px 0px 0px 0px; background: " + object.background + "; text-align: " + object.align + ";' for='collapsible" + collapsible_id + "' class='lbl-toggle'><h2>" + label + "</h2></label><div class='collapsible-content'><div class='content-inner'>";
								section_collapsible = true;
								collapsible_id++;
							}else{
								content += "<div width='100%' style='margin: 5px 0px; background: " + object.background + "; text-align: " + object.align + ";'><h2 class='no-margin'>" + label + "</h2></div>";
							}
							break;
						case "subsection":
							if(object.align == undefined) object.align = "center";
							if(object.background == undefined) object.background = subsection_color;
							
							if(subsection_collapsible){
								content += "</div></div></div>";
								subsection_collapsible = false;
							}
							
							if(object.collapsible != undefined && object.collapsible){
								content += "<div class='wrap-collapsible'><input id='collapsible" + collapsible_id + "' class='toggle' type='checkbox' " + (object.collapsed != undefined && object.collapsed == false ? "checked" : "") + "><label style='margin: 5px 0px 0px 0px; background: " + object.background + "; text-align: " + object.align + ";' for='collapsible" + collapsible_id + "' class='lbl-toggle'><h4>" + label + "</h4></label><div class='collapsible-content'><div class='content-inner'>";
								subsection_collapsible = true;
								collapsible_id++;
							}else{
								content += "<div width='100%' style='margin: 5px 0px; background: " + object.background + "; text-align: " + object.align + ";'><h4 class='no-margin'>" + label + "</h4></div>";
							}
							break;
						case "text":
							var value = this.getElseSet(object.id, object.default, "");
							
							content += this.join(label_first, label, "<input id='" + object.id + "'" + object.style + " type='text' value='" + value + "' />");

							content += "<br>";
							break;
						case "textarea":
							var value = this.getElseSet(object.id, object.default, "");
							
							content += this.join(label_first, label, "<textarea id='" + object.id + "'" + object.style + " value='" + value + "'>" + value + "</textarea>");

							content += "<br>";
							break;
						case "password":
							var value = this.getElseSet(object.id, object.default, "");
							
							content += this.join(label_first, label, "<input id='" + object.id + "'" + object.style + " type='password' value='" + value + "' />");

							content += "<br>";
							break;
						case "checkbox":
							var value = this.getElseSet(object.id, object.default, false);
							
							if(value == "true" || value == true) value = true;
							else value = false;

							label = "<label for='" + object.id + "'>" + label + "</label>";
							
							content += this.join(label_first, label, "<input id='" + object.id + "'" + object.style + " default='" + value + "' type='checkbox' " + (value ? "checked" : "") + "/>");

							content += "<br>";
							break;
						case "select":
							var value = this.getElseSet(object.id, object.default, "");

							var select = " <select" + object.style + " id='" + object.id + "'>";
							object.options.forEach(function(opt){
								if(opt == value){
									select += "<option selected>" + opt + "</option>";
								}else{
									select += "<option>" + opt + "</option>";
								}
							});
							select += "</select> ";

							content += this.join(label_first, label, select);

							content += "<br>";
							break;
						case "numeric":
							var value = this.getElseSet(object.id, object.default, 0);
							
							var element = "<input id='" + object.id + "'" + object.style + " type='number' value='" + value + "'";
							if(object.min != undefined) element += " min='" + object.min + "'";
							if(object.max != undefined) element += " max='" + object.max + "'";
							element += " />";
							
							content += this.join(label_first, label, element);

							content += "<br>";
							break;
						case "color":
							var value = this.getElseSet(object.id, object.default, "#FFFFFF");

							content += this.join(label_first, label, "<input id='" + object.id + "'" + object.style + " type='color' value='" + value + "' />");

							content += "<br>";
							break;
						default: break;
					}
				}else{
					content += "<p>" + data.content[i] + "</p>";
				}
			}
			
			if(subsection_collapsible){
				content += "</div></div></div>";
				section_collapsible = false;
			}
			
			if(section_collapsible){
				content += "</div></div></div>";
				section_collapsible = false;
			}
		}else{
			content = data.content;
		}
		//content += "<br style='height: 25px;' />";
		content += "<br><br><br>";
		
		var buttons = "";

        if(data.completeresetbutton == undefined || data.completeresetbutton == true || data.completeresetbutton == "true"){
            buttons += "<button id='completeResetButton'><i class='fa fa-trash'></i></button>";
        }

		if(data.revertbutton == undefined || data.revertbutton == true ||  data.revertbutton == "true"){
			buttons += "<button id='revertButton'><i class='fa fa-undo'></i></button>";
		}

		if(data.savebutton == undefined || data.savebutton == true ||  data.savebutton == "true"){
			buttons += "<button id='saveButton'><i class='fa fa-save'></i></button>";
		}

		var topbuttons = "";
		if(data.top == undefined || data.top.close == undefined || data.top.close == "true"){
			if(data.theme == "mac")		topbuttons += '<span id="window_close" class="btn" style="background:#ED594A; margin-right: 20px;"><i class="fa fa-times" style="vertical-align: sub;"></i></span>';
			else if(data.theme == "win10") topbuttons += '<span id="window_close" class="btn" style="margin-right: 0px;"><i class="fa fa-times"></i></span>';
			else if(data.theme == "winXP") topbuttons += '<span id="window_close" class="btn"><i class="fa fa-times"></i></span>';
		}
		
		if(data.top == undefined || data.top.maximize == undefined || data.top.maximize == "true"){
			if(data.theme == "mac")		topbuttons += '<span id="window_maximize" class="btn" style="background:#FDD800;"><i class="fa fa-window-maximize" style="vertical-align: sub;"></i></span>';
			else if(data.theme == "win10" || data.theme == "winXP") topbuttons += '<span id="window_maximize" class="btn"><i class="fa fa-window-maximize"></i></span>';
		}
		
		if(data.top == undefined || data.top.minimize == undefined || data.top.minimize == "true"){
			if(data.theme == "mac")		topbuttons += '<span id="window_minimize" class="btn" style="background:#5AC05A;"><i class="fa fa-window-minimize" style="vertical-align: sub;"></i></span>';
			else if(data.theme == "win10" || data.theme == "winXP") topbuttons += '<span id="window_minimize" class="btn"><i class="fa fa-window-minimize"></i></span>';
		}
		

		$('body').append(`
			<div id="` + this.window_id + `" style='display: none;' class="window">
				<div id="top">
					` + topbuttons +
					`<p class="title">` + data.title + `</p>
				</div>

				<div id="content">
					` + content + `
				</div>

				<div id="footer">
					` + buttons + `
				</div>
				` +
				(data.theme_selector ? `<select id="theme_dropdown" value="Theme">
					<option value="std" style="display: none;">Theme</option>
					<option value="mac">Mac</option>
					<option value="win10">Windows 10</option>
					<option value="winXP">Windows XP</option>
				</select>` : "") + `
			</div>
		`);

		this.makeDragable($('#' + this.window_id)[0], $('#' + this.window_id).find("#top")[0], true);

        var confirm_close = "Unsaved changes. Discard changes?";
        var confirm_revert = "Reset all changes?";
        var confirm_reset = "Bring settings back to factory settings?";
        if(data.confirm_close != undefined) confirm_close = data.confirm_close;
        if(data.confirm_revert != undefined) confirm_revert = data.confirm_revert;
        if(data.confirm_reset != undefined) confirm_reset = data.confirm_reset;

		$('#' + this.window_id).find('#revertButton').click(function(){
            if(confirm(confirm_revert)) configurationWindow.revertChanges();
		});
		
		$('#' + this.window_id).find('#saveButton').click(function(){
			configurationWindow.saveChanges();
            $('#' + configurationWindow.window_id).find('#saveButton').css("background", "lime");
            setTimeout(function(){
                $('#' + configurationWindow.window_id).find('#saveButton').css("background", "");
            }, 1000);
		});

        $('#' + this.window_id).find('#completeResetButton').click(function(){
			if(confirm(confirm_reset)) configurationWindow.ResetSettings();
		});

        $('#' + this.window_id).find('#window_close').click(function(){
            configurationWindow.close();
		});

		//================ WINDOW RESIZE BUTTONS ===================//
		$('#' + this.window_id).find('#window_maximize').click(function(){
			if(configurationWindow.maximized && !configurationWindow.minimized)
				configurationWindow.normalize();
			else
				configurationWindow.maximize();
		});

		$('#' + this.window_id).find('#window_minimize').click(function(){
			configurationWindow.minimize();
		});

		$('#' + this.window_id).find("#top").dblclick(function(){
			if(configurationWindow.minimized){
				if(configurationWindow.maximized)
					configurationWindow.maximize();
				else
					configurationWindow.normalize();
			}else{
				if(configurationWindow.maximized)
					configurationWindow.normalize();
				else
					configurationWindow.maximize();
			}
			configurationWindow.clearSelection();
		});

		//==================== THEME SELECTOR =======================//
		$('#' + this.window_id).find("#theme_dropdown").change(function(){
			if(! configurationWindow.close()) return;
			GM_setValue("config_theme", this.value);
			configurationWindow.create(configurationWindow.data);
			configurationWindow.open();
		});
		

		//==================== FIELD CHANGE LISTENER =====================//
		$('#' + this.window_id).find("#content").find("input[type=text], input[type=number], input[type=password], input[type=color], textarea").change(function(){
			if($(this).attr("value") != $(this).val())
				$(this).css("border", "#fff400 solid 2px");
			else
				$(this).css("border", "");

			configurationWindow.updateChanged();
		});
		 
		$('#' + this.window_id).find("#content").find("input[type=number]").change(function(){
			if($(this).attr("min") != undefined && $(this).val() < parseFloat($(this).attr("min")))
				$(this).val($(this).attr("min"));
			else if($(this).attr("max") != undefined && $(this).val() > parseFloat($(this).attr("max"))){
				$(this).val($(this).attr("max"));
			}
			
			configurationWindow.updateChanged();
		});

		

		$('#' + this.window_id).find("#content").find("select").change(function(){
			if(this.value != $(this).find("option[selected]").val())
				$(this).css("border", "#fff400 solid 2px");
			else
				$(this).css("border", "");

			configurationWindow.updateChanged();
		});

		$('#' + this.window_id).find("#content").find('input[type=checkbox]:not(.toggle)').change(function() {
			if(this.checked != ($(this).attr("default") == "true")){
				$(this).css("outline", "#fff400 solid 3px");
			}else{
				$(this).css("outline", "");
			}
			
			$('[require="' + this.id + '"]').prop("disabled", !this.checked);
			
			configurationWindow.updateChanged();
		});
		
		$('#' + this.window_id).find("#content").find('input[type=checkbox]:not(.toggle)').trigger("change");
		
		$(document).keyup(function(e) {
			if (e.keyCode == 27) {
				configurationWindow.close();
			}
		});
		
		this.updateChanged();
	}
};