/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.gwt.user.client.ui.rta.cmd.internal; import org.xwiki.gwt.user.client.StringUtils; import org.xwiki.gwt.user.client.Cache.CacheCallback; import org.xwiki.gwt.user.client.ui.rta.RichTextArea; import com.google.gwt.core.client.JsonUtils; /** * Base class for executables that insert or update HTML elements. * * @param <C> the type of configuration object used to update the element * @param <E> the type of element that is inserted or updated * @version $Id: 026d0e3940edf06cf949da442dc4f567ca8fb243 $ */ public abstract class AbstractInsertElementExecutable<C, E extends com.google.gwt.dom.client.Element> extends InsertHTMLExecutable { /** * Creates a configuration object from a DOM element. * * @param <C> the type of configuration object returned by the read method * @param <E> the type of DOM element being read */ public interface ConfigDOMReader<C, E extends com.google.gwt.dom.client.Element> { /** * Reads the configuration from the given DOM element. * * @param element a DOM element * @return the newly created configuration object */ C read(E element); } /** * Updates a DOM element from a configuration object. * * @param <C> the type of configuration object that is used to update the DOM element * @param <E> the type of DOM element being updated */ public interface ConfigDOMWriter<C, E extends com.google.gwt.dom.client.Element> { /** * Writes the given configuration to the specified DOM element. * * @param config the configuration object used to update the DOM element * @param element the DOM element being updated */ void write(C config, E element); } /** * Creates configuration objects from JSON. * * @param <C> the type of configuration object returned by the parse method */ public interface ConfigJSONParser<C> { /** * Creates a new configuration object from its JSON representation. * * @param json the JSON representation of of a configuration object * @return a new configuration object */ C parse(String json); } /** * Serializes a configuration object to JSON. * * @param <C> the type of configuration object that is being serialized to JSON */ public interface ConfigJSONSerializer<C> { /** * Serializes the given configuration object to JSON. * * @param config the configuration object to be serialized * @return the JSON serialization */ String serialize(C config); } /** * Base class for all classes that serialize configuration objects to JSON. It includes some utility methods. * * @param <C> the type of configuration object that is being serialized to JSON */ public abstract static class AbstractConfigJSONSerializer<C> implements ConfigJSONSerializer<C> { /** * Serializes a property of the {@link ImageConfig}. * * @param property the name of the property to serialize * @param value the value of the specified property * @return the {@code property:value} JSON pair if the property value is not {@code null}, the empty string * otherwise */ protected String serialize(String property, Object value) { return value != null ? property + ":" + JsonUtils.escapeValue(value.toString()) : ""; } /** * Appends a JSON pair to the given {@link StringBuffer}. * * @param result the string buffer where to append the given pair * @param pair a {@code property:value} JSON pair */ protected void append(StringBuffer result, String pair) { if (!StringUtils.isEmpty(pair)) { if (result.length() > 0) { result.append(","); } result.append(pair); } } } /** * The object used to extract a configuration object from an element. */ protected ConfigDOMReader<C, E> configDOMReader; /** * The object used to update a DOM element from a configuration object. */ protected ConfigDOMWriter<C, E> configDOMWriter; /** * The object used to serialize a configuration object to JSON. */ protected ConfigJSONParser<C> configJSONParser; /** * The object used to create a configuration object from JSON. */ protected ConfigJSONSerializer<C> configJSONSerializer; /** * Creates a new executable that can be used to insert HTML elements in the specified rich text area. * * @param rta the execution target */ public AbstractInsertElementExecutable(RichTextArea rta) { super(rta); } @Override public boolean execute(String json) { C config = configJSONParser.parse(json); E element = getSelectedElement(); if (element == null) { // Insert a new element. element = newElement(); if (!super.execute(element)) { return false; } } // Update the selected element. write(config, element); return true; } /** * Updates the attributes of the given element based on the given configuration object. * <p> * Note: This method was added mainly to allow derived classes to adjust the configuration object before the element * is updated. * * @param config the object used to update the attributes of the given element * @param element the element whose attributes are being updated */ protected void write(C config, E element) { configDOMWriter.write(config, element); } @Override public boolean isExecuted() { // NOTE: We don't use this.getClass().getName() as cache key prefix because we want to be able to compile the // code without class meta data information. return cache.get(getCacheKeyPrefix() + "#executed", new CacheCallback<Boolean>() { public Boolean get() { return getSelectedElement() != null; } }); } @Override public String getParameter() { E selectedElement = getSelectedElement(); if (selectedElement == null) { return null; } return configJSONSerializer.serialize(configDOMReader.read(selectedElement)); } /** * @return the text to prefix all cache keys used by this class */ protected abstract String getCacheKeyPrefix(); /** * @return the selected element, {@code null} if no element is selected */ protected abstract E getSelectedElement(); /** * @return a new element to be inserted */ protected abstract E newElement(); }