silverstripe-cms/javascript/ImageEditor/History.js

362 lines
14 KiB
JavaScript

/**
* @author Mateusz
*/
ImageEditor.History = {
initialize: function() {
this.history = new Array();
this.historyPointer = -1;
this.isEnabled = true;
this.image = ImageEditor.Positioning.addBehaviour($('image'));
this.size = new Array();
this.fakeImage = $('fakeImg');
this.image = $('image');
this.adjust = new Array();
this.undo = ImageEditor.History.undo.bind(this);
this.redo = ImageEditor.History.redo.bind(this);
this.add = ImageEditor.History.add.bind(this);
this.addListeners = ImageEditor.History.addListeners.bind(this);
this.hasOperation = ImageEditor.History.hasOperation.bind(this);
this.isInHistory = ImageEditor.History.isInHistory.bind(this);
this.onImageLoad = ImageEditor.History.onImageLoad.bind(this);
this.removeLastOperation = ImageEditor.History.removeLastOperation.bind(this);
this.getOptimizedHistory = ImageEditor.History.getOptimizedHistory.bind(this);
this.addCrop = ImageEditor.History.addCrop.bind(this);
this.addResize = ImageEditor.History.addResize.bind(this);
this.addEffect = ImageEditor.History.addEffect.bind(this);
this.addAdjust = ImageEditor.History.addAdjust.bind(this);
this.enable = ImageEditor.History.enable.bind(this);
this.disable = ImageEditor.History.disable.bind(this);
this.clear = ImageEditor.History.clear.bind(this);
this.onlyResized = ImageEditor.History.onlyResized.bind(this);
this.optimizeOtherEffects = ImageEditor.History.optimizeOtherEffects.bind(this);
this.optimizeCrop = ImageEditor.History.optimizeCrop.bind(this);
this.optimizeResize = ImageEditor.History.optimizeResize.bind(this);
this.optimizeRotate = ImageEditor.History.optimizeRotate.bind(this);
this.checkSpecialOperation = ImageEditor.History.checkSpecialOperation.bind(this);
this.addListeners();
},
undo: function() {
if(this.isEnabled) {
if(this.historyPointer >= 1) {
var operation = this.history[this.historyPointer].operation;
this.checkSpecialOperation('undo',this.history[this.historyPointer]);
Event.observe('image','load',this.onImageLoad);
this.historyPointer = this.historyPointer - 1;
this.image.src = this.history[this.historyPointer].fileUrl;
} else {
ImageEditor.statusMessageWrapper.statusMessage("No more undo","bad");
}
}
},
redo: function() {
if(this.isEnabled) {
if(this.historyPointer < this.history.length-1) {
var operation = this.history[this.historyPointer+1].operation;
this.checkSpecialOperation('redo',this.history[this.historyPointer+1]);
Event.observe('image','load',this.onImageLoad);
this.historyPointer = this.historyPointer + 1;
this.image.src = this.history[this.historyPointer].fileUrl;
} else {
ImageEditor.statusMessageWrapper.statusMessage("No more redo","bad");
}
}
},
add: function(operation,url,additionalInfo) {
var imageWidth = isNaN(parseInt($('image').style.width)) ? Element.getDimensions($('image')).width : parseInt($('image').style.width);//IE hack
var imageHeight = isNaN(parseInt($('image').style.height)) ? Element.getDimensions($('image')).height : parseInt($('image').style.height);//IE hack
//code above should be moved to Positioning.addBehaviour
if(!this.isInHistory(operation,url)) {
this.historyPointer++;
this.size[this.historyPointer] = {'width': imageWidth,'height': imageHeight};
this.history[this.historyPointer] = {'operation': operation,'fileUrl' : url,'additionalInfo': additionalInfo};
this.size = this.size.slice(0,this.historyPointer+1);
this.history = this.history.slice(0,this.historyPointer+1);
}
},
addCrop: function(url,top,left,width,height) {
this.add('crop',url,{
'top':top,
'left': left,
'width': width,
'height': height
});
},
addResize: function(url,width,height) {
this.add('resize',url,{
'width': width,
'height': height
});
},
addEffect: function(url,name) {
this.add(name,url);
},
addAdjust: function(name,value,url) {
this.add(name,url,{'value': value});
if(this.adjust[name] == undefined) {
this.adjust[name] = {'pointer': 0,'values': Array()}
this.adjust[name].values[0] = ImageEditor.effects.getEffect(name).getDefaultValue();
}
this.adjust[name].values[this.adjust[name].values.length] = value;
this.adjust[name].pointer++;
},
addListeners: function() {
this.undoListener = Event.observe('UndoButton','click',this.undo);
this.redoListener = Event.observe('RedoButton','click',this.redo);
},
hasOperation: function(operation,historyPointer) {
if(historyPointer == undefined) historyPointer = this.history.length-1;
for(i=historyPointer;i>=0;i--) {
if(this.history[i].operation == operation) {
return true;
}
}
return false;
},
getOptimizedHistory: function(without) {
var history = this.history.slice(0,this.historyPointer+1);
var result = {};
var historyPointer = 1;
result[0] = {fileUrl : history[0].fileUrl};
var resize = this.optimizeResize(history,this.size);
var rotate = this.optimizeRotate(history);
var crop = this.optimizeCrop(history,this.size);
var other = this.optimizeOtherEffects(history,without);
if(rotate != undefined) {
for(var i =0;i<rotate.length;i++) {
result[historyPointer] = rotate[i];
historyPointer++;
}
}
if(resize != undefined){
result[historyPointer] = resize;
historyPointer++;
}
if(crop != undefined) {
result[historyPointer] = crop;
historyPointer++;
}
if(other != undefined) {
for(var i =0;i<other.length;i++) {
result[historyPointer] = other[i];
historyPointer++;
}
}
return result;
},
enable: function() {
this.isEnabled = true;
},
disable: function() {
this.isEnabled = false;
},
clear: function() {
this.history = new Array();
this.historyPointer = -1;
this.size = new Array();
},
removeLastOperation: function() {
this.history.pop();
this.size.pop();
this.historyPointer--;
},
isInHistory: function(operation,url) {
if(operation == 'initialize' && this.historyPointer != -1) return true;
for(var k=0;k<this.history.length;k++) {
if(this.history[k].operation == operation && this.history[k].fileUrl == url) {
return true;
}
}
return false;
},
onImageLoad: function(event) {
Event.stopObserving($('image'),'load',this.onImageLoad);
this.image.style.width = this.size[this.historyPointer].width + 'px';
this.image.style.height = this.size[this.historyPointer].height + 'px';
$('imageContainer').style.width = this.size[this.historyPointer].width + 'px';
$('imageContainer').style.height = this.size[this.historyPointer].height + 'px';
ImageEditor.resize.imageContainerResize.originalWidth = this.size[this.historyPointer].width;
ImageEditor.resize.imageContainerResize.originalHeight = this.size[this.historyPointer].height;
ImageEditor.imageToResize.onImageLoad();
},
onlyResized: function() {
for(i=this.historyPointer;i>=0;i--) {
if(this.history[i].operation != 'resize') {
return false;
}
}
return true;
},
optimizeResize: function(history,size) {
var scallingXFactor = 1;var scallingYFactor = 1;
var initWidth = size[0].width;var initHeight = size[0].height;
for(var i=0;i<history.length && i < (this.historyPointer+1);i++) {
switch(history[i].operation) {
case 'resize':
if(i == 0) {
var previousWidth = 0;
var previousHeight = 0;
} else {
previousWidth = size[i-1].width;
previousHeight = size[i-1].height;
}
if(i != 0) {
scallingXFactor *= history[i].additionalInfo.width/previousWidth
scallingYFactor *= history[i].additionalInfo.height/previousHeight;
}
break;
case 'rotate':
var tempX = scallingXFactor;
scallingXFactor = scallingYFactor;
scallingYFactor = tempX;
var tempW = initWidth;
initWidth = initHeight;
initHeight = tempW;
break;
}
}
if(scallingXFactor != 1 || scallingYFactor != 1) return {'operation': 'resize','additionalInfo': {'width': initWidth*scallingXFactor,'height': initHeight*scallingYFactor}};
},
optimizeCrop: function(history,size) {
var imageWidth = size[0].width;var imageHeight = size[0].height;
var topCrop = 0;var leftCrop = 0;
var scallingXFactor = 1;var scallingYFactor = 1;
var crops = new Array();var cropNumber = 0;var resizeNumber = 0;
var lastResizeNumber = 0;
for(var i=0;i<history.length && i < (this.historyPointer+1);i++) {
switch(history[i].operation) {
case 'crop':
crops[cropNumber] = {
'width': history[i].additionalInfo.width, 'height': history[i].additionalInfo.height,
'top': history[i].additionalInfo.top, 'left': history[i].additionalInfo.left,
'parent': {'width': size[i-1].width,'height': size[i-1].height}
};
imageWidth = crops[cropNumber].width;
imageHeight = crops[cropNumber].height;
cropNumber++;
scallingXFactor = 1;scallingYFactor = 1;
break;
case 'resize':
if(crops.length != 0) {
resizeNumber++;
if(i == 0) {
var previousWidth = 0;
var previousHeight = 0;
} else {
previousWidth = size[i-1].width;
previousHeight = size[i-1].height;
}
if(i != 0) {
scallingXFactor = history[i].additionalInfo.width/previousWidth
scallingYFactor = history[i].additionalInfo.height/previousHeight;
}
for(var k=0;k<crops.length;k++) {
crops[k].top *= scallingYFactor;
crops[k].left *= scallingXFactor;
crops[k].parent.width *= scallingXFactor;
crops[k].parent.height *= scallingYFactor;
crops[k].width *= scallingXFactor;
crops[k].height *= scallingYFactor;
}
crops[cropNumber-1].width = history[i].additionalInfo.width;
crops[cropNumber-1].height = history[i].additionalInfo.height;
}
break;
case 'rotate':
if(crops.length != 0) {
for(var k = 0;k<crops.length;k++) {
var tempTop = crops[k].top;
crops[k].top = crops[k].parent.width - crops[k].width - crops[k].left;
crops[k].left = tempTop;
tempWidth = crops[k].parent.width;
crops[k].parent.width = crops[k].parent.height;
crops[k].parent.height = tempWidth;
var tempWidth = crops[k].width;
crops[k].width = crops[k].height;
crops[k].height = tempWidth;
}
}
break;
}
}
for(var l=0;l<crops.length;l++) {
topCrop += crops[l].top;
leftCrop += crops[l].left;
}
if(cropNumber == 0) return;
if((topCrop + leftCrop + crops[cropNumber-1].width + crops[cropNumber-1].height) == 0) return;
return {'operation': 'crop','additionalInfo': {'top': topCrop,'left': leftCrop,'width': crops[cropNumber-1].width,'height': crops[cropNumber-1].height}};
},
optimizeOtherEffects: function(history,without) {
var result = Array();var effectsNumber = 0;var isInResult = false;
for(var i=0;i<history.length;i++) {
if(history[i].operation == 'resize' || history[i].operation == 'crop' || history[i].operation == 'rotate' || history[i].operation == without) continue;
if(history[i].operation.indexOf('adjust') != -1) {
isInResult = false;
for(var k=0;k<result.length;k++) {
if(result[k].operation == history[i].operation) {
result[k] = history[i];
isInResult = true;
}
}
if(!isInResult) {
result[effectsNumber] = history[i];
effectsNumber++;
}
} else {
result[effectsNumber] = history[i];
effectsNumber++;
}
}
return result;
},
optimizeRotate: function(history) {
var result = Array();var rotateNumber = 0;var rotate;
for(var i=0;i<history.length;i++) {
if(history[i].operation.indexOf('rotate') != -1) {
rotateNumber++;
rotate = history[i];
}
}
rotateNumber = rotateNumber % 4;
for(var i=0;i<rotateNumber;i++) {
result[result.length] = rotate;
}
return result.length == 0 ? undefined : result;
},
checkSpecialOperation: function(operationType,historyEntry) {
if(this.adjust[historyEntry.operation] != undefined) {
if(operationType == 'undo') {
if(this.adjust[historyEntry.operation].pointer > 0) this.adjust[historyEntry.operation].pointer--;
} else {
this.adjust[historyEntry.operation].pointer++;
}
ImageEditor.effects.getEffect(historyEntry.operation).setValue(this.adjust[historyEntry.operation].values[this.adjust[historyEntry.operation].pointer]);
}
}
};