/*
* Copyright (c) 2009-2010 Lockheed Martin Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.eurekastreams.web.client.ui.common.form.elements;
import java.io.Serializable;
import org.eurekastreams.web.client.ui.pages.master.StaticResourceBundle;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextArea;
/**
* RichText Text Area.
*
*/
public class RichTextAreaFormElement extends FlowPanel implements FormElement
{
/**
* The default width of the form element.
*/
private static final int DEFAULT_WIDTH = 400;
/**
* The delay in ms before the reinitialize commands run.
*/
private static final int REINITIALIZE_DELAY = 10;
/**
* The text box.
*/
private TextArea textArea = new TextArea();
/**
* The label.
*/
private Label label = new Label();
/**
* Puts a (required) on the form.
*/
private Label requiredLabel = new Label();
/**
* instructions for the element.
*/
private Label instructions = new Label();
/**
* The key that this corresponds to in the model.
*/
private String key = "";
/**
* The text value in the text box.
*/
private String textValue = "";
/**
* Creates a RichText TextArea Form element.
*
* @param labelVal
* The label test.
* @param inKey
* The value name of the element.
* @param value
* The value of the element.
* @param inInstructions
* The instructions for the element.
* @param required
* If the field is required.
*/
public RichTextAreaFormElement(final String labelVal, final String inKey, final String value,
final String inInstructions, final boolean required)
{
this(labelVal, inKey, value, inInstructions, DEFAULT_WIDTH, required);
}
/**
* Creates a RichText TextArea Form element.
*
* @param labelVal
* The label test.
* @param inKey
* The value name of the element.
* @param value
* The value of the element.
* @param inInstructions
* The instructions for the element.
* @param width
* The width in pixels of the form element.
* @param required
* If the field is required.
*/
public RichTextAreaFormElement(final String labelVal, final String inKey, final String value,
final String inInstructions, final int width, final boolean required)
{
key = inKey;
label.setText(labelVal);
label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().formLabel());
textArea.setText(value);
// Add random int to ID to prevent bug where text areas are rendered twice
// when user leaves page and then comes back without refreshing.
textArea.getElement().setId(inKey + Random.nextInt());
this.addStyleName(StaticResourceBundle.INSTANCE.coreCss().yuiSkinSam());
if (required)
{
requiredLabel.addStyleName(StaticResourceBundle.INSTANCE.coreCss().requiredFormLabel());
requiredLabel.setText("(required)");
}
this.add(label);
this.add(requiredLabel);
this.add(textArea);
if (inInstructions != null && !inInstructions.isEmpty())
{
instructions.addStyleName(StaticResourceBundle.INSTANCE.coreCss().formInstructions());
instructions.setText(inInstructions);
this.add(instructions);
}
setUpRTE(textArea.getElement().getId(), width + "px");
}
/**
* Sets the value the text editor should have when it comes back from being hidden.
*/
@Override
protected void onDetach()
{
textValue = getValue().toString();
super.onDetach();
}
/**
* Reinitializes the text editor with the value it should have, and calls Show to fix bugs from hiding it.
*/
@Override
protected void onAttach()
{
DeferredCommand.addCommand(new Command()
{
public void execute()
{
// There is a race condition here between the time the text area breaks and
// the time that the deferred command is ran. Adding this timer helps to make sure
// that this occurs last.
Timer delay = new Timer()
{
public void run()
{
if (textValue != "")
{
setEditorHtml(textArea.getElement().getId(), textValue);
showEditor(textArea.getElement().getId());
}
}
};
// Delay for 10 ms.
delay.schedule(REINITIALIZE_DELAY);
}
});
super.onAttach();
}
/**
* Clear the editor.
*
* Note: Clearing the editor still leaves a space in the editor. YUI does this because to set the cursor something
* has to be in the element.
*/
public void clearEditor()
{
clearEditorNative(textArea.getElement().getId());
}
/**
* get key.
*
* @return key.
*/
public String getKey()
{
return key;
}
/**
* get value.
*
* @return value.
*/
public Serializable getValue()
{
if (textArea.isAttached())
{
saveEditorHtml(textArea.getElement().getId());
}
return textArea.getValue();
}
/**
* Gets called if this element has an error.
*
* @param errMessage
* the error Message.
*/
public void onError(final String errMessage)
{
label.addStyleName(StaticResourceBundle.INSTANCE.coreCss().formError());
}
/**
* Gets called if this element was successful.
*/
public void onSuccess()
{
label.removeStyleName(StaticResourceBundle.INSTANCE.coreCss().formError());
}
/**
* @return if the richtext area is empty.
*/
public boolean isEmpty()
{
return stripHTML((String) this.getValue()).trim().isEmpty();
}
/**
* When run it sets up the RTA.
*
* @param targetTextAreaId
* The ID of the element you want to setup.
* @param controlWidth
* The width of the element in pixels.
*/
private native void setUpRTE(final String targetTextAreaId, final String controlWidth)
/*-{
var editorConfig={
height: '130px',
width: controlWidth,
animate: true,
dompath: false,
extracss: 'body {background-color:white;font-family: "Lucida Sans Unicode", "Lucida Sans",'
+ '"Verdana", "Tahoma", "Geneva", "Kalimati", sans-serif ! important;font-size:14px}',
toolbar: {
grouplabels: false,
buttons: [
{ group: 'textstyle', label: '',
buttons: [
{ type: 'push', label: 'Bold', value: 'bold' },
{ type: 'push', label: 'Italic', value: 'italic' },
{ type: 'push', label: 'Underline', value: 'underline' },
{ type: 'separator' },
{ type: 'push', label: 'Create an Unordered List', value:'insertunorderedlist'},
{ type: 'push', label: 'Create an Ordered List', value:'insertorderedlist'},
{ type: 'separator' },
{ type: 'push', label: 'HTML Link CTRL + SHIFT +L', value:'createlink'}
]
}
]
}
};
var editorKey = 'editor_' + targetTextAreaId;
if (!$wnd[editorKey]) {
var editor = new $wnd.YAHOO.widget.SimpleEditor(targetTextAreaId, editorConfig);
$wnd[editorKey] = editor;
$wnd['saveEditor_' + targetTextAreaId] = function() {
editor.saveHTML();
}
$wnd['clearEditor_' + targetTextAreaId] = function() {
editor.clearEditorDoc();
}
$wnd['showEditor_' + targetTextAreaId] = function() {
editor.show();
}
$wnd['setEditor_' + targetTextAreaId] = function(value) {
editor.setEditorHTML(value);
}
}
$wnd[editorKey].render();
}-*/;
/**
* Save the editor HTML.
*
* @param targetTextAreaId
* the text area id.
*/
private native void saveEditorHtml(final String targetTextAreaId)
/*-{
$wnd['saveEditor_' + targetTextAreaId]();
}-*/;
/**
* Clear the editor HTML.
*
* @param targetTextAreaId
* the text area id.
*/
private native void clearEditorNative(final String targetTextAreaId)
/*-{
$wnd['clearEditor_' + targetTextAreaId]();
}-*/;
/**
* Show the editor (fixes bugs when the editor is hidden).
*
* @param targetTextAreaId
* the text area id.
*/
private native void showEditor(final String targetTextAreaId)
/*-{
$wnd['showEditor_' + targetTextAreaId]();
}-*/;
/**
* Sets the editor's text value.
*
* @param targetTextAreaId
* the text area id.
* @param value
* the text area value.
*/
private native void setEditorHtml(final String targetTextAreaId, final String value)
/*-{
$wnd['setEditor_' + targetTextAreaId](value);
}-*/;
/**
* strips html out of String.
*
* @param htmlString
* the string to strip.
* @return a stripped string.
*/
private String stripHTML(final String htmlString)
{
String stripHTML =
"<\\/?\\w+((\\s+(\\w|\\w[\\w-]*\\w)"
+ "(\\s*=\\s*(?:\\\".*?\\\"|\'.*?\'|[^\'\\\">\\s]+))?)+\\s*|\\s*)\\/?>";
String nohtml = htmlString.replaceAll(stripHTML, "");
nohtml = nohtml.replaceAll(" ", "");
return nohtml;
}
}