mirror of
https://github.com/OCA/web.git
synced 2025-02-22 13:21:25 +02:00
web_widget_darkroom: Add o2m DarkroomJS widget
This commit is contained in:
11
web_widget_darkroom/static/src/css/darkroom.css
Executable file
11
web_widget_darkroom/static/src/css/darkroom.css
Executable file
@@ -0,0 +1,11 @@
|
||||
/*.darkroom-container{
|
||||
padding-top: 50px;
|
||||
}
|
||||
.darkroom-toolbar{
|
||||
top: 5px;
|
||||
}
|
||||
*/
|
||||
|
||||
.darkroom-button-group{
|
||||
display: inline;
|
||||
}
|
||||
20
web_widget_darkroom/static/src/js/darkroom_plugins.js
Normal file
20
web_widget_darkroom/static/src/js/darkroom_plugins.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/* 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
|
||||
|
||||
});
|
||||
683
web_widget_darkroom/static/src/js/plugins/darkroom.crop.js
Executable file
683
web_widget_darkroom/static/src/js/plugins/darkroom.crop.js
Executable file
@@ -0,0 +1,683 @@
|
||||
/* 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
|
||||
});
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return {DarkroomPluginCrop: DarkroomPluginCrop};
|
||||
|
||||
});
|
||||
80
web_widget_darkroom/static/src/js/plugins/darkroom.history.js
Executable file
80
web_widget_darkroom/static/src/js/plugins/darkroom.history.js
Executable file
@@ -0,0 +1,80 @@
|
||||
/* 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,
|
||||
});
|
||||
|
||||
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};
|
||||
|
||||
});
|
||||
70
web_widget_darkroom/static/src/js/plugins/darkroom.rotate.js
Executable file
70
web_widget_darkroom/static/src/js/plugins/darkroom.rotate.js
Executable file
@@ -0,0 +1,70 @@
|
||||
/* 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_rotate', function(require){
|
||||
|
||||
'use strict';
|
||||
|
||||
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 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 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})
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return {DarkroomPluginRotate: DarkroomPluginRotate};
|
||||
|
||||
});
|
||||
198
web_widget_darkroom/static/src/js/plugins/darkroom.zoom.js
Executable file
198
web_widget_darkroom/static/src/js/plugins/darkroom.zoom.js
Executable file
@@ -0,0 +1,198 @@
|
||||
/* 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);
|
||||
});
|
||||
|
||||
//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};
|
||||
|
||||
});
|
||||
238
web_widget_darkroom/static/src/js/widget_darkroom.js
Normal file
238
web_widget_darkroom/static/src/js/widget_darkroom.js
Normal file
@@ -0,0 +1,238 @@
|
||||
/* 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
|
||||
},
|
||||
},
|
||||
|
||||
// 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 = '<!-- inject:svg --><!-- endinject -->';
|
||||
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 = '<i class="' + options.image + ' fa-2x"></i>';
|
||||
if (options.editOnly) {
|
||||
buttonElement.classList.add('oe_edit_only');
|
||||
}
|
||||
if (options.addClass) {
|
||||
buttonElement.classList.add(options.addClass);
|
||||
}
|
||||
// buttonElement.innerHTML = '<svg class="darkroom-icon"><use xlink:href="#' + options.image + '" /></svg>';
|
||||
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() {
|
||||
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,
|
||||
}
|
||||
|
||||
});
|
||||
246
web_widget_darkroom/static/src/js/widget_darkroom.js.orig
Normal file
246
web_widget_darkroom/static/src/js/widget_darkroom.js.orig
Normal file
@@ -0,0 +1,246 @@
|
||||
/* © 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 = '<!-- inject:svg --><!-- endinject -->';
|
||||
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 = '<i class="' + options.image + ' fa-2x"></i>';
|
||||
if (options.editOnly) {
|
||||
buttonElement.classList.add('oe_edit_only');
|
||||
}
|
||||
<<<<<<< Updated upstream
|
||||
if (options.addClass) {
|
||||
buttonElement.classList.add(options.addClass);
|
||||
}
|
||||
// buttonElement.innerHTML = '<svg class="darkroom-icon"><use xlink:href="#' + options.image + '" /></svg>';
|
||||
=======
|
||||
>>>>>>> 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,
|
||||
}
|
||||
|
||||
});
|
||||
17
web_widget_darkroom/static/src/xml/field_templates.xml
Normal file
17
web_widget_darkroom/static/src/xml/field_templates.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright 2016 LasLabs Inc.
|
||||
License LGPL-3 or later (http://www.gnu.org/licenses/lgpl.html).
|
||||
-->
|
||||
|
||||
<templates id="field_templates" xml:space="preserve">
|
||||
<t t-name="FieldDarkroomImage">
|
||||
<span class="oe_form_field o_form_field_darkroom"
|
||||
t-att-style="widget.node.attrs.style">
|
||||
<t t-if="!widget.get('effective_readonly')">
|
||||
<div class="darkroom-toolbar" />
|
||||
</t>
|
||||
</span>
|
||||
</t>
|
||||
</templates>
|
||||
Reference in New Issue
Block a user