/**
* Copyright 2010 Google Inc.
*
* 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.waveprotocol.wave.client.doodad.attachment;
import com.google.gwt.user.client.Window;
import org.waveprotocol.wave.client.doodad.attachment.ImageThumbnail.ThumbnailActionHandler;
import org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailRenderer;
import org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailView.ImageThumbnailViewListener;
import org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailWrapper;
import org.waveprotocol.wave.client.editor.NodeEventHandlerImpl;
import org.waveprotocol.wave.client.editor.content.ContentElement;
import org.waveprotocol.wave.client.editor.content.ContentNode;
import org.waveprotocol.wave.client.editor.event.EditorEvent;
import org.waveprotocol.wave.common.logging.LoggerBundle;
import org.waveprotocol.wave.model.document.util.Point;
/**
* Node event handler for ImageThumbnail.
*
* NOTE(user): We can probably make this more general and use it for different
* types of doodads.
*
*/
final class ImageThumbnailNodeEventHandler extends NodeEventHandlerImpl {
private final ThumbnailActionHandler actionHandler;
private final LoggerBundle logger;
ImageThumbnailRenderer renderer;
ImageThumbnailNodeEventHandler(LoggerBundle logger,
ImageThumbnailRenderer renderer, ThumbnailActionHandler actionHandler) {
this.logger = logger;
this.renderer = renderer;
this.actionHandler = actionHandler;
}
@SuppressWarnings("unchecked") // Limitations of java's type system
@Override
public void onActivated(final ContentElement element) {
renderer.getView(element).setListener(new ImageThumbnailViewListener() {
public void onRequestSetFullSizeMode(boolean isOn) {
element.getMutableDoc().setElementAttribute(element,
ImageThumbnail.STYLE_ATTR, isOn ? ImageThumbnail.STYLE_FULL : null);
}
public void onClickImage() {
ImageThumbnailWrapper thumbnail = ImageThumbnailWrapper.of(element);
if (!actionHandler.onClick(thumbnail)) {
String url = thumbnail.getAttachment().getAttachmentUrl();
if (url != null) {
// TODO(nigeltao): Is it necessary to open a window here? All attachments are set to
// content-disposition=attachment which means the browser should download them.
// The current implementation means we always get a blank tab.
Window.open(url, "_blank", "");
}
}
}
});
}
/**
* Removes the entire thumbnail on backspace after
*
* {@inheritDoc}
*/
@Override
public boolean handleBackspaceAfterNode(ContentElement element, EditorEvent event) {
logger.trace().log("backspace after", element);
element.getMutableDoc().deleteNode(element);
return true;
}
/**
* Removes the entire thumbnail on delete before
*
* {@inheritDoc}
*/
@Override
public boolean handleDeleteBeforeNode(ContentElement element, EditorEvent event) {
logger.trace().log("Delete before", element);
element.getMutableDoc().deleteNode(element);
return true;
}
/**
* Handles a left arrow that occurred with the caret immediately
* after this node, by moving caret to end of caption
*
* {@inheritDoc}
*/
@Override
public boolean handleLeftAfterNode(ContentElement element, EditorEvent event) {
element.getSelectionHelper().setCaret(
Point.<ContentNode> end(getCaption(element)));
return true;
}
/**
* Handles a right arrow that occurred with the caret immediately
* before this node, by moving caret to beginning of caption
*
* {@inheritDoc}
*/
@Override
public boolean handleRightBeforeNode(ContentElement element, EditorEvent event) {
element.getSelectionHelper().setCaret(
Point.start(element.getRenderedContentView(), getCaption(element)));
return true;
}
@Override
public boolean handleLeftAtBeginning(ContentElement element, EditorEvent event) {
// NOTE(danilatos): The use of location mapper will normalise into text nodes,
// masking a weird firefox selection bug except when there is no adjacent text node.
element.getSelectionHelper().setCaret(element.getLocationMapper().getLocation(
Point.before(element.getRenderedContentView(), element)));
return true;
}
@Override
public boolean handleRightAtEnd(ContentElement element, EditorEvent event) {
// NOTE(danilatos): The use of location mapper will normalise into text nodes,
// masking a weird firefox selection bug except when there is no adjacent text node.
element.getSelectionHelper().setCaret(element.getLocationMapper().getLocation(
Point.after(element.getRenderedContentView(), element)));
return true;
}
private ContentElement getCaption(ContentElement element) {
// TODO(danilatos): Enforce correctness via schema
return (ContentElement) element.getFirstChild();
}
}