627 lines
25 KiB
JavaScript
627 lines
25 KiB
JavaScript
|
dojo.provide("dojox.data.ItemExplorer");
|
||
|
dojo.require("dijit.Tree");
|
||
|
dojo.require("dijit.Dialog");
|
||
|
dojo.require("dijit.Menu");
|
||
|
dojo.require("dijit.form.ValidationTextBox");
|
||
|
dojo.require("dijit.form.Textarea");
|
||
|
dojo.require("dijit.form.Button");
|
||
|
dojo.require("dijit.form.CheckBox");
|
||
|
dojo.require("dijit.form.FilteringSelect");
|
||
|
|
||
|
(function(){
|
||
|
var getValue = function(store, item, prop){
|
||
|
var value = store.getValues(item, prop);
|
||
|
if(value.length < 2){
|
||
|
value = store.getValue(item, prop);
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
dojo.declare("dojox.data.ItemExplorer", dijit.Tree, {
|
||
|
useSelect: false,
|
||
|
refSelectSearchAttr: null,
|
||
|
constructor: function(options){
|
||
|
dojo.mixin(this, options);
|
||
|
var self = this;
|
||
|
var initialRootValue = {};
|
||
|
var root = this.rootModelNode = {value:initialRootValue,id:"root"};
|
||
|
|
||
|
this._modelNodeIdMap = {};
|
||
|
this._modelNodePropMap = {};
|
||
|
var nextId = 1;
|
||
|
this.model = {
|
||
|
getRoot: function(onItem){
|
||
|
onItem(root);
|
||
|
},
|
||
|
mayHaveChildren: function(modelNode){
|
||
|
return modelNode.value && typeof modelNode.value == 'object' && !(modelNode.value instanceof Date);
|
||
|
},
|
||
|
getChildren: function(parentModelNode, onComplete, onError){
|
||
|
var keys, parent, item = parentModelNode.value;
|
||
|
var children = [];
|
||
|
if(item == initialRootValue){
|
||
|
onComplete([]);
|
||
|
return;
|
||
|
}
|
||
|
var isItem = self.store && self.store.isItem(item, true);
|
||
|
if(isItem && !self.store.isItemLoaded(item)){
|
||
|
// if it is not loaded, do so now.
|
||
|
self.store.loadItem({
|
||
|
item:item,
|
||
|
onItem:function(loadedItem){
|
||
|
item = loadedItem;
|
||
|
enumerate();
|
||
|
}
|
||
|
});
|
||
|
}else{
|
||
|
enumerate();
|
||
|
}
|
||
|
function enumerate(){
|
||
|
// once loaded, enumerate the keys
|
||
|
if(isItem){
|
||
|
// get the properties through the dojo data API
|
||
|
keys = self.store.getAttributes(item);
|
||
|
parent = item;
|
||
|
}else if(item && typeof item == 'object'){
|
||
|
parent = parentModelNode.value;
|
||
|
keys = [];
|
||
|
// also we want to be able to drill down into plain JS objects/arrays
|
||
|
for(var i in item){
|
||
|
if(item.hasOwnProperty(i) && i != '__id' && i != '__clientId'){
|
||
|
keys.push(i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if(keys){
|
||
|
for(var key, k=0; key = keys[k++];){
|
||
|
children.push({
|
||
|
property:key,
|
||
|
value: isItem ? getValue(self.store, item, key) : item[key],
|
||
|
parent: parent});
|
||
|
}
|
||
|
children.push({addNew:true, parent: parent, parentNode : parentModelNode});
|
||
|
}
|
||
|
onComplete(children);
|
||
|
}
|
||
|
},
|
||
|
getIdentity: function(modelNode){
|
||
|
if(!modelNode.id){
|
||
|
if(modelNode.addNew){
|
||
|
modelNode.property = "--addNew";
|
||
|
}
|
||
|
modelNode.id = nextId++;
|
||
|
if(self.store){
|
||
|
if(self.store.isItem(modelNode.value)){
|
||
|
var identity = self.store.getIdentity(modelNode.value);
|
||
|
(self._modelNodeIdMap[identity] = self._modelNodeIdMap[identity] || []).push(modelNode);
|
||
|
}
|
||
|
if(modelNode.parent){
|
||
|
identity = self.store.getIdentity(modelNode.parent) + '.' + modelNode.property;
|
||
|
(self._modelNodePropMap[identity] = self._modelNodePropMap[identity] || []).push(modelNode);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return modelNode.id;
|
||
|
},
|
||
|
getLabel: function(modelNode){
|
||
|
return modelNode === root ?
|
||
|
"Object Properties" :
|
||
|
modelNode.addNew ? (modelNode.parent instanceof Array ? "Add new value" : "Add new property") :
|
||
|
modelNode.property + ": " +
|
||
|
(modelNode.value instanceof Array ? "(" + modelNode.value.length + " elements)" : modelNode.value);
|
||
|
},
|
||
|
onChildrenChange: function(modelNode){
|
||
|
},
|
||
|
onChange: function(modelNode){
|
||
|
}
|
||
|
};
|
||
|
},
|
||
|
postCreate: function(){
|
||
|
this.inherited(arguments);
|
||
|
// handle the clicking on the "add new property item"
|
||
|
dojo.connect(this, "onClick", function(modelNode, treeNode){
|
||
|
this.lastFocused = treeNode;
|
||
|
if(modelNode.addNew){
|
||
|
//this.focusNode(treeNode.getParent());
|
||
|
this._addProperty();
|
||
|
}else{
|
||
|
this._editProperty();
|
||
|
}
|
||
|
});
|
||
|
var contextMenu = new dijit.Menu({
|
||
|
targetNodeIds: [this.rootNode.domNode],
|
||
|
id: "contextMenu"
|
||
|
});
|
||
|
dojo.connect(contextMenu, "_openMyself", this, function(e){
|
||
|
var node = dijit.getEnclosingWidget(e.target);
|
||
|
if(node){
|
||
|
var item = node.item;
|
||
|
if(this.store.isItem(item.value, true) && !item.parent){
|
||
|
contextMenu.getChildren().forEach(function(widget){
|
||
|
widget.attr("disabled", (widget.label != "Add"));
|
||
|
});
|
||
|
this.lastFocused = node;
|
||
|
// TODO: Root Node - allow Edit when mutli-value editing is possible
|
||
|
}else if(item.value && typeof item.value == 'object' && !(item.value instanceof Date)){
|
||
|
// an object that's not a Date - could be a store item
|
||
|
contextMenu.getChildren().forEach(function(widget){
|
||
|
widget.attr("disabled", (widget.label != "Add") && (widget.label != "Delete"));
|
||
|
});
|
||
|
this.lastFocused = node;
|
||
|
// TODO: Object - allow Edit when mutli-value editing is possible
|
||
|
}else if(item.property && dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){ // id node
|
||
|
this.focusNode(node);
|
||
|
alert("Cannot modify an Identifier node.");
|
||
|
}else if(item.addNew){
|
||
|
this.focusNode(node);
|
||
|
}else{
|
||
|
contextMenu.getChildren().forEach(function(widget){
|
||
|
widget.attr("disabled", (widget.label != "Edit") && (widget.label != "Delete"));
|
||
|
})
|
||
|
// this won't focus the node but gives us a way to reference the node
|
||
|
this.lastFocused = node;
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
contextMenu.addChild(new dijit.MenuItem({label: "Add", onClick: dojo.hitch(this, "_addProperty")}));
|
||
|
contextMenu.addChild(new dijit.MenuItem({label: "Edit", onClick: dojo.hitch(this, "_editProperty")}));
|
||
|
contextMenu.addChild(new dijit.MenuItem({label: "Delete", onClick: dojo.hitch(this, "_destroyProperty")}));
|
||
|
contextMenu.startup();
|
||
|
},
|
||
|
store: null,
|
||
|
setStore: function(store){
|
||
|
this.store = store;
|
||
|
var self = this;
|
||
|
if(this._editDialog){
|
||
|
this._editDialog.destroyRecursive();
|
||
|
delete this._editDialog;
|
||
|
}
|
||
|
// i think we should just destroy this._editDialog and let _createEditDialog take care of everything
|
||
|
// once it gets called again by either _editProperty or _addProperty - it will create everything again
|
||
|
// using the new store. this way we don't need to keep track of what is in the dialog if we change it.
|
||
|
/*if(this._editDialog && this.useSelect){
|
||
|
dojo.query(".reference [widgetId]", this._editDialog.containerNode).forEach(function(node){
|
||
|
dijit.getEnclosingWidget(node).attr("store", store);
|
||
|
});
|
||
|
}*/
|
||
|
dojo.connect(store, "onSet", function(item, attribute, oldValue, newValue){
|
||
|
var nodes, i, identity = self.store.getIdentity(item);
|
||
|
nodes = self._modelNodeIdMap[identity];
|
||
|
|
||
|
if(nodes &&
|
||
|
(oldValue === undefined || newValue === undefined ||
|
||
|
oldValue instanceof Array || newValue instanceof Array || typeof oldValue == 'object' || typeof newValue == 'object')){
|
||
|
for(i = 0; i < nodes.length; i++){
|
||
|
(function(node){
|
||
|
self.model.getChildren(node, function(children){
|
||
|
self.model.onChildrenChange(node, children);
|
||
|
});
|
||
|
})(nodes[i]);
|
||
|
}
|
||
|
}
|
||
|
nodes = self._modelNodePropMap[identity + "." + attribute];
|
||
|
|
||
|
if(nodes){
|
||
|
for(i = 0; i < nodes.length; i++){
|
||
|
nodes[i].value = newValue;
|
||
|
self.model.onChange(nodes[i]);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
this.rootNode.setChildItems([]);
|
||
|
},
|
||
|
setItem: function(item){
|
||
|
// this is called to show a different item
|
||
|
|
||
|
// reset the maps, for the root getIdentity is not called, so we pre-initialize it here
|
||
|
(this._modelNodeIdMap = {})[this.store.getIdentity(item)] = [this.rootModelNode];
|
||
|
this._modelNodePropMap = {};
|
||
|
|
||
|
this.rootModelNode.value = item;
|
||
|
var self = this;
|
||
|
this.model.getChildren(this.rootModelNode, function(children){
|
||
|
self.rootNode.setChildItems(children);
|
||
|
});
|
||
|
|
||
|
},
|
||
|
refreshItem: function(){
|
||
|
this.setItem(this.rootModelNode.value);
|
||
|
},
|
||
|
_createEditDialog: function(){
|
||
|
this._editDialog = new dijit.Dialog({
|
||
|
title: "Edit Property",
|
||
|
execute: dojo.hitch(this, "_updateItem"),
|
||
|
preload: true
|
||
|
});
|
||
|
this._editDialog.placeAt(dojo.body());
|
||
|
this._editDialog.startup();
|
||
|
|
||
|
// handle for dialog content
|
||
|
var pane = dojo.doc.createElement('div');
|
||
|
|
||
|
// label for property
|
||
|
var labelProp = dojo.doc.createElement('label');
|
||
|
dojo.attr(labelProp, "for", "property");
|
||
|
dojo.style(labelProp, "fontWeight", "bold");
|
||
|
dojo.attr(labelProp, "innerHTML", "Property:")
|
||
|
pane.appendChild(labelProp);
|
||
|
|
||
|
// property name field
|
||
|
var propName = new dijit.form.ValidationTextBox({
|
||
|
name: "property",
|
||
|
value: "",
|
||
|
required: true,
|
||
|
disabled: true
|
||
|
}).placeAt(pane);
|
||
|
|
||
|
pane.appendChild(dojo.doc.createElement("br"));
|
||
|
pane.appendChild(dojo.doc.createElement("br"));
|
||
|
|
||
|
// radio button for "value"
|
||
|
var value = new dijit.form.RadioButton({
|
||
|
name: "itemType",
|
||
|
value: "value",
|
||
|
onClick: dojo.hitch(this, function(){this._enableFields("value");})
|
||
|
}).placeAt(pane);
|
||
|
|
||
|
// label for value
|
||
|
var labelVal = dojo.doc.createElement('label');
|
||
|
dojo.attr(labelVal, "for", "value");
|
||
|
dojo.attr(labelVal, "innerHTML", "Value (JSON):")
|
||
|
pane.appendChild(labelVal);
|
||
|
|
||
|
// container for value fields
|
||
|
var valueDiv = dojo.doc.createElement("div");
|
||
|
dojo.addClass(valueDiv, "value");
|
||
|
|
||
|
// textarea
|
||
|
var textarea = new dijit.form.Textarea({
|
||
|
name: "jsonVal"
|
||
|
}).placeAt(valueDiv);
|
||
|
pane.appendChild(valueDiv);
|
||
|
|
||
|
// radio button for "reference"
|
||
|
var reference = new dijit.form.RadioButton({
|
||
|
name: "itemType",
|
||
|
value: "reference",
|
||
|
onClick: dojo.hitch(this, function(){this._enableFields("reference");})
|
||
|
}).placeAt(pane);
|
||
|
|
||
|
// label for reference
|
||
|
var labelRef = dojo.doc.createElement('label');
|
||
|
dojo.attr(labelRef, "for", "_reference");
|
||
|
dojo.attr(labelRef, "innerHTML", "Reference (ID):")
|
||
|
pane.appendChild(labelRef);
|
||
|
pane.appendChild(dojo.doc.createElement("br"));
|
||
|
|
||
|
// container for reference fields
|
||
|
var refDiv = dojo.doc.createElement("div");
|
||
|
dojo.addClass(refDiv, "reference");
|
||
|
|
||
|
if(this.useSelect){
|
||
|
// filteringselect
|
||
|
// TODO: see if there is a way to sort the items in this list
|
||
|
var refSelect = new dijit.form.FilteringSelect({
|
||
|
name: "_reference",
|
||
|
store: this.store,
|
||
|
searchAttr: this.refSelectSearchAttr || this.store.getIdentityAttributes()[0],
|
||
|
required: false,
|
||
|
value: null, // need to file a ticket about the fetch that happens when declared with value: null
|
||
|
pageSize: 10
|
||
|
}).placeAt(refDiv);
|
||
|
}else{
|
||
|
var refTextbox = new dijit.form.ValidationTextBox({
|
||
|
name: "_reference",
|
||
|
value: "",
|
||
|
promptMessage: "Enter the ID of the item to reference",
|
||
|
isValid: dojo.hitch(this, function(isFocused){
|
||
|
// don't validate while it's focused
|
||
|
return true;//isFocused || this.store.getItemByIdentity(this._editDialog.attr("value")._reference);
|
||
|
})
|
||
|
}).placeAt(refDiv);
|
||
|
}
|
||
|
pane.appendChild(refDiv);
|
||
|
pane.appendChild(dojo.doc.createElement("br"));
|
||
|
pane.appendChild(dojo.doc.createElement("br"));
|
||
|
|
||
|
// buttons
|
||
|
var buttons = document.createElement('div');
|
||
|
buttons.setAttribute("dir", "rtl");
|
||
|
var cancelButton = new dijit.form.Button({type: "reset", label: "Cancel"}).placeAt(buttons);
|
||
|
cancelButton.onClick = dojo.hitch(this._editDialog, "onCancel");
|
||
|
var okButton = new dijit.form.Button({type: "submit", label: "OK"}).placeAt(buttons);
|
||
|
pane.appendChild(buttons);
|
||
|
|
||
|
this._editDialog.attr("content", pane);
|
||
|
},
|
||
|
_enableFields: function(selection){
|
||
|
// enables/disables fields based on whether the value in this._editDialog is a reference or a primitive value
|
||
|
switch(selection){
|
||
|
case "reference":
|
||
|
dojo.query(".value [widgetId]", this._editDialog.containerNode).forEach(function(node){
|
||
|
dijit.getEnclosingWidget(node).attr("disabled", true);
|
||
|
});
|
||
|
dojo.query(".reference [widgetId]", this._editDialog.containerNode).forEach(function(node){
|
||
|
dijit.getEnclosingWidget(node).attr("disabled", false);
|
||
|
});
|
||
|
break;
|
||
|
case "value":
|
||
|
dojo.query(".value [widgetId]", this._editDialog.containerNode).forEach(function(node){
|
||
|
dijit.getEnclosingWidget(node).attr("disabled", false);
|
||
|
});
|
||
|
dojo.query(".reference [widgetId]", this._editDialog.containerNode).forEach(function(node){
|
||
|
dijit.getEnclosingWidget(node).attr("disabled", true);
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
},
|
||
|
_updateItem: function(vals){
|
||
|
// a single "execute" function that handles adding and editing of values and references.
|
||
|
var node, item, val, storeItemVal, editingItem = this._editDialog.attr("title") == "Edit Property";
|
||
|
var editDialog = this._editDialog;
|
||
|
var store = this.store;
|
||
|
function setValue(){
|
||
|
try{
|
||
|
var itemVal, propPath = [];
|
||
|
var prop = vals.property;
|
||
|
if(editingItem){
|
||
|
while(!store.isItem(item.parent, true)){
|
||
|
node = node.getParent();
|
||
|
propPath.push(item.property);
|
||
|
item = node.item;
|
||
|
}
|
||
|
if(propPath.length == 0){
|
||
|
// working with an item attribute already
|
||
|
store.setValue(item.parent, item.property, val);
|
||
|
}else{
|
||
|
// need to walk back down the item property to the object
|
||
|
storeItemVal = getValue(store, item.parent, item.property);
|
||
|
if(storeItemVal instanceof Array){
|
||
|
// create a copy for modification
|
||
|
storeItemVal = storeItemVal.concat();
|
||
|
}
|
||
|
itemVal = storeItemVal;
|
||
|
while(propPath.length > 1){
|
||
|
itemVal = itemVal[propPath.pop()];
|
||
|
}
|
||
|
itemVal[propPath] = val; // this change is reflected in storeItemVal as well
|
||
|
store.setValue(item.parent, item.property, storeItemVal);
|
||
|
}
|
||
|
}else{
|
||
|
// adding a property
|
||
|
if(store.isItem(value, true)){
|
||
|
// adding a top-level property to an item
|
||
|
if (!store.isItemLoaded(value)) {
|
||
|
// fetch the value and see if it is an array
|
||
|
store.loadItem({
|
||
|
item: value,
|
||
|
onItem: function(loadedItem){
|
||
|
if (loadedItem instanceof Array) {
|
||
|
prop = loadedItem.length;
|
||
|
}
|
||
|
store.setValue(loadedItem, prop, val);
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
if (value instanceof Array) {
|
||
|
prop = value.length;
|
||
|
}
|
||
|
store.setValue(value, prop, val);
|
||
|
}
|
||
|
}else{
|
||
|
// adding a property to a lower level in an item
|
||
|
if(item.value instanceof Array){
|
||
|
propPath.push(item.value.length);
|
||
|
}else{
|
||
|
propPath.push(vals.property);
|
||
|
}
|
||
|
while(!store.isItem(item.parent, true)){
|
||
|
node = node.getParent();
|
||
|
propPath.push(item.property);
|
||
|
item = node.item;
|
||
|
}
|
||
|
storeItemVal = getValue(store, item.parent, item.property);
|
||
|
itemVal = storeItemVal;
|
||
|
while(propPath.length > 1){
|
||
|
itemVal = itemVal[propPath.pop()];
|
||
|
}
|
||
|
itemVal[propPath] = val;
|
||
|
store.setValue(item.parent, item.property, storeItemVal);
|
||
|
}
|
||
|
}
|
||
|
}catch(e){
|
||
|
alert(e);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(editDialog.validate()){
|
||
|
node = this.lastFocused;
|
||
|
item = node.item;
|
||
|
var value = item.value;
|
||
|
// var property = null;
|
||
|
if (item.addNew) {
|
||
|
// we are adding a property to the parent item
|
||
|
// the real value of the parent is in the parent property of the lastFocused item
|
||
|
// this.lastFocused.getParent().item.value may be a reference to an item
|
||
|
value = node.item.parent;
|
||
|
node = node.getParent();
|
||
|
item = node.item;
|
||
|
}
|
||
|
val = null;
|
||
|
switch(vals.itemType){
|
||
|
case "reference":
|
||
|
this.store.fetchItemByIdentity({identity:vals._reference,
|
||
|
onItem:function(item){
|
||
|
val = item;
|
||
|
setValue();
|
||
|
},
|
||
|
onError:function(){
|
||
|
alert("The id could not be found");
|
||
|
}
|
||
|
});
|
||
|
break;
|
||
|
case "value":
|
||
|
var jsonVal = vals.jsonVal;
|
||
|
val = dojo.fromJson(jsonVal);
|
||
|
// if it is a function we want to preserve the source (comments, et al)
|
||
|
if(typeof val == 'function'){
|
||
|
val.toString = function(){
|
||
|
return jsonVal;
|
||
|
}
|
||
|
}
|
||
|
setValue();
|
||
|
break;
|
||
|
}
|
||
|
}else{
|
||
|
// the form didn't validate - show it again.
|
||
|
editDialog.show();
|
||
|
}
|
||
|
},
|
||
|
_editProperty: function(){
|
||
|
// this mixin stops us polluting the tree item with jsonVal etc.
|
||
|
// FIXME: if a store identifies items by instanceof checks, this will fail
|
||
|
var item = dojo.mixin({}, this.lastFocused.item);
|
||
|
// create the dialog or reset it if it already exists
|
||
|
if(!this._editDialog){
|
||
|
this._createEditDialog();
|
||
|
}else{
|
||
|
this._editDialog.reset();
|
||
|
}
|
||
|
// not allowed to edit an item's id - so check for that and stop it.
|
||
|
if(dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){
|
||
|
alert("Cannot Edit an Identifier!");
|
||
|
}else{
|
||
|
this._editDialog.attr("title", "Edit Property");
|
||
|
// make sure the property input is disabled
|
||
|
dijit.getEnclosingWidget(dojo.query("input", this._editDialog.containerNode)[0]).attr("disabled", true);
|
||
|
if(this.store.isItem(item.value, true)){
|
||
|
// root node || Item reference
|
||
|
if(item.parent){
|
||
|
// Item reference
|
||
|
item.itemType = "reference";
|
||
|
this._enableFields(item.itemType);
|
||
|
item._reference = this.store.getIdentity(item.value);
|
||
|
this._editDialog.attr("value", item);
|
||
|
this._editDialog.show();
|
||
|
} // else root node
|
||
|
}else{
|
||
|
if(item.value && typeof item.value == 'object' && !(item.value instanceof Date)){
|
||
|
// item.value is an object but it's NOT an item from the store - no-op
|
||
|
// only allow editing on a property not on the node that represents the object/array
|
||
|
}else{
|
||
|
// this is a primitive
|
||
|
item.itemType = "value";
|
||
|
this._enableFields(item.itemType);
|
||
|
item.jsonVal = typeof item.value == 'function' ?
|
||
|
// use the plain toString for functions, dojo.toJson doesn't support functions
|
||
|
item.value.toString() :
|
||
|
item.value instanceof Date ?
|
||
|
// A json-ish form of a date:
|
||
|
'new Date("' + item.value + '")' :
|
||
|
dojo.toJson(item.value);
|
||
|
this._editDialog.attr("value", item);
|
||
|
this._editDialog.show();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
_destroyProperty: function(){
|
||
|
var node = this.lastFocused;
|
||
|
var item = node.item;
|
||
|
var propPath = [];
|
||
|
// we have to walk up the tree to the item before we can know if we're working with the identifier
|
||
|
while(!this.store.isItem(item.parent, true) || item.parent instanceof Array){
|
||
|
node = node.getParent();
|
||
|
propPath.push(item.property);
|
||
|
item = node.item;
|
||
|
}
|
||
|
// this will prevent any part of the identifier from being changed
|
||
|
if(dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){
|
||
|
alert("Cannot Delete an Identifier!");
|
||
|
}else{
|
||
|
try{
|
||
|
if(propPath.length > 0){
|
||
|
// not deleting a top-level property of an item so get the top-level store item to change
|
||
|
var itemVal, storeItemVal = getValue(this.store, item.parent, item.property);
|
||
|
itemVal = storeItemVal;
|
||
|
// walk back down the object if needed
|
||
|
while(propPath.length > 1){
|
||
|
itemVal = itemVal[propPath.pop()];
|
||
|
}
|
||
|
// delete the property
|
||
|
if(dojo.isArray(itemVal)){
|
||
|
// the value being deleted represents an array element
|
||
|
itemVal.splice(propPath, 1);
|
||
|
}else{
|
||
|
// object property
|
||
|
delete itemVal[propPath];
|
||
|
}
|
||
|
// save it back to the store
|
||
|
this.store.setValue(item.parent, item.property, storeItemVal);
|
||
|
}else{
|
||
|
// deleting an item property
|
||
|
this.store.unsetAttribute(item.parent, item.property);
|
||
|
}
|
||
|
}catch(e){
|
||
|
alert(e);
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
_addProperty: function(){
|
||
|
// item is what we are adding a property to
|
||
|
var item = this.lastFocused.item;
|
||
|
// value is the real value of the item - not a reference to a store item
|
||
|
var value = item.value;
|
||
|
var showDialog = dojo.hitch(this, function(){
|
||
|
var property = null;
|
||
|
if(!this._editDialog){
|
||
|
this._createEditDialog();
|
||
|
}else{
|
||
|
this._editDialog.reset();
|
||
|
}
|
||
|
// are we adding another item to an array?
|
||
|
if(value instanceof Array){
|
||
|
// preset the property to the next index in the array and disable the property field
|
||
|
property = value.length;
|
||
|
dijit.getEnclosingWidget(dojo.query("input", this._editDialog.containerNode)[0]).attr("disabled", true);
|
||
|
}else{
|
||
|
// enable the property TextBox
|
||
|
dijit.getEnclosingWidget(dojo.query("input", this._editDialog.containerNode)[0]).attr("disabled", false);
|
||
|
}
|
||
|
this._editDialog.attr("title", "Add Property");
|
||
|
// default to a value type
|
||
|
this._enableFields("value");
|
||
|
this._editDialog.attr("value", {itemType: "value", property: property});
|
||
|
this._editDialog.show();
|
||
|
});
|
||
|
|
||
|
if (item.addNew) {
|
||
|
// we are adding a property to the parent item
|
||
|
item = this.lastFocused.getParent().item;
|
||
|
// the real value of the parent is in the parent property of the lastFocused item
|
||
|
// this.lastFocused.getParent().item.value may be a reference to an item
|
||
|
value = this.lastFocused.item.parent;
|
||
|
}
|
||
|
if(item.property && dojo.indexOf(this.store.getIdentityAttributes(), item.property) >= 0){
|
||
|
alert("Cannot add properties to an ID node!");
|
||
|
}else{
|
||
|
// if the value is an item then we need to get the item's value
|
||
|
if(this.store.isItem(value, true) && !this.store.isItemLoaded(value)) {
|
||
|
// fetch the value and see if it is an array
|
||
|
this.store.loadItem({
|
||
|
item: value,
|
||
|
onItem: function(loadedItem){
|
||
|
value = loadedItem;
|
||
|
showDialog();
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
showDialog();
|
||
|
}
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
})();
|
||
|
|