Files
alfresco-community-repo/source/web/scripts/ajax/picker.js
Paul Holmes-Higgin e563eb7449 Updated files to LGPL
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18981 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
2010-03-03 13:08:14 +00:00

536 lines
17 KiB
JavaScript

/*
* Copyright (C) 2005-2010 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Prerequisites: common.js
* mootools.v1.11.js
*/
// Picker class definition
var AlfPicker = new Class(
{
/* id of the picker */
id: null,
/* variable name being used */
varName: null,
/* form Id to submit when selection complete */
formClientId: null,
/* the item the picker will start with */
startId: null,
/* list of items currently selected */
selected: null,
/* list of items pre-selected */
preselected: null,
/* the current parent being shown */
parent: null,
/* the list of items currently displayed */
items: [],
/* parent stack for the Navigate Up action*/
stack: [],
/* row type toggle */
oddRow: true,
/* ajax service call to retrieve data */
service: null,
/* default icon to use if not provided by the associated service */
defaultIcon: null,
/* single selection mode flag */
singleSelect: false,
/* initial display style of the outer div */
initialDisplayStyle: null,
/* addition service request attributes if any */
requestAttributes: null,
initialize: function(id, varName, service, formClientId, singleSelect)
{
this.id = id;
this.varName = varName;
this.service = service;
this.formClientId = formClientId;
if (singleSelect != undefined)
{
this.singleSelect = singleSelect;
}
this.selected = [];
this.preselected = [];
},
setDefaultIcon: function(icon)
{
this.defaultIcon = icon;
},
setStartId: function(id)
{
this.startId = id;
},
setSelectedItems: function(jsonString)
{
this.preselected = Json.evaluate(jsonString);
},
setRequestAttributes: function(attrs)
{
this.requestAttributes = attrs;
},
showSelector: function()
{
// init selector state
this.selected = [];
this.stack = [];
this.initialDisplayStyle = $(this.id + "-noitems").getStyle("display");
$(this.id + "-selector").setStyle("display", "block");
$(this.id + "-selected").empty();
$(this.id + "-selected").setStyle("display", "block");
$(this.id + "-noitems").setStyle("display", "none");
if (this.singleSelect)
{
$(this.id + "-finish").setStyle("display", "none");
}
this.preselected.each(function(item, i)
{
this.addSelectedItem(item);
}, this);
// first ajax request for the children of the start item
this.getNodeData(this.startId, null, this.populateChildren);
},
childClicked: function(index)
{
this.hidePanels();
var item = this.items[index];
// add an extra property to record the scroll position for this item
item.scrollpos = $(this.id + "-results-list").scrollTop;
this.stack.push(item); // ready for the breadcrumb redraw after the child data request
this.getNodeData(item.id, null, this.populateChildren)
},
upClicked: function()
{
this.hidePanels();
// pop the parent off
var parent = this.stack.pop();
// peek for the grandparent - we may not have a grandparent (depending on start location) - so use the
// getNodeData(parent, child, ...) call to pass in the child rather than the parent and let server calculate it
var grandParent = null;
if (this.stack.length != 0)
{
grandParent = this.stack[this.stack.length-1];
}
this.getNodeData(grandParent != null ? grandParent.id : null, grandParent == null ? parent.id : null, this.populateChildren, parent.scrollpos);
},
addItem: function(index)
{
var item;
if (index != -1)
{
item = this.items[index];
}
else
{
item = this.parent;
}
if (this.singleSelect)
{
this.selected.push(item);
this.doneClicked();
}
else
{
this.addSelectedItem(item);
// hide the Add button as this item is now added
$(this.id + "-add-" + item.id).setStyle("display", "none");
}
},
addSelectedItem: function(item)
{
// add item to list of selected items
this.selected.push(item);
// add the item to list outside the selector
var itemId = this.id + "-sel-" + item.id;
var itemDiv = new Element("div", {"id": itemId, "class": "pickerSelectedItem"});
var itemSpan = new Element("span", {"class": "pickerSelectedItemText"});
itemSpan.appendText(item.name);
itemSpan.injectInside(itemDiv);
var actionSpan = new Element("span", {"class": "pickerSelectedItemAction"});
var actionScript = "javascript:" + this.varName + ".delItem('" + item.id + "');";
var actionLink = new Element("a", {"href": actionScript});
var deleteIcon = new Element("img", {"src": getContextPath() + "/images/icons/minus.gif", "class": "pickerSelectedIcon",
"border": 0, "title": "Remove", "alt": "Remove"});
deleteIcon.injectInside(actionLink);
actionLink.injectInside(actionSpan);
actionSpan.injectInside(itemDiv);
// add mouse enter/leave enter to toggle delete icon (and toggle margin on outer div)
itemDiv.addEvent('mouseenter', function(e) {
$E('.pickerSelectedIcon', itemDiv).setStyle("opacity", 1);
});
itemDiv.addEvent('mouseleave', function(e) {
$E('.pickerSelectedIcon', itemDiv).setStyle("opacity", 0);
});
// add the item to the main selected item div
itemDiv.injectInside($(this.id + "-selected"));
// set the background image now the itemdiv has been added to the DOM (for IE)
itemDiv.setStyle("background-image", "url(" + getContextPath() + item.icon + ")");
// set opacity the style now the item has been added to the DOM (for IE)
$E('.pickerSelectedIcon', itemDiv).setStyle("opacity", 0);
// apply the effect
var fx = new Fx.Styles(itemDiv, {duration: 1000, wait: false, transition: Fx.Transitions.Quad.easeOut});
fx.start({'background-color': ['#faf7ce', '#ffffff']});
},
delItem: function(itemId)
{
// remove item from the selected items list
for (i=0; i<this.selected.length; i++)
{
if (this.selected[i].id == itemId)
{
this.selected.splice(i, 1); break;
}
}
// remove the div representing the selected item
$(this.id + "-sel-" + itemId).remove();
// unhide the Add button if visible
var addBtn = $(this.id + "-add-" + itemId);
if (addBtn != null)
{
addBtn.setStyle("display", "block");
}
},
populateBreadcrumb: function()
{
var bcpanel = $(this.id + "-nav-bread");
bcpanel.empty();
// add each item from the navigation stack to the breadcrumb
for (var i=0; i<this.stack.length; i++)
{
var div = new Element("div", {"class": "pickerNavBreadcrumbItem"});
var actionScript = "javascript:" + this.varName + ".clickBreadcumb(" + i + ");";
var actionLink = new Element("a", {"href": actionScript});
actionLink.setText(this.stack[i].name);
actionLink.injectInside(div);
div.injectInside(bcpanel);
// override left padding to indent the items appropriately
div.setStyle("padding-left", (i<<3)+2);
}
},
clickBreadcumb: function(index)
{
this.hidePanels();
var item = this.stack[index];
// remove all items under this one from the navigation stack
var removeCount = (this.stack.length - index - 1);
if (removeCount != 0)
{
this.stack.splice(index + 1, removeCount);
}
this.getNodeData(item.id, null, this.populateChildren);
},
breadcrumbToggle: function()
{
var bcpanel = $(this.id + "-nav-bread");
if (bcpanel.getChildren().length != 0)
{
if (bcpanel.getStyle("display") == "none")
{
bcpanel.setStyle("opacity", 0);
bcpanel.setStyle("display", "block");
var fx = new Fx.Styles(bcpanel, {duration: 200, wait: false, transition: Fx.Transitions.Quad.easeOut});
fx.start({'opacity': [0, 1]});
}
else
{
var fx = new Fx.Styles(bcpanel, {duration: 200, wait: false, transition: Fx.Transitions.Quad.easeOut,
onComplete: function() {bcpanel.setStyle("display", "none");}});
fx.start({'opacity': [1, 0]});
}
}
},
hidePanels: function()
{
$(this.id + "-nav-bread").setStyle("display", "none");
},
doneClicked: function()
{
var ids = "";
for (i=0; i<this.selected.length; i++)
{
if (i != 0) ids += ",";
ids += this.selected[i].id;
}
// special case for clearing out multi-select lists
if (!this.singleSelect && (ids == ""))
{
ids = "empty";
}
$(this.id + "-value").setProperty("value", ids);
document.forms[this.formClientId].submit();
return false;
},
cancelClicked: function()
{
$(this.id + "-selector").setStyle("display", "none");
$(this.id + "-selected").setStyle("display", "none");
$(this.id + "-noitems").setStyle("display", this.initialDisplayStyle);
},
populateChildren: function(response, picker, scrollpos)
{
// clear any current results
var results = $(picker.id + "-results-list");
results.empty();
// set the new parent
picker.parent = {id: response.parent.id, name: response.parent.name};
// if nav stack is empty - add the parent item as the first entry
if (picker.stack.length == 0)
{
picker.stack.push(picker.parent);
}
// if the parent is null we're at the root so hide the up link
// otherwise we need to render it with the correct details
var upLink = $(picker.id + "-nav-up");
if (picker.parent.id == null || response.parent.isroot == true)
{
upLink.setStyle("display", "none");
upLink.setProperty("href", "#");
}
else
{
upLink.setStyle("display", "block");
upLink.setProperty("href", "javascript:" + picker.varName + ".upClicked();");
}
// show what the parent next to the breadcrumb drop-down
$(picker.id + "-nav-txt").setText(picker.parent.name);
// render action for parent item (as it may be the root and not shown in child list!)
$(picker.id + "-nav-add").empty();
if (response.parent.selectable != false)
{
var isSelected = false;
for (i=0; i<picker.selected.length; i++)
{
if (picker.selected[i].id == picker.parent.id)
{
isSelected = true; break;
}
}
if (isSelected == false)
{
var actionId = picker.id + "-add-" + picker.parent.id;
var actionScript = "javascript:" + picker.varName + ".addItem(-1);";
var actionLink = new Element("a", {"href": actionScript});
var actionImg = new Element("img", {"id": actionId, "src": getContextPath() + "/images/icons/plus.gif", "class": "pickerActionButton",
"border": 0, "title": "Add", "alt": "Add"});
actionImg.injectInside(actionLink);
actionLink.injectInside($(picker.id + "-nav-add"));
// style modification for this Add button - it's inside a floating div unlike the others
if (document.all == undefined) actionImg.setStyle("vertical-align", "-18px");
}
}
// iterate through the children and render a row for each one
picker.items = [];
picker.oddRow = true;
for (var i=0; i<response.children.length; i++)
{
var item = response.children[i];
if (item.icon == undefined)
{
item.icon = picker.defaultIcon;
}
picker.items.push(item);
picker.renderResultItem(item, i);
}
// scroll back to last position if required
results.scrollTop = (scrollpos == undefined ? 0 : scrollpos);
picker.populateBreadcrumb();
},
renderResultItem: function(item, index)
{
var divClass = "pickerResultsRow " + (this.oddRow ? "pickerResultsOddRow" : "pickerResultsEvenRow");
this.oddRow = !this.oddRow;
var div = new Element("div", {"class": divClass});
// render icon
var iconSpan = new Element("span", {"class": "pickerResultIcon"});
var iconImg = new Element("img", {"src": getContextPath() + item.icon});
iconImg.injectInside(iconSpan);
iconSpan.injectInside(div);
// render actions
var isSelected = false;
if (item.selectable != false)
{
var actionsSpan = new Element("span", {"class": "pickerResultActions"});
// display Add button for the item
for (i=0; i<this.selected.length; i++)
{
if (this.selected[i].id == item.id)
{
isSelected = true; break;
}
}
// even if found in the selected list, still need to generate the button - but hide it later
var actionId = this.id + "-add-" + item.id;
var actionScript = "javascript:" + this.varName + ".addItem(" + index + ");";
var actionLink = new Element("a", {"href": actionScript});
var actionImg = new Element("img", {"id": actionId, "src": getContextPath() + "/images/icons/plus.gif", "class": "pickerActionButton",
"border": 0, "title": "Add", "alt": "Add"});
actionImg.injectInside(actionLink);
actionLink.injectInside(actionsSpan);
actionsSpan.injectInside(div);
}
// render name link
var nameSpan = new Element("span", {"class": "pickerResultName"});
var nameLink;
if (item.url == undefined)
{
var link = "javascript:" + this.varName + ".childClicked(" + index + ");";
nameLink = new Element("a", {"href": link});
}
else
{
nameLink = new Element("a", {"href": getContextPath() + item.url, "target": "new"});
}
nameLink.appendText(item.name);
nameLink.injectInside(nameSpan);
nameSpan.injectInside(div);
// add results
div.injectInside($(this.id + "-results-list"));
// hide the Add button (now this item is in the DOM) if in the selected list
if (isSelected)
{
actionImg.setStyle("display", "none");
}
},
getNodeData: function(parent, child, callback, scrollpos)
{
// show ajax wait panel
$(this.id + '-ajax-wait').setStyle('display', 'block');
$(this.id + '-results-list').setStyle('visibility', 'hidden');
var picker = this;
// execute ajax service call to retrieve list of child nodes as JSON response
new Ajax(getContextPath() + "/ajax/invoke/" + this.service +
"?parent=" + (parent != null ? parent : "") +
(child != null ? ("&child=" + child) : "") +
(this.requestAttributes!=null ? ("&" + this.requestAttributes) : ""),
{
method: 'get',
onComplete: function(r)
{
if (r.startsWith("ERROR:") == false)
{
result = Json.evaluate(r);
result.children.sort(picker.sortByName);
callback(result, picker, scrollpos);
// display results list again and hide ajax wait panel
$(picker.id + '-results-list').setStyle('visibility', 'visible');
$(picker.id + '-ajax-wait').setStyle('display', 'none');
}
else
{
// display results list again and hide ajax wait panel
$(picker.id + '-results-list').setStyle('visibility', 'visible');
$(picker.id + '-ajax-wait').setStyle('display', 'none');
// display the error
alert(r);
}
},
onFailure: function (r)
{
}
}).request();
},
sortByName: function(a, b)
{
if (a.selectable == b.selectable)
{
return ((a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0));
}
else
{
return (a.selectable == false) ? -1 : 1;
}
}
});