Browse Source

Added theme switch

Eiyeron 10 years ago
parent
commit
826c082fdb

+ 0 - 0
app/www/data/themes/default/script.js


+ 0 - 0
app/www/css/style.css → app/www/data/themes/default/style.css


+ 213 - 168
app/www/data/themes/omnimaga/style.css

@@ -1,83 +1,88 @@
 html,body{
-	width: 100%;
-	height: 100%;
-	padding: 0;
-	margin: 0;
-	overflow: hidden;
+        width: 100%;
+        height: 100%;
+        padding: 0;
+        margin: 0;
+        overflow: hidden;
 }
 .unselectable{
-	cursor: default;
-	display: block;
-	margin: auto;
-	margin-bottom: 1em;
-	vertical-align: middle;
-	text-align: center;
+        cursor: default;
+        display: block;
+        margin: auto;
+        margin-bottom: 1em;
+        vertical-align: middle;
+        text-align: center;
 }
 .fill{
-	width: 100%;
-	height: 100%;
+        width: 100%;
+        height: 100%;
 }
 .row{
-	display: table-row;
+        display: table-row;
 }
 .cell{
-	display: table-cell;
+        display: table-cell;
 }
 .date_cell{
-	word-wrap: normal;
-	white-space: pre;
-	word-break: keep-all;
+        word-wrap: normal;
+        white-space: pre;
+        word-break: keep-all;
 }
 .unselectable,#tabs-list div.tab{
-	-webkit-touch-callout: none;
-	-webkit-user-select: none;
-	-khtml-user-select: none;
-	-moz-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
+        -webkit-touch-callout: none;
+        -webkit-user-select: none;
+        -khtml-user-select: none;
+        -moz-user-select: none;
+        -ms-user-select: none;
+        user-select: none;
 }
 .close-button{
-	float: right;
-	font-weight: bold;
-	font-size: 24px;
-	margin-top: -5px;
-	font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
-    line-height: 17px;
-    margin-top: 0;
-    display: block;
+        float: right;
+        font-weight: bold;
+        font-size: 24px;
+        margin-top: -5px;
+        font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
+        line-height: 17px;
+        margin-top: 0;
+        display: block;
+        cursor: pointer;
 }
 .close-button:hover{
-	color: red;
+        color: red;
 }
 #head{
-	right: 0;
-	top: 0;
-	width: 100%;
-	height: 40px;
-	border-bottom-style: solid;
-	background-color: white;
-	transition: height 0.3s;
-	z-index: 10;
+        right: 0;
+        top: 0;
+        width: 100%;
+        height: 40px;
+        border-bottom-style: solid;
+        background-color: white;
+        transition: height 0.3s;
+        z-index: 10;
     font-size: 10px;
     font-family:verdana,sans-serif;
     background-color: #DFEFFF;
 }
 #info{
-	display: table;
-	width: 100%;
+        display: table;
+        width: 100%;
 }
 #title{
-	display: table-cell;
+        display: table-cell;
 }
 #topic{
-	display: table-cell;
-	text-align: right;
+        display: table-cell;
+        text-align: right;
 }
+<<<<<<< HEAD
 #content{
-	width: 100%;
-	height: calc(100% - 61px);
-	top: 41px;
-	left: 0;
+=======
+#content,#console-log{
+>>>>>>> 602ebd94f77c751ea4ecdee3da8b46a2f06b66f9
+        width: 100%;
+        height: calc(100% - 61px);
+        top: 41px;
+        left: 0;
     font-size: 10px;
     font-family:verdana,sans-serif;
     line-height:13px;
@@ -87,200 +92,240 @@ html,body{
     background-color: #cae4ff;
 }
 #content-list a, #content-list a:hover, #content-list a:active , #content-list a:active, #content-list a:link {
-	color:blue;
-	text-decoration: none;
-	border-bottom: 1px solid rgba(0, 0, 255, 0.3);
+        color:blue;
+        text-decoration: none;
+        border-bottom: 1px solid rgba(0, 0, 255, 0.3);
 
 }
 #content-list a:hover {
-	text-decoration: none;
-	text-shadow: 0 0 4px rgba(0, 40, 170, 0.5);
+        text-decoration: none;
+        text-shadow: 0 0 4px rgba(0, 40, 170, 0.5);
+}
+
+<<<<<<< HEAD
+=======
+#console-log{
+    font-size: 14px;
+        display: none;
+}
+#console-log-pre{
+        height: 100%;
+        margin: 0;
+        padding: 2px;
+}
+#console-log-controls{
+        position: absolute;
+        bottom: 22px;
+        width: 100%;
+        overflow: hidden;
 }
 
+>>>>>>> 602ebd94f77c751ea4ecdee3da8b46a2f06b66f9
 #settings,#users{
-	font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
-	font-size: 12px;
-	bottom: 0;
-	height: 19px;
-	background-color: white;
-	border-left-style: solid;
-	border-top-style: solid;
-	margin-top: -1px;
-	transition: width 0.5s, height 0.5s, right 0.5s;
+        font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
+        font-size: 12px;
+        bottom: 0;
+        height: 19px;
+        background-color: white;
+        border-left-style: solid;
+        border-top-style: solid;
+        margin-top: -1px;
+        transition: width 0.5s, height 0.5s, right 0.5s;
 }
 #settings span,#users span{
-	cursor: pointer;
+        cursor: pointer;
+}
+<<<<<<< HEAD
+=======
+#settings.open span,#users.open.span{
+        cursor: default;
 }
+#settings.open span.close-button,#users.open span.close-button{
+        cursor: pointer;
+}
+>>>>>>> 602ebd94f77c751ea4ecdee3da8b46a2f06b66f9
 #users{
-	right: 0;
-	width: 36px;
-	z-index: 1;
-	background-color: #cae4ff;
+        right: 0;
+        width: 36px;
+        z-index: 1;
+        background-color: #cae4ff;
 }
 #settings{
-	width: 50px;
+        width: 50px;
     border-top-color: rgba(102, 153, 255, 0.6);
-	border-right-style: solid;
-	right: 36px;
-	background-color: #cae4ff;
+        border-right-style: solid;
+        right: 36px;
+        background-color: #cae4ff;
 
 }
 #settings.hovered,#users.hovered{
-	height: 21px;
+        height: 21px;
 }
 #settings.open,#users.open{
-	width: 150px;
-	height: 100%;
-	right: 0;
-	z-index: 20;
+        width: 150px;
+        height: 100%;
+        right: 0;
+        z-index: 20;
 }
 #settings.open{
-	width: 300px;
+        width: 300px;
 }
 
 #settings input, #settings select {
-	background-color: #DFEFFF;
-	border-radius: 2px;
-	border: solid 1px rgba(102, 153, 255, 0.9);
+        background-color: #DFEFFF;
+        border-radius: 2px;
+        border: solid 1px rgba(102, 153, 255, 0.9);
 
 }
 #entry{
-	width: 100%;
-	border-top-style: solid;
-	height: 19px;
-	bottom: 0;
+        width: 100%;
+        border-top-style: solid;
+        height: 19px;
+        bottom: 0;
 
 }
 #input{
-	width: calc(100% - 126px);
-	height: 17px;
-	margin: 0;
-	padding: 1px;
-	border-style: none;
-	clear: none;
-	bottom: 0;
-	left: 0;
-	background-color: #cae4ff;
+        width: calc(100% - 126px);
+        height: 17px;
+        margin: 0;
+        padding: 1px;
+        border-style: none;
+        clear: none;
+        bottom: 0;
+        left: 0;
+        background-color: #cae4ff;
 }
 #send{
 
-	clear: none;
-	bottom: 0;
-	right: 88px;
-	width: 48px;
-	padding: 0;
-	padding-bottom: 4px;
-	margin: 0;
-	height: 19px;
-	border-style: none;
-	border-left: 1px solid;
-	background-color: #cae4ff;
-	transition: background-color 0.2s;
-	font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
-	font-size: 12px;
-	vertical-align: top;
-	text-align: center;
+        clear: none;
+        bottom: 0;
+        right: 88px;
+        width: 48px;
+        padding: 0;
+        padding-bottom: 4px;
+        margin: 0;
+        height: 19px;
+        border-style: none;
+        border-left: 1px solid;
+        background-color: #cae4ff;
+        transition: background-color 0.2s;
+        font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
+        font-size: 12px;
+        vertical-align: top;
+        text-align: center;
 }
 #send:hover{
-	background-color: #DFEFFF;
+        background-color: #DFEFFF;
 }
 #send.clicked{
-	background-color: rgba(102, 153, 255, 0.9);
+        background-color: rgba(102, 153, 255, 0.9);
 }
 #popup-title, #send {
-	font-variant: small-caps;
+        font-variant: small-caps;
 }
 
+<<<<<<< HEAD
 #content,#head,#users,#entry,#input,#send,#settings{
- 	border-color: rgba(102, 153, 255, 0.6);
- 	border-top-color: rgba(102, 153, 255, 0.9);
-	border-width: 1px;
-	position: absolute;
-	overflow: hidden;
-}
+=======
+#console-log,#content,#head,#users,#entry,#input,#send,#settings{
+>>>>>>> 602ebd94f77c751ea4ecdee3da8b46a2f06b66f9
+        border-color: rgba(102, 153, 255, 0.6);
+        border-top-color: rgba(102, 153, 255, 0.9);
+        border-width: 1px;
+        position: absolute;
+        overflow: hidden;
+}
+<<<<<<< HEAD
 #content{
-	overflow-y: scroll;
+=======
+#console-log,#content{
+>>>>>>> 602ebd94f77c751ea4ecdee3da8b46a2f06b66f9
+        overflow-y: scroll;
 }
 #users,#input,#send,#settings{
-	position: fixed;
+        position: fixed;
 }
 #content-list,#user-list,#settings-list,#tabs-list{
-	list-style-type: none;
-	margin: 0;
-	padding: 0;
-	overflow-y: auto;
-	word-wrap: break-word;
-	white-space: pre-wrap;
-	word-break: break-all;
+        list-style-type: none;
+        margin: 0;
+        padding: 0;
+        overflow-y: auto;
+        word-wrap: break-word;
+        white-space: pre-wrap;
+        word-break: break-all;
 }
 #content-list,#user-list,#tabs-list{
-	width: 100%;
-	height: 100%;
+        width: 100%;
+        height: 100%;
 }
 #content-list,#settings-list{
-	display: table;
-	table-layout: fixed;
+        display: table;
+        table-layout: fixed;
 }
 #settings-list > li{
-	line-height: 4px;
+        line-height: 4px;
 }
 #user-list{
-	font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
-	font-size: 15px;
+        font-family: Arial,Liberation Sans,DejaVu Sans,sans-serif;
+        font-size: 15px;
 }
+<<<<<<< HEAD
 #user-list li:nth-child(even) {
+=======
+#user-list li:nth-child(even){
+>>>>>>> 602ebd94f77c751ea4ecdee3da8b46a2f06b66f9
     background-color: #DFEFFF;
     border: solid 1px #6699ff;
     border-left: 0px;
     border-right: 0px;
 }
 #tabs-list{
-	width: calc(100% - 42px);
-	height: 20px;
-	position: absolute;
-	left: 0;
-	top: 20px;
-	overflow: hidden;
+        width: calc(100% - 42px);
+        height: 20px;
+        position: absolute;
+        left: 0;
+        top: 20px;
+        overflow: hidden;
 }
 #tabs-list div.tab{
-	float: left;
-	max-width: 200px;
-	overflow: hidden;
-	position: relative;
+        float: left;
+        max-width: 200px;
+        overflow: hidden;
+        position: relative;
     height: 18px;
     margin-bottom: -1px;
 }
 #tabs-list div.tab.clicked{
     background-color: #cae4ff;
     border: solid 1px #6699ff;
-	border-bottom-width: 0px;
+        border-bottom-width: 0px;
 }
 #tabs-scroll-left{
-	position: absolute;
-	right: 20px;
-	top: 20px;
-	height: 20px;
-	width: 20px;
+        position: absolute;
+        right: 20px;
+        top: 20px;
+        height: 20px;
+        width: 20px;
 }
 #tabs-scroll-right{
-	position: absolute;
-	right: 0;
-	top: 20px;
-	height: 20px;
-	width: 20px;
+        position: absolute;
+        right: 0;
+        top: 20px;
+        height: 20px;
+        width: 20px;
 }
 #tabs-list div.tab, #tabs-scroll-right,#tabs-scroll-left{
-	border-top-right-radius: 3px;
-	border-top-left-radius: 3px;
+        border-top-right-radius: 3px;
+        border-top-left-radius: 3px;
     border: 1px solid rgba(102, 153, 255, 0.3);
     border-top-color: rgba(102, 153, 255, 0.6);
-	border-width: 1px;
-	border-bottom-width: 0px;
-	padding: 0;
-	margin: 0;
-	background-color: white;
-	cursor: pointer;
-	clear: none;
+        border-width: 1px;
+        border-bottom-width: 0px;
+        padding: 0;
+        margin: 0;
+        background-color: white;
+        cursor: pointer;
+        clear: none;
 
     display: block;
     -webkit-box-align: center;
@@ -302,6 +347,6 @@ html,body{
 #tabs-scroll-left.disabled, #tabs-scroll-right.disabled{
     background-color: #cae4ff;
     border: solid 1px #6699ff;
-	border-bottom-width: 0px;
+        border-bottom-width: 0px;
 
-}
+}

+ 4 - 4
app/www/index.html

@@ -17,10 +17,10 @@
 		<script type="text/javascript" src="socket.io/socket.io.js"></script>
 		<script type="text/javascript" src="js/omnomirc.js"></script>
 		<script type="text/javascript" src="api/themes.js"></script>
-		<link rel="stylesheet" href="css/style.css"></link>
+		<script id="theme-script"></script>
 		<link rel="stylesheet" href="css/jquery.contextMenu.css"></link>
-		<link rel="stylesheet" href="themes/omnom.css"></link>
-</head>
+		<link id="theme-style"></link>
+	</head>
 	<body>
 		<div id="head">
 			<div id="info">
@@ -50,4 +50,4 @@
 		</div>
 		<div id="console-log"></div>
 	</body>
-</html>
+</html>

+ 18 - 14
app/www/js/consoleshim.js

@@ -34,21 +34,25 @@
 	};
 	console._old = [];
 	for(i=0;i<a.length;i++){
-		var name = a[i],
-			index = i;
-		console._old.push(oC[name] || noop);
-		if(a[i] != 'error'){
-			console[name] = function(){
-				return console._call(index,name.toUpperCase(),arguments)
-			}
-		}else{
-			console[name] = function(){
-				var args;
-				for(var i in arguments){
-					args.push(arguments[i].message);
+		(function(name,index){
+			console._old.push(oC[name] || noop);
+			if(a[i] != 'error'){
+				console[name] = function(){
+					return console._call(index,name.toUpperCase(),arguments)
+				}
+			}else{
+				console[name] = function(){
+					var args = [];
+					for(var i in arguments){
+						if(typeof arguments[i].message == 'undefined'){
+							args.push(arguments[i]);
+						}else{
+							args.push(arguments[i].message);
+						}
+					}
+					return console._call(index,name.toUpperCase(),args)
 				}
-				return console._call(index,name.toUpperCase(),args)
 			}
-		}
+		})(a[i],i);
 	}
 })(window);

+ 224 - 80
app/www/js/omnomirc.js

@@ -24,7 +24,7 @@
 		},
 		event = function(msg,type){
 			if(settings.debug){
-				type=typeof type == 'undefined'?'event':type;
+				type=exists(type)?type:'event';
 				switch(type){
 					case 'ready':type='document_ready';break;
 				}
@@ -54,29 +54,14 @@
 			return false;
 		},
 		selectedTab=0,
-		settings = {
-			colour: false,
-			debug: false,
-			timestamp: 'exact',
-			server: location.origin,
-			autoconnect: true,
-			autojoin: [
-				'#omnimaga',
-				'#omnimaga-fr',
-				'#irp'
-			],
-			scrollspeed: 100,
-			theme: 'default',
-			nick: 'User'
-		},
+		settings = {},
+		settingsConf = {},
 		tabs = [],
 		properties = {
 			nick: 'User',
 			sig: '',
 			tabs: tabs,
-			themes: [
-				'default'
-			]
+			themes: []
 		},
 		commands = [
 			{ // names
@@ -125,7 +110,7 @@
 			{ // help
 				cmd: 'help',
 				fn: function(args){
-					if(typeof args[1] == 'undefined'){
+					if(exists(args[1])){
 						var m = 'Commands:',i;
 						for(i in commands){
 							m += ' '+commands[i].cmd;
@@ -135,7 +120,7 @@
 						var i,cmd;
 						for(i in commands){
 							cmd = commands[i];
-							if(cmd.cmd == args[1] && typeof cmd.help != 'undefined'){
+							if(cmd.cmd == args[1] && exists(cmd.help)){
 								$o.msg('Command /'+cmd.cmd+': '+cmd.help);
 								return;
 							}
@@ -191,10 +176,24 @@
 						if(v != null){
 							if(tab.users.indexOf(v.trim()) == -1){
 								emit('echo',{
-									room: $o.ui.tabs.current().name,
+									room: data.room,
 									message: v+' left the room',
 									from: 0
 								});
+								runHook('part',[
+									v,
+									data.room
+								]);
+							}
+						}
+					});
+					$(tab.users).each(function(i,v){
+						if(v != null){
+							if(users.indexOf(v.trim()) == -1){
+								runHook('join',[
+									v,
+									data.room
+								]);
 							}
 						}
 					});
@@ -209,6 +208,7 @@
 							name: settings.autojoin[i]
 						});
 					}
+					runHook('authorized');
 				}
 			},
 			{ // join
@@ -228,6 +228,7 @@
 					event('reconnected');
 					properties.connected = true;
 					$o.chat.auth();
+					runHook('reconnect');
 					emit('echo',{
 						room: $o.ui.tabs.current().name,
 						from: 0,
@@ -241,6 +242,7 @@
 					event('connected');
 					properties.connected = true;
 					$o.chat.auth();
+					runHook('connect');
 					emit('echo',{
 						room: $o.ui.tabs.current().name,
 						from: 0,
@@ -253,6 +255,7 @@
 				fn: function(data){
 					event('disconnected');
 					properties.connected = false;
+					runHook('disconnected');
 					$o.msg('* disconnected');
 				}
 			},
@@ -288,11 +291,22 @@
 					}else{
 						$('.date_cell').css('visibility','visible');
 					}
-					
+					runHook('message',[
+						data.message,
+						data.from,
+						data.room
+					]);
 				}
 			}
 		],
 		hooks = [
+			{
+				type: '',
+				hook: 'setting',
+				fn: function(name){
+					return name != 'colour';
+				}
+			},
 			{	// load - style
 				type: 'style',
 				hook: 'load',
@@ -303,22 +317,27 @@
 			}
 		],
 		currentPlugin = 0,
-		runHook = function(name){
-			var i,hook,fn,sandbox = {
+		runHook = function(name,args){
+			var i,r=true,hook,fn,sandbox = {
 				testing: 'test'
 			};
+			args=exists(args)?args:[];
 			for(i in hooks){
 				hook = hooks[i];
 				if(hook.hook == name){
 					fn = (hook.fn+'').replace(/\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g,'').replace(/\"/g,'\\"').replace(/\n/g,'').replace(/\r/g,'');
-					fn = 'eval("with(this){('+fn+')();}");';
+					fn = 'var ret = true;eval("with(this){ret = ('+fn+').apply(this,arguments);}");return ret;';
 					try{
-						(new Function(fn)).call(sandbox);
+						r = (new Function(fn)).apply(sandbox,args);
 					}catch(e){
 						event('Hook failed to run: '+e+"\nFunction that ran: "+fn,'hook_error');
 					}
 				}
+				if(r == false){
+					break;
+				}
 			}
+			return r;
 		},
 		version = '3.0',
 		abbrDate = function(selector){
@@ -348,8 +367,6 @@
 			}
 		},
 		socket,$i,$s,$h,$cl,$c,$tl,hht;
-		
-		runHook('load');
 	$.extend($o,{
 		version: function(){
 			return version;
@@ -358,6 +375,7 @@
 			theme: function(name){
 				if(-1==$.inArray(properties.themes,name)){
 					properties.themes.push(name);
+					runHook('theme',[name]);
 					return true;
 				}
 				return false;
@@ -368,7 +386,7 @@
 						cmd: name,
 						fn: fn
 					};
-					if(typeof help != 'undefined'){
+					if(exists(help)){
 						o.help = help;
 					}
 					commands.push(o);
@@ -379,11 +397,30 @@
 			plugin: function(){
 				// STUB
 			},
-			setting: function(name,defaultVal,validate,values){
-				// STUB
+			setting: function(name,type,val,validate,values,callback){
+				if(!exists(settings[name])){
+					validate = exists(validate)?validate:function(){};
+					values = exists(values)?values:undefined;
+					callback = exists(callback)?callback:function(){};
+					settings[name] = val;
+					settingsConf[name] = {
+						validate: validate,
+						callback: callback,
+						type: type,
+						values: values,
+						default: val,
+						name: name
+					}
+					return true;
+				}else{
+					return false;
+				}
 			},
 			hook: function(event,fn){
-				
+				hooks.push({
+					hook: event,
+					fn: fn
+				})
 			}
 		},
 		hook: function(event,fn){
@@ -400,7 +437,7 @@
 								item = $('<select>')
 											.attr('id','setting_'+name)
 											.change(function(){
-												$o.set(this.id.substr(8),$(this).find(':selected').text(),false);
+												$o.set(this.id.substr(8),$(this).find(':selected').text().trim(),false);
 											});
 								for(var i in setting.values){
 									item.append(
@@ -643,7 +680,7 @@
 						id = $o.ui.tabs.idForName(id);
 						if(!id) return false;
 					}
-					return typeof tabs[id] == 'undefined'?false:tabs[id];
+					return exists(tabs[id])?tabs[id]:false;
 				},
 				dom: function(id){
 					if(typeof id == 'string' && !id.isNumber()){
@@ -653,7 +690,7 @@
 					return typeof tabs[id] == 'undefined'?false:tabs[id].body;
 				},
 				obj: function(id){
-					if(typeof id !== 'undefined'){
+					if(exists(id)){
 						if(typeof id == 'string' && !id.isNumber()){
 							id = $o.ui.tabs.idForName(id);
 							if(!id) return;
@@ -747,7 +784,7 @@
 				if($o.chat.connected()){
 					$o.disconnect();
 				}
-				if(typeof server == 'undefined'){
+				if(!exists(server)){
 					server = settings.server;
 				}
 				socket = window.socket =  io.connect(server);
@@ -762,10 +799,10 @@
 				}
 			},
 			connected: function(){
-				return typeof socket == 'undefined'?false:properties.connected;
+				return exists(socket)?properties.connected:false;
 			},
 			send: function(msg,room){
-				if(typeof room == 'undefined'){
+				if(!exists(room)){
 					room = $o.ui.tabs.current().name;
 				}
 				if(msg !== ''){
@@ -803,57 +840,62 @@
 			}
 		},
 		get: function(name,formatted){
-			if(typeof formatted == 'undefined'){
+			if(!exists(formatted)){
 				return exists(settings[name])?settings[name]:false;
 			}else{
-				var val = $o.get(name),
-					type,
-					values = false;
-				switch(name){
-					case 'theme':
-						type = 'select';
-						values = properties.themes;
-						break;
-					case 'autojoin':type = 'array';break;
-					case 'timestamp':type = 'string';break;
-					default:
-						type = typeof val;
+				if(exists(settingsConf[name]) && exists(settings[name])){
+					var r = $.extend({},settingsConf[name]);
+					r.val = settings[name];
+					r.validate = undefined;
+					r.callback = undefined;
+					delete r['validate'];
+					delete r['callback'];
+					return r;
+				}else{
+					return false;
 				}
-				return {
-					type: type,
-					val: val,
-					values: values,
-					name: name
-				};
 			}
 		},
 		set: function(name,value,render){
 			if(exists(settings[name])){
+				var setting;
+				if(exists(settingsConf[name])){
+					setting = $.extend({},settingsConf[name]);
+				}else{
+					setting = {
+						val: setting[name],
+						callback: function(){},
+						validate: function(){},
+						values: undefined,
+						type: typeof setting[name]
+					}
+				}
+				if(
+					(exists(setting.values) && $.inArray(value,setting.values) == -1) ||
+					setting.validate(setting[name],value,setting.values,name) == false ||
+					!runHook('setting',[
+						name,
+						settings[name],
+						value,
+						$o.get(name,true).values
+					])
+				){
+					if(exists(render)){
+						$o.ui.render.settings();
+					}
+					return false;
+				}
 				settings[name] = value;
 				$.localStorage('settings',JSON.stringify(settings));
-				switch(name){
-					case 'timestamp':
-						abbrDate('abbr.date');
-						if(settings.timestamp == ''){
-							$('.date_cell').css('visibility','hidden');
-						}else{
-							$('.date_cell').css('visibility','visible');
-						}
-					break;
-					case 'nick':
-						$o.chat.auth();
-					break;
-					case 'debug':
-						if(typeof render != 'undefined'){
-							$o.ui.render.settings();
-						}
-					break;
-				}
-				if(typeof render == 'undefined'){
+				setting.callback(value,name,exists(render));
+				if(exists(render)){
 					$o.ui.render.settings();
 				}
 				return true;
 			}else{
+				if(exists(render)){
+					$o.ui.render.settings();
+				}
 				return false;
 			}
 		},
@@ -865,7 +907,7 @@
 		},
 		msg: function(msg,tabName){
 			var frag;
-			if(typeof tabName == 'undefined' || tabName == $o.ui.tabs.current().name || typeof $o.ui.tabs.tab(tabName).body == 'undefined'){
+			if(!exists(tabName) || tabName == $o.ui.tabs.current().name || !exists($o.ui.tabs.tab(tabName).body)){
 				frag = document.createDocumentFragment();
 			}else{
 				frag = $o.ui.tabs.tab(tabName).body;
@@ -876,7 +918,7 @@
 						$(frag).append($('<li>').html(msg.htmlentities()));
 						break;
 					case 'object':
-						if(typeof msg.html == 'undefined'){
+						if(!exists(msg.html)){
 							$(frag).append($('<li>').html('&lt;'+msg.user+'&gt;&nbsp;'+msg.text.htmlentities()));
 						}else{
 							$(frag).append(msg.html);
@@ -900,7 +942,7 @@
 				});
 			}
 			$.localStorage('tabs',scroll);
-			if(typeof tabName == 'undefined' || tabName == $o.ui.tabs.current().name){
+			if(!exists(tabName) || tabName == $o.ui.tabs.current().name){
 				$o.ui.tabs.select(selectedTab);
 			}
 		},
@@ -908,6 +950,86 @@
 			event(message,event_name);
 		}
 	});
+	(function(settings){
+		var i,s;
+		for(i in settings){
+			s = settings[i];
+			$o.register.setting(i,s.type,s.val,s['validate'],s['values'],s['callback']);
+		}
+	})({
+		colour: {
+			type: 'boolean',
+			val: false
+		},
+		debug: {
+			type: 'boolean',
+			val: false,
+			callback: function(v,s,r){
+				if(r){
+					$o.ui.render.settings();
+				}
+			}
+		},
+		timestamp: {
+			type: 'string',
+			val: 'exact',
+			callback: function(v,s){
+				abbrDate('abbr.date');
+				if(v == ''){
+					$('.date_cell').css('visibility','hidden');
+				}else{
+					$('.date_cell').css('visibility','visible');
+				}
+			}
+		},
+		server: {
+			type: 'string',
+			val: location.origin
+		},
+		autoconnect: {
+			type: 'boolean',
+			val: true
+		},
+		autojoin: {
+			type: 'array',
+			val: [
+				'#omnimaga',
+				'#omnimaga-fr',
+				'#irp'
+			]
+		},
+		scrollspeed: {
+			type: 'number',
+			val: 100
+		},
+		theme: {
+			type: 'select',
+			val: 'default',
+			values: properties.themes,
+			callback: function(v,s,r){
+				if($('link[id="theme-style"]').attr('href') != 'data/themes/'+v+'/style.css' || $('script[id="theme-script"]').attr('src') != 'data/themes/'+v+'/script.js'){
+					event('Loading theme '+v);
+					$('link[id="theme-style"]').attr({
+						id: 'theme-style',
+						rel: 'stylesheet',
+						href: 'data/themes/'+v+'/style.css'
+					});
+					$('script[id="theme-script"]').attr({
+						id: 'theme-script',
+						type: 'text/javascript',
+						src: 'data/themes/'+v+'/script.js'
+					});
+				}
+			}
+		},
+		nick: {
+			type: 'string',
+			val: 'User',
+			callback: function(){
+				$o.chat.auth();
+			}
+		}
+	});
 	String.prototype.htmlentities = function(){
 		return this
 			.replace(/&/g, '&amp;')
@@ -921,6 +1043,7 @@
 	$(document).ready(function(){
 		$.extend(settings,$.parseJSON($.localStorage('settings')));
 		$.localStorage('settings',JSON.stringify(settings));
+		settingsConf['theme'].callback(settings['theme'],'theme',true);
 		$i = $('#input');
 		$s = $('#send');
 		$cl = $('#content-list');
@@ -1043,8 +1166,29 @@
 		if(settings.autoconnect){
 			$o.chat.connect();
 		}
+		// Check for script updates and update if required
+		(function checkScripts(){
+			for(var i in document.scripts){
+				(function(el,src){
+					if(exists(src) && el.innerHTML == ''){
+						$.ajax(src,{
+							success: function(source){
+								if(exists($(el).data('source')) && $(el).data('source') != source){
+									event('Reloading','update');
+									location.reload();
+								}
+								$(el).data('source',source);
+							},
+							dataType: 'text'
+						});
+					}
+				})(document.scripts[i],document.scripts[i].src);
+			}
+			setTimeout(checkScripts,1000*30);
+		})();
 	});
 	window.io = null;
+	runHook('load');
 })(window,jQuery,io);
 if (!Date.prototype.toISOString) {
     Date.prototype.toISOString = function() {