123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- /*! inline-attachment - v2.0.3 - 2016-08-20 */
- /*jslint newcap: true */
- /*global XMLHttpRequest: false, FormData: false */
- /*
- * Inline Text Attachment
- *
- * Author: Roy van Kaathoven
- * Contact: ik@royvankaathoven.nl
- */
- (function(document, window) {
- 'use strict';
- var inlineAttachment = function(options, instance) {
- this.settings = inlineAttachment.util.merge(options, inlineAttachment.defaults);
- this.editor = instance;
- this.filenameTag = '{filename}';
- this.lastValue = null;
- };
- /**
- * Will holds the available editors
- *
- * @type {Object}
- */
- inlineAttachment.editors = {};
- /**
- * Utility functions
- */
- inlineAttachment.util = {
- /**
- * Simple function to merge the given objects
- *
- * @param {Object[]} object Multiple object parameters
- * @returns {Object}
- */
- merge: function() {
- var result = {};
- for (var i = arguments.length - 1; i >= 0; i--) {
- var obj = arguments[i];
- for (var k in obj) {
- if (obj.hasOwnProperty(k)) {
- result[k] = obj[k];
- }
- }
- }
- return result;
- },
- /**
- * Append a line of text at the bottom, ensuring there aren't unnecessary newlines
- *
- * @param {String} appended Current content
- * @param {String} previous Value which should be appended after the current content
- */
- appendInItsOwnLine: function(previous, appended) {
- return (previous + "\n\n[[D]]" + appended)
- .replace(/(\n{2,})\[\[D\]\]/, "\n\n")
- .replace(/^(\n*)/, "");
- },
- /**
- * Inserts the given value at the current cursor position of the textarea element
- *
- * @param {HtmlElement} el
- * @param {String} value Text which will be inserted at the cursor position
- */
- insertTextAtCursor: function(el, text) {
- var scrollPos = el.scrollTop,
- strPos = 0,
- browser = false,
- range;
- if ((el.selectionStart || el.selectionStart === '0')) {
- browser = "ff";
- } else if (document.selection) {
- browser = "ie";
- }
- if (browser === "ie") {
- el.focus();
- range = document.selection.createRange();
- range.moveStart('character', -el.value.length);
- strPos = range.text.length;
- } else if (browser === "ff") {
- strPos = el.selectionStart;
- }
- var front = (el.value).substring(0, strPos);
- var back = (el.value).substring(strPos, el.value.length);
- el.value = front + text + back;
- strPos = strPos + text.length;
- if (browser === "ie") {
- el.focus();
- range = document.selection.createRange();
- range.moveStart('character', -el.value.length);
- range.moveStart('character', strPos);
- range.moveEnd('character', 0);
- range.select();
- } else if (browser === "ff") {
- el.selectionStart = strPos;
- el.selectionEnd = strPos;
- el.focus();
- }
- el.scrollTop = scrollPos;
- }
- };
- /**
- * Default configuration options
- *
- * @type {Object}
- */
- inlineAttachment.defaults = {
- /**
- * URL where the file will be send
- */
- uploadUrl: 'upload_attachment.php',
- /**
- * Which method will be used to send the file to the upload URL
- */
- uploadMethod: 'POST',
- /**
- * Name in which the file will be placed
- */
- uploadFieldName: 'file',
- /**
- * Extension which will be used when a file extension could not
- * be detected
- */
- defaultExtension: 'png',
- /**
- * JSON field which refers to the uploaded file URL
- */
- jsonFieldName: 'filename',
- /**
- * Allowed MIME types
- */
- allowedTypes: [
- 'image/jpeg',
- 'image/png',
- 'image/jpg',
- 'image/gif'
- ],
- /**
- * Text which will be inserted when dropping or pasting a file.
- * Acts as a placeholder which will be replaced when the file is done with uploading
- */
- progressText: '![Uploading file...]()',
- /**
- * When a file has successfully been uploaded the progressText
- * will be replaced by the urlText, the {filename} tag will be replaced
- * by the filename that has been returned by the server
- */
- urlText: "",
- /**
- * Text which will be used when uploading has failed
- */
- errorText: "Error uploading file",
- /**
- * Extra parameters which will be send when uploading a file
- */
- extraParams: {},
- /**
- * Extra headers which will be send when uploading a file
- */
- extraHeaders: {},
- /**
- * Before the file is send
- */
- beforeFileUpload: function() {
- return true;
- },
- /**
- * Triggers when a file is dropped or pasted
- */
- onFileReceived: function() {},
- /**
- * Custom upload handler
- *
- * @return {Boolean} when false is returned it will prevent default upload behavior
- */
- onFileUploadResponse: function() {
- return true;
- },
- /**
- * Custom error handler. Runs after removing the placeholder text and before the alert().
- * Return false from this function to prevent the alert dialog.
- *
- * @return {Boolean} when false is returned it will prevent default error behavior
- */
- onFileUploadError: function() {
- return true;
- },
- /**
- * When a file has succesfully been uploaded
- */
- onFileUploaded: function() {}
- };
- /**
- * Uploads the blob
- *
- * @param {Blob} file blob data received from event.dataTransfer object
- * @return {XMLHttpRequest} request object which sends the file
- */
- inlineAttachment.prototype.uploadFile = function(file) {
- var me = this,
- formData = new FormData(),
- xhr = new XMLHttpRequest(),
- settings = this.settings,
- extension = settings.defaultExtension || settings.defualtExtension;
- if (typeof settings.setupFormData === 'function') {
- settings.setupFormData(formData, file);
- }
- // Attach the file. If coming from clipboard, add a default filename (only works in Chrome for now)
- // http://stackoverflow.com/questions/6664967/how-to-give-a-blob-uploaded-as-formdata-a-file-name
- if (file.name) {
- var fileNameMatches = file.name.match(/\.(.+)$/);
- if (fileNameMatches) {
- extension = fileNameMatches[1];
- }
- }
- var remoteFilename = "image-" + Date.now() + "." + extension;
- if (typeof settings.remoteFilename === 'function') {
- remoteFilename = settings.remoteFilename(file);
- }
- formData.append(settings.uploadFieldName, file, remoteFilename);
- // Append the extra parameters to the formdata
- if (typeof settings.extraParams === "object") {
- for (var key in settings.extraParams) {
- if (settings.extraParams.hasOwnProperty(key)) {
- formData.append(key, settings.extraParams[key]);
- }
- }
- }
- xhr.open('POST', settings.uploadUrl);
- // Add any available extra headers
- if (typeof settings.extraHeaders === "object") {
- for (var header in settings.extraHeaders) {
- if (settings.extraHeaders.hasOwnProperty(header)) {
- xhr.setRequestHeader(header, settings.extraHeaders[header]);
- }
- }
- }
- xhr.onload = function() {
- // If HTTP status is OK or Created
- if (xhr.status === 200 || xhr.status === 201) {
- me.onFileUploadResponse(xhr);
- } else {
- me.onFileUploadError(xhr);
- }
- };
- if (settings.beforeFileUpload(xhr) !== false) {
- xhr.send(formData);
- }
- return xhr;
- };
- /**
- * Returns if the given file is allowed to handle
- *
- * @param {File} clipboard data file
- */
- inlineAttachment.prototype.isFileAllowed = function(file) {
- if (file.kind === 'string') { return false; }
- if (this.settings.allowedTypes.indexOf('*') === 0){
- return true;
- } else {
- return this.settings.allowedTypes.indexOf(file.type) >= 0;
- }
- };
- /**
- * Handles upload response
- *
- * @param {XMLHttpRequest} xhr
- * @return {Void}
- */
- inlineAttachment.prototype.onFileUploadResponse = function(xhr) {
- if (this.settings.onFileUploadResponse.call(this, xhr) !== false) {
- var result = JSON.parse(xhr.responseText),
- filename = result[this.settings.jsonFieldName];
- if (result && filename) {
- var newValue;
- if (typeof this.settings.urlText === 'function') {
- newValue = this.settings.urlText.call(this, filename, result);
- } else {
- newValue = this.settings.urlText.replace(this.filenameTag, filename);
- }
- var text = this.editor.getValue().replace(this.lastValue, newValue);
- this.editor.setValue(text);
- this.settings.onFileUploaded.call(this, filename);
- }
- }
- };
- /**
- * Called when a file has failed to upload
- *
- * @param {XMLHttpRequest} xhr
- * @return {Void}
- */
- inlineAttachment.prototype.onFileUploadError = function(xhr) {
- if (this.settings.onFileUploadError.call(this, xhr) !== false) {
- var text = this.editor.getValue().replace(this.lastValue, "");
- this.editor.setValue(text);
- }
- };
- /**
- * Called when a file has been inserted, either by drop or paste
- *
- * @param {File} file
- * @return {Void}
- */
- inlineAttachment.prototype.onFileInserted = function(file) {
- if (this.settings.onFileReceived.call(this, file) !== false) {
- this.lastValue = this.settings.progressText;
- this.editor.insertValue(this.lastValue);
- }
- };
- /**
- * Called when a paste event occured
- * @param {Event} e
- * @return {Boolean} if the event was handled
- */
- inlineAttachment.prototype.onPaste = function(e) {
- var result = false,
- clipboardData = e.clipboardData,
- items;
- if (typeof clipboardData === "object") {
- items = clipboardData.items || clipboardData.files || [];
- for (var i = 0; i < items.length; i++) {
- var item = items[i];
- if (this.isFileAllowed(item)) {
- result = true;
- this.onFileInserted(item.getAsFile());
- this.uploadFile(item.getAsFile());
- }
- }
- }
- if (result) { e.preventDefault(); }
- return result;
- };
- /**
- * Called when a drop event occures
- * @param {Event} e
- * @return {Boolean} if the event was handled
- */
- inlineAttachment.prototype.onDrop = function(e) {
- var result = false;
- for (var i = 0; i < e.dataTransfer.files.length; i++) {
- var file = e.dataTransfer.files[i];
- if (this.isFileAllowed(file)) {
- result = true;
- this.onFileInserted(file);
- this.uploadFile(file);
- }
- }
- return result;
- };
- window.inlineAttachment = inlineAttachment;
- })(document, window);
- /*jslint newcap: true */
- /*global inlineAttachment: false, jQuery: false */
- /**
- * jQuery plugin for inline attach
- *
- * @param {document} document
- * @param {window} window
- * @param {jQuery} $
- */
- (function(document, window, $) {
- 'use strict';
- inlineAttachment.editors.jquery = {};
- /**
- * Creates a new editor using jQuery
- */
- var editor = function(instance) {
- var $this = $(instance);
- return {
- getValue: function() {
- return $this.val();
- },
- insertValue: function(val) {
- inlineAttachment.util.insertTextAtCursor($this[0], val);
- },
- setValue: function(val) {
- $this.val(val);
- }
- };
- };
- $.fn.inlineattachment = function(options) {
- var set = $(this);
- set.each(function() {
- var $this = $(this),
- ed = new editor($this),
- inlineattach = new inlineAttachment(options, ed);
- $this.bind({
- 'paste': function(e) {
- inlineattach.onPaste(e.originalEvent);
- },
- 'drop': function(e) {
- e.stopPropagation();
- e.preventDefault();
- inlineattach.onDrop(e.originalEvent);
- },
- 'dragenter dragover': function(e) {
- e.stopPropagation();
- e.preventDefault();
- }
- });
- });
- return this;
- };
- inlineAttachment.editors.jquery.Editor = editor;
- })(document, window, jQuery);
|