editor.js/plugins/image/image.js

701 lines
19 KiB
JavaScript
Raw Normal View History

/**
2017-01-26 00:41:04 +01:00
* Image plugin for codex-editor
* @author CodeX Team <team@ifmo.su>
*
* @version 1.3.0
2017-01-26 00:41:04 +01:00
*/
var image = (function(image_plugin) {
2017-01-26 00:41:04 +01:00
/**
* @private
*
* CSS classNames
*/
var elementClasses_ = {
ce_image : 'ce-image',
loading : 'ce-plugin-image__loader',
blockStretched: 'ce-block--stretched',
uploadedImage : {
2017-01-26 00:41:04 +01:00
centered : 'ce-plugin-image__uploaded--centered',
stretched : 'ce-plugin-image__uploaded--stretched'
},
imageCaption : 'ce-plugin-image__caption',
imageWrapper : 'ce-plugin-image__wrapper',
formHolder : 'ce-plugin-image__holder',
2017-01-26 00:41:04 +01:00
uploadButton : 'ce-plugin-image__button',
imagePreview : 'ce-image__preview',
selectorHolder: 'ce-settings-checkbox',
selectorButton: 'ce-settings-checkbox__toggler',
settingsItem: 'ce-image-settings__item',
imageWrapperBordered : 'ce-image__wrapper--bordered',
toggled : 'ce-image-settings__item--toggled'
2017-01-26 00:41:04 +01:00
};
2017-01-26 00:41:04 +01:00
/**
*
* @private
*
* UI methods
*/
var ui_ = {
holder : function(){
var element = document.createElement('DIV');
2017-01-26 00:41:04 +01:00
element.classList.add(elementClasses_.formHolder);
element.classList.add(elementClasses_.ce_image);
return element;
},
uploadButton : function(){
var button = document.createElement('SPAN');
2017-01-26 00:41:04 +01:00
button.classList.add(elementClasses_.uploadButton);
button.innerHTML = '<i class="ce-icon-picture"> </i>';
button.innerHTML += 'Загрузить фотографию';
return button;
},
/**
2017-01-26 00:41:04 +01:00
* @param {object} file - file path
* @param {string} style - css class
* @return {object} image - document IMG tag
*/
image : function(file, styles) {
var image = document.createElement('IMG');
styles.map(function(item) {
image.classList.add(item);
});
2017-01-26 00:41:04 +01:00
image.src = file.url;
image.dataset.bigUrl = file.bigUrl;
return image;
},
wrapper : function() {
var div = document.createElement('div');
2017-01-26 00:41:04 +01:00
div.classList.add(elementClasses_.imageWrapper);
return div;
},
caption : function() {
var div = document.createElement('div');
2017-01-26 00:41:04 +01:00
div.classList.add(elementClasses_.imageCaption);
div.contentEditable = true;
return div;
},
/**
* Draws form for image upload
*/
makeForm : function() {
2017-01-26 00:41:04 +01:00
var holder = ui_.holder(),
uploadButton = ui_.uploadButton();
holder.appendChild(uploadButton);
2017-01-26 00:41:04 +01:00
uploadButton.addEventListener('click', uploadButtonClicked_, false );
2017-01-26 00:41:04 +01:00
image.holder = holder;
return holder;
},
/**
* wraps image and caption
* @param {object} data - image information
* @param {string} imageTypeClass - plugin's style
* @param {boolean} stretched - stretched or not
* @return wrapped block with image and caption
*/
makeImage : function(data, imageTypeClasses, stretched, bordered) {
var file = data,
text = data.caption,
type = data.type,
image = ui_.image(file, imageTypeClasses),
2017-01-26 00:41:04 +01:00
caption = ui_.caption(),
wrapper = ui_.wrapper();
2017-01-31 13:20:09 +01:00
caption.innerHTML = text || '';
wrapper.dataset.stretched = stretched;
wrapper.dataset.bordered = bordered;
/** Appeding to the wrapper */
wrapper.appendChild(image);
wrapper.appendChild(caption);
return wrapper;
},
/**
* @param {HTML} data - Rendered block with image
*/
getImage : function(data) {
2017-01-26 00:41:04 +01:00
var image = data.querySelector('.' + elementClasses_.uploadedImage.centered) ||
data.querySelector('.' + elementClasses_.uploadedImage.stretched);
return image;
},
/**
* wraps image and caption
* @deprecated
* @param {object} data - image information
* @return wrapped block with image and caption
*/
centeredImage : function(data) {
2017-01-26 00:41:04 +01:00
var file = data.file,
text = data.caption,
type = data.type,
2017-01-26 00:41:04 +01:00
image = ui_.image(file, elementClasses_.uploadedImage.centered),
caption = ui_.caption(),
wrapper = ui_.wrapper();
caption.textContent = text;
wrapper.dataset.stretched = 'false';
/** Appeding to the wrapper */
wrapper.appendChild(image);
wrapper.appendChild(caption);
return wrapper;
},
/**
* wraps image and caption
* @deprecated
* @param {object} data - image information
* @return stretched image
*/
stretchedImage : function(data) {
2017-01-26 00:41:04 +01:00
var file = data.file,
text = data.caption,
type = data.type,
2017-01-26 00:41:04 +01:00
image = ui_.image(file, elementClasses_.uploadedImage.stretched),
caption = ui_.caption(),
wrapper = ui_.wrapper();
caption.textContent = text;
wrapper.dataset.stretched = 'true';
2017-01-26 00:41:04 +01:00
/** Appeding to the wrapper */
wrapper.appendChild(image);
wrapper.appendChild(caption);
return wrapper;
}
2017-01-26 00:41:04 +01:00
};
2017-01-26 00:41:04 +01:00
/**
* @private
*
* After render callback
*/
var uploadButtonClicked_ = function(event) {
var url = image_plugin.config.uploadImage,
beforeSend = uploadingCallbacks_.ByClick.beforeSend,
2017-01-26 01:10:36 +01:00
success = uploadingCallbacks_.ByClick.success,
error = uploadingCallbacks_.ByClick.error;
2017-01-26 00:41:04 +01:00
/** Define callbacks */
codex.editor.transport.selectAndUpload({
url : url,
multiple : false,
accept : 'image/*',
beforeSend : beforeSend,
success : success,
error : error
2017-01-26 00:41:04 +01:00
});
};
2017-01-26 00:41:04 +01:00
var methods_ = {
addSelectTypeClickListener : function(el, type) {
el.addEventListener('click', function() {
// el - settings element
switch (type) {
case 'bordered':
methods_.toggleBordered(type, this); break;
case 'stretched':
methods_.toggleStretched(type, this); break;
}
}, false);
},
toggleBordered : function(type, clickedSettingsItem ) {
var current = codex.editor.content.currentNode,
blockContent = current.childNodes[0],
img = ui_.getImage(current),
2017-01-26 00:41:04 +01:00
wrapper = current.querySelector('.' + elementClasses_.imageWrapper);
if (!img) {
2017-01-26 00:41:04 +01:00
return;
}
/**
* Add classes to the IMG tag and to the Settings element
*/
img.classList.toggle(elementClasses_.imageWrapperBordered);
clickedSettingsItem.classList.toggle(elementClasses_.toggled);
2017-01-26 00:41:04 +01:00
/**
* Save settings in dataset
*/
wrapper.dataset.bordered = img.classList.contains(elementClasses_.imageWrapperBordered);
setTimeout(function() {
codex.editor.toolbar.settings.close();
}, 200);
},
toggleStretched : function( type, clickedSettingsItem ) {
var current = codex.editor.content.currentNode,
blockContent = current.childNodes[0],
img = ui_.getImage(current),
wrapper = current.querySelector('.' + elementClasses_.imageWrapper);
if (!img) {
return;
}
/** Clear classList */
blockContent.classList.add(elementClasses_.blockStretched);
img.classList.toggle(elementClasses_.uploadedImage.stretched);
img.classList.toggle(elementClasses_.uploadedImage.centered);
clickedSettingsItem.classList.toggle(elementClasses_.toggled);
wrapper.dataset.stretched = img.classList.contains(elementClasses_.uploadedImage.stretched);
2017-01-26 00:41:04 +01:00
setTimeout(function() {
codex.editor.toolbar.settings.close();
}, 1000);
}
};
2017-01-26 00:41:04 +01:00
/**
* @private
* Callbacks
*/
var uploadingCallbacks_ = {
2017-01-26 00:41:04 +01:00
ByClick : {
/**
2017-01-26 00:41:04 +01:00
* Before sending ajax request
*/
2017-01-26 00:41:04 +01:00
beforeSend : function() {
var input = codex.editor.transport.input,
2017-01-26 00:41:04 +01:00
files = input.files;
2017-01-26 01:12:00 +01:00
var validFileExtensions = ["jpg", "jpeg", "bmp", "gif", "png"];
2017-01-26 00:41:04 +01:00
var type = files[0].type.split('/');
2017-01-26 01:12:00 +01:00
var result = validFileExtensions.some(function(ext) {
return ext == type[1];
2017-01-26 00:41:04 +01:00
});
if (!result) {
return;
}
var reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onload = function(e) {
var data = {
background : false,
border : false,
isstretch : false,
url : e.target.result,
bigUrl : null,
width : null,
height : null,
additionalData : null,
2017-01-26 00:41:04 +01:00
caption : '',
cover : null
};
2017-01-26 01:10:36 +01:00
var newImage = make_(data);
2017-01-26 00:41:04 +01:00
2017-04-25 17:05:05 +02:00
codex.editor.content.switchBlock(image.holder, newImage, 'image');
2017-01-26 01:10:36 +01:00
newImage.classList.add(elementClasses_.imagePreview);
2017-01-26 00:41:04 +01:00
/**
* Change holder to image
*/
2017-01-26 01:10:36 +01:00
image.holder = newImage;
2017-01-26 00:41:04 +01:00
};
},
/** Photo was uploaded successfully */
success : function(result) {
var parsed = JSON.parse(result),
data,
currentBlock = codex.editor.content.currentNode;
2017-01-26 00:41:04 +01:00
/**
* Preparing {Object} data to draw an image
* @uses ceImage.make method
*/
data = parsed.data;
image.holder.classList.remove(elementClasses_.imagePreview);
/**
* Change src of image
*/
2017-01-26 01:10:36 +01:00
var newImage = image.holder.getElementsByTagName('IMG')[0];
2017-01-26 00:41:04 +01:00
newImage.src = parsed.data.url;
newImage.dataset.bigUrl = parsed.data.bigUrl;
newImage.dataset.width = parsed.data.width;
newImage.dataset.height = parsed.data.height;
newImage.dataset.additionalData = parsed.data.additionalData;
2017-01-26 15:02:30 +01:00
2017-01-26 00:41:04 +01:00
},
/** Error callback. Sends notification to user that something happend or plugin doesn't supports method */
error : function(result) {
var oldHolder = image.holder;
var form = ui_.makeForm();
2017-04-25 17:05:05 +02:00
codex.editor.content.switchBlock(oldHolder, form, 'image');
2017-01-26 00:41:04 +01:00
}
},
ByPaste : {
/**
2017-01-26 00:41:04 +01:00
* Direct upload
* Any URL that contains image extension
* @param url
*/
2017-01-26 00:41:04 +01:00
uploadImageFromUrl : function(path) {
var image,
current = codex.editor.content.currentNode,
2017-01-26 00:41:04 +01:00
beforeSend,
success_callback;
/** When image is uploaded to redactors folder */
success_callback = function(data) {
var imageInfo = JSON.parse(data);
var newImage = image.getElementsByTagName('IMG')[0];
2017-01-26 15:02:30 +01:00
newImage.dataset.stretched = false;
newImage.dataset.src = imageInfo.url;
newImage.dataset.bigUrl = imageInfo.bigUrl;
newImage.dataset.width = imageInfo.width;
newImage.dataset.height = imageInfo.height;
newImage.dataset.additionalData = imageInfo.additionalData;
2017-01-26 00:41:04 +01:00
image.classList.remove(elementClasses_.imagePreview);
2017-01-26 00:41:04 +01:00
};
/** Before sending XMLHTTP request */
beforeSend = function() {
var content = current.querySelector('.ce-block__content');
var data = {
background: false,
border: false,
isStretch: false,
file: {
url: path,
bigUrl: null,
width: null,
height: null,
additionalData: null
},
caption: '',
cover: null
};
image = codex.editor.tools.image_extended.render(data);
2017-01-26 00:41:04 +01:00
image.classList.add(elementClasses_.imagePreview);
2017-01-26 00:41:04 +01:00
var img = image.querySelector('img');
2017-01-26 00:41:04 +01:00
2017-04-25 17:05:05 +02:00
codex.editor.content.switchBlock(codex.editor.content.currentNode, image, 'image');
2017-01-26 00:41:04 +01:00
};
/** Preparing data for XMLHTTP */
var data = {
url: image_plugin.config.uploadFromUrl,
2017-01-26 00:41:04 +01:00
type: "POST",
data : {
url: path
},
beforeSend : beforeSend,
success : success_callback
};
codex.editor.core.ajax(data);
2017-01-26 00:41:04 +01:00
}
}
};
2017-01-26 00:41:04 +01:00
/**
* Image path
* @type {null}
*/
image_plugin.path = null;
2017-01-26 00:41:04 +01:00
2017-01-26 13:56:37 +01:00
/**
2017-01-26 00:41:04 +01:00
* Plugin configuration
*/
image_plugin.config = null;
2017-01-26 00:41:04 +01:00
/**
*
* @private
*
* @param data
* @return {*}
*
*/
2017-01-26 00:41:04 +01:00
var make_ = function ( data ) {
var holder,
classes = [];
if (data) {
if (data.border) {
classes.push(elementClasses_.imageWrapperBordered);
}
2017-01-26 00:41:04 +01:00
if ( data.isstretch || data.isstretch === 'true') {
classes.push(elementClasses_.uploadedImage.stretched);
holder = ui_.makeImage(data, classes, 'true', data.border);
2017-01-26 00:41:04 +01:00
} else {
2017-01-26 00:41:04 +01:00
classes.push(elementClasses_.uploadedImage.centered);
holder = ui_.makeImage(data, classes, 'false', data.border);
2017-01-26 00:41:04 +01:00
}
2017-01-26 00:41:04 +01:00
return holder;
} else {
2017-01-26 00:41:04 +01:00
holder = ui_.makeForm();
2017-01-26 00:41:04 +01:00
return holder;
}
2017-01-26 00:41:04 +01:00
};
2017-01-26 01:22:53 +01:00
/**
* @private
*
* Prepare clear data before save
*
* @param data
*/
var prepareDataForSave_ = function(data) {
};
2017-01-26 00:41:04 +01:00
/**
* @public
* @param config
*/
image_plugin.prepare = function(config) {
image_plugin.config = config;
return Promise.resolve();
};
/**
2017-01-26 00:41:04 +01:00
* @public
*
* this tool works when tool is clicked in toolbox
*/
image_plugin.appendCallback = function(event) {
/** Upload image and call success callback*/
2017-01-26 00:41:04 +01:00
uploadButtonClicked_(event);
};
/**
* @public
*
* @param data
* @return {*}
*/
image_plugin.render = function( data ) {
2017-01-26 00:41:04 +01:00
return make_(data);
};
/**
* @public
*
* @param block
* @return {{background: boolean, border: boolean, isstretch: boolean, file: {url: (*|string|Object), bigUrl: (null|*), width: *, height: *, additionalData: null}, caption: (string|*|string), cover: null}}
*/
image_plugin.save = function ( block ) {
2017-01-26 00:41:04 +01:00
var content = block,
image = ui_.getImage(content),
caption = content.querySelector('.' + elementClasses_.imageCaption);
var data = {
background : false,
border : content.dataset.bordered === 'true' ? true : false,
2017-01-26 00:41:04 +01:00
isstretch : content.dataset.stretched === 'true' ? true : false,
// file : {
2017-01-26 15:02:30 +01:00
url : image.dataset.src || image.src,
2017-01-26 00:41:04 +01:00
bigUrl : image.dataset.bigUrl,
width : image.width,
height : image.height,
additionalData :null,
// },
caption : caption.innerHTML || '',
2017-01-26 00:41:04 +01:00
cover : null
};
2017-01-26 00:41:04 +01:00
return data;
};
/**
2017-01-26 00:41:04 +01:00
* @public
*
* Settings panel content
* @return {Element} element contains all settings
*/
image_plugin.makeSettings = function () {
var currentNode = codex.editor.content.currentNode,
wrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper),
holder = document.createElement('DIV'),
types = {
stretched : "На всю ширину",
bordered : "Добавить рамку"
},
currentImageWrapper = currentNode.querySelector('.' + elementClasses_.imageWrapper ),
currentImageSettings = currentImageWrapper.dataset;
/** Add holder classname */
holder.className = 'ce-image-settings';
/** Now add type selectors */
for (var type in types){
/**
* Settings template
*/
var settingsItem = document.createElement('DIV'),
selectorsHolder = document.createElement('SPAN'),
selectorsButton = document.createElement('SPAN');
settingsItem.classList.add(elementClasses_.settingsItem);
selectorsHolder.classList.add(elementClasses_.selectorHolder);
selectorsButton.classList.add(elementClasses_.selectorButton);
selectorsHolder.appendChild(selectorsButton);
settingsItem.appendChild(selectorsHolder);
selectTypeButton = document.createTextNode(types[type]);
settingsItem.appendChild(selectTypeButton);
/**
* Activate previously selected settings
*/
if ( currentImageSettings[type] == 'true' ){
settingsItem.classList.add(elementClasses_.toggled);
}
methods_.addSelectTypeClickListener(settingsItem, type);
holder.appendChild(settingsItem);
}
return holder;
};
2017-01-26 01:10:36 +01:00
/**
* Share as API
*/
image_plugin.uploadImageFromUri = uploadingCallbacks_.ByPaste.uploadImageFromUrl;
2017-01-26 01:10:36 +01:00
image_plugin.pastePatterns = [
{
type: 'image',
regex: /(?:([^:\/?#]+):)?(?:\/\/([^\/?#]*))?([^?#]*\.(?:jpe?g|gif|png))(?:\?([^#]*))?(?:#(.*))?/i,
callback: image_plugin.uploadImageFromUri
},
{
type: 'uploadCare',
regex: /^https:\/\/(uploadcare\.cmtt\.ru|ucarecdn\.com|static[0-9]+\.siliconrus\.cmtt\.ru|static[0-9]+\.cmtt\.ru)/i,
callback: image_plugin.uploadImageFromUri
} ];
image_plugin.destroy = function () {
image = null;
};
return image_plugin;
})({});