diff --git a/web_widget_darkroom/README.rst b/web_widget_darkroom/README.rst
index befb0c9f..02e280d6 100755
--- a/web_widget_darkroom/README.rst
+++ b/web_widget_darkroom/README.rst
@@ -1,70 +1,72 @@
-.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
+.. image:: https://img.shields.io/badge/license-LGPL--3-blue.svg
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
-======================
-Odoo DarkroomJS Widget
-======================
+================================
+DarkroomJS Image Editing for Web
+================================
-This module provides a `DarkroomJS`_ web widget for use with images fields.
+This module provides a `DarkroomJS`_ (v2.0.1) web widget for use with image
+fields. It also adds a Darkroom button to the normal image widget, which can
+be used to edit the image via Darkroom in a modal.
.. _DarkroomJS: https://github.com/MattKetmo/darkroomjs
-This widget will allow you to perform the following actions on images:
+The widget currently supports the following operations and can be extended to
+allow others:
- * Zoom
- * Rotate
- * Crop
- * Step back in history client-side (before save)
+* Zoom and pan
+* Rotate
+* Crop
+* Step back in history client-side (before save)
-
Usage
=====
-To use this module, you need to:
-
-* Install web_widget_darkroom
-* Add the to any One2many image relation by using the `darkroom` widget. Options can be passed through to Darkroom using the `options` key::
+After installing the module, you can use it in the following ways:
-
+* Specify the ``darkroom`` widget when adding an image field to a view.
+ Configuration values can be provided using the ``options`` attribute::
-The Odoo DarkroomJS widget passes options directly through to Darkroom, which are copied from the source below::
+
- // Default options
- defaults: {
- // Canvas properties (dimension, ratio, color)
- minWidth: null,
- minHeight: null,
- maxWidth: null,
- maxHeight: null,
- ratio: null,
- backgroundColor: '#fff',
+ The widget passes options directly through to DarkroomJS, which supports the
+ following:
- // Plugins options
- plugins: {},
+ * minWidth
+ * minHeight
+ * maxWidth
+ * maxHeight
+ * ratio (aspect ratio)
+ * backgroundColor
- // Post-initialisation callback
- initialize: function() { /* noop */ }
- },
+* Open a form view that contains an image in edit mode and hover over the
+ image widget. You should see a Darkoom button that can be clicked to open
+ the image in a Darkroom modal, where it can be edited and the changes can be
+ saved.
+ .. image:: /web_widget_darkroom/static/description/modal_screenshot_1.png
+ :alt: Darkroom Modal Screenshot 1
+ :class: img-thumbnail
+ :height: 260
+ .. image:: /web_widget_darkroom/static/description/modal_screenshot_2.png
+ :alt: Darkroom Modal Screenshot 2
+ :class: img-thumbnail col-xs-offset-1
+ :height: 260
-Known Issues/Roadmap
-====================
-
-* Plugins are not able to be added without inheriting, then redefining the widget in the registry due to JS inheritance.
- ** This is not scalable because there would need to be an explicit dependency chain in order to avoid registry overwrite.
-
+Known Issues / Roadmap
+======================
+* Darkroom modals are currently not supported during record creation
Bug Tracker
===========
-Bugs are tracked on `GitHub Issues
-`_. In case of trouble, please
-check there if your issue has already been reported. If you spotted it first,
-help us smashing it by providing a detailed and welcomed feedback.
+Bugs are tracked on `GitHub Issues `_. In
+case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smash it by providing detailed and welcome
+feedback.
Credits
=======
@@ -72,12 +74,14 @@ Credits
Images
------
-* Odoo Community Association: `Icon `_.
+* Odoo Community Association:
+ `Icon `_.
Contributors
------------
* Dave Lasley
+* Oleg Bulkin
Maintainer
----------
diff --git a/web_widget_darkroom/__init__.py b/web_widget_darkroom/__init__.py
old mode 100755
new mode 100644
index 08d9d6b0..c1a869f5
--- a/web_widget_darkroom/__init__.py
+++ b/web_widget_darkroom/__init__.py
@@ -1,3 +1,5 @@
# -*- coding: utf-8 -*-
-# Copyright 2016 LasLabs Inc.
+# Copyright 2016-2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
+
+from . import wizards
diff --git a/web_widget_darkroom/__openerp__.py b/web_widget_darkroom/__openerp__.py
old mode 100755
new mode 100644
index 9bc1c568..47a4b742
--- a/web_widget_darkroom/__openerp__.py
+++ b/web_widget_darkroom/__openerp__.py
@@ -1,28 +1,26 @@
# -*- coding: utf-8 -*-
-# Copyright 2016 LasLabs Inc.
+# Copyright 2016-2017 LasLabs Inc.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
{
- "name": "Web Darkroom Image Widget",
- "summary": "Widget provides a dynamic, editable canvas for use on any"
- " One2many image field in backend form views.",
- "version": "9.0.1.0.1",
- "category": "Web",
- "website": "https://laslabs.com/",
- "author": "LasLabs, Odoo Community Association (OCA)",
- "license": "LGPL-3",
- "application": False,
- "installable": True,
- "depends": [
- "web",
+ 'name': 'Web DarkroomJS Image Editing',
+ 'summary': 'Provides web widget for image editing and adds it to standard'
+ ' image widget as modal',
+ 'version': '9.0.1.0.1',
+ 'category': 'Web',
+ 'website': 'https://laslabs.com/',
+ 'author': 'LasLabs, Odoo Community Association (OCA)',
+ 'license': 'LGPL-3',
+ 'application': False,
+ 'installable': True,
+ 'depends': [
+ 'web',
],
- "data": [
+ 'data': [
'views/assets.xml',
+ 'wizards/darkroom_modal.xml',
],
'qweb': [
- "static/src/xml/field_templates.xml",
+ 'static/src/xml/field_templates.xml',
],
- 'demo': [
- 'demo/res_users.xml',
- ]
}
diff --git a/web_widget_darkroom/demo/res_users.xml b/web_widget_darkroom/demo/res_users.xml
deleted file mode 100644
index 43a17825..00000000
--- a/web_widget_darkroom/demo/res_users.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
-
- res.users.form.darkroom
- res.users
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/web_widget_darkroom/static/description/modal_screenshot_1.png b/web_widget_darkroom/static/description/modal_screenshot_1.png
new file mode 100644
index 00000000..5505d68b
Binary files /dev/null and b/web_widget_darkroom/static/description/modal_screenshot_1.png differ
diff --git a/web_widget_darkroom/static/description/modal_screenshot_2.png b/web_widget_darkroom/static/description/modal_screenshot_2.png
new file mode 100644
index 00000000..6c0ce569
Binary files /dev/null and b/web_widget_darkroom/static/description/modal_screenshot_2.png differ
diff --git a/web_widget_darkroom/static/lib/darkroomjs/.editorconfig b/web_widget_darkroom/static/lib/darkroomjs/.editorconfig
deleted file mode 100755
index 8c98bb17..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/.editorconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-root = true
-
-[*]
-charset = utf-8
-end_of_line = LF
-indent_style = space
-trim_trailing_whitespace = true
-insert_final_newline = true
-indent_size = 2
diff --git a/web_widget_darkroom/static/lib/darkroomjs/.gitignore b/web_widget_darkroom/static/lib/darkroomjs/.gitignore
deleted file mode 100755
index abad6da3..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-/.sass-cache/
-/bower_components/
-/build/
-/node_modules/
-/docs/
diff --git a/web_widget_darkroom/static/lib/darkroomjs/CHANGELOG.md b/web_widget_darkroom/static/lib/darkroomjs/CHANGELOG.md
deleted file mode 100755
index 17b13903..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/CHANGELOG.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Change Log
-
-All notable changes to this project will be documented in this file.
-
-## Unreleased
-
-- Add type "button" to avoid html5 submit validation (#24)
-
-## 2.0.0 (2015-08-01)
-
-- Use of **Gulp** for the build process
-- Replace the webfont by **SVG symbols** (which are direclty included in the compiled javascript)
-- Ability to change **canvas ratio**
-- Original image is kept and changes are done on a clone
-
-## 1.0.x (2014)
-
-Initial release.
-
-- Create canvas with FabricJS from an image element
-- Plugins: Crop, History, Rotate, Save
-- Build process via Grunt
-- Build webfont from SVG files to display the icons
diff --git a/web_widget_darkroom/static/lib/darkroomjs/LICENSE b/web_widget_darkroom/static/lib/darkroomjs/LICENSE
deleted file mode 100755
index 35541ed0..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/LICENSE
+++ /dev/null
@@ -1,18 +0,0 @@
-Copyright (c) 2013 Matthieu Moquet
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/web_widget_darkroom/static/lib/darkroomjs/README.md b/web_widget_darkroom/static/lib/darkroomjs/README.md
deleted file mode 100755
index 5ba31b0b..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/README.md
+++ /dev/null
@@ -1,88 +0,0 @@
-# DarkroomJS
-
-DarkroomJS is a JavaScript library which provides basic image editing tools in
-your browser, such as **rotation** or **cropping**. It is based on the awesome
-[FabricJS](http://fabricjs.com/) library to handle images in HTML5 canvas.
-
-## Demo
-
-Try the online demo at [http://mattketmo.github.io/darkroomjs](http://mattketmo.github.io/darkroomjs/)
-
-The library is currently *work in progress*.
-I know there is some bug especially when resizing the crop zone.
-Feel free to fork the project or report issues on GitHub.
-All ideas are also welcome.
-
-## Building
-
-- Install [Node](http://nodejs.org/) & `npm`.
-- Run `npm install` to build dependencies.
-- Run `npm start` to build the assets and start the demo webserver.
-
-## Usage
-
-Simply instanciate a new Darkroom object with a reference to the image element:
-
-```html
-
-
-```
-
-You can also pass some options:
-
-```javascript
-new Darkroom('#target', {
- // Canvas initialization size
- minWidth: 100,
- minHeight: 100,
- maxWidth: 500,
- maxHeight: 500,
-
- // Plugins options
- plugins: {
- crop: {
- minHeight: 50,
- minWidth: 50,
- ratio: 1
- },
- save: false // disable plugin
- },
-
- // Post initialization method
- initialize: function() {
- // Active crop selection
- this.plugins['crop'].requireFocus();
-
- // Add custom listener
- this.addEventListener('core:transformation', function() { /* ... */ });
- }
-});
-```
-
-## Why?
-
-It's easy to get a javascript script to crop an image in a web page.
-But if your want more features like rotation or brightness adjustment, then you
-will have to do it yourself. No more jQuery plugins here.
-It only uses the power of HTML5 canvas to make what ever you want with your image.
-
-## The concept
-
-The library is designed to be easily extendable. The core script only transforms
-the target image to a canvas with a FabricJS instance, and creates an empty toolbar.
-All the features are then implemented in separate plugins.
-
-Each plugin is responsible for creating its own functionality.
-Buttons can easily be added to the toolbar and binded with those features.
-
-## Contributing
-
-Run `npm develop` to build and watch the files while developing.
-
-## License
-
-DarkroomJS is released under the MIT License. See the [bundled LICENSE file](LICENSE)
-for details.
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/bower.json b/web_widget_darkroom/static/lib/darkroomjs/bower.json
deleted file mode 100755
index aa38ffe7..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/bower.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "name": "darkroom",
- "description": "Extensible image editing tool via HTML canvas",
- "version": "2.0.0",
- "homepage": "http://mattketmo.github.io/darkroomjs/",
- "authors": [
- "Matthieu Moquet "
- ],
- "license": "MIT",
- "dependencies": {
- "fabric": "~1.4.*"
- },
- "main": [
- "build/darkroom.css",
- "build/darkroom.js"
- ],
- "moduleType": [
- "globals"
- ],
- "keywords": [
- "image",
- "canvas",
- "crop"
- ],
- "ignore": [
- "node_modules",
- "bower_components",
- "test",
- "tests"
- ]
-}
diff --git a/web_widget_darkroom/static/lib/darkroomjs/core/darkroom.js b/web_widget_darkroom/static/lib/darkroomjs/core/darkroom.js
new file mode 100755
index 00000000..328fed20
--- /dev/null
+++ b/web_widget_darkroom/static/lib/darkroomjs/core/darkroom.js
@@ -0,0 +1,356 @@
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+(function() {
+ 'use strict';
+
+ window.Darkroom = Darkroom;
+
+ // Core object of DarkroomJS.
+ // Basically it's a single object, instanciable via an element
+ // (it could be a CSS selector or a DOM element), some custom options,
+ // and a list of plugin objects (or none to use default ones).
+ function Darkroom(element, options, plugins) {
+ return this.constructor(element, options, plugins);
+ }
+
+ // Create an empty list of plugin objects, which will be filled by
+ // other plugin scripts. This is the default plugin list if none is
+ // specified in Darkroom's constructor.
+ Darkroom.plugins = [];
+
+ Darkroom.prototype = {
+ // Reference to the main container element
+ containerElement: null,
+
+ // Reference to the Fabric canvas object
+ canvas: null,
+
+ // Reference to the Fabric image object
+ image: null,
+
+ // Reference to the Fabric source canvas object
+ sourceCanvas: null,
+
+ // Reference to the Fabric source image object
+ sourceImage: null,
+
+ // Track of the original image element
+ originalImageElement: null,
+
+ // Stack of transformations to apply to the image source
+ transformations: [],
+
+ // Default options
+ defaults: {
+ // Canvas properties (dimension, ratio, color)
+ minWidth: null,
+ minHeight: null,
+ maxWidth: null,
+ maxHeight: null,
+ ratio: null,
+ backgroundColor: '#fff',
+
+ // Plugins options
+ plugins: {},
+
+ // Post-initialisation callback
+ initialize: function() { /* noop */ }
+ },
+
+ // List of the instancied plugins
+ plugins: {},
+
+ // This options are a merge between `defaults` and the options passed
+ // through the constructor
+ options: {},
+
+ constructor: function(element, options) {
+ this.options = Darkroom.Utils.extend(options, this.defaults);
+
+ if (typeof element === 'string')
+ element = document.querySelector(element);
+ if (null === element)
+ return;
+
+ var image = new Image();
+ var parent = element.parentElement;
+ image.onload = function() {
+ // Initialize the DOM/Fabric elements
+ this._initializeDOM(element, parent);
+ this._initializeImage();
+
+ // Then initialize the plugins
+ this._initializePlugins(Darkroom.plugins);
+
+ // Public method to adjust image according to the canvas
+ this.refresh(function() {
+ // Execute a custom callback after initialization
+ this.options.initialize.bind(this).call();
+ }.bind(this));
+ }.bind(this);
+
+ image.src = element.src;
+ },
+
+ selfDestroy: function() {
+ var container = this.containerElement;
+ var image = new Image();
+ image.onload = function() {
+ container.parentNode.replaceChild(image, container);
+ };
+
+ image.src = this.sourceImage.toDataURL();
+ },
+
+ // Add ability to attach event listener on the core object.
+ // It uses the canvas element to process events.
+ addEventListener: function(eventName, callback) {
+ var el = this.canvas.getElement();
+ if (el.addEventListener) {
+ el.addEventListener(eventName, callback);
+ } else if (el.attachEvent) {
+ el.attachEvent('on' + eventName, callback);
+ }
+ },
+
+ dispatchEvent: function(eventName) {
+ // Use the old way of creating event to be IE compatible
+ // See https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
+ var event = document.createEvent('Event');
+ event.initEvent(eventName, true, true);
+
+ this.canvas.getElement().dispatchEvent(event);
+ },
+
+ // Adjust image & canvas dimension according to min/max width/height
+ // and ratio specified in the options.
+ // This method should be called after each image transformation.
+ refresh: function(next) {
+ var clone = new Image();
+ clone.onload = function() {
+ this._replaceCurrentImage(new fabric.Image(clone));
+ if (next) next();
+ }.bind(this);
+ clone.src = this.sourceImage.toDataURL();
+ },
+
+ _replaceCurrentImage: function(newImage) {
+ if (this.image) {
+ this.image.remove();
+ }
+
+ this.image = newImage;
+ this.image.selectable = false;
+
+ // Adjust width or height according to specified ratio
+ var viewport = Darkroom.Utils.computeImageViewPort(this.image);
+ var canvasWidth = viewport.width;
+ var canvasHeight = viewport.height;
+
+ if (null !== this.options.ratio) {
+ var canvasRatio = +this.options.ratio;
+ var currentRatio = canvasWidth / canvasHeight;
+
+ if (currentRatio > canvasRatio) {
+ canvasHeight = canvasWidth / canvasRatio;
+ } else if (currentRatio < canvasRatio) {
+ canvasWidth = canvasHeight * canvasRatio;
+ }
+ }
+
+ // Then scale the image to fit into dimension limits
+ var scaleMin = 1;
+ var scaleMax = 1;
+ var scaleX = 1;
+ var scaleY = 1;
+
+ if (null !== this.options.maxWidth && this.options.maxWidth < canvasWidth) {
+ scaleX = this.options.maxWidth / canvasWidth;
+ }
+ if (null !== this.options.maxHeight && this.options.maxHeight < canvasHeight) {
+ scaleY = this.options.maxHeight / canvasHeight;
+ }
+ scaleMin = Math.min(scaleX, scaleY);
+
+ scaleX = 1;
+ scaleY = 1;
+ if (null !== this.options.minWidth && this.options.minWidth > canvasWidth) {
+ scaleX = this.options.minWidth / canvasWidth;
+ }
+ if (null !== this.options.minHeight && this.options.minHeight > canvasHeight) {
+ scaleY = this.options.minHeight / canvasHeight;
+ }
+ scaleMax = Math.max(scaleX, scaleY);
+
+ var scale = scaleMax * scaleMin; // one should be equals to 1
+
+ canvasWidth *= scale;
+ canvasHeight *= scale;
+
+ // Finally place the image in the center of the canvas
+ this.image.setScaleX(1 * scale);
+ this.image.setScaleY(1 * scale);
+ this.canvas.add(this.image);
+ this.canvas.setWidth(canvasWidth);
+ this.canvas.setHeight(canvasHeight);
+ this.canvas.centerObject(this.image);
+ this.image.setCoords();
+ },
+
+ // Apply the transformation on the current image and save it in the
+ // transformations stack (in order to reconstitute the previous states
+ // of the image).
+ applyTransformation: function(transformation) {
+ this.transformations.push(transformation);
+
+ transformation.applyTransformation(
+ this.sourceCanvas,
+ this.sourceImage,
+ this._postTransformation.bind(this)
+ );
+ },
+
+ _postTransformation: function(newImage) {
+ if (newImage)
+ this.sourceImage = newImage;
+
+ this.refresh(function() {
+ this.dispatchEvent('core:transformation');
+ }.bind(this));
+ },
+
+ // Initialize image from original element plus re-apply every
+ // transformations.
+ reinitializeImage: function() {
+ this.sourceImage.remove();
+ this._initializeImage();
+ this._popTransformation(this.transformations.slice());
+ },
+
+ _popTransformation: function(transformations) {
+ if (0 === transformations.length) {
+ this.dispatchEvent('core:reinitialized');
+ this.refresh();
+ return;
+ }
+
+ var transformation = transformations.shift();
+
+ var next = function(newImage) {
+ if (newImage) this.sourceImage = newImage;
+ this._popTransformation(transformations);
+ };
+
+ transformation.applyTransformation(
+ this.sourceCanvas,
+ this.sourceImage,
+ next.bind(this)
+ );
+ },
+
+ // Create the DOM elements and instanciate the Fabric canvas.
+ // The image element is replaced by a new `div` element.
+ // However the original image is re-injected in order to keep a trace of it.
+ _initializeDOM: function(imageElement) {
+ // Container
+ var mainContainerElement = document.createElement('div');
+ mainContainerElement.className = 'darkroom-container';
+
+ // Toolbar
+ var toolbarElement = document.createElement('div');
+ toolbarElement.className = 'darkroom-toolbar';
+ mainContainerElement.appendChild(toolbarElement);
+
+ // Viewport canvas
+ var canvasContainerElement = document.createElement('div');
+ canvasContainerElement.className = 'darkroom-image-container';
+ var canvasElement = document.createElement('canvas');
+ canvasContainerElement.appendChild(canvasElement);
+ mainContainerElement.appendChild(canvasContainerElement);
+
+ // Source canvas
+ var sourceCanvasContainerElement = document.createElement('div');
+ sourceCanvasContainerElement.className = 'darkroom-source-container';
+ sourceCanvasContainerElement.style.display = 'none';
+ var sourceCanvasElement = document.createElement('canvas');
+ sourceCanvasContainerElement.appendChild(sourceCanvasElement);
+ mainContainerElement.appendChild(sourceCanvasContainerElement);
+
+ // Original image
+ imageElement.parentNode.replaceChild(mainContainerElement, imageElement);
+ imageElement.style.display = 'none';
+ mainContainerElement.appendChild(imageElement);
+
+ // Instanciate object from elements
+ this.containerElement = mainContainerElement;
+ this.originalImageElement = imageElement;
+
+ this.toolbar = new Darkroom.UI.Toolbar(toolbarElement);
+
+ this.canvas = new fabric.Canvas(canvasElement, {
+ selection: false,
+ backgroundColor: this.options.backgroundColor,
+ });
+
+ this.sourceCanvas = new fabric.Canvas(sourceCanvasElement, {
+ selection: false,
+ backgroundColor: this.options.backgroundColor,
+ });
+ },
+
+ // Instanciate the Fabric image object.
+ // The image is created as a static element with no control,
+ // then it is add in the Fabric canvas object.
+ _initializeImage: function() {
+ this.sourceImage = new fabric.Image(this.originalImageElement, {
+ // Some options to make the image static
+ selectable: false,
+ evented: false,
+ lockMovementX: true,
+ lockMovementY: true,
+ lockRotation: true,
+ lockScalingX: true,
+ lockScalingY: true,
+ lockUniScaling: true,
+ hasControls: false,
+ hasBorders: false,
+ });
+
+ this.sourceCanvas.add(this.sourceImage);
+
+ // Adjust width or height according to specified ratio
+ var viewport = Darkroom.Utils.computeImageViewPort(this.sourceImage);
+ var canvasWidth = viewport.width;
+ var canvasHeight = viewport.height;
+
+ this.sourceCanvas.setWidth(canvasWidth);
+ this.sourceCanvas.setHeight(canvasHeight);
+ this.sourceCanvas.centerObject(this.sourceImage);
+ this.sourceImage.setCoords();
+ },
+
+ // Initialize every plugins.
+ // Note that plugins are instanciated in the same order than they
+ // are declared in the parameter object.
+ _initializePlugins: function(plugins) {
+ for (var name in plugins) {
+ var plugin = plugins[name];
+ var options = this.options.plugins[name];
+
+ // Setting false into the plugin options will disable the plugin
+ if (options === false)
+ continue;
+
+ // Avoid any issues with _proto_
+ if (!plugins.hasOwnProperty(name))
+ continue;
+
+ this.plugins[name] = new plugin(this, options);
+ }
+ },
+ };
+})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/core/plugin.js b/web_widget_darkroom/static/lib/darkroomjs/core/plugin.js
new file mode 100755
index 00000000..03334418
--- /dev/null
+++ b/web_widget_darkroom/static/lib/darkroomjs/core/plugin.js
@@ -0,0 +1,47 @@
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+(function() {
+ 'use strict';
+
+ Darkroom.Plugin = Plugin;
+
+ // Define a plugin object. This is the (abstract) parent class which
+ // has to be extended for each plugin.
+ function Plugin(darkroom, options) {
+ this.darkroom = darkroom;
+ this.options = Darkroom.Utils.extend(options, this.defaults);
+ this.initialize();
+ }
+
+ Plugin.prototype = {
+ defaults: {},
+ initialize: function() { /* no-op */ }
+ };
+
+ // Inspired by Backbone.js extend capability.
+ Plugin.extend = function(protoProps) {
+ var parent = this;
+ var child;
+
+ if (protoProps && protoProps.hasOwnProperty('constructor')) {
+ child = protoProps.constructor;
+ } else {
+ child = function() { return parent.apply(this, arguments); };
+ }
+
+ Darkroom.Utils.extend(child, parent);
+
+ var Surrogate = function() { this.constructor = child; };
+ Surrogate.prototype = parent.prototype;
+ child.prototype = new Surrogate();
+
+ if (protoProps) Darkroom.Utils.extend(child.prototype, protoProps);
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/core/transformation.js b/web_widget_darkroom/static/lib/darkroomjs/core/transformation.js
new file mode 100755
index 00000000..8ea8441a
--- /dev/null
+++ b/web_widget_darkroom/static/lib/darkroomjs/core/transformation.js
@@ -0,0 +1,43 @@
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+(function() {
+ 'use strict';
+
+ Darkroom.Transformation = Transformation;
+
+ function Transformation(options) {
+ this.options = options;
+ }
+
+ Transformation.prototype = {
+ applyTransformation: function() { /* no-op */ }
+ };
+
+ // Inspired by Backbone.js extend capability.
+ Transformation.extend = function(protoProps) {
+ var parent = this;
+ var child;
+
+ if (protoProps && protoProps.hasOwnProperty('constructor')) {
+ child = protoProps.constructor;
+ } else {
+ child = function() { return parent.apply(this, arguments); };
+ }
+
+ Darkroom.Utils.extend(child, parent);
+
+ var Surrogate = function() { this.constructor = child; };
+ Surrogate.prototype = parent.prototype;
+ child.prototype = new Surrogate();
+
+ if (protoProps) Darkroom.Utils.extend(child.prototype, protoProps);
+
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/core/utils.js b/web_widget_darkroom/static/lib/darkroomjs/core/utils.js
new file mode 100755
index 00000000..2e0a5e21
--- /dev/null
+++ b/web_widget_darkroom/static/lib/darkroomjs/core/utils.js
@@ -0,0 +1,36 @@
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+(function() {
+ 'use strict';
+
+ Darkroom.Utils = {
+ extend: extend,
+ computeImageViewPort: computeImageViewPort,
+ };
+
+ // Utility method to easily extend objects.
+ function extend(b, a) {
+ var prop;
+ if (b === undefined) {
+ return a;
+ }
+
+ for (prop in a) {
+ if (a.hasOwnProperty(prop) && b.hasOwnProperty(prop) === false) {
+ b[prop] = a[prop];
+ }
+ }
+ return b;
+ }
+
+ function computeImageViewPort(image) {
+ return {
+ height: Math.abs(image.getWidth() * (Math.sin(image.getAngle() * Math.PI/180))) + Math.abs(image.getHeight() * (Math.cos(image.getAngle() * Math.PI/180))),
+ width: Math.abs(image.getHeight() * (Math.sin(image.getAngle() * Math.PI/180))) + Math.abs(image.getWidth() * (Math.cos(image.getAngle() * Math.PI/180))),
+ };
+ }
+})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/gh-pages.sh b/web_widget_darkroom/static/lib/darkroomjs/gh-pages.sh
deleted file mode 100755
index 2ae99a52..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/gh-pages.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/bin/bash
-
-# Update gh-pages branch
-git branch -D gh-pages
-git checkout -b gh-pages HEAD
-
-# Build assets
-rm -rf build
-gulp build --prod
-
-# Put build into demo folder
-rm demo/build
-cp -r build demo/build
-
-# Commit
-git add -f demo
-git commit -m "Build GH pages"
-
-# Push & reset
-git push origin `git subtree split --prefix demo HEAD`:gh-pages --force
-git checkout -
diff --git a/web_widget_darkroom/static/lib/darkroomjs/gulpfile.js b/web_widget_darkroom/static/lib/darkroomjs/gulpfile.js
deleted file mode 100755
index dced1e88..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/gulpfile.js
+++ /dev/null
@@ -1,112 +0,0 @@
-var concat = require('gulp-concat')
-var connect = require('gulp-connect')
-var gulp = require('gulp')
-var gutil = require('gulp-util')
-var htmlJsStr = require('js-string-escape')
-var inject = require('gulp-inject')
-var plumber = require('gulp-plumber')
-var rimraf = require('rimraf')
-var sass = require('gulp-sass')
-var sourcemaps = require('gulp-sourcemaps')
-var spawn = require("child_process").spawn
-var streamqueue = require('streamqueue')
-var svgmin = require('gulp-svgmin')
-var svgstore = require('gulp-svgstore')
-var uglify = require('gulp-uglify')
-
-
-//
-// Variables
-//
-var srcDir = './lib';
-var distDir = './build';
-var isDebug = !gutil.env.prod;
-
-//
-// Default
-//
-gulp.task('default', ['build'], function() {
- gulp.start('watch');
-});
-
-//
-// Clean
-//
-gulp.task('clean', function(cb) {
- rimraf(distDir, cb);
-});
-
-//
-// Build
-//
-gulp.task('build', ['clean'], function() {
- gulp.start('scripts', 'styles');
-});
-
-//
-// Watch
-//
-gulp.task('watch', ['server'], function() {
- gulp.watch(srcDir + '/js/**/*.js', ['scripts']);
-
- gulp.watch(srcDir + '/css/**/*.scss', ['styles']);
-});
-
-//
-// Server
-//
-gulp.task('server', function() {
- connect.server({
- root: './demo',
- port: 2222,
- livereload: false
- });
-});
-
-//
-// Javascript
-//
-gulp.task('scripts', function () {
- var svgs = gulp.src(srcDir + '/icons/*.svg')
- .pipe(svgmin())
- .pipe(svgstore({inlineSvg: true}))
- // .pipe(gulp.dest(distDir));
-
- function fileContents (filePath, file) {
- return file.contents.toString();
- }
-
- var files = [
- srcDir + '/js/core/bootstrap.js',
- srcDir + '/js/core/darkroom.js',
- srcDir + '/js/core/*.js',
- // srcDir + '/js/plugins/*.js',
- srcDir + '/js/plugins/darkroom.history.js',
- srcDir + '/js/plugins/darkroom.rotate.js',
- srcDir + '/js/plugins/darkroom.crop.js',
- srcDir + '/js/plugins/darkroom.save.js',
- ];
-
- gulp.src(files)
- .pipe(plumber())
- .pipe(isDebug ? sourcemaps.init() : gutil.noop())
- .pipe(concat('darkroom.js', {newLine: ';'}))
- .pipe(inject(svgs, { transform: fileContents }))
- .pipe(isDebug ? gutil.noop() : uglify({mangle: false}))
- .pipe(isDebug ? sourcemaps.write() : gutil.noop())
- .pipe(gulp.dest(distDir))
-})
-
-//
-// Stylesheet
-//
-gulp.task('styles', function () {
- gulp.src(srcDir + '/css/darkroom.scss')
- .pipe(plumber())
- .pipe(isDebug ? sourcemaps.init() : gutil.noop())
- .pipe(sass({
- outputStyle: isDebug ? 'nested' : 'compressed'
- }))
- .pipe(isDebug ? sourcemaps.write() : gutil.noop())
- .pipe(gulp.dest(distDir))
-})
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/css/_layout.scss b/web_widget_darkroom/static/lib/darkroomjs/lib/css/_layout.scss
deleted file mode 100755
index 693cd38a..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/css/_layout.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-.darkroom-container {
- position: relative;
-}
-
-.darkroom-image-container {
- top: 0;
- left: 0;
-}
-
-.darkroom-image-container img {
- // display: none;
-}
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/css/_toolbar.scss b/web_widget_darkroom/static/lib/darkroomjs/lib/css/_toolbar.scss
deleted file mode 100755
index f90aaac5..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/css/_toolbar.scss
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// Toolbar
-//
-.darkroom-toolbar {
- display: block;
- position: absolute;
- top: -45px;
- left: 0;
- background: #444;
- height: 40px;
- min-width: 40px;
- z-index: 99;
- border-radius: 2px;
- white-space: nowrap;
- padding: 0 5px;
-
- // Triangle
- &:before {
- content: "";
- position: absolute;
- bottom: -7px;
- left: 20px;
- width: 0;
- height: 0;
- border-left: 7px solid transparent;
- border-right: 7px solid transparent;
- border-top: 7px solid #444;
- }
-}
-
-//
-// Button Group
-//
-.darkroom-button-group {
- display: inline-block;
- margin: 0;
- padding: 0;
- // border-right: 1px solid #777;
-
- &:last-child {
- border-right: none;
- }
-}
-
-
-//
-// Button
-//
-.darkroom-button {
- box-sizing: border-box;
- background: transparent;
- border: none;
- outline: none;
- padding: 2px 0 0 0;
- width: 40px;
- height: 40px;
-
- &:hover {
- cursor: pointer;
- background: #555;
- }
- &:active {
- cursor: pointer;
- background: #333;
- }
-
- &:disabled .darkroom-icon {
- fill: #666;
- }
- &:disabled:hover {
- cursor: default;
- /*cursor: not-allowed;*/
- background: transparent;
- }
- &.darkroom-button-active .darkroom-icon {
- fill: #33b5e5;
- }
- &.darkroom-button-hidden {
- display: none;
- }
- &.darkroom-button-success .darkroom-icon {
- fill: #99cc00;
- }
- &.darkroom-button-warning .darkroom-icon {
- fill: #FFBB33;
- }
- &.darkroom-button-danger .darkroom-icon {
- fill: #FF4444;
- }
-}
-
-//
-// Icon
-//
-.darkroom-icon {
- width: 24px;
- height: 24px;
- fill: #fff;
-}
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/css/darkroom.scss b/web_widget_darkroom/static/lib/darkroomjs/lib/css/darkroom.scss
deleted file mode 100755
index 22d3411c..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/css/darkroom.scss
+++ /dev/null
@@ -1,2 +0,0 @@
-@import 'layout';
-@import 'toolbar';
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/close.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/close.svg
deleted file mode 100755
index 6c375ca8..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/close.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/crop.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/crop.svg
deleted file mode 100755
index f3affcc4..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/crop.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/done.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/done.svg
deleted file mode 100755
index 0af0fb9f..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/done.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/redo.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/redo.svg
deleted file mode 100755
index fb1cc3a1..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/redo.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/rotate-left.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/rotate-left.svg
deleted file mode 100755
index dd87ec4f..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/rotate-left.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/rotate-right.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/rotate-right.svg
deleted file mode 100755
index fdfae402..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/rotate-right.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/save.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/save.svg
deleted file mode 100755
index 2a4e62bb..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/save.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/undo.svg b/web_widget_darkroom/static/lib/darkroomjs/lib/icons/undo.svg
deleted file mode 100755
index 273f4918..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/icons/undo.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/bootstrap.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/bootstrap.js
deleted file mode 100755
index 34f32795..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/bootstrap.js
+++ /dev/null
@@ -1,14 +0,0 @@
-(function() {
-'use strict';
-
-// Inject SVG icons into the DOM
-var element = document.createElement('div');
-element.id = 'darkroom-icons';
-element.style.height = 0;
-element.style.width = 0;
-element.style.position = 'absolute';
-element.style.visibility = 'hidden';
-element.innerHTML = '';
-document.body.appendChild(element);
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/darkroom.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/darkroom.js
deleted file mode 100755
index 7ea5b363..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/darkroom.js
+++ /dev/null
@@ -1,354 +0,0 @@
-(function() {
-'use strict';
-
-window.Darkroom = Darkroom;
-
-// Core object of DarkroomJS.
-// Basically it's a single object, instanciable via an element
-// (it could be a CSS selector or a DOM element), some custom options,
-// and a list of plugin objects (or none to use default ones).
-function Darkroom(element, options, plugins) {
- return this.constructor(element, options, plugins);
-}
-
-// Create an empty list of plugin objects, which will be filled by
-// other plugin scripts. This is the default plugin list if none is
-// specified in Darkroom'ss constructor.
-Darkroom.plugins = [];
-
-Darkroom.prototype = {
- // Refenrece to the main container element
- containerElement: null,
-
- // Reference to the Fabric canvas object
- canvas: null,
-
- // Reference to the Fabric image object
- image: null,
-
- // Reference to the Fabric source canvas object
- sourceCanvas: null,
-
- // Reference to the Fabric source image object
- sourceImage: null,
-
- // Track of the original image element
- originalImageElement: null,
-
- // Stack of transformations to apply to the image source
- transformations: [],
-
- // Default options
- defaults: {
- // Canvas properties (dimension, ratio, color)
- minWidth: null,
- minHeight: null,
- maxWidth: null,
- maxHeight: null,
- ratio: null,
- backgroundColor: '#fff',
-
- // Plugins options
- plugins: {},
-
- // Post-initialisation callback
- initialize: function() { /* noop */ }
- },
-
- // List of the instancied plugins
- plugins: {},
-
- // This options are a merge between `defaults` and the options passed
- // through the constructor
- options: {},
-
- constructor: function(element, options, plugins) {
- this.options = Darkroom.Utils.extend(options, this.defaults);
-
- if (typeof element === 'string')
- element = document.querySelector(element);
- if (null === element)
- return;
-
- var image = new Image();
- var parent = element.parentElement;
- image.onload = function() {
- // Initialize the DOM/Fabric elements
- this._initializeDOM(element, parent);
- this._initializeImage();
-
- // Then initialize the plugins
- this._initializePlugins(Darkroom.plugins);
-
- // Public method to adjust image according to the canvas
- this.refresh(function() {
- // Execute a custom callback after initialization
- this.options.initialize.bind(this).call();
- }.bind(this));
-
- }.bind(this)
-
- //image.crossOrigin = 'anonymous';
- image.src = element.src;
- },
-
- selfDestroy: function() {
- var container = this.containerElement;
- var image = new Image();
- image.onload = function() {
- container.parentNode.replaceChild(image, container);
- }
-
- image.src = this.sourceImage.toDataURL();
- },
-
- // Add ability to attach event listener on the core object.
- // It uses the canvas element to process events.
- addEventListener: function(eventName, callback) {
- var el = this.canvas.getElement();
- if (el.addEventListener){
- el.addEventListener(eventName, callback);
- } else if (el.attachEvent) {
- el.attachEvent('on' + eventName, callback);
- }
- },
-
- dispatchEvent: function(eventName) {
- // Use the old way of creating event to be IE compatible
- // See https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
- var event = document.createEvent('Event');
- event.initEvent(eventName, true, true);
-
- this.canvas.getElement().dispatchEvent(event);
- },
-
- // Adjust image & canvas dimension according to min/max width/height
- // and ratio specified in the options.
- // This method should be called after each image transformation.
- refresh: function(next) {
- var clone = new Image();
- clone.onload = function() {
- this._replaceCurrentImage(new fabric.Image(clone));
-
- if (next) next();
- }.bind(this);
- clone.src = this.sourceImage.toDataURL();
- },
-
- _replaceCurrentImage: function(newImage) {
- if (this.image) {
- this.image.remove();
- }
-
- this.image = newImage;
- this.image.selectable = false;
-
- // Adjust width or height according to specified ratio
- var viewport = Darkroom.Utils.computeImageViewPort(this.image);
- var canvasWidth = viewport.width;
- var canvasHeight = viewport.height;
-
- if (null !== this.options.ratio) {
- var canvasRatio = +this.options.ratio;
- var currentRatio = canvasWidth / canvasHeight;
-
- if (currentRatio > canvasRatio) {
- canvasHeight = canvasWidth / canvasRatio;
- } else if (currentRatio < canvasRatio) {
- canvasWidth = canvasHeight * canvasRatio;
- }
- }
-
- // Then scale the image to fit into dimension limits
- var scaleMin = 1;
- var scaleMax = 1;
- var scaleX = 1;
- var scaleY = 1;
-
- if (null !== this.options.maxWidth && this.options.maxWidth < canvasWidth) {
- scaleX = this.options.maxWidth / canvasWidth;
- }
- if (null !== this.options.maxHeight && this.options.maxHeight < canvasHeight) {
- scaleY = this.options.maxHeight / canvasHeight;
- }
- scaleMin = Math.min(scaleX, scaleY);
-
- scaleX = 1;
- scaleY = 1;
- if (null !== this.options.minWidth && this.options.minWidth > canvasWidth) {
- scaleX = this.options.minWidth / canvasWidth;
- }
- if (null !== this.options.minHeight && this.options.minHeight > canvasHeight) {
- scaleY = this.options.minHeight / canvasHeight;
- }
- scaleMax = Math.max(scaleX, scaleY);
-
- var scale = scaleMax * scaleMin; // one should be equals to 1
-
- canvasWidth *= scale;
- canvasHeight *= scale;
-
- // Finally place the image in the center of the canvas
- this.image.setScaleX(1 * scale);
- this.image.setScaleY(1 * scale);
- this.canvas.add(this.image);
- this.canvas.setWidth(canvasWidth);
- this.canvas.setHeight(canvasHeight);
- this.canvas.centerObject(this.image);
- this.image.setCoords();
- },
-
- // Apply the transformation on the current image and save it in the
- // transformations stack (in order to reconstitute the previous states
- // of the image).
- applyTransformation: function(transformation) {
- this.transformations.push(transformation);
-
- transformation.applyTransformation(
- this.sourceCanvas,
- this.sourceImage,
- this._postTransformation.bind(this)
- );
- },
-
- _postTransformation: function(newImage) {
- if (newImage)
- this.sourceImage = newImage;
-
- this.refresh(function() {
- this.dispatchEvent('core:transformation');
- }.bind(this));
- },
-
- // Initialize image from original element plus re-apply every
- // transformations.
- reinitializeImage: function() {
- this.sourceImage.remove();
- this._initializeImage();
- this._popTransformation(this.transformations.slice())
- },
-
- _popTransformation: function(transformations) {
- if (0 === transformations.length) {
- this.dispatchEvent('core:reinitialized');
- this.refresh();
- return;
- }
-
- var transformation = transformations.shift();
-
- var next = function(newImage) {
- if (newImage) this.sourceImage = newImage;
- this._popTransformation(transformations)
- };
-
- transformation.applyTransformation(
- this.sourceCanvas,
- this.sourceImage,
- next.bind(this)
- );
- },
-
- // Create the DOM elements and instanciate the Fabric canvas.
- // The image element is replaced by a new `div` element.
- // However the original image is re-injected in order to keep a trace of it.
- _initializeDOM: function(imageElement) {
- // Container
- var mainContainerElement = document.createElement('div');
- mainContainerElement.className = 'darkroom-container';
-
- // Toolbar
- var toolbarElement = document.createElement('div');
- toolbarElement.className = 'darkroom-toolbar';
- mainContainerElement.appendChild(toolbarElement);
-
- // Viewport canvas
- var canvasContainerElement = document.createElement('div');
- canvasContainerElement.className = 'darkroom-image-container';
- var canvasElement = document.createElement('canvas');
- canvasContainerElement.appendChild(canvasElement);
- mainContainerElement.appendChild(canvasContainerElement);
-
- // Source canvas
- var sourceCanvasContainerElement = document.createElement('div');
- sourceCanvasContainerElement.className = 'darkroom-source-container';
- sourceCanvasContainerElement.style.display = 'none';
- var sourceCanvasElement = document.createElement('canvas');
- sourceCanvasContainerElement.appendChild(sourceCanvasElement);
- mainContainerElement.appendChild(sourceCanvasContainerElement);
-
- // Original image
- imageElement.parentNode.replaceChild(mainContainerElement, imageElement);
- imageElement.style.display = 'none';
- mainContainerElement.appendChild(imageElement);
-
- // Instanciate object from elements
- this.containerElement = mainContainerElement;
- this.originalImageElement = imageElement;
-
- this.toolbar = new Darkroom.UI.Toolbar(toolbarElement);
-
- this.canvas = new fabric.Canvas(canvasElement, {
- selection: false,
- backgroundColor: this.options.backgroundColor
- });
-
- this.sourceCanvas = new fabric.Canvas(sourceCanvasElement, {
- selection: false,
- backgroundColor: this.options.backgroundColor
- });
- },
-
- // Instanciate the Fabric image object.
- // The image is created as a static element with no control,
- // then it is add in the Fabric canvas object.
- _initializeImage: function() {
- this.sourceImage = new fabric.Image(this.originalImageElement, {
- // Some options to make the image static
- selectable: false,
- evented: false,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- lockUniScaling: true,
- hasControls: false,
- hasBorders: false,
- });
-
- this.sourceCanvas.add(this.sourceImage);
-
- // Adjust width or height according to specified ratio
- var viewport = Darkroom.Utils.computeImageViewPort(this.sourceImage);
- var canvasWidth = viewport.width;
- var canvasHeight = viewport.height;
-
- this.sourceCanvas.setWidth(canvasWidth);
- this.sourceCanvas.setHeight(canvasHeight);
- this.sourceCanvas.centerObject(this.sourceImage);
- this.sourceImage.setCoords();
- },
-
- // Initialize every plugins.
- // Note that plugins are instanciated in the same order than they
- // are declared in the parameter object.
- _initializePlugins: function(plugins) {
- for (var name in plugins) {
- var plugin = plugins[name];
- var options = this.options.plugins[name];
-
- // Setting false into the plugin options will disable the plugin
- if (options === false)
- continue;
-
- // Avoid any issues with _proto_
- if (!plugins.hasOwnProperty(name))
- continue;
-
- this.plugins[name] = new plugin(this, options);
- }
- },
-}
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/plugin.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/plugin.js
deleted file mode 100755
index 07b35a05..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/plugin.js
+++ /dev/null
@@ -1,43 +0,0 @@
-(function() {
-'use strict';
-
-Darkroom.Plugin = Plugin;
-
-// Define a plugin object. This is the (abstract) parent class which
-// has to be extended for each plugin.
-function Plugin(darkroom, options) {
- this.darkroom = darkroom;
- this.options = Darkroom.Utils.extend(options, this.defaults);
- this.initialize();
-}
-
-Plugin.prototype = {
- defaults: {},
- initialize: function() { }
-}
-
-// Inspired by Backbone.js extend capability.
-Plugin.extend = function(protoProps) {
- var parent = this;
- var child;
-
- if (protoProps && protoProps.hasOwnProperty('constructor')) {
- child = protoProps.constructor;
- } else {
- child = function(){ return parent.apply(this, arguments); };
- }
-
- Darkroom.Utils.extend(child, parent);
-
- var Surrogate = function(){ this.constructor = child; };
- Surrogate.prototype = parent.prototype;
- child.prototype = new Surrogate;
-
- if (protoProps) Darkroom.Utils.extend(child.prototype, protoProps);
-
- child.__super__ = parent.prototype;
-
- return child;
-}
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/transformation.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/transformation.js
deleted file mode 100755
index e0d27461..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/transformation.js
+++ /dev/null
@@ -1,38 +0,0 @@
-(function() {
-'use strict';
-
-Darkroom.Transformation = Transformation;
-
-function Transformation(options) {
- this.options = options;
-}
-
-Transformation.prototype = {
- applyTransformation: function(image) { /* no-op */ }
-}
-
-// Inspired by Backbone.js extend capability.
-Transformation.extend = function(protoProps) {
- var parent = this;
- var child;
-
- if (protoProps && protoProps.hasOwnProperty('constructor')) {
- child = protoProps.constructor;
- } else {
- child = function(){ return parent.apply(this, arguments); };
- }
-
- Darkroom.Utils.extend(child, parent);
-
- var Surrogate = function(){ this.constructor = child; };
- Surrogate.prototype = parent.prototype;
- child.prototype = new Surrogate;
-
- if (protoProps) Darkroom.Utils.extend(child.prototype, protoProps);
-
- child.__super__ = parent.prototype;
-
- return child;
-}
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/ui.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/ui.js
deleted file mode 100755
index b4d752a8..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/ui.js
+++ /dev/null
@@ -1,91 +0,0 @@
-(function() {
-'use strict';
-
-Darkroom.UI = {
- Toolbar: Toolbar,
- ButtonGroup: ButtonGroup,
- Button: Button,
-};
-
-// Toolbar object.
-function Toolbar(element) {
- this.element = element;
-}
-
-Toolbar.prototype = {
- createButtonGroup: function(options) {
- var buttonGroup = document.createElement('div');
- buttonGroup.className = 'darkroom-button-group';
- this.element.appendChild(buttonGroup);
-
- return new ButtonGroup(buttonGroup);
- }
-};
-
-// ButtonGroup object.
-function ButtonGroup(element) {
- this.element = element;
-}
-
-ButtonGroup.prototype = {
- createButton: function(options) {
- var defaults = {
- image: 'help',
- type: 'default',
- group: 'default',
- hide: false,
- disabled: false
- };
-
- options = Darkroom.Utils.extend(options, defaults);
-
- var buttonElement = document.createElement('button');
- buttonElement.type = 'button';
- buttonElement.className = 'darkroom-button darkroom-button-' + options.type;
- buttonElement.innerHTML = '';
- this.element.appendChild(buttonElement);
-
- var button = new Button(buttonElement);
- button.hide(options.hide);
- button.disable(options.disabled);
-
- return button;
- }
-}
-
-// Button object.
-function Button(element) {
- this.element = element;
-}
-
-Button.prototype = {
- addEventListener: function(eventName, listener) {
- if (this.element.addEventListener){
- this.element.addEventListener(eventName, listener);
- } else if (this.element.attachEvent) {
- this.element.attachEvent('on' + eventName, listener);
- }
- },
- removeEventListener: function(eventName, listener) {
- if (this.element.removeEventListener){
- this.element.removeEventListener(eventName, listener);
- }
- },
- active: function(value) {
- if (value)
- this.element.classList.add('darkroom-button-active');
- else
- this.element.classList.remove('darkroom-button-active');
- },
- hide: function(value) {
- if (value)
- this.element.classList.add('darkroom-button-hidden');
- else
- this.element.classList.remove('darkroom-button-hidden');
- },
- disable: function(value) {
- this.element.disabled = (value) ? true : false;
- }
-};
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/utils.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/utils.js
deleted file mode 100755
index f4de5f9a..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/core/utils.js
+++ /dev/null
@@ -1,31 +0,0 @@
-(function() {
-'use strict';
-
-Darkroom.Utils = {
- extend: extend,
- computeImageViewPort: computeImageViewPort,
-};
-
-
-// Utility method to easily extend objects.
-function extend(b, a) {
- var prop;
- if (b === undefined) {
- return a;
- }
- for (prop in a) {
- if (a.hasOwnProperty(prop) && b.hasOwnProperty(prop) === false) {
- b[prop] = a[prop];
- }
- }
- return b;
-}
-
-function computeImageViewPort(image) {
- return {
- height: Math.abs(image.getWidth() * (Math.sin(image.getAngle() * Math.PI/180))) + Math.abs(image.getHeight() * (Math.cos(image.getAngle() * Math.PI/180))),
- width: Math.abs(image.getHeight() * (Math.sin(image.getAngle() * Math.PI/180))) + Math.abs(image.getWidth() * (Math.cos(image.getAngle() * Math.PI/180))),
- }
-}
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.crop.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.crop.js
deleted file mode 100755
index 9c441823..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.crop.js
+++ /dev/null
@@ -1,669 +0,0 @@
-(function() {
-'use strict';
-
-var Crop = Darkroom.Transformation.extend({
- applyTransformation: function(canvas, image, next) {
- // Snapshot the image delimited by the crop zone
- var snapshot = new Image();
- snapshot.onload = function() {
- // Validate image
- if (height < 1 || width < 1)
- return;
-
- var imgInstance = new fabric.Image(this, {
- // options to make the image static
- selectable: false,
- evented: false,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- lockUniScaling: true,
- hasControls: false,
- hasBorders: false
- });
-
- var width = this.width;
- var height = this.height;
-
- // Update canvas size
- canvas.setWidth(width);
- canvas.setHeight(height);
-
- // Add image
- image.remove();
- canvas.add(imgInstance);
-
- next(imgInstance);
- };
-
- var viewport = Darkroom.Utils.computeImageViewPort(image);
- var imageWidth = viewport.width;
- var imageHeight = viewport.height;
-
- var left = this.options.left * imageWidth;
- var top = this.options.top * imageHeight;
- var width = Math.min(this.options.width * imageWidth, imageWidth - left);
- var height = Math.min(this.options.height * imageHeight, imageHeight - top);
-
- snapshot.src = canvas.toDataURL({
- left: left,
- top: top,
- width: width,
- height: height,
- });
- }
-});
-
-var CropZone = fabric.util.createClass(fabric.Rect, {
- _render: function(ctx) {
- this.callSuper('_render', ctx);
-
- var canvas = ctx.canvas;
- var dashWidth = 7;
-
- // Set original scale
- var flipX = this.flipX ? -1 : 1;
- var flipY = this.flipY ? -1 : 1;
- var scaleX = flipX / this.scaleX;
- var scaleY = flipY / this.scaleY;
-
- ctx.scale(scaleX, scaleY);
-
- // Overlay rendering
- ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
- this._renderOverlay(ctx);
-
- // Set dashed borders
- if (ctx.setLineDash !== undefined)
- ctx.setLineDash([dashWidth, dashWidth]);
- else if (ctx.mozDash !== undefined)
- ctx.mozDash = [dashWidth, dashWidth];
-
- // First lines rendering with black
- ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
- this._renderBorders(ctx);
- this._renderGrid(ctx);
-
- // Re render lines in white
- ctx.lineDashOffset = dashWidth;
- ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
- this._renderBorders(ctx);
- this._renderGrid(ctx);
-
- // Reset scale
- ctx.scale(1/scaleX, 1/scaleY);
- },
-
- _renderOverlay: function(ctx) {
- var canvas = ctx.canvas;
- var borderOffset = 0;
-
- //
- // x0 x1 x2 x3
- // y0 +------------------------+
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // y1 +------+---------+-------+
- // |\\\\\\| |\\\\\\\|
- // |\\\\\\| 0 |\\\\\\\|
- // |\\\\\\| |\\\\\\\|
- // y2 +------+---------+-------+
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // y3 +------------------------+
- //
-
- var x0 = Math.ceil(-this.getWidth() / 2 - this.getLeft());
- var x1 = Math.ceil(-this.getWidth() / 2);
- var x2 = Math.ceil(this.getWidth() / 2);
- var x3 = Math.ceil(this.getWidth() / 2 + (canvas.width - this.getWidth() - this.getLeft()));
-
- var y0 = Math.ceil(-this.getHeight() / 2 - this.getTop());
- var y1 = Math.ceil(-this.getHeight() / 2);
- var y2 = Math.ceil(this.getHeight() / 2);
- var y3 = Math.ceil(this.getHeight() / 2 + (canvas.height - this.getHeight() - this.getTop()));
-
- // Upper rect
- ctx.fillRect(x0, y0, x3 - x0, y1 - y0 + borderOffset);
-
- // Left rect
- ctx.fillRect(x0, y1, x1 - x0, y2 - y1 + borderOffset);
-
- // Right rect
- ctx.fillRect(x2, y1, x3 - x2, y2 - y1 + borderOffset);
-
- // Down rect
- ctx.fillRect(x0, y2, x3 - x0, y3 - y2);
- },
-
- _renderBorders: function(ctx) {
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2); // upper left
- ctx.lineTo(this.getWidth()/2, -this.getHeight()/2); // upper right
- ctx.lineTo(this.getWidth()/2, this.getHeight()/2); // down right
- ctx.lineTo(-this.getWidth()/2, this.getHeight()/2); // down left
- ctx.lineTo(-this.getWidth()/2, -this.getHeight()/2); // upper left
- ctx.stroke();
- },
-
- _renderGrid: function(ctx) {
- // Vertical lines
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2 + 1/3 * this.getWidth(), -this.getHeight()/2);
- ctx.lineTo(-this.getWidth()/2 + 1/3 * this.getWidth(), this.getHeight()/2);
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2 + 2/3 * this.getWidth(), -this.getHeight()/2);
- ctx.lineTo(-this.getWidth()/2 + 2/3 * this.getWidth(), this.getHeight()/2);
- ctx.stroke();
- // Horizontal lines
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2 + 1/3 * this.getHeight());
- ctx.lineTo(this.getWidth()/2, -this.getHeight()/2 + 1/3 * this.getHeight());
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2 + 2/3 * this.getHeight());
- ctx.lineTo(this.getWidth()/2, -this.getHeight()/2 + 2/3 * this.getHeight());
- ctx.stroke();
- }
-});
-
-Darkroom.plugins['crop'] = Darkroom.Plugin.extend({
- // Init point
- startX: null,
- startY: null,
-
- // Keycrop
- isKeyCroping: false,
- isKeyLeft: false,
- isKeyUp: false,
-
- defaults: {
- // min crop dimension
- minHeight: 1,
- minWidth: 1,
- // ensure crop ratio
- ratio: null,
- // quick crop feature (set a key code to enable it)
- quickCropKey: false
- },
-
- initialize: function InitDarkroomCropPlugin() {
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- this.cropButton = buttonGroup.createButton({
- image: 'crop'
- });
- this.okButton = buttonGroup.createButton({
- image: 'done',
- type: 'success',
- hide: true
- });
- this.cancelButton = buttonGroup.createButton({
- image: 'close',
- type: 'danger',
- hide: true
- });
-
- // Buttons click
- this.cropButton.addEventListener('click', this.toggleCrop.bind(this));
- this.okButton.addEventListener('click', this.cropCurrentZone.bind(this));
- this.cancelButton.addEventListener('click', this.releaseFocus.bind(this));
-
- // Canvas events
- this.darkroom.canvas.on('mouse:down', this.onMouseDown.bind(this));
- this.darkroom.canvas.on('mouse:move', this.onMouseMove.bind(this));
- this.darkroom.canvas.on('mouse:up', this.onMouseUp.bind(this));
- this.darkroom.canvas.on('object:moving', this.onObjectMoving.bind(this));
- this.darkroom.canvas.on('object:scaling', this.onObjectScaling.bind(this));
-
- fabric.util.addListener(fabric.document, 'keydown', this.onKeyDown.bind(this));
- fabric.util.addListener(fabric.document, 'keyup', this.onKeyUp.bind(this));
-
- this.darkroom.addEventListener('core:transformation', this.releaseFocus.bind(this));
- },
-
- // Avoid crop zone to go beyond the canvas edges
- onObjectMoving: function(event) {
- if (!this.hasFocus()) {
- return;
- }
-
- var currentObject = event.target;
- if (currentObject !== this.cropZone)
- return;
-
- var canvas = this.darkroom.canvas;
- var x = currentObject.getLeft(), y = currentObject.getTop();
- var w = currentObject.getWidth(), h = currentObject.getHeight();
- var maxX = canvas.getWidth() - w;
- var maxY = canvas.getHeight() - h;
-
- if (x < 0)
- currentObject.set('left', 0);
- if (y < 0)
- currentObject.set('top', 0);
- if (x > maxX)
- currentObject.set('left', maxX);
- if (y > maxY)
- currentObject.set('top', maxY);
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- // Prevent crop zone from going beyond the canvas edges (like mouseMove)
- onObjectScaling: function(event) {
- if (!this.hasFocus()) {
- return;
- }
-
- var preventScaling = false;
- var currentObject = event.target;
- if (currentObject !== this.cropZone)
- return;
-
- var canvas = this.darkroom.canvas;
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
-
- var minX = currentObject.getLeft();
- var minY = currentObject.getTop();
- var maxX = currentObject.getLeft() + currentObject.getWidth();
- var maxY = currentObject.getTop() + currentObject.getHeight();
-
- if (null !== this.options.ratio) {
- if (minX < 0 || maxX > canvas.getWidth() || minY < 0 || maxY > canvas.getHeight()) {
- preventScaling = true;
- }
- }
-
- if (minX < 0 || maxX > canvas.getWidth() || preventScaling) {
- var lastScaleX = this.lastScaleX || 1;
- currentObject.setScaleX(lastScaleX);
- }
- if (minX < 0) {
- currentObject.setLeft(0);
- }
-
- if (minY < 0 || maxY > canvas.getHeight() || preventScaling) {
- var lastScaleY = this.lastScaleY || 1;
- currentObject.setScaleY(lastScaleY);
- }
- if (minY < 0) {
- currentObject.setTop(0);
- }
-
- if (currentObject.getWidth() < this.options.minWidth) {
- currentObject.scaleToWidth(this.options.minWidth);
- }
- if (currentObject.getHeight() < this.options.minHeight) {
- currentObject.scaleToHeight(this.options.minHeight);
- }
-
- this.lastScaleX = currentObject.getScaleX();
- this.lastScaleY = currentObject.getScaleY();
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- // Init crop zone
- onMouseDown: function(event) {
- if (!this.hasFocus()) {
- return;
- }
-
- var canvas = this.darkroom.canvas;
-
- // recalculate offset, in case canvas was manipulated since last `calcOffset`
- canvas.calcOffset();
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
- var point = new fabric.Point(x, y);
-
- // Check if user want to scale or drag the crop zone.
- var activeObject = canvas.getActiveObject();
- if (activeObject === this.cropZone || this.cropZone.containsPoint(point)) {
- return;
- }
-
- canvas.discardActiveObject();
- this.cropZone.setWidth(0);
- this.cropZone.setHeight(0);
- this.cropZone.setScaleX(1);
- this.cropZone.setScaleY(1);
-
- this.startX = x;
- this.startY = y;
- },
-
- // Extend crop zone
- onMouseMove: function(event) {
- // Quick crop feature
- if (this.isKeyCroping)
- return this.onMouseMoveKeyCrop(event);
-
- if (null === this.startX || null === this.startY) {
- return;
- }
-
- var canvas = this.darkroom.canvas;
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
-
- this._renderCropZone(this.startX, this.startY, x, y);
- },
-
- onMouseMoveKeyCrop: function(event) {
- var canvas = this.darkroom.canvas;
- var zone = this.cropZone;
-
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
-
- if (!zone.left || !zone.top) {
- zone.setTop(y);
- zone.setLeft(x);
- }
-
- this.isKeyLeft = x < zone.left + zone.width / 2 ;
- this.isKeyUp = y < zone.top + zone.height / 2 ;
-
- this._renderCropZone(
- Math.min(zone.left, x),
- Math.min(zone.top, y),
- Math.max(zone.left+zone.width, x),
- Math.max(zone.top+zone.height, y)
- );
- },
-
- // Finish crop zone
- onMouseUp: function(event) {
- if (null === this.startX || null === this.startY) {
- return;
- }
-
- var canvas = this.darkroom.canvas;
- this.cropZone.setCoords();
- canvas.setActiveObject(this.cropZone);
- canvas.calcOffset();
-
- this.startX = null;
- this.startY = null;
- },
-
- onKeyDown: function(event) {
- if (false === this.options.quickCropKey || event.keyCode !== this.options.quickCropKey || this.isKeyCroping)
- return;
-
- // Active quick crop flow
- this.isKeyCroping = true ;
- this.darkroom.canvas.discardActiveObject();
- this.cropZone.setWidth(0);
- this.cropZone.setHeight(0);
- this.cropZone.setScaleX(1);
- this.cropZone.setScaleY(1);
- this.cropZone.setTop(0);
- this.cropZone.setLeft(0);
- },
-
- onKeyUp: function(event) {
- if (false === this.options.quickCropKey || event.keyCode !== this.options.quickCropKey || !this.isKeyCroping)
- return;
-
- // Unactive quick crop flow
- this.isKeyCroping = false;
- this.startX = 1;
- this.startY = 1;
- this.onMouseUp();
- },
-
- selectZone: function(x, y, width, height, forceDimension) {
- if (!this.hasFocus())
- this.requireFocus();
-
- if (!forceDimension) {
- this._renderCropZone(x, y, x+width, y+height);
- } else {
- this.cropZone.set({
- 'left': x,
- 'top': y,
- 'width': width,
- 'height': height
- });
- }
-
- var canvas = this.darkroom.canvas;
- canvas.bringToFront(this.cropZone);
- this.cropZone.setCoords();
- canvas.setActiveObject(this.cropZone);
- canvas.calcOffset();
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- toggleCrop: function() {
- if (!this.hasFocus())
- this.requireFocus();
- else
- this.releaseFocus();
- },
-
- cropCurrentZone: function() {
- if (!this.hasFocus())
- return;
-
- // Avoid croping empty zone
- if (this.cropZone.width < 1 && this.cropZone.height < 1)
- return;
-
- var image = this.darkroom.image;
-
- // Compute crop zone dimensions
- var top = this.cropZone.getTop() - image.getTop();
- var left = this.cropZone.getLeft() - image.getLeft();
- var width = this.cropZone.getWidth();
- var height = this.cropZone.getHeight();
-
- // Adjust dimensions to image only
- if (top < 0) {
- height += top;
- top = 0;
- }
-
- if (left < 0) {
- width += left;
- left = 0;
- }
-
- // Apply crop transformation.
- // Make sure to use relative dimension since the crop will be applied
- // on the source image.
- this.darkroom.applyTransformation(new Crop({
- top: top / image.getHeight(),
- left: left / image.getWidth(),
- width: width / image.getWidth(),
- height: height / image.getHeight(),
- }));
- },
-
- // Test wether crop zone is set
- hasFocus: function() {
- return this.cropZone !== undefined;
- },
-
- // Create the crop zone
- requireFocus: function() {
- this.cropZone = new CropZone({
- fill: 'transparent',
- hasBorders: false,
- originX: 'left',
- originY: 'top',
- //stroke: '#444',
- //strokeDashArray: [5, 5],
- //borderColor: '#444',
- cornerColor: '#444',
- cornerSize: 8,
- transparentCorners: false,
- lockRotation: true,
- hasRotatingPoint: false,
- });
-
- if (null !== this.options.ratio) {
- this.cropZone.set('lockUniScaling', true);
- }
-
- this.darkroom.canvas.add(this.cropZone);
- this.darkroom.canvas.defaultCursor = 'crosshair';
-
- this.cropButton.active(true);
- this.okButton.hide(false);
- this.cancelButton.hide(false);
- },
-
- // Remove the crop zone
- releaseFocus: function() {
- if (undefined === this.cropZone)
- return;
-
- this.cropZone.remove();
- this.cropZone = undefined;
-
- this.cropButton.active(false);
- this.okButton.hide(true);
- this.cancelButton.hide(true);
-
- this.darkroom.canvas.defaultCursor = 'default';
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- _renderCropZone: function(fromX, fromY, toX, toY) {
- var canvas = this.darkroom.canvas;
-
- var isRight = (toX > fromX);
- var isLeft = !isRight;
- var isDown = (toY > fromY);
- var isUp = !isDown;
-
- var minWidth = Math.min(+this.options.minWidth, canvas.getWidth());
- var minHeight = Math.min(+this.options.minHeight, canvas.getHeight());
-
- // Define corner coordinates
- var leftX = Math.min(fromX, toX);
- var rightX = Math.max(fromX, toX);
- var topY = Math.min(fromY, toY);
- var bottomY = Math.max(fromY, toY);
-
- // Replace current point into the canvas
- leftX = Math.max(0, leftX);
- rightX = Math.min(canvas.getWidth(), rightX);
- topY = Math.max(0, topY)
- bottomY = Math.min(canvas.getHeight(), bottomY);
-
- // Recalibrate coordinates according to given options
- if (rightX - leftX < minWidth) {
- if (isRight)
- rightX = leftX + minWidth;
- else
- leftX = rightX - minWidth;
- }
- if (bottomY - topY < minHeight) {
- if (isDown)
- bottomY = topY + minHeight;
- else
- topY = bottomY - minHeight;
- }
-
- // Truncate truncate according to canvas dimensions
- if (leftX < 0) {
- // Translate to the left
- rightX += Math.abs(leftX);
- leftX = 0
- }
- if (rightX > canvas.getWidth()) {
- // Translate to the right
- leftX -= (rightX - canvas.getWidth());
- rightX = canvas.getWidth();
- }
- if (topY < 0) {
- // Translate to the bottom
- bottomY += Math.abs(topY);
- topY = 0
- }
- if (bottomY > canvas.getHeight()) {
- // Translate to the right
- topY -= (bottomY - canvas.getHeight());
- bottomY = canvas.getHeight();
- }
-
- var width = rightX - leftX;
- var height = bottomY - topY;
- var currentRatio = width / height;
-
- if (this.options.ratio && +this.options.ratio !== currentRatio) {
- var ratio = +this.options.ratio;
-
- if(this.isKeyCroping) {
- isLeft = this.isKeyLeft;
- isUp = this.isKeyUp;
- }
-
- if (currentRatio < ratio) {
- var newWidth = height * ratio;
- if (isLeft) {
- leftX -= (newWidth - width);
- }
- width = newWidth;
- } else if (currentRatio > ratio) {
- var newHeight = height / (ratio * height/width);
- if (isUp) {
- topY -= (newHeight - height);
- }
- height = newHeight;
- }
-
- if (leftX < 0) {
- leftX = 0;
- //TODO
- }
- if (topY < 0) {
- topY = 0;
- //TODO
- }
- if (leftX + width > canvas.getWidth()) {
- var newWidth = canvas.getWidth() - leftX;
- height = newWidth * height / width;
- width = newWidth;
- if (isUp) {
- topY = fromY - height;
- }
- }
- if (topY + height > canvas.getHeight()) {
- var newHeight = canvas.getHeight() - topY;
- width = width * newHeight / height;
- height = newHeight;
- if (isLeft) {
- leftX = fromX - width;
- }
- }
- }
-
- // Apply coordinates
- this.cropZone.left = leftX;
- this.cropZone.top = topY;
- this.cropZone.width = width;
- this.cropZone.height = height;
-
- this.darkroom.canvas.bringToFront(this.cropZone);
-
- this.darkroom.dispatchEvent('crop:update');
- }
-});
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.history.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.history.js
deleted file mode 100755
index 81bea34a..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.history.js
+++ /dev/null
@@ -1,66 +0,0 @@
-;(function(window, document, Darkroom, fabric) {
- 'use strict';
-
- Darkroom.plugins['history'] = Darkroom.Plugin.extend({
- undoTransformations: [],
-
- initialize: function InitDarkroomHistoryPlugin() {
- this._initButtons();
-
- this.darkroom.addEventListener('core:transformation', this._onTranformationApplied.bind(this));
- },
-
- undo: function() {
- if (this.darkroom.transformations.length === 0) {
- return;
- }
-
- var lastTransformation = this.darkroom.transformations.pop();
- this.undoTransformations.unshift(lastTransformation);
-
- this.darkroom.reinitializeImage();
- this._updateButtons();
- },
-
- redo: function() {
- if (this.undoTransformations.length === 0) {
- return;
- }
-
- var cancelTransformation = this.undoTransformations.shift();
- this.darkroom.transformations.push(cancelTransformation);
-
- this.darkroom.reinitializeImage();
- this._updateButtons();
- },
-
- _initButtons: function() {
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- this.backButton = buttonGroup.createButton({
- image: 'undo',
- disabled: true
- });
-
- this.forwardButton = buttonGroup.createButton({
- image: 'redo',
- disabled: true
- });
-
- this.backButton.addEventListener('click', this.undo.bind(this));
- this.forwardButton.addEventListener('click', this.redo.bind(this));
-
- return this;
- },
-
- _updateButtons: function() {
- this.backButton.disable((this.darkroom.transformations.length === 0))
- this.forwardButton.disable((this.undoTransformations.length === 0))
- },
-
- _onTranformationApplied: function() {
- this.undoTransformations = [];
- this._updateButtons();
- }
- });
-})(window, document, Darkroom, fabric);
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.rotate.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.rotate.js
deleted file mode 100755
index 1f2fbe92..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.rotate.js
+++ /dev/null
@@ -1,57 +0,0 @@
-(function() {
-'use strict';
-
-var Rotation = Darkroom.Transformation.extend({
- applyTransformation: function(canvas, image, next) {
- var angle = (image.getAngle() + this.options.angle) % 360;
- image.rotate(angle);
-
- var width, height;
- height = Math.abs(image.getWidth()*(Math.sin(angle*Math.PI/180)))+Math.abs(image.getHeight()*(Math.cos(angle*Math.PI/180)));
- width = Math.abs(image.getHeight()*(Math.sin(angle*Math.PI/180)))+Math.abs(image.getWidth()*(Math.cos(angle*Math.PI/180)));
-
- canvas.setWidth(width);
- canvas.setHeight(height);
-
- canvas.centerObject(image);
- image.setCoords();
- canvas.renderAll();
-
- next();
- }
-});
-
-Darkroom.plugins['rotate'] = Darkroom.Plugin.extend({
-
- initialize: function InitDarkroomRotatePlugin() {
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- var leftButton = buttonGroup.createButton({
- image: 'rotate-left'
- });
-
- var rightButton = buttonGroup.createButton({
- image: 'rotate-right'
- });
-
- leftButton.addEventListener('click', this.rotateLeft.bind(this));
- rightButton.addEventListener('click', this.rotateRight.bind(this));
- },
-
- rotateLeft: function rotateLeft() {
- this.rotate(-90);
- },
-
- rotateRight: function rotateRight() {
- this.rotate(90);
- },
-
- rotate: function rotate(angle) {
- this.darkroom.applyTransformation(
- new Rotation({angle: angle})
- );
- }
-
-});
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.save.js b/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.save.js
deleted file mode 100755
index d12eeadf..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/lib/js/plugins/darkroom.save.js
+++ /dev/null
@@ -1,23 +0,0 @@
-(function() {
-'use strict';
-
-Darkroom.plugins['save'] = Darkroom.Plugin.extend({
-
- defaults: {
- callback: function() {
- this.darkroom.selfDestroy();
- }
- },
-
- initialize: function InitializeDarkroomSavePlugin() {
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- this.destroyButton = buttonGroup.createButton({
- image: 'save'
- });
-
- this.destroyButton.addEventListener('click', this.options.callback.bind(this));
- },
-});
-
-})();
diff --git a/web_widget_darkroom/static/lib/darkroomjs/package.json b/web_widget_darkroom/static/lib/darkroomjs/package.json
deleted file mode 100755
index 4684f431..00000000
--- a/web_widget_darkroom/static/lib/darkroomjs/package.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "name": "darkroom",
- "description": "Extensible image editing tool via HTML canvas",
- "version": "2.0.1",
- "license": "MIT",
- "homepage": "https://mattketmo.github.io/darkroomjs",
- "repository": {
- "type": "git",
- "url": "https://github.com/mattketmo/darkroomjs.git"
- },
- "author": "Matthieu Moquet (http://moquet.net/)",
- "dependencies": {},
- "devDependencies": {
- "cheerio": "^0.18.0",
- "gulp": "^3.8.6",
- "gulp-concat": "^2.3.4",
- "gulp-connect": "^2.0.6",
- "gulp-inject": "^1.2.0",
- "gulp-plumber": "^0.6.4",
- "gulp-sass": "^0.7.2",
- "gulp-sourcemaps": "^1.1.0",
- "gulp-svgmin": "^1.1.1",
- "gulp-svgstore": "^5.0.0",
- "gulp-uglify": "^0.3.1",
- "gulp-util": "^3.0.0",
- "js-string-escape": "^1.0.0",
- "rimraf": "^2.2.8",
- "streamqueue": "^0.1.1"
- },
- "scripts": {
- "start": "node_modules/.bin/gulp server build --prod",
- "develop": "node_modules/.bin/gulp"
- },
- "ignore": [
- "**/.*",
- "node_modules",
- "bower_components"
- ]
-}
diff --git a/web_widget_darkroom/static/src/css/darkroom.css b/web_widget_darkroom/static/src/css/darkroom.css
deleted file mode 100755
index 21d4668a..00000000
--- a/web_widget_darkroom/static/src/css/darkroom.css
+++ /dev/null
@@ -1,11 +0,0 @@
-/*.darkroom-container{
- padding-top: 50px;
-}
-.darkroom-toolbar{
- top: 5px;
-}
-*/
-
-.darkroom-button-group{
- display: inline;
-}
diff --git a/web_widget_darkroom/static/src/js/darkroom_plugins.js b/web_widget_darkroom/static/src/js/darkroom_plugins.js
deleted file mode 100644
index b7dd01c1..00000000
--- a/web_widget_darkroom/static/src/js/darkroom_plugins.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/* Copyright 2016 LasLabs Inc.
- * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
- */
-
-odoo.define('web_widget_darkroom.darkroom_plugins', function(require){
- "use strict";
-
- var DarkroomPlugins = Object;
- DarkroomPlugins.extend = function(destination, source) {
- for (var property in source) {
- if (source.hasOwnProperty(property)) {
- destination[property] = source[property];
- }
- }
- return destination;
- };
-
- return DarkroomPlugins
-
-});
diff --git a/web_widget_darkroom/static/src/js/plugins/darkroom.crop.js b/web_widget_darkroom/static/src/js/plugins/darkroom.crop.js
index 8819a57c..0ae738f0 100755
--- a/web_widget_darkroom/static/src/js/plugins/darkroom.crop.js
+++ b/web_widget_darkroom/static/src/js/plugins/darkroom.crop.js
@@ -1,683 +1,693 @@
-/* Adapted from https://github.com/MattKetmo/darkroomjs/tree/master/lib/js/plugins
- * License https://github.com/MattKetmo/darkroomjs/blob/master/LICENSE
- */
-
-odoo.define('web_widget_darkroom.darkroom_crop', function(require){
-
- 'use strict';
-
- var DarkroomPluginCrop = function(){
-
- var Crop = Darkroom.Transformation.extend({
- applyTransformation: function(canvas, image, next) {
- // Snapshot the image delimited by the crop zone
- var snapshot = new Image();
- snapshot.onload = function() {
- // Validate image
- if (height < 1 || width < 1)
- return;
-
- var imgInstance = new fabric.Image(this, {
- // options to make the image static
- selectable: false,
- evented: false,
- lockMovementX: true,
- lockMovementY: true,
- lockRotation: true,
- lockScalingX: true,
- lockScalingY: true,
- lockUniScaling: true,
- hasControls: false,
- hasBorders: false
- });
-
- var width = this.width;
- var height = this.height;
-
- // Update canvas size
- canvas.setWidth(width);
- canvas.setHeight(height);
-
- // Add image
- image.remove();
- canvas.add(imgInstance);
-
- next(imgInstance);
- };
-
- var viewport = Darkroom.Utils.computeImageViewPort(image);
- var imageWidth = viewport.width;
- var imageHeight = viewport.height;
-
- var left = this.options.left * imageWidth;
- var top = this.options.top * imageHeight;
- var width = Math.min(this.options.width * imageWidth, imageWidth - left);
- var height = Math.min(this.options.height * imageHeight, imageHeight - top);
-
- snapshot.src = canvas.toDataURL({
- left: left,
- top: top,
- width: width,
- height: height,
- });
- }
- });
-
- var CropZone = fabric.util.createClass(fabric.Rect, {
- _render: function(ctx) {
- this.callSuper('_render', ctx);
-
- var canvas = ctx.canvas;
- var dashWidth = 7;
-
- // Set original scale
- var flipX = this.flipX ? -1 : 1;
- var flipY = this.flipY ? -1 : 1;
- var scaleX = flipX / this.scaleX;
- var scaleY = flipY / this.scaleY;
-
- ctx.scale(scaleX, scaleY);
-
- // Overlay rendering
- ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
- this._renderOverlay(ctx);
-
- // Set dashed borders
- if (ctx.setLineDash !== undefined)
- ctx.setLineDash([dashWidth, dashWidth]);
- else if (ctx.mozDash !== undefined)
- ctx.mozDash = [dashWidth, dashWidth];
-
- // First lines rendering with black
- ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
- this._renderBorders(ctx);
- this._renderGrid(ctx);
-
- // Re render lines in white
- ctx.lineDashOffset = dashWidth;
- ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
- this._renderBorders(ctx);
- this._renderGrid(ctx);
-
- // Reset scale
- ctx.scale(1/scaleX, 1/scaleY);
- },
-
- _renderOverlay: function(ctx) {
- var canvas = ctx.canvas;
- var borderOffset = 0;
-
- //
- // x0 x1 x2 x3
- // y0 +------------------------+
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // y1 +------+---------+-------+
- // |\\\\\\| |\\\\\\\|
- // |\\\\\\| 0 |\\\\\\\|
- // |\\\\\\| |\\\\\\\|
- // y2 +------+---------+-------+
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // |\\\\\\\\\\\\\\\\\\\\\\\\|
- // y3 +------------------------+
- //
-
- var x0 = Math.ceil(-this.getWidth() / 2 - this.getLeft());
- var x1 = Math.ceil(-this.getWidth() / 2);
- var x2 = Math.ceil(this.getWidth() / 2);
- var x3 = Math.ceil(this.getWidth() / 2 + (canvas.width - this.getWidth() - this.getLeft()));
-
- var y0 = Math.ceil(-this.getHeight() / 2 - this.getTop());
- var y1 = Math.ceil(-this.getHeight() / 2);
- var y2 = Math.ceil(this.getHeight() / 2);
- var y3 = Math.ceil(this.getHeight() / 2 + (canvas.height - this.getHeight() - this.getTop()));
-
- // Upper rect
- ctx.fillRect(x0, y0, x3 - x0, y1 - y0 + borderOffset);
-
- // Left rect
- ctx.fillRect(x0, y1, x1 - x0, y2 - y1 + borderOffset);
-
- // Right rect
- ctx.fillRect(x2, y1, x3 - x2, y2 - y1 + borderOffset);
-
- // Down rect
- ctx.fillRect(x0, y2, x3 - x0, y3 - y2);
- },
-
- _renderBorders: function(ctx) {
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2); // upper left
- ctx.lineTo(this.getWidth()/2, -this.getHeight()/2); // upper right
- ctx.lineTo(this.getWidth()/2, this.getHeight()/2); // down right
- ctx.lineTo(-this.getWidth()/2, this.getHeight()/2); // down left
- ctx.lineTo(-this.getWidth()/2, -this.getHeight()/2); // upper left
- ctx.stroke();
- },
-
- _renderGrid: function(ctx) {
- // Vertical lines
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2 + 1/3 * this.getWidth(), -this.getHeight()/2);
- ctx.lineTo(-this.getWidth()/2 + 1/3 * this.getWidth(), this.getHeight()/2);
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2 + 2/3 * this.getWidth(), -this.getHeight()/2);
- ctx.lineTo(-this.getWidth()/2 + 2/3 * this.getWidth(), this.getHeight()/2);
- ctx.stroke();
- // Horizontal lines
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2 + 1/3 * this.getHeight());
- ctx.lineTo(this.getWidth()/2, -this.getHeight()/2 + 1/3 * this.getHeight());
- ctx.stroke();
- ctx.beginPath();
- ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2 + 2/3 * this.getHeight());
- ctx.lineTo(this.getWidth()/2, -this.getHeight()/2 + 2/3 * this.getHeight());
- ctx.stroke();
- }
- });
-
- Darkroom.plugins['crop'] = Darkroom.Plugin.extend({
- // Init point
- startX: null,
- startY: null,
-
- // Keycrop
- isKeyCroping: false,
- isKeyLeft: false,
- isKeyUp: false,
-
- defaults: {
- // min crop dimension
- minHeight: 1,
- minWidth: 1,
- // ensure crop ratio
- ratio: null,
- // quick crop feature (set a key code to enable it)
- quickCropKey: false
- },
-
- initialize: function InitDarkroomCropPlugin() {
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- this.cropButton = buttonGroup.createButton({
- image: 'fa fa-crop',
- editOnly: true,
- });
- this.okButton = buttonGroup.createButton({
- image: 'fa fa-check',
- editOnly: true,
- type: 'success',
- hide: true
- });
- this.cancelButton = buttonGroup.createButton({
- image: 'fa fa-times',
- editOnly: true,
- type: 'danger',
- hide: true
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+odoo.define('web_widget_darkroom.darkroom_crop', function(){
+ 'use strict';
+
+ var DarkroomPluginCrop = function() {
+ var Crop = Darkroom.Transformation.extend({
+ applyTransformation: function(canvas, image, next) {
+ // Snapshot the image delimited by the crop zone
+ var snapshot = new Image();
+ snapshot.onload = function() {
+ var width = this.width;
+ var height = this.height;
+
+ // Validate image
+ if (height < 1 || width < 1) {
+ return;
+ }
+
+ var imgInstance = new fabric.Image(this, {
+ // Options to make the image static
+ selectable: false,
+ evented: false,
+ lockMovementX: true,
+ lockMovementY: true,
+ lockRotation: true,
+ lockScalingX: true,
+ lockScalingY: true,
+ lockUniScaling: true,
+ hasControls: false,
+ hasBorders: false,
+ });
+
+ // Update canvas size
+ canvas.setWidth(width);
+ canvas.setHeight(height);
+
+ // Add image
+ image.remove();
+ canvas.add(imgInstance);
+
+ next(imgInstance);
+ };
+
+ var viewport = Darkroom.Utils.computeImageViewPort(image);
+ var imageWidth = viewport.width;
+ var imageHeight = viewport.height;
+
+ var left = this.options.left * imageWidth;
+ var top = this.options.top * imageHeight;
+ var width = Math.min(this.options.width * imageWidth, imageWidth - left);
+ var height = Math.min(this.options.height * imageHeight, imageHeight - top);
+
+ snapshot.src = canvas.toDataURL({
+ left: left,
+ top: top,
+ width: width,
+ height: height,
+ });
+ },
});
-
- // Buttons click
- this.cropButton.addEventListener('click', this.toggleCrop.bind(this));
- this.okButton.addEventListener('click', this.cropCurrentZone.bind(this));
- this.cancelButton.addEventListener('click', this.releaseFocus.bind(this));
-
- // Canvas events
- this.darkroom.canvas.on('mouse:down', this.onMouseDown.bind(this));
- this.darkroom.canvas.on('mouse:move', this.onMouseMove.bind(this));
- this.darkroom.canvas.on('mouse:up', this.onMouseUp.bind(this));
- this.darkroom.canvas.on('object:moving', this.onObjectMoving.bind(this));
- this.darkroom.canvas.on('object:scaling', this.onObjectScaling.bind(this));
-
- fabric.util.addListener(fabric.document, 'keydown', this.onKeyDown.bind(this));
- fabric.util.addListener(fabric.document, 'keyup', this.onKeyUp.bind(this));
-
- this.darkroom.addEventListener('core:transformation', this.releaseFocus.bind(this));
- },
-
- // Avoid crop zone to go beyond the canvas edges
- onObjectMoving: function(event) {
- if (!this.hasFocus()) {
- return;
- }
-
- var currentObject = event.target;
- if (currentObject !== this.cropZone)
- return;
-
- var canvas = this.darkroom.canvas;
- var x = currentObject.getLeft(), y = currentObject.getTop();
- var w = currentObject.getWidth(), h = currentObject.getHeight();
- var maxX = canvas.getWidth() - w;
- var maxY = canvas.getHeight() - h;
-
- if (x < 0)
- currentObject.set('left', 0);
- if (y < 0)
- currentObject.set('top', 0);
- if (x > maxX)
- currentObject.set('left', maxX);
- if (y > maxY)
- currentObject.set('top', maxY);
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- // Prevent crop zone from going beyond the canvas edges (like mouseMove)
- onObjectScaling: function(event) {
- if (!this.hasFocus()) {
- return;
- }
-
- var preventScaling = false;
- var currentObject = event.target;
- if (currentObject !== this.cropZone)
- return;
-
- var canvas = this.darkroom.canvas;
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
-
- var minX = currentObject.getLeft();
- var minY = currentObject.getTop();
- var maxX = currentObject.getLeft() + currentObject.getWidth();
- var maxY = currentObject.getTop() + currentObject.getHeight();
-
- if (null !== this.options.ratio) {
- if (minX < 0 || maxX > canvas.getWidth() || minY < 0 || maxY > canvas.getHeight()) {
- preventScaling = true;
- }
- }
-
- if (minX < 0 || maxX > canvas.getWidth() || preventScaling) {
- var lastScaleX = this.lastScaleX || 1;
- currentObject.setScaleX(lastScaleX);
- }
- if (minX < 0) {
- currentObject.setLeft(0);
- }
-
- if (minY < 0 || maxY > canvas.getHeight() || preventScaling) {
- var lastScaleY = this.lastScaleY || 1;
- currentObject.setScaleY(lastScaleY);
- }
- if (minY < 0) {
- currentObject.setTop(0);
- }
-
- if (currentObject.getWidth() < this.options.minWidth) {
- currentObject.scaleToWidth(this.options.minWidth);
- }
- if (currentObject.getHeight() < this.options.minHeight) {
- currentObject.scaleToHeight(this.options.minHeight);
- }
-
- this.lastScaleX = currentObject.getScaleX();
- this.lastScaleY = currentObject.getScaleY();
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- // Init crop zone
- onMouseDown: function(event) {
- if (!this.hasFocus()) {
- return;
- }
-
- var canvas = this.darkroom.canvas;
-
- // recalculate offset, in case canvas was manipulated since last `calcOffset`
- canvas.calcOffset();
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
- var point = new fabric.Point(x, y);
-
- // Check if user want to scale or drag the crop zone.
- var activeObject = canvas.getActiveObject();
- if (activeObject === this.cropZone || this.cropZone.containsPoint(point)) {
- return;
- }
-
- canvas.discardActiveObject();
- this.cropZone.setWidth(0);
- this.cropZone.setHeight(0);
- this.cropZone.setScaleX(1);
- this.cropZone.setScaleY(1);
-
- this.startX = x;
- this.startY = y;
- },
-
- // Extend crop zone
- onMouseMove: function(event) {
- // Quick crop feature
- if (this.isKeyCroping)
- return this.onMouseMoveKeyCrop(event);
-
- if (null === this.startX || null === this.startY) {
- return;
- }
-
- var canvas = this.darkroom.canvas;
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
-
- this._renderCropZone(this.startX, this.startY, x, y);
- },
-
- onMouseMoveKeyCrop: function(event) {
- var canvas = this.darkroom.canvas;
- var zone = this.cropZone;
-
- var pointer = canvas.getPointer(event.e);
- var x = pointer.x;
- var y = pointer.y;
-
- if (!zone.left || !zone.top) {
- zone.setTop(y);
- zone.setLeft(x);
- }
-
- this.isKeyLeft = x < zone.left + zone.width / 2 ;
- this.isKeyUp = y < zone.top + zone.height / 2 ;
-
- this._renderCropZone(
- Math.min(zone.left, x),
- Math.min(zone.top, y),
- Math.max(zone.left+zone.width, x),
- Math.max(zone.top+zone.height, y)
- );
- },
-
- // Finish crop zone
- onMouseUp: function(event) {
- if (null === this.startX || null === this.startY) {
- return;
- }
-
- var canvas = this.darkroom.canvas;
- this.cropZone.setCoords();
- canvas.setActiveObject(this.cropZone);
- canvas.calcOffset();
-
- this.startX = null;
- this.startY = null;
- },
-
- onKeyDown: function(event) {
- if (false === this.options.quickCropKey || event.keyCode !== this.options.quickCropKey || this.isKeyCroping)
- return;
-
- // Active quick crop flow
- this.isKeyCroping = true ;
- this.darkroom.canvas.discardActiveObject();
- this.cropZone.setWidth(0);
- this.cropZone.setHeight(0);
- this.cropZone.setScaleX(1);
- this.cropZone.setScaleY(1);
- this.cropZone.setTop(0);
- this.cropZone.setLeft(0);
- },
-
- onKeyUp: function(event) {
- if (false === this.options.quickCropKey || event.keyCode !== this.options.quickCropKey || !this.isKeyCroping)
- return;
-
- // Unactive quick crop flow
- this.isKeyCroping = false;
- this.startX = 1;
- this.startY = 1;
- this.onMouseUp();
- },
-
- selectZone: function(x, y, width, height, forceDimension) {
- if (!this.hasFocus())
- this.requireFocus();
-
- if (!forceDimension) {
- this._renderCropZone(x, y, x+width, y+height);
- } else {
- this.cropZone.set({
- 'left': x,
- 'top': y,
- 'width': width,
- 'height': height
- });
- }
-
- var canvas = this.darkroom.canvas;
- canvas.bringToFront(this.cropZone);
- this.cropZone.setCoords();
- canvas.setActiveObject(this.cropZone);
- canvas.calcOffset();
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- toggleCrop: function() {
- if (!this.hasFocus())
- this.requireFocus();
- else
- this.releaseFocus();
- },
-
- cropCurrentZone: function() {
- if (!this.hasFocus())
- return;
-
- // Avoid croping empty zone
- if (this.cropZone.width < 1 && this.cropZone.height < 1)
- return;
-
- var image = this.darkroom.image;
-
- // Compute crop zone dimensions
- var top = this.cropZone.getTop() - image.getTop();
- var left = this.cropZone.getLeft() - image.getLeft();
- var width = this.cropZone.getWidth();
- var height = this.cropZone.getHeight();
-
- // Adjust dimensions to image only
- if (top < 0) {
- height += top;
- top = 0;
- }
-
- if (left < 0) {
- width += left;
- left = 0;
- }
-
- // Apply crop transformation.
- // Make sure to use relative dimension since the crop will be applied
- // on the source image.
- this.darkroom.applyTransformation(new Crop({
- top: top / image.getHeight(),
- left: left / image.getWidth(),
- width: width / image.getWidth(),
- height: height / image.getHeight(),
- }));
- },
-
- // Test wether crop zone is set
- hasFocus: function() {
- return this.cropZone !== undefined;
- },
-
- // Create the crop zone
- requireFocus: function() {
- this.cropZone = new CropZone({
- fill: 'transparent',
- hasBorders: false,
- originX: 'left',
- originY: 'top',
- //stroke: '#444',
- //strokeDashArray: [5, 5],
- //borderColor: '#444',
- cornerColor: '#444',
- cornerSize: 8,
- transparentCorners: false,
- lockRotation: true,
- hasRotatingPoint: false,
+
+ var CropZone = fabric.util.createClass(fabric.Rect, {
+ _render: function(ctx) {
+ this.callSuper('_render', ctx);
+ var dashWidth = 7;
+
+ // Set original scale
+ var flipX = this.flipX ? -1 : 1;
+ var flipY = this.flipY ? -1 : 1;
+ var scaleX = flipX / this.scaleX;
+ var scaleY = flipY / this.scaleY;
+ ctx.scale(scaleX, scaleY);
+
+ // Overlay rendering
+ ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
+ this._renderOverlay(ctx);
+
+ // Set dashed borders
+ if (typeof ctx.setLineDash !== 'undefined') {
+ ctx.setLineDash([dashWidth, dashWidth]);
+ } else if (typeof ctx.mozDash !== 'undefined') {
+ ctx.mozDash = [dashWidth, dashWidth];
+ }
+
+ // First lines rendering with black
+ ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)';
+ this._renderBorders(ctx);
+ this._renderGrid(ctx);
+
+ // Re render lines in white
+ ctx.lineDashOffset = dashWidth;
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.4)';
+ this._renderBorders(ctx);
+ this._renderGrid(ctx);
+
+ // Reset scale
+ ctx.scale(1/scaleX, 1/scaleY);
+ },
+
+ _renderOverlay: function(ctx) {
+ var canvas = ctx.canvas;
+ var borderOffset = 0;
+
+ //
+ // x0 x1 x2 x3
+ // y0 +------------------------+
+ // |\\\\\\\\\\\\\\\\\\\\\\\\|
+ // |\\\\\\\\\\\\\\\\\\\\\\\\|
+ // y1 +------+---------+-------+
+ // |\\\\\\| |\\\\\\\|
+ // |\\\\\\| 0 |\\\\\\\|
+ // |\\\\\\| |\\\\\\\|
+ // y2 +------+---------+-------+
+ // |\\\\\\\\\\\\\\\\\\\\\\\\|
+ // |\\\\\\\\\\\\\\\\\\\\\\\\|
+ // y3 +------------------------+
+ //
+
+ var x0 = Math.ceil(-this.getWidth() / 2 - this.getLeft());
+ var x1 = Math.ceil(-this.getWidth() / 2);
+ var x2 = Math.ceil(this.getWidth() / 2);
+ var x3 = Math.ceil(this.getWidth() / 2 + (canvas.width - this.getWidth() - this.getLeft()));
+
+ var y0 = Math.ceil(-this.getHeight() / 2 - this.getTop());
+ var y1 = Math.ceil(-this.getHeight() / 2);
+ var y2 = Math.ceil(this.getHeight() / 2);
+ var y3 = Math.ceil(this.getHeight() / 2 + (canvas.height - this.getHeight() - this.getTop()));
+
+ // Upper rect
+ ctx.fillRect(x0, y0, x3 - x0, y1 - y0 + borderOffset);
+
+ // Left rect
+ ctx.fillRect(x0, y1, x1 - x0, y2 - y1 + borderOffset);
+
+ // Right rect
+ ctx.fillRect(x2, y1, x3 - x2, y2 - y1 + borderOffset);
+
+ // Down rect
+ ctx.fillRect(x0, y2, x3 - x0, y3 - y2);
+ },
+
+ _renderBorders: function(ctx) {
+ ctx.beginPath();
+ // upper left
+ ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2);
+ // upper right
+ ctx.lineTo(this.getWidth()/2, -this.getHeight()/2);
+ // down right
+ ctx.lineTo(this.getWidth()/2, this.getHeight()/2);
+ // down left
+ ctx.lineTo(-this.getWidth()/2, this.getHeight()/2);
+ // upper left
+ ctx.lineTo(-this.getWidth()/2, -this.getHeight()/2);
+ ctx.stroke();
+ },
+
+ _renderGrid: function(ctx) {
+ // Vertical lines
+ ctx.beginPath();
+ ctx.moveTo(-this.getWidth()/2 + 1/3 * this.getWidth(), -this.getHeight()/2);
+ ctx.lineTo(-this.getWidth()/2 + 1/3 * this.getWidth(), this.getHeight()/2);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(-this.getWidth()/2 + 2/3 * this.getWidth(), -this.getHeight()/2);
+ ctx.lineTo(-this.getWidth()/2 + 2/3 * this.getWidth(), this.getHeight()/2);
+ ctx.stroke();
+
+ // Horizontal lines
+ ctx.beginPath();
+ ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2 + 1/3 * this.getHeight());
+ ctx.lineTo(this.getWidth()/2, -this.getHeight()/2 + 1/3 * this.getHeight());
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.moveTo(-this.getWidth()/2, -this.getHeight()/2 + 2/3 * this.getHeight());
+ ctx.lineTo(this.getWidth()/2, -this.getHeight()/2 + 2/3 * this.getHeight());
+ ctx.stroke();
+ },
});
-
- if (null !== this.options.ratio) {
- this.cropZone.set('lockUniScaling', true);
- }
-
- this.darkroom.canvas.add(this.cropZone);
- this.darkroom.canvas.defaultCursor = 'crosshair';
-
- this.cropButton.active(true);
- this.okButton.hide(false);
- this.cancelButton.hide(false);
- },
-
- // Remove the crop zone
- releaseFocus: function() {
- if (undefined === this.cropZone)
- return;
-
- this.cropZone.remove();
- this.cropZone = undefined;
-
- this.cropButton.active(false);
- this.okButton.hide(true);
- this.cancelButton.hide(true);
-
- this.darkroom.canvas.defaultCursor = 'default';
-
- this.darkroom.dispatchEvent('crop:update');
- },
-
- _renderCropZone: function(fromX, fromY, toX, toY) {
- var canvas = this.darkroom.canvas;
-
- var isRight = (toX > fromX);
- var isLeft = !isRight;
- var isDown = (toY > fromY);
- var isUp = !isDown;
-
- var minWidth = Math.min(+this.options.minWidth, canvas.getWidth());
- var minHeight = Math.min(+this.options.minHeight, canvas.getHeight());
-
- // Define corner coordinates
- var leftX = Math.min(fromX, toX);
- var rightX = Math.max(fromX, toX);
- var topY = Math.min(fromY, toY);
- var bottomY = Math.max(fromY, toY);
-
- // Replace current point into the canvas
- leftX = Math.max(0, leftX);
- rightX = Math.min(canvas.getWidth(), rightX);
- topY = Math.max(0, topY)
- bottomY = Math.min(canvas.getHeight(), bottomY);
-
- // Recalibrate coordinates according to given options
- if (rightX - leftX < minWidth) {
- if (isRight)
- rightX = leftX + minWidth;
- else
- leftX = rightX - minWidth;
- }
- if (bottomY - topY < minHeight) {
- if (isDown)
- bottomY = topY + minHeight;
- else
- topY = bottomY - minHeight;
- }
-
- // Truncate truncate according to canvas dimensions
- if (leftX < 0) {
- // Translate to the left
- rightX += Math.abs(leftX);
- leftX = 0
- }
- if (rightX > canvas.getWidth()) {
- // Translate to the right
- leftX -= (rightX - canvas.getWidth());
- rightX = canvas.getWidth();
- }
- if (topY < 0) {
- // Translate to the bottom
- bottomY += Math.abs(topY);
- topY = 0
- }
- if (bottomY > canvas.getHeight()) {
- // Translate to the right
- topY -= (bottomY - canvas.getHeight());
- bottomY = canvas.getHeight();
- }
-
- var width = rightX - leftX;
- var height = bottomY - topY;
- var currentRatio = width / height;
-
- if (this.options.ratio && +this.options.ratio !== currentRatio) {
- var ratio = +this.options.ratio;
-
- if(this.isKeyCroping) {
- isLeft = this.isKeyLeft;
- isUp = this.isKeyUp;
- }
-
- if (currentRatio < ratio) {
- var newWidth = height * ratio;
- if (isLeft) {
- leftX -= (newWidth - width);
- }
- width = newWidth;
- } else if (currentRatio > ratio) {
- var newHeight = height / (ratio * height/width);
- if (isUp) {
- topY -= (newHeight - height);
- }
- height = newHeight;
- }
-
- if (leftX < 0) {
- leftX = 0;
- //TODO
- }
- if (topY < 0) {
- topY = 0;
- //TODO
- }
- if (leftX + width > canvas.getWidth()) {
- var newWidth = canvas.getWidth() - leftX;
- height = newWidth * height / width;
- width = newWidth;
- if (isUp) {
- topY = fromY - height;
- }
- }
- if (topY + height > canvas.getHeight()) {
- var newHeight = canvas.getHeight() - topY;
- width = width * newHeight / height;
- height = newHeight;
- if (isLeft) {
- leftX = fromX - width;
+
+ Darkroom.plugins.crop = Darkroom.Plugin.extend({
+ // Init point
+ startX: null,
+ startY: null,
+
+ // Keycrop
+ isKeyCroping: false,
+ isKeyLeft: false,
+ isKeyUp: false,
+
+ defaults: {
+ // Min crop dimensions
+ minHeight: 1,
+ minWidth: 1,
+ // Ensure crop ratio
+ ratio: null,
+ // Quick crop feature (set a key code to enable it)
+ quickCropKey: false,
+ },
+
+ initialize: function InitDarkroomCropPlugin() {
+ var buttonGroup = this.darkroom.toolbar.createButtonGroup();
+
+ this.cropButton = buttonGroup.createButton({
+ image: 'fa fa-crop',
+ editOnly: true,
+ });
+ this.okButton = buttonGroup.createButton({
+ image: 'fa fa-check',
+ editOnly: true,
+ type: 'success',
+ hide: true
+ });
+ this.cancelButton = buttonGroup.createButton({
+ image: 'fa fa-times',
+ editOnly: true,
+ type: 'danger',
+ hide: true
+ });
+
+ // Button click events
+ this.cropButton.addEventListener('click', this.toggleCrop.bind(this));
+ this.okButton.addEventListener('click', this.cropCurrentZone.bind(this));
+ this.cancelButton.addEventListener('click', this.releaseFocus.bind(this));
+
+ // Canvas events
+ this.darkroom.canvas.on('mouse:down', this.onMouseDown.bind(this));
+ this.darkroom.canvas.on('mouse:move', this.onMouseMove.bind(this));
+ this.darkroom.canvas.on('mouse:up', this.onMouseUp.bind(this));
+ this.darkroom.canvas.on('object:moving', this.onObjectMoving.bind(this));
+ this.darkroom.canvas.on('object:scaling', this.onObjectScaling.bind(this));
+
+ fabric.util.addListener(fabric.document, 'keydown', this.onKeyDown.bind(this));
+ fabric.util.addListener(fabric.document, 'keyup', this.onKeyUp.bind(this));
+
+ this.darkroom.addEventListener('core:transformation', this.releaseFocus.bind(this));
+ },
+
+ // Avoid crop zone to go beyond the canvas edges
+ onObjectMoving: function(event) {
+ if (!this.hasFocus()) {
+ return;
+ }
+
+ var currentObject = event.target;
+ if (currentObject !== this.cropZone) {
+ return;
+ }
+
+ var canvas = this.darkroom.canvas;
+ var x = currentObject.getLeft(), y = currentObject.getTop();
+ var w = currentObject.getWidth(), h = currentObject.getHeight();
+ var maxX = canvas.getWidth() - w;
+ var maxY = canvas.getHeight() - h;
+
+ if (x < 0) {
+ currentObject.set('left', 0);
+ }
+ if (y < 0) {
+ currentObject.set('top', 0);
+ }
+ if (x > maxX) {
+ currentObject.set('left', maxX);
+ }
+ if (y > maxY) {
+ currentObject.set('top', maxY);
+ }
+
+ this.darkroom.dispatchEvent('crop:update');
+ },
+
+ // Prevent crop zone from going beyond the canvas edges (like mouseMove)
+ onObjectScaling: function(event) {
+ if (!this.hasFocus()) {
+ return;
+ }
+
+ var preventScaling = false;
+ var currentObject = event.target;
+ if (currentObject !== this.cropZone) {
+ return;
+ }
+
+ var canvas = this.darkroom.canvas;
+
+ var minX = currentObject.getLeft();
+ var minY = currentObject.getTop();
+ var maxX = currentObject.getLeft() + currentObject.getWidth();
+ var maxY = currentObject.getTop() + currentObject.getHeight();
+
+ if (this.options.ratio !== null) {
+ if (minX < 0 || maxX > canvas.getWidth() || minY < 0 || maxY > canvas.getHeight()) {
+ preventScaling = true;
+ }
+ }
+
+ if (minX < 0 || maxX > canvas.getWidth() || preventScaling) {
+ var lastScaleX = this.lastScaleX || 1;
+ currentObject.setScaleX(lastScaleX);
+ }
+ if (minX < 0) {
+ currentObject.setLeft(0);
+ }
+
+ if (minY < 0 || maxY > canvas.getHeight() || preventScaling) {
+ var lastScaleY = this.lastScaleY || 1;
+ currentObject.setScaleY(lastScaleY);
+ }
+ if (minY < 0) {
+ currentObject.setTop(0);
+ }
+
+ if (currentObject.getWidth() < this.options.minWidth) {
+ currentObject.scaleToWidth(this.options.minWidth);
+ }
+ if (currentObject.getHeight() < this.options.minHeight) {
+ currentObject.scaleToHeight(this.options.minHeight);
+ }
+
+ this.lastScaleX = currentObject.getScaleX();
+ this.lastScaleY = currentObject.getScaleY();
+
+ this.darkroom.dispatchEvent('crop:update');
+ },
+
+ // Init crop zone
+ onMouseDown: function(event) {
+ if (!this.hasFocus()) {
+ return;
+ }
+
+ var canvas = this.darkroom.canvas;
+
+ // Recalculate offset, in case canvas was manipulated since last `calcOffset`
+ canvas.calcOffset();
+ var pointer = canvas.getPointer(event.e);
+ var x = pointer.x;
+ var y = pointer.y;
+ var point = new fabric.Point(x, y);
+
+ // Check if user want to scale or drag the crop zone.
+ var activeObject = canvas.getActiveObject();
+ if (activeObject === this.cropZone || this.cropZone.containsPoint(point)) {
+ return;
+ }
+
+ canvas.discardActiveObject();
+ this.cropZone.setWidth(0);
+ this.cropZone.setHeight(0);
+ this.cropZone.setScaleX(1);
+ this.cropZone.setScaleY(1);
+
+ this.startX = x;
+ this.startY = y;
+ },
+
+ // Extend crop zone
+ onMouseMove: function(event) {
+ // Quick crop feature
+ if (this.isKeyCroping) {
+ return this.onMouseMoveKeyCrop(event);
+ }
+ if (this.startX === null || this.startY === null) {
+ return;
+ }
+
+ var canvas = this.darkroom.canvas;
+ var pointer = canvas.getPointer(event.e);
+ var x = pointer.x;
+ var y = pointer.y;
+
+ this._renderCropZone(this.startX, this.startY, x, y);
+ },
+
+ onMouseMoveKeyCrop: function(event) {
+ var canvas = this.darkroom.canvas;
+ var zone = this.cropZone;
+
+ var pointer = canvas.getPointer(event.e);
+ var x = pointer.x;
+ var y = pointer.y;
+
+ if (!zone.left || !zone.top) {
+ zone.setTop(y);
+ zone.setLeft(x);
+ }
+
+ this.isKeyLeft = x < zone.left + zone.width / 2;
+ this.isKeyUp = y < zone.top + zone.height / 2;
+
+ this._renderCropZone(
+ Math.min(zone.left, x),
+ Math.min(zone.top, y),
+ Math.max(zone.left+zone.width, x),
+ Math.max(zone.top+zone.height, y)
+ );
+ },
+
+ // Finish crop zone
+ onMouseUp: function() {
+ if (this.startX === null || this.startY === null) {
+ return;
+ }
+
+ var canvas = this.darkroom.canvas;
+ this.cropZone.setCoords();
+ canvas.setActiveObject(this.cropZone);
+ canvas.calcOffset();
+
+ this.startX = null;
+ this.startY = null;
+ },
+
+ onKeyDown: function(event) {
+ if (this.options.quickCropKey === false || event.keyCode !== this.options.quickCropKey || this.isKeyCroping) {
+ return;
+ }
+
+ // Active quick crop flow
+ this.isKeyCroping = true ;
+ this.darkroom.canvas.discardActiveObject();
+ this.cropZone.setWidth(0);
+ this.cropZone.setHeight(0);
+ this.cropZone.setScaleX(1);
+ this.cropZone.setScaleY(1);
+ this.cropZone.setTop(0);
+ this.cropZone.setLeft(0);
+ },
+
+ onKeyUp: function(event) {
+ if (this.options.quickCropKey === false || event.keyCode !== this.options.quickCropKey || !this.isKeyCroping) {
+ return;
+ }
+
+ // Inactive quick crop flow
+ this.isKeyCroping = false;
+ this.startX = 1;
+ this.startY = 1;
+ this.onMouseUp();
+ },
+
+ selectZone: function(x, y, width, height, forceDimension) {
+ if (!this.hasFocus()) {
+ this.requireFocus();
+ }
+
+ if (forceDimension) {
+ this.cropZone.set({
+ 'left': x,
+ 'top': y,
+ 'width': width,
+ 'height': height,
+ });
+ } else {
+ this._renderCropZone(x, y, x+width, y+height);
+ }
+
+ var canvas = this.darkroom.canvas;
+ canvas.bringToFront(this.cropZone);
+ this.cropZone.setCoords();
+ canvas.setActiveObject(this.cropZone);
+ canvas.calcOffset();
+
+ this.darkroom.dispatchEvent('crop:update');
+ },
+
+ toggleCrop: function() {
+ if (this.hasFocus()) {
+ this.releaseFocus();
+ } else {
+ this.requireFocus();
+ }
+ },
+
+ cropCurrentZone: function() {
+ if (!this.hasFocus()) {
+ return;
+ }
+
+ // Avoid croping empty zone
+ if (this.cropZone.width < 1 && this.cropZone.height < 1) {
+ return;
+ }
+
+ var image = this.darkroom.image;
+
+ // Compute crop zone dimensions
+ var top = this.cropZone.getTop() - image.getTop();
+ var left = this.cropZone.getLeft() - image.getLeft();
+ var width = this.cropZone.getWidth();
+ var height = this.cropZone.getHeight();
+
+ // Adjust dimensions to image only
+ if (top < 0) {
+ height += top;
+ top = 0;
+ }
+
+ if (left < 0) {
+ width += left;
+ left = 0;
+ }
+
+ // Apply crop transformation. Make sure to use relative
+ // dimension since the crop will be applied on the source image.
+ this.darkroom.applyTransformation(new Crop({
+ top: top / image.getHeight(),
+ left: left / image.getWidth(),
+ width: width / image.getWidth(),
+ height: height / image.getHeight(),
+ }));
+ },
+
+ // Test whether crop zone is set
+ hasFocus: function() {
+ return typeof this.cropZone !== 'undefined';
+ },
+
+ // Create the crop zone
+ requireFocus: function() {
+ this.cropZone = new CropZone({
+ fill: 'transparent',
+ hasBorders: false,
+ originX: 'left',
+ originY: 'top',
+ cornerColor: '#444',
+ cornerSize: 8,
+ transparentCorners: false,
+ lockRotation: true,
+ hasRotatingPoint: false,
+ });
+
+ if (this.options.ratio !== null) {
+ this.cropZone.set('lockUniScaling', true);
+ }
+
+ this.darkroom.canvas.add(this.cropZone);
+ this.darkroom.canvas.defaultCursor = 'crosshair';
+
+ this.cropButton.active(true);
+ this.okButton.hide(false);
+ this.cancelButton.hide(false);
+ },
+
+ // Remove the crop zone
+ releaseFocus: function() {
+ if (typeof this.cropZone === 'undefined') {
+ return;
+ }
+
+ this.cropZone.remove();
+ this.cropZone = undefined;
+
+ this.cropButton.active(false);
+ this.okButton.hide(true);
+ this.cancelButton.hide(true);
+
+ this.darkroom.canvas.defaultCursor = 'default';
+ this.darkroom.dispatchEvent('crop:update');
+ },
+
+ _renderCropZone: function(fromX, fromY, toX, toY) {
+ var canvas = this.darkroom.canvas;
+
+ var isRight = toX > fromX;
+ var isLeft = !isRight;
+ var isDown = toY > fromY;
+ var isUp = !isDown;
+
+ var minWidth = Math.min(Number(this.options.minWidth), canvas.getWidth());
+ var minHeight = Math.min(Number(this.options.minHeight), canvas.getHeight());
+
+ // Define corner coordinates
+ var leftX = Math.min(fromX, toX);
+ var rightX = Math.max(fromX, toX);
+ var topY = Math.min(fromY, toY);
+ var bottomY = Math.max(fromY, toY);
+
+ // Replace current point into the canvas
+ leftX = Math.max(0, leftX);
+ rightX = Math.min(canvas.getWidth(), rightX);
+ topY = Math.max(0, topY);
+ bottomY = Math.min(canvas.getHeight(), bottomY);
+
+ // Recalibrate coordinates according to given options
+ if (rightX - leftX < minWidth) {
+ if (isRight) {
+ rightX = leftX + minWidth;
+ } else {
+ leftX = rightX - minWidth;
+ }
+ }
+ if (bottomY - topY < minHeight) {
+ if (isDown) {
+ bottomY = topY + minHeight;
+ } else {
+ topY = bottomY - minHeight;
+ }
+ }
+
+ // Truncate truncate according to canvas dimensions
+ if (leftX < 0) {
+ // Translate to the left
+ rightX += Math.abs(leftX);
+ leftX = 0;
+ }
+ if (rightX > canvas.getWidth()) {
+ // Translate to the right
+ leftX -= rightX - canvas.getWidth();
+ rightX = canvas.getWidth();
+ }
+ if (topY < 0) {
+ // Translate to the bottom
+ bottomY += Math.abs(topY);
+ topY = 0;
+ }
+ if (bottomY > canvas.getHeight()) {
+ // Translate to the right
+ topY -= bottomY - canvas.getHeight();
+ bottomY = canvas.getHeight();
+ }
+
+ var width = rightX - leftX;
+ var height = bottomY - topY;
+ var currentRatio = width / height;
+
+ if (this.options.ratio && Number(this.options.ratio) !== currentRatio) {
+ var ratio = Number(this.options.ratio);
+ var newWidth = 0, newHeight = 0;
+
+ if(this.isKeyCroping) {
+ isLeft = this.isKeyLeft;
+ isUp = this.isKeyUp;
+ }
+
+ if (currentRatio < ratio) {
+ newWidth = height * ratio;
+ if (isLeft) {
+ leftX -= newWidth - width;
+ }
+ width = newWidth;
+ } else if (currentRatio > ratio) {
+ newHeight = height / (ratio * height/width);
+ if (isUp) {
+ topY -= newHeight - height;
+ }
+ height = newHeight;
+ }
+
+ if (leftX < 0) {
+ leftX = 0;
+ //TODO
+ }
+ if (topY < 0) {
+ topY = 0;
+ //TODO
+ }
+ if (leftX + width > canvas.getWidth()) {
+ newWidth = canvas.getWidth() - leftX;
+ height = newWidth * height / width;
+ width = newWidth;
+ if (isUp) {
+ topY = fromY - height;
+ }
+ }
+ if (topY + height > canvas.getHeight()) {
+ newHeight = canvas.getHeight() - topY;
+ width = width * newHeight / height;
+ height = newHeight;
+ if (isLeft) {
+ leftX = fromX - width;
+ }
+ }
+ }
+
+ // Apply coordinates
+ this.cropZone.left = leftX;
+ this.cropZone.top = topY;
+ this.cropZone.width = width;
+ this.cropZone.height = height;
+
+ this.darkroom.canvas.bringToFront(this.cropZone);
+ this.darkroom.dispatchEvent('crop:update');
}
- }
- }
-
- // Apply coordinates
- this.cropZone.left = leftX;
- this.cropZone.top = topY;
- this.cropZone.width = width;
- this.cropZone.height = height;
-
- this.darkroom.canvas.bringToFront(this.cropZone);
-
- this.darkroom.dispatchEvent('crop:update');
- }
- });
-
- }
-
- return {DarkroomPluginCrop: DarkroomPluginCrop};
+ });
+ };
+ return {DarkroomPluginCrop: DarkroomPluginCrop};
});
diff --git a/web_widget_darkroom/static/src/js/plugins/darkroom.history.js b/web_widget_darkroom/static/src/js/plugins/darkroom.history.js
index 99bc07f6..11b2569c 100755
--- a/web_widget_darkroom/static/src/js/plugins/darkroom.history.js
+++ b/web_widget_darkroom/static/src/js/plugins/darkroom.history.js
@@ -1,80 +1,76 @@
-/* Adapted from https://github.com/MattKetmo/darkroomjs/tree/master/lib/js/plugins
- * License https://github.com/MattKetmo/darkroomjs/blob/master/LICENSE
- */
-
-odoo.define('web_widget_darkroom.darkroom_history', function(require){
-
- 'use strict';
-
- var DarkroomPluginHistory = function() {
-
- Darkroom.plugins['history'] = Darkroom.Plugin.extend({
- undoTransformations: [],
-
- initialize: function InitDarkroomHistoryPlugin() {
- this._initButtons();
-
- this.darkroom.addEventListener('core:transformation', this._onTranformationApplied.bind(this));
- },
-
- undo: function() {
- if (this.darkroom.transformations.length === 0) {
- return;
- }
-
- var lastTransformation = this.darkroom.transformations.pop();
- this.undoTransformations.unshift(lastTransformation);
-
- this.darkroom.reinitializeImage();
- this._updateButtons();
- },
-
- redo: function() {
- if (this.undoTransformations.length === 0) {
- return;
- }
-
- var cancelTransformation = this.undoTransformations.shift();
- this.darkroom.transformations.push(cancelTransformation);
-
- this.darkroom.reinitializeImage();
- this._updateButtons();
- },
-
- _initButtons: function() {
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- this.backButton = buttonGroup.createButton({
- image: 'fa fa-step-backward',
- disabled: true,
- editOnly: true,
- });
-
- this.forwardButton = buttonGroup.createButton({
- image: 'fa fa-step-forward',
- disabled: true,
- editOnly: true,
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+odoo.define('web_widget_darkroom.darkroom_history', function() {
+ 'use strict';
+
+ var DarkroomPluginHistory = function() {
+ Darkroom.plugins.history = Darkroom.Plugin.extend({
+ undoTransformations: [],
+
+ initialize: function InitDarkroomHistoryPlugin() {
+ this._initButtons();
+ this.darkroom.addEventListener('core:transformation', this._onTranformationApplied.bind(this));
+ },
+
+ undo: function() {
+ if (this.darkroom.transformations.length === 0) {
+ return;
+ }
+
+ var lastTransformation = this.darkroom.transformations.pop();
+ this.undoTransformations.unshift(lastTransformation);
+
+ this.darkroom.reinitializeImage();
+ this._updateButtons();
+ },
+
+ redo: function() {
+ if (this.undoTransformations.length === 0) {
+ return;
+ }
+
+ var cancelTransformation = this.undoTransformations.shift();
+ this.darkroom.transformations.push(cancelTransformation);
+
+ this.darkroom.reinitializeImage();
+ this._updateButtons();
+ },
+
+ _initButtons: function() {
+ var buttonGroup = this.darkroom.toolbar.createButtonGroup();
+
+ this.backButton = buttonGroup.createButton({
+ image: 'fa fa-step-backward',
+ disabled: true,
+ editOnly: true,
+ });
+ this.forwardButton = buttonGroup.createButton({
+ image: 'fa fa-step-forward',
+ disabled: true,
+ editOnly: true,
+ });
+
+ this.backButton.addEventListener('click', this.undo.bind(this));
+ this.forwardButton.addEventListener('click', this.redo.bind(this));
+
+ return this;
+ },
+
+ _updateButtons: function() {
+ this.backButton.disable(this.darkroom.transformations.length === 0);
+ this.forwardButton.disable(this.undoTransformations.length === 0);
+ },
+
+ _onTranformationApplied: function() {
+ this.undoTransformations = [];
+ this._updateButtons();
+ },
});
-
- this.backButton.addEventListener('click', this.undo.bind(this));
- this.forwardButton.addEventListener('click', this.redo.bind(this));
-
- return this;
- },
-
- _updateButtons: function() {
- this.backButton.disable((this.darkroom.transformations.length === 0))
- this.forwardButton.disable((this.undoTransformations.length === 0))
- },
-
- _onTranformationApplied: function() {
- this.undoTransformations = [];
- this._updateButtons();
- }
- });
-
- };
-
- return {DarkroomPluginHistory: DarkroomPluginHistory};
-
+ };
+
+ return {DarkroomPluginHistory: DarkroomPluginHistory};
});
diff --git a/web_widget_darkroom/static/src/js/plugins/darkroom.rotate.js b/web_widget_darkroom/static/src/js/plugins/darkroom.rotate.js
index e50a0d5f..0a02629a 100755
--- a/web_widget_darkroom/static/src/js/plugins/darkroom.rotate.js
+++ b/web_widget_darkroom/static/src/js/plugins/darkroom.rotate.js
@@ -1,70 +1,64 @@
-/* Adapted from https://github.com/MattKetmo/darkroomjs/tree/master/lib/js/plugins
- * License https://github.com/MattKetmo/darkroomjs/blob/master/LICENSE
- */
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
-odoo.define('web_widget_darkroom.darkroom_rotate', function(require){
-
- 'use strict';
-
- var DarkroomPluginRotate = function() {
+odoo.define('web_widget_darkroom.darkroom_rotate', function() {
+ 'use strict';
- var Rotation = Darkroom.Transformation.extend({
- applyTransformation: function(canvas, image, next) {
- var angle = (image.getAngle() + this.options.angle) % 360;
- image.rotate(angle);
-
- var width, height;
- height = Math.abs(image.getWidth()*(Math.sin(angle*Math.PI/180)))+Math.abs(image.getHeight()*(Math.cos(angle*Math.PI/180)));
- width = Math.abs(image.getHeight()*(Math.sin(angle*Math.PI/180)))+Math.abs(image.getWidth()*(Math.cos(angle*Math.PI/180)));
-
- canvas.setWidth(width);
- canvas.setHeight(height);
-
- canvas.centerObject(image);
- image.setCoords();
- canvas.renderAll();
-
- next();
- }
- });
-
- Darkroom.plugins['rotate'] = Darkroom.Plugin.extend({
-
- initialize: function InitDarkroomRotatePlugin() {
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- var leftButton = buttonGroup.createButton({
- image: 'fa fa-undo oe_edit_only',
- editOnly: true,
+ var DarkroomPluginRotate = function() {
+ var Rotation = Darkroom.Transformation.extend({
+ applyTransformation: function(canvas, image, next) {
+ var angle = (image.getAngle() + this.options.angle) % 360;
+ image.rotate(angle);
+
+ var height = Math.abs(image.getWidth()*Math.sin(angle*Math.PI/180))+Math.abs(image.getHeight()*Math.cos(angle*Math.PI/180));
+ var width = Math.abs(image.getHeight()*Math.sin(angle*Math.PI/180))+Math.abs(image.getWidth()*Math.cos(angle*Math.PI/180));
+
+ canvas.setWidth(width);
+ canvas.setHeight(height);
+
+ canvas.centerObject(image);
+ image.setCoords();
+ canvas.renderAll();
+
+ next();
+ },
});
-
- var rightButton = buttonGroup.createButton({
- image: 'fa fa-repeat oe_edit_only',
- editOnly: true,
+
+ Darkroom.plugins.rotate = Darkroom.Plugin.extend({
+ initialize: function InitDarkroomRotatePlugin() {
+ var buttonGroup = this.darkroom.toolbar.createButtonGroup();
+
+ var leftButton = buttonGroup.createButton({
+ image: 'fa fa-undo oe_edit_only',
+ editOnly: true,
+ });
+ var rightButton = buttonGroup.createButton({
+ image: 'fa fa-repeat oe_edit_only',
+ editOnly: true,
+ });
+
+ leftButton.addEventListener('click', this.rotateLeft.bind(this));
+ rightButton.addEventListener('click', this.rotateRight.bind(this));
+ },
+
+ rotateLeft: function rotateLeft() {
+ this.rotate(-90);
+ },
+
+ rotateRight: function rotateRight() {
+ this.rotate(90);
+ },
+
+ rotate: function rotate(angle) {
+ this.darkroom.applyTransformation(
+ new Rotation({angle: angle})
+ );
+ }
});
-
- leftButton.addEventListener('click', this.rotateLeft.bind(this));
- rightButton.addEventListener('click', this.rotateRight.bind(this));
- },
-
- rotateLeft: function rotateLeft() {
- this.rotate(-90);
- },
-
- rotateRight: function rotateRight() {
- this.rotate(90);
- },
-
- rotate: function rotate(angle) {
- this.darkroom.applyTransformation(
- new Rotation({angle: angle})
- );
- }
-
- });
-
- }
+ };
- return {DarkroomPluginRotate: DarkroomPluginRotate};
-
+ return {DarkroomPluginRotate: DarkroomPluginRotate};
});
diff --git a/web_widget_darkroom/static/src/js/plugins/darkroom.zoom.js b/web_widget_darkroom/static/src/js/plugins/darkroom.zoom.js
index 65085aee..c4849196 100755
--- a/web_widget_darkroom/static/src/js/plugins/darkroom.zoom.js
+++ b/web_widget_darkroom/static/src/js/plugins/darkroom.zoom.js
@@ -1,198 +1,148 @@
-/* Copyright 2016 LasLabs Inc.
- * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
- */
-
-odoo.define('web_widget_darkroom.darkroom_zoom', function(require){
-
- 'use strict';
-
- var DarkroomPluginZoom = function(){
-
- Darkroom.plugins['zoom'] = Darkroom.Plugin.extend({
-
- inZoom: false,
- zoomLevel: 0,
- zoomFactor: .1,
-
- initialize: function() {
- var self = this;
- var buttonGroup = this.darkroom.toolbar.createButtonGroup();
-
- this.zoomButton = buttonGroup.createButton({
- image: 'fa fa-search',
- })
- this.zoomInButton = buttonGroup.createButton({
- image: 'fa fa-plus',
- })
- this.zoomOutButton = buttonGroup.createButton({
- image: 'fa fa-minus',
- })
- this.okButton = buttonGroup.createButton({
- image: 'fa fa-check',
- type: 'success',
- hide: true,
- editOnly: true,
- });
- this.cancelButton = buttonGroup.createButton({
- image: 'fa fa-times',
- type: 'danger',
- hide: true
- });
-
- // Buttons click
- this.zoomButton.addEventListener('click', this.toggleZoom.bind(this));
- this.zoomInButton.addEventListener('click', this.zoomIn.bind(this));
- this.zoomOutButton.addEventListener('click', this.zoomOut.bind(this));
- //this.okButton.addEventListener('click', this.saveZoom.bind(this));
- this.cancelButton.addEventListener('click', this.releaseFocus.bind(this));
-
- // Canvas events
- this.darkroom.canvas.on('mouse:down', this.onMouseDown.bind(this));
- this.darkroom.canvas.on('mouse:move', this.onMouseMove.bind(this));
- this.darkroom.canvas.on('mouse:up', this.onMouseUp.bind(this));
- //this.darkroom.canvas.on('object:moving', this.onObjectMoving.bind(this));
- //this.darkroom.canvas.on('object:scaling', this.onObjectScaling.bind(this));
- $(this.darkroom.canvas.wrapperEl).on('mousewheel', function(event){
- self.onMouseWheel(event);
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+odoo.define('web_widget_darkroom.darkroom_zoom', function() {
+ 'use strict';
+
+ var DarkroomPluginZoom = function() {
+ Darkroom.plugins.zoom = Darkroom.Plugin.extend({
+ inZoom: false,
+ zoomLevel: 0,
+ zoomFactor: 0.1,
+
+ initialize: function() {
+ var self = this;
+ var buttonGroup = this.darkroom.toolbar.createButtonGroup();
+
+ this.zoomButton = buttonGroup.createButton({
+ image: 'fa fa-search',
+ });
+ this.zoomInButton = buttonGroup.createButton({
+ image: 'fa fa-plus',
+ });
+ this.zoomOutButton = buttonGroup.createButton({
+ image: 'fa fa-minus',
+ });
+ this.cancelButton = buttonGroup.createButton({
+ image: 'fa fa-times',
+ type: 'danger',
+ hide: true
+ });
+
+ // Button click events
+ this.zoomButton.addEventListener('click', this.toggleZoom.bind(this));
+ this.zoomInButton.addEventListener('click', this.zoomIn.bind(this));
+ this.zoomOutButton.addEventListener('click', this.zoomOut.bind(this));
+ this.cancelButton.addEventListener('click', this.releaseFocus.bind(this));
+
+ // Canvas events
+ this.darkroom.canvas.on('mouse:down', this.onMouseDown.bind(this));
+ this.darkroom.canvas.on('mouse:move', this.onMouseMove.bind(this));
+ this.darkroom.canvas.on('mouse:up', this.onMouseUp.bind(this));
+ $(this.darkroom.canvas.wrapperEl).on('mousewheel', function(event){
+ self.onMouseWheel(event);
+ });
+
+ this.toggleElements(false);
+ },
+
+ toggleZoom: function() {
+ if (this.hasFocus()) {
+ this.releaseFocus();
+ } else {
+ this.requireFocus();
+ }
+ },
+
+ hasFocus: function() {
+ return this.inZoom;
+ },
+
+ releaseFocus: function() {
+ this.toggleElements(false);
+ },
+
+ requireFocus: function() {
+ this.toggleElements(true);
+ },
+
+ toggleElements: function(bool) {
+ var toggle = bool;
+ if (typeof bool === 'undefined') {
+ toggle = !this.hasFocus();
+ }
+
+ this.zoomButton.active(toggle);
+ this.inZoom = toggle;
+ this.zoomInButton.hide(!toggle);
+ this.zoomOutButton.hide(!toggle);
+ this.cancelButton.hide(!toggle);
+ this.darkroom.canvas.default_cursor = toggle ? 'move' : 'default';
+ },
+
+ zoomIn: function() {
+ return this.setZoomLevel(this.zoomFactor, this.getCenterPoint());
+ },
+
+ zoomOut: function() {
+ return this.setZoomLevel(-this.zoomFactor, this.getCenterPoint());
+ },
+
+ // Return fabric.Point object for center of canvas
+ getCenterPoint: function() {
+ var center = this.darkroom.canvas.getCenter();
+ return new fabric.Point(center.left, center.top);
+ },
+
+ // Set internal zoom
+ setZoomLevel: function(factor, point) {
+ var zoomLevel = this.zoomLevel + factor;
+ if (zoomLevel < 0) {
+ zoomLevel = 0;
+ }
+ if (zoomLevel === this.zoomLevel) {
+ return false;
+ }
+ if (point) {
+ var canvas = this.darkroom.canvas;
+ // Add one for zero index
+ canvas.zoomToPoint(point, zoomLevel + 1);
+ this.zoomLevel = zoomLevel;
+ }
+ return true;
+ },
+
+ onMouseWheel: function(event) {
+ if (this.hasFocus() && event && event.originalEvent) {
+ var modifier = event.originalEvent.wheelDelta < 0 ? -1 : 1;
+ var pointer = this.darkroom.canvas.getPointer(event.originalEvent);
+ var mousePoint = new fabric.Point(pointer.x, pointer.y);
+ this.setZoomLevel(modifier * this.zoomFactor, mousePoint);
+ return event.preventDefault();
+ }
+ },
+
+ onMouseDown: function() {
+ if (this.hasFocus()) {
+ this.panning = true;
+ }
+ },
+
+ onMouseUp: function() {
+ this.panning = false;
+ },
+
+ onMouseMove: function(event) {
+ if (this.panning && event && event.e) {
+ var delta = new fabric.Point(event.e.movementX, event.e.movementY);
+ this.darkroom.canvas.relativePan(delta);
+ }
+ },
});
-
- //fabric.util.addListener(fabric.document, 'keydown', this.onKeyDown.bind(this));
- //fabric.util.addListener(fabric.document, 'keyup', this.onKeyUp.bind(this));
- this.toggleElements(false);
-
- },
-
- toggleZoom: function() {
- if (this.hasFocus()) {
- this.releaseFocus();
- } else {
- this.requireFocus();
- }
- },
-
- hasFocus: function() {
- return this.inZoom;
- },
-
- releaseFocus: function() {
- this.toggleElements(false);
- },
-
- requireFocus: function() {
- this.toggleElements(true);
- },
-
- toggleElements: function(activate) {
- if (activate === 'undefined') {
- activate = !this.hasFocus();
- }
- this.zoomButton.active(!activate);
- this.inZoom = activate;
- this.zoomInButton.hide(!activate);
- this.zoomOutButton.hide(!activate);
- this.okButton.hide(!activate);
- this.cancelButton.hide(!activate);
- this.darkroom.canvas.default_cursor = activate ? "move" : "default";
- },
-
- // Return fabric.Point object for center of canvas
- getCenterPoint: function() {
- var center = this.darkroom.canvas.getCenter();
- return new fabric.Point(center.left, center.top);
- },
-
- // Set internal zoom
- setZoomLevel: function(factor, point) {
- var zoomLevel = this.zoomLevel + factor;
- if (zoomLevel < 0) zoomLevel = 0;
- if (zoomLevel == this.zoomLevel) return false;
- console.log('Setting zoom factor');
- console.log(zoomLevel);
- console.log(point);
- if (point) {
- var canvas = this.darkroom.canvas;
- canvas.zoomToPoint(point, zoomLevel + 1); // Add one for zero index
- this.zoomLevel = zoomLevel;
- }
- return true;
- },
-
- getObjectBounds: function() {
- var canvas = this.darkroom.canvas;
- var objects = canvas.getObjects();
- var top = 0, bottom = 0, left = 0, right = 0;
- for (var idx in objects) {
- var obj = objects[idx];
- var objRight = obj.left + obj.getWidth();
- var objBottom = obj.top + obj.getHeight();
- if (obj.left < left) left = obj.left;
- if (objRight > right) right = objRight;
- if (obj.top < top) top = obj.top;
- if (objBottom > bottom) bottom = objBottom;
- }
- return {
- top: top,
- bottom: bottom,
- left: left,
- right: right,
- height: (bottom - top),
- width: (right - left),
- }
- },
-
- zoomIn: function() {
- return this.setZoomLevel(this.zoomFactor, this.getCenterPoint());
- },
-
- zoomOut: function() {
- return this.setZoomLevel(-this.zoomFactor, this.getCenterPoint());
- },
-
- onMouseWheel: function(event) {
- if (this.hasFocus() && event && event.originalEvent) {
- var modifier = event.originalEvent.wheelDelta < 0 ? -1 : 1;
- var pointer = this.darkroom.canvas.getPointer(event.originalEvent);
- var mousePoint = new fabric.Point(pointer.x, pointer.y);
- this.setZoomLevel(modifier * this.zoomFactor, mousePoint);
- return event.preventDefault();
- }
- },
-
- onMouseDown: function(event) {
- if (this.hasFocus()) {
- this.panning = true;
- }
- },
-
- onMouseUp: function(event) {
- this.panning = false;
- },
-
- onMouseMove: function(event) {
- if (this.panning && event && event.e) {
- var delta = new fabric.Point(event.e.movementX,
- event.e.movementY);
- var canvas = this.darkroom.canvas;
- var objBounds = this.getObjectBounds();
- var newPoint = new fabric.Point(
- -delta.x - canvas.viewportTransform[4],
- -delta.y - canvas.viewportTransform[5]
- )
- if (newPoint.x < objBounds.left || newPoint.x > objBounds.right) {
- return;
- }
- if (newPoint.y < objBounds.top || newPoint.y > objBounds.bottom) {
- return;
- }
- canvas.absolutePan(newPoint);
- //canvas.setCoords();
- }
- },
-
- });
-
- }
-
- return {DarkroomPluginZoom: DarkroomPluginZoom};
+ };
+ return {DarkroomPluginZoom: DarkroomPluginZoom};
});
diff --git a/web_widget_darkroom/static/src/js/widget_darkroom.js b/web_widget_darkroom/static/src/js/widget_darkroom.js
index 582f8997..c9814b58 100644
--- a/web_widget_darkroom/static/src/js/widget_darkroom.js
+++ b/web_widget_darkroom/static/src/js/widget_darkroom.js
@@ -1,238 +1,224 @@
-/* Copyright 2016 LasLabs Inc.
- * License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
- */
-
-odoo.define('web_widget_darkroom.darkroom_widget', function(require){
- "use strict";
-
- var core = require('web.core');
- var common = require('web.form_common');
- var session = require('web.session');
- var utils = require('web.utils');
- var framework = require('web.framework');
- var crash_manager = require('web.crash_manager');
-
- var QWeb = core.qweb;
- var _t = core._t;
-
- var FieldDarkroomImage = common.AbstractField.extend(common.ReinitializeFieldMixin, {
- className: 'darkroom-widget',
- template: 'FieldDarkroomImage',
- placeholder: "/web/static/src/img/placeholder.png",
- darkroom: null,
- no_rerender: false,
-
- defaults: {
- // Canvas initialization size
- minWidth: 100,
- minHeight: 100,
- maxWidth: 700,
- maxHeight: 500,
-
- // Plugins options
- plugins: {
- crop: {
- minHeight: 50,
- minWidth: 50,
- ratio: 1
+/**
+* Copyright 2013 Matthieu Moquet
+* Copyright 2016-2017 LasLabs Inc.
+* License MIT (https://opensource.org/licenses/MIT)
+**/
+
+odoo.define('web_widget_darkroom.darkroom_widget', function(require) {
+ 'use strict';
+
+ var core = require('web.core');
+ var common = require('web.form_common');
+ var session = require('web.session');
+ var utils = require('web.utils');
+ var _ = require('_');
+
+ var QWeb = core.qweb;
+
+ var FieldDarkroomImage = common.AbstractField.extend(common.ReinitializeFieldMixin, {
+ className: 'darkroom-widget',
+ template: 'FieldDarkroomImage',
+ placeholder: "/web/static/src/img/placeholder.png",
+ darkroom: null,
+ no_rerender: false,
+
+ defaults: {
+ // Canvas initialization size
+ minWidth: 100,
+ minHeight: 100,
+ maxWidth: 700,
+ maxHeight: 500,
+
+ // Plugin options
+ plugins: {
+ crop: {
+ minHeight: 50,
+ minWidth: 50,
+ ratio: 1
+ },
+ },
+ },
+
+ init: function(field_manager, node) {
+ this._super(field_manager, node);
+ this.options = _.defaults(this.options, this.defaults);
+ },
+
+ _init_darkroom: function() {
+ if (!this.darkroom) {
+ this._init_darkroom_icons();
+ this._init_darkroom_ui();
+ this._init_darkroom_plugins();
+ }
+ },
+
+ _init_darkroom_icons: function() {
+ var element = document.createElement('div');
+ element.id = 'darkroom-icons';
+ element.style.height = 0;
+ element.style.width = 0;
+ element.style.position = 'absolute';
+ element.style.visibility = 'hidden';
+ element.innerHTML = '';
+ this.el.appendChild(element);
+ },
+
+ _init_darkroom_plugins: function() {
+ require('web_widget_darkroom.darkroom_crop').DarkroomPluginCrop();
+ require('web_widget_darkroom.darkroom_history').DarkroomPluginHistory();
+ require('web_widget_darkroom.darkroom_rotate').DarkroomPluginRotate();
+ require('web_widget_darkroom.darkroom_zoom').DarkroomPluginZoom();
+ },
+
+ _init_darkroom_ui: function() {
+ // Button object
+ function Button(element) {
+ this.element = element;
+ }
+
+ Button.prototype = {
+ addEventListener: function(eventName, listener) {
+ if (this.element.addEventListener) {
+ this.element.addEventListener(eventName, listener);
+ } else if (this.element.attachEvent) {
+ this.element.attachEvent('on' + eventName, listener);
+ }
+ },
+ removeEventListener: function(eventName, listener) {
+ if (this.element.removeEventListener) {
+ this.element.removeEventListener(eventName, listener);
+ } else if (this.element.detachEvent) {
+ this.element.detachEvent('on' + eventName, listener);
+ }
+ },
+ active: function(bool) {
+ if (bool) {
+ this.element.classList.add('darkroom-button-active');
+ } else {
+ this.element.classList.remove('darkroom-button-active');
+ }
+ },
+ hide: function(bool) {
+ if (bool) {
+ this.element.classList.add('hidden');
+ } else {
+ this.element.classList.remove('hidden');
+ }
+ },
+ disable: function(bool) {
+ this.element.disabled = bool;
+ },
+ };
+
+ // ButtonGroup object
+ function ButtonGroup(element) {
+ this.element = element;
+ }
+
+ ButtonGroup.prototype = {
+ createButton: function(options) {
+ var defaults = {
+ image: 'fa fa-question-circle',
+ type: 'default',
+ group: 'default',
+ hide: false,
+ disabled: false,
+ editOnly: false,
+ addClass: '',
+ };
+ var optionsMerged = Darkroom.Utils.extend(options, defaults);
+
+ var buttonElement = document.createElement('button');
+ buttonElement.type = 'button';
+ buttonElement.className = 'darkroom-button darkroom-button-' + optionsMerged.type;
+ buttonElement.innerHTML = '';
+ if (optionsMerged.editOnly) {
+ buttonElement.classList.add('oe_edit_only');
+ }
+ if (optionsMerged.addClass) {
+ buttonElement.classList.add(optionsMerged.addClass);
+ }
+ this.element.appendChild(buttonElement);
+
+ var button = new Button(buttonElement);
+ button.hide(optionsMerged.hide);
+ button.disable(optionsMerged.disabled);
+
+ return button;
+ }
+ };
+
+ // Toolbar object
+ function Toolbar(element) {
+ this.element = element;
+ }
+
+ Toolbar.prototype = {
+ createButtonGroup: function() {
+ var buttonGroupElement = document.createElement('div');
+ buttonGroupElement.className = 'darkroom-button-group';
+ this.element.appendChild(buttonGroupElement);
+
+ return new ButtonGroup(buttonGroupElement);
+ }
+ };
+
+ Darkroom.UI = {
+ Toolbar: Toolbar,
+ ButtonGroup: ButtonGroup,
+ Button: Button,
+ };
},
- },
-
- // Post initialization method
- initialize: function() {
- // Active crop selection
- // this.plugins['crop'].requireFocus();
- // Add custom listener
- // this.addEventListener('core:transformation', function() { /* ... */ });
- }
-
- },
-
- init: function(field_manager, node) {
- this._super(field_manager, node);
- this.options = _.defaults(this.options, this.defaults);
- },
-
- _init_darkroom_icons: function() {
- var element = document.createElement('div');
- element.id = 'darkroom-icons';
- element.style.height = 0;
- element.style.width = 0;
- element.style.position = 'absolute';
- element.style.visibility = 'hidden';
- element.innerHTML = '';
- this.el.appendChild(element);
- },
-
- _init_darkroom_plugins: function(){
- require('web_widget_darkroom.darkroom_crop').DarkroomPluginCrop();
- require('web_widget_darkroom.darkroom_history').DarkroomPluginHistory();
- require('web_widget_darkroom.darkroom_rotate').DarkroomPluginRotate();
- require('web_widget_darkroom.darkroom_zoom').DarkroomPluginZoom();
- },
-
- _init_darkroom: function() {
- if (!this.darkroom) {
- this._init_darkroom_icons();
- this._init_darkroom_ui();
- this._init_darkroom_plugins();
- }
- },
-
- _init_darkroom_ui: function() {
-
- Darkroom.UI = {
- Toolbar: Toolbar,
- ButtonGroup: ButtonGroup,
- Button: Button,
- };
-
- // Toolbar object.
- function Toolbar(element) {
- this.element = element;
- }
-
- Toolbar.prototype = {
- createButtonGroup: function(options) {
- var buttonGroup = document.createElement('div');
- buttonGroup.className = 'darkroom-button-group';
- this.element.appendChild(buttonGroup);
-
- return new ButtonGroup(buttonGroup);
- }
- };
-
- // ButtonGroup object.
- function ButtonGroup(element) {
- this.element = element;
- }
-
- ButtonGroup.prototype = {
- createButton: function(options) {
- var defaults = {
- image: 'fa fa-question-circle',
- type: 'default',
- group: 'default',
- hide: false,
- disabled: false,
- editOnly: false,
- addClass: '',
- };
-
- options = Darkroom.Utils.extend(options, defaults);
-
- var buttonElement = document.createElement('button');
- buttonElement.type = 'button';
- buttonElement.className = 'darkroom-button darkroom-button-' + options.type;
- buttonElement.innerHTML = '';
- if (options.editOnly) {
- buttonElement.classList.add('oe_edit_only');
- }
- if (options.addClass) {
- buttonElement.classList.add(options.addClass);
- }
- // buttonElement.innerHTML = '';
- this.element.appendChild(buttonElement);
-
- var button = new Button(buttonElement);
- button.hide(options.hide);
- button.disable(options.disabled);
-
- return button;
- }
- }
-
- // Button object.
- function Button(element) {
- this.element = element;
- }
-
- Button.prototype = {
- addEventListener: function(eventName, listener) {
- if (this.element.addEventListener){
- this.element.addEventListener(eventName, listener);
- } else if (this.element.attachEvent) {
- this.element.attachEvent('on' + eventName, listener);
- }
+
+ destroy_content: function() {
+ if (this.darkroom && this.darkroom.containerElement) {
+ this.darkroom.containerElement.remove();
+ this.darkroom = null;
+ }
},
- removeEventListener: function(eventName, listener) {
- if (this.element.removeEventListener){
- this.element.removeEventListener(eventName, listener);
- }
+
+ set_value: function(value) {
+ return this._super(value);
},
- active: function(value) {
- if (value){
- this.element.classList.add('darkroom-button-active');
- this.element.disabled = false;
- } else {
- this.element.classList.remove('darkroom-button-active');
- this.element.disabled = true;
- }
+
+ render_value: function() {
+ this.destroy_content();
+ this._init_darkroom();
+
+ var url = null;
+ if (this.get('value') && !utils.is_bin_size(this.get('value'))) {
+ url = 'data:image/png;base64,' + this.get('value');
+ } else if (this.get('value')) {
+ var id = JSON.stringify(this.view.datarecord.id || null);
+ var field = this.name;
+ if (this.options.preview_image) {
+ field = this.options.preview_image;
+ }
+ url = session.url('/web/image', {
+ model: this.view.dataset.model,
+ id: id,
+ field: field,
+ unique: (this.view.datarecord.__last_update || '').replace(/[^0-9]/g, ''),
+ });
+ } else {
+ url = this.placeholder;
+ }
+
+ var $img = $(QWeb.render("FieldBinaryImage-img", {widget: this, url: url}));
+ this.$el.find('> img').remove();
+ this.$el.append($img);
+ this.darkroom = new Darkroom($img.get(0), this.options);
+ this.darkroom.widget = this;
},
- hide: function(value) {
- if (value)
- this.element.classList.add('hidden');
- else
- this.element.classList.remove('hidden');
+
+ commit_value: function() {
+ if (this.darkroom.sourceImage) {
+ this.set_value(this.darkroom.sourceImage.toDataURL().split(',')[1]);
+ }
},
- disable: function(value) {
- this.element.disabled = (value) ? true : false;
- }
- };
-
- },
-
- destroy_content: function() {
- if (this.darkroom && this.darkroom.containerElement) {
- this.darkroom.containerElement.remove();
- this.darkroom = null;
- }
- },
-
- set_value: function(value){
- this.destroy_content();
- return this._super(value);
- },
-
- render_value: function() {
- this._init_darkroom();
- var url;
- if (this.get('value') && !utils.is_bin_size(this.get('value'))) {
- url = 'data:image/png;base64,' + this.get('value');
- } else if (this.get('value')) {
- var id = JSON.stringify(this.view.datarecord.id || null);
- var field = this.name;
- if (this.options.preview_image)
- field = this.options.preview_image;
- url = session.url('/web/image', {
- model: this.view.dataset.model,
- id: id,
- field: field,
- unique: (this.view.datarecord.__last_update || '').replace(/[^0-9]/g, ''),
- });
- } else {
- url = this.placeholder;
- }
-
- var $img = $(QWeb.render("FieldBinaryImage-img", { widget: this, url: url }));
- this.$el.find('> img').remove();
- this.$el.append($img);
- this.darkroom = new Darkroom($img.get(0), this.options);
- this.darkroom.widget = this;
- },
-
- commit_value: function(callback) {
- this.set_value(
- this.darkroom.sourceImage.toDataURL().split(',')[1]
- );
- },
-
- });
-
- core.form_widget_registry.add("darkroom", FieldDarkroomImage);
-
- return {
- FieldDarkroomImage: FieldDarkroomImage,
- }
-
+ });
+
+ core.form_widget_registry.add("darkroom", FieldDarkroomImage);
+
+ return {FieldDarkroomImage: FieldDarkroomImage};
});
diff --git a/web_widget_darkroom/static/src/js/widget_darkroom.js.orig b/web_widget_darkroom/static/src/js/widget_darkroom.js.orig
deleted file mode 100644
index 4b0f04f1..00000000
--- a/web_widget_darkroom/static/src/js/widget_darkroom.js.orig
+++ /dev/null
@@ -1,246 +0,0 @@
-/* © 2016-TODAY LasLabs Inc.
- * License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
- */
-
-odoo.define('web_widget_darkroom.darkroom_widget', function(require){
- "use strict";
-
- var core = require('web.core');
- var common = require('web.form_common');
- var session = require('web.session');
- var utils = require('web.utils');
- var framework = require('web.framework');
- var crash_manager = require('web.crash_manager');
-
- var QWeb = core.qweb;
- var _t = core._t;
-
- var FieldDarkroomImage = common.AbstractField.extend(common.ReinitializeFieldMixin, {
- className: 'darkroom-widget',
- template: 'FieldDarkroomImage',
- placeholder: "/web/static/src/img/placeholder.png",
- darkroom: null,
- no_rerender: false,
-
- _init_darkroom_icons: function() {
- var element = document.createElement('div');
- element.id = 'darkroom-icons';
- element.style.height = 0;
- element.style.width = 0;
- element.style.position = 'absolute';
- element.style.visibility = 'hidden';
- element.innerHTML = '';
- this.el.appendChild(element);
- },
-
- _init_darkroom_plugins: function(){
- require('web_widget_darkroom.darkroom_crop').DarkroomPluginCrop();
- require('web_widget_darkroom.darkroom_history').DarkroomPluginHistory();
- require('web_widget_darkroom.darkroom_rotate').DarkroomPluginRotate();
- require('web_widget_darkroom.darkroom_zoom').DarkroomPluginZoom();
- require('web_widget_darkroom.darkroom_save').DarkroomPluginSave();
- },
-
- _init_darkroom_ui: function() {
-
- this._init_darkroom_icons();
-
- Darkroom.UI = {
- Toolbar: Toolbar,
- ButtonGroup: ButtonGroup,
- Button: Button,
- };
-
- // Toolbar object.
- function Toolbar(element) {
- this.element = element;
- }
-
- Toolbar.prototype = {
- createButtonGroup: function(options) {
- var buttonGroup = document.createElement('div');
- buttonGroup.className = 'darkroom-button-group';
- this.element.appendChild(buttonGroup);
-
- return new ButtonGroup(buttonGroup);
- }
- };
-
- // ButtonGroup object.
- function ButtonGroup(element) {
- this.element = element;
- }
-
- ButtonGroup.prototype = {
- createButton: function(options) {
- var defaults = {
- image: 'fa fa-question-circle',
- type: 'default',
- group: 'default',
- hide: false,
- disabled: false,
- editOnly: false,
- addClass: '',
- };
-
- options = Darkroom.Utils.extend(options, defaults);
-
- var buttonElement = document.createElement('button');
- buttonElement.type = 'button';
- buttonElement.className = 'darkroom-button darkroom-button-' + options.type;
- buttonElement.innerHTML = '';
- if (options.editOnly) {
- buttonElement.classList.add('oe_edit_only');
- }
-<<<<<<< Updated upstream
- if (options.addClass) {
- buttonElement.classList.add(options.addClass);
- }
- // buttonElement.innerHTML = '';
-=======
->>>>>>> Stashed changes
- this.element.appendChild(buttonElement);
-
- var button = new Button(buttonElement);
- button.hide(options.hide);
- button.disable(options.disabled);
-
- return button;
- }
- }
-
- // Button object.
- function Button(element) {
- this.element = element;
- }
-
- Button.prototype = {
- addEventListener: function(eventName, listener) {
- if (this.element.addEventListener){
- this.element.addEventListener(eventName, listener);
- } else if (this.element.attachEvent) {
- this.element.attachEvent('on' + eventName, listener);
- }
- },
- removeEventListener: function(eventName, listener) {
- if (this.element.removeEventListener){
- this.element.removeEventListener(eventName, listener);
- }
- },
- active: function(value) {
- if (value){
- this.element.classList.add('darkroom-button-active');
- this.element.disabled = false;
- } else {
- this.element.classList.remove('darkroom-button-active');
- this.element.disabled = true;
- }
- },
- hide: function(value) {
- if (value)
- this.element.classList.add('hidden');
- else
- this.element.classList.remove('hidden');
- },
- disable: function(value) {
- this.element.disabled = (value) ? true : false;
- }
- };
-
- },
-
- destroy_content: function() {
- console.log('Destroying Darkroom Obj');
- this.darkroom.selfDestroy();
- },
-
- render_value: function() {
- console.log('Rerendering');
- var url;
- if (this.get('value') && !utils.is_bin_size(this.get('value'))) {
- url = 'data:image/png;base64,' + this.get('value');
- } else if (this.get('value')) {
- var id = JSON.stringify(this.view.datarecord.id || null);
- var field = this.name;
- if (this.options.preview_image)
- field = this.options.preview_image;
- url = session.url('/web/image', {
- model: this.view.dataset.model,
- id: id,
- field: field,
- unique: (this.view.datarecord.__last_update || '').replace(/[^0-9]/g, ''),
- });
- } else {
- url = this.placeholder;
- }
-
- var $img = $(QWeb.render("FieldBinaryImage-img", { widget: this, url: url }));
- this.$el.find('> img').remove();
- this.$el.append($img);
-
- if (!this.darkroom) {
- this._init_darkroom_ui();
- this._init_darkroom_plugins();
- }
- this.darkroom = new Darkroom($img.get(0));
- this.darkroom.widget = this;
- },
-
- on_save_as: function(e) {
-
- framework.blockUI();
- var value = this.darkroom.sourceImage.toDataURL();
- var c = crash_manager;
- var filename_fieldname = this.node.attrs.filename;
- var filename_field = this.view.fields && this.view.fields[filename_fieldname];
-
- var filereader = new FileReader();
- filereader.onload = function(upload) {
- var data = upload.target.result;
- data = data.split(',')[1];
- $.post({
- url: '/web/binary/upload',
-
- })
- };
- filereader.readAsDataURL(new Blob(value));
-
- this.$el.find('form.o_form_darkroom_form input[name=ufile]').val(value);
- this.$el.find('form.o_form_darkroom_form input[name=session_id]').val(this.session.session_id);
- this.$el.find('form.o_form_darkroom_form').submit();
-
- var $form = $(parentEl).find('form');
- $form.find('input[name=ufile]').val(value);
-
- },
-
- init: function(field_manager, node) {
- var self = this;
- this._super(field_manager, node);
- this.binary_value = false;
- this.useFileAPI = !!window.FileReader;
- this.max_upload_size = 25 * 1024 * 1024; // 25Mo
- if (!this.useFileAPI) {
- this.fileupload_id = _.uniqueId('oe_fileupload');
- $(window).on(this.fileupload_id, function() {
- var args = [].slice.call(arguments).slice(1);
- self.on_file_uploaded.apply(self, args);
- });
- }
- },
- stop: function() {
- if (!this.useFileAPI) {
- $(window).off(this.fileupload_id);
- }
- this._super.apply(this, arguments);
- },
-
- });
-
- core.form_widget_registry.add("darkroom", FieldDarkroomImage);
-
- return {
- FieldDarkroomImage: FieldDarkroomImage,
- }
-
-});
diff --git a/web_widget_darkroom/static/src/js/widget_darkroom_modal.js b/web_widget_darkroom/static/src/js/widget_darkroom_modal.js
new file mode 100644
index 00000000..118fd102
--- /dev/null
+++ b/web_widget_darkroom/static/src/js/widget_darkroom_modal.js
@@ -0,0 +1,64 @@
+/**
+* Copyright 2017 LasLabs Inc.
+* License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
+**/
+
+odoo.define('web_widget_darkroom.darkroom_modal_button', function(require) {
+ 'use strict';
+
+ var core = require('web.core');
+ var DataModel = require('web.DataModel');
+
+ core.form_widget_registry.get('image').include({
+ // Used in template to prevent Darkroom buttons from being added to
+ // forms for new records, which are not supported
+ darkroom_supported: function() {
+ if (this.field_manager.dataset.index === null) {
+ return false;
+ }
+ return true;
+ },
+
+ render_value: function() {
+ this._super();
+
+ var imageWidget = this;
+ var activeModel = imageWidget.field_manager.dataset._model.name;
+ var activeRecordId = imageWidget.field_manager.datarecord.id;
+ var activeField = imageWidget.node.attrs.name;
+
+ var updateImage = function() {
+ var ActiveModel = new DataModel(activeModel);
+ ActiveModel.query([activeField]).
+ filter([['id', '=', activeRecordId]]).
+ all().
+ then(function(result) {
+ imageWidget.set_value(result[0].image);
+ });
+ };
+
+ var openModal = function() {
+ var context = {
+ active_model: activeModel,
+ active_record_id: activeRecordId,
+ active_field: activeField,
+ };
+ var modalAction = {
+ type: 'ir.actions.act_window',
+ res_model: 'darkroom.modal',
+ name: 'Darkroom',
+ views: [[false, 'form']],
+ target: 'new',
+ context: context,
+ };
+ var options = {on_close: updateImage};
+ imageWidget.do_action(modalAction, options);
+ };
+
+ var $button = this.$('.oe_form_binary_image_darkroom_modal');
+ if ($button.length > 0) {
+ $button.click(openModal);
+ }
+ },
+ });
+});
diff --git a/web_widget_darkroom/static/src/less/darkroom.less b/web_widget_darkroom/static/src/less/darkroom.less
new file mode 100755
index 00000000..1c8a1b85
--- /dev/null
+++ b/web_widget_darkroom/static/src/less/darkroom.less
@@ -0,0 +1,11 @@
+.darkroom-button-group {
+ display: inline;
+}
+
+.darkroom-button-active {
+ color: @odoo-brand-primary;
+}
+
+.oe_form_field_image_controls i {
+ margin: 0 5%;
+}
diff --git a/web_widget_darkroom/static/src/xml/field_templates.xml b/web_widget_darkroom/static/src/xml/field_templates.xml
index 746426be..2692cb7e 100644
--- a/web_widget_darkroom/static/src/xml/field_templates.xml
+++ b/web_widget_darkroom/static/src/xml/field_templates.xml
@@ -1,17 +1,30 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web_widget_darkroom/tests/__init__.py b/web_widget_darkroom/tests/__init__.py
new file mode 100644
index 00000000..3773eddd
--- /dev/null
+++ b/web_widget_darkroom/tests/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 LasLabs Inc.
+# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
+
+from . import test_darkroom_modal
diff --git a/web_widget_darkroom/tests/test_darkroom_modal.py b/web_widget_darkroom/tests/test_darkroom_modal.py
new file mode 100644
index 00000000..f299939e
--- /dev/null
+++ b/web_widget_darkroom/tests/test_darkroom_modal.py
@@ -0,0 +1,203 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 LasLabs Inc.
+# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
+
+from openerp.tests.common import TransactionCase
+
+
+class TestDarkroomModal(TransactionCase):
+
+ def test_default_res_model_id_model_in_context(self):
+ """Should return correct ir.model record when context has model name"""
+ active_model = 'res.users'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ })
+ test_result = test_model._default_res_model_id()
+
+ expected = self.env['ir.model'].search([('model', '=', active_model)])
+ self.assertEqual(test_result, expected)
+
+ def test_default_res_model_id_no_valid_info_in_context(self):
+ """Should return empty ir.model recordset when missing/invalid info"""
+ test_model = self.env['darkroom.modal'].with_context({})
+ test_result = test_model._default_res_model_id()
+
+ self.assertEqual(test_result, self.env['ir.model'])
+
+ def test_default_res_record_id_id_in_context(self):
+ """Should return correct value when ID in context"""
+ active_record_id = 5
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_record_id': active_record_id,
+ })
+ test_result = test_model._default_res_record_id()
+
+ self.assertEqual(test_result, active_record_id)
+
+ def test_default_res_record_id_no_id_in_context(self):
+ """Should return 0 when no ID in context"""
+ test_model = self.env['darkroom.modal'].with_context({})
+ test_result = test_model._default_res_record_id()
+
+ self.assertEqual(test_result, 0)
+
+ def test_default_res_record_model_and_id_in_context(self):
+ """Should return correct record when context has model name and ID"""
+ active_model = 'res.users'
+ active_record_id = 1
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ 'active_record_id': active_record_id,
+ })
+ test_result = test_model._default_res_record()
+
+ expected = self.env[active_model].browse(active_record_id)
+ self.assertEqual(test_result, expected)
+
+ def test_default_res_record_model_but_no_id_in_context(self):
+ """Should return right empty recordset if model but no ID in context"""
+ active_model = 'res.users'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ })
+ test_result = test_model._default_res_record()
+
+ self.assertEqual(test_result, self.env[active_model])
+
+ def test_default_res_record_no_valid_model_info_in_context(self):
+ """Should return None if context has missing/invalid model info"""
+ active_model = 'bad.model.name'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ })
+ test_result = test_model._default_res_record()
+
+ self.assertIsNone(test_result)
+
+ def test_default_res_field_id_model_and_field_in_context(self):
+ """Should return correct ir.model.fields record when info in context"""
+ active_model = 'res.users'
+ active_field = 'name'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ 'active_field': active_field,
+ })
+ test_result = test_model._default_res_field_id()
+
+ self.assertEqual(test_result.name, active_field)
+ self.assertEqual(test_result.model_id.model, active_model)
+
+ def test_default_res_field_id_no_valid_field_in_context(self):
+ """Should return empty recordset if field info missing/invalid"""
+ active_model = 'res.users'
+ active_field = 'totally.not.a.real.field.name'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ 'active_field': active_field,
+ })
+ test_result = test_model._default_res_field_id()
+
+ self.assertEqual(test_result, self.env['ir.model.fields'])
+
+ def test_default_res_field_id_no_valid_model_in_context(self):
+ """Should return empty recordset if model info missing/invalid"""
+ active_field = 'name'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_field': active_field,
+ })
+ test_result = test_model._default_res_field_id()
+
+ self.assertEqual(test_result, self.env['ir.model.fields'])
+
+ def test_default_image_all_info_in_context(self):
+ """Should return value of correct field if all info in context"""
+ active_model = 'res.users'
+ active_record_id = 1
+ active_field = 'name'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ 'active_record_id': active_record_id,
+ 'active_field': active_field,
+ })
+ test_result = test_model._default_image()
+
+ expected = self.env[active_model].browse(active_record_id).name
+ self.assertEqual(test_result, expected)
+
+ def test_default_image_no_valid_field_in_context(self):
+ """Should return None if missing/invalid field info in context"""
+ active_model = 'res.users'
+ active_record_id = 1
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ 'active_record_id': active_record_id,
+ })
+ test_result = test_model._default_image()
+
+ self.assertIsNone(test_result)
+
+ def test_default_image_no_valid_id_in_context(self):
+ """Should return False/None if missing/invalid record ID in context"""
+ active_model = 'res.users'
+ active_field = 'name'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ 'active_field': active_field,
+ })
+ test_result = test_model._default_image()
+
+ self.assertFalse(test_result)
+
+ def test_default_image_no_valid_model_in_context(self):
+ """Should return None if missing/invalid model info in context"""
+ active_record_id = 1
+ active_field = 'name'
+ test_model = self.env['darkroom.modal'].with_context({
+ 'active_record_id': active_record_id,
+ 'active_field': active_field,
+ })
+ test_result = test_model._default_image()
+
+ self.assertIsNone(test_result)
+
+ def test_action_save_record_count_in_self(self):
+ """Should raise correct error if not called on recordset of 1"""
+ test_wizard = self.env['darkroom.modal'].with_context({
+ 'active_model': 'res.users',
+ 'active_record_id': 1,
+ 'active_field': 'name',
+ }).create({})
+ test_wizard_set = test_wizard + test_wizard.copy()
+
+ with self.assertRaises(ValueError):
+ self.env['darkroom.modal'].action_save()
+ with self.assertRaises(ValueError):
+ test_wizard_set.action_save()
+
+ def test_action_save_update_source(self):
+ """Should update source record correctly"""
+ active_model = 'res.users'
+ active_record_id = 1
+ test_wizard = self.env['darkroom.modal'].with_context({
+ 'active_model': active_model,
+ 'active_record_id': active_record_id,
+ 'active_field': 'name',
+ }).create({})
+ test_name = 'Test Name'
+ test_wizard.image = test_name
+ test_wizard.action_save()
+
+ result = self.env[active_model].browse(active_record_id).name
+ self.assertEqual(result, test_name)
+
+ def test_action_save_return_action(self):
+ """Should return correct action"""
+ test_wizard = self.env['darkroom.modal'].with_context({
+ 'active_model': 'res.users',
+ 'active_record_id': 1,
+ 'active_field': 'name',
+ }).create({})
+ test_value = test_wizard.action_save()
+
+ self.assertEqual(test_value, {'type': 'ir.actions.act_window_close'})
diff --git a/web_widget_darkroom/views/assets.xml b/web_widget_darkroom/views/assets.xml
index 7b57c7a1..87e6a18a 100644
--- a/web_widget_darkroom/views/assets.xml
+++ b/web_widget_darkroom/views/assets.xml
@@ -1,31 +1,28 @@
-
-
-
+
+
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/web_widget_darkroom/wizards/__init__.py b/web_widget_darkroom/wizards/__init__.py
new file mode 100644
index 00000000..202f83a0
--- /dev/null
+++ b/web_widget_darkroom/wizards/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 LasLabs Inc.
+# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
+
+from . import darkroom_modal
diff --git a/web_widget_darkroom/wizards/darkroom_modal.py b/web_widget_darkroom/wizards/darkroom_modal.py
new file mode 100644
index 00000000..37646f76
--- /dev/null
+++ b/web_widget_darkroom/wizards/darkroom_modal.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 LasLabs Inc.
+# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
+
+from openerp import api, fields, models
+from openerp.exceptions import MissingError
+
+
+class DarkroomModal(models.TransientModel):
+ _name = 'darkroom.modal'
+ _description = 'Darkroom Modal - Wizard Model'
+
+ @api.model
+ def _default_res_model_id(self):
+ res_model_name = self.env.context.get('active_model')
+ return self.env['ir.model'].search([('model', '=', res_model_name)])
+
+ @api.model
+ def _default_res_record_id(self):
+ return self.env.context.get('active_record_id', 0)
+
+ @api.model
+ def _default_res_record(self):
+ res_model_name = self._default_res_model_id().model
+ try:
+ res_model_model = self.env[res_model_name]
+ except KeyError:
+ return None
+
+ return res_model_model.browse(self._default_res_record_id())
+
+ @api.model
+ def _default_res_field_id(self):
+ res_model_id = self._default_res_model_id()
+ res_field_name = self.env.context.get('active_field')
+ return self.env['ir.model.fields'].search([
+ ('model_id', '=', res_model_id.id),
+ ('name', '=', res_field_name),
+ ])
+
+ @api.model
+ def _default_image(self):
+ res_record = self._default_res_record()
+ res_field_name = self._default_res_field_id().name
+
+ try:
+ return getattr(res_record, res_field_name, None)
+ except (TypeError, MissingError):
+ return None
+
+ res_model_id = fields.Many2one(
+ comodel_name='ir.model',
+ string='Source Model',
+ required=True,
+ default=lambda s: s._default_res_model_id(),
+ )
+ res_record_id = fields.Integer(
+ string='Source Record ID',
+ required=True,
+ default=lambda s: s._default_res_record_id(),
+ )
+ res_field_id = fields.Many2one(
+ comodel_name='ir.model.fields',
+ string='Source Field',
+ required=True,
+ default=lambda s: s._default_res_field_id(),
+ )
+ image = fields.Binary(
+ string='Darkroom Image',
+ required=True,
+ default=lambda s: s._default_image(),
+ )
+
+ @api.multi
+ def action_save(self):
+ self.ensure_one()
+
+ res_record = self._default_res_record()
+ res_field_name = self._default_res_field_id().name
+ setattr(res_record, res_field_name, self.image)
+
+ return {'type': 'ir.actions.act_window_close'}
diff --git a/web_widget_darkroom/wizards/darkroom_modal.xml b/web_widget_darkroom/wizards/darkroom_modal.xml
new file mode 100644
index 00000000..413e6f15
--- /dev/null
+++ b/web_widget_darkroom/wizards/darkroom_modal.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ Darkroom Modal Wizard
+ darkroom.modal
+
+
+
+
+