From bd58e931bb5b33313fd2b347dfd03a70f923049f Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Sat, 15 Sep 2007 01:08:25 +0000 Subject: [PATCH] mujma: All PHP and JS files for ImageEditor?, works on FF 1.5/2.0. (merged from branches/gsoc) git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@41872 467b73ca-7a2a-4603-9d3b-597d59a354a9 --- _config.php | 3 +- code/AssetTableField.php | 4 +- code/ImageEditor.php | 127 ++++++++ css/ImageEditor/ImageEditor.css | 109 +++++++ images/ImageEditor/clickBox.JPG | Bin 0 -> 633 bytes images/ImageEditor/indicator.gif | Bin 0 -> 8815 bytes javascript/ImageEditor/.project | 11 + javascript/ImageEditor/Activator.js | 24 ++ javascript/ImageEditor/Crop.js | 143 +++++++++ javascript/ImageEditor/Effects.js | 18 ++ javascript/ImageEditor/Environment.js | 9 + javascript/ImageEditor/Image.js | 30 ++ javascript/ImageEditor/ImageBox.js | 50 ++++ javascript/ImageEditor/ImageEditor.js | 42 +++ javascript/ImageEditor/ImageHistory.js | 88 ++++++ javascript/ImageEditor/ImageTransformation.js | 79 +++++ javascript/ImageEditor/Require.js | 3 + javascript/ImageEditor/Resize.js | 60 ++++ javascript/ImageEditor/Resizeable.js | 278 ++++++++++++++++++ javascript/ImageEditor/Utils.js | 72 +++++ templates/ImageEditor.ss | 53 ++++ 21 files changed, 1201 insertions(+), 2 deletions(-) create mode 100644 code/ImageEditor.php create mode 100644 css/ImageEditor/ImageEditor.css create mode 100644 images/ImageEditor/clickBox.JPG create mode 100644 images/ImageEditor/indicator.gif create mode 100644 javascript/ImageEditor/.project create mode 100644 javascript/ImageEditor/Activator.js create mode 100644 javascript/ImageEditor/Crop.js create mode 100644 javascript/ImageEditor/Effects.js create mode 100644 javascript/ImageEditor/Environment.js create mode 100644 javascript/ImageEditor/Image.js create mode 100644 javascript/ImageEditor/ImageBox.js create mode 100644 javascript/ImageEditor/ImageEditor.js create mode 100644 javascript/ImageEditor/ImageHistory.js create mode 100644 javascript/ImageEditor/ImageTransformation.js create mode 100644 javascript/ImageEditor/Require.js create mode 100644 javascript/ImageEditor/Resize.js create mode 100644 javascript/ImageEditor/Resizeable.js create mode 100644 javascript/ImageEditor/Utils.js create mode 100644 templates/ImageEditor.ss diff --git a/_config.php b/_config.php index 49100a9f..b5d76a71 100644 --- a/_config.php +++ b/_config.php @@ -15,9 +15,10 @@ Director::addRules(100, array( 'admin/comments/$Action' => 'CommentAdmin', 'admin/ReportField/$Action/$ID/$Type/$OtherID' => 'ReportField_Controller', 'admin/bulkload/$Action/$ID/$OtherID' => 'BulkLoaderAdmin', + 'admin/ImageEditor/$Action' => 'ImageEditor', 'admin/$Action/$ID/$OtherID' => 'CMSMain', 'unsubscribe/$Email/$MailingList' => 'Unsubscribe_Controller', - 'membercontrolpanel/$Email' => 'MemberControlPanel' + 'membercontrolpanel/$Email' => 'MemberControlPanel' )); ?> diff --git a/code/AssetTableField.php b/code/AssetTableField.php index b08d47fc..f8169ecf 100755 --- a/code/AssetTableField.php +++ b/code/AssetTableField.php @@ -11,6 +11,7 @@ class AssetTableField extends ComplexTableField { $this->sourceSort = "Title"; $this->Markable = true; + Requirements::javascript("cms/javascript/ImageEditor/Activator.js"); } function setFolder($folder) { @@ -85,7 +86,8 @@ class AssetTableField extends ComplexTableField { $detailFormFields->addFieldToTab("BottomRoot", new Tab("Image", new LiteralField("ImageFull", - "{$childData->Name}" + '' . "{$childData->Name}" . '' . + '' ) ), 'Main' diff --git a/code/ImageEditor.php b/code/ImageEditor.php new file mode 100644 index 00000000..359acc7f --- /dev/null +++ b/code/ImageEditor.php @@ -0,0 +1,127 @@ +requestParams['fileToEdit'])) $this->raiseError(); + $fileWithPath = $this->requestParams['fileToEdit']; + $this->fileToEdit = $this->file2Origin($fileWithPath); + + return $this->renderWith(__CLASS__); + } + + private function raiseError() + { + Debug::friendlyError(500,"Bad arguments",__FILE__,__LINE__,''); + exit(); + } + + public function manipulate() { + $fileName = $this->requestParams['file']; + $command = $this->requestParams['command']; + $this->checkFileExists($fileName); + $gd = new GD($fileName); + switch($command) { + case 'rotate': + $angle = $_POST['angle']; + $gd = $gd->rotate($angle); + break; + case 'resize': + $imageNewWidth = $_POST['newImageWidth']; + $imageNewHeight = $_POST['newImageHeight']; + $gd = $gd->resize($imageNewWidth,$imageNewHeight); + break; + case 'crop': + $top = $_POST['top']; + $left = $_POST['left']; + $width = $_POST['width']; + $height = $_POST['height']; + $gd = $gd->crop($top,$left,$width,$height); + break; + } + $rand = md5(rand(1,100000)); + $gd->writeTo('../assets/tmp/' . $rand . '.jpg'); + $this->returnImage($gd,'/assets/tmp/' . $rand . '.jpg'); + } + + public function save() { + if(isset($this->requestParams['originalFile']) && isset($this->requestParams['editedFile'])) { + $originalFile = $this->requestParams['originalFile']; + $editedFile = $this->requestParams['editedFile']; + if($this->checkFileExists($originalFile) && $this->checkFileExists($editedFile)) { + if($editedFile != $originalFile && copy($this->url2File($editedFile),$this->url2File($originalFile))) { + $image = DataObject::get_one('File',"Filename = '" . substr($this->url2File($originalFile),3) . "'"); + $image->generateFormattedImage('AssetLibraryPreview'); + } else { + $this->raiseError(); + } + } else { + $this->raiseError(); + } + } else { + $this->raiseError(); + } + } + + private function returnImage(GD $gd,$strFile) + { + list($width, $height) = getimagesize('..' . $strFile); + echo json_encode(array( + 'fileName' => $strFile, + 'width' => $width, + 'height' => $height) + ); + } + + private function file2Origin($file) { + $file = str_replace('_resampled/','',$file); + $file = str_replace('_resampled/','',$file); + $file = str_replace('AssetLibraryPreview-','',$file); + $this->checkFileExists($file); + return $file; + } + + private function url2File($url) { + return '..' . substr($url,strpos($url,'/assets')); + } + + + private function checkFileExists($url) { + $pathInfo = pathinfo($url); + if(count($pathInfo) <= 3) $this->raiseError(); + if(!in_array($pathInfo['extension'],array('jpeg','jpg','jpe','png','gif'))) $this->raiseError(); + $path = explode('/',$pathInfo['dirname']); + if(count($path) > 1) { + $assetId = array_search('assets',$path); + if($assetId > 0) { + $realPath = '../' . implode('/',array_slice($path,$assetId,count($path) - $assetId)); + if(strpos($pathInfo['basename'],'AssetLibraryPreview') !== false) { + $realPath .= '/' . substr($pathInfo['basename'],strpos($pathInfo['basename'],'-')); + } else { + $realPath .= '/' . $pathInfo['basename']; + } + } else { + $this->raiseError(); + } + if(file_exists($realPath)) { return true; + } else { + $this->raiseError(); + } + } else { + $this->raiseError(); + } + } + } +?> \ No newline at end of file diff --git a/css/ImageEditor/ImageEditor.css b/css/ImageEditor/ImageEditor.css new file mode 100644 index 00000000..8eb61af7 --- /dev/null +++ b/css/ImageEditor/ImageEditor.css @@ -0,0 +1,109 @@ +* +{ + margin: 0px; + padding: 0px; +} + +.clickBox +{ + width: 7px; + height: 7px; + background-color: red; + position: absolute; +} +.leftUpperClickBox +{ + cursor: nw-resize; +} + +.leftMiddleClickBox +{ + cursor: e-resize; +} + +.leftLowerClickBox +{ + cursor: ne-resize; +} + +.rightUpperClickBox +{ + cursor: ne-resize; +} + +.rightMiddleClickBox +{ + cursor: w-resize; +} + +.rightLowerClickBox +{ + cursor: nw-resize; +} + +.upperMiddleClickBox +{ + cursor: n-resize; +} + +.lowerMiddleClickBox +{ + cursor: n-resize; +} +.inline +{ + display: inline; +} +#mainContainer +{ + width: 100%; + height:600px; +} +#imageContainer +{ + position: absolute; +} +#menuBarContainer +{ + border-bottom: 1px solid; + height: 100px; +} +.floatRight +{ + float: right; +} +#loadingIndicatorContainer +{ + display: none; + z-index: 1000; + position: absolute; +} +#fakeImg +{ + display: none; +} +#image +{ + width: 100%; + height: 100%; +} +#cropBox +{ + position: absolute; +} +.greyBox +{ + background-color: black; + position: absolute; + opacity: 0.5; +} +#mainContainer +{ + border-color: black; + border-style: solid; + background-color: white; + margin: 0px; + position: absolute; + top: 20px; + padding: 0px; +} diff --git a/images/ImageEditor/clickBox.JPG b/images/ImageEditor/clickBox.JPG new file mode 100644 index 0000000000000000000000000000000000000000..717c3912c09a6d5a8c06c1a70c04f6325ba69b94 GIT binary patch literal 633 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 Nxqtrk7mELV{s(hFy3POq literal 0 HcmV?d00001 diff --git a/javascript/ImageEditor/.project b/javascript/ImageEditor/.project new file mode 100644 index 00000000..1e36a9d4 --- /dev/null +++ b/javascript/ImageEditor/.project @@ -0,0 +1,11 @@ + + + ImageEditor-SS + + + + + + + + diff --git a/javascript/ImageEditor/Activator.js b/javascript/ImageEditor/Activator.js new file mode 100644 index 00000000..1c3254cd --- /dev/null +++ b/javascript/ImageEditor/Activator.js @@ -0,0 +1,24 @@ +var ImageEditorActivator = { + initialize: function() { + this.onOpen = ImageEditorActivator.onOpen.bind(this); + }, + + onOpen: function() { + iframe = window.top.document.getElementById('imageEditorIframe'); + if(iframe != null) { + iframe.parentNode.removeChild(iframe); + } + iframe = document.createElement('iframe'); + fileToEdit = $('ImageEditorActivator').firstChild.src; + iframe.setAttribute("src","/admin/ImageEditor?fileToEdit=" + fileToEdit); + iframe.id = 'imageEditorIframe'; + iframe.style.width = "97%"; + iframe.style.height = "300%"; + iframe.style.zIndex = "1000"; + iframe.style.position = "absolute"; + iframe.style.top = "-2%"; + iframe.style.left = "1.5%"; + window.top.document.body.appendChild(iframe); + } + +} \ No newline at end of file diff --git a/javascript/ImageEditor/Crop.js b/javascript/ImageEditor/Crop.js new file mode 100644 index 00000000..9afa07d7 --- /dev/null +++ b/javascript/ImageEditor/Crop.js @@ -0,0 +1,143 @@ +/** + * @author Mateusz + */ +var Crop = { + + initialize: function() { + this.cropBox = $('cropBox'); + new Positioning.addBehaviour(this.cropBox); + this.imageContainer = $('imageContainer'); + this.leftGreyBox = $('leftGreyBox'); + this.rightGreyBox = $('rightGreyBox'); + this.upperGreyBox = $('upperGreyBox'); + this.lowerGreyBox = $('lowerGreyBox'); + options = { + resizeStop: Crop.resizeStop.bind(this), + onDrag: Crop.onDrag.bind(this), + onResize: Crop.onResize.bind(this), + getMousePos: Crop.getMousePos.bind(this) + }; + this.centerCropBox = Crop.centerCropBox.bind(this); + this.placeGreyBox = Crop.placeGreyBox.bind(this); + this.setListeners = Crop.setListeners.bind(this); + this.onCropStop = Crop.onCropStop.bind(this); + this.onCropStart = Crop.onCropStart.bind(this); + this.onCropOk = Crop.onCropOk.bind(this); + this.onCropCancel = Crop.onCropCancel.bind(this); + this.doCrop = Crop.doCrop.bind(this); + this.setVisible = Crop.setVisible.bind(this); + Event.observe('image','load',this.centerCropBox); + this.resizeCropBox = new Resizeable.initialize(this.cropBox,options); + Event.observe(this.cropBox,'dblclick',this.onCropStop); + this.setListeners(); + this.setVisible(false); + }, + + resizeStop: function(event) { + EventStack.clearStack(); + this.resizeCropBox.originalHeight = this.cropBox.getHeight(); + this.resizeCropBox.originalWidth = this.cropBox.getWidth(); + }, + + onDrag: function() { + if(this.cropBox.getLeft() <= 0 ) this.cropBox.style.left = '0px'; + if(this.cropBox.getTop() <= 0 ) this.cropBox.style.top = '0px'; + if(this.cropBox.getLeft() + this.cropBox.getWidth() > this.cropBox.getParentWidth()) this.cropBox.style.left = this.cropBox.getParentWidth()- this.cropBox.getWidth() + 'px'; + if(this.cropBox.getTop() + this.cropBox.getHeight() > this.cropBox.getParentHeight()) this.cropBox.style.top = this.cropBox.getParentHeight() - this.cropBox.getHeight() + 'px'; + this.placeGreyBox(); + }, + + centerCropBox: function() { + this.cropBox.style.width = this.cropBox.getParentWidth()/2 + 'px'; + this.cropBox.style.height = this.cropBox.getParentHeight()/2 + 'px'; + this.cropBox.style.left = (this.cropBox.getParentWidth() - this.cropBox.getWidth())/2 + "px"; + this.cropBox.style.top = (this.cropBox.getParentHeight() - this.cropBox.getHeight())/2 + "px"; + this.placeGreyBox(); + this.leftBoxConstraint = this.cropBox.getParentLeft(); + this.topBoxConstraint = this.cropBox.getParentTop(); + this.rightBoxConstraint = this.cropBox.getParentLeft() + this.cropBox.getParentWidth(); + this.bottomBoxConstraint = this.cropBox.getParentTop() + this.cropBox.getParentHeight()-1;//hack without 1 doesn't work; + }, + + placeGreyBox: function() { + this.leftGreyBox.style.width = this.cropBox.getLeft() + "px"; + this.leftGreyBox.style.height = "100%"; + this.rightGreyBox.style.width = this.cropBox.getParentWidth() - this.cropBox.getLeft() - this.cropBox.getWidth() + "px"; + this.rightGreyBox.style.height = "100%"; + this.rightGreyBox.style.left = this.cropBox.getLeft() + this.cropBox.getWidth() + "px"; + this.upperGreyBox.style.width = this.cropBox.getWidth() + 'px'; + this.upperGreyBox.style.left = this.cropBox.getLeft() + 'px'; + this.upperGreyBox.style.height = this.cropBox.getTop() + 'px'; + this.lowerGreyBox.style.width = "100%"; + this.lowerGreyBox.style.height = this.cropBox.getParentHeight() - this.cropBox.getTop() - this.cropBox.getHeight() + "px"; + this.lowerGreyBox.style.top = this.cropBox.getTop() + this.cropBox.getHeight() + "px"; + this.lowerGreyBox.style.width = this.cropBox.getWidth() + 'px'; + this.lowerGreyBox.style.left = this.cropBox.getLeft() + 'px'; + }, + + onResize: function(event) { + x = Event.pointerX(event); + this.placeGreyBox(); + }, + getMousePos: function(event) { + x = Event.pointerX(event); + y = Event.pointerY(event); + if(x <= this.leftBoxConstraint) x = this.leftBoxConstraint; + if(y <= this.topBoxConstraint) y = this.topBoxConstraint; + if(x >= this.rightBoxConstraint) x = this.rightBoxConstraint; + if(y >= this.bottomBoxConstraint) y = this.bottomBoxConstraint; + return {x: x,y: y}; + }, + + onCropStop: function(event) { + this.doCrop(); + }, + + doCrop: function() { + newWidth = this.cropBox.getWidth() + newHeight = this.cropBox.getHeight() ; + startTop = this.cropBox.getTop() ; + startLeft = this.cropBox.getLeft() ; + if(newWidth > 30 && newHeight > 30) { + imageTransformation.crop(startTop,startLeft,newWidth,newHeight); + imageHistory.enable(); + } else { + alert('Crop area too small'); + } + }, + + setListeners: function() { + Event.observe('cropStart','click',this.onCropStart); + Event.observe('cropOk','click',this.onCropOk); + Event.observe('cropCancel','click',this.onCropCancel); + }, + + onCropStart: function() { + this.setVisible(true); + Element.show($('cropOk'),$('cropCancel')); + imageHistory.disable(); + }, + + onCropOk: function() { + Element.hide($('cropOk'),$('cropCancel')); + this.doCrop(); + }, + + onCropCancel: function() { + Element.hide($('cropOk'),$('cropCancel')); + this.setVisible(false); + imageHistory.enable(); + }, + + setVisible: function(setVisible) { + if(setVisible) { + Element.show(this.cropBox,this.leftGreyBox,this.rightGreyBox,this.upperGreyBox,this.lowerGreyBox); + this.centerCropBox(); + this.placeGreyBox(); + } else { + Element.hide(this.cropBox,this.leftGreyBox,this.rightGreyBox,this.upperGreyBox,this.lowerGreyBox,$('cropOk'),$('cropCancel')); + } + resize.imageContainerResize.setVisible(!setVisible); + this.resizeCropBox.setVisible(setVisible); + } +} \ No newline at end of file diff --git a/javascript/ImageEditor/Effects.js b/javascript/ImageEditor/Effects.js new file mode 100644 index 00000000..e1b3df40 --- /dev/null +++ b/javascript/ImageEditor/Effects.js @@ -0,0 +1,18 @@ +/** + * @author Mateusz + */ +var Effects = { + initialize: function() { + this.setListeners = Effects.setListeners.bind(this); + this.rotate = Effects.rotate.bind(this); + this.setListeners(); + }, + + rotate: function() { + imageTransformation.rotate(90); + }, + + setListeners: function() { + Event.observe('rotateButton','click',this.rotate); + } +} \ No newline at end of file diff --git a/javascript/ImageEditor/Environment.js b/javascript/ImageEditor/Environment.js new file mode 100644 index 00000000..8a8b2c0c --- /dev/null +++ b/javascript/ImageEditor/Environment.js @@ -0,0 +1,9 @@ +/** + * @author Mateusz + */ +var Environment = { + initialize: function (imageFile) { + imageBox = new ImageBox.initialize(); + image = new Image.initialize(imageFile); + }, +} \ No newline at end of file diff --git a/javascript/ImageEditor/Image.js b/javascript/ImageEditor/Image.js new file mode 100644 index 00000000..ee2149b9 --- /dev/null +++ b/javascript/ImageEditor/Image.js @@ -0,0 +1,30 @@ +/** + * @author Mateusz + */ +var Image = { + initialize: function(imageFile) { + this.image = $('image'); + this.image.src = imageFile; + this.reportSize = Image.reportSize.bind(this); + this.onImageLoad = Image.onImageLoad.bind(this); + Event.observe('image','load',this.onImageLoad); + imageHistory.add('initialize',this.image.src); + }, + + reportSize: function() { + $('imageWidth').innerHTML = this.image.width + "px"; + $('imageHeight').innerHTML = this.image.height + "px"; + }, + + onImageLoad: function() { + this.reportSize(); + if(resize.imageContainerResize.originalHeight == 0 && resize.imageContainerResize.originalWidth == 0) { + imageBox.center(); + } + $('imageContainer').style.width = this.image.width + 'px'; + $('imageContainer').style.height = this.image.height + 'px'; + resize.imageContainerResize.originalWidth = this.image.width; + resize.imageContainerResize.originalHeight = this.image.height; + + }, +}; diff --git a/javascript/ImageEditor/ImageBox.js b/javascript/ImageEditor/ImageBox.js new file mode 100644 index 00000000..cbb76d12 --- /dev/null +++ b/javascript/ImageEditor/ImageBox.js @@ -0,0 +1,50 @@ +/** + * @author Mateusz + */ +var ImageBox = { + + initialize: function() { + this.showIndicator = ImageBox.showIndicator.bind(this); + this.hideIndicator = ImageBox.hideIndicator.bind(this); + this.reCenterIndicator = ImageBox.reCenterIndicator.bind(this); + this.centerIndicator = ImageBox.centerIndicator.bind(this); + this.center = ImageBox.center.bind(this); + this.imageContainer = $('imageContainer'); + Element.hide(this.imageContainer); + }, + + showIndicator: function() { + this.centerIndicator(); + indicator.style.display = 'inline'; + }, + + hideIndicator: function() { + indicator = $('loadingIndicatorContainer'); + indicator.style.display = 'none'; + }, + + centerIndicator: function() { + indicator = $('loadingIndicatorContainer'); + indicatorImage = $('loadingIndicator'); + top = this.imageContainer.getTop(); + left = this.imageContainer.getLeft(); + width = this.imageContainer.getWidth(); + height = this.imageContainer.getHeight(); + indicator.style.left = left + width/2 - indicatorImage.width/2 + "px"; + indicator.style.top = top + height/2 - indicatorImage.height/2 + "px"; + }, + + reCenterIndicator: function() { + if($('loadingIndicatorContainer').style.display == 'inline') { + this.centerIndicator(); + } + }, + + center: function() { + $('imageContainer').style.left = this.imageContainer.getParentWidth()/2 - this.imageContainer.getWidth()/2 + 'px'; + $('imageContainer').style.top = this.imageContainer.getParentHeight()/2 - this.imageContainer.getHeight()/2 + 'px'; + Element.show(this.imageContainer); + } + + +}; diff --git a/javascript/ImageEditor/ImageEditor.js b/javascript/ImageEditor/ImageEditor.js new file mode 100644 index 00000000..ef4e0d7f --- /dev/null +++ b/javascript/ImageEditor/ImageEditor.js @@ -0,0 +1,42 @@ +/** + * @author Mateusz + */ + +Scriptaculous.require('cms/javascript/ImageEditor/Utils.js'); +Scriptaculous.require('cms/javascript/ImageEditor/ImageHistory.js'); +Scriptaculous.require('cms/javascript/ImageEditor/Image.js"'); +Scriptaculous.require('cms/javascript/ImageEditor/ImageTransformation.js'); +Scriptaculous.require('cms/javascript/ImageEditor/Resizeable.js'); +Scriptaculous.require('cms/javascript/ImageEditor/Effects.js'); +Scriptaculous.require('cms/javascript/ImageEditor/Environment.js'); +Scriptaculous.require('cms/javascript/ImageEditor/Crop.js'); +Scriptaculous.require('cms/javascript/ImageEditor/Resize.js'); +Scriptaculous.require('cms/javascript/ImageEditor/ImageBox.js'); +var ImageEditor = { + initialize: function(imageFile) { + imageHistory = new ImageHistory.initialize(); + environment = new Environment.initialize(imageFile); + imageTransformation = new ImageTransformation.initialize(); + resize = new Resize.initialize($('imageContainer')); + effects = new Effects.initialize(); + crop = new Crop.initialize(); + this.originalImageFile = imageFile; + this.tottalyOriginalImageFile = imageFile; + this.onSave = ImageEditor.onSave.bind(this); + this.onClose = ImageEditor.onClose.bind(this); + Event.observe($('saveButton'),'click',this.onSave); + Event.observe($('closeButton'),'click',this.onClose); + }, + onSave: function() { + if(this.tottalyOriginalImageFile != $('image').src) { + imageTransformation.save(this.tottalyOriginalImageFile,$('image').src); + } else { + this.onClose(); + } + }, + + onClose: function() { + window.parent.frames[1].location.reload(1); + Element.hide(window.frameElement); + } +} diff --git a/javascript/ImageEditor/ImageHistory.js b/javascript/ImageEditor/ImageHistory.js new file mode 100644 index 00000000..cc2b076f --- /dev/null +++ b/javascript/ImageEditor/ImageHistory.js @@ -0,0 +1,88 @@ +/** + * @author Mateusz + */ +ImageHistory = { + + initialize: function() { + this.history = new Array(); + this.historyPointer = -1; + this.modifiedOriginalImage = false; + this.undo = ImageHistory.undo.bind(this); + this.redo = ImageHistory.redo.bind(this); + this.add = ImageHistory.add.bind(this); + this.addLinsteners = ImageHistory.addLinsteners.bind(this); + this.addLinsteners(); + this.operationMade = ImageHistory.operationMade.bind(this); + this.onFakeImageLoad = ImageHistory.onFakeImageLoad.bind(this); + this.enable = ImageHistory.enable.bind(this); + this.disable = ImageHistory.disable.bind(this); + }, + + undo: function() { + if(this.historyPointer >= 1) { + image = $('image'); + fakeImage = $('fakeImg'); + operation = this.history[this.historyPointer].operation; + if(operation == 'rotate' || operation == 'crop') { + if(this.operationMade(this.historyPointer-1,'rotate') || this.operationMade(this.historyPointer-1,'crop')) + this.modifiedOriginalImage = true; else this.modifiedOriginalImage = false; + } + image.src = this.history[this.historyPointer-1].fileUrl; + fakeImage.src = this.history[this.historyPointer-1].fileUrl; + Event.observe('fakeImg','load',this.onFakeImageLoad); + this.historyPointer--; + } else { + alert("No more undo"); + } + }, + + redo: function() { + if(this.historyPointer < this.history.length-1) { + operation = this.history[this.historyPointer+1].operation; + if(operation == 'rotate' || operation == 'crop') this.modifiedOriginalImage = true; + $('image').src = this.history[this.historyPointer+1].fileUrl; + $('fakeImg').src = $('image').src; + Event.observe('fakeImg','load',this.onFakeImageLoad); + this.historyPointer++; + } else { + alert("No more redo"); + } + }, + + add: function(operation,url) { + this.historyPointer++; + this.history[this.historyPointer] = {'operation': operation,'fileUrl' : url}; + if(operation == 'rotate' || operation == 'crop') this.modifiedOriginalImage = true; + }, + + addLinsteners: function() { + this.undoListener = Event.observe('undoButton','click',this.undo); + this.redoListener = Event.observe('redoButton','click',this.redo); + }, + + operationMade: function(historyPointer,operation) { + for(i=historyPointer;i>=0;i--) { + if(this.history[i].operation == operation) { + return true; + } + } + return false; + }, + + onFakeImageLoad: function() { + $('imageContainer').style.width = fakeImage.width + 'px'; + $('imageContainer').style.height = fakeImage.height + 'px'; + resize.imageContainerResize.originalWidth = fakeImage.width; + resize.imageContainerResize.originalHeight = fakeImage.height; + resize.imageContainerResize.placeClickBox(); + }, + + enable: function() { + this.addLinsteners(); + }, + + disable: function() { + Event.stopObserving($('undoButton'),'click', this.undo); + Event.stopObserving($('redoButton'),'click', this.redo); + }, +}; \ No newline at end of file diff --git a/javascript/ImageEditor/ImageTransformation.js b/javascript/ImageEditor/ImageTransformation.js new file mode 100644 index 00000000..b84fdecb --- /dev/null +++ b/javascript/ImageEditor/ImageTransformation.js @@ -0,0 +1,79 @@ +/** + * @author Mateusz + */ +var ImageTransformation = { + initialize: function() { + this.resize = ImageTransformation.resize.bind(this); + this.rotate = ImageTransformation.rotate.bind(this); + this.crop = ImageTransformation.crop.bind(this); + this.save = ImageTransformation.save.bind(this); + }, + + resize: function(width,height) { + if(imageHistory.modifiedOriginalImage) { + fileToResize = $('image').src; + } else { + fileToResize = imageEditor.originalImageFile; + } + var options = { + method: 'post', + postBody: 'command=resize&file=' + fileToResize + '&newImageWidth=' + width + '&newImageHeight=' + height, + onSuccess: function(transport) { + imageBox.hideIndicator(); + response = eval('(' + transport.responseText + ')'); + $('image').src = response.fileName; + imageHistory.add('resize',$('image').src); + }, + }; + imageBox.showIndicator(); + new Ajax.Request('/admin/ImageEditor/manipulate', options); + }, + + rotate: function(angle) { + var options = { + method: 'post', + postBody: 'command=rotate&file=' + $('image').src + '&angle=' + angle , + onSuccess: function(transport) { + imageBox.hideIndicator(); + response = eval('(' + transport.responseText + ')'); + $('image').src = response.fileName; + $('imageContainer').style.width = response.width + 'px'; + $('imageContainer').style.height = response.height + 'px'; + imageHistory.add('rotate',$('image').src); + resize.imageContainerResize.placeClickBox(); + } + }; + imageBox.showIndicator(); + new Ajax.Request('/admin/ImageEditor/manipulate', options); + }, + + crop: function(top,left,width,height) { + var options = { + method: 'post', + postBody: 'command=crop&file=' + $('image').src + '&top=' + top + '&left=' + left + '&width=' + width + '&height=' + height, + onSuccess: function(transport) { + imageBox.hideIndicator(); + response = eval('(' + transport.responseText + ')'); + $('image').src = response.fileName; + $('imageContainer').style.width = response.width + 'px'; + $('imageContainer').style.height = response.height + 'px'; + imageHistory.add('crop',$('image').src); + crop.setVisible(false); + }, + }; + imageBox.showIndicator(); + new Ajax.Request('/admin/ImageEditor/manipulate', options); + }, + + save: function(originalFile,editedFile) { + var options = { + method: 'post', + postBody: 'command=save&editedFile=' + editedFile + '&originalFile=' + originalFile, + onSuccess: function(transport) { + imageEditor.onClose(); + }, + }; + new Ajax.Request('/admin/ImageEditor/save', options); + } +} + diff --git a/javascript/ImageEditor/Require.js b/javascript/ImageEditor/Require.js new file mode 100644 index 00000000..17f8318e --- /dev/null +++ b/javascript/ImageEditor/Require.js @@ -0,0 +1,3 @@ +/** + * @author Mateusz + */ diff --git a/javascript/ImageEditor/Resize.js b/javascript/ImageEditor/Resize.js new file mode 100644 index 00000000..baed4ab9 --- /dev/null +++ b/javascript/ImageEditor/Resize.js @@ -0,0 +1,60 @@ +/** + * @author Mateusz + */ +var Resize = { + + initialize: function(element) { + this.element = element; + this.leftBoxConstraint = 20; + this.topBoxConstraint = 100; + this.getRelativeMousePos = Resize.getRelativeMousePos.bind(this); + options = { + resizeStop: Resize.resizeStop.bind(this), + onDrag: Resize.onDrag.bind(this), + onResize: Resize.onResize, + getMousePos: Resize.getMousePos.bind(this) + }; + new Positioning.addBehaviour(this.element); + this.imageContainerResize = new Resizeable.initialize(element,options); + this.imageContainerResize.setVisible(true); + }, + + resizeStop: function(event) { + if(EventStack.getLastEvent() != null) { + imageElement = $('image'); + EventStack.clearStack(); + if(this.imageContainerResize.originalWidth != imageElement.width || this.imageContainerResize.originalHeight != imageElement.height) { + imageTransformation.resize(imageElement.width,imageElement.height); + } + } + }, + + onDrag: function() + { + if(this.element.getTop() < this.topBoxConstraint) this.element.style.top = this.topBoxConstraint + "px"; + if(this.element.getLeft() < this.leftBoxConstraint) this.element.style.left = this.leftBoxConstraint + "px"; + if(this.element.getTop() + this.element.getHeight() >= this.element.getParentHeight()) this.element.style.top = this.element.getParentHeight() - this.element.getHeight() - 3 + 'px'; + if(this.element.getLeft() + this.element.getWidth() > this.element.getParentWidth()) this.element.style.left = this.element.getParentWidth() - this.element.getWidth() - 3 + 'px'; + imageBox.reCenterIndicator(); + }, + + onResize: function() { + }, + getMousePos: function(event) { + relativeMouseX = this.getRelativeMousePos(event).x; + relativeMouseY = this.getRelativeMousePos(event).y; + if(relativeMouseX <= this.leftBoxConstraint) x = this.leftBoxConstraint + this.element.getParentLeft(); else x = relativeMouseX + this.element.getParentLeft(); + if(relativeMouseY <= this.topBoxConstraint) y = this.topBoxConstraint + this.element.getParentTop(); else y = relativeMouseY + this.element.getParentTop(); + if(relativeMouseX >= this.element.getParentWidth()) { + x = this.element.getParentLeft() + this.element.getParentWidth(); + } + if(relativeMouseY >= this.element.getParentHeight()) y = this.element.getParentTop() + this.element.getParentHeight(); + return {x: x,y: y}; + }, + + getRelativeMousePos: function(event) { + relativeMouseX = Event.pointerX(event) - this.element.getParentLeft(); + relativeMouseY = Event.pointerY(event) - this.element.getParentTop(); + return {x: relativeMouseX,y: relativeMouseY}; + } +} \ No newline at end of file diff --git a/javascript/ImageEditor/Resizeable.js b/javascript/ImageEditor/Resizeable.js new file mode 100644 index 00000000..b174b83d --- /dev/null +++ b/javascript/ImageEditor/Resizeable.js @@ -0,0 +1,278 @@ +/** + * @author Mateusz + */ +Resizeable = { + + initialize: function(element,options) { + this.resizeStop = options.resizeStop.bind(this); + this.onDrag = options.onDrag.bind(this); + this.customOnResize = options.onResize.bind(this); + this.getMousePos = options.getMousePos.bind(this); + this.bindAll = Resizeable.bindAll.bind(this); + this.bindAll(); + this.element = element; + this.createClickBoxes(); + this.setListeners(); + this.placeClickBoxOnImageLoad(); + this.originalHeight = 0; + this.originalWidth = 0; + }, + + resizeStart: function(event) { + EventStack.addEvent(event); + Event.stop(event); + }, + + leftUpperDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newWidth = left - relativeMouseX + width; + newHeight = top - relativeMouseY + height; + if(this.resize(newWidth,newHeight)) { + this.element.style.top = top - (newHeight - height) + "px"; + this.element.style.left = left - (newWidth - width) + "px"; + } + }, + + leftMiddleDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newWidth = left - relativeMouseX + width; + if(this.resize(newWidth,-1000)) this.element.style.left = left - (left - relativeMouseX) + "px"; + }, + + leftLowerDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newWidth = left - relativeMouseX + width; + newHeight = relativeMouseY - (top + height) + height; + if(this.resize(newWidth,newHeight)) this.element.style.left = left - (left - relativeMouseX) + "px"; + }, + + rightUpperDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newWidth = relativeMouseX - left - width + width; + newHeight = top - relativeMouseY + height; + if(this.resize(newWidth,newHeight)) this.element.style.top = (top - (newHeight - height) ) + 'px'; + }, + + rightMiddleDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newWidth = relativeMouseX - left; + this.resize(newWidth,-1000); + }, + + rightLowerDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newWidth = relativeMouseX - left; + newHeight = relativeMouseY - top; + this.resize(newWidth,newHeight); + }, + + upperMiddleDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newHeight = top - relativeMouseY + height; + if(this.resize(-1000,newHeight)) { + this.element.style.top = (top - (newHeight - height)) + 'px'; + } + }, + + lowerMiddleDrag: function(event,top,left,height,width,parentTop,parentLeft,relativeMouseX,relativeMouseY) { + newHeight = relativeMouseY - (top + height) + height; + this.resize(-1000,newHeight); + }, + + onResize: function(event) { + if(EventStack.getLastEvent() != null && this.isVisible) { + lastEventElement = Event.element(EventStack.getLastEvent()); + var relativeMouseX = this.getMousePos(event).x - this.element.getParentLeft(); + var relativeMouseY = this.getMousePos(event).y - this.element.getParentTop(); + if(Element.hasClassName(lastEventElement,'leftUpperClickBox')) { + this.leftUpperDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + if(Element.hasClassName(lastEventElement,'leftMiddleClickBox')) { + this.leftMiddleDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + if(Element.hasClassName(lastEventElement,'leftLowerClickBox')) { + this.leftLowerDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + if(Element.hasClassName(lastEventElement,'rightUpperClickBox')) { + this.rightUpperDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + if(Element.hasClassName(lastEventElement,'rightMiddleClickBox')) { + this.rightMiddleDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + if(Element.hasClassName(lastEventElement,'rightLowerClickBox')) { + this.rightLowerDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + if(Element.hasClassName(lastEventElement,'upperMiddleClickBox')) { + this.upperMiddleDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + if(Element.hasClassName(lastEventElement,'lowerMiddleClickBox')) { + this.lowerMiddleDrag(event,this.element.getTop(),this.element.getLeft(),this.element.getHeight(),this.element.getWidth(),this.element.getParentTop(),this.element.getParentLeft(),relativeMouseX,relativeMouseY); + } + this.placeClickBox(); + imageBox.reCenterIndicator(); + this.customOnResize(); + } + }, + + resize: function(width,height) { + if(width < 30 && height == -1000) { + return false; + } + if(height < 30 && width == -1000) { + return false; + } + if((width < 30 || height < 30) && (width != -1000 && height != -1000)) { + return false; + } + if(width != -1000) { + this.element.style.width = width + "px"; + } else { + this.element.style.width = this.originalWidth + "px"; + } + if(height != -1000) { + this.element.style.height = height + "px"; + } else { + this.element.style.height = this.originalHeight + "px"; + } + return true; + }, + + placeClickBoxOnImageLoad: function() { + Event.observe('image','load',this.placeClickBox); + }, + + placeClickBox: function(event) { + if(event != null) { + this.originalHeight = Element.getDimensions(this.element).height; + this.originalWidth = Element.getDimensions(this.element).width; + } + width = Element.getDimensions(this.element).width; + height = Element.getDimensions(this.element).height; + + clickBoxHalfWidth = Math.floor(Element.getDimensions(this.leftUpperClickBox).width/2); + + leftUpper = new Point.initialize(-clickBoxHalfWidth,-clickBoxHalfWidth); + leftMiddle = new Point.initialize(-clickBoxHalfWidth,height/2-clickBoxHalfWidth); + leftLower = new Point.initialize(-clickBoxHalfWidth,height-clickBoxHalfWidth); + rightUpper = new Point.initialize(width-clickBoxHalfWidth,-clickBoxHalfWidth); + rightMiddle = new Point.initialize(width-clickBoxHalfWidth,height/2-clickBoxHalfWidth); + rightLower = new Point.initialize(width-clickBoxHalfWidth,height-clickBoxHalfWidth); + upperMiddle = new Point.initialize(width/2-clickBoxHalfWidth,-clickBoxHalfWidth); + lowerMiddle = new Point.initialize(width/2-clickBoxHalfWidth,height-clickBoxHalfWidth); + + this.leftUpperClickBox.style.left = leftUpper.x + 'px'; + this.leftUpperClickBox.style.top = leftUpper.y + 'px'; + this.leftMiddleClickBox.style.left = leftMiddle.x + 'px'; + this.leftMiddleClickBox.style.top = leftMiddle.y + 'px'; + this.leftLowerClickBox.style.left = leftLower.x + 'px'; + this.leftLowerClickBox.style.top = leftLower.y + 'px'; + + this.rightUpperClickBox.style.left = rightUpper.x + 'px'; + this.rightUpperClickBox.style.top = rightUpper.y + 'px'; + this.rightMiddleClickBox.style.left = rightMiddle.x + 'px'; + this.rightMiddleClickBox.style.top = rightMiddle.y + 'px'; + this.rightLowerClickBox.style.left = rightLower.x + 'px'; + this.rightLowerClickBox.style.top = rightLower.y + 'px'; + + this.upperMiddleClickBox.style.left = upperMiddle.x + 'px'; + this.upperMiddleClickBox.style.top = upperMiddle.y + 'px'; + this.lowerMiddleClickBox.style.left = lowerMiddle.x + 'px'; + this.lowerMiddleClickBox.style.top = lowerMiddle.y + 'px'; + }, + + createClickBoxes: function() { + this.leftUpperClickBox = this.createElement('div',Math.random(),["leftUpperClickBox","clickBox"]); + this.leftMiddleClickBox = this.createElement('div',Math.random(),["leftMiddleClickBox","clickBox"]); + this.leftLowerClickBox = this.createElement('div',Math.random(),["leftLowerClickBox","clickBox"]); + this.rightUpperClickBox = this.createElement('div',Math.random(),["rightUpperClickBox","clickBox"]); + this.rightMiddleClickBox = this.createElement('div',Math.random(),["rightMiddleClickBox","clickBox"]); + this.rightLowerClickBox = this.createElement('div',Math.random(),["rightLowerClickBox","clickBox"]); + this.upperMiddleClickBox = this.createElement('div',Math.random(),["upperMiddleClickBox","clickBox"]); + this.lowerMiddleClickBox = this.createElement('div',Math.random(),["lowerMiddleClickBox","clickBox"]); + }, + + createElement: function(tag,id,classes) { + newElement = document.createElement(tag); + newElement.id = id; + classes.each(function(item) { + Element.addClassName(newElement,item); + } + ); + this.addListener(newElement); + this.element.appendChild(newElement); + return newElement; + }, + + bindAll: function() { + this.setListeners = Resizeable.setListeners.bind(this); + this.placeClickBox = Resizeable.placeClickBox.bind(this); + this.resizeStart = Resizeable.resizeStart.bind(this); + this.onResize = Resizeable.onResize.bind(this); + this.resize = Resizeable.resize.bind(this); + this.placeClickBoxOnImageLoad = Resizeable.placeClickBoxOnImageLoad.bind(this); + this.createClickBoxes = Resizeable.createClickBoxes.bind(this); + this.createElement = Resizeable.createElement.bind(this); + this.addListener = Resizeable.addListener.bind(this); + this.addDraging = Resizeable.addDraging.bind(this); + this.setVisible = Resizeable.setVisible.bind(this); + this.removeDraging = Resizeable.removeDraging.bind(this); + + this.leftUpperDrag = Resizeable.leftUpperDrag.bind(this); + this.leftMiddleDrag = Resizeable.leftMiddleDrag.bind(this); + this.leftLowerDrag = Resizeable.leftLowerDrag.bind(this); + this.rightUpperDrag = Resizeable.rightUpperDrag.bind(this); + this.rightMiddleDrag = Resizeable.rightMiddleDrag.bind(this); + this.rightLowerDrag = Resizeable.rightLowerDrag.bind(this); + this.upperMiddleDrag = Resizeable.upperMiddleDrag.bind(this); + this.lowerMiddleDrag = Resizeable.lowerMiddleDrag.bind(this); + }, + + setListeners: function() { + Event.observe('mainContainer','mousemove',this.onResize); + Event.observe('mainContainer','mouseup',this.resizeStop); + }, + + addListener: function(element) { + Event.observe(element,'mousedown',this.resizeStart); + Event.observe(element,'mousemove',this.onResize); + + }, + + addDraging: function() { + if(this.draggableImage) this.removeDraging(); + var options = { + starteffect: function() {}, + endeffect: function() {}, + change: this.onDrag, + }; + this.draggableImage = new Draggable(this.element,options); + }, + + removeDraging: function() { + if(this.draggableImage) { + this.draggableImage.destroy(); + this.draggableImage = null; + } + }, + + setVisible: function(setVisible) { + this.isVisible = setVisible; + if(setVisible) { + Element.show( + this.leftUpperClickBox, + this.leftMiddleClickBox, + this.leftLowerClickBox, + this.rightUpperClickBox, + this.rightMiddleClickBox, + this.rightLowerClickBox, + this.upperMiddleClickBox, + this.lowerMiddleClickBox); + this.addDraging(); + this.placeClickBox(); + } else { + Element.hide( + this.leftUpperClickBox, + this.leftMiddleClickBox, + this.leftLowerClickBox, + this.rightUpperClickBox, + this.rightMiddleClickBox, + this.rightLowerClickBox, + this.upperMiddleClickBox, + this.lowerMiddleClickBox); + this.removeDraging(); + } + } +} \ No newline at end of file diff --git a/javascript/ImageEditor/Utils.js b/javascript/ImageEditor/Utils.js new file mode 100644 index 00000000..502fd9d7 --- /dev/null +++ b/javascript/ImageEditor/Utils.js @@ -0,0 +1,72 @@ +/** + * @author Mateusz + */ +Point = { + initialize: function(x,y) { + this.x = x; + this.y = y; + } +} + +EventStack = { + lastEvent: null, + getLastEvent: function(){ + return EventStack.lastEvent + }, + + addEvent: function(event) { + EventStack.lastEvent = event; + }, + + clearStack: function() { + this.lastEvent = null; + } +} + +Positioning = { + addBehaviour: function(element) { + this.element = element; + this.element.getTop = Positioning.getTop.bind(this); + this.element.getLeft = Positioning.getLeft.bind(this); + this.element.getWidth = Positioning.getWidth.bind(this); + this.element.getHeight = Positioning.getHeight.bind(this); + this.element.getParentLeft = Positioning.getParentLeft.bind(this); + this.element.getParentTop = Positioning.getParentTop.bind(this); + this.element.getParentHeight = Positioning.getParentHeight.bind(this); + this.element.getParentWidth = Positioning.getParentWidth.bind(this); + }, + + getTop: function() { + return Position.positionedOffset(this.element)[1]; + }, + + getLeft: function() { + return Position.positionedOffset(this.element)[0]; + }, + + getWidth: function() { + return Element.getDimensions(this.element).width; + }, + + getHeight: function() { + return Element.getDimensions(this.element).height; + }, + + getParentLeft: function() { + parentLeft = Position.cumulativeOffset(Position.offsetParent(this.element))[0]; + return parentLeft; + }, + + getParentTop: function() { + parentTop = Position.cumulativeOffset(Position.offsetParent(this.element))[1]; + return parentTop; + }, + + getParentHeight: function() { + return Element.getDimensions(Position.offsetParent(this.element)).height; + }, + + getParentWidth: function() { + return Element.getDimensions(Position.offsetParent(this.element)).width + } +} \ No newline at end of file diff --git a/templates/ImageEditor.ss b/templates/ImageEditor.ss new file mode 100644 index 00000000..913df107 --- /dev/null +++ b/templates/ImageEditor.ss @@ -0,0 +1,53 @@ + + + + + <% base_tag %> + Untitled Document + + + +
+ +
+
+
+
+
+
+ We have encountered an error +
+
+
+ indicator +
+
+
+
+ fakeImg +
+ + + \ No newline at end of file