[dss-commits] r8856 - in dss/trunk: . data/webroot data/webroot/js websrc websrc/dss-setup-interface websrc/dss-setup-interface/dSS websrc/dss-setup-interface/dSS/data websrc/dss-setup-interface/dSS/grid

dss-commits at forum.digitalstrom.org dss-commits at forum.digitalstrom.org
Thu Oct 22 14:35:09 CEST 2009


Author: mfernandez
Date: 2009-10-22 14:35:09 +0200 (Thu, 22 Oct 2009)
New Revision: 8856

Added:
   dss/trunk/data/webroot/js/dss-setup-interface.js
   dss/trunk/websrc/
   dss/trunk/websrc/dss-setup-interface/
   dss/trunk/websrc/dss-setup-interface/README
   dss/trunk/websrc/dss-setup-interface/dSS/
   dss/trunk/websrc/dss-setup-interface/dSS/ZoneBrowser.js
   dss/trunk/websrc/dss-setup-interface/dSS/ZonePanel.js
   dss/trunk/websrc/dss-setup-interface/dSS/ZoneView.js
   dss/trunk/websrc/dss-setup-interface/dSS/data/
   dss/trunk/websrc/dss-setup-interface/dSS/data/DeviceStore.js
   dss/trunk/websrc/dss-setup-interface/dSS/data/ZoneStore.js
   dss/trunk/websrc/dss-setup-interface/dSS/grid/
   dss/trunk/websrc/dss-setup-interface/dSS/grid/DevicePanel.js
   dss/trunk/websrc/dss-setup-interface/dss-setup-interface.js
Modified:
   dss/trunk/data/webroot/js/DataView-more.js
   dss/trunk/data/webroot/js/setup.js
   dss/trunk/data/webroot/setup.html
Log:
Refurbished setup interface
- now uses sprocktes as build environment http://getsprockets.org/
- redesigned for easy addition of new functionality


Modified: dss/trunk/data/webroot/js/DataView-more.js
===================================================================
--- dss/trunk/data/webroot/js/DataView-more.js	2009-10-20 10:57:50 UTC (rev 8855)
+++ dss/trunk/data/webroot/js/DataView-more.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -1,170 +1,87 @@
 Ext.DataView.DragSelector = function(cfg){
-    cfg = cfg || {};
-
-    var view, proxy, tracker;
-
-var rs, bodyRegion, dragRegion = new Ext.lib.Region(0,0,0,0);
-
-var dragSafe = cfg.dragSafe === true;
-
-
-
-this.init = function(dataView){
-
-    view = dataView;
-
-    view.on('render', onRender);
-
+	cfg = cfg || {};
+	var view, proxy, tracker;
+	var rs, bodyRegion, dragRegion = new Ext.lib.Region(0,0,0,0);
+	var dragSafe = cfg.dragSafe === true;
+	
+	this.init = function(dataView){
+		view = dataView;
+		view.on('render', onRender);
+	};
+	
+	function fillRegions(){
+		rs = [];
+		view.all.each(function(el){
+			rs[rs.length] = el.getRegion();
+		});
+		bodyRegion = view.el.getRegion();
+	}
+	function cancelClick(){
+		return false;
+	}
+	
+	function onStart(e){
+		//view.on('containerclick', cancelClick, view, {single:true});
+		
+		if(!proxy){
+			proxy = view.el.createChild({cls:'x-view-selector'});
+		} else {
+			proxy.setDisplayed('block');
+		}
+		fillRegions();
+		view.clearSelections();
+	}
+	
+	function onDrag(e){
+		var startXY = tracker.startXY;
+		var xy = tracker.getXY();
+		var x = Math.min(startXY[0], xy[0]);
+		var y = Math.min(startXY[1], xy[1]);
+		var w = Math.abs(startXY[0] - xy[0]);
+		var h = Math.abs(startXY[1] - xy[1]);
+		dragRegion.left = x;
+		dragRegion.top = y;
+		dragRegion.right = x+w;
+		dragRegion.bottom = y+h;
+		dragRegion.constrainTo(bodyRegion);
+		proxy.setRegion(dragRegion);
+		for(var i = 0, len = rs.length; i < len; i++){
+			var r = rs[i], sel = dragRegion.intersect(r);
+			if(sel && !r.selected){
+				r.selected = true;
+				view.select(i, true);
+			} else if(!sel && r.selected) {
+				r.selected = false;
+				view.deselect(i);
+			}
+		}
+	}
+	
+	function onEnd(e){
+		if (!Ext.isIE) {
+			view.un('containerclick', cancelClick, view);
+		}
+		if(proxy){
+			proxy.setDisplayed(false);
+		}
+	}
+	
+	function onRender(view){
+		tracker = new Ext.dd.DragTracker();//{preventDefault: true});
+		tracker.on({
+			'dragstart': {
+				fn: onStart,
+				scope: this
+			},
+			'drag': {
+				fn: onDrag,
+				scope: this
+			},
+			'dragend': {
+				fn: onEnd,
+				scope:this
+			}
+		});
+		tracker.initEl(view.el);
+	}
 };
-
-
-
-function fillRegions(){
-
-    rs = [];
-
-    view.all.each(function(el){
-
-        rs[rs.length] = el.getRegion();
-
-    });
-
-    bodyRegion = view.el.getRegion();
-
-}
-
-
-
-function cancelClick(){
-
-    return false;
-
-}
-
-
-
-function onBeforeStart(e){
-
-    return !dragSafe || e.target == view.el.dom;
-
-}
-
-
-
-function onStart(e){
-
-    view.on('containerclick', cancelClick, view, {single:true});
-
-    if(!proxy){
-
-        proxy = view.el.createChild({cls:'x-view-selector'});
-
-    }else{
-
-        proxy.setDisplayed('block');
-
-    }
-
-    fillRegions();
-
-    view.clearSelections();
-
-}
-
-
-
-function onDrag(e){
-
-    var startXY = tracker.startXY;
-
-    var xy = tracker.getXY();
-
-
-
-    var x = Math.min(startXY[0], xy[0]);
-
-    var y = Math.min(startXY[1], xy[1]);
-
-    var w = Math.abs(startXY[0] - xy[0]);
-
-    var h = Math.abs(startXY[1] - xy[1]);
-
-
-
-    dragRegion.left = x;
-
-    dragRegion.top = y;
-
-    dragRegion.right = x+w;
-
-    dragRegion.bottom = y+h;
-
-
-
-    dragRegion.constrainTo(bodyRegion);
-
-    proxy.setRegion(dragRegion);
-
-
-
-    for(var i = 0, len = rs.length; i < len; i++){
-
-        var r = rs[i], sel = dragRegion.intersect(r);
-
-        if(sel && !r.selected){
-
-            r.selected = true;
-
-            view.select(i, true);
-
-        }else if(!sel && r.selected){
-
-            r.selected = false;
-
-            view.deselect(i);
-
-        }
-
-    }
-
-}
-
-
-
-function onEnd(e){
-
-    if (!Ext.isIE) {
-
-        view.un('containerclick', cancelClick, view);    
-
-    }        
-
-    if(proxy){
-
-        proxy.setDisplayed(false);
-
-    }
-
-}
-
-
-
-function onRender(view){
-
-    tracker = new Ext.dd.DragTracker({
-
-        onBeforeStart: onBeforeStart,
-
-        onStart: onStart,
-
-        onDrag: onDrag,
-
-        onEnd: onEnd
-
-    });
-
-    tracker.initEl(view.el);
-
-}
-
-};
\ No newline at end of file

Added: dss/trunk/data/webroot/js/dss-setup-interface.js
===================================================================
--- dss/trunk/data/webroot/js/dss-setup-interface.js	                        (rev 0)
+++ dss/trunk/data/webroot/js/dss-setup-interface.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,463 @@
+Ext.namespace('dSS', 'dSS.data');
+
+dSS.data.ZoneStore = Ext.extend(Ext.data.Store, {
+	constructor: function(config) {
+		var zoneRecord = Ext.data.Record.create([
+			{name:"name"},
+			{name:"id"}
+		]);
+
+		var zoneReader = new Ext.data.JsonReader(
+			{
+				root: "zones"
+			},
+			zoneRecord
+		);
+
+		Ext.apply(this, { reader: zoneReader });
+		dSS.data.ZoneStore.superclass.constructor.call(this, arguments);
+	}
+});
+
+Ext.namespace('dSS');
+
+dSS.ZoneView = Ext.extend(Ext.DataView, {
+	initComponent: function() {
+
+		var zoneTemplate = new Ext.XTemplate(
+			'<tpl for=".">',
+				'<div class="zone-wrap {css}" id="zone-{id}">',
+					'<span>{name}</span>',
+				'</div>',
+			'</tpl>',
+			'<div class="x-clear"></div>'
+		);
+
+		var zoneStore = new dSS.data.ZoneStore();
+
+		Ext.apply(this, {
+			store: zoneStore,
+			tpl: zoneTemplate,
+			multiSelect: true,
+			layout: 'fit',
+			style: "overflow: auto",
+			overClass:'x-view-over',
+			itemSelector:'div.zone-wrap',
+			emptyText: 'No Rooms to display',
+			plugins: [
+				new Ext.DataView.DragSelector()
+			]
+		});
+
+		dSS.ZoneView.superclass.initComponent.apply(this, arguments);
+		this.on(
+			'selectionchange',
+			function(dv,nodes) {
+				var l = nodes.length;
+				var s = l != 1 ? 's' : '';
+				this.findParentByType('dsszonepanel').setTitle("Zones (" + l + ' zone' + s + ' selected)');
+				this.findParentByType('dsszonebrowser').filterDevices();
+			},
+			this
+		);
+
+		this.on(
+			'render',
+			function() {
+				var zoneView = this;
+				this.dropZone = new Ext.dd.DropZone(zoneView.getEl(), {
+					ddGroup          : "zoneDeviceDD",
+					getTargetFromEvent: function(e) {
+						return e.getTarget(zoneView.itemSelector);
+					},
+					onNodeEnter : function(target, dd, e, data){
+						Ext.fly(target).addClass('my-row-highlight-class');
+					},
+					onNodeOut : function(target, dd, e, data){
+						Ext.fly(target).removeClass('my-row-highlight-class');
+					},
+					onNodeOver : function(target, dd, e, data){
+						return Ext.dd.DropZone.prototype.dropAllowed;
+					},
+					onNodeDrop : function(target, dd, e, data){
+						var record = zoneView.getRecord(target);
+						Ext.each(data.selections, function(device) {
+							var currentDevice = device;
+							Ext.Ajax.request({
+								url: '/json/structure/zoneAddDevice',
+								disableCaching: true,
+								method: "GET",
+								scope: zoneView,
+								params: {		devid: currentDevice.data.id,
+														zone:  record.data.id
+												},
+								success: function(result, request) {
+									try {
+										var jsonData = Ext.util.JSON.decode(result.responseText);
+										if(jsonData.ok) {
+											currentDevice.set("zone", record.data.id);
+											this.getStore().commitChanges();
+											this.findParentByType('dsszonebrowser').filterDevices();
+										}
+									}
+									catch (err) {
+										Ext.MessageBox.alert('Error', 'Could not move device "' + device.data.dsid + '"');
+									}
+								},
+								failure: function(result, request) {
+									Ext.MessageBox.alert('Error', 'Could not move device "' + device.data.dsid + '"');
+								},
+							});
+						});
+						return true;
+					}
+				});
+			},
+			this
+		);
+	}
+});
+
+Ext.reg('dsszoneview', dSS.ZoneView);
+
+Ext.namespace('dSS');
+
+dSS.ZonePanel = Ext.extend(Ext.Panel, {
+	initComponent: function() {
+		Ext.apply(this, {
+			title:'Zones',
+			layout: 'border',
+			items: [{ xtype: 'dsszoneview', ref: 'zoneView', region: 'center'}]
+		});
+
+		this.tbar = this.buildTopToolbar();
+
+		dSS.ZonePanel.superclass.initComponent.apply(this, arguments);
+	},
+
+	buildTopToolbar: function() {
+		return ['->',
+			{
+				text: 'New Zone',
+				iconCls: 'newZoneAction',
+				handler: this.createNewZone,
+				scope: this
+			},
+			{
+				text: 'Reload',
+				iconCls: 'reloadAction',
+				handler: this.reload,
+				scope: this
+			}
+		];
+	},
+
+	createNewZone: function() {
+		var zoneStore = this.zoneView.getStore();
+		Ext.Msg.prompt('Create new zone', 'Name for new Zone:', function(btn, text){
+			if (btn == 'ok'){
+				for(var i = 0; i <= zoneStore.data.length; i++) {
+					if(zoneStore.findExact('id', i) === -1) {
+
+						Ext.Ajax.request({
+							url: '/json/structure/addZone',
+							disableCaching: true,
+							method: "GET",
+							params: { zoneID: i },
+							success: function(result, request) {
+								try {
+									var jsonData = Ext.util.JSON.decode(result.responseText);
+									if(jsonData.ok) {
+
+
+
+									Ext.Ajax.request({
+										url: '/json/zone/setName',
+										disableCaching: true,
+										method: "GET",
+										params: { id: i,
+															newName: text},
+										success: function(result, request) {
+											try {
+												var jsonData = Ext.util.JSON.decode(result.responseText);
+												if(jsonData.ok) {
+
+
+													var newZone = new zoneStore.recordType({id: i, name: text}, i);
+													zoneStore.insert(i, newZone);
+
+
+
+												}
+											}
+											catch (err) {
+												Ext.MessageBox.alert('Error', 'Could not create Zone');
+											}
+										},
+										failure: function(result, request) {
+											Ext.MessageBox.alert('Error', 'Could not create Zone');
+										},
+									});
+
+
+									}
+								}
+								catch (err) {
+									Ext.MessageBox.alert('Error', 'Could not create Zone');
+								}
+							},
+							failure: function(result, request) {
+								Ext.MessageBox.alert('Error', 'Could not create Zone');
+							},
+						});
+						return;
+					}
+				}
+			}
+		})
+	},
+	reload: function() {
+		this.ownerCt.loadData();
+	}
+});
+
+Ext.reg('dsszonepanel', dSS.ZonePanel);
+Ext.namespace('dSS', 'dSS.data');
+
+dSS.data.DeviceStore = Ext.extend(Ext.data.Store, {
+	constructor: function(config) {
+		var deviceRecord = Ext.data.Record.create([
+			{name:"name"},
+			{name:"id"},
+			{name:"on"},
+			{name:"circuit"},
+			{name:"modulator"},
+			{name:"zone"}
+		]);
+
+		var deviceReader = new Ext.data.JsonReader(
+			{
+				root:"devices"
+			},
+			deviceRecord
+		);
+
+		Ext.apply(this, { reader: deviceReader });
+		dSS.data.DeviceStore.superclass.constructor.call(this, arguments);
+	}
+});
+
+Ext.namespace('dSS', 'dSS.grid');
+
+dSS.grid.DevicePanel = Ext.extend(Ext.grid.GridPanel, {
+	initComponent: function() {
+
+		var deviceCols = [
+			{id: 'id', header: "id",  width: 50, sortable: true, dataIndex: 'id'},
+			{id: 'name', header: "name", width: 50, sortable: true, dataIndex: 'name', editable: true, editor: new Ext.form.TextField()},
+			{header: "on", width: 50, sortable: true, dataIndex: 'on'},
+			{header: "circuit", width: 50, sortable: true, dataIndex: 'circuit'},
+			{header: "modulator", width: 50, sortable: true, dataIndex: 'modulator'},
+			{header: "zone", width: 50, sortable: true, dataIndex: 'zone'},
+		];
+
+		var editor = new Ext.ux.grid.RowEditor({
+			saveText: 'Update'
+		});
+
+		editor.on('afteredit', function() {
+			deviceStore.commitChanges();
+			filterDevices();
+		});
+
+		var deviceStore = new dSS.data.DeviceStore();
+
+		Ext.apply(this, {
+			store            : deviceStore,
+			columns          : deviceCols,
+			ddGroup          : "zoneDeviceDD",
+			enableDragDrop   : true,
+			stripeRows       : true,
+			autoExpandColumn : 'id',
+			title            : 'Devices',
+			plugins          : [editor]
+		});
+
+		dSS.grid.DevicePanel.superclass.initComponent.apply(this, arguments);
+
+		this.on(
+			'rowcontextmenu',
+			function() {
+			},
+			this
+		);
+	}
+});
+
+Ext.reg('dssdevicepanel', dSS.grid.DevicePanel);
+
+Ext.namespace('dSS');
+
+dSS.ZoneBrowser = Ext.extend(Ext.Panel, {
+	initComponent: function() {
+
+		Ext.apply(this, {
+			layout: 'border',
+			items: [{
+					xtype: 'dsszonepanel',
+					ref: 'zonePanel',
+					region: 'west',
+					width: 225, // give east and west regions a width
+					minSize: 175,
+					maxSize: 400,
+					split: true
+				},{
+					xtype: 'dssdevicepanel',
+					ref: 'devicePanel',
+					minSize: 400,
+					region: 'center'
+				}
+			]
+		});
+
+		dSS.ZoneBrowser.superclass.initComponent.apply(this, arguments);
+		this.on(
+			'afterrender',
+			this.loadData,
+			this
+		);
+
+	},
+	allDevices: undefined,
+	filterDevices: function() {
+		var selectedZones = this.zonePanel.zoneView.getSelectedRecords();
+		if(selectedZones.length === 0) {
+			this.devicePanel.getStore().clearFilter();
+			return
+		}
+		this.devicePanel.getStore().filterBy(function(record) {
+			for(var i = 0; i < selectedZones.length; i++) {
+				if(record.data.zone == selectedZones[i].data.id) {
+					return true;
+				}
+			}
+			return false;
+		});
+	},
+	processStructure: function(structure) {
+		var devices = [], zones = [];
+		Ext.each(structure.apartment.zones, function(zone) {
+			if(zone.id === 0) { // Skip zone 0
+				Ext.each(zone.devices, function(device) {
+					devices.push(device);
+				});
+			}
+			zones.push({
+				id: zone.id,
+				name: zone.id === 0 ? 'Uncategorized' : zone.name
+			});
+			Ext.each(zone.devices, function(device) {
+				for(var i = 0; i < devices.length; i++) {
+					if(devices[i].id == device.id) {
+						devices[i].zone = zone.id;
+					}
+				}
+			});
+		});
+		this.zonePanel.zoneView.getStore().loadData({zones: zones});
+		this.allDevices = devices;
+	},
+	processCircuits: function(circuits) {
+		Ext.each(this.allDevices, function(device) {
+			var circuitID = device.circuitID;
+			for( var i = 0; i < circuits.length; i++) {
+				if(circuits[i].busid == circuitID) {
+					device.circuit = circuits[i].name;
+					device.modulator = circuits[i].dsid;
+				}
+			}
+		});
+		var deviceStore = this.devicePanel.getStore();
+		deviceStore.loadData({devices: this.allDevices});
+		if(this.zonePanel.zoneView.getStore().getCount() > 1) {
+			this.zonePanel.zoneView.select(1);
+		} else {
+			this.zonePanel.zoneView.select(0);
+		}
+	},
+	loadStructure: function() {
+		Ext.Ajax.request({
+			url: '/json/apartment/getStructure',
+			disableCaching: true,
+			method: "GET",
+			scope: this,
+			success: function(result, request) {
+				try {
+					var jsonData = Ext.util.JSON.decode(result.responseText);
+					this.processStructure(jsonData);
+				}
+				catch (err) {
+					Ext.MessageBox.alert('AJAX Error', 'Error loading apartment structure: "' + err + '"');
+				}
+			},
+			failure: function(result, request) {
+				Ext.MessageBox.alert('AJAX Error', 'Could not load "' + request.url + '"');
+			},
+		});
+	},
+	loadCircuits: function() {
+		Ext.Ajax.request({
+			url: '/json/apartment/getCircuits',
+			disableCaching: true,
+			method: "GET",
+			scope: this,
+			success: function(result, request) {
+				try {
+					var jsonData = Ext.util.JSON.decode(result.responseText);
+					this.processCircuits(jsonData.result.circuits);
+				}
+				catch (err) {
+					Ext.MessageBox.alert('AJAX Error', 'Could not load circuits: "' + err + '"');
+				}
+			},
+			failure: function(result, request) {
+				Ext.MessageBox.alert('AJAX Error', 'Could not load "' + request.url + '"');
+			},
+		});
+	},
+	loadData: function() {
+		this.loadStructure();
+		this.loadCircuits();
+	}
+
+});
+
+Ext.reg('dsszonebrowser', dSS.ZoneBrowser);
+
+Ext.onReady(function(){
+	Ext.get('start').remove();
+	var viewport = new Ext.Viewport({
+		layout: 'border',
+		items: [
+			{
+				xtype: 'box',
+				region: 'north',
+				height: 32, // give north and south regions a height
+				autoEl: {
+					tag: 'div',
+					html:'<h1>digitalSTROM Setup</h1>'
+				}
+			}, {
+				region: 'center',
+				xtype: 'tabpanel',
+				activeItem: 0,
+				items: [
+					{
+						title: 'Zones',
+						xtype: 'dsszonebrowser',
+						ref: 'zonebrowser'
+					}
+				]
+			}]
+	});
+});

Modified: dss/trunk/data/webroot/js/setup.js
===================================================================
--- dss/trunk/data/webroot/js/setup.js	2009-10-20 10:57:50 UTC (rev 8855)
+++ dss/trunk/data/webroot/js/setup.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -29,19 +29,28 @@
 	// create the data store
 	var deviceStore = new Ext.data.Store({
 		fields : deviceFields,
-		reader : deviceReader//,
-		// data: deviceData
+		reader : deviceReader
 	});
 	
 	var deviceCols = [
 		{id: 'id', header: "id",  width: 50, sortable: true, dataIndex: 'id'},
-		{id: 'name', header: "name", width: 50, sortable: true, dataIndex: 'name'},
+		{id: 'name', header: "name", width: 50, sortable: true, dataIndex: 'name', editable: true, editor: new Ext.form.TextField()},
 		{header: "on", width: 50, sortable: true, dataIndex: 'on'},
 		{header: "circuit", width: 50, sortable: true, dataIndex: 'circuit'},
 		{header: "modulator", width: 50, sortable: true, dataIndex: 'modulator'},
 		{header: "zone", width: 50, sortable: true, dataIndex: 'zone'},
 	];
 	
+	var editor = new Ext.ux.grid.RowEditor({
+		saveText: 'Update'
+	});
+	
+	editor.on('afteredit', function() {
+		console.log('a device has been edited');
+		deviceStore.commitChanges();
+		filterDevices();
+	});
+	
 	var deviceGrid = new Ext.grid.GridPanel({
 		store            : deviceStore,
 		columns          : deviceCols,
@@ -51,9 +60,14 @@
 		autoExpandColumn : 'id',
 		width            : 500,
 		region           : 'center',
-		title            : 'Devices'
+		title            : 'Devices',
+		plugins          : [editor]
 	});
 	
+	deviceGrid.on('rowcontextmenu', function() {
+		console.log('rowcontextmenu');
+	});
+	
 	var zoneRecord = Ext.data.Record.create([
 		{name:"name"},
 		{name:"id"}
@@ -105,10 +119,27 @@
 					zonePanel.setTitle("Zones (" + l + ' zone' + s + ' selected)');
 					filterDevices();
 				}
+			},
+			containerclick: {
+				fn: function() {
+					console.log('container click');
+				}
+			},
+			click: {
+				fn: function() {
+					console.log('click event');
+				}
 			}
 		}
 	});
 	
+	zoneView.on('contextmenu', function() {
+// 			e.stopEvent();
+			console.log("context");
+// 			e.preventDefault();
+		}
+	);
+	
 	function filterDevices() {
 		var selectedZones = zoneView.getSelectedRecords();
 		if(selectedZones.length === 0) {
@@ -136,7 +167,7 @@
 	var createZoneAction = new Ext.Action({
 		text: "New Zone",
 		handler: function() {
-			Ext.Msg.prompt('Name', 'Name:', function(btn, text){
+			Ext.Msg.prompt('Create new zone', 'Name for new Zone:', function(btn, text){
 				if (btn == 'ok'){
 					for(var i = 0; i <= zoneStore.data.length; i++) {
 						if(zoneStore.findExact('id', i) === -1) {

Modified: dss/trunk/data/webroot/setup.html
===================================================================
--- dss/trunk/data/webroot/setup.html	2009-10-20 10:57:50 UTC (rev 8855)
+++ dss/trunk/data/webroot/setup.html	2009-10-22 12:35:09 UTC (rev 8856)
@@ -4,10 +4,16 @@
 		<title>digitalStrom Setup</title>
 		
 		<link rel="stylesheet" type="text/css" href="js/lib/extjs/resources/css/ext-all.css" />
+
+		<!-- ExtJS libraries -->
 		<script type="text/javascript" src="js/lib/extjs/adapter/ext/ext-base.js"></script>
 		<script type="text/javascript" src="js/lib/extjs/ext-all.js"></script>
+		
+		<!-- ExtJS extensions -->
 		<script type="text/javascript" src="js/DataView-more.js"></script>
-		<script type="text/javascript" src="js/setup.js"></script>
+		<script type="text/javascript" src="js/lib/extjs/examples/ux/RowEditor.js"></script>
+		
+		<script type="text/javascript" src="js/dss-setup-interface.js"></script>
 		<style>
 			.zone-wrap{
 				margin: 4px;
@@ -41,7 +47,7 @@
 		</style>
 	</head>
 	<body>
-		<h1>digitalSTROM Setup</h1>
-		<div id="panel"></div>
+		<!-- <h1>digitalSTROM Setup</h1> -->
+		<div id="start">loading ...</div>
 	</body>
 </html>
\ No newline at end of file

Added: dss/trunk/websrc/dss-setup-interface/README
===================================================================
--- dss/trunk/websrc/dss-setup-interface/README	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/README	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,10 @@
+This is the setup interface for the digitalSTROM server.
+
+It is written in JavaScript and is based on the extjs JavaScript
+library, see http://www.extjs.com/
+
+Use "sprockets" to build it (see http://getsprockets.org/).
+
+$ sprocketize -I ./ dss-setup-interface.js > out.js
+
+and then copy out.js to where you want.
\ No newline at end of file

Added: dss/trunk/websrc/dss-setup-interface/dSS/ZoneBrowser.js
===================================================================
--- dss/trunk/websrc/dss-setup-interface/dSS/ZoneBrowser.js	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/dSS/ZoneBrowser.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,140 @@
+//= require <dSS/ZonePanel>
+//= require <dSS/grid/DevicePanel>
+
+Ext.namespace('dSS');
+
+dSS.ZoneBrowser = Ext.extend(Ext.Panel, {
+	initComponent: function() {
+		
+		Ext.apply(this, {
+			layout: 'border',
+			items: [{
+					xtype: 'dsszonepanel',
+					ref: 'zonePanel', 
+					region: 'west',
+					width: 225, // give east and west regions a width
+					minSize: 175,
+					maxSize: 400,
+					split: true
+				},{
+					xtype: 'dssdevicepanel',
+					ref: 'devicePanel',
+					minSize: 400,
+					region: 'center'
+				}
+			]
+		});
+		
+		dSS.ZoneBrowser.superclass.initComponent.apply(this, arguments);
+		this.on(
+			'afterrender',
+			this.loadData,
+			this
+		);
+		
+	},
+	allDevices: undefined,
+	filterDevices: function() {
+		var selectedZones = this.zonePanel.zoneView.getSelectedRecords();
+		if(selectedZones.length === 0) {
+			this.devicePanel.getStore().clearFilter();
+			return
+		}
+		this.devicePanel.getStore().filterBy(function(record) {
+			for(var i = 0; i < selectedZones.length; i++) {
+				if(record.data.zone == selectedZones[i].data.id) {
+					return true;
+				}
+			}
+			return false;
+		});
+	},
+	processStructure: function(structure) {
+		var devices = [], zones = [];
+		Ext.each(structure.apartment.zones, function(zone) {
+			if(zone.id === 0) { // Skip zone 0
+				Ext.each(zone.devices, function(device) {
+					devices.push(device);
+				});
+			}
+			zones.push({
+				id: zone.id,
+				name: zone.id === 0 ? 'Uncategorized' : zone.name
+			});
+			Ext.each(zone.devices, function(device) {
+				for(var i = 0; i < devices.length; i++) {
+					if(devices[i].id == device.id) {
+						devices[i].zone = zone.id;
+					}
+				}
+			});
+		});
+		this.zonePanel.zoneView.getStore().loadData({zones: zones});
+		this.allDevices = devices;
+	},
+	processCircuits: function(circuits) {
+		Ext.each(this.allDevices, function(device) {
+			var circuitID = device.circuitID;
+			for( var i = 0; i < circuits.length; i++) {
+				if(circuits[i].busid == circuitID) {
+					device.circuit = circuits[i].name;
+					device.modulator = circuits[i].dsid;
+				}
+			}
+		});
+		var deviceStore = this.devicePanel.getStore();
+		deviceStore.loadData({devices: this.allDevices});
+		if(this.zonePanel.zoneView.getStore().getCount() > 1) {
+			this.zonePanel.zoneView.select(1);
+		} else {
+			this.zonePanel.zoneView.select(0);
+		}
+	},
+	loadStructure: function() {
+		Ext.Ajax.request({
+			url: '/json/apartment/getStructure',
+			disableCaching: true,
+			method: "GET",
+			scope: this,
+			success: function(result, request) {
+				try {
+					var jsonData = Ext.util.JSON.decode(result.responseText);
+					this.processStructure(jsonData);
+				}
+				catch (err) {
+					Ext.MessageBox.alert('AJAX Error', 'Error loading apartment structure: "' + err + '"');
+				}
+			},
+			failure: function(result, request) {
+				Ext.MessageBox.alert('AJAX Error', 'Could not load "' + request.url + '"');
+			},
+		});
+	},
+	loadCircuits: function() {
+		Ext.Ajax.request({
+			url: '/json/apartment/getCircuits',
+			disableCaching: true,
+			method: "GET",
+			scope: this,
+			success: function(result, request) {
+				try {
+					var jsonData = Ext.util.JSON.decode(result.responseText);
+					this.processCircuits(jsonData.result.circuits);
+				}
+				catch (err) {
+					Ext.MessageBox.alert('AJAX Error', 'Could not load circuits: "' + err + '"');
+				}
+			},
+			failure: function(result, request) {
+				Ext.MessageBox.alert('AJAX Error', 'Could not load "' + request.url + '"');
+			},
+		});
+	},
+	loadData: function() {
+		this.loadStructure();
+		this.loadCircuits();
+	}
+	
+});
+
+Ext.reg('dsszonebrowser', dSS.ZoneBrowser);
\ No newline at end of file

Added: dss/trunk/websrc/dss-setup-interface/dSS/ZonePanel.js
===================================================================
--- dss/trunk/websrc/dss-setup-interface/dSS/ZonePanel.js	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/dSS/ZonePanel.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,105 @@
+//= require <dSS/ZoneView>
+
+Ext.namespace('dSS');
+
+dSS.ZonePanel = Ext.extend(Ext.Panel, {
+	initComponent: function() {
+		Ext.apply(this, {
+			title:'Zones',
+			layout: 'border',
+			items: [{ xtype: 'dsszoneview', ref: 'zoneView', region: 'center'}]
+			//tbar: ['->', createZoneAction, reloadAction]
+		});
+		
+		this.tbar = this.buildTopToolbar();
+		
+		dSS.ZonePanel.superclass.initComponent.apply(this, arguments);
+	},
+	
+	buildTopToolbar: function() {
+		return ['->',
+			{
+				text: 'New Zone',
+				iconCls: 'newZoneAction',
+				handler: this.createNewZone,
+				scope: this
+			},
+			{
+				text: 'Reload',
+				iconCls: 'reloadAction',
+				handler: this.reload,
+				scope: this
+			}
+		];
+	},
+	
+	createNewZone: function() {
+		var zoneStore = this.zoneView.getStore();
+		Ext.Msg.prompt('Create new zone', 'Name for new Zone:', function(btn, text){
+			if (btn == 'ok'){
+				for(var i = 0; i <= zoneStore.data.length; i++) {
+					if(zoneStore.findExact('id', i) === -1) {
+						
+						Ext.Ajax.request({
+							url: '/json/structure/addZone',
+							disableCaching: true,
+							method: "GET",
+							params: { zoneID: i },
+							success: function(result, request) {
+								try {
+									var jsonData = Ext.util.JSON.decode(result.responseText);
+									if(jsonData.ok) {
+									
+									
+									
+									Ext.Ajax.request({
+										url: '/json/zone/setName',
+										disableCaching: true,
+										method: "GET",
+										params: { id: i,
+															newName: text},
+										success: function(result, request) {
+											try {
+												var jsonData = Ext.util.JSON.decode(result.responseText);
+												if(jsonData.ok) {
+												
+												
+													var newZone = new zoneStore.recordType({id: i, name: text}, i);
+													zoneStore.insert(i, newZone);
+												
+												
+												
+												}
+											}
+											catch (err) {
+												Ext.MessageBox.alert('Error', 'Could not create Zone');
+											}
+										},
+										failure: function(result, request) {
+											Ext.MessageBox.alert('Error', 'Could not create Zone');
+										},
+									});
+									
+									
+									}
+								}
+								catch (err) {
+									Ext.MessageBox.alert('Error', 'Could not create Zone');
+								}
+							},
+							failure: function(result, request) {
+								Ext.MessageBox.alert('Error', 'Could not create Zone');
+							},
+						});
+						return;
+					}
+				}
+			}
+		})
+	},
+	reload: function() {
+		this.ownerCt.loadData();
+	}
+});
+
+Ext.reg('dsszonepanel', dSS.ZonePanel);

Added: dss/trunk/websrc/dss-setup-interface/dSS/ZoneView.js
===================================================================
--- dss/trunk/websrc/dss-setup-interface/dSS/ZoneView.js	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/dSS/ZoneView.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,105 @@
+//= require <dSS/data/ZoneStore>
+
+Ext.namespace('dSS');
+
+dSS.ZoneView = Ext.extend(Ext.DataView, {
+	initComponent: function() {
+		
+		var zoneTemplate = new Ext.XTemplate(
+			'<tpl for=".">',
+				'<div class="zone-wrap {css}" id="zone-{id}">',
+					'<span>{name}</span>',
+				'</div>',
+			'</tpl>',
+			'<div class="x-clear"></div>'
+		);
+		
+		var zoneStore = new dSS.data.ZoneStore();
+		
+		Ext.apply(this, {
+			store: zoneStore,
+			tpl: zoneTemplate,
+//			autoHeight:true,
+			multiSelect: true,
+			layout: 'fit',
+			style: "overflow: auto",
+			overClass:'x-view-over',
+			itemSelector:'div.zone-wrap',
+			emptyText: 'No Rooms to display',
+			plugins: [
+				new Ext.DataView.DragSelector()
+			]
+		});
+		
+		dSS.ZoneView.superclass.initComponent.apply(this, arguments);
+		// Here you can add functionality that requires the object to
+		// exist, like event handling.
+		this.on(
+			'selectionchange',
+			function(dv,nodes) {
+				var l = nodes.length;
+				var s = l != 1 ? 's' : '';
+				this.findParentByType('dsszonepanel').setTitle("Zones (" + l + ' zone' + s + ' selected)');
+				this.findParentByType('dsszonebrowser').filterDevices();
+			},
+			this
+		);
+		
+		this.on(
+			'render',
+			function() {
+				var zoneView = this;
+				this.dropZone = new Ext.dd.DropZone(zoneView.getEl(), {
+					ddGroup          : "zoneDeviceDD",
+					getTargetFromEvent: function(e) {
+						return e.getTarget(zoneView.itemSelector);
+					},
+					onNodeEnter : function(target, dd, e, data){ 
+						Ext.fly(target).addClass('my-row-highlight-class');
+					},
+					onNodeOut : function(target, dd, e, data){ 
+						Ext.fly(target).removeClass('my-row-highlight-class');
+					},
+					onNodeOver : function(target, dd, e, data){ 
+						return Ext.dd.DropZone.prototype.dropAllowed;
+					},
+					onNodeDrop : function(target, dd, e, data){
+						var record = zoneView.getRecord(target);
+						Ext.each(data.selections, function(device) {
+							var currentDevice = device;
+							Ext.Ajax.request({
+								url: '/json/structure/zoneAddDevice',
+								disableCaching: true,
+								method: "GET",
+								scope: zoneView,
+								params: {		devid: currentDevice.data.id,
+														zone:  record.data.id
+												},
+								success: function(result, request) {
+									try {
+										var jsonData = Ext.util.JSON.decode(result.responseText);
+										if(jsonData.ok) {
+											currentDevice.set("zone", record.data.id);
+											this.getStore().commitChanges();
+											this.findParentByType('dsszonebrowser').filterDevices();
+										}
+									}
+									catch (err) {
+										Ext.MessageBox.alert('Error', 'Could not move device "' + device.data.dsid + '"');
+									}
+								},
+								failure: function(result, request) {
+									Ext.MessageBox.alert('Error', 'Could not move device "' + device.data.dsid + '"');
+								},
+							});
+						});
+						return true;
+					}
+				});
+			},
+			this
+		);
+	}
+});
+
+Ext.reg('dsszoneview', dSS.ZoneView);
\ No newline at end of file

Added: dss/trunk/websrc/dss-setup-interface/dSS/data/DeviceStore.js
===================================================================
--- dss/trunk/websrc/dss-setup-interface/dSS/data/DeviceStore.js	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/dSS/data/DeviceStore.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,26 @@
+Ext.namespace('dSS', 'dSS.data');
+
+dSS.data.DeviceStore = Ext.extend(Ext.data.Store, {
+	constructor: function(config) {
+		// create a record constructor for device records
+		var deviceRecord = Ext.data.Record.create([
+			{name:"name"},
+			{name:"id"},
+			{name:"on"},
+			{name:"circuit"},
+			{name:"modulator"},
+			{name:"zone"}
+		]);
+		
+		// a json reader to read the device data
+		var deviceReader = new Ext.data.JsonReader(
+			{
+				root:"devices"
+			},
+			deviceRecord
+		);
+		
+		Ext.apply(this, { reader: deviceReader });
+		dSS.data.DeviceStore.superclass.constructor.call(this, arguments);
+	}
+});

Added: dss/trunk/websrc/dss-setup-interface/dSS/data/ZoneStore.js
===================================================================
--- dss/trunk/websrc/dss-setup-interface/dSS/data/ZoneStore.js	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/dSS/data/ZoneStore.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,22 @@
+Ext.namespace('dSS', 'dSS.data');
+
+dSS.data.ZoneStore = Ext.extend(Ext.data.Store, {
+	constructor: function(config) {
+		// create a record constructor for zone records
+		var zoneRecord = Ext.data.Record.create([
+			{name:"name"},
+			{name:"id"}
+		]);
+		
+		// a json reader to read the zone data
+		var zoneReader = new Ext.data.JsonReader(
+			{
+				root: "zones"
+			},
+			zoneRecord
+		);
+		
+		Ext.apply(this, { reader: zoneReader });
+		dSS.data.ZoneStore.superclass.constructor.call(this, arguments);
+	}
+});

Added: dss/trunk/websrc/dss-setup-interface/dSS/grid/DevicePanel.js
===================================================================
--- dss/trunk/websrc/dss-setup-interface/dSS/grid/DevicePanel.js	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/dSS/grid/DevicePanel.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,54 @@
+//= require <dSS/data/DeviceStore>
+
+Ext.namespace('dSS', 'dSS.grid');
+
+dSS.grid.DevicePanel = Ext.extend(Ext.grid.GridPanel, {
+	initComponent: function() {
+		
+		var deviceCols = [
+			{id: 'id', header: "id",  width: 50, sortable: true, dataIndex: 'id'},
+			{id: 'name', header: "name", width: 50, sortable: true, dataIndex: 'name', editable: true, editor: new Ext.form.TextField()},
+			{header: "on", width: 50, sortable: true, dataIndex: 'on'},
+			{header: "circuit", width: 50, sortable: true, dataIndex: 'circuit'},
+			{header: "modulator", width: 50, sortable: true, dataIndex: 'modulator'},
+			{header: "zone", width: 50, sortable: true, dataIndex: 'zone'},
+		];
+		
+		var editor = new Ext.ux.grid.RowEditor({
+			saveText: 'Update'
+		});
+		
+		editor.on('afteredit', function() {
+			//console.log('a device has been edited');
+			deviceStore.commitChanges();
+			filterDevices();
+		});
+		
+		var deviceStore = new dSS.data.DeviceStore();
+		
+		Ext.apply(this, {
+			store            : deviceStore,
+			columns          : deviceCols,
+			ddGroup          : "zoneDeviceDD",
+			enableDragDrop   : true,
+			stripeRows       : true,
+			autoExpandColumn : 'id',
+			title            : 'Devices',
+			plugins          : [editor]
+		});
+		
+		dSS.grid.DevicePanel.superclass.initComponent.apply(this, arguments);
+		
+		// Here you can add functionality that requires the object to
+		// exist, like event handling.
+		this.on(
+			'rowcontextmenu',
+			function() {
+				//console.log('rowcontextmenu');
+			},
+			this
+		);
+	}
+});
+
+Ext.reg('dssdevicepanel', dSS.grid.DevicePanel);

Added: dss/trunk/websrc/dss-setup-interface/dss-setup-interface.js
===================================================================
--- dss/trunk/websrc/dss-setup-interface/dss-setup-interface.js	                        (rev 0)
+++ dss/trunk/websrc/dss-setup-interface/dss-setup-interface.js	2009-10-22 12:35:09 UTC (rev 8856)
@@ -0,0 +1,29 @@
+//= require <dSS/ZoneBrowser>
+
+Ext.onReady(function(){
+	Ext.get('start').remove();
+	var viewport = new Ext.Viewport({
+		layout: 'border',
+		items: [
+			{
+				xtype: 'box',
+				region: 'north',
+				height: 32, // give north and south regions a height
+				autoEl: {
+					tag: 'div',
+					html:'<h1>digitalSTROM Setup</h1>'
+				}
+			}, {
+				region: 'center',
+				xtype: 'tabpanel',
+				activeItem: 0,
+				items: [
+					{
+						title: 'Zones',
+						xtype: 'dsszonebrowser',
+						ref: 'zonebrowser'
+					}
+				]
+			}]
+	});
+});



More information about the dss-commits mailing list