diff --git a/htdocs/themes/cleanwhite/js/filereader.js b/htdocs/themes/cleanwhite/js/filereader.js new file mode 100644 index 0000000..ddeb815 --- /dev/null +++ b/htdocs/themes/cleanwhite/js/filereader.js @@ -0,0 +1,432 @@ +/*! +FileReader.js - v0.99 +A lightweight wrapper for common FileReader usage. +Copyright 2014 Brian Grinstead - MIT License. +See http://github.com/bgrins/filereader.js for documentation. +*/ + +(function(window, document) { + + var FileReader = window.FileReader; + var FileReaderSyncSupport = false; + var workerScript = "self.addEventListener('message', function(e) { var data=e.data; try { var reader = new FileReaderSync; postMessage({ result: reader[data.readAs](data.file), extra: data.extra, file: data.file})} catch(e){ postMessage({ result:'error', extra:data.extra, file:data.file}); } }, false);"; + var syncDetectionScript = "onmessage = function(e) { postMessage(!!FileReaderSync); };"; + var fileReaderEvents = ['loadstart', 'progress', 'load', 'abort', 'error', 'loadend']; + var sync = false; + var FileReaderJS = window.FileReaderJS = { + enabled: false, + setupInput: setupInput, + setupDrop: setupDrop, + setupClipboard: setupClipboard, + setSync: function (value) { + sync = value; + + if (sync && !FileReaderSyncSupport) { + checkFileReaderSyncSupport(); + } + }, + getSync: function() { + return sync && FileReaderSyncSupport; + }, + output: [], + opts: { + dragClass: "drag", + accept: false, + readAsDefault: 'DataURL', + readAsMap: { + }, + on: { + loadstart: noop, + progress: noop, + load: noop, + abort: noop, + error: noop, + loadend: noop, + skip: noop, + groupstart: noop, + groupend: noop, + beforestart: noop + } + } + }; + + // Setup jQuery plugin (if available) + if (typeof(jQuery) !== "undefined") { + jQuery.fn.fileReaderJS = function(opts) { + return this.each(function() { + if (jQuery(this).is("input")) { + setupInput(this, opts); + } + else { + setupDrop(this, opts); + } + }); + }; + + jQuery.fn.fileClipboard = function(opts) { + return this.each(function() { + setupClipboard(this, opts); + }); + }; + } + + // Not all browsers support the FileReader interface. Return with the enabled bit = false. + if (!FileReader) { + return; + } + + + // makeWorker is a little wrapper for generating web workers from strings + function makeWorker(script) { + var URL = window.URL || window.webkitURL; + var Blob = window.Blob; + var Worker = window.Worker; + + if (!URL || !Blob || !Worker || !script) { + return null; + } + + var blob = new Blob([script]); + var worker = new Worker(URL.createObjectURL(blob)); + return worker; + } + + // setupClipboard: bind to clipboard events (intended for document.body) + function setupClipboard(element, opts) { + + if (!FileReaderJS.enabled) { + return; + } + var instanceOptions = extend(extend({}, FileReaderJS.opts), opts); + + element.addEventListener("paste", onpaste, false); + + function onpaste(e) { + var files = []; + var clipboardData = e.clipboardData || {}; + var items = clipboardData.items || []; + + for (var i = 0; i < items.length; i++) { + var file = items[i].getAsFile(); + + if (file) { + + // Create a fake file name for images from clipboard, since this data doesn't get sent + var matches = new RegExp("/\(.*\)").exec(file.type); + if (!file.name && matches) { + var extension = matches[1]; + file.name = "clipboard" + i + "." + extension; + } + + files.push(file); + } + } + + if (files.length) { + processFileList(e, files, instanceOptions); + e.preventDefault(); + e.stopPropagation(); + } + } + } + + // setupInput: bind the 'change' event to an input[type=file] + function setupInput(input, opts) { + + if (!FileReaderJS.enabled) { + return; + } + var instanceOptions = extend(extend({}, FileReaderJS.opts), opts); + + input.addEventListener("change", inputChange, false); + input.addEventListener("drop", inputDrop, false); + + function inputChange(e) { + processFileList(e, input.files, instanceOptions); + } + + function inputDrop(e) { + e.stopPropagation(); + e.preventDefault(); + processFileList(e, e.dataTransfer.files, instanceOptions); + } + } + + // setupDrop: bind the 'drop' event for a DOM element + function setupDrop(dropbox, opts) { + + if (!FileReaderJS.enabled) { + return; + } + var instanceOptions = extend(extend({}, FileReaderJS.opts), opts); + var dragClass = instanceOptions.dragClass; + var initializedOnBody = false; + + // Bind drag events to the dropbox to add the class while dragging, and accept the drop data transfer. + dropbox.addEventListener("dragenter", onlyWithFiles(dragenter), false); + dropbox.addEventListener("dragleave", onlyWithFiles(dragleave), false); + dropbox.addEventListener("dragover", onlyWithFiles(dragover), false); + dropbox.addEventListener("drop", onlyWithFiles(drop), false); + + // Bind to body to prevent the dropbox events from firing when it was initialized on the page. + document.body.addEventListener("dragstart", bodydragstart, true); + document.body.addEventListener("dragend", bodydragend, true); + document.body.addEventListener("drop", bodydrop, false); + + function bodydragend(e) { + initializedOnBody = false; + } + + function bodydragstart(e) { + initializedOnBody = true; + } + + function bodydrop(e) { + if (e.dataTransfer.files && e.dataTransfer.files.length ){ + e.stopPropagation(); + e.preventDefault(); + } + } + + function onlyWithFiles(fn) { + return function() { + if (!initializedOnBody) { + fn.apply(this, arguments); + } + }; + } + + function drop(e) { + e.stopPropagation(); + e.preventDefault(); + if (dragClass) { + removeClass(dropbox, dragClass); + } + processFileList(e, e.dataTransfer.files, instanceOptions); + } + + function dragenter(e) { + e.stopPropagation(); + e.preventDefault(); + if (dragClass) { + addClass(dropbox, dragClass); + } + } + + function dragleave(e) { + if (dragClass) { + removeClass(dropbox, dragClass); + } + } + + function dragover(e) { + e.stopPropagation(); + e.preventDefault(); + if (dragClass) { + addClass(dropbox, dragClass); + } + } + } + + // setupCustomFileProperties: modify the file object with extra properties + function setupCustomFileProperties(files, groupID) { + for (var i = 0; i < files.length; i++) { + var file = files[i]; + file.extra = { + nameNoExtension: file.name.substring(0, file.name.lastIndexOf('.')), + extension: file.name.substring(file.name.lastIndexOf('.') + 1), + fileID: i, + uniqueID: getUniqueID(), + groupID: groupID, + prettySize: prettySize(file.size) + }; + } + } + + // getReadAsMethod: return method name for 'readAs*' - http://www.w3.org/TR/FileAPI/#reading-a-file + function getReadAsMethod(type, readAsMap, readAsDefault) { + for (var r in readAsMap) { + if (type.match(new RegExp(r))) { + return 'readAs' + readAsMap[r]; + } + } + return 'readAs' + readAsDefault; + } + + // processFileList: read the files with FileReader, send off custom events. + function processFileList(e, files, opts) { + + var filesLeft = files.length; + var group = { + groupID: getGroupID(), + files: files, + started: new Date() + }; + + function groupEnd() { + group.ended = new Date(); + opts.on.groupend(group); + } + + function groupFileDone() { + if (--filesLeft === 0) { + groupEnd(); + } + } + + FileReaderJS.output.push(group); + setupCustomFileProperties(files, group.groupID); + + opts.on.groupstart(group); + + // No files in group - end immediately + if (!files.length) { + groupEnd(); + return; + } + + var supportsSync = sync && FileReaderSyncSupport; + var syncWorker; + + // Only initialize the synchronous worker if the option is enabled - to prevent the overhead + if (supportsSync) { + syncWorker = makeWorker(workerScript); + syncWorker.onmessage = function(e) { + var file = e.data.file; + var result = e.data.result; + + // Workers seem to lose the custom property on the file object. + if (!file.extra) { + file.extra = e.data.extra; + } + + file.extra.ended = new Date(); + + // Call error or load event depending on success of the read from the worker. + opts.on[result === "error" ? "error" : "load"]({ target: { result: result } }, file); + groupFileDone(); + }; + } + + Array.prototype.forEach.call(files, function(file) { + + file.extra.started = new Date(); + + if (opts.accept && !file.type.match(new RegExp(opts.accept))) { + opts.on.skip(file); + groupFileDone(); + return; + } + + if (opts.on.beforestart(file) === false) { + opts.on.skip(file); + groupFileDone(); + return; + } + + var readAs = getReadAsMethod(file.type, opts.readAsMap, opts.readAsDefault); + + if (syncWorker) { + syncWorker.postMessage({ + file: file, + extra: file.extra, + readAs: readAs + }); + } + else { + + var reader = new FileReader(); + reader.originalEvent = e; + + fileReaderEvents.forEach(function(eventName) { + reader['on' + eventName] = function(e) { + if (eventName == 'load' || eventName == 'error') { + file.extra.ended = new Date(); + } + opts.on[eventName](e, file); + if (eventName == 'loadend') { + groupFileDone(); + } + }; + }); + reader[readAs](file); + } + }); + } + + // checkFileReaderSyncSupport: Create a temporary worker and see if FileReaderSync exists + function checkFileReaderSyncSupport() { + var worker = makeWorker(syncDetectionScript); + if (worker) { + worker.onmessage =function(e) { + FileReaderSyncSupport = e.data; + }; + worker.postMessage({}); + } + } + + // noop: do nothing + function noop() { + + } + + // extend: used to make deep copies of options object + function extend(destination, source) { + for (var property in source) { + if (source[property] && source[property].constructor && + source[property].constructor === Object) { + destination[property] = destination[property] || {}; + arguments.callee(destination[property], source[property]); + } + else { + destination[property] = source[property]; + } + } + return destination; + } + + // hasClass: does an element have the css class? + function hasClass(el, name) { + return new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)").test(el.className); + } + + // addClass: add the css class for the element. + function addClass(el, name) { + if (!hasClass(el, name)) { + el.className = el.className ? [el.className, name].join(' ') : name; + } + } + + // removeClass: remove the css class from the element. + function removeClass(el, name) { + if (hasClass(el, name)) { + var c = el.className; + el.className = c.replace(new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)", "g"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, ''); + } + } + + // prettySize: convert bytes to a more readable string. + function prettySize(bytes) { + var s = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB']; + var e = Math.floor(Math.log(bytes)/Math.log(1024)); + return (bytes/Math.pow(1024, Math.floor(e))).toFixed(2)+" "+s[e]; + } + + // getGroupID: generate a unique int ID for groups. + var getGroupID = (function(id) { + return function() { + return id++; + }; + })(0); + + // getUniqueID: generate a unique int ID for files + var getUniqueID = (function(id) { + return function() { + return id++; + }; + })(0); + + // The interface is supported, bind the FileReaderJS callbacks + FileReaderJS.enabled = true; + +})(this, document); \ No newline at end of file diff --git a/htdocs/themes/cleanwhite/js/linkify-jquery.min.js b/htdocs/themes/cleanwhite/js/linkify-jquery.min.js new file mode 100644 index 0000000..b67d661 --- /dev/null +++ b/htdocs/themes/cleanwhite/js/linkify-jquery.min.js @@ -0,0 +1 @@ +"use strict";!function(e,t,n){var i=function(t,n){function i(e,t,n){var i=n[n.length-1];e.replaceChild(i,t);for(var r=n.length-2;r>=0;r--)e.insertBefore(n[r],i),i=n[r]}function r(e,t,n){for(var i=[],r=e,a=Array.isArray(r),o=0,r=a?r:r[Symbol.iterator]();;){var l;if(a){if(o>=r.length)break;l=r[o++]}else{if(o=r.next(),o.done)break;l=o.value}var f=l;if("nl"===f.type&&t.nl2br)i.push(n.createElement("br"));else if(f.isLink&&t.check(f)){var s=t.resolve(f),c=s.formatted,u=s.formattedHref,d=s.tagName,m=s.className,y=s.target,h=s.events,k=s.attributes,v=n.createElement(d);if(v.setAttribute("href",u),m&&v.setAttribute("class",m),y&&v.setAttribute("target",y),k)for(var g in k)v.setAttribute(g,k[g]);if(h)for(var b in h)v.addEventListener?v.addEventListener(b,h[b]):v.attachEvent&&v.attachEvent("on"+b,h[b]);v.appendChild(n.createTextNode(c)),i.push(v)}else i.push(n.createTextNode(f.toString()))}return i}function a(e,t,n){if(!e||e.nodeType!==d)throw new Error("Cannot linkify "+e+" - Invalid DOM Node type");var o=t.ignoreTags;if("A"===e.tagName||s.contains(o,e.tagName))return e;for(var l=e.firstChild;l;){switch(l.nodeType){case d:a(l,t,n);break;case m:var c=l.nodeValue,y=f(c);if(0===y.length||1===y.length&&y[0]instanceof u)break;var h=r(y,t,n);i(e,l,h),l=h[h.length-1]}l=l.nextSibling}return e}function o(t,n){var i=!(arguments.length<=2||void 0===arguments[2])&&arguments[2];try{i=i||document||e&&e.document||global&&global.document}catch(r){}if(!i)throw new Error("Cannot find document implementation. If you are in a non-browser environment like Node.js, pass the document implementation as the third argument to linkifyElement.");return n=new c(n),a(t,n,i)}function l(t){function n(e){return e=o.normalize(e),this.each(function(){o.helper(this,e,i)})}var i=!(arguments.length<=1||void 0===arguments[1])&&arguments[1];t.fn=t.fn||{};try{i=i||document||e&&e.document||global&&global.document}catch(r){}if(!i)throw new Error("Cannot find document implementation. If you are in a non-browser environment like Node.js, pass the document implementation as the second argument to linkify/jquery");"function"!=typeof t.fn.linkify&&(t.fn.linkify=n,t(i).ready(function(){t("[data-linkify]").each(function(){var e=t(this),n=e.data(),i=n.linkify,r=n.linkifyNlbr,a={attributes:n.linkifyAttributes,defaultProtocol:n.linkifyDefaultProtocol,events:n.linkifyEvents,format:n.linkifyFormat,formatHref:n.linkifyFormatHref,nl2br:!!r&&0!==r&&"false"!==r,tagName:n.linkifyTagname,target:n.linkifyTarget,className:n.linkifyClassName||n.linkifyLinkclass,validate:n.linkifyValidate,ignoreTags:n.linkifyIgnoreTags},o="this"===i?e:e.find(i);o.linkify(a)})}))}var f=n.tokenize,s=n.options,c=s.Options,u=n.parser.TOKENS.TEXT,d=1,m=3;o.helper=a,o.normalize=function(e){return new c(e)};try{!define&&(e.linkifyElement=o)}catch(y){}return l}(n,t);"function"!=typeof n.fn.linkify&&i(n)}(window,linkify,jQuery); \ No newline at end of file diff --git a/htdocs/themes/cleanwhite/js/linkify.min.js b/htdocs/themes/cleanwhite/js/linkify.min.js new file mode 100644 index 0000000..377d412 --- /dev/null +++ b/htdocs/themes/cleanwhite/js/linkify.min.js @@ -0,0 +1 @@ +!function(){"use strict";var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t};!function(e){function n(t,e){var n=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],o=Object.create(t.prototype);for(var a in n)o[a]=n[a];return o.constructor=e,e.prototype=o,e}function o(t){t=t||{},this.defaultProtocol=t.defaultProtocol||g.defaultProtocol,this.events=t.events||g.events,this.format=t.format||g.format,this.formatHref=t.formatHref||g.formatHref,this.nl2br=t.nl2br||g.nl2br,this.tagName=t.tagName||g.tagName,this.target=t.target||g.target,this.validate=t.validate||g.validate,this.ignoreTags=[],this.attributes=t.attributes||t.linkAttributes||g.attributes,this.className=t.className||t.linkClass||g.className;for(var e=t.ignoreTags||g.ignoreTags,n=0;n=r)return[];for(;a=0&&u++,c++,a++;if(!(u<0)){a-=u,c-=u;var h=l.emit();o.push(new h(t.substr(a-c,c)))}}return o},gt=Z,pt=Object.freeze({State:m,TOKENS:M,run:ht,start:gt}),ft=l();ft.prototype={type:"token",isLink:!1,toString:function(){for(var t=[],e=0;e=0&&u++,n++,c++;if(u<0)for(var h=n-c;h0&&(o.push(new dt(a)),a=[]),n-=u,c-=u;var g=l.emit();o.push(new g(t.slice(n-c,n)))}}return a.length>0&&o.push(new dt(a)),o},te=Object.freeze({State:d,TOKENS:yt,run:$t,start:wt});Array.isArray||(Array.isArray=function(t){return"[object Array]"===Object.prototype.toString.call(t)});var ee=function(t){return $t(ht(t))},ne=function(t){for(var e=arguments.length<=1||void 0===arguments[1]?null:arguments[1],n=ee(t),o=[],a=0;acarabiner->js('jquery.js'); $this->carabiner->js('jquery.timers.js'); +$this->carabiner->js('filereader.js'); +$this->carabiner->js('linkify.min.js'); +$this->carabiner->js('linkify-jquery.min.js'); $this->carabiner->js('stikked.js'); $this->carabiner->js('codemirror/codemirror.js'); $this->carabiner->js('codemirror_exec.js'); diff --git a/htdocs/themes/cleanwhite/views/view/view_footer.php b/htdocs/themes/cleanwhite/views/view/view_footer.php index a5d6707..4e4df0a 100644 --- a/htdocs/themes/cleanwhite/views/view/view_footer.php +++ b/htdocs/themes/cleanwhite/views/view/view_footer.php @@ -2,11 +2,15 @@ ' . json_encode($codemirror_modes) . ''; +if(isset($codemirror_modes)){ + echo ''; +} //Javascript $this->carabiner->js('jquery.js'); $this->carabiner->js('jquery.timers.js'); +$this->carabiner->js('linkify.min.js'); +$this->carabiner->js('linkify-jquery.min.js'); $this->carabiner->js('stikked.js'); $this->carabiner->js('codemirror/codemirror.js'); $this->carabiner->js('codemirror_exec.js');