diff --git a/source/java/org/alfresco/web/ui/repo/component/BaseAjaxItemPicker.java b/source/java/org/alfresco/web/ui/repo/component/BaseAjaxItemPicker.java index e50a851df8..b16f67e340 100644 --- a/source/java/org/alfresco/web/ui/repo/component/BaseAjaxItemPicker.java +++ b/source/java/org/alfresco/web/ui/repo/component/BaseAjaxItemPicker.java @@ -25,6 +25,7 @@ package org.alfresco.web.ui.repo.component; import java.io.IOException; +import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -37,10 +38,12 @@ import javax.faces.context.ResponseWriter; import javax.faces.el.ValueBinding; import javax.transaction.UserTransaction; +import org.alfresco.model.ApplicationModel; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.web.app.Application; +import org.alfresco.web.bean.ajax.JSONWriter; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.ui.common.Utils; import org.springframework.web.jsf.FacesContextUtils; @@ -53,6 +56,12 @@ public abstract class BaseAjaxItemPicker extends UIInput private static final String MSG_GO_UP = "go_up"; private static final String MSG_OK = "ok"; private static final String MSG_CANCEL = "cancel"; + + private static final String ID_ID = "id"; + private static final String ID_NAME = "name"; + private static final String ID_ICON = "icon"; + + private static final String FOLDER_IMAGE_PREFIX = "/images/icons/"; /** label to be displayed before an item is selected */ protected String label = null; @@ -161,6 +170,7 @@ public abstract class BaseAjaxItemPicker extends UIInput // get values from submitted value or none selected String selectedValues = null; String selectedNames = null; + String selectedItems = null; List submitted = null; if (getSingleSelect() == true) { @@ -190,6 +200,11 @@ public abstract class BaseAjaxItemPicker extends UIInput { submitted = (List)getValue(); } + // special case to submit empty lists on multi-select values + else if (submitted.equals("empty")) + { + submitted = null; + } } if (submitted != null) { @@ -201,21 +216,26 @@ public abstract class BaseAjaxItemPicker extends UIInput StringBuilder nameBuf = new StringBuilder(128); StringBuilder valueBuf = new StringBuilder(128); + StringBuilder itemBuf = new StringBuilder(256); NodeService nodeService = (NodeService)FacesContextUtils.getRequiredWebApplicationContext( fc).getBean("nodeService"); for (NodeRef value : submitted) { String name = (String)nodeService.getProperty(value, ContentModel.PROP_NAME); + String icon = (String)nodeService.getProperty(value, ApplicationModel.PROP_ICON); if (nameBuf.length() != 0) { nameBuf.append(", "); valueBuf.append(","); + itemBuf.append(","); } nameBuf.append(name); valueBuf.append(value.toString()); + itemBuf.append(getItemJson(value.toString(), name, icon)); } selectedNames = nameBuf.toString(); selectedValues = valueBuf.toString(); + selectedItems = "[" + itemBuf.toString() + "]"; // commit the transaction tx.commit(); @@ -244,6 +264,10 @@ public abstract class BaseAjaxItemPicker extends UIInput { out.write(" window." + objId + ".setDefaultIcon('" + getDefaultIcon() + "');"); } + if ((!getSingleSelect()) && (selectedItems != null)) + { + out.write(" window." + objId + ".setSelectedItems('" + selectedItems + "');"); + } out.write("}"); out.write("window.addEvent('domready', init" + divId + ");"); out.write(""); @@ -494,4 +518,30 @@ public abstract class BaseAjaxItemPicker extends UIInput { return this.getId() + "-value"; } + + /** + * Returns Json string representing an already-selected item. + * + * @return hidden field name + */ + protected String getItemJson(String id, String name, String icon) + { + String itemJson = ""; + StringWriter item = new StringWriter(128); + JSONWriter json = new JSONWriter(item); + + try + { + json.startObject(); + json.writeValue(ID_ID, id); + json.writeValue(ID_NAME, name); + json.writeValue(ID_ICON, (icon != null ? FOLDER_IMAGE_PREFIX + icon + "-16.gif" : getDefaultIcon())); + json.endObject(); + } + catch (Throwable err) + { + } + itemJson = item.toString(); + return itemJson; + } } diff --git a/source/web/scripts/ajax/picker.js b/source/web/scripts/ajax/picker.js index d70f22ec10..70714e7d6c 100644 --- a/source/web/scripts/ajax/picker.js +++ b/source/web/scripts/ajax/picker.js @@ -38,6 +38,9 @@ var AlfPicker = new Class( /* list of items currently selected */ selected: null, + + /* list of items pre-selected */ + preselected: null, /* the current parent being shown */ parent: null, @@ -73,6 +76,8 @@ var AlfPicker = new Class( { this.singleSelect = singleSelect; } + this.selected = []; + this.preselected = []; }, setDefaultIcon: function(icon) @@ -85,6 +90,11 @@ var AlfPicker = new Class( this.startId = id; }, + setSelectedItems: function(jsonString) + { + this.preselected = Json.evaluate(jsonString); + }, + showSelector: function() { // init selector state @@ -101,6 +111,11 @@ var AlfPicker = new Class( $(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.getChildData(this.startId, this.populateChildren); }, @@ -136,56 +151,61 @@ var AlfPicker = new Class( item = this.parent; } - // add item to list of selected items - this.selected.push(item); - if (this.singleSelect) { + this.selected.push(item); 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']}); - + 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) { @@ -278,6 +298,13 @@ var AlfPicker = new Class( 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(); @@ -351,6 +378,8 @@ var AlfPicker = new Class( // iterate through the children and render a row for each one picker.items = []; + picker.oddRow = true; + for (var i=0; i