Index: chrome/browser/resources/file_manager/js/image_editor/image_editor.js |
diff --git a/chrome/browser/resources/file_manager/js/image_editor/image_editor.js b/chrome/browser/resources/file_manager/js/image_editor/image_editor.js |
deleted file mode 100644 |
index 29858cf61a6d4a96a30a339187b7302ae445a992..0000000000000000000000000000000000000000 |
--- a/chrome/browser/resources/file_manager/js/image_editor/image_editor.js |
+++ /dev/null |
@@ -1,1162 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-'use strict'; |
- |
-/** |
- * ImageEditor is the top level object that holds together and connects |
- * everything needed for image editing. |
- * @param {Viewport} viewport The viewport. |
- * @param {ImageView} imageView The ImageView containing the images to edit. |
- * @param {ImageEditor.Prompt} prompt Prompt instance. |
- * @param {Object} DOMContainers Various DOM containers required for the editor. |
- * @param {Array.<ImageEditor.Mode>} modes Available editor modes. |
- * @param {function} displayStringFunction String formatting function. |
- * @constructor |
- */ |
-function ImageEditor( |
- viewport, imageView, prompt, DOMContainers, modes, displayStringFunction) { |
- this.rootContainer_ = DOMContainers.root; |
- this.container_ = DOMContainers.image; |
- this.modes_ = modes; |
- this.displayStringFunction_ = displayStringFunction; |
- |
- ImageUtil.removeChildren(this.container_); |
- |
- var document = this.container_.ownerDocument; |
- |
- this.viewport_ = viewport; |
- this.viewport_.sizeByFrame(this.container_); |
- |
- this.buffer_ = new ImageBuffer(); |
- this.viewport_.addRepaintCallback(this.buffer_.draw.bind(this.buffer_)); |
- |
- this.imageView_ = imageView; |
- this.imageView_.addContentCallback(this.onContentUpdate_.bind(this)); |
- this.buffer_.addOverlay(this.imageView_); |
- |
- this.panControl_ = new ImageEditor.MouseControl( |
- this.rootContainer_, this.container_, this.getBuffer()); |
- |
- this.panControl_.setDoubleTapCallback(this.onDoubleTap_.bind(this)); |
- |
- this.mainToolbar_ = new ImageEditor.Toolbar( |
- DOMContainers.toolbar, displayStringFunction); |
- |
- this.modeToolbar_ = new ImageEditor.Toolbar( |
- DOMContainers.mode, displayStringFunction, |
- this.onOptionsChange.bind(this)); |
- |
- this.prompt_ = prompt; |
- |
- this.createToolButtons(); |
- |
- this.commandQueue_ = null; |
-} |
- |
-/** |
- * @return {boolean} True if no user commands are to be accepted. |
- */ |
-ImageEditor.prototype.isLocked = function() { |
- return !this.commandQueue_ || this.commandQueue_.isBusy(); |
-}; |
- |
-/** |
- * @return {boolean} True if the command queue is busy. |
- */ |
-ImageEditor.prototype.isBusy = function() { |
- return this.commandQueue_ && this.commandQueue_.isBusy(); |
-}; |
- |
-/** |
- * Reflect the locked state of the editor in the UI. |
- * @param {boolean} on True if locked. |
- */ |
-ImageEditor.prototype.lockUI = function(on) { |
- ImageUtil.setAttribute(this.rootContainer_, 'locked', on); |
-}; |
- |
-/** |
- * Report the tool use to the metrics subsystem. |
- * @param {string} name Action name. |
- */ |
-ImageEditor.prototype.recordToolUse = function(name) { |
- ImageUtil.metrics.recordEnum( |
- ImageUtil.getMetricName('Tool'), name, this.actionNames_); |
-}; |
- |
-/** |
- * Content update handler. |
- * @private |
- */ |
-ImageEditor.prototype.onContentUpdate_ = function() { |
- for (var i = 0; i != this.modes_.length; i++) { |
- var mode = this.modes_[i]; |
- ImageUtil.setAttribute(mode.button_, 'disabled', !mode.isApplicable()); |
- } |
-}; |
- |
-/** |
- * Open the editing session for a new image. |
- * |
- * @param {string} url Image url. |
- * @param {Object} metadata Metadata. |
- * @param {Object} effect Transition effect object. |
- * @param {function(function)} saveFunction Image save function. |
- * @param {function} displayCallback Display callback. |
- * @param {function} loadCallback Load callback. |
- */ |
-ImageEditor.prototype.openSession = function( |
- url, metadata, effect, saveFunction, displayCallback, loadCallback) { |
- if (this.commandQueue_) |
- throw new Error('Session not closed'); |
- |
- this.lockUI(true); |
- |
- var self = this; |
- this.imageView_.load( |
- url, metadata, effect, displayCallback, function(loadType, delay, error) { |
- self.lockUI(false); |
- self.commandQueue_ = new CommandQueue( |
- self.container_.ownerDocument, |
- self.imageView_.getCanvas(), |
- saveFunction); |
- self.commandQueue_.attachUI( |
- self.getImageView(), self.getPrompt(), self.lockUI.bind(self)); |
- self.updateUndoRedo(); |
- loadCallback(loadType, delay, error); |
- }); |
-}; |
- |
-/** |
- * Close the current image editing session. |
- * @param {function} callback Callback. |
- */ |
-ImageEditor.prototype.closeSession = function(callback) { |
- this.getPrompt().hide(); |
- if (this.imageView_.isLoading()) { |
- if (this.commandQueue_) { |
- console.warn('Inconsistent image editor state'); |
- this.commandQueue_ = null; |
- } |
- this.imageView_.cancelLoad(); |
- this.lockUI(false); |
- callback(); |
- return; |
- } |
- if (!this.commandQueue_) { |
- // Session is already closed. |
- callback(); |
- return; |
- } |
- |
- this.executeWhenReady(callback); |
- this.commandQueue_.close(); |
- this.commandQueue_ = null; |
-}; |
- |
-/** |
- * Commit the current operation and execute the action. |
- * |
- * @param {function} callback Callback. |
- */ |
-ImageEditor.prototype.executeWhenReady = function(callback) { |
- if (this.commandQueue_) { |
- this.leaveModeGently(); |
- this.commandQueue_.executeWhenReady(callback); |
- } else { |
- if (!this.imageView_.isLoading()) |
- console.warn('Inconsistent image editor state'); |
- callback(); |
- } |
-}; |
- |
-/** |
- * @return {boolean} True if undo queue is not empty. |
- */ |
-ImageEditor.prototype.canUndo = function() { |
- return this.commandQueue_ && this.commandQueue_.canUndo(); |
-}; |
- |
-/** |
- * Undo the recently executed command. |
- */ |
-ImageEditor.prototype.undo = function() { |
- if (this.isLocked()) return; |
- this.recordToolUse('undo'); |
- |
- // First undo click should dismiss the uncommitted modifications. |
- if (this.currentMode_ && this.currentMode_.isUpdated()) { |
- this.currentMode_.reset(); |
- return; |
- } |
- |
- this.getPrompt().hide(); |
- this.leaveMode(false); |
- this.commandQueue_.undo(); |
- this.updateUndoRedo(); |
-}; |
- |
-/** |
- * Redo the recently un-done command. |
- */ |
-ImageEditor.prototype.redo = function() { |
- if (this.isLocked()) return; |
- this.recordToolUse('redo'); |
- this.getPrompt().hide(); |
- this.leaveMode(false); |
- this.commandQueue_.redo(); |
- this.updateUndoRedo(); |
-}; |
- |
-/** |
- * Update Undo/Redo buttons state. |
- */ |
-ImageEditor.prototype.updateUndoRedo = function() { |
- var canUndo = this.commandQueue_ && this.commandQueue_.canUndo(); |
- var canRedo = this.commandQueue_ && this.commandQueue_.canRedo(); |
- ImageUtil.setAttribute(this.undoButton_, 'disabled', !canUndo); |
- this.redoButton_.hidden = !canRedo; |
-}; |
- |
-/** |
- * @return {HTMLCanvasElement} The current image canvas. |
- */ |
-ImageEditor.prototype.getCanvas = function() { |
- return this.getImageView().getCanvas(); |
-}; |
- |
-/** |
- * @return {ImageBuffer} ImageBuffer instance. |
- */ |
-ImageEditor.prototype.getBuffer = function() { return this.buffer_ }; |
- |
-/** |
- * @return {ImageView} ImageView instance. |
- */ |
-ImageEditor.prototype.getImageView = function() { return this.imageView_ }; |
- |
-/** |
- * @return {Viewport} Viewport instance. |
- */ |
-ImageEditor.prototype.getViewport = function() { return this.viewport_ }; |
- |
-/** |
- * @return {ImageEditor.Prompt} Prompt instance. |
- */ |
-ImageEditor.prototype.getPrompt = function() { return this.prompt_ }; |
- |
-/** |
- * Handle the toolbar controls update. |
- * @param {Object} options A map of options. |
- */ |
-ImageEditor.prototype.onOptionsChange = function(options) { |
- ImageUtil.trace.resetTimer('update'); |
- if (this.currentMode_) { |
- this.currentMode_.update(options); |
- } |
- ImageUtil.trace.reportTimer('update'); |
-}; |
- |
-/** |
- * ImageEditor.Mode represents a modal state dedicated to a specific operation. |
- * Inherits from ImageBuffer. Overlay to simplify the drawing of mode-specific |
- * tools. |
- * |
- * @param {string} name The mode name. |
- * @param {string} title The mode title. |
- * @constructor |
- */ |
- |
-ImageEditor.Mode = function(name, title) { |
- this.name = name; |
- this.title = title; |
- this.message_ = 'GALLERY_ENTER_WHEN_DONE'; |
-}; |
- |
-ImageEditor.Mode.prototype = {__proto__: ImageBuffer.Overlay.prototype }; |
- |
-/** |
- * @return {Viewport} Viewport instance. |
- */ |
-ImageEditor.Mode.prototype.getViewport = function() { return this.viewport_ }; |
- |
-/** |
- * @return {ImageView} ImageView instance. |
- */ |
-ImageEditor.Mode.prototype.getImageView = function() { return this.imageView_ }; |
- |
-/** |
- * @return {string} The mode-specific message to be displayed when entering. |
- */ |
-ImageEditor.Mode.prototype.getMessage = function() { return this.message_ }; |
- |
-/** |
- * @return {boolean} True if the mode is applicable in the current context. |
- */ |
-ImageEditor.Mode.prototype.isApplicable = function() { return true }; |
- |
-/** |
- * Called once after creating the mode button. |
- * |
- * @param {ImageEditor} editor The editor instance. |
- * @param {HTMLElement} button The mode button. |
- */ |
- |
-ImageEditor.Mode.prototype.bind = function(editor, button) { |
- this.editor_ = editor; |
- this.editor_.registerAction_(this.name); |
- this.button_ = button; |
- this.viewport_ = editor.getViewport(); |
- this.imageView_ = editor.getImageView(); |
-}; |
- |
-/** |
- * Called before entering the mode. |
- */ |
-ImageEditor.Mode.prototype.setUp = function() { |
- this.editor_.getBuffer().addOverlay(this); |
- this.updated_ = false; |
-}; |
- |
-/** |
- * Create mode-specific controls here. |
- * @param {ImageEditor.Toolbar} toolbar The toolbar to populate. |
- */ |
-ImageEditor.Mode.prototype.createTools = function(toolbar) {}; |
- |
-/** |
- * Called before exiting the mode. |
- */ |
-ImageEditor.Mode.prototype.cleanUpUI = function() { |
- this.editor_.getBuffer().removeOverlay(this); |
-}; |
- |
-/** |
- * Called after exiting the mode. |
- */ |
-ImageEditor.Mode.prototype.cleanUpCaches = function() {}; |
- |
-/** |
- * Called when any of the controls changed its value. |
- * @param {Object} options A map of options. |
- */ |
-ImageEditor.Mode.prototype.update = function(options) { |
- this.markUpdated(); |
-}; |
- |
-/** |
- * Mark the editor mode as updated. |
- */ |
-ImageEditor.Mode.prototype.markUpdated = function() { |
- this.updated_ = true; |
-}; |
- |
-/** |
- * @return {boolean} True if the mode controls changed. |
- */ |
-ImageEditor.Mode.prototype.isUpdated = function() { return this.updated_ }; |
- |
-/** |
- * Resets the mode to a clean state. |
- */ |
-ImageEditor.Mode.prototype.reset = function() { |
- this.editor_.modeToolbar_.reset(); |
- this.updated_ = false; |
-}; |
- |
-/** |
- * One-click editor tool, requires no interaction, just executes the command. |
- * |
- * @param {string} name The mode name. |
- * @param {string} title The mode title. |
- * @param {Command} command The command to execute on click. |
- * @constructor |
- */ |
-ImageEditor.Mode.OneClick = function(name, title, command) { |
- ImageEditor.Mode.call(this, name, title); |
- this.instant = true; |
- this.command_ = command; |
-}; |
- |
-ImageEditor.Mode.OneClick.prototype = {__proto__: ImageEditor.Mode.prototype}; |
- |
-/** |
- * @return {Command} command. |
- */ |
-ImageEditor.Mode.OneClick.prototype.getCommand = function() { |
- return this.command_; |
-}; |
- |
-/** |
- * Register the action name. Required for metrics reporting. |
- * @param {string} name Button name. |
- * @private |
- */ |
-ImageEditor.prototype.registerAction_ = function(name) { |
- this.actionNames_.push(name); |
-}; |
- |
-/** |
- * Populate the toolbar. |
- */ |
-ImageEditor.prototype.createToolButtons = function() { |
- this.mainToolbar_.clear(); |
- this.actionNames_ = []; |
- |
- var self = this; |
- function createButton(name, title, handler) { |
- return self.mainToolbar_.addButton(name, |
- title, |
- handler, |
- name /* opt_className */); |
- } |
- |
- for (var i = 0; i != this.modes_.length; i++) { |
- var mode = this.modes_[i]; |
- mode.bind(this, createButton(mode.name, |
- mode.title, |
- this.enterMode.bind(this, mode))); |
- } |
- |
- this.undoButton_ = createButton('undo', |
- 'GALLERY_UNDO', |
- this.undo.bind(this)); |
- this.registerAction_('undo'); |
- |
- this.redoButton_ = createButton('redo', |
- 'GALLERY_REDO', |
- this.redo.bind(this)); |
- this.registerAction_('redo'); |
-}; |
- |
-/** |
- * @return {ImageEditor.Mode} The current mode. |
- */ |
-ImageEditor.prototype.getMode = function() { return this.currentMode_ }; |
- |
-/** |
- * The user clicked on the mode button. |
- * |
- * @param {ImageEditor.Mode} mode The new mode. |
- */ |
-ImageEditor.prototype.enterMode = function(mode) { |
- if (this.isLocked()) return; |
- |
- if (this.currentMode_ == mode) { |
- // Currently active editor tool clicked, commit if modified. |
- this.leaveMode(this.currentMode_.updated_); |
- return; |
- } |
- |
- this.recordToolUse(mode.name); |
- |
- this.leaveModeGently(); |
- // The above call could have caused a commit which might have initiated |
- // an asynchronous command execution. Wait for it to complete, then proceed |
- // with the mode set up. |
- this.commandQueue_.executeWhenReady(this.setUpMode_.bind(this, mode)); |
-}; |
- |
-/** |
- * Set up the new editing mode. |
- * |
- * @param {ImageEditor.Mode} mode The mode. |
- * @private |
- */ |
-ImageEditor.prototype.setUpMode_ = function(mode) { |
- this.currentTool_ = mode.button_; |
- |
- ImageUtil.setAttribute(this.currentTool_, 'pressed', true); |
- |
- this.currentMode_ = mode; |
- this.currentMode_.setUp(); |
- |
- if (this.currentMode_.instant) { // Instant tool. |
- this.leaveMode(true); |
- return; |
- } |
- |
- this.getPrompt().show(this.currentMode_.getMessage()); |
- |
- this.modeToolbar_.clear(); |
- this.currentMode_.createTools(this.modeToolbar_); |
- this.modeToolbar_.show(true); |
-}; |
- |
-/** |
- * The user clicked on 'OK' or 'Cancel' or on a different mode button. |
- * @param {boolean} commit True if commit is required. |
- */ |
-ImageEditor.prototype.leaveMode = function(commit) { |
- if (!this.currentMode_) return; |
- |
- if (!this.currentMode_.instant) { |
- this.getPrompt().hide(); |
- } |
- |
- this.modeToolbar_.show(false); |
- |
- this.currentMode_.cleanUpUI(); |
- if (commit) { |
- var self = this; |
- var command = this.currentMode_.getCommand(); |
- if (command) { // Could be null if the user did not do anything. |
- this.commandQueue_.execute(command); |
- this.updateUndoRedo(); |
- } |
- } |
- this.currentMode_.cleanUpCaches(); |
- this.currentMode_ = null; |
- |
- ImageUtil.setAttribute(this.currentTool_, 'pressed', false); |
- this.currentTool_ = null; |
-}; |
- |
-/** |
- * Leave the mode, commit only if required by the current mode. |
- */ |
-ImageEditor.prototype.leaveModeGently = function() { |
- this.leaveMode(this.currentMode_ && |
- this.currentMode_.updated_ && |
- this.currentMode_.implicitCommit); |
-}; |
- |
-/** |
- * Enter the editor mode with the given name. |
- * |
- * @param {string} name Mode name. |
- * @private |
- */ |
-ImageEditor.prototype.enterModeByName_ = function(name) { |
- for (var i = 0; i != this.modes_.length; i++) { |
- var mode = this.modes_[i]; |
- if (mode.name == name) { |
- if (!mode.button_.hasAttribute('disabled')) |
- this.enterMode(mode); |
- return; |
- } |
- } |
- console.error('Mode "' + name + '" not found.'); |
-}; |
- |
-/** |
- * Key down handler. |
- * @param {Event} event The keydown event. |
- * @return {boolean} True if handled. |
- */ |
-ImageEditor.prototype.onKeyDown = function(event) { |
- switch (util.getKeyModifiers(event) + event.keyIdentifier) { |
- case 'U+001B': // Escape |
- case 'Enter': |
- if (this.getMode()) { |
- this.leaveMode(event.keyIdentifier == 'Enter'); |
- return true; |
- } |
- break; |
- |
- case 'Ctrl-U+005A': // Ctrl+Z |
- if (this.commandQueue_.canUndo()) { |
- this.undo(); |
- return true; |
- } |
- break; |
- |
- case 'Ctrl-U+0059': // Ctrl+Y |
- if (this.commandQueue_.canRedo()) { |
- this.redo(); |
- return true; |
- } |
- break; |
- |
- case 'U+0041': // 'a' |
- this.enterModeByName_('autofix'); |
- return true; |
- |
- case 'U+0042': // 'b' |
- this.enterModeByName_('exposure'); |
- return true; |
- |
- case 'U+0043': // 'c' |
- this.enterModeByName_('crop'); |
- return true; |
- |
- case 'U+004C': // 'l' |
- this.enterModeByName_('rotate_left'); |
- return true; |
- |
- case 'U+0052': // 'r' |
- this.enterModeByName_('rotate_right'); |
- return true; |
- |
- } |
- return false; |
-}; |
- |
-/** |
- * Double tap handler. |
- * @param {number} x X coordinate of the event. |
- * @param {number} y Y coordinate of the event. |
- * @private |
- */ |
-ImageEditor.prototype.onDoubleTap_ = function(x, y) { |
- if (this.getMode()) { |
- var action = this.buffer_.getDoubleTapAction(x, y); |
- if (action == ImageBuffer.DoubleTapAction.COMMIT) |
- this.leaveMode(true); |
- else if (action == ImageBuffer.DoubleTapAction.CANCEL) |
- this.leaveMode(false); |
- } |
-}; |
- |
-/** |
- * Hide the tools that overlap the given rectangular frame. |
- * |
- * @param {Rect} frame Hide the tool that overlaps this rect. |
- * @param {Rect} transparent But do not hide the tool that is completely inside |
- * this rect. |
- */ |
-ImageEditor.prototype.hideOverlappingTools = function(frame, transparent) { |
- var tools = this.rootContainer_.ownerDocument.querySelectorAll('.dimmable'); |
- for (var i = 0; i != tools.length; i++) { |
- var tool = tools[i]; |
- var toolRect = tool.getBoundingClientRect(); |
- ImageUtil.setAttribute(tool, 'dimmed', |
- (frame && frame.intersects(toolRect)) && |
- !(transparent && transparent.contains(toolRect))); |
- } |
-}; |
- |
-/** |
- * A helper object for panning the ImageBuffer. |
- * |
- * @param {HTMLElement} rootContainer The top-level container. |
- * @param {HTMLElement} container The container for mouse events. |
- * @param {ImageBuffer} buffer Image buffer. |
- * @constructor |
- */ |
-ImageEditor.MouseControl = function(rootContainer, container, buffer) { |
- this.rootContainer_ = rootContainer; |
- this.container_ = container; |
- this.buffer_ = buffer; |
- |
- var handlers = { |
- 'touchstart': this.onTouchStart, |
- 'touchend': this.onTouchEnd, |
- 'touchcancel': this.onTouchCancel, |
- 'touchmove': this.onTouchMove, |
- 'mousedown': this.onMouseDown, |
- 'mouseup': this.onMouseUp |
- }; |
- |
- for (var eventName in handlers) { |
- container.addEventListener( |
- eventName, handlers[eventName].bind(this), false); |
- } |
- |
- // Mouse move handler has to be attached to the window to receive events |
- // from outside of the window. See: http://crbug.com/155705 |
- window.addEventListener('mousemove', this.onMouseMove.bind(this), false); |
-}; |
- |
-/** |
- * Maximum movement for touch to be detected as a tap (in pixels). |
- * @private |
- */ |
-ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_ = 8; |
- |
-/** |
- * Maximum time for touch to be detected as a tap (in milliseconds). |
- * @private |
- */ |
-ImageEditor.MouseControl.MAX_TAP_DURATION_ = 500; |
- |
-/** |
- * Maximum distance from the first tap to the second tap to be considered |
- * as a double tap. |
- * @private |
- */ |
-ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_ = 32; |
- |
-/** |
- * Maximum time for touch to be detected as a double tap (in milliseconds). |
- * @private |
- */ |
-ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_ = 1000; |
- |
-/** |
- * Returns an event's position. |
- * |
- * @param {MouseEvent|Touch} e Pointer position. |
- * @return {Object} A pair of x,y in page coordinates. |
- * @private |
- */ |
-ImageEditor.MouseControl.getPosition_ = function(e) { |
- return { |
- x: e.pageX, |
- y: e.pageY |
- }; |
-}; |
- |
-/** |
- * Returns touch position or null if there is more than one touch position. |
- * |
- * @param {TouchEvent} e Event. |
- * @return {object?} A pair of x,y in page coordinates. |
- * @private |
- */ |
-ImageEditor.MouseControl.prototype.getTouchPosition_ = function(e) { |
- if (e.targetTouches.length == 1) |
- return ImageEditor.MouseControl.getPosition_(e.targetTouches[0]); |
- else |
- return null; |
-}; |
- |
-/** |
- * Touch start handler. |
- * @param {TouchEvent} e Event. |
- */ |
-ImageEditor.MouseControl.prototype.onTouchStart = function(e) { |
- var position = this.getTouchPosition_(e); |
- if (position) { |
- this.touchStartInfo_ = { |
- x: position.x, |
- y: position.y, |
- time: Date.now() |
- }; |
- this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y, |
- true /* touch */); |
- this.dragHappened_ = false; |
- } |
- e.preventDefault(); |
-}; |
- |
-/** |
- * Touch end handler. |
- * @param {TouchEvent} e Event. |
- */ |
-ImageEditor.MouseControl.prototype.onTouchEnd = function(e) { |
- if (!this.dragHappened_ && Date.now() - this.touchStartInfo_.time <= |
- ImageEditor.MouseControl.MAX_TAP_DURATION_) { |
- this.buffer_.onClick(this.touchStartInfo_.x, this.touchStartInfo_.y); |
- if (this.previousTouchStartInfo_ && |
- Date.now() - this.previousTouchStartInfo_.time < |
- ImageEditor.MouseControl.MAX_DOUBLE_TAP_DURATION_) { |
- var prevTouchCircle = new Circle( |
- this.previousTouchStartInfo_.x, |
- this.previousTouchStartInfo_.y, |
- ImageEditor.MouseControl.MAX_DISTANCE_FOR_DOUBLE_TAP_); |
- if (prevTouchCircle.inside(this.touchStartInfo_.x, |
- this.touchStartInfo_.y)) { |
- this.doubleTapCallback_(this.touchStartInfo_.x, this.touchStartInfo_.y); |
- } |
- } |
- this.previousTouchStartInfo_ = this.touchStartInfo_; |
- } else { |
- this.previousTouchStartInfo_ = null; |
- } |
- this.onTouchCancel(e); |
- e.preventDefault(); |
-}; |
- |
-/** |
- * Default double tap handler. |
- * @param {number} x X coordinate of the event. |
- * @param {number} y Y coordinate of the event. |
- * @private |
- */ |
-ImageEditor.MouseControl.prototype.doubleTapCallback_ = function(x, y) {}; |
- |
-/** |
- * Sets callback to be called when double tap detected. |
- * @param {function(number, number)} callback New double tap callback. |
- */ |
-ImageEditor.MouseControl.prototype.setDoubleTapCallback = function(callback) { |
- this.doubleTapCallback_ = callback; |
-}; |
- |
-/** |
- * Touch chancel handler. |
- */ |
-ImageEditor.MouseControl.prototype.onTouchCancel = function() { |
- this.dragHandler_ = null; |
- this.dragHappened_ = false; |
- this.touchStartInfo_ = null; |
- this.lockMouse_(false); |
-}; |
- |
-/** |
- * Touch move handler. |
- * @param {TouchEvent} e Event. |
- */ |
-ImageEditor.MouseControl.prototype.onTouchMove = function(e) { |
- var position = this.getTouchPosition_(e); |
- if (!position) |
- return; |
- |
- if (this.touchStartInfo_ && !this.dragHappened_) { |
- var tapCircle = new Circle(this.touchStartInfo_.x, this.touchStartInfo_.y, |
- ImageEditor.MouseControl.MAX_MOVEMENT_FOR_TAP_); |
- this.dragHappened_ = !tapCircle.inside(position.x, position.y); |
- } |
- if (this.dragHandler_ && this.dragHappened_) { |
- this.dragHandler_(position.x, position.y); |
- this.lockMouse_(true); |
- } |
- e.preventDefault(); |
-}; |
- |
-/** |
- * Mouse down handler. |
- * @param {MouseEvent} e Event. |
- */ |
-ImageEditor.MouseControl.prototype.onMouseDown = function(e) { |
- var position = ImageEditor.MouseControl.getPosition_(e); |
- |
- this.dragHandler_ = this.buffer_.getDragHandler(position.x, position.y, |
- false /* mouse */); |
- this.dragHappened_ = false; |
- this.updateCursor_(position); |
- e.preventDefault(); |
-}; |
- |
-/** |
- * Mouse up handler. |
- * @param {MouseEvent} e Event. |
- */ |
-ImageEditor.MouseControl.prototype.onMouseUp = function(e) { |
- var position = ImageEditor.MouseControl.getPosition_(e); |
- |
- if (!this.dragHappened_) { |
- this.buffer_.onClick(position.x, position.y); |
- } |
- this.dragHandler_ = null; |
- this.dragHappened_ = false; |
- this.lockMouse_(false); |
- e.preventDefault(); |
-}; |
- |
-/** |
- * Mouse move handler. |
- * @param {MouseEvent} e Event. |
- */ |
-ImageEditor.MouseControl.prototype.onMouseMove = function(e) { |
- var position = ImageEditor.MouseControl.getPosition_(e); |
- |
- if (this.dragHandler_ && !e.which) { |
- // mouseup must have happened while the mouse was outside our window. |
- this.dragHandler_ = null; |
- this.lockMouse_(false); |
- } |
- |
- this.updateCursor_(position); |
- if (this.dragHandler_) { |
- this.dragHandler_(position.x, position.y); |
- this.dragHappened_ = true; |
- this.lockMouse_(true); |
- } |
- e.preventDefault(); |
-}; |
- |
-/** |
- * Update the UI to reflect mouse drag state. |
- * @param {boolean} on True if dragging. |
- * @private |
- */ |
-ImageEditor.MouseControl.prototype.lockMouse_ = function(on) { |
- ImageUtil.setAttribute(this.rootContainer_, 'mousedrag', on); |
-}; |
- |
-/** |
- * Update the cursor. |
- * |
- * @param {Object} position An object holding x and y properties. |
- * @private |
- */ |
-ImageEditor.MouseControl.prototype.updateCursor_ = function(position) { |
- var oldCursor = this.container_.getAttribute('cursor'); |
- var newCursor = this.buffer_.getCursorStyle( |
- position.x, position.y, !!this.dragHandler_); |
- if (newCursor != oldCursor) // Avoid flicker. |
- this.container_.setAttribute('cursor', newCursor); |
-}; |
- |
-/** |
- * A toolbar for the ImageEditor. |
- * @param {HTMLElement} parent The parent element. |
- * @param {function} displayStringFunction A string formatting function. |
- * @param {function} updateCallback The callback called when controls change. |
- * @constructor |
- */ |
-ImageEditor.Toolbar = function(parent, displayStringFunction, updateCallback) { |
- this.wrapper_ = parent; |
- this.displayStringFunction_ = displayStringFunction; |
- this.updateCallback_ = updateCallback; |
-}; |
- |
-/** |
- * Clear the toolbar. |
- */ |
-ImageEditor.Toolbar.prototype.clear = function() { |
- ImageUtil.removeChildren(this.wrapper_); |
-}; |
- |
-/** |
- * Create a control. |
- * @param {string} tagName The element tag name. |
- * @return {HTMLElement} The created control element. |
- * @private |
- */ |
-ImageEditor.Toolbar.prototype.create_ = function(tagName) { |
- return this.wrapper_.ownerDocument.createElement(tagName); |
-}; |
- |
-/** |
- * Add a control. |
- * @param {HTMLElement} element The control to add. |
- * @return {HTMLElement} The added element. |
- */ |
-ImageEditor.Toolbar.prototype.add = function(element) { |
- this.wrapper_.appendChild(element); |
- return element; |
-}; |
- |
-/** |
- * Add a text label. |
- * @param {string} name Label name. |
- * @return {HTMLElement} The added label. |
- */ |
-ImageEditor.Toolbar.prototype.addLabel = function(name) { |
- var label = this.create_('span'); |
- label.textContent = this.displayStringFunction_(name); |
- return this.add(label); |
-}; |
- |
-/** |
- * Add a button. |
- * |
- * @param {string} name Button name. |
- * @param {string} title Button title. |
- * @param {function} handler onClick handler. |
- * @param {string=} opt_class Extra class name. |
- * @return {HTMLElement} The added button. |
- */ |
-ImageEditor.Toolbar.prototype.addButton = function( |
- name, title, handler, opt_class) { |
- var button = this.create_('button'); |
- if (opt_class) button.classList.add(opt_class); |
- var label = this.create_('span'); |
- label.textContent = this.displayStringFunction_(title); |
- button.appendChild(label); |
- button.label = this.displayStringFunction_(title); |
- button.addEventListener('click', handler, false); |
- return this.add(button); |
-}; |
- |
-/** |
- * Add a range control (scalar value picker). |
- * |
- * @param {string} name An option name. |
- * @param {string} title An option title. |
- * @param {number} min Min value of the option. |
- * @param {number} value Default value of the option. |
- * @param {number} max Max value of the options. |
- * @param {number} scale A number to multiply by when setting |
- * min/value/max in DOM. |
- * @param {boolean=} opt_showNumeric True if numeric value should be displayed. |
- * @return {HTMLElement} Range element. |
- */ |
-ImageEditor.Toolbar.prototype.addRange = function( |
- name, title, min, value, max, scale, opt_showNumeric) { |
- var self = this; |
- |
- scale = scale || 1; |
- |
- var range = this.create_('input'); |
- |
- range.className = 'range'; |
- range.type = 'range'; |
- range.name = name; |
- range.min = Math.ceil(min * scale); |
- range.max = Math.floor(max * scale); |
- |
- var numeric = this.create_('div'); |
- numeric.className = 'numeric'; |
- function mirror() { |
- numeric.textContent = Math.round(range.getValue() * scale) / scale; |
- } |
- |
- range.setValue = function(newValue) { |
- range.value = Math.round(newValue * scale); |
- mirror(); |
- }; |
- |
- range.getValue = function() { |
- return Number(range.value) / scale; |
- }; |
- |
- range.reset = function() { |
- range.setValue(value); |
- }; |
- |
- range.addEventListener('change', |
- function() { |
- mirror(); |
- self.updateCallback_(self.getOptions()); |
- }, |
- false); |
- |
- range.setValue(value); |
- |
- var label = this.create_('div'); |
- label.textContent = this.displayStringFunction_(title); |
- label.className = 'label ' + name; |
- this.add(label); |
- this.add(range); |
- if (opt_showNumeric) this.add(numeric); |
- |
- return range; |
-}; |
- |
-/** |
- * @return {Object} options A map of options. |
- */ |
-ImageEditor.Toolbar.prototype.getOptions = function() { |
- var values = {}; |
- for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) { |
- if (child.name) |
- values[child.name] = child.getValue(); |
- } |
- return values; |
-}; |
- |
-/** |
- * Reset the toolbar. |
- */ |
-ImageEditor.Toolbar.prototype.reset = function() { |
- for (var child = this.wrapper_.firstChild; child; child = child.nextSibling) { |
- if (child.reset) child.reset(); |
- } |
-}; |
- |
-/** |
- * Show/hide the toolbar. |
- * @param {boolean} on True if show. |
- */ |
-ImageEditor.Toolbar.prototype.show = function(on) { |
- if (!this.wrapper_.firstChild) |
- return; // Do not show empty toolbar; |
- |
- this.wrapper_.hidden = !on; |
-}; |
- |
-/** A prompt panel for the editor. |
- * |
- * @param {HTMLElement} container Container element. |
- * @param {function} displayStringFunction A formatting function. |
- * @constructor |
- */ |
-ImageEditor.Prompt = function(container, displayStringFunction) { |
- this.container_ = container; |
- this.displayStringFunction_ = displayStringFunction; |
-}; |
- |
-/** |
- * Reset the prompt. |
- */ |
-ImageEditor.Prompt.prototype.reset = function() { |
- this.cancelTimer(); |
- if (this.wrapper_) { |
- this.container_.removeChild(this.wrapper_); |
- this.wrapper_ = null; |
- this.prompt_ = null; |
- } |
-}; |
- |
-/** |
- * Cancel the delayed action. |
- */ |
-ImageEditor.Prompt.prototype.cancelTimer = function() { |
- if (this.timer_) { |
- clearTimeout(this.timer_); |
- this.timer_ = null; |
- } |
-}; |
- |
-/** |
- * Schedule the delayed action. |
- * @param {function} callback Callback. |
- * @param {number} timeout Timeout. |
- */ |
-ImageEditor.Prompt.prototype.setTimer = function(callback, timeout) { |
- this.cancelTimer(); |
- var self = this; |
- this.timer_ = setTimeout(function() { |
- self.timer_ = null; |
- callback(); |
- }, timeout); |
-}; |
- |
-/** |
- * Show the prompt. |
- * |
- * @param {string} text The prompt text. |
- * @param {number} timeout Timeout in ms. |
- * @param {Object} formatArgs varArgs for the formatting fuction. |
- */ |
-ImageEditor.Prompt.prototype.show = function(text, timeout, formatArgs) { |
- this.showAt.apply(this, |
- ['center'].concat(Array.prototype.slice.call(arguments))); |
-}; |
- |
-/** |
- * |
- * @param {string} pos The 'pos' attribute value. |
- * @param {string} text The prompt text. |
- * @param {number} timeout Timeout in ms. |
- * @param {Object} formatArgs varArgs for the formatting function. |
- */ |
-ImageEditor.Prompt.prototype.showAt = function(pos, text, timeout, formatArgs) { |
- this.reset(); |
- if (!text) return; |
- |
- var document = this.container_.ownerDocument; |
- this.wrapper_ = document.createElement('div'); |
- this.wrapper_.className = 'prompt-wrapper'; |
- this.wrapper_.setAttribute('pos', pos); |
- this.container_.appendChild(this.wrapper_); |
- |
- this.prompt_ = document.createElement('div'); |
- this.prompt_.className = 'prompt'; |
- |
- // Create an extra wrapper which opacity can be manipulated separately. |
- var tool = document.createElement('div'); |
- tool.className = 'dimmable'; |
- this.wrapper_.appendChild(tool); |
- tool.appendChild(this.prompt_); |
- |
- var args = [text].concat(Array.prototype.slice.call(arguments, 3)); |
- this.prompt_.textContent = this.displayStringFunction_.apply(null, args); |
- |
- var close = document.createElement('div'); |
- close.className = 'close'; |
- close.addEventListener('click', this.hide.bind(this)); |
- this.prompt_.appendChild(close); |
- |
- setTimeout( |
- this.prompt_.setAttribute.bind(this.prompt_, 'state', 'fadein'), 0); |
- |
- if (timeout) |
- this.setTimer(this.hide.bind(this), timeout); |
-}; |
- |
-/** |
- * Hide the prompt. |
- */ |
-ImageEditor.Prompt.prototype.hide = function() { |
- if (!this.prompt_) return; |
- this.prompt_.setAttribute('state', 'fadeout'); |
- // Allow some time for the animation to play out. |
- this.setTimer(this.reset.bind(this), 500); |
-}; |