AJAX Tag picker component

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@8027 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Mike Hatfield
2008-01-21 10:09:39 +00:00
parent 0df2f7447d
commit ff923528d1
16 changed files with 1377 additions and 98 deletions

View File

@@ -208,6 +208,78 @@ public class PickerBean
*
* The 16x16 pixel folder icon path is output as the 'icon' property for each child folder.
*/
@InvokeCommand.ResponseMimetype(value=MimetypeMap.MIMETYPE_HTML)
public void getTagNodes() throws Exception
{
FacesContext fc = FacesContext.getCurrentInstance();
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(FacesContext.getCurrentInstance(), true);
tx.begin();
Collection<ChildAssociationRef> childRefs;
NodeRef parentRef = null;
Map params = fc.getExternalContext().getRequestParameterMap();
String strParentRef = (String)params.get(ID_PARENT);
if (strParentRef == null || strParentRef.length() == 0)
{
childRefs = this.categoryService.getRootCategories(
Repository.getStoreRef(),
ContentModel.ASPECT_TAGGABLE);
}
else
{
parentRef = new NodeRef(strParentRef);
childRefs = this.categoryService.getChildren(
parentRef,
CategoryService.Mode.SUB_CATEGORIES,
CategoryService.Depth.IMMEDIATE);
}
JSONWriter out = new JSONWriter(fc.getResponseWriter());
out.startObject();
out.startValue(ID_PARENT);
out.startObject();
if (parentRef == null)
{
out.writeNullValue(ID_ID);
out.writeValue(ID_NAME, "Tags");
out.writeValue(ID_ISROOT, true);
out.writeValue(ID_SELECTABLE, false);
}
else
{
out.writeValue(ID_ID, strParentRef);
out.writeValue(ID_NAME, Repository.getNameForNode(this.internalNodeService, parentRef));
}
out.endObject();
out.endValue();
out.startValue(ID_CHILDREN);
out.startArray();
for (ChildAssociationRef ref : childRefs)
{
NodeRef nodeRef = ref.getChildRef();
out.startObject();
out.writeValue(ID_ID, nodeRef.toString());
out.writeValue(ID_NAME, Repository.getNameForNode(this.internalNodeService, nodeRef));
out.endObject();
}
out.endArray();
out.endValue();
out.endObject();
tx.commit();
}
catch (Throwable err)
{
Utils.addErrorMessage("PickerBean exception in getTagNodes()", err);
fc.getResponseWriter().write("ERROR: " + err.getMessage());
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
@InvokeCommand.ResponseMimetype(value=MimetypeMap.MIMETYPE_HTML)
public void getFolderNodes() throws Exception
{

View File

@@ -0,0 +1,107 @@
/*
* 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.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.web.bean.generator;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.alfresco.service.cmr.dictionary.PropertyDefinition;
import org.alfresco.web.app.servlet.FacesHelper;
import org.alfresco.web.ui.repo.RepoConstants;
import org.alfresco.web.ui.repo.component.UIMultiValueEditor;
import org.alfresco.web.ui.repo.component.property.PropertySheetItem;
import org.alfresco.web.ui.repo.component.property.UIPropertySheet;
/**
* Generates a category selector component.
*
* @author Mike Hatfield
*/
public class AjaxTagPickerGenerator extends BaseComponentGenerator
{
public UIComponent generate(FacesContext context, String id)
{
UIComponent component = context.getApplication().
createComponent(RepoConstants.ALFRESCO_FACES_AJAX_TAG_PICKER);
FacesHelper.setupComponentId(context, component, id);
return component;
}
@Override
@SuppressWarnings("unchecked")
protected UIComponent createComponent(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item)
{
// the category selector component is used whatever mode the property sheet is in
return generate(context, item.getName());
}
@Override
protected void setupMandatoryValidation(FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem item, UIComponent component, boolean realTimeChecking, String idSuffix)
{
if (component instanceof UIMultiValueEditor)
{
// Override the setup of the mandatory validation
// so we can send the _current_value id suffix.
// We also enable real time so the page load
// check disables the ok button if necessary, as the user
// adds or removes items from the multi value list the
// page will be refreshed and therefore re-check the status.
super.setupMandatoryValidation(context, propertySheet, item,
component, true, "_current_value");
}
else
{
// Override the setup of the mandatory validation
// so we can send the _selected id suffix.
// We also enable real time so the page load check disabled
// the ok button if necessary, as the control is used the
// page will be refreshed and therefore re-check the status.
super.setupMandatoryValidation(context, propertySheet, item,
component, true, "_selected");
}
}
@Override
protected ControlType getControlType()
{
return ControlType.SELECTOR;
}
@Override
protected UIComponent setupMultiValuePropertyIfNecessary(
FacesContext context, UIPropertySheet propertySheet,
PropertySheetItem property, PropertyDefinition propertyDef,
UIComponent component)
{
return component;
}
}

View File

@@ -51,6 +51,7 @@ public final class RepoConstants
public static final String ALFRESCO_FACES_BOOLEAN_CONVERTER = "org.alfresco.faces.BooleanLabelConverter";
public static final String ALFRESCO_FACES_MLTEXT_RENDERER = "org.alfresco.faces.MultilingualText";
public static final String ALFRESCO_FACES_MLTEXTAREA_RENDERER = "org.alfresco.faces.MultilingualTextArea";
public static final String ALFRESCO_FACES_AJAX_TAG_PICKER = "org.alfresco.faces.AjaxTagPicker";
public static final String GENERATOR_LABEL = "LabelGenerator";
public static final String GENERATOR_TEXT_FIELD = "TextFieldGenerator";

View File

@@ -61,15 +61,15 @@ import org.springframework.web.jsf.FacesContextUtils;
*/
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";
protected static final String MSG_GO_UP = "go_up";
protected static final String MSG_OK = "ok";
protected 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";
protected static final String ID_ID = "id";
protected static final String ID_NAME = "name";
protected static final String ID_ICON = "icon";
private static final String FOLDER_IMAGE_PREFIX = "/images/icons/";
protected static final String FOLDER_IMAGE_PREFIX = "/images/icons/";
/** label to be displayed before an item is selected */
protected String label = null;
@@ -407,6 +407,10 @@ public abstract class BaseAjaxItemPicker extends UIInput
{
this.label = (String)vb.getValue(getFacesContext());
}
else
{
this.label = "";
}
return this.label;
}
@@ -420,7 +424,7 @@ public abstract class BaseAjaxItemPicker extends UIInput
}
/**
* @return Returns the initial selecttion.
* @return Returns the initial selection.
*/
public String getInitialSelection()
{

View File

@@ -0,0 +1,302 @@
/*
* 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.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.web.ui.repo.component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
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.repository.Repository;
import org.alfresco.web.ui.common.Utils;
import org.springframework.web.jsf.FacesContextUtils;
/**
* @author Mike Hatfield
*/
public class UIAjaxTagPicker extends BaseAjaxItemPicker
{
private static final String MSG_CLICK_TO_SELECT_TAG = "click_to_select_tag";
@Override
public String getFamily()
{
return "org.alfresco.faces.AjaxTagPicker";
}
@Override
protected String getServiceCall()
{
return "PickerBean.getTagNodes";
}
@Override
protected String getDefaultIcon()
{
return "/images/icons/category_small.gif";
}
@Override
public Boolean getSingleSelect()
{
// Tag component is never in single select mode, but the base class needs to know this
return false;
}
@Override
public String getLabel()
{
// Tagger label only retrieved from a value binding when null
if (this.label == null)
{
super.getLabel();
}
return this.label;
}
@Override
/**
* @see javax.faces.component.UIComponentBase#encodeBegin(javax.faces.context.FacesContext)
*/
public void encodeBegin(FacesContext fc) throws IOException
{
if (isRendered() == false)
{
return;
}
ResponseWriter out = fc.getResponseWriter();
String formClientId = Utils.getParentForm(fc, this).getClientId(fc);
Map attrs = this.getAttributes();
ResourceBundle msg = Application.getBundle(fc);
// get values from submitted value or none selected
String selectedValues = null;
String selectedNames = null;
String selectedItems = null;
List<NodeRef> submitted = null;
submitted = (List<NodeRef>)getSubmittedValue();
if (submitted == null)
{
submitted = (List<NodeRef>)getValue();
}
// special case to submit empty lists on multi-select values
else if (submitted.equals("empty"))
{
submitted = null;
}
if (submitted != null)
{
UserTransaction tx = null;
try
{
tx = Repository.getUserTransaction(fc, true);
tx.begin();
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();
}
catch (Throwable err)
{
try { if (tx != null) {tx.rollback();} } catch (Exception tex) {}
}
}
// generate the Ids for our script object and containing DIV element
String divId = getId();
String objId = divId + "Obj";
// generate the script to create and init our script object
String contextPath = fc.getExternalContext().getRequestContextPath();
out.write("<script type='text/javascript'>");
out.write("function init" + divId + "() {");
out.write(" window." + objId + " = new AlfTagger('" + divId + "','" + objId + "','" + getServiceCall() +
"','" + formClientId + "');");
out.write(" window." + objId + ".setChildNavigation(false);");
if (getDefaultIcon() != null)
{
out.write(" window." + objId + ".setDefaultIcon('" + getDefaultIcon() + "');");
}
if (selectedItems != null)
{
out.write(" window." + objId + ".setSelectedItems('" + selectedItems + "');");
}
out.write("}");
out.write("window.addEvent('domready', init" + divId + ");");
out.write("</script>");
// generate the DIV structure for our component as expected by the script object
out.write("<div id='" + divId + "' class='picker'>") ;
out.write(" <input id='" + getHiddenFieldName() + "' name='" + getHiddenFieldName() + "' type='hidden' value='");
if (selectedValues != null)
{
out.write(selectedValues);
}
out.write("'>");
// current selection displayed as link and message to launch the selector
out.write(" <div id='" + divId + "-noitems'");
if (attrs.get("style") != null)
{
out.write(" style=\"");
out.write((String)attrs.get("style"));
out.write('"');
}
if (attrs.get("styleClass") != null)
{
out.write(" class=");
out.write((String)attrs.get("styleClass"));
}
out.write(">");
if (isDisabled())
{
out.write(" <span>");
if (selectedNames != null)
{
out.write(selectedNames);
}
out.write(" </span>");
}
else
{
out.write(" <span class='pickerActionButton'><a href='javascript:" + objId + ".showSelector();'>");
if (selectedNames == null)
{
if (getLabel() == "")
{
setLabel(msg.getString(MSG_CLICK_TO_SELECT_TAG));
}
out.write(getLabel());
}
else
{
out.write(selectedNames);
}
out.write(" </a></span>");
}
out.write(" </div>");
// container for item navigation
out.write(" <div id='" + divId + "-selector' class='pickerSelector'>");
out.write(" <div class='pickerResults'>");
out.write(" <div class='pickerResultsHeader'>");
out.write(" <div class='pickerNavControls'>");
out.write(" <span class='pickerNavUp'>");
out.write(" <a id='" + divId + "-nav-up' href='#'><img src='");
out.write(contextPath);
out.write("/images/icons/arrow_up.gif' border='0' alt='");
out.write(msg.getString(MSG_GO_UP));
out.write("' title='");
out.write(msg.getString(MSG_GO_UP));
out.write("'></a>");
out.write(" </span>");
out.write(" <span class='pickerNavBreadcrumb'>");
out.write(" <span id='" + divId + "-nav-txt' class='pickerNavBreadcrumbText'></span></a>");
out.write(" </span>");
out.write(" <span class='pickerNavAddTag'>");
out.write(" <span class='pickerAddTagIcon'></span>");
out.write(" <span id='" + divId + "-addTag-linkContainer' class='pickerAddTagLinkContainer'>");
out.write(" <a href='#' onclick='window." + objId + ".showAddTagForm(); return false;'>Add a tag</a>");
out.write(" </span>");
out.write(" <span id='" + divId + "-addTag-formContainer' class='pickerAddTagFormContainer'>");
out.write(" <input id='" + divId + "-addTag-box' class='pickerAddTagBox' name='" + divId + "-addTag-box' type='text'>");
out.write(" <img id='" + divId + "-addTag-ok' class='pickerAddTagImage' alt='Add' src='");
out.write(contextPath);
out.write("/images/office/action_successful.gif'>");
out.write(" <img id='" + divId + "-addTag-cancel' class='pickerAddTagImage' alt='Cancel' src='");
out.write(contextPath);
out.write("/images/office/action_failed.gif'>");
out.write(" </span>");
out.write(" </span>");
out.write(" <span id='" + divId + "-nav-add'></span>");
out.write(" </div>");
out.write(" </div>");
// container for item selection
out.write(" <div>");
out.write(" <div id='" + divId + "-ajax-wait' class='pickerAjaxWait'");
String height = getHeight();
if (height != null)
{
out.write(" style='height:" + height + "'");
}
out.write("></div>");
out.write(" <div id='" + divId + "-results-list' class='pickerResultsList'");
if (height != null)
{
out.write(" style='height:" + height + "'");
}
out.write("></div>");
out.write(" </div>");
out.write(" </div>");
// controls (OK & Cancel buttons etc.)
out.write(" <div class='pickerFinishControls'>");
out.write(" <div id='" + divId + "-finish' style='float:left' class='pickerButtons'><a href='javascript:" + objId + ".doneClicked();'>");
out.write(msg.getString(MSG_OK));
out.write("</a></div>");
out.write(" <div style='float:right' class='pickerButtons'><a href='javascript:" + objId + ".cancelClicked();'>");
out.write(msg.getString(MSG_CANCEL));
out.write("</a></div>");
out.write(" </div>");
out.write(" </div>");
// container for the selected items
out.write(" <div id='" + divId + "-selected' class='pickerSelectedItems'></div>");
out.write("</div>");
}
}

View File

@@ -0,0 +1,43 @@
/*
* 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.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
/*
* Created on 25-May-2005
*/
package org.alfresco.web.ui.repo.tag;
/**
* @author Mike Hatfield
*/
public class AjaxTagSelectorTag extends AjaxItemSelectorTag
{
/**
* @see javax.faces.webapp.UIComponentTag#getComponentType()
*/
public String getComponentType()
{
return "org.alfresco.faces.AjaxTagPicker";
}
}

View File

@@ -70,7 +70,8 @@ public class PageTag extends TagSupport
// pop-up panel helper objects
"/scripts/ajax/summary-info.js",
// ajax pickers
"/scripts/ajax/picker.js"
"/scripts/ajax/picker.js",
"/scripts/ajax/tagger.js"
};
private final static String[] CSS =