package er.taggable.components; import com.webobjects.appserver.WOContext; import com.webobjects.appserver.WOResponse; import com.webobjects.eocontrol.EOEditingContext; import com.webobjects.eocontrol.EOQualifier; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSComparator; import com.webobjects.foundation.NSDictionary; import com.webobjects.foundation.NSMutableArray; import er.extensions.components.ERXComponent; import er.extensions.eof.ERXEC; import er.extensions.eof.ERXQ; import er.extensions.foundation.ERXArrayUtilities; import er.taggable.ERTaggableEntity; /** * ERTagCloud provides a simple tag cloud view. The contents of this * component will be used as the renderer for each tag. You can use * the example css file ERTagCloud.css for default styling. By default * the class names will be "tagCloud1", "tagCloud2", etc. * * As an example: * * <code> * <wo:ERTagCloud entityName = "InventoryItem" tag = "$tag" tagClass = "$tagClass"> * <wo:WOGenericContainer elementName = "span" class = "$tagClass"><wo:str value = "$tag"/></wo:WOGenericContainer> * </wo:ERTagCloud> * </code> * * @binding tag the name of the current tag being rendered * @binding tagClass the class name of the current tag * @binding entityName the name of the entity to load tags for * @binding limit the maximum number of tags to show * @binding minimum the minimum tag count required for a tag to be shown * @binding categories the tag category names to use (NSArray of Strings) * @binding categoryCount the number of categories to split into (default 5) * @binding tagClassPrefix the prefix to prepend to the tag cloud class name ("tagCloud" by default) * @binding cache if false, the computation of the tag cloud is not cached (this is EXPENSIVE) * @binding additionalQualifier an optional restricting qualifier * * @binding shouldResetTagCloud forces recalculation of the tag cloud when the binding evaluates to true. * After recalculation, the binding will be set to false again. * @author mschrag */ public class ERTagCloud extends ERXComponent { /** * Do I need to update serialVersionUID? * See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the * <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a> */ private static final long serialVersionUID = 1L; private NSDictionary<String, String> _tagCloud; private String _repetitionTag; public ERTagCloud(WOContext context) { super(context); } @Override public boolean synchronizesVariablesWithBindings() { return false; } @SuppressWarnings( { "cast", "unchecked" }) public NSArray<String> tagNames() { return (NSArray<String>) ERXArrayUtilities.sortedArrayUsingComparator(tagCloud().allKeys(), NSComparator.AscendingStringComparator); } public String entityName() { return stringValueForBinding("entityName"); } public void setRepetitionTag(String repetitionTag) { _repetitionTag = repetitionTag; setValueForBinding(_repetitionTag, "tag"); setValueForBinding(tagClass(), "tagClass"); } public String repetitionTag() { return _repetitionTag; } public String tagClass() { return _tagCloud.objectForKey(_repetitionTag); } public int minimum() { return intValueForBinding("minimum", -1); } public int limit() { return intValueForBinding("limit", 100); } public int categoryCount() { return intValueForBinding("categoryCount", 5); } public EOQualifier additionalQualifier() { return (EOQualifier) valueForBinding("additionalQualifier"); } @SuppressWarnings("unchecked") public NSArray<String> categories() { return (NSArray<String>) valueForBinding("categories"); } public String tagClassPrefix() { return stringValueForBinding("tagClassPrefix", "tagCloud"); } public NSDictionary<String, String> tagCloud() { if (_tagCloud == null || !booleanValueForBinding("cache", true)) { EOEditingContext editingContext = ERXEC.newEditingContext(); ERTaggableEntity<?> taggableEntity = ERTaggableEntity.taggableEntity(entityName()); NSDictionary<String, Integer> tagCount; int limit = limit(); int minimum = minimum(); if (limit == -1 && minimum == -1) { tagCount = taggableEntity.tagCount(editingContext, -1, additionalQualifier()); } else if (minimum == -1) { tagCount = taggableEntity.tagCount(editingContext, limit, additionalQualifier()); } else { tagCount = taggableEntity.tagCount(editingContext, ERXQ.GTEQ, minimum, limit, additionalQualifier()); } NSArray<String> categories = categories(); if (categories == null) { NSMutableArray<String> mutableCategories = new NSMutableArray<>(); int categoryCount = categoryCount(); for (int i = 1; i <= categoryCount; i++) { mutableCategories.addObject(tagClassPrefix() + i); } categories = mutableCategories; } _tagCloud = taggableEntity.cloud(tagCount, categories); } return _tagCloud; } @Override protected void preAppendToResponse(WOResponse response, WOContext context) { if (booleanValueForBinding("shouldResetTagCloud")) { _tagCloud = null; if (canSetValueForBinding("shouldResetTagCloud")) { setValueForBinding(false, "shouldResetTagCloud"); } } } }