/* * 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.importer.ui; import java.util.EnumSet; import java.util.HashMap; import java.util.Map; import org.xwiki.gwt.user.client.FocusCommand; import org.xwiki.gwt.user.client.ui.rta.RichTextArea; import org.xwiki.gwt.user.client.ui.wizard.AbstractInteractiveWizardStep; import org.xwiki.gwt.user.client.ui.wizard.NavigationListener.NavigationDirection; import org.xwiki.gwt.wysiwyg.client.Strings; import org.xwiki.gwt.wysiwyg.client.plugin.importer.ImportServiceAsync; import org.xwiki.gwt.wysiwyg.client.plugin.importer.PasteFilter; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.event.dom.client.LoadEvent; import com.google.gwt.event.dom.client.LoadHandler; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Panel; /** * Wizard step responsible for importing copy-pasted office content. * * @version $Id: 8ed08cb019f414a10c51ac02e8dfee9bf4a7f35b $ * @since 2.0.1 */ public class ImportOfficePasteWizardStep extends AbstractInteractiveWizardStep implements LoadHandler { /** * The text area where the user can paste his content. */ private RichTextArea textArea; /** * Storage for the result of the import operation. */ private Object result; /** * Checkbox allowing the user to select whether he wants to filter out office styles or not. */ private CheckBox filterStylesCheckBox; /** * The component used to clean content copy&pasted from office documents. */ private final ImportServiceAsync importService; /** * The object used to filter the pasted document before cleaning it on the server. */ private final PasteFilter pasteFilter = GWT.create(PasteFilter.class); /** * Creates an instance of {@link ImportOfficePasteWizardStep}. * * @param importService the component used to clean content copy and pasted from office documents */ public ImportOfficePasteWizardStep(ImportServiceAsync importService) { this.importService = importService; setStepTitle(Strings.INSTANCE.importOfficePasteWizardStepTitle()); setValidDirections(EnumSet.of(NavigationDirection.CANCEL, NavigationDirection.FINISH)); setDirectionName(NavigationDirection.FINISH, Strings.INSTANCE.importWizardImportButtonCaption()); // Info label. Panel infoLabel = new FlowPanel(); infoLabel.setStyleName("xInfoLabel"); infoLabel.add(new InlineLabel(Strings.INSTANCE.importOfficePasteInfoLabel())); InlineLabel mandatoryLabel = new InlineLabel(Strings.INSTANCE.mandatory()); mandatoryLabel.addStyleName("xMandatory"); infoLabel.add(mandatoryLabel); display().add(infoLabel); // Help label. Label helpLabel = new Label(Strings.INSTANCE.importOfficePasteHelpLabel()); helpLabel.setStyleName("xHelpLabel"); display().add(helpLabel); // Text area panel. textArea = new RichTextArea(); textArea.addStyleName("xImportOfficeContentEditor"); textArea.addLoadHandler(this); display().add(textArea); // Filter styles check box. this.filterStylesCheckBox = new CheckBox(Strings.INSTANCE.importOfficeContentFilterStylesCheckBoxLabel()); // The filter styles check box should be checked by default. this.filterStylesCheckBox.setValue(true); display().add(filterStylesCheckBox); } @Override public void init(Object data, AsyncCallback< ? > cb) { textArea.setHTML(""); cb.onSuccess(null); } @Override public Object getResult() { return this.result; } /** * Sets the result of this wizard step. * * @param result the result. */ private void setResult(Object result) { this.result = result; } @Override public void onCancel() { textArea.setHTML(""); } @Override public void onSubmit(final AsyncCallback<Boolean> async) { pasteFilter.filter(textArea.getDocument()); String officeHTML = textArea.getHTML(); if (officeHTML.trim().equals("")) { async.onSuccess(false); } else { importService.cleanOfficeHTML(officeHTML, "wysiwyg", getHTMLCleaningParams(), new AsyncCallback<String>() { @Override public void onSuccess(String result) { setResult(result); async.onSuccess(true); } @Override public void onFailure(Throwable thrown) { async.onFailure(thrown); } }); } } /** * Prepares the cleaning parameters map. * * @return a {@link Map} with cleaning parameters for office importer. */ protected Map<String, String> getHTMLCleaningParams() { Map<String, String> params = new HashMap<String, String>(); if (filterStylesCheckBox.getValue()) { params.put("filterStyles", "strict"); } // For Office2007: Office2007 generates an xhtml document (when copied) which has attributes and tags of // several namespaces. But the document itself doesn't contain the namespace definitions, which causes // the HTMLCleaner (the DomSerializer) to fail while performing it's operations. As a workaround we // force HTMLCleaner to avoid parsing of namespace information. params.put("namespacesAware", Boolean.toString(false)); return params; } @Override public void onLoad(LoadEvent event) { if (event.getSource() == textArea) { // The rich text area where the content is pasted is reloaded each time this wizard step is displayed so we // use the load event to focus the text area. Note that we can't focus if the rich text area isn't loaded. // We use a deferred command in case the rich text area is loaded synchronously. Scheduler.get().scheduleDeferred(new FocusCommand(textArea)); } } }