Merge branch 'master' of ssh://git.eclipse.org/gitroot/orion/org.eclipse.orion.client
diff --git a/bundles/org.eclipse.orion.client.core/web/js-tests/metatype/testcase.js b/bundles/org.eclipse.orion.client.core/web/js-tests/metatype/testcase.js
index 049a07b..46c6f27 100644
--- a/bundles/org.eclipse.orion.client.core/web/js-tests/metatype/testcase.js
+++ b/bundles/org.eclipse.orion.client.core/web/js-tests/metatype/testcase.js
@@ -64,7 +64,7 @@
 		var ocd = metaTypeRegistry.getObjectClassDefinitionForPid('mypid');
 		assert.ok(!!ocd);
 		assert.strictEqual(ocd.getId(), 'myclass');
-		var props = ocd.getPropertyTypes();
+		var props = ocd.getAttributeDefinitions();
 		assert.strictEqual(props.length, 1);
 		assert.ok(!!props[0]);
 		assert.strictEqual(props[0].getId(), 'myprop0');
@@ -102,7 +102,7 @@
 		assert.ok(!!ocd);
 		assert.strictEqual(ocd.getId(), 'myclass');
 		assert.strictEqual(ocd.getName(), 'My Class');
-		var props = ocd.getPropertyTypes();
+		var props = ocd.getAttributeDefinitions();
 		assert.strictEqual(props.length, 2);
 		assert.ok(!!props[0]);
 		assert.strictEqual(props[0].getId(), 'myprop0');
diff --git a/bundles/org.eclipse.orion.client.core/web/js-tests/settings/testcase.js b/bundles/org.eclipse.orion.client.core/web/js-tests/settings/testcase.js
index e8835e3..650cfac 100644
--- a/bundles/org.eclipse.orion.client.core/web/js-tests/settings/testcase.js
+++ b/bundles/org.eclipse.orion.client.core/web/js-tests/settings/testcase.js
@@ -56,14 +56,14 @@
 		var objectClass = metaTypeRegistry.getObjectClassDefinitionForPid('mysetting');
 
 		assert.equal(objectClass.getId(), 'myclass', 'ObjectClassDefinition is designated for setting\'s PID');
-		assert.equal(objectClass.getPropertyTypes().length, 2);
-		assert.equal(objectClass.getPropertyTypes()[0].getId(), 'prop1');
-		assert.equal(objectClass.getPropertyTypes()[1].getId(), 'prop2');
+		assert.equal(objectClass.getAttributeDefinitions().length, 2);
+		assert.equal(objectClass.getAttributeDefinitions()[0].getId(), 'prop1');
+		assert.equal(objectClass.getAttributeDefinitions()[1].getId(), 'prop2');
 
-		// Ensure setting.getPropertyTypes() has the same property types as the OCD.
-		assert.equal(settings[0].getPropertyTypes().length, 2);
-		assert.equal(settings[0].getPropertyTypes()[0].getId(), 'prop1');
-		assert.equal(settings[0].getPropertyTypes()[1].getId(), 'prop2');
+		// Ensure setting.getAttributeDefinitions() has the same attribute definitions as the OCD.
+		assert.equal(settings[0].getAttributeDefinitions().length, 2);
+		assert.equal(settings[0].getAttributeDefinitions()[0].getId(), 'prop1');
+		assert.equal(settings[0].getAttributeDefinitions()[1].getId(), 'prop2');
 
 		serviceRegistration.unregister();
 		assert.equal(settingsRegistry.getSettings().length, 0);
@@ -91,18 +91,71 @@
 		assert.ok(objectClass, 'Setting\'s PID is designated');
 
 		assert.equal(objectClass.getId(), objectClassId);
-		assert.equal(objectClass.getPropertyTypes().length, 2);
-		assert.equal(objectClass.getPropertyTypes()[0].getId(), 'foo');
-		assert.equal(objectClass.getPropertyTypes()[1].getId(), 'bar');
+		assert.equal(objectClass.getAttributeDefinitions().length, 2);
+		assert.equal(objectClass.getAttributeDefinitions()[0].getId(), 'foo');
+		assert.equal(objectClass.getAttributeDefinitions()[1].getId(), 'bar');
 
-		assert.equal(settings[0].getPropertyTypes().length, 2);
-		assert.equal(settings[0].getPropertyTypes()[0].getId(), 'foo');
-		assert.equal(settings[0].getPropertyTypes()[1].getId(), 'bar');
+		assert.equal(settings[0].getAttributeDefinitions().length, 2);
+		assert.equal(settings[0].getAttributeDefinitions()[0].getId(), 'foo');
+		assert.equal(settings[0].getAttributeDefinitions()[1].getId(), 'bar');
 
 		serviceRegistration.unregister();
 		assert.equal(settingsRegistry.getSettings().length, 0);
 		assert.ok(!metaTypeRegistry.getObjectClassDefinitionForPid('mysetting'), 'Setting\'s PID no longer designated');
 		assert.ok(!metaTypeRegistry.getObjectClassDefinition(objectClassId), 'ObjectClassDefinition was removed');
 	});
+	tests['test setting categories'] = makeTest(function() {
+		var serviceRegistration1 = serviceRegistry.registerService(SETTING_SERVICE, {},
+			{	settings: [
+					{	pid: 'mypid1',
+						category: 'cat',
+						properties: [
+							{	id: 'prop' }
+						]
+					},
+					{	pid: 'mypid2',
+						category: 'dog',
+						properties: [
+							{	id: 'prop' }
+						]
+					},
+					{	pid: 'mypid3',
+						category: 'cat',
+						properties: [
+							{	id: 'prop' }
+						]
+					}
+				]
+			});
+		var serviceRegistration2 = serviceRegistry.registerService(SETTING_SERVICE, {},
+			{	settings: [
+					{	pid: 'mypid4',
+						category: 'cat',
+						properties: [
+							{	id: 'prop' }
+						]
+					}
+				]
+			});
+
+		var settings = settingsRegistry.getSettings();
+		assert.equal(settings.length, 4);
+		assert.deepEqual(settingsRegistry.getCategories().sort(), ['cat', 'dog'].sort());
+		var catSettings = settingsRegistry.getSettings('cat');
+		var dogSettings = settingsRegistry.getSettings('dog');
+
+		assert.equal(catSettings.length, 3);
+		assert.equal(catSettings[0].getPid(), 'mypid1');
+		assert.equal(catSettings[1].getPid(), 'mypid3');
+		assert.equal(catSettings[2].getPid(), 'mypid4');
+
+		assert.equal(dogSettings.length, 1);
+		assert.equal(dogSettings[0].getPid(), 'mypid2');
+
+		serviceRegistration1.unregister();
+		assert.deepEqual(settingsRegistry.getCategories(), ['cat']);
+		assert.equal(settingsRegistry.getSettings('cat').length, 1);
+		assert.equal(settingsRegistry.getSettings('dog').length, 0);
+	});
 	return tests;
 });
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/compare/compare-container.js b/bundles/org.eclipse.orion.client.core/web/orion/compare/compare-container.js
index 606a074..0059c20 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/compare/compare-container.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/compare/compare-container.js
@@ -701,14 +701,14 @@
 			}));
 			return view;
 		};
-			
+		/*
 		var contentAssistFactory = {
 			createContentAssistMode: function(editor) {
 				var contentAssist = new mContentAssist.ContentAssist(editor.getTextView());
 				var widget = new mContentAssist.ContentAssistWidget(contentAssist, "contentassist"); //$NON-NLS-0$
 				return new mContentAssist.ContentAssistMode(contentAssist, widget);
 			}
-		};
+		};*/
 			
 		var keyBindingFactory = function(editor, keyModeStack, undoStack, contentAssist) {
 			// Create keybindings for generic editing
@@ -746,7 +746,7 @@
 			undoStackFactory: undoStackFactory,
 			annotationFactory: annotationFactory,
 			//lineNumberRulerFactory: new exports.LineNumberRulerFactory(),
-			contentAssistFactory: contentAssistFactory,
+			//contentAssistFactory: contentAssistFactory,
 			keyBindingFactory: keyBindingFactory, 
 			statusReporter: statusReporter,
 			domNode: editorContainerDomNode
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/compare/compareUtils.js b/bundles/org.eclipse.orion.client.core/web/orion/compare/compareUtils.js
index 0f9f762..a4a4e63 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/compare/compareUtils.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/compare/compareUtils.js
@@ -187,6 +187,10 @@
 				var lineText = diffArray[mapperItem[2]-1+j];
 				text = text + lineText.substring(diffArraySubstrIndex) + lineDelim;
 			}
+			var lineCount = oldTextModel.getLineCount();
+			if(startLineIndex >= lineCount ){
+				startLineIndex = lineCount -1;
+			}
 			var startOffset = oldTextModel.getLineStart(startLineIndex);
 			oldTextModel.setText(text, startOffset, startOffset);
 		}
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/metatype.js b/bundles/org.eclipse.orion.client.core/web/orion/metatype.js
index 58b77fa..2c0916a 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/metatype.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/metatype.js
@@ -12,7 +12,7 @@
 define(['orion/serviceTracker'], function(ServiceTracker) {
 	var PROPERTY_CLASSES = 'classes', PROPERTY_DESIGNATES = 'designates'; //$NON-NLS-0$ //$NON-NLS-1$
 	var METATYPE_SERVICE = 'orion.cm.metatype'; //$NON-NLS-0$
-	var PropertyTypeImpl, ObjectClassDefinitionImpl;
+	var AttributeDefinitionImpl, ObjectClassDefinitionImpl;
 
 	/**
 	 * @name orion.metatype.MetaTypeRegistry
@@ -91,11 +91,11 @@
 		}
 		this.props = [];
 		for (var i=0; i < props.length; i++) {
-			this.props.push(new PropertyTypeImpl(props[i]));
+			this.props.push(new AttributeDefinitionImpl(props[i]));
 		}
 	};
 	ObjectClassDefinitionImpl.prototype = {
-		getPropertyTypes: function() {
+		getAttributeDefinitions: function() {
 			return this.props;
 		},
 		getId: function() {
@@ -107,10 +107,10 @@
 	};
 
 	/**
-	 * @name orion.metatype.impl.PropertyTypeImpl
+	 * @name orion.metatype.impl.AttributeDefinitionImpl
 	 * @private
 	 */
-	PropertyTypeImpl = /** @ignore */ function(attrJson) {
+	AttributeDefinitionImpl = /** @ignore */ function(attrJson) {
 		function isType(t) {
 			switch (t) {
 				case 'boolean': //$NON-NLS-0$
@@ -138,7 +138,7 @@
 			});
 		}
 	};
-	PropertyTypeImpl.prototype = {
+	AttributeDefinitionImpl.prototype = {
 		getId: function() {
 			return this.id;
 		},
@@ -170,10 +170,10 @@
 	 * what properties may appear in a {@link orion.cm.ConfigurationProperties} dictionary.</p>
 	 */
 		/**
-		 * @name orion.metatype.ObjectClassDefinition#getPropertyTypes
+		 * @name orion.metatype.ObjectClassDefinition#getAttributeDefinitions
 		 * @function
-		 * @description Returns the property types.
-		 * @returns {orion.metatype.PropertyType[]} The property types of this Object Class Definition.
+		 * @description Returns the attribute definitions.
+		 * @returns {orion.metatype.AttributeDefinition[]} The attribute definitions of this Object Class Definition.
 		 */
 		/**
 		 * @name orion.metatype.ObjectClassDefinition#getId
@@ -188,39 +188,39 @@
 		 * @returns {String} The name of this Object Class Definition. May be <code>null</code>.
 		 */
 	/**
-	 * @name orion.metatype.PropertyType
-	 * @class Describes the data type of a property.
-	 * @description A <code>PropertyType</code> describes the data type of a property. <p>It typically serves to
+	 * @name orion.metatype.AttributeDefinition
+	 * @class Describes the data type of a property/attribute.
+	 * @description An <code>AttributeDefinition</code> describes the data type of a property/attribute. <p>It typically serves to
 	 * describe the type of an individual property that may appear in a {@link orion.cm.ConfigurationProperties} dictionary.</p>
 	 */
 		/**
-		 * @name orion.metatype.PropertyType#getId
+		 * @name orion.metatype.AttributeDefinition#getId
 		 * @function
 		 * @description Returns the id.
-		 * @returns {String} The id of this PropertyType.
+		 * @returns {String} The id of this AttributeDefinition.
 		 */
 		/**
-		 * @name orion.metatype.PropertyType#getName
+		 * @name orion.metatype.AttributeDefinition#getName
 		 * @function
 		 * @description Returns the description.
 		 * @returns {String} The name, or <code>null</code>.
 		 */
 		/**
-		 * @name orion.metatype.PropertyType#getOptionValues
+		 * @name orion.metatype.AttributeDefinition#getOptionValues
 		 * @function
-		 * @description Returns the option values that this property can take.
+		 * @description Returns the option values that this attribute can take.
 		 * @returns {Object[]|null} The option values. The ordering of the returned array matches the ordering of the labels
 		 * array returned by {@link #getOptionLabels}. If there are no option values available, <code>null</code> is returned.
 		 */
 		/**
-		 * @name orion.metatype.PropertyType#getOptionLabels
+		 * @name orion.metatype.AttributeDefinition#getOptionLabels
 		 * @function
 		 * @description Returns a list of labels for option values.
 		 * @returns {String[]|null} The option labels. The ordering of the returned array matches the ordering of the values
 		 * array returned by {@link #getOptionValues}. If there are no option labels available, <code>null</code> is returned.
 		 */
 		/**
-		 * @name orion.metatype.PropertyType#getType
+		 * @name orion.metatype.AttributeDefinition#getType
 		 * @function
 		 * @description Returns the type.
 		 * @returns {String} The type. It is one of:
@@ -231,7 +231,7 @@
 		 * </ul>
 		 */
 		/**
-		 * @name orion.metatype.PropertyType#getDefaultValue
+		 * @name orion.metatype.AttributeDefinition#getDefaultValue
 		 * @function
 		 * @description Returns the default value.
 		 * @returns {Object} The default value, or <code>null</code> if no default exists.
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/settings/nls/root/messages.js b/bundles/org.eclipse.orion.client.core/web/orion/settings/nls/root/messages.js
index 7169467..3e54593 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/settings/nls/root/messages.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/settings/nls/root/messages.js
@@ -113,5 +113,6 @@
 	"Authentication" : "Authentication",

 	"Please be aware that your credentials will be stored persistently in the browser." : "Please be aware that your credentials will be stored persistently in the browser.",

 	"Do you wish to enable the Key Storage?" : "Do you wish to enable the Key Storage?",

-	PluginSettings: 'Plugin Settings'

+	"general": "General",

+	"validation": "Validation"

 });
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/settings/settingsRegistry.js b/bundles/org.eclipse.orion.client.core/web/orion/settings/settingsRegistry.js
index 67aeecf..529a82c 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/settings/settingsRegistry.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/settings/settingsRegistry.js
@@ -13,15 +13,16 @@
 define(['orion/serviceTracker'], function(ServiceTracker) {
 	var METATYPE_SERVICE = 'orion.cm.metatype', SETTING_SERVICE = 'orion.core.setting'; //$NON-NLS-0$ //$NON-NLS-1$
 	var SETTINGS_PROP = 'settings'; //$NON-NLS-0$
+	var DEFAULT_CATEGORY = 'unsorted'; //$NON-NLS-0$
 
 	/**
 	 * @param {Object} value
-	 * @param {orion.metatype.PropertyType} propertyType
+	 * @param {orion.metatype.AttributeDefinition} attributeDefinition
 	 */
-	function equalsDefaultValue(value, propertyType) {
-		var defaultValue = propertyType.getDefaultValue();
+	function equalsDefaultValue(value, attributeDefinition) {
+		var defaultValue = attributeDefinition.getDefaultValue();
 		var result = value === defaultValue;
-		if (propertyType.getType() === 'string') { //$NON-NLS-0$
+		if (attributeDefinition.getType() === 'string') { //$NON-NLS-0$
 			result = result || (value === '' && defaultValue === null);
 		}
 		return result;
@@ -36,9 +37,15 @@
 		 * @name orion.settings.Setting#isDefaults
 		 * @function
 		 * @description
-		 * @param {Object} properties A map of PropertyType IDs to values.
+		 * @param {Object} properties A map of AttributeDefinition IDs to values.
 		 * @returns {Boolean} <code>true</code> if <code>properties</code> contains a key for each of this setting's
-		 * PropertyTypes, and the corresponding value equals the PropertyType's default value.
+		 * AttributeDefinitions, and the corresponding value equals the AttributeDefinition's default value.
+		 */
+		/**
+		 * @name orion.settings.Setting#getCategory
+		 * @function
+		 * @description
+		 * @returns {String} The category of this setting.
 		 */
 		/**
 		 * @name orion.settings.Setting#getPid
@@ -59,10 +66,10 @@
 		 * @returns {String}
 		 */
 		/**
-		 * @name orion.settings.Setting#getPropertyTypes
+		 * @name orion.settings.Setting#getAttributeDefinitions
 		 * @function
 		 * @description
-		 * @returns {orion.metatype.PropertyType[]}
+		 * @returns {orion.metatype.AttributeDefinition[]}
 		 */
 		/**
 		 * @name orion.settings.Setting#getTags
@@ -76,6 +83,7 @@
 		this.classId = this.isRef ? json.classId : this.pid + '.type'; //$NON-NLS-0$
 		this.name = typeof json.name === 'string' ? json.name : null; //$NON-NLS-0$
 		this.properties = null;
+		this.category = json.category;
 		this.tags = json.tags;
 		if (!this.pid) { throw new Error('Missing "pid" property'); } //$NON-NLS-0$
 	}
@@ -83,11 +91,12 @@
 		getName: function() { return this.name; },
 		getPid: function() { return this.pid; },
 		getObjectClassDefinitionId: function() { return this.classId; },
-		getPropertyTypes: function() { return this.properties; },
+		getAttributeDefinitions: function() { return this.properties; },
+		getCategory: function() { return this.category || null; },
 		getTags: function() { return this.tags || []; },
 		isDefaults: function(properties) {
-			return this.getPropertyTypes().every(function(propertyType) {
-				return equalsDefaultValue(properties[propertyType.getId()], propertyType);
+			return this.getAttributeDefinitions().every(function(attributeDefinition) {
+				return equalsDefaultValue(properties[attributeDefinition.getId()], attributeDefinition);
 			});
 		}
 	};
@@ -95,7 +104,7 @@
 	/**
 	 * Tracks dynamic registration/unregistration of settings and registers/unregisters the corresponding MetaType service.
 	 */
-	function SettingTracker(serviceRegistry, metaTypeRegistry, settingsMap) {
+	function SettingTracker(serviceRegistry, metaTypeRegistry, settingsMap, categoriesMap) {
 		var serviceRegistrations = {};
 
 		function _addSetting(settingJson) {
@@ -116,23 +125,28 @@
 			}
 			serviceRegistrations[setting.getPid()] = serviceRegistry.registerService(METATYPE_SERVICE, {}, serviceProperties);
 			var ocd = metaTypeRegistry.getObjectClassDefinition(classId);
-			setting.properties = ocd.getPropertyTypes();
+			setting.properties = ocd.getAttributeDefinitions();
 			settingsMap[setting.getPid()] = setting;
+			var category = setting.getCategory() || DEFAULT_CATEGORY;
+			if (!categoriesMap[category]) {
+				categoriesMap[category] = [];
+			}
+			categoriesMap[category].push(setting.getPid());
 		}
 
-		function _deleteSetting(pid) {
+		function _deleteSetting(pid, category) {
 			var serviceRegistration = serviceRegistrations[pid];
 			serviceRegistration.unregister();
 			delete serviceRegistrations[pid];
 			delete settingsMap[pid];
+			var pids = categoriesMap[category || DEFAULT_CATEGORY];
+			pids.splice(pids.indexOf(pid), 1);
+			if (!pids.length) {
+				delete categoriesMap[category];
+			}
 		}
 
 		ServiceTracker.call(this, serviceRegistry, SETTING_SERVICE);
-		serviceRegistry.getServiceReferences(SETTING_SERVICE).forEach(function(ref) {
-			(ref.getProperty(SETTINGS_PROP) || []).forEach(function(settingJson) {
-				_addSetting(settingJson);
-			});
-		});
 		this.addingService = function(serviceRef) {
 			var settings = serviceRef.getProperty(SETTINGS_PROP);
 			if (!settings || !settings.length) {
@@ -146,7 +160,7 @@
 		this.removedService = function(serviceRef, service) {
 			var settings = serviceRef.getProperty(SETTINGS_PROP);
 			for (var i=0; i < settings.length; i++) {
-				_deleteSetting(settings[i].pid);
+				_deleteSetting(settings[i].pid, settings[i].category);
 			}
 		};
 	}
@@ -159,20 +173,33 @@
 	 * @param {orion.metatype.MetaTypeRegistry} metaTypeRegistry The metatype registry to look up Object Class Definitions in.
 	 */
 	function SettingsRegistry(serviceRegistry, metaTypeRegistry) {
-		this.settingsMap = {};
-		var tracker = new SettingTracker(serviceRegistry, metaTypeRegistry, this.settingsMap);
+		this.settingsMap = Object.create(null); // PID -> Setting
+		this.categories = Object.create(null);  // Category -> PID[]
+		var tracker = new SettingTracker(serviceRegistry, metaTypeRegistry, this.settingsMap, this.categories);
 		tracker.open();
 	}
 	SettingsRegistry.prototype = /** @lends orion.settings.SettingsRegistry.prototype */ {
 		/**
-		 * Returns all settings.
+		 * Returns settings.
+		 * @param {String} [category] If passed, returns only the settings in the given category. Otherwise, returns all settings.
 		 * @returns {orion.settings.Setting[]}
 		 */
-		getSettings: function() {
+		getSettings: function(category) {
 			var settingsMap = this.settingsMap;
-			return Object.keys(settingsMap).map(function(pid) {
+			var pids = (typeof category === 'string') ? this.categories[category] : Object.keys(settingsMap);
+			if (!pids) {
+				return [];
+			}
+			return pids.map(function(pid) {
 				return settingsMap[pid];
 			});
+		},
+		/**
+		 * Returns all setting categories.
+		 * @returns {String[]}
+		 */
+		getCategories: function() {
+			return Object.keys(this.categories);
 		}
 	};
 
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/settings/ui/PluginSettings.js b/bundles/org.eclipse.orion.client.core/web/orion/settings/ui/PluginSettings.js
index ff901c9..1a0a0c5 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/settings/ui/PluginSettings.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/settings/ui/PluginSettings.js
@@ -84,7 +84,7 @@
 			}
 		}
 	}),
-	PropertiesWidget = dojo.declare('orion.widgets.settings.PropertiesWidget', [dijit._Container, dijit._WidgetBase], { //$NON-NLS-0$
+	PropertiesWidget = dojo.declare('orion.widgets.settings.PropertiesWidget', [dijit._WidgetBase, dijit._Container], { //$NON-NLS-0$
 		buildRendering: function() {
 			this.inherited(arguments);
 			var serviceRegistry = this.serviceRegistry;
@@ -113,7 +113,7 @@
 		},
 		createChildren: function(configuration) {
 			var self = this;
-			this.setting.getPropertyTypes().forEach(function(property) {
+			this.setting.getAttributeDefinitions().forEach(function(property) {
 				var options = {
 					property: property, configuration: configuration, serviceRegistry: self.serviceRegistry,
 					changeProperty: self.changeProperty.bind(self, property)
@@ -136,11 +136,11 @@
 				self.addChild(widget);
 			});
 		},
-		changeProperty: function(propertyType, value) {
+		changeProperty: function(attributeDefinition, value) {
 			this.initConfiguration().then(function(configuration) {
 				var setting = this.setting;
 				var props = configuration.getProperties() || {};
-				props[propertyType.getId()] = value;
+				props[attributeDefinition.getId()] = value;
 				if (setting.isDefaults(props)) {
 					configuration.remove();
 					this.configuration = null;
@@ -157,6 +157,7 @@
 	 */
 	function SettingsRenderer(settingsList, serviceRegistry) {
 		this.serviceRegistry = serviceRegistry;
+		this.childWidgets = [];
 		SelectionRenderer.call(this, {/*registry: that.registry, actionScopeId: "sdsd",*/ cachePrefix: 'pluginSettings'}, settingsList); //$NON-NLS-0$
 	}
 	SettingsRenderer.prototype = new SelectionRenderer();
@@ -176,6 +177,7 @@
 		var propertiesElement = document.createElement('div'); //$NON-NLS-0$
 		propertiesElement.className = 'setting-content'; //$NON-NLS-0$
 		var propertiesWidget = this.createPropertiesWidget(propertiesElement, setting);
+		this.childWidgets.push(propertiesWidget);
 		propertiesWidget.startup();
 
 		settingSection.appendChild(sectionHeader);
@@ -189,6 +191,14 @@
 	SettingsRenderer.prototype.renderTableHeader = function(tableNode) {
 		return document.createElement('div'); //$NON-NLS-0$
 	};
+	SettingsRenderer.prototype.destroy = function() {
+		if (this.childWidgets) {
+			this.childWidgets.forEach(function(widget) {
+				widget.destroyRecursive();
+			});
+		}
+		this.childWidgets = null;
+	};
 
 	/**
 	 * Explorer for SettingsList.
@@ -197,40 +207,47 @@
 		Explorer.call(this, serviceRegistry, selection, new SettingsRenderer(this, serviceRegistry));
 	}
 	SettingsListExplorer.prototype = new Explorer();
+	SettingsListExplorer.prototype.destroy = function() {
+		if (this.renderer) {
+			this.renderer.destroy();
+		}
+	};
 
 	/**
 	 * Widget showing list of Plugin Settings.
 	 * Requires the 'orion.cm.configadmin' service.
 	 * @param {DomNode|String} options.parent
 	 * @param {orion.serviceregistry.ServiceRegistry} options.serviceRegistry
-	 * @param {orion.settings.SettingsRegistry} options.settingsRegistry
+	 * @param {orion.settings.Settings[]} options.settings
 	 */
 	function SettingsList(options) {
 		var parent = options.parent;
 		var serviceRegistry = options.serviceRegistry;
-		var settingsRegistry = options.settingsRegistry;
-		if (!options.parent || !options.serviceRegistry || !options.settingsRegistry) {
+		var settings = options.settings;
+		if (!options.parent || !options.serviceRegistry || !options.settings || !options.title) {
 			throw 'Missing required option'; //$NON-NLS-0$
 		}
 		this.parent = typeof parent === 'string' ? document.getElementById('parent') : parent; //$NON-NLS-0$ //$NON-NLS-1$
 		// TODO add commands
-		this.render(parent, serviceRegistry, settingsRegistry);
+		this.render(parent, serviceRegistry, settings, options.title);
 	}
 	SettingsList.prototype = {
-		_makeSection: function(parent, sectionId, settings) {
-			var section = new Section(parent, {id: sectionId, title: messages.PluginSettings, useAuxStyle: true,
-				getItemCount: function() { return settings.length; } });
+		_makeSection: function(parent, sectionId, settings, title) {
+			var section = new Section(parent, { id: sectionId, title: title, useAuxStyle: true,
+					getItemCount: function() { return settings.length; } });
 			return section;
 		},
-		render: function(parent, serviceRegistry, settingsRegistry) {
-			var allSettings = settingsRegistry.getSettings();
+		destroy: function() {
+			this.explorer.destroy();
+		},
+		render: function(parent, serviceRegistry, settings, title) {
 			// FIXME Section forces a singleton id, bad
 			var idPrefix = 'pluginsettings-'; //$NON-NLS-0$
 			var sectionId = idPrefix + 'section'; //$NON-NLS-0$
-			var section = this._makeSection(parent, sectionId, allSettings);
+			var section = this._makeSection(parent, sectionId, settings, title);
 
 			this.explorer = new SettingsListExplorer(serviceRegistry);
-			this.explorer.createTree(section.getContentElement().id, new mExplorer.SimpleFlatModel(allSettings, 'setting-', //$NON-NLS-0$
+			this.explorer.createTree(section.getContentElement().id, new mExplorer.SimpleFlatModel(settings, 'setting-', //$NON-NLS-0$
 				function(item) {
 					return item.getPid();
 				}),
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js b/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js
index 1b86203..ce00d42 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/sites/nls/root/messages.js
@@ -57,7 +57,7 @@
 	"WorkspaceFile": "Workspace file: ${0}",
 	"WorkspaceFolder": "Workspace folder: ${0}",
 	"WorkspaceResourceNotFound": "Workspace resource not found: ${0}",
-	"ExternalLinkTo ": "External link to ${0}",
+	"ExternalLinkTo": "External link to ${0}",
 	"Move Up": "Move Up",
 	"Move Down": "Move Down",
 	"HostHint": "HostHint",
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/sites/siteMappingsTable.js b/bundles/org.eclipse.orion.client.core/web/orion/sites/siteMappingsTable.js
index 2d00077..f40ce3c 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/sites/siteMappingsTable.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/sites/siteMappingsTable.js
@@ -132,7 +132,7 @@
 				});
 			} else {
 				href = target;
-				a = dojo.create("a", {href: href, target: "_new"}, "only"); //$NON-NLS-2$ //$NON-NLS-0$
+				a = dojo.create("a", {href: href, target: "_new"}, col, "only"); //$NON-NLS-2$ //$NON-NLS-0$
 				dojo.create("span", {"class": "imageSprite core-sprite-link", title: i18nUtil.formatMessage(messages.ExternalLinkTo, href)}, a); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
 			}
 			dojo.addClass(col, "isValidCell"); //$NON-NLS-0$
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/sites/sitesExplorer.js b/bundles/org.eclipse.orion.client.core/web/orion/sites/sitesExplorer.js
index b435035..2a6a18d 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/sites/sitesExplorer.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/sites/sitesExplorer.js
@@ -9,92 +9,227 @@
  * Contributors: IBM Corporation - initial API and implementation
  ******************************************************************************/
 /*global define document*/
-define(['i18n!orion/sites/nls/messages', 'orion/i18nUtil', 'dojo', 'orion/Deferred', 'orion/commands', 'orion/globalCommands',
-		'orion/selection', 'orion/sites/siteUtils', 'orion/sites/siteClient', 'orion/sites/siteCommands', 'orion/treetable'],
-		function(messages, i18nUtil, dojo, Deferred, mCommands, mGlobalCommands, mSelection, mSiteUtils, mSiteClient, mSiteCommands, treetable) {
-	var formatMessage = i18nUtil.formatMessage;
-	var TableTree = treetable.TableTree;
-	var SitesTree, ViewOnSiteTree;
+define(['i18n!orion/sites/nls/messages', 'orion/i18nUtil', 'dojo', 'orion/explorers/explorer', 'orion/Deferred', 'orion/commands', 'orion/globalCommands',
+		'orion/selection', 'orion/sites/siteUtils', 'orion/explorers/navigationUtils', 'orion/sites/siteClient', 'orion/sites/siteCommands', 'orion/treetable'],
+		function(messages, i18nUtil, dojo, mExplorer, Deferred, mCommands, mGlobalCommands, mSelection, mSiteUtils, mNavUtils, mSiteClient, mSiteCommands, treetable) {
+	var SiteServicesExplorer, SitesRenderer, SiteTreeModel;
 
 	/** 
-	 * @name orion.sites.SiteServicesExplorer
-	 * @class Section-based explorer showing the sites on each site service.
+	 * Generates an explorer showing the sites on each site service.
+	 * 
 	 * @param {orion.serviceregistry.ServiceRegistry} options.serviceRegistry
-	 * @param {DomNode} options.parent
+	 * @param registry [required] service registry
+	 * @param selection [required] selection service
+	 * @param parentId [required] parent node id
+	 * @returns SiteServicesExplorer object
 	 */
-	function SiteServicesExplorer(options) {
-		this.registry = options.serviceRegistry;
-		this.parentNode = options.parent;
-		this.siteServiceRefs = this.registry.getServiceReferences('orion.site'); //$NON-NLS-0$
-	}
-	
-	var updatePageActions = function(registry, toolbarId, scopeId, item){
-		var toolbar = dojo.byId(toolbarId);
-		var commandService = registry.getService("orion.page.command");  //$NON-NLS-0$
-		if (toolbar) {
-			commandService.destroy(toolbar);
-		} else {
-			throw "could not find toolbar " + toolbarId; //$NON-NLS-0$
+	SiteServicesExplorer = (function() {
+		
+		function SiteServicesExplorer(registry, selection, parentId) {
+			this.registry = registry;
+			this.checkbox = false;
+			this.parentId = parentId;
+			this.selection = selection;
+			
+			this.pageActionsWrapperId = "pageActions";
+			this.selectionActionsWrapperId = "selectionTools";
+			this.defaultActionWrapperId = "DefaultActionWrapper";
 		}
-		commandService.renderCommands(scopeId, toolbar, item, null, "button");  //$NON-NLS-0$
-	};
-	
-	SiteServicesExplorer.prototype = /** @lends orion.sites.SiteServicesExplorer.prototype */ {
-		display: function() {
-			var serviceRegistry = this.registry;
-			var commandService = serviceRegistry.getService('orion.page.command'); //$NON-NLS-0$
-			var serviceRefs = this.siteServiceRefs;
-			for (var i=0; i < serviceRefs.length; i++) {
-				var siteServiceRef = serviceRefs[i];
-				var siteService = this.registry.getService(siteServiceRef);
-				var siteClient = new mSiteClient.SiteClient(serviceRegistry, siteService, siteServiceRef);
-				var sectionId = 'section' + i; //$NON-NLS-0$
-				var sitesNodeId = sectionId + 'siteNode'; //$NON-NLS-0$
-				
-				var section = {};
-				
-				var contentParent = dojo.create("div", {"role": "region", "class":"sectionTable"}, this.parentNode, "last");
-				contentParent.innerHTML = '<div id="' + sitesNodeId + '" class="plugin-settings-list"></div>'; //$NON-NLS-0$
-				
-				commandService.registerCommandContribution("pageActions", 'orion.site.create', 100); //$NON-NLS-0$
-				
-				updatePageActions(this.registry, "pageActions", "pageActions", siteServiceRef); //$NON-NLS-1$ //$NON-NLS-0$
-
-				var sectionItemActionScopeId = 'section' + i + 'Action'; //$NON-NLS-1$ //$NON-NLS-0$
-				
-				commandService.registerCommandContribution(sectionItemActionScopeId, 'orion.site.edit', 10); //$NON-NLS-0$
-				commandService.registerCommandContribution(sectionItemActionScopeId, 'orion.site.start', 20); //$NON-NLS-0$
-				commandService.registerCommandContribution(sectionItemActionScopeId, 'orion.site.stop', 30); //$NON-NLS-0$
-				commandService.registerCommandContribution(sectionItemActionScopeId, 'orion.site.delete', 40); //$NON-NLS-0$
-				
-				var refresher = (function(section) {
-					return function() {
-						section.tree.refresh();
-					};
-				}(section));
-				section.tree = new SitesTree({
-					id: sitesNodeId + 'tree', //$NON-NLS-0$
-					parent: sitesNodeId,
-					actionScopeId: sectionItemActionScopeId,
-					serviceRegistry: this.registry,
-					siteService: siteClient,
-					startCallback: refresher,
-					stopCallback: refresher,
-					deleteCallback: refresher
-				});
+		
+		SiteServicesExplorer.prototype = new mExplorer.Explorer();
+		
+		SiteServicesExplorer.prototype._updatePageActions = function(registry, item){
+			var toolbar = dojo.byId(this.pageActionsWrapperId);
+			var commandService = registry.getService("orion.page.command");  //$NON-NLS-0$
+			if (toolbar) {
+				commandService.destroy(toolbar);
+			} else {
+				throw "could not find toolbar " + this.pageActionsWrapperId; //$NON-NLS-0$
 			}
-		}
-	};
+			commandService.renderCommands(this.pageActionsWrapperId, toolbar, item, this, "button", this.getRefreshHandler());  //$NON-NLS-0$
+		};
+		
+		SiteServicesExplorer.prototype._getSiteConfigurations = function(siteServices, result, deferred){
+			var that = this;
+			
+			if (!deferred)
+				deferred = new dojo.Deferred();
+			
+			if (!result)
+				result = [];
+			
+			if (siteServices.length > 0) {
+				siteServices[0].getSiteConfigurations().then(
+					function(/**Array*/ siteConfigurations) {
+						result.push.apply(result, siteConfigurations);
+						that._getSiteConfigurations(siteServices.slice(1), result, deferred);
+					}
+				);					
+			} else {
+				deferred.callback(result);
+			}
+			
+			return deferred;
+		};
+		
+		SiteServicesExplorer.prototype.display = function(){
+			var that = this;
+			
+			var progressService = this.registry.getService("orion.page.message"); //$NON-NLS-0$
+			var loadingDeferred = new dojo.Deferred();
+			progressService.showWhile(loadingDeferred, messages['Loading...']);
+			
+			var siteServiceRefs = this.registry.getServiceReferences('orion.site'); //$NON-NLS-0$
 
-	var SiteTreeModel = (function() {
+			this.siteClients = [];
+			for (var i=0; i < siteServiceRefs.length; i++) {
+				var siteServiceRef = siteServiceRefs[i];
+				var siteService = this.registry.getService(siteServiceRef);
+				this.siteClients.push(new mSiteClient.SiteClient(this.registry, siteService, siteServiceRef));
+			}
+
+			this._getSiteConfigurations(this.siteClients).then(
+				function(siteConfigurations){
+					that.renderer = new SitesRenderer({registry: that.registry, actionScopeId: "sdsd", cachePrefix: "SitesExplorer", checkbox: false}, that); //$NON-NLS-0$
+
+					var commandService = that.registry.getService('orion.page.command'); //$NON-NLS-0$
+					
+					commandService.registerCommandContribution(that.pageActionsWrapperId, 'orion.site.create', 100); //$NON-NLS-0$
+					
+					commandService.registerCommandContribution(that.selectionActionsWrapperId, 'orion.site.start', 20); //$NON-NLS-0$
+					commandService.registerCommandContribution(that.selectionActionsWrapperId, 'orion.site.stop', 30); //$NON-NLS-0$
+					commandService.registerCommandContribution(that.selectionActionsWrapperId, 'orion.site.delete', 40); //$NON-NLS-0$
+					
+					commandService.registerCommandContribution(that.defaultActionWrapperId, 'orion.site.start', 20); //$NON-NLS-0$
+					commandService.registerCommandContribution(that.defaultActionWrapperId, 'orion.site.stop', 30); //$NON-NLS-0$
+					
+					that.createTree(that.parentId, new SiteTreeModel(siteConfigurations), {setFocus: true});
+					
+					// TODO should show Create per each site service
+					that._updatePageActions(that.registry, siteServiceRefs[0]); //$NON-NLS-1$ //$NON-NLS-0$
+					
+					if (!that.doOnce){
+						that.registry.getService("orion.page.selection").addEventListener("selectionChanged", function(event) { //$NON-NLS-1$ //$NON-NLS-0$
+							var selectionTools = dojo.byId(that.selectionActionsWrapperId);
+							if (selectionTools) {
+								commandService.destroy(selectionTools);						
+								commandService.renderCommands(that.selectionActionsWrapperId, selectionTools, event.selections, that, "button", that.getRefreshHandler()); //$NON-NLS-1$ //$NON-NLS-0$
+							}
+						});
+						
+						that.doOnce = true;
+					}
+					
+					loadingDeferred.callback();
+					progressService.setProgressMessage("");
+				}
+			);
+		};
+		
+		SiteServicesExplorer.prototype.getRefreshHandler = function(){
+			return {
+				startCallback: dojo.hitch(this, this.refresh),
+				stopCallback: dojo.hitch(this, this.refresh),
+				deleteCallback: dojo.hitch(this, this.refresh),
+				errorCallback: dojo.hitch(this, this.refresh)
+			};
+		};
+		
+		SiteServicesExplorer.prototype.refresh = function(){
+			var that = this;
+			
+			this._getSiteConfigurations(this.siteClients).then(
+				function(siteConfigurations){
+					that.createTree(that.parentId, new SiteTreeModel(siteConfigurations), {setFocus: true});
+				}
+			);
+		};
+		
+		return SiteServicesExplorer;
+	}());
+	
+	SitesRenderer = (function() {
+		
+		SitesRenderer.prototype = new mExplorer.SelectionRenderer();
+		
+		/**
+		 * @name orion.sites.SitesRenderer
+		 * @class A renderer for a list of site configurations obtained from a site service.
+		 * @see orion.treetable.TableTree
+		 * @private
+		 */
+		function SitesRenderer(options, explorer) {
+			this._init(options);
+			this.options = options;
+			this.explorer = explorer;
+			this.registry = options.registry;
+		}
+		
+		SitesRenderer.prototype.getCellElement = function(col_no, item, tableRow){					
+			switch(col_no){
+				case 0:
+					var td = document.createElement("td"); //$NON-NLS-0$
+					var div = dojo.create( "div", {"class" : "sectionTableItem"}, td ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+					
+					var navGridHolder = this.explorer.getNavDict() ? this.explorer.getNavDict().getGridNavHolder(item, true) : null;
+					
+					// Site config column
+					var href = mSiteUtils.generateEditSiteHref(item);
+					var nameLink = dojo.create("a", {href: href}, div, "last"); //$NON-NLS-1$ //$NON-NLS-0$
+					dojo.place(document.createTextNode(item.Name), nameLink, "last"); //$NON-NLS-0$
+					mNavUtils.addNavGrid(this.explorer.getNavDict(), item, nameLink);
+					
+					var statusField = dojo.create("span", {"style" : "padding-left:10px; padding-right:10px"}, div, "last");
+					
+					// Status, URL columns
+					var status = item.HostingStatus;
+					if (typeof status === "object") { //$NON-NLS-0$
+						if (status.Status === "started") { //$NON-NLS-0$
+							dojo.place(document.createTextNode("(" + messages["Started"] + " "), statusField, "last"); //$NON-NLS-1$
+							
+							var link = dojo.create("a", null, statusField, "last"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+							dojo.place(document.createTextNode(status.URL), link, "last"); //$NON-NLS-0$
+							mNavUtils.addNavGrid(this.explorer.getNavDict(), item, link);
+							
+							dojo.place(document.createTextNode(")"), statusField, "last");
+							
+							var inlineAction = dojo.create("span", {"style" : "padding-left:10px;"}, statusField, "last");
+							this.registry.getService('orion.page.command').renderCommands("DefaultActionWrapper", inlineAction, item, this.explorer, "button", this.explorer.getRefreshHandler(), navGridHolder); //$NON-NLS-1$ //$NON-NLS-0$
+							
+							var statusString = "this site.";
+							dojo.place(document.createTextNode(statusString), statusField, "last"); //$NON-NLS-0$
+							
+							link.href = status.URL;
+						} else {
+							var statusString = "(" + status.Status.substring(0,1).toUpperCase() + status.Status.substring(1) + ")";
+							dojo.place(document.createTextNode(statusString), statusField, "last"); //$NON-NLS-0$
+							
+							var inlineAction = dojo.create("span", {"style" : "padding-left:10px"}, statusField, "last");
+							this.registry.getService('orion.page.command').renderCommands("DefaultActionWrapper", inlineAction, item, this.explorer, "button", this.explorer.getRefreshHandler(), navGridHolder); //$NON-NLS-1$ //$NON-NLS-0$
+							
+							dojo.place(document.createTextNode("this site"), statusField, "last"); //$NON-NLS-0$
+						}
+					} else {
+						dojo.place(document.createTextNode(messages["Unknown"]), statusField, "last"); //$NON-NLS-1$
+					}
+	
+					return td;
+				break;
+			}
+		};
+				
+		return SitesRenderer;
+	}());
+	
+	SiteTreeModel = (function() {
 		/**
 		 * @name orion.sites.SiteTreeModel
 		 * @class Tree model for powering a tree of site configurations.
 		 * @see orion.treetable.TableTree
 		 * @private
 		 */
-		function SiteTreeModel(siteService, id) {
-			this._siteService = siteService;
+		function SiteTreeModel(siteConfigurations, id) {
+			this._siteConfigurations = siteConfigurations;
 			this._root = {};
 			this._id = id;
 		}
@@ -102,16 +237,14 @@
 			getRoot: function(/**function*/ onItem) {
 				onItem(this._root);
 			},
+			
 			getChildren: function(/**dojo.data.Item*/ parentItem, /**Function(items)*/ onComplete) {
 				if (parentItem.children) {
 					// The parent already has the children fetched
 					onComplete(parentItem.children);
 				} else if (parentItem === this._root) {
-					this._siteService.getSiteConfigurations().then(
-						function(/**Array*/ siteConfigurations) {
-							parentItem.children = siteConfigurations;
-							onComplete(siteConfigurations);
-						});
+					parentItem.children = this._siteConfigurations;
+					onComplete(this._siteConfigurations);
 				} else {
 					return onComplete([]);
 				}
@@ -122,294 +255,6 @@
 		};
 		return SiteTreeModel;
 	}());
-	
-	var SitesRenderer = (function() {
-		/**
-		 * @name orion.sites.SitesRenderer
-		 * @class A renderer for a list of site configurations obtained from a site service.
-		 * @see orion.treetable.TableTree
-		 * @private
-		 */
-		function SitesRenderer(options) {
-			this._commandService = options.serviceRegistry.getService("orion.page.command"); //$NON-NLS-0$
-			this._options = options;
-		}
-		SitesRenderer.prototype = /** @lends orion.sites.SitesRenderer.prototype */{
-			initTable: function (tableNode, tableTree) {
-				dojo.addClass(tableNode, "treetable");
-			},
-			render: function(item, tableRow) {
-				dojo.addClass(tableRow, "treeTableRow sitesTableRow"); //$NON-NLS-0$
-				
-				var siteConfigCol = dojo.create("td", {id: tableRow.id + "col1"}); //$NON-NLS-1$ //$NON-NLS-0$
-				var actionCol = dojo.create("td", {id: tableRow.id + "col4"}); //$NON-NLS-1$ //$NON-NLS-0$
-				
-				// Site config column
-				var href = mSiteUtils.generateEditSiteHref(item);
-				var nameLink = dojo.create("a", {href: href}, siteConfigCol, "last"); //$NON-NLS-1$ //$NON-NLS-0$
-				dojo.place(document.createTextNode(item.Name), nameLink, "last"); //$NON-NLS-0$
-				
-				var statusField = dojo.create("span", {"style" : "padding-left:10px; padding-right:10px"}, siteConfigCol, "last");
-				
-				// Status, URL columns
-				var status = item.HostingStatus;
-				if (typeof status === "object") { //$NON-NLS-0$
-					if (status.Status === "started") { //$NON-NLS-0$
-						dojo.place(document.createTextNode(messages["Started"]), statusField, "last"); //$NON-NLS-1$
-						var link = dojo.create("a", null, siteConfigCol, "last"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-						dojo.place(document.createTextNode(status.URL), link, "last"); //$NON-NLS-0$
-						link.href = status.URL;
-					} else {
-						var statusString = status.Status.substring(0,1).toUpperCase() + status.Status.substring(1);
-						dojo.place(document.createTextNode(statusString), statusField, "last"); //$NON-NLS-0$
-					}
-				} else {
-					dojo.place(document.createTextNode(messages["Unknown"]), statusField, "last"); //$NON-NLS-1$
-				}
-				
-				// Action column
-				var actionsWrapper = dojo.create("span", {id: tableRow.id + "actionswrapper", "class":"sectionTableItemActions"}, actionCol, "only"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-				var options = this._options;
-				var userData = {
-					startCallback: options.startCallback,
-					stopCallback: options.stopCallback,
-					deleteCallback: options.deleteCallback,
-					errorCallback: function(err) {
-						options.serviceRegistry.getService('orion.page.message').setProgressResult(err); //$NON-NLS-0$
-					}
-				};
-				this._commandService.renderCommands(options.actionScopeId, actionsWrapper, item, null /*handler*/, "tool", userData); //$NON-NLS-0$
-				
-				dojo.place(siteConfigCol, tableRow, "last"); //$NON-NLS-0$
-				dojo.place(actionCol, tableRow, "last"); //$NON-NLS-0$
-			},
-			rowsChanged: function() {
-				dojo.query(".treeTableRow").forEach(function(node, i) { //$NON-NLS-0$
-					if (i % 2) {
-						dojo.addClass(node, "darkTreeTableRow"); //$NON-NLS-0$
-						dojo.removeClass(node, "lightTreeTableRow"); //$NON-NLS-0$
-					} else {
-						dojo.addClass(node, "lightTreeTableRow"); //$NON-NLS-0$
-						dojo.removeClass(node, "darkTreeTableRow"); //$NON-NLS-0$
-					}
-				});
-			},
-			labelColumnIndex: 0
-		};
-		return SitesRenderer;
-	}());
-	
-	var ViewOnSiteTreeModel = (function() {
-		function createModelItems(siteConfigurations, isRunningOns) {
-			function ViewOnSiteModelItem(siteConfig, isFileRunningOn) {
-				this.SiteConfiguration = siteConfig;
-				this.Id = "ViewOnSite" + siteConfig.Id; //$NON-NLS-0$
-				// Model keeps track of whether the file is available on this site configuration
-				this.IsFileRunningOn = isFileRunningOn;
-			}
-			var modelItems = [];
-			modelItems.push(
-				{	Id: "newsite", //$NON-NLS-0$
-					Placeholder: true
-				});
-			for (var i=0; i < siteConfigurations.length; i++) {
-				modelItems.push(new ViewOnSiteModelItem(siteConfigurations[i], isRunningOns[i]));
-			}
-			return modelItems;
-		}
-		/** @returns {Deferred} */
-		function isFileRunningOnSite(siteService, site, file) {
-			return siteService.isFileMapped(site, file).then(function(isFileMapped) {
-				var isStarted = site.HostingStatus && site.HostingStatus.Status === "started"; //$NON-NLS-0$
-				return site && file && isStarted && isFileMapped;
-			});
-		}
-		/**
-		 * @param {Object} file
-		 */
-		function ViewOnSiteTreeModel(siteService, id, file) {
-			SiteTreeModel.call(this, siteService, id);
-			this._file = file;
-		}
-		ViewOnSiteTreeModel.prototype = {
-			getRoot: SiteTreeModel.prototype.getRoot,
-			getId: SiteTreeModel.prototype.getId,
-			getChildren: function(parentItem, onComplete) {
-				if (parentItem.children) {
-					onComplete(parentItem.children);
-				} else if (parentItem === this._root) {
-					var self = this;
-					ViewOnSiteTreeModel.createViewOnSiteModelItems(self._siteService, self._file).then(function(modelItems) {
-						parentItem.children = modelItems;
-						onComplete(modelItems);
-					});
-				} else {
-					onComplete([]);
-				}
-			}
-		};
-		/** @returns {Deferred} */
-		ViewOnSiteTreeModel.createViewOnSiteModelItems = function(siteService, file) {
-			return siteService.getSiteConfigurations().then(function(siteConfigurations) {
-				return Deferred.all(siteConfigurations.map(function(site) {
-					return isFileRunningOnSite(siteService, site, file);
-				})).then(function(isRunningOns) {
-					return createModelItems(siteConfigurations, isRunningOns);
-				});
-			});
-		};
-		return ViewOnSiteTreeModel;
-	}());
-	
-	var ViewOnSiteRenderer = (function() {
-		/**
-		 * @param {Object} options.file
-		 * @param {Function} options.addToCallback
-		 * @param {Function} options.errorCallback
-		 */
-		function ViewOnSiteRenderer(options) {
-			SitesRenderer.apply(this, Array.prototype.slice.call(arguments));
-			this.serviceRegistry = options.serviceRegistry;
-			this.file = options.file;
-			this.addToCallback = options.addToCallback;
-			this.errorCallback = options.errorCallback;
-		}
-		ViewOnSiteRenderer.prototype = {
-			initTable: function (tableNode, tableTree) {
-				this.tableTree = tableTree;
-				dojo.addClass(tableNode, "treetable"); //$NON-NLS-0$
-				var thead = dojo.create("thead", null); //$NON-NLS-0$
-				dojo.create("th", {innerHTML: messages['Name']}, thead, "last"); //$NON-NLS-2$ //$NON-NLS-0$
-				dojo.create("th", {innerHTML: messages['Actions']}, thead, "last"); //$NON-NLS-2$ //$NON-NLS-0$
-				tableNode.appendChild(thead);
-			},
-			render: function(item, tableRow) {
-				var siteConfig = item.SiteConfiguration;
-				dojo.addClass(tableRow, "treeTableRow sitesTableRow"); //$NON-NLS-0$
-				if (item.Placeholder) {
-					dojo.addClass(tableRow, "newSiteRow"); //$NON-NLS-0$
-				}
-				var siteConfigCol = dojo.create("td", { //$NON-NLS-0$
-					id: tableRow.id + "col1", //$NON-NLS-0$
-					className: item.Placeholder ? "newSiteCol" : ""}); //$NON-NLS-0$ //$NON-NLS-1$
-				var actionCol = dojo.create("td", {id: tableRow.id + "col2"}); //$NON-NLS-1$ //$NON-NLS-0$
-				
-				// Site config column
-				var name = item.Placeholder ? messages["New Site"] : siteConfig.Name;
-				dojo.place(document.createTextNode(name), siteConfigCol, "last"); //$NON-NLS-0$
 
-				// Action column
-				var actionsWrapper = dojo.create("span", {id: tableRow.id + "actionswrapper"}, actionCol, "only"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-
-				var userData = {
-					file: this.file,
-					addToCallback: this.addToCallback,
-					errorCallback: this.errorCallback
-				};
-				this._commandService.renderCommands("viewOnSiteScope", actionsWrapper, item,  null /*handler*/, "button", userData); //$NON-NLS-1$ //$NON-NLS-0$
-
-				dojo.place(siteConfigCol, tableRow, "last"); //$NON-NLS-0$
-				dojo.place(actionCol, tableRow, "last"); //$NON-NLS-0$
-			},
-			rowsChanged: SitesRenderer.prototype.rowsChanged,
-			labelColumnIndex: 0
-		};
-		return ViewOnSiteRenderer;
-	}());
-
-	/**
-	 * @param {orion.sites.SiteService} options.siteService
-	 * @param {String} options.id
-	 * @param {DomNode} options.parent
-	 * @param {orion.sites.SiteTreeModel} [options.model]
-	 * @param {orion.sites.SitesRenderer} [options.renderer]
-	 * @class
-	 * @private
-	 */
-	SitesTree = (function() {
-		function SitesTree(options) {
-			this.siteService = options.siteService;
-			var model = this.model = options.model || new SiteTreeModel(this.siteService, options.id);
-			this.treeWidget = new TableTree({
-				id: options.id,
-				parent: options.parent,
-				model: model,
-				showRoot: false,
-				renderer: options.renderer || new SitesRenderer(options)
-			});
-		}
-		SitesTree.prototype = {
-			refresh: function() {
-				var self = this;
-				this.siteService.getSiteConfigurations().then(function(siteConfigs) {
-					self.treeWidget.refresh(self.model._id, siteConfigs, true);
-				});
-			}
-		};
-		return SitesTree;
-	}());
-
-	/**
-	 * @name orion.sites.ViewOnSiteTree
-	 * @class A tree widget that displays a list of sites that a file can be viewed on.
-	 * @param {orion.serviceregistry.ServiceRegistry} options.serviceRegistry
-	 * @param {String} options.fileLocation
-	 *
-	 * @param {String} options.id
-	 * @param {DomNode} options.parent
-	 * @param {orion.sites.SiteTreeModel} [options.model]
-	 * @param {orion.sites.SitesRenderer} [options.renderer]
-	 */
-	ViewOnSiteTree = /** @ignore */ (function() {
-		function ViewOnSiteTree(options) {
-			var serviceRegistry = options.serviceRegistry;
-			var commandService = serviceRegistry.getService("orion.page.command"); //$NON-NLS-0$
-			var siteService = mSiteClient.forFileLocation(serviceRegistry, options.fileLocation);
-			var self = this;
-			serviceRegistry.getService("orion.core.file").read(options.fileLocation, true).then(function(file) { //$NON-NLS-0$
-				options.siteService = siteService;
-				options.model = new ViewOnSiteTreeModel(siteService, options.id, file);
-				options.file = self.file = file;
-
-				// TODO should this be done by glue code?
-				commandService.registerCommandContribution("viewOnSiteScope", "orion.site.add-to", 10); //$NON-NLS-1$ //$NON-NLS-0$
-				commandService.registerCommandContribution("viewOnSiteScope", "orion.site.view-on-link", 20); //$NON-NLS-1$ //$NON-NLS-0$
-
-				mGlobalCommands.setPageTarget({
-						task: messages.ViewOnSiteTitle,
-						target: file,
-						serviceRegistry: serviceRegistry,
-						commandService: commandService});
-
-				options.addToCallback = function() {
-					self.refresh();
-				};
-				options.errorCallback = function(err) {
-					options.serviceRegistry.getService('orion.page.message').setErrorMessage(err); //$NON-NLS-0$
-				};
-
-				options.renderer = new ViewOnSiteRenderer(options);
-				if (options.label) {
-					dojo.byId(options.label).innerHTML = formatMessage(messages.ViewOnSiteCaption, file.Name);
-				}
-				SitesTree.call(self, options);
-			});
-		}
-		ViewOnSiteTree.prototype = /** @lends orion.sites.ViewOnSiteTree.prototype */ {
-			refresh: function() {
-				// TODO call helper for this
-				var self = this;
-				ViewOnSiteTreeModel.createViewOnSiteModelItems(self.siteService, self.file).then(
-					function(modelItems) {
-						self.treeWidget.refresh(self.model._id, modelItems, true);
-					});
-			}
-		};
-		return ViewOnSiteTree;
-	}());
-
-	return {
-		SiteServicesExplorer: SiteServicesExplorer,
-		ViewOnSiteTree: ViewOnSiteTree
-	};
+	return SiteServicesExplorer;
 });
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/sites/sitesExplorer2.js b/bundles/org.eclipse.orion.client.core/web/orion/sites/sitesExplorer2.js
deleted file mode 100644
index 6366705..0000000
--- a/bundles/org.eclipse.orion.client.core/web/orion/sites/sitesExplorer2.js
+++ /dev/null
@@ -1,262 +0,0 @@
-/*******************************************************************************
- * @license
- * Copyright (c) 2012 IBM Corporation and others.
- * All rights reserved. This program and the accompanying materials are made
- * available under the terms of the Eclipse Public License v1.0
- * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
- * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
- *
- * Contributors: IBM Corporation - initial API and implementation
- ******************************************************************************/
-/*global define document*/
-define(['i18n!orion/sites/nls/messages', 'orion/i18nUtil', 'dojo', 'orion/explorers/explorer', 'orion/Deferred', 'orion/commands', 'orion/globalCommands',
-		'orion/selection', 'orion/sites/siteUtils', 'orion/explorers/navigationUtils', 'orion/sites/siteClient', 'orion/sites/siteCommands', 'orion/treetable'],
-		function(messages, i18nUtil, dojo, mExplorer, Deferred, mCommands, mGlobalCommands, mSelection, mSiteUtils, mNavUtils, mSiteClient, mSiteCommands, treetable) {
-	var SiteServicesExplorer2, SitesRenderer2, SiteTreeModel;
-
-	/** 
-	 * Generates an explorer showing the sites on each site service.
-	 * 
-	 * @param {orion.serviceregistry.ServiceRegistry} options.serviceRegistry
-	 * @param registry [required] service registry
-	 * @param selection [required] selection service
-	 * @param parentId [required] parent node id
-	 * @returns SiteServicesExplorer2 object
-	 */
-	SiteServicesExplorer2 = (function() {
-		
-		function SiteServicesExplorer2(registry, selection, parentId) {
-			this.registry = registry;
-			this.checkbox = false;
-			this.parentId = parentId;
-			this.selection = selection;
-			
-			this.pageActionsWrapperId = "pageActions";
-			this.selectionActionsWrapperId = "selectionTools";
-			this.defaultActionWrapperId = "DefaultActionWrapper";
-		}
-		
-		SiteServicesExplorer2.prototype = new mExplorer.Explorer();
-		
-		SiteServicesExplorer2.prototype._updatePageActions = function(registry, item){
-			var toolbar = dojo.byId(this.pageActionsWrapperId);
-			var commandService = registry.getService("orion.page.command");  //$NON-NLS-0$
-			if (toolbar) {
-				commandService.destroy(toolbar);
-			} else {
-				throw "could not find toolbar " + this.pageActionsWrapperId; //$NON-NLS-0$
-			}
-			commandService.renderCommands(this.pageActionsWrapperId, toolbar, item, this, "button", this.getRefreshHandler());  //$NON-NLS-0$
-		};
-		
-		SiteServicesExplorer2.prototype._getSiteConfigurations = function(siteServices, result, deferred){
-			var that = this;
-			
-			if (!deferred)
-				deferred = new dojo.Deferred();
-			
-			if (!result)
-				result = [];
-			
-			if (siteServices.length > 0) {
-				siteServices[0].getSiteConfigurations().then(
-					function(/**Array*/ siteConfigurations) {
-						result.push.apply(result, siteConfigurations);
-						that._getSiteConfigurations(siteServices.slice(1), result, deferred);
-					}
-				);					
-			} else {
-				deferred.callback(result);
-			}
-			
-			return deferred;
-		};
-		
-		SiteServicesExplorer2.prototype.display = function(){
-			var that = this;
-			
-			var progressService = this.registry.getService("orion.page.message"); //$NON-NLS-0$
-			var loadingDeferred = new dojo.Deferred();
-			progressService.showWhile(loadingDeferred, messages['Loading...']);
-			
-			var siteServiceRefs = this.registry.getServiceReferences('orion.site'); //$NON-NLS-0$
-
-			this.siteClients = [];
-			for (var i=0; i < siteServiceRefs.length; i++) {
-				var siteServiceRef = siteServiceRefs[i];
-				var siteService = this.registry.getService(siteServiceRef);
-				this.siteClients.push(new mSiteClient.SiteClient(this.registry, siteService, siteServiceRef));
-			}
-
-			this._getSiteConfigurations(this.siteClients).then(
-				function(siteConfigurations){
-					that.renderer = new SitesRenderer2({registry: that.registry, actionScopeId: "sdsd", cachePrefix: "SitesExplorer", checkbox: false}, that); //$NON-NLS-0$
-
-					var commandService = that.registry.getService('orion.page.command'); //$NON-NLS-0$
-					
-					commandService.registerCommandContribution(that.pageActionsWrapperId, 'orion.site.create', 100); //$NON-NLS-0$
-					
-					commandService.registerCommandContribution(that.selectionActionsWrapperId, 'orion.site.start', 20); //$NON-NLS-0$
-					commandService.registerCommandContribution(that.selectionActionsWrapperId, 'orion.site.stop', 30); //$NON-NLS-0$
-					commandService.registerCommandContribution(that.selectionActionsWrapperId, 'orion.site.delete', 40); //$NON-NLS-0$
-					
-					commandService.registerCommandContribution(that.defaultActionWrapperId, 'orion.site.start', 20); //$NON-NLS-0$
-					commandService.registerCommandContribution(that.defaultActionWrapperId, 'orion.site.stop', 30); //$NON-NLS-0$
-					
-					that.createTree(that.parentId, new SiteTreeModel(siteConfigurations), {setFocus: true});
-					
-					// TODO should show Create per each site service
-					that._updatePageActions(that.registry, siteServiceRefs[0]); //$NON-NLS-1$ //$NON-NLS-0$
-					
-					if (!that.doOnce){
-						that.registry.getService("orion.page.selection").addEventListener("selectionChanged", function(event) { //$NON-NLS-1$ //$NON-NLS-0$
-							var selectionTools = dojo.byId(that.selectionActionsWrapperId);
-							if (selectionTools) {
-								commandService.destroy(selectionTools);						
-								commandService.renderCommands(that.selectionActionsWrapperId, selectionTools, event.selections, that, "button", that.getRefreshHandler()); //$NON-NLS-1$ //$NON-NLS-0$
-							}
-						});
-						
-						that.doOnce = true;
-					}
-					
-					loadingDeferred.callback();
-					progressService.setProgressMessage("");
-				}
-			);
-		};
-		
-		SiteServicesExplorer2.prototype.getRefreshHandler = function(){
-			return {
-				startCallback: dojo.hitch(this, this.refresh),
-				stopCallback: dojo.hitch(this, this.refresh),
-				deleteCallback: dojo.hitch(this, this.refresh),
-				errorCallback: dojo.hitch(this, this.refresh)
-			};
-		};
-		
-		SiteServicesExplorer2.prototype.refresh = function(){
-			var that = this;
-			
-			this._getSiteConfigurations(this.siteClients).then(
-				function(siteConfigurations){
-					that.createTree(that.parentId, new SiteTreeModel(siteConfigurations), {setFocus: true});
-				}
-			);
-		};
-		
-		return SiteServicesExplorer2;
-	}());
-	
-	SitesRenderer2 = (function() {
-		
-		SitesRenderer2.prototype = new mExplorer.SelectionRenderer();
-		
-		/**
-		 * @name orion.sites.SitesRenderer
-		 * @class A renderer for a list of site configurations obtained from a site service.
-		 * @see orion.treetable.TableTree
-		 * @private
-		 */
-		function SitesRenderer2(options, explorer) {
-			this._init(options);
-			this.options = options;
-			this.explorer = explorer;
-			this.registry = options.registry;
-		}
-		
-		SitesRenderer2.prototype.getCellElement = function(col_no, item, tableRow){					
-			switch(col_no){
-				case 0:
-					var td = document.createElement("td"); //$NON-NLS-0$
-					var div = dojo.create( "div", {"class" : "sectionTableItem"}, td ); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-					
-					var navGridHolder = this.explorer.getNavDict() ? this.explorer.getNavDict().getGridNavHolder(item, true) : null;
-					
-					// Site config column
-					var href = mSiteUtils.generateEditSiteHref(item);
-					var nameLink = dojo.create("a", {href: href}, div, "last"); //$NON-NLS-1$ //$NON-NLS-0$
-					dojo.place(document.createTextNode(item.Name), nameLink, "last"); //$NON-NLS-0$
-					mNavUtils.addNavGrid(this.explorer.getNavDict(), item, nameLink);
-					
-					var statusField = dojo.create("span", {"style" : "padding-left:10px; padding-right:10px"}, div, "last");
-					
-					// Status, URL columns
-					var status = item.HostingStatus;
-					if (typeof status === "object") { //$NON-NLS-0$
-						if (status.Status === "started") { //$NON-NLS-0$
-							dojo.place(document.createTextNode("(" + messages["Started"] + " "), statusField, "last"); //$NON-NLS-1$
-							
-							var link = dojo.create("a", null, statusField, "last"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
-							dojo.place(document.createTextNode(status.URL), link, "last"); //$NON-NLS-0$
-							mNavUtils.addNavGrid(this.explorer.getNavDict(), item, link);
-							
-							dojo.place(document.createTextNode(")"), statusField, "last");
-							
-							var inlineAction = dojo.create("span", {"style" : "padding-left:10px;"}, statusField, "last");
-							this.registry.getService('orion.page.command').renderCommands("DefaultActionWrapper", inlineAction, item, this.explorer, "button", this.explorer.getRefreshHandler(), navGridHolder); //$NON-NLS-1$ //$NON-NLS-0$
-							
-							var statusString = "this site.";
-							dojo.place(document.createTextNode(statusString), statusField, "last"); //$NON-NLS-0$
-							
-							link.href = status.URL;
-						} else {
-							var statusString = "(" + status.Status.substring(0,1).toUpperCase() + status.Status.substring(1) + ")";
-							dojo.place(document.createTextNode(statusString), statusField, "last"); //$NON-NLS-0$
-							
-							var inlineAction = dojo.create("span", {"style" : "padding-left:10px"}, statusField, "last");
-							this.registry.getService('orion.page.command').renderCommands("DefaultActionWrapper", inlineAction, item, this.explorer, "button", this.explorer.getRefreshHandler(), navGridHolder); //$NON-NLS-1$ //$NON-NLS-0$
-							
-							dojo.place(document.createTextNode("this site"), statusField, "last"); //$NON-NLS-0$
-						}
-					} else {
-						dojo.place(document.createTextNode(messages["Unknown"]), statusField, "last"); //$NON-NLS-1$
-					}
-	
-					return td;
-				break;
-			}
-		};
-				
-		return SitesRenderer2;
-	}());
-	
-	SiteTreeModel = (function() {
-		/**
-		 * @name orion.sites.SiteTreeModel
-		 * @class Tree model for powering a tree of site configurations.
-		 * @see orion.treetable.TableTree
-		 * @private
-		 */
-		function SiteTreeModel(siteConfigurations, id) {
-			this._siteConfigurations = siteConfigurations;
-			this._root = {};
-			this._id = id;
-		}
-		SiteTreeModel.prototype = /** @lends orion.sites.SiteTreeModel.prototype */{
-			getRoot: function(/**function*/ onItem) {
-				onItem(this._root);
-			},
-			
-			getChildren: function(/**dojo.data.Item*/ parentItem, /**Function(items)*/ onComplete) {
-				if (parentItem.children) {
-					// The parent already has the children fetched
-					onComplete(parentItem.children);
-				} else if (parentItem === this._root) {
-					parentItem.children = this._siteConfigurations;
-					onComplete(this._siteConfigurations);
-				} else {
-					return onComplete([]);
-				}
-			},
-			getId: function(/**dojo.data.Item|String*/ item) {
-				return (item === this._root || item === this._id) ? this._id : item.Id;
-			}
-		};
-		return SiteTreeModel;
-	}());
-
-	return {
-		SiteServicesExplorer2: SiteServicesExplorer2
-	};
-});
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/sites/viewOnSiteTree.js b/bundles/org.eclipse.orion.client.core/web/orion/sites/viewOnSiteTree.js
new file mode 100644
index 0000000..4ca973d
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.core/web/orion/sites/viewOnSiteTree.js
@@ -0,0 +1,320 @@
+/*******************************************************************************
+ * @license
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License v1.0
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
+ *
+ * Contributors: IBM Corporation - initial API and implementation
+ ******************************************************************************/
+/*global define document*/
+/*jslint sub:true*/
+define(['i18n!orion/sites/nls/messages', 'orion/i18nUtil', 'dojo', 'orion/Deferred', 'orion/commands', 'orion/globalCommands',
+		'orion/selection', 'orion/sites/siteUtils', 'orion/sites/siteClient', 'orion/sites/siteCommands', 'orion/treetable'],
+		function(messages, i18nUtil, dojo, Deferred, mCommands, mGlobalCommands, mSelection, mSiteUtils, mSiteClient, mSiteCommands, treetable) {
+	var formatMessage = i18nUtil.formatMessage;
+	var TableTree = treetable.TableTree;
+	var ViewOnSiteTree;
+
+	var SiteTreeModel = (function() {
+		/**
+		 * @name orion.sites.SiteTreeModel
+		 * @class Tree model for powering a tree of site configurations.
+		 * @see orion.treetable.TableTree
+		 * @private
+		 */
+		function SiteTreeModel(siteService, id) {
+			this._siteService = siteService;
+			this._root = {};
+			this._id = id;
+		}
+		SiteTreeModel.prototype = /** @lends orion.sites.SiteTreeModel.prototype */{
+			getRoot: function(/**function*/ onItem) {
+				onItem(this._root);
+			},
+			getChildren: function(/**dojo.data.Item*/ parentItem, /**Function(items)*/ onComplete) {
+				if (parentItem.children) {
+					// The parent already has the children fetched
+					onComplete(parentItem.children);
+				} else if (parentItem === this._root) {
+					this._siteService.getSiteConfigurations().then(
+						function(/**Array*/ siteConfigurations) {
+							parentItem.children = siteConfigurations;
+							onComplete(siteConfigurations);
+						});
+				} else {
+					return onComplete([]);
+				}
+			},
+			getId: function(/**dojo.data.Item|String*/ item) {
+				return (item === this._root || item === this._id) ? this._id : item.Id;
+			}
+		};
+		return SiteTreeModel;
+	}());
+	
+	var SitesRenderer = (function() {
+		/**
+		 * @name orion.sites.SitesRenderer
+		 * @class A renderer for a list of site configurations obtained from a site service.
+		 * @see orion.treetable.TableTree
+		 * @private
+		 */
+		function SitesRenderer(options) {
+			this._commandService = options.serviceRegistry.getService("orion.page.command"); //$NON-NLS-0$
+			this._options = options;
+		}
+		SitesRenderer.prototype = /** @lends orion.sites.SitesRenderer.prototype */{
+			initTable: function (tableNode, tableTree) {
+				dojo.addClass(tableNode, "treetable");
+			},
+			render: function(item, tableRow) {
+				dojo.addClass(tableRow, "treeTableRow sitesTableRow"); //$NON-NLS-0$
+				
+				var siteConfigCol = dojo.create("td", {id: tableRow.id + "col1"}); //$NON-NLS-1$ //$NON-NLS-0$
+				var actionCol = dojo.create("td", {id: tableRow.id + "col4"}); //$NON-NLS-1$ //$NON-NLS-0$
+				
+				// Site config column
+				var href = mSiteUtils.generateEditSiteHref(item);
+				var nameLink = dojo.create("a", {href: href}, siteConfigCol, "last"); //$NON-NLS-1$ //$NON-NLS-0$
+				dojo.place(document.createTextNode(item.Name), nameLink, "last"); //$NON-NLS-0$
+				
+				var statusField = dojo.create("span", {"style" : "padding-left:10px; padding-right:10px"}, siteConfigCol, "last");
+				
+				// Status, URL columns
+				var status = item.HostingStatus;
+				if (typeof status === "object") { //$NON-NLS-0$
+					if (status.Status === "started") { //$NON-NLS-0$
+						dojo.place(document.createTextNode(messages["Started"]), statusField, "last"); //$NON-NLS-1$
+						var link = dojo.create("a", null, siteConfigCol, "last"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+						dojo.place(document.createTextNode(status.URL), link, "last"); //$NON-NLS-0$
+						link.href = status.URL;
+					} else {
+						var statusString = status.Status.substring(0,1).toUpperCase() + status.Status.substring(1);
+						dojo.place(document.createTextNode(statusString), statusField, "last"); //$NON-NLS-0$
+					}
+				} else {
+					dojo.place(document.createTextNode(messages["Unknown"]), statusField, "last"); //$NON-NLS-1$
+				}
+				
+				// Action column
+				var actionsWrapper = dojo.create("span", {id: tableRow.id + "actionswrapper", "class":"sectionTableItemActions"}, actionCol, "only"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+				var options = this._options;
+				var userData = {
+					startCallback: options.startCallback,
+					stopCallback: options.stopCallback,
+					deleteCallback: options.deleteCallback,
+					errorCallback: function(err) {
+						options.serviceRegistry.getService('orion.page.message').setProgressResult(err); //$NON-NLS-0$
+					}
+				};
+				this._commandService.renderCommands(options.actionScopeId, actionsWrapper, item, null /*handler*/, "tool", userData); //$NON-NLS-0$
+				
+				dojo.place(siteConfigCol, tableRow, "last"); //$NON-NLS-0$
+				dojo.place(actionCol, tableRow, "last"); //$NON-NLS-0$
+			},
+			rowsChanged: function() {
+				dojo.query(".treeTableRow").forEach(function(node, i) { //$NON-NLS-0$
+					if (i % 2) {
+						dojo.addClass(node, "darkTreeTableRow"); //$NON-NLS-0$
+						dojo.removeClass(node, "lightTreeTableRow"); //$NON-NLS-0$
+					} else {
+						dojo.addClass(node, "lightTreeTableRow"); //$NON-NLS-0$
+						dojo.removeClass(node, "darkTreeTableRow"); //$NON-NLS-0$
+					}
+				});
+			},
+			labelColumnIndex: 0
+		};
+		return SitesRenderer;
+	}());
+	
+	var ViewOnSiteTreeModel = (function() {
+		function createModelItems(siteConfigurations, isRunningOns) {
+			function ViewOnSiteModelItem(siteConfig, isFileRunningOn) {
+				this.SiteConfiguration = siteConfig;
+				this.Id = "ViewOnSite" + siteConfig.Id; //$NON-NLS-0$
+				// Model keeps track of whether the file is available on this site configuration
+				this.IsFileRunningOn = isFileRunningOn;
+			}
+			var modelItems = [];
+			modelItems.push(
+				{	Id: "newsite", //$NON-NLS-0$
+					Placeholder: true
+				});
+			for (var i=0; i < siteConfigurations.length; i++) {
+				modelItems.push(new ViewOnSiteModelItem(siteConfigurations[i], isRunningOns[i]));
+			}
+			return modelItems;
+		}
+		/** @returns {Deferred} */
+		function isFileRunningOnSite(siteService, site, file) {
+			return siteService.isFileMapped(site, file).then(function(isFileMapped) {
+				var isStarted = site.HostingStatus && site.HostingStatus.Status === "started"; //$NON-NLS-0$
+				return site && file && isStarted && isFileMapped;
+			});
+		}
+		/**
+		 * @param {Object} file
+		 */
+		function ViewOnSiteTreeModel(siteService, id, file) {
+			SiteTreeModel.call(this, siteService, id);
+			this._file = file;
+		}
+		ViewOnSiteTreeModel.prototype = {
+			getRoot: SiteTreeModel.prototype.getRoot,
+			getId: SiteTreeModel.prototype.getId,
+			getChildren: function(parentItem, onComplete) {
+				if (parentItem.children) {
+					onComplete(parentItem.children);
+				} else if (parentItem === this._root) {
+					var self = this;
+					ViewOnSiteTreeModel.createViewOnSiteModelItems(self._siteService, self._file).then(function(modelItems) {
+						parentItem.children = modelItems;
+						onComplete(modelItems);
+					});
+				} else {
+					onComplete([]);
+				}
+			}
+		};
+		/** @returns {Deferred} */
+		ViewOnSiteTreeModel.createViewOnSiteModelItems = function(siteService, file) {
+			return siteService.getSiteConfigurations().then(function(siteConfigurations) {
+				return Deferred.all(siteConfigurations.map(function(site) {
+					return isFileRunningOnSite(siteService, site, file);
+				})).then(function(isRunningOns) {
+					return createModelItems(siteConfigurations, isRunningOns);
+				});
+			});
+		};
+		return ViewOnSiteTreeModel;
+	}());
+	
+	var ViewOnSiteRenderer = (function() {
+		/**
+		 * @param {Object} options.file
+		 * @param {Function} options.addToCallback
+		 * @param {Function} options.errorCallback
+		 */
+		function ViewOnSiteRenderer(options) {
+			SitesRenderer.apply(this, Array.prototype.slice.call(arguments));
+			this.serviceRegistry = options.serviceRegistry;
+			this.file = options.file;
+			this.addToCallback = options.addToCallback;
+			this.errorCallback = options.errorCallback;
+		}
+		ViewOnSiteRenderer.prototype = {
+			initTable: function (tableNode, tableTree) {
+				this.tableTree = tableTree;
+				dojo.addClass(tableNode, "treetable"); //$NON-NLS-0$
+				var thead = dojo.create("thead", null); //$NON-NLS-0$
+				dojo.create("th", {innerHTML: messages['Name']}, thead, "last"); //$NON-NLS-2$ //$NON-NLS-0$
+				dojo.create("th", {innerHTML: messages['Actions']}, thead, "last"); //$NON-NLS-2$ //$NON-NLS-0$
+				tableNode.appendChild(thead);
+			},
+			render: function(item, tableRow) {
+				var siteConfig = item.SiteConfiguration;
+				dojo.addClass(tableRow, "treeTableRow sitesTableRow"); //$NON-NLS-0$
+				if (item.Placeholder) {
+					dojo.addClass(tableRow, "newSiteRow"); //$NON-NLS-0$
+				}
+				var siteConfigCol = dojo.create("td", { //$NON-NLS-0$
+					id: tableRow.id + "col1", //$NON-NLS-0$
+					className: item.Placeholder ? "newSiteCol" : ""}); //$NON-NLS-0$ //$NON-NLS-1$
+				var actionCol = dojo.create("td", {id: tableRow.id + "col2"}); //$NON-NLS-1$ //$NON-NLS-0$
+				
+				// Site config column
+				var name = item.Placeholder ? messages["New Site"] : siteConfig.Name;
+				dojo.place(document.createTextNode(name), siteConfigCol, "last"); //$NON-NLS-0$
+
+				// Action column
+				var actionsWrapper = dojo.create("span", {id: tableRow.id + "actionswrapper"}, actionCol, "only"); //$NON-NLS-2$ //$NON-NLS-1$ //$NON-NLS-0$
+
+				var userData = {
+					file: this.file,
+					addToCallback: this.addToCallback,
+					errorCallback: this.errorCallback
+				};
+				this._commandService.renderCommands("viewOnSiteScope", actionsWrapper, item,  null /*handler*/, "button", userData); //$NON-NLS-1$ //$NON-NLS-0$
+
+				dojo.place(siteConfigCol, tableRow, "last"); //$NON-NLS-0$
+				dojo.place(actionCol, tableRow, "last"); //$NON-NLS-0$
+			},
+			rowsChanged: SitesRenderer.prototype.rowsChanged,
+			labelColumnIndex: 0
+		};
+		return ViewOnSiteRenderer;
+	}());
+
+	/**
+	 * @name orion.sites.ViewOnSiteTree
+	 * @class A tree widget that displays a list of sites that a file can be viewed on.
+	 * @param {orion.serviceregistry.ServiceRegistry} options.serviceRegistry
+	 * @param {String} options.fileLocation
+	 *
+	 * @param {String} options.id
+	 * @param {DomNode} options.parent
+	 * @param {orion.sites.SiteTreeModel} [options.model]
+	 * @param {orion.sites.SitesRenderer} [options.renderer]
+	 */
+	ViewOnSiteTree = /** @ignore */ (function() {
+		function ViewOnSiteTree(options) {
+			var serviceRegistry = options.serviceRegistry;
+			var commandService = serviceRegistry.getService("orion.page.command"); //$NON-NLS-0$
+			var siteService = this.siteService = mSiteClient.forFileLocation(serviceRegistry, options.fileLocation);
+			var self = this;
+			serviceRegistry.getService("orion.core.file").read(options.fileLocation, true).then(function(file) { //$NON-NLS-0$
+				options.siteService = siteService;
+				options.model = new ViewOnSiteTreeModel(siteService, options.id, file);
+				options.file = self.file = file;
+
+				// TODO should this be done by glue code?
+				commandService.registerCommandContribution("viewOnSiteScope", "orion.site.add-to", 10); //$NON-NLS-1$ //$NON-NLS-0$
+				commandService.registerCommandContribution("viewOnSiteScope", "orion.site.view-on-link", 20); //$NON-NLS-1$ //$NON-NLS-0$
+
+				mGlobalCommands.setPageTarget({
+						task: messages.ViewOnSiteTitle,
+						target: file,
+						serviceRegistry: serviceRegistry,
+						commandService: commandService});
+
+				options.addToCallback = function() {
+					self.refresh();
+				};
+				options.errorCallback = function(err) {
+					options.serviceRegistry.getService('orion.page.message').setErrorMessage(err); //$NON-NLS-0$
+				};
+
+				options.renderer = new ViewOnSiteRenderer(options);
+				if (options.label) {
+					dojo.byId(options.label).innerHTML = formatMessage(messages.ViewOnSiteCaption, file.Name);
+				}
+
+				// Create tree widget
+				var model = this.model = options.model || new SiteTreeModel(siteService, options.id);
+				this.treeWidget = new TableTree({
+					id: options.id,
+					parent: options.parent,
+					model: model,
+					showRoot: false,
+					renderer: options.renderer || new SitesRenderer(options)
+				});
+			});
+		}
+		ViewOnSiteTree.prototype = /** @lends orion.sites.ViewOnSiteTree.prototype */ {
+			refresh: function() {
+				// TODO call helper for this
+				var self = this;
+				ViewOnSiteTreeModel.createViewOnSiteModelItems(self.siteService, self.file).then(
+					function(modelItems) {
+						self.treeWidget.refresh(self.model._id, modelItems, true);
+					});
+			}
+		};
+		return ViewOnSiteTree;
+	}());
+
+	return ViewOnSiteTree;
+});
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SettingsContainer.js b/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SettingsContainer.js
index cec43e7..7898c7c 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SettingsContainer.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SettingsContainer.js
@@ -9,7 +9,7 @@
  * Contributors: Anton McConville - IBM Corporation - initial API and implementation

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

 /*global dojo dijit widgets orion  window console define localStorage*/

-/*jslint browser:true*/

+/*jslint browser:true sub:true*/

 

 /* This SettingsContainer widget is a dojo border container with a left and right side. The left is for choosing a 

    category, the right shows the resulting HTML for that category. */

@@ -23,7 +23,41 @@
 	dojo.declare("orion.widgets.settings.SettingsContainer", [orion.widgets.settings.SplitSelectionLayout], { //$NON-NLS-0$

 

 		constructor: function() {		

-			

+			this.settingsCategories = [

+				{

+					id: "userSettings", //$NON-NLS-0$

+					textContent: messages["User Profile"],

+					show: this.showUserSettings

+				},

+				{

+					id: "themeBuilder", //$NON-NLS-0$

+					textContent: 'UI Theme', // messages["Themes"],

+					show: this.showThemeBuilder

+				},

+				{

+					id: "editorThemeBuilder", //$NON-NLS-0$

+					textContent: 'Editor Theme', // messages["Themes"],

+					show: this.showEditorThemeBuilder

+				},

+				{

+					id: "plugins", //$NON-NLS-0$

+					textContent: messages["Plugins"],

+					show: this.showPlugins

+				}];

+			this.settingsCategories.forEach(function(item) {

+				item.show = item.show.bind(this, item.id);

+			}.bind(this));

+		},

+

+		postMixInProperties: function() {

+			// Add extension categories

+			this.settingsRegistry.getCategories().sort().forEach(function(category, i) {

+				this.settingsCategories.push({

+					id: category,

+					textContent: messages[category] || category,

+					show: this.showPluginSettings.bind(this, category)

+				});

+			}.bind(this));

 		},

 

 		postCreate: function() {

@@ -50,7 +84,7 @@
 				var selection = prefs.get( 'selection' );

 				

 				var category = pageParams.category || selection; //$NON-NLS-0$

-				container.showById(category);

+				container.showByCategory(category);

 				

 			} );

 			

@@ -106,79 +140,6 @@
 			}

 		},

 

-		addPlugins: function() {

-

-			var item = {

-				id: "plugins", //$NON-NLS-0$

-				innerHTML: messages["Plugins"],

-				"class": 'navbar-item', //$NON-NLS-1$ //$NON-NLS-0$

-				role: "tab", //$NON-NLS-0$

-				tabindex: -1,

-				"aria-selected": "false", //$NON-NLS-1$ //$NON-NLS-0$

-				onclick: dojo.hitch( this, 'showPlugins', "plugins" ) //$NON-NLS-1$ //$NON-NLS-0$

-			};

-

-			this.addCategory(item, this.initialSettings.length);

-		},

-		

-		addUserSettings: function() {

-

-			var item = {

-				id: "userSettings", //$NON-NLS-0$

-				innerHTML: messages["User Profile"],

-				"class": 'navbar-item', //$NON-NLS-1$ //$NON-NLS-0$

-				role: "tab", //$NON-NLS-0$

-				tabindex: -1,

-				"aria-selected": "false", //$NON-NLS-1$ //$NON-NLS-0$

-				onclick: dojo.hitch( this, 'showUserSettings', "userSettings" ) //$NON-NLS-1$ //$NON-NLS-0$

-			};

-

-			this.addCategory(item, this.initialSettings.length);

-		},

-		

-		addThemeBuilder: function() {

-

-			var item = {

-				id: "themeBuilder", //$NON-NLS-0$

-				innerHTML: 'UI Theme', // messages["Themes"],

-				"class": 'navbar-item', //$NON-NLS-1$ //$NON-NLS-0$

-				role: "tab", //$NON-NLS-0$

-				tabindex: -1,

-				"aria-selected": "false", //$NON-NLS-1$ //$NON-NLS-0$

-				onclick: dojo.hitch( this, 'showThemeBuilder', "themeBuilder" ) //$NON-NLS-1$ //$NON-NLS-0$

-			};

-

-			this.addCategory(item, this.initialSettings.length);

-		},

-		

-		addEditorThemeBuilder: function() {

-

-			var item = {

-				id: "editorThemeBuilder", //$NON-NLS-0$

-				innerHTML: 'Editor Theme', // messages["Themes"],

-				"class": 'navbar-item', //$NON-NLS-1$ //$NON-NLS-0$

-				role: "tab", //$NON-NLS-0$

-				tabindex: -1,

-				"aria-selected": "false", //$NON-NLS-1$ //$NON-NLS-0$

-				onclick: dojo.hitch( this, 'showEditorThemeBuilder', "editorThemeBuilder" ) //$NON-NLS-1$ //$NON-NLS-0$

-			};

-

-			this.addCategory(item, this.initialSettings.length);

-		},

-

-		addPluginSettings: function() {

-			var item = {

-				id: "pluginSettings", //$NON-NLS-0$

-				innerHTML: messages.PluginSettings,

-				"class": 'navbar-item', //$NON-NLS-1$ //$NON-NLS-0$

-				role: "tab", //$NON-NLS-0$

-				tabindex: -1,

-				"aria-selected": "false", //$NON-NLS-1$ //$NON-NLS-0$

-				onclick: this.showPluginSettings.bind(this, "pluginSettings") //$NON-NLS-0$

-			};

-			this.addCategory(item, this.initialSettings.length);

-		},

-		

 		showThemeBuilder: function(id){

 		

 			this.selectCategory(id);

@@ -274,20 +235,28 @@
 			this.pluginWidget.startup();

 		},

 

-	initPluginSettings: function(id) {

-		dojo.empty(this.table);

+		initPluginSettings: function(category) {

+			function settingsCompare(a, b) {

+				var nameA = a.getName(), nameB = b.getName();

+				if (typeof nameA === 'string' && typeof nameB === 'string') {

+					return nameA.localeCompare(nameB);

+				}

+				return a.getPid().localeCompare(b.getPid());

+			}

 

-//		if (this.pluginSettingsWidget) {

-//			this.pluginSettingsWidget.destroy();

-//		}

+			dojo.empty(this.table);

 

-		this.pluginSettingsWidget = new SettingsList({

-			parent: this.table,

-			serviceRegistry: this.registry,

-			settingsRegistry: this.settingsRegistry

-		});

-		// starts itself. will also remove previous version of itself

-	},

+			if (this.pluginSettingsWidget) {

+				this.pluginSettingsWidget.destroy();

+			}

+

+			this.pluginSettingsWidget = new SettingsList({

+				parent: this.table,

+				serviceRegistry: this.registry,

+				settings: this.settingsRegistry.getSettings(category).sort(settingsCompare),

+				title: messages[category] || category

+			});

+		},

 

 /*	showPlugins - iterates over the plugin array, reads

 	meta-data and creates a dom entry for each plugin.

@@ -307,15 +276,14 @@
 			this.initPlugins(id);

 		},

 

-		// Creates the RHS content of plugins settings and stuff

-		showPluginSettings: function(id) {

+		showPluginSettings: function(category) {

+			var id = category;

 			this.selectCategory(id);

 

-			this.initPluginSettings(id);

+			this.initPluginSettings(category);

 		},

 		

 		selectCategory: function(id) {

-

 			this.preferences.getPreferences('/settingsContainer', 2).then(function(prefs){

 				prefs.put( 'selection', id );

 			} );

@@ -346,51 +314,44 @@
 			}

 		},

 

-		showById: function(id) {

-		

-				

+		showByCategory: function(id) {

 			

 			this.updateToolbar(id);

-				

-				switch(id){

-				

-					case "plugins": //$NON-NLS-0$

-						this.showPlugins(id);

-						break;

-					

-					case "userSettings": //$NON-NLS-0$

-						this.showUserSettings(id);

-						break;

-						

-					case "themeBuilder":

-						this.showThemeBuilder(id);

-						break;

-						

-					case "editorThemeBuilder":

-						this.showEditorThemeBuilder(id);

-						break;

-						

-					case "pluginSettings":

-						this.showPluginSettings(id);

-						break;

-	

-					default:

-						this.selectCategory(id);

-						break;

-				

-				}	

+

+			var isDefaultCategory = this.settingsCategories.some(function(category) {

+				if (category.id === id) {

+					category.show();

+					return true;

+				}

+			});

+

+			if (!isDefaultCategory) {

+				this.selectCategory(id);

+			}

+		},

+

+		addCategory: function(category) {

+			category['class'] = (category['class'] || '') + ' navbar-item'; //$NON-NLS-1$ //$NON-NLS-0$

+			category.role = "tab";

+			category.tabindex = -1;

+			category["aria-selected"] = "false"; //$NON-NLS-1$ //$NON-NLS-0$

+			category.onclick = category.show;

+			this.inherited(arguments);

+		},

+

+		addCategories: function() {

+			var self = this;

+			this.settingsCategories.forEach(function(category, i) {

+				self.addCategory(category);

+			});

 		},

 

 		drawUserInterface: function(settings) {

 

 			this.inherited(arguments);

 

+			this.addCategories();

 

-			this.addUserSettings();

-			this.addThemeBuilder();

-			this.addEditorThemeBuilder();

-			this.addPlugins();

-			this.addPluginSettings();

 			this.processHash();

 

 			/* Adjusting width of mainNode - the css class is shared 

@@ -470,226 +431,6 @@
 							{ "ui": "Login", "label": "Login", "input": "textfield", "setting": "" },

 							{ "ui": "Email Address", "label": "Email Address", "input": "textfield", "setting": "" }*/

 

-initialSettings: [

-//			{"category": "User",

-//				"subcategory": [{ "ui": "Personal information", "label": "Personal information",

-//				"items": [ { "ui": "Login", "label": "Login", "input": "textfield", "setting": "" },

-//							{ "ui": "Email Address", "label": "Email Address", "input": "textfield", "setting": "" } ]}

-//				]

-//			},

-			{"category": messages['JavaScript Editor'], //$NON-NLS-0$

-			"subcategory": [{

-				"ui": messages["Font"], //$NON-NLS-0$

-				"label": messages['Font'], //$NON-NLS-0$

-				"items": [{ //$NON-NLS-0$

-					"ui": messages["Family"], //$NON-NLS-0$

-					"label": messages['Family'], //$NON-NLS-0$

-					"input": "combo", //$NON-NLS-1$ //$NON-NLS-0$

-					"values": [{ //$NON-NLS-0$

-						"label": messages["Sans Serif"] //$NON-NLS-0$

-					},

-					{

-						"label": messages["Serif"] //$NON-NLS-0$

-					}],

-					"setting": messages['Serif'] //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Size"], //$NON-NLS-0$

-					"label": messages['Size'], //$NON-NLS-0$

-					"input": "combo", //$NON-NLS-1$ //$NON-NLS-0$

-					"values": [{ //$NON-NLS-0$

-						"label": messages["8pt"] //$NON-NLS-0$

-					},

-					{

-						"label": messages["9pt"] //$NON-NLS-0$

-					},

-					{

-						"label": messages["10pt"] //$NON-NLS-0$

-					},

-					{

-						"label": "11pt" //$NON-NLS-1$ //$NON-NLS-0$

-					},

-					{

-						"label": messages["12pt"] //$NON-NLS-0$

-					}],

-					"setting": messages['10pt'] //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Color"], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#000000" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Background"], //$NON-NLS-0$

-					"label": messages['Background'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				}]

-			},

-

-			{

-				"ui": messages["Strings"], //$NON-NLS-0$

-				"label": messages["String Types"], //$NON-NLS-0$

-				"items": [{ //$NON-NLS-0$

-					"ui": messages['Color'], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": messages["blue"] //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Weight"], //$NON-NLS-0$

-					"label": messages['Weight'], //$NON-NLS-0$

-					"input": "combo", //$NON-NLS-1$ //$NON-NLS-0$

-					"values": [{ //$NON-NLS-0$

-						"label": messages["Normal"] //$NON-NLS-0$

-					},

-					{

-						"label": messages["Bold"] //$NON-NLS-0$

-					}],

-					"setting": messages['Normal'] //$NON-NLS-0$

-				}]

-			},

-			{

-				"ui": messages["Comments"], //$NON-NLS-0$

-				"label": messages["Comment Types"], //$NON-NLS-0$

-				"items": [{ //$NON-NLS-0$

-					"ui": messages['Color'], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": messages["green"] //$NON-NLS-0$

-				},

-				{

-					"ui": messages['Weight'], //$NON-NLS-0$

-					"label": messages['Weight'], //$NON-NLS-0$

-					"input": "combo", //$NON-NLS-1$ //$NON-NLS-0$

-					"values": [{ //$NON-NLS-0$

-						"label": messages['Normal'] //$NON-NLS-0$

-					},

-					{

-						"label": messages['Bold'] //$NON-NLS-0$

-					}],

-					"setting": messages['Normal'] //$NON-NLS-0$

-				}]

-			},

-			{

-				"ui": messages["Keywords"], //$NON-NLS-0$

-				"label": messages["Keyword Types"], //$NON-NLS-0$

-				"items": [{ //$NON-NLS-0$

-					"ui": messages['Color'], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": messages["darkred"] //$NON-NLS-0$

-				},

-				{

-					"label": messages['Weight'], //$NON-NLS-0$

-					"input": "combo", //$NON-NLS-1$ //$NON-NLS-0$

-					"values": [{ //$NON-NLS-0$

-						"label": messages['Normal'] //$NON-NLS-0$

-					},

-					{

-						"label": messages['Bold'] //$NON-NLS-0$

-					}],

-					"setting": messages['Bold'] //$NON-NLS-0$

-				}]

-			},

-			{

-				"ui": 'Annotations Ruler',  //$NON-NLS-0$

-				"label":'Annotations Ruler', //$NON-NLS-0$

-				"items": [{

-					"ui": messages["Color"], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "lightgrey" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Background"], //$NON-NLS-0$

-					"label": messages['Background'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				}

-				]

-			},

-			{

-				"ui": 'Folding Ruler',  //$NON-NLS-0$

-				"label":'Folding Ruler', //$NON-NLS-0$

-				"items": [{

-					"ui": messages["Color"], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#000000" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Background"], //$NON-NLS-0$

-					"label": messages['Background'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				}

-				]

-			},

-			{

-				"ui": 'Overview Ruler',  //$NON-NLS-0$

-				"label":'Overview Ruler', //$NON-NLS-0$

-				"items": [{

-					"ui": messages["Color"], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Background"], //$NON-NLS-0$

-					"label": messages['Background'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				}

-				]

-			},

-			{

-				"ui": 'Line Number Ruler',  //$NON-NLS-0$

-				"label":'Line Number Ruler', //$NON-NLS-0$

-				"items": [

-				

-				/* Don't think this is necessary {

-					"ui": messages["Color"], //$NON-NLS-0$

-					"label": messages['Color'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": messages["Background"], //$NON-NLS-0$

-					"label": messages['Background'], //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				},*/

-				{

-					"ui": 'Even Rows Color', //$NON-NLS-0$

-					"label": 'Even Rows Color', //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#444" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": 'Even Rows Background', //$NON-NLS-0$

-					"label": 'Even Rows Background', //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": 'Odd Rows Color', //$NON-NLS-0$

-					"label": 'Odd Rows Color', //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#444" //$NON-NLS-1$ //$NON-NLS-0$

-				},

-				{

-					"ui": 'Odd Rows Background', //$NON-NLS-0$

-					"label":'Odd Rows Background', //$NON-NLS-0$

-					"input": "color", //$NON-NLS-1$ //$NON-NLS-0$

-					"setting": "#FFFFFF" //$NON-NLS-1$ //$NON-NLS-0$

-				}

-				]

-			}

-			

-			]

-		}]

-

+		initialSettings: []

 	});

 });
diff --git a/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SplitSelectionLayout.js b/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SplitSelectionLayout.js
index 12a3865..a9a31b3 100644
--- a/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SplitSelectionLayout.js
+++ b/bundles/org.eclipse.orion.client.core/web/orion/widgets/settings/SplitSelectionLayout.js
@@ -79,7 +79,9 @@
 

 

 		addCategory: function(item, index) {

-			dojo.create("li", item, this.navbar); //$NON-NLS-0$

+			index = (typeof index === "undefined") ? 0 : index;

+			var li = dojo.create("li", item, this.navbar); //$NON-NLS-0$

+			li.textContent = item.textContent;

 			this.itemToIndexMap[item.id] = index;

 		},

 

diff --git a/bundles/org.eclipse.orion.client.core/web/plugins/jslintPlugin.js b/bundles/org.eclipse.orion.client.core/web/plugins/jslintPlugin.js
index cf24f7c..22066b0 100644
--- a/bundles/org.eclipse.orion.client.core/web/plugins/jslintPlugin.js
+++ b/bundles/org.eclipse.orion.client.core/web/plugins/jslintPlugin.js
@@ -234,6 +234,7 @@
 				{	pid: 'jslint.config',
 					name: 'JSLint Validator',
 					tags: 'validation javascript js jslint'.split(' '),
+					category: 'validation',
 					properties: [
 						{	id: 'options',
 							name: 'Default Options',
diff --git a/bundles/org.eclipse.orion.client.core/web/plugins/nonnlsPlugin.html b/bundles/org.eclipse.orion.client.core/web/plugins/nonnlsPlugin.html
index 0fcb98d..fe67e35 100644
--- a/bundles/org.eclipse.orion.client.core/web/plugins/nonnlsPlugin.html
+++ b/bundles/org.eclipse.orion.client.core/web/plugins/nonnlsPlugin.html
@@ -109,6 +109,7 @@
 				{	settings: [
 						{	pid: 'nonnls.config',
 							name: 'NLS Validator',
+							category: 'validation',
 							tags: 'validation javascript js nls'.split(' '),
 							properties: [
 								{	id: 'enabled',
diff --git a/bundles/org.eclipse.orion.client.core/web/plugins/pageLinksPlugin.html b/bundles/org.eclipse.orion.client.core/web/plugins/pageLinksPlugin.html
index 10daa98..577143c 100644
--- a/bundles/org.eclipse.orion.client.core/web/plugins/pageLinksPlugin.html
+++ b/bundles/org.eclipse.orion.client.core/web/plugins/pageLinksPlugin.html
@@ -85,6 +85,7 @@
 			settings: [
 				{	pid: "nav.config",
 					name: "Navigation",
+					category: 'general',
 					properties: [
 						{	id: "links.newtab",
 							name: "Links",
diff --git a/bundles/org.eclipse.orion.client.core/web/settings/maker.js b/bundles/org.eclipse.orion.client.core/web/settings/maker.js
index 0e2cec4..a4a600a 100644
--- a/bundles/org.eclipse.orion.client.core/web/settings/maker.js
+++ b/bundles/org.eclipse.orion.client.core/web/settings/maker.js
@@ -13,7 +13,14 @@
 /*global define dojo dijit orion window widgets localStorage*/

 /*jslint browser:true devel:true*/

 

-define(['i18n!orion/settings/nls/messages', 'require', 'dojo', 'orion/bootstrap', 'orion/status', 'orion/commands', 'orion/operationsClient', 'orion/fileClient', 'orion/searchClient', 'orion/dialogs', 'orion/globalCommands', 'orion/sites/siteClient', 'orion/sites/siteUtils', 'orion/sites/sitesExplorer', 'orion/treetable', 'dojo/parser', 'dojo/hash', 'dojo/date/locale', 'dijit/layout/BorderContainer', 'dijit/layout/ContentPane', 'orion/widgets/maker/PluginMakerContainer', 'orion/widgets/maker/ScrollingContainerSection', 'orion/widgets/maker/PluginDescriptionSection', 'orion/widgets/maker/PluginCompletionSection', 'dijit/form/Button', 'dijit/ColorPalette'], function(messages, require, dojo, mBootstrap, mStatus, mCommands, mOperationsClient, mFileClient, mSearchClient, mDialogs, mGlobalCommands, mSiteClient, mSiteUtils, mSiteTree, mTreeTable) {

+define(['i18n!orion/settings/nls/messages', 'require', 'dojo', 'orion/bootstrap', 'orion/status', 'orion/commands', 'orion/operationsClient',

+		'orion/fileClient', 'orion/searchClient', 'orion/dialogs', 'orion/globalCommands', 'orion/sites/siteClient',

+		'dojo/parser', 'dojo/hash', 'dojo/date/locale', 'dijit/layout/BorderContainer', 'dijit/layout/ContentPane',

+		'orion/widgets/maker/PluginMakerContainer', 'orion/widgets/maker/ScrollingContainerSection',

+		'orion/widgets/maker/PluginDescriptionSection', 'orion/widgets/maker/PluginCompletionSection', 'dijit/form/Button',

+		'dijit/ColorPalette'],

+		function(messages, require, dojo, mBootstrap, mStatus, mCommands, mOperationsClient, mFileClient, mSearchClient,

+			mDialogs, mGlobalCommands) {

 

 	dojo.addOnLoad(function() {

 		mBootstrap.startup().then(function(core) {

diff --git a/bundles/org.eclipse.orion.client.core/web/sites/sites.js b/bundles/org.eclipse.orion.client.core/web/sites/sites.js
index ea21304..fe2ecf1 100644
--- a/bundles/org.eclipse.orion.client.core/web/sites/sites.js
+++ b/bundles/org.eclipse.orion.client.core/web/sites/sites.js
@@ -13,9 +13,9 @@
 /*jslint browser:true*/
 define(['require', 'dojo', 'orion/bootstrap', 'orion/status', 'orion/progress', 'orion/commands', 'orion/fileClient', 'orion/operationsClient',
 		'orion/searchClient', 'orion/selection', 'orion/dialogs', 'orion/globalCommands', 'orion/sites/siteUtils', 'orion/sites/siteCommands', 
-		'orion/sites/sitesExplorer2','dojo/hash', 'dojo/date/locale'], 
+		'orion/sites/sitesExplorer','dojo/hash', 'dojo/date/locale'], 
 		function(require, dojo, mBootstrap, mStatus, mProgress, mCommands, mFileClient, mOperationsClient, mSearchClient, mSelection, mDialogs, mGlobalCommands,
-			mSiteUtils, mSiteCommands, mSitesExplorer) {
+			mSiteUtils, mSiteCommands, SitesExplorer) {
 
 	dojo.addOnLoad(function() {
 		mBootstrap.startup().then(function(core) {
@@ -48,7 +48,7 @@
 			mGlobalCommands.generateBanner("orion-sites", serviceRegistry, commandService, preferences, searcher); //$NON-NLS-0$
 			mGlobalCommands.setPageTarget({task: "Sites"});
 			
-			var explorer = new mSitesExplorer.SiteServicesExplorer2(serviceRegistry, selection, "table"); //$NON-NLS-0$
+			var explorer = new SitesExplorer(serviceRegistry, selection, "table"); //$NON-NLS-0$
 			createCommands();
 			explorer.display();
 		});
diff --git a/bundles/org.eclipse.orion.client.core/web/sites/view.js b/bundles/org.eclipse.orion.client.core/web/sites/view.js
index e93df24..2d9c323 100644
--- a/bundles/org.eclipse.orion.client.core/web/sites/view.js
+++ b/bundles/org.eclipse.orion.client.core/web/sites/view.js
@@ -13,9 +13,9 @@
 /*jslint */
 define(['require', 'dojo', 'orion/bootstrap', 'orion/status', 'orion/progress', 'orion/commands', 'orion/fileClient', 'orion/operationsClient',
 		'orion/searchClient', 'orion/globalCommands', 'orion/sites/siteUtils', 'orion/sites/siteCommands', 
-		'orion/sites/sitesExplorer', 'orion/PageUtil','dojo/hash', 'dojo/date/locale'], 
+		'orion/sites/viewOnSiteTree', 'orion/PageUtil','dojo/hash', 'dojo/date/locale'], 
 		function(require, dojo, mBootstrap, mStatus, mProgress, mCommands, mFileClient, mOperationsClient, mSearchClient, mGlobalCommands,
-			mSiteUtils, mSiteCommands, mSitesExplorer, PageUtil) {
+			mSiteUtils, mSiteCommands, ViewOnSiteTree, PageUtil) {
 
 	dojo.addOnLoad(function() {
 		mBootstrap.startup().then(function(core) {
@@ -38,7 +38,7 @@
 				if (treeWidget) {
 					dojo.empty(parentId);
 				}
-				treeWidget = new mSitesExplorer.ViewOnSiteTree({
+				treeWidget = new ViewOnSiteTree({
 					id: 'view-on-site-table', //$NON-NLS-0$
 					parent: parentId,
 					label: labelId,
diff --git a/bundles/org.eclipse.orion.client.editor/web/examples/editor/embeddededitor.js b/bundles/org.eclipse.orion.client.editor/web/examples/editor/embeddededitor.js
index 5e6011c..0b6c91d 100644
--- a/bundles/org.eclipse.orion.client.editor/web/examples/editor/embeddededitor.js
+++ b/bundles/org.eclipse.orion.client.editor/web/examples/editor/embeddededitor.js
@@ -42,7 +42,8 @@
 	var contentAssistFactory = {
 		createContentAssistMode: function(editor) {
 			contentAssist = new mContentAssist.ContentAssist(editor.getTextView());
-			var contentAssistWidget = new mContentAssist.ContentAssistWidget(contentAssist, "contentassist");
+			var contentAssistDomNode = document.getElementById("contentassist");
+			var contentAssistWidget = new mContentAssist.ContentAssistWidget(contentAssist, contentAssistDomNode);
 			return new mContentAssist.ContentAssistMode(contentAssist, contentAssistWidget);
 		}
 	};