/*! * medium-editor-insert-plugin v0.3.2 - jQuery insert plugin for MediumEditor * * https://github.com/orthes/medium-editor-insert-plugin * * Copyright (c) 2014 Pavel Linkesch (http://linkesch.sk) * Released under the MIT license */ (function ($) { $.fn.mediumInsert.registerAddon('images', { /** * Images default options */ defaults: { /** * Active or inactive image's drag and drop */ useDragAndDrop: true, /** * Relative path to a script that handles file uploads */ imagesUploadScript: 'upload.php', /** * Relative path to a script that handles file deleting */ imagesDeleteScript: 'delete.php', /** * Placeeholder text for inserting link */ urlPlaceholder: 'Paste or type a link', /** * Format data before sending them to server while uploading an image * * @param {File} file File to upload * @return {object} formData FormData instance */ formatData: function (file) { var formData = new FormData(); formData.append('file', file); return formData; }, /** * Upload single file * * @param {element} $placeholder Placeholder to add image to * @param {File} file File to upload * @param {object} that Context * @param {void} */ uploadFile: function ($placeholder, file, that) { $.ajax({ type: "post", url: that.options.imagesUploadScript, xhr: function () { var xhr = new XMLHttpRequest(); xhr.upload.onprogress = that.updateProgressBar; return xhr; }, cache: false, contentType: false, complete: function (jqxhr) { that.uploadCompleted(jqxhr, $placeholder); }, processData: false, data: that.options.formatData(file) }); }, /** * Makes ajax call for deleting a file on a server * * @param {string} file File name * @param {object} that Context * @return {void} */ deleteFile: function (file, that) { $.ajax({ type: "post", url: that.options.imagesDeleteScript, data: { file: file } }); } }, /** * Images initial function * * @param {object} options Options to overide defaults * @return {void} */ init: function (options) { if (options && options.$el) { this.$el = options.$el; } this.options = $.extend(this.defaults, options); this.setImageEvents(); if (this.options.useDragAndDrop === true){ this.setDragAndDropEvents(); } this.preparePreviousImages(); }, /** * Returns insert button * * @param {string} buttonLabels * @return {string} */ insertButton: function(buttonLabels){ var label = 'Img'; if (buttonLabels === 'fontawesome' || typeof buttonLabels === 'object' && !!(buttonLabels.fontawesome)) { label = ''; } if (typeof buttonLabels === 'object' && buttonLabels.img) { label = buttonLabels.img; } return ''; }, /** * Make existing images interactive * * @return {void} */ preparePreviousImages: function () { this.$el.find('.mediumInsert-images').each(function() { var $parent = $(this).parent(); if (!$parent.hasClass('mediumInsert-placeholder')) { $parent.html($.fn.mediumInsert.insert.getButtons('images') + '
' + $parent.html() + '
' ); } }); }, /** * Add image to placeholder * * @param {element} $placeholder Placeholder to add image to * @return {element} $selectFile element */ add: function ($placeholder) { var that = this, $selectFile, files; $selectFile = $('').click(); $selectFile.change(function () { files = this.files; that.uploadFiles($placeholder, files, that); }); $.fn.mediumInsert.insert.deselect(); return $selectFile; }, /** * Update progressbar while upload * * @param {event} e XMLHttpRequest.upload.onprogress event * @return {void} */ updateProgressBar: function (e) { var $progress = $('.progress:first', this.$el), complete; if (e.lengthComputable) { complete = e.loaded / e.total * 100; complete = complete ? complete : 0; $progress.attr('value', complete); $progress.html(complete); } }, /** * Show uploaded image after upload completed * * @param {jqXHR} jqxhr jqXHR object * @return {void} */ uploadCompleted: function (jqxhr, $placeholder) { var $progress = $('.progress:first', $placeholder), $img; $progress.attr('value', 100); $progress.html(100); if (jqxhr.responseText) { $progress.before('
'); $img = $progress.siblings('img'); $img.load(function () { $img.parent().mouseleave().mouseenter(); }); } else { $progress.before('
There was a problem uploading the file.
'); setTimeout(function () { $('.mediumInsert-error:first', $placeholder).fadeOut(function () { $(this).remove(); }); }, 3000); } $progress.remove(); $placeholder.closest('[data-medium-element]').trigger('keyup').trigger('input'); }, /** * Upload single file * * @param {element} $placeholder Placeholder to add image to * @param {File} file File to upload * @param {object} that Context * @param {void} */ uploadFile: function ($placeholder, file, that) { return that.options.uploadFile($placeholder, file, that); }, /** * Lopp though files, check file types and call uploadFile() function on each file that passes * * @param {element} placeholder Placeholder to add image to * @param {FileList} files Files to upload * @param {object} that Context * @return {void} */ uploadFiles: function ($placeholder, files, that) { var acceptedTypes = { 'image/png': true, 'image/jpeg': true, 'image/gif': true }; for (var i = 0; i < files.length; i++) { var file = files[i]; if (acceptedTypes[file.type] === true) { $placeholder.append('0'); that.uploadFile($placeholder, file, that); } } }, /** * Makes ajax call for deleting a file on a server * * @param {string} file File name * @param {object} that Context * @return {void} */ deleteFile: function (file, that) { return that.options.deleteFile(file, that); }, /** * Set image events displaying remove and resize buttons * * @return {void} */ setImageEvents: function () { var that = this; this.$el.on('mouseenter', '.mediumInsert-images', function () { var $img = $('img', this), positionTop, positionLeft; if ($.fn.mediumInsert.settings.enabled === false) { return; } if ($img.length > 0) { $(this).append(''); if ($(this).prevAll().length === 0) { if ($(this).parent().parent().hasClass('small')) { $(this).append(''); } else { $(this).append(''); } } if ($(this).siblings().length === 0) { if ($img.parent().is('a')) { $(this).append(''); } else { $(this).append(''); } } positionTop = $img.position().top + parseInt($img.css('margin-top'), 10); positionLeft = $img.position().left + $img.width() -30; $('.mediumInsert-imageRemove', this).css({ 'right': 'auto', 'top': positionTop, 'left': positionLeft }); $('.mediumInsert-imageResizeBigger, .mediumInsert-imageResizeSmaller', this).css({ 'right': 'auto', 'top': positionTop, 'left': positionLeft-31 }); $('.mediumInsert-imageLink, .mediumInsert-imageUnlink', this).css({ 'right': 'auto', 'top': positionTop, 'left': positionLeft-62 }); } }); this.$el.on('mouseleave', '.mediumInsert-images', function () { $('.mediumInsert-imageIcon', this).remove(); }); this.$el.on('click', '.mediumInsert-imageResizeSmaller', function () { $(this).parent().parent().parent().addClass('small'); $(this).parent().mouseleave().mouseleave(); $.fn.mediumInsert.insert.deselect(); that.$el.trigger('keyup').trigger('input'); }); this.$el.on('click', '.mediumInsert-imageResizeBigger', function () { $(this).parent().parent().parent().removeClass('small'); $(this).parent().mouseleave().mouseleave(); $.fn.mediumInsert.insert.deselect(); that.$el.trigger('keyup').trigger('input'); }); this.$el.on('click', '.mediumInsert-imageRemove', function () { var img = $(this).siblings('img').attr('src'); if ($(this).parent().siblings().length === 0) { $(this).parent().parent().parent().removeClass('small'); } $(this).parent().remove(); that.deleteFile(img, that); $.fn.mediumInsert.insert.deselect(); that.$el.trigger('keyup').trigger('input'); }); this.$el.on('click', '.mediumInsert-imageLink', function () { var $placeholder = $(this).closest('.mediumInsert-placeholder'), $formHtml = $('
'); $formHtml.appendTo($placeholder); setTimeout(function () { $formHtml.find('input').focus(); }, 50); $.fn.mediumInsert.insert.deselect(); }); this.$el.on('click', '.mediumInsert-imageUnlink', function () { var $figure = $(this).closest('.mediumInsert-images'); $figure.find('img').unwrap(); $(this).removeClass('mediumInsert-imageUnlink') .addClass('mediumInsert-imageLink'); that.$el.trigger('keyup').trigger('input'); }); this.$el .on('keypress', '.mediumInsert-imageLinkText', function (e) { var $placeholder = $(this).closest('.mediumInsert-placeholder'); if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) { $placeholder.find('.mediumInsert-images:first').find('img').wrap(''); $placeholder.find('.mediumInsert-imageLink') .removeClass('mediumInsert-imageLink') .addClass('mediumInsert-imageUnlink'); // Workaround for "Uncaught NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is no longer a child of this node. Perhaps it was moved in a 'blur' event handler?" try { $('.mediumInsert-imageLinkWire').remove(); } catch(err) {} that.$el.trigger('keyup').trigger('input'); } }) .on('blur', '.mediumInsert-imageLinkText', function () { $('.mediumInsert-imageLinkWire').remove(); }) .on('paste', '.mediumInsert-imageLinkText', function (e) { if ($.fn.mediumInsert.insert.isFirefox && e.originalEvent.clipboardData) { $(this).val(e.originalEvent.clipboardData.getData('text/plain')); } }); }, /** * Set drag and drop events * * @return {void} */ setDragAndDropEvents: function () { var that = this, dropSuccessful = false, dropSort = false, dropSortIndex, dropSortParent; $(document).on('dragover', 'body', function () { if ($.fn.mediumInsert.settings.enabled === false) { return; } that.$el.addClass('hover'); }); $(document).on('dragend', 'body', function () { if ($.fn.mediumInsert.settings.enabled === false) { return; } that.$el.removeClass('hover'); }); this.$el.on('dragover', '.mediumInsert', function () { if ($.fn.mediumInsert.settings.enabled === false) { return; } $(this).addClass('hover'); $(this).attr('contenteditable', true); }); this.$el.on('dragleave', '.mediumInsert', function () { if ($.fn.mediumInsert.settings.enabled === false) { return; } $(this).removeClass('hover'); $(this).attr('contenteditable', false); }); this.$el.on('dragstart', '.mediumInsert .mediumInsert-images img', function () { if ($.fn.mediumInsert.settings.enabled === false) { return; } dropSortIndex = $(this).parent().index(); dropSortParent = $(this).parent().parent().parent().attr('id'); }); this.$el.on('dragend', '.mediumInsert .mediumInsert-images img', function (e) { if ($.fn.mediumInsert.settings.enabled === false) { return; } if (dropSuccessful === true) { if ($(e.originalEvent.target.parentNode).siblings().length === 0) { $(e.originalEvent.target.parentNode).parent().parent().removeClass('small'); } $(e.originalEvent.target.parentNode).mouseleave(); $(e.originalEvent.target.parentNode).remove(); dropSuccessful = false; dropSort = false; that.$el.trigger('keyup').trigger('input'); } }); this.$el.on('dragover', '.mediumInsert .mediumInsert-images img', function (e) { if ($.fn.mediumInsert.settings.enabled === false) { return; } e.preventDefault(); }); this.$el.on('drop', '.mediumInsert .mediumInsert-images img', function () { var index, $dragged, finalIndex; if ($.fn.mediumInsert.settings.enabled === false) { return; } if (dropSortParent !== $(this).parent().parent().parent().attr('id')) { dropSort = false; dropSortIndex = dropSortParent = null; return; } index = parseInt(dropSortIndex, 10); // Sort $dragged = $(this).parent().parent().find('.mediumInsert-images:nth-child('+ (index+1) +')'); finalIndex = $(this).parent().index(); if(index < finalIndex) { $dragged.insertAfter($(this).parent()); } else if(index > finalIndex) { $dragged.insertBefore($(this).parent()); } $dragged.mouseleave(); dropSort = true; dropSortIndex = null; that.$el.trigger('keyup').trigger('input'); }); this.$el.on('drop', '.mediumInsert', function (e) { var files; e.preventDefault(); if ($.fn.mediumInsert.settings.enabled === false) { return; } $(this).removeClass('hover'); that.$el.removeClass('hover'); $(this).attr('contenteditable', false); files = e.originalEvent.dataTransfer.files; if (files.length > 0) { // File upload that.uploadFiles($('.mediumInsert-placeholder', this), files, that); } else if (dropSort === true) { dropSort = false; } else { // Image move from block to block $('.mediumInsert-placeholder', this).append('
'+ e.originalEvent.dataTransfer.getData('text/html') +'
'); $('meta', this).remove(); dropSuccessful = true; } }); } }); }(jQuery));