/* * 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.wysiwyg.client.plugin.image; import org.xwiki.gwt.dom.client.Element; import org.xwiki.gwt.user.client.Config; import org.xwiki.gwt.user.client.ui.rta.RichTextArea; import org.xwiki.gwt.user.client.ui.rta.cmd.Command; import org.xwiki.gwt.user.client.ui.wizard.Wizard; import org.xwiki.gwt.user.client.ui.wizard.WizardListener; import org.xwiki.gwt.wysiwyg.client.Images; import org.xwiki.gwt.wysiwyg.client.Strings; import org.xwiki.gwt.wysiwyg.client.plugin.image.exec.InsertImageExecutable; import org.xwiki.gwt.wysiwyg.client.plugin.image.ui.ImageWizard; import org.xwiki.gwt.wysiwyg.client.plugin.image.ui.ImageWizard.ImageWizardStep; import org.xwiki.gwt.wysiwyg.client.plugin.internal.AbstractPlugin; import org.xwiki.gwt.wysiwyg.client.plugin.internal.FocusWidgetUIExtension; import org.xwiki.gwt.wysiwyg.client.wiki.WikiServiceAsync; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.PushButton; /** * Rich text editor plug-in for inserting images, using a dialog to get image data settings from the user. It installs * one button in the toolbar, to be used for both insert and edit image actions. * * @version $Id: 7e94c6e9e3f1af237f8fabe74c5b0d2f70fca8e5 $ */ public class ImagePlugin extends AbstractPlugin implements ClickHandler, WizardListener { /** * Image toolbar button. */ private PushButton imageButton; /** * The toolbar extension used to add the link buttons to the toolbar. <br> * TODO: move this in its own extension, just like {@link ImageMenuExtension} */ private final FocusWidgetUIExtension toolBarExtension = new FocusWidgetUIExtension("toolbar"); /** * The menu extension of this plugin. */ private ImageMenuExtension menuExtension; /** * Image medadata extractor, to handle the images metadata. */ private ImageMetaDataExtractor metaDataExtractor; /** * Behavior adjuster to handle the images correctly. */ private ImageBehaviorAdjuster behaviorAdjuster; /** * The image insert or edit wizard. */ private ImageWizard imageWizard; /** * The service used to access the wiki. */ private final WikiServiceAsync wikiService; /** * The object used to serialize an {@link ImageConfig} instance to JSON. */ private final ImageConfigJSONSerializer imageConfigJSONSerializer = new ImageConfigJSONSerializer(); /** * The object used to create an {@link ImageConfig} from JSON. */ private final ImageConfigJSONParser imageConfigJSONParser = new ImageConfigJSONParser(); /** * Create a new image plugin that used the specified wiki service. * * @param wikiService the service used to access the wiki */ public ImagePlugin(WikiServiceAsync wikiService) { this.wikiService = wikiService; } @Override public void init(RichTextArea textArea, Config config) { super.init(textArea, config); // register the custom command textArea.getCommandManager().registerCommand(Command.INSERT_IMAGE, new InsertImageExecutable(textArea)); // add the toolbar extension if (getTextArea().getCommandManager().isSupported(Command.INSERT_IMAGE)) { imageButton = new PushButton(new Image(Images.INSTANCE.image())); saveRegistration(imageButton.addClickHandler(this)); imageButton.setTitle(Strings.INSTANCE.imageTooltip()); toolBarExtension.addFeature("image", imageButton); getUIExtensionList().add(toolBarExtension); // add the menu extension menuExtension = new ImageMenuExtension(this); getUIExtensionList().add(menuExtension); // Hack: We can access the menus where each menu item was placed only after the main menu bar is // initialized, which happens after all the plugins are loaded. Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { menuExtension.registerAttachHandlers(); } }); imageWizard = new ImageWizard(getConfig(), wikiService); imageWizard.addWizardListener(this); } // Create an image metadata extractor for this text area metaDataExtractor = new ImageMetaDataExtractor(); // do the initial extracting on the loaded document metaDataExtractor.onInnerHTMLChange((Element) getTextArea().getDocument().getDocumentElement()); getTextArea().getDocument().addInnerHTMLListener(metaDataExtractor); // Create an image behavior adjuster for this text area behaviorAdjuster = new ImageBehaviorAdjuster(); behaviorAdjuster.setTextArea(getTextArea()); saveRegistration(getTextArea().addKeyDownHandler(behaviorAdjuster)); saveRegistration(getTextArea().addKeyUpHandler(behaviorAdjuster)); saveRegistration(getTextArea().addKeyPressHandler(behaviorAdjuster)); } @Override public void destroy() { if (imageButton != null) { imageButton.removeFromParent(); imageButton = null; } toolBarExtension.clearFeatures(); if (menuExtension != null) { menuExtension.clearFeatures(); } // If a metadata extractor was created and setup, remove it if (metaDataExtractor != null) { getTextArea().getDocument().removeInnerHTMLListener(metaDataExtractor); metaDataExtractor = null; } behaviorAdjuster = null; super.destroy(); } @Override public void onClick(ClickEvent event) { if (event.getSource() == imageButton) { onImage(); } } /** * Function to handle the image event, when the tool bar button is clicked or the menu command is issued: either * create a new image, or edit an existing image. */ public void onImage() { ImageConfig imageConfig; String imageJSON = getTextArea().getCommandManager().getStringValue(Command.INSERT_IMAGE); String startStep = ImageWizardStep.ATTACHED_IMAGE_SELECTOR.toString(); if (imageJSON != null) { startStep = ImageWizardStep.IMAGE_REFERENCE_PARSER.toString(); imageConfig = imageConfigJSONParser.parse(imageJSON); } else { imageConfig = new ImageConfig(); imageConfig.setAltText(getTextArea().getDocument().getSelection().getRangeAt(0).toString()); } imageWizard.start(startStep, imageConfig); } /** * Start the edit image wizard. */ public void onImageEdit() { String imageJSON = getTextArea().getCommandManager().getStringValue(Command.INSERT_IMAGE); ImageConfig imageConfig = imageConfigJSONParser.parse(imageJSON); imageWizard.start(ImageWizardStep.IMAGE_REFERENCE_PARSER.toString(), imageConfig); } /** * Start the insert attached image wizard. */ public void onAttachedImage() { ImageConfig imageConfig = new ImageConfig(); imageConfig.setAltText(getTextArea().getDocument().getSelection().getRangeAt(0).toString()); imageWizard.start(ImageWizardStep.ATTACHED_IMAGE_SELECTOR.toString(), imageConfig); } /** * Start the insert external image wizard. */ public void onURLImage() { ImageConfig imageConfig = new ImageConfig(); imageConfig.setAltText(getTextArea().getDocument().getSelection().getRangeAt(0).toString()); imageWizard.start(ImageWizardStep.URL_IMAGE_SELECTOR.toString(), imageConfig); } /** * Removes the selection if the insert image command is executed. */ public void onImageRemove() { if (getTextArea().getCommandManager().isExecuted(Command.INSERT_IMAGE)) { getTextArea().setFocus(true); getTextArea().getCommandManager().execute(Command.DELETE); } } @Override public void onFinish(Wizard sender, Object result) { getTextArea().setFocus(true); String imageJSON = imageConfigJSONSerializer.serialize((ImageConfig) result); getTextArea().getCommandManager().execute(Command.INSERT_IMAGE, imageJSON); } @Override public void onCancel(Wizard sender) { // return the focus to the text area getTextArea().setFocus(true); } }