Files
alfresco-community-repo/source/web/scripts/ajax/picker.js

476 lines
16 KiB
JavaScript

/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/*
* 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,
/* 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,
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;
}
},
setDefaultIcon: function(icon)
{
this.defaultIcon = icon;
},
setStartId: function(id)
{
this.startId = id;
},
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");
}
// first ajax request for the children of the start item
this.getChildData(this.startId, 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.getChildData(item.id, this.populateChildren)
},
upClicked: function()
{
this.hidePanels();
// pop the parent off - peek for the grandparent
var parent = this.stack.pop();
var grandParent = this.stack[this.stack.length-1];
this.getChildData(grandParent != null ? grandParent.id : null, this.populateChildren, parent.scrollpos);
},
addItem: function(index)
{
var item;
if (index != -1)
{
item = this.items[index];
}
else
{
item = this.parent;
}
// add item to list of selected items
this.selected.push(item);
if (this.singleSelect)
{
this.doneClicked();
}
else
{
// add the item to list above 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']});
// hide the Add button as this item is now added
$(this.id + "-add-" + item.id).setStyle("display", "none");
}
},
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.getChildData(item.id, 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;
}
$(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('" + picker.parent.id + "');");
}
// 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 = [];
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.oddRow = true;
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");
}
},
getChildData: function(parent, 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 : ""),
{
method: 'get',
async: false,
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');
}
},
onFailure: function (r)
{
}
}).request();
},
sortByName: function(a, b)
{
return ((a.name < b.name) ? -1 : ((a.name > b.name) ? 1 : 0));
}
});