diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..551688d --- /dev/null +++ b/Readme.md @@ -0,0 +1,24 @@ +### Simple Image Crop plugin for CKEditor + +#### Config for django-ckeditor-upload + + + { + 'default': { + 'toolbar': 'full', + 'extraPlugins': 'imagecrop', + 'allowedContent': True, + 'cropperCssUrl': 'https://cdnjs.cloudflare.com/ajax/libs/cropperjs/0.8.1/cropper.min.css', + 'cropperJsUrl': 'https://cdnjs.cloudflare.com/ajax/libs/cropperjs/0.8.1/cropper.min.js', + 'cropperOption': { + 'aspectRatio': 16 / 9, + 'autoCropArea': 1, + 'cropBoxResizable': False, + 'dragMode': 'move', + 'background': False + }, + 'resultOption': { + 'width': 300 + } + } + } diff --git a/dialogs/imagecrop.js b/dialogs/imagecrop.js new file mode 100644 index 0000000..e05891a --- /dev/null +++ b/dialogs/imagecrop.js @@ -0,0 +1,155 @@ +CKEDITOR.dialog.add('cropDialog', function (editor) { + var cropper, + imageType = 'image/jpeg', + width = parseInt(window.innerWidth * 80 / 100), + height = parseInt(window.innerHeight * 80 / 100), + options = editor.config.cropperOption, + uploadOnChange = function (e) { + var URL = window.URL || window.webkitURL, + blobURL, + file = e.target.files[0], + canvas = CKEDITOR.document.getById('img').$; + + if (!cropper) + cropper = new Cropper(canvas, options); + + if (/^image\/\w+/.test(file.type)) { + blobURL = URL.createObjectURL(file); + cropper.reset().replace(blobURL); + } else { + window.alert(editor.lang.imagecrop.wrongImageType); + } + }, + ref = CKEDITOR.tools.addFunction(function (url) { + var dialog = editor._.filebrowserSe.getDialog(), + abbr = dialog.element; + + abbr.setAttribute('src', url); + abbr.setAttribute('data-cke-saved-src', url); + dialog.commitContent(abbr); + if (dialog.insertMode) + editor.insertElement(abbr); + }); + + if (!HTMLCanvasElement.prototype.toBlob) { + Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', { + value: function (callback, type, quality) { + + var binStr = atob(this.toDataURL(type, quality).split(',')[1]), + len = binStr.length, + arr = new Uint8Array(len); + + for (var i = 0; i < len; i++) { + arr[i] = binStr.charCodeAt(i); + } + + callback(new Blob([arr], {type: type || imageType})); + } + }); + } + + return { + title: editor.lang.imagecrop.title, + width: width, + height: height, + contents: [ + { + id: 'base', + label: editor.lang.imagecrop.cropTab, + filebrowser: 'uploadButton', + elements: [ + { + type: 'hbox', + widths: ['80%', '20%'], + children: [ + { + type: 'html', + html: '', + id: 'img', + label: editor.lang.common.image, + style: 'width: 100%; height: ' + parseInt(window.innerHeight * 80 / 100) + 'px; border-color:#CECECE', + setup: function(element) { + cropper.reset().replace(element.getAttribute('src')); + } + }, + { + type: 'vbox', + align: 'right', + children: [ + { + type: 'file', + id: 'upload', + label: editor.lang.common.browseServer, + onClick: function (e) { + e.sender.$.removeEventListener('change', uploadOnChange, false); + e.sender.$.addEventListener('change', uploadOnChange, false); + } + }, { + type: 'fileButton', + style: 'display: none', + id: 'uploadButton', + label: editor.lang.imagecrop.btnUpload, + for: ['base', 'upload'], + filebrowser: { + action: 'QuickUpload' + }, + onClick: function () { + var dialog = this.getDialog(), + form = dialog.getContentElement('base', 'upload').getInputElement().$.form, + fileName = dialog.getContentElement('base', 'upload').getInputElement().$.value.replace(/^.*[\\\/]/, '') || 'upload.jpg', + formData, + xhr = new XMLHttpRequest(); + + editor._.filebrowserSe = this; + + xhr.onreadystatechange = function (response) { + if (xhr.readyState == 4 && xhr.status == 200) { + form.ownerDocument.write(response.target.responseText); + cropper.destroy(); + CKEDITOR.document.getById('img').$.removeAttribute('src'); + } + }; + + if (form) { + cropper.getCroppedCanvas(editor.config.resultOption).toBlob(function (blob) { + formData = new FormData(); + formData.append('upload', blob, fileName); + xhr.open('POST', (form.action + '&CKEditorFuncNum=' + ref), true); // todo + xhr.send(formData); + }); + } + return false; + } + } + ] + } + ] + } + ] + } + ], + onShow: function () { + var selection = editor.getSelection(); + var element = selection.getStartElement(); + + if (element) + element = element.getAscendant('img', true); + + if (!element || element.getName() != 'img') { + element = editor.document.createElement('img'); + this.insertMode = true; + } + else + this.insertMode = false; + + this.element = element; + if (!this.insertMode) + this.setupContent(this.element); + }, + onOk: function () { + var dialog = this, + uploadButton = dialog.getContentElement('base', 'uploadButton'); + uploadButton.click(); + } + } +}); diff --git a/icons/imagecrop.png b/icons/imagecrop.png new file mode 100644 index 0000000..1a42b65 Binary files /dev/null and b/icons/imagecrop.png differ diff --git a/lang/en.js b/lang/en.js new file mode 100644 index 0000000..439bda2 --- /dev/null +++ b/lang/en.js @@ -0,0 +1,6 @@ +CKEDITOR.plugins.setLang('imagecrop', 'en', { + cropTab: 'Crop Image', + title: 'Crop Image', + btnUpload: 'Send it to the Server', + wrongImageType: 'Please choose an image file.' +}); diff --git a/plugin.js b/plugin.js new file mode 100644 index 0000000..5de94cf --- /dev/null +++ b/plugin.js @@ -0,0 +1,46 @@ +/** + * Created by anna on 25.08.16. + * + * @fileOverview The Image Crop plugin. + */ + +CKEDITOR.plugins.add('imagecrop', { + requires: 'dialog', + icons: 'imagecrop', + lang: 'en', + init: function (editor) { + var pluginDirectory = this.path, + style = document.createElement('link'); + + editor.addCommand('imagecrop', new CKEDITOR.dialogCommand('cropDialog')); + + style.type = 'text/css'; + style.rel = 'stylesheet'; + style.href = editor.config.cropperCssUrl; + document.getElementsByTagName("head")[0].appendChild(style); + + CKEDITOR.scriptLoader.load(editor.config.cropperJsUrl); + editor.ui.addButton('Crop', { + label: editor.lang.imagecrop.title, + command: 'imagecrop', + toolbar: 'insert' + }); + + if (editor.contextMenu) { + editor.addMenuGroup('cropGroup'); + editor.addMenuItem('cropItem', { + label: 'Edit Image', + icon: this.path + 'icons/imagecrop.png', + command: 'imagecrop', + group: 'cropGroup' + }); + editor.contextMenu.addListener(function (element) { + if (element.getAscendant('img', true)) { + return {cropItem: CKEDITOR.TRISTATE_OFF}; + } + }); + } + + CKEDITOR.dialog.add('cropDialog', pluginDirectory + 'dialogs/imagecrop.js'); + } +});