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.appserver.ERXResponseRewriter;
import er.extensions.eof.ERXQ;
import er.extensions.foundation.ERXArrayUtilities;
import er.extensions.foundation.ERXStringUtilities;
import er.taggable.ERTaggable;
import er.taggable.ERTaggableEntity;
import er.taggable.model.ERTag;
/**
* ERTagField implements a fancy del.icio.us-style javascript-enabled
* tagging text field with tab completion, toggling pickers, etc. If
* you have a large tagset, you should not use this component, because
* it renders all of the available tags for the user to choose from.
*
* @author mschrag
* @binding taggable the ERTaggable to manage
* @binding limit the maximum number of tags to show
* @binding minimum the minimum tag count required for a tag to be shown
* @binding size the size of the text field. Defaults to 60.
* @binding class the css class of the text field
* @binding style the css style of the text field
* @binding id the dom ID of the text field
* @binding additionalQualifier an optional restricting qualifier
*/
public class ERTagField extends er.extensions.components.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 String _id;
private NSArray<String> _availableTags;
private String _tags;
private ERTaggable<?> _taggable;
public ERTagField(WOContext context) {
super(context);
}
protected void clearCacheIfNecessary() {
ERTaggable<?> taggable = taggable();
if (taggable == null || (taggable != _taggable && !taggable.equals(_taggable))) {
_tags = null;
_availableTags = null;
_taggable = taggable;
}
}
public ERTaggable<?> taggable() {
return (ERTaggable<?>) valueForBinding("taggable");
}
public String size() {
String size;
if (hasBinding("size")) {
size = stringValueForBinding("size");
}
else {
size = "60";
}
return size;
}
public int minimum() {
return intValueForBinding("minimum", -1);
}
public int limit() {
return intValueForBinding("limit", -1);
}
public EOQualifier additionalQualifier() {
return (EOQualifier) valueForBinding("additionalQualifier");
}
public NSArray<String> availableTags() {
clearCacheIfNecessary();
if (_availableTags == null) {
EOEditingContext editingContext = taggable().item().editingContext();
int minimum = minimum();
int limit = limit();
NSArray<String> availableTags;
if (minimum == -1) {
NSDictionary<String, Integer> tagCount = taggable().taggableEntity().tagCount(editingContext, limit, additionalQualifier());
availableTags = tagCount.allKeys();
}
else {
NSDictionary<String, Integer> tagCount = taggable().taggableEntity().tagCount(editingContext, ERXQ.GTEQ, minimum, limit, additionalQualifier());
availableTags = tagCount.allKeys();
}
_availableTags = ERXArrayUtilities.sortedArrayUsingComparator(availableTags, NSComparator.AscendingStringComparator);
}
return _availableTags;
}
public String javascriptAvailableTags() {
StringBuilder sb = new StringBuilder();
sb.append('[');
NSMutableArray<String> availableTags = availableTags().mutableClone();
int availableTagsCount = availableTags.count();
if (availableTagsCount > 0) {
for (int tagNum = 0; tagNum < availableTagsCount; tagNum ++) {
String availableTag = availableTags.objectAtIndex(tagNum);
availableTag = availableTag.replaceAll("'", "\\\\'");
availableTag = ERTag.escapeTagNamed(availableTag);
availableTags.replaceObjectAtIndex(availableTag, tagNum);
}
sb.append('\'');
sb.append(availableTags.componentsJoinedByString("','"));
sb.append('\'');
}
sb.append(']');
return sb.toString();
}
public String tags() {
clearCacheIfNecessary();
if (_tags == null || true) {
String separator = " ";
NSMutableArray<String> tagNames = taggable().tagNames().mutableClone();
if (ERTaggableEntity.isWhitespaceSeparator(separator)) {
int tagsCount = tagNames.count();
for (int tagNum = 0; tagNum < tagsCount; tagNum ++) {
String tagName = tagNames.objectAtIndex(tagNum);
tagNames.replaceObjectAtIndex(ERTag.escapeTagNamed(tagName), tagNum);
}
}
_tags = tagNames.componentsJoinedByString(separator);
if (_tags.length() > 0) {
_tags += separator;
}
}
return _tags;
}
public void setTags(String tags) {
clearCacheIfNecessary();
if (tags == null || (tags != _tags && !tags.equals(_tags))) {
taggable().setTags(tags);
_tags = tags;
_availableTags = null;
}
}
public String id() {
if (_id == null) {
_id = stringValueForBinding("id");
if (_id == null) {
_id = ERXStringUtilities.safeIdentifierName(context().elementID());
}
}
return _id;
}
public String tagsID() {
return id() + "_tags";
}
@Override
public boolean synchronizesVariablesWithBindings() {
return false;
}
@Override
public void appendToResponse(WOResponse response, WOContext context) {
ERXResponseRewriter.addScriptResourceInHead(response, context, "Ajax", "prototype.js");
ERXResponseRewriter.addScriptResourceInHead(response, context, "ERTaggable", "ERTagField.js");
ERXResponseRewriter.addStylesheetResourceInHead(response, context, "ERTaggable", "ERTagField.css");
super.appendToResponse(response, context);
}
}