diff --git a/README.md b/README.md index 786c4d7..17ccbc7 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,10 @@ VCS-Maker.js ============ A browser firendly VCS file generator written entirely in javascript!!!!!! + + +The source has forked and compiled versions of the following projects: +* FileSaver.js (https://github.com/eligrey/FileSaver.js) +* Blob.js (https://github.com/eligrey/Blob.js) + +I've compressed them and included them into the source. \ No newline at end of file diff --git a/vcs-maker-min.js b/vcs-maker-min.js new file mode 100644 index 0000000..163787c --- /dev/null +++ b/vcs-maker-min.js @@ -0,0 +1 @@ +var BlobBuilder=BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder||function(e){if(navigator.userAgent.indexOf("MSIE")>-1&&navigator.userAgent.indexOf("MSIE 10")==-1){console.log("Unsupported Browser");return}"use strict";var t=function(e){return Object.prototype.toString.call(e).match(/^\[object\s(.*)\]$/)[1]},n=function(){this.data=[]},r=function(e,t,n){this.data=e;this.size=e.length;this.type=t;this.encoding=n},i=n.prototype,s=r.prototype,o=e.FileReaderSync,u=function(e){this.code=this[this.name=e]},a=("NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "+"NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR").split(" "),f=a.length,l=e.URL||e.webkitURL||e,c=l.createObjectURL,h=l.revokeObjectURL,p=l,d=e.btoa,v=e.atob,m=false,g=function(e){m=!e},y=e.ArrayBuffer,b=e.Uint8Array;n.fake=s.fake=true;while(f--){u.prototype[a[f]]=f+1}try{if(b){g.apply(0,new b(1))}}catch(w){}if(!l.createObjectURL){p=e.URL={}}p.createObjectURL=function(e){var t=e.type,n;if(t===null){t="application/octet-stream"}if(e instanceof r){n="data:"+t;if(e.encoding==="base64"){return n+";base64,"+e.data}else if(e.encoding==="URI"){return n+","+decodeURIComponent(e.data)}if(d){return n+";base64,"+d(e.data)}else{return n+","+encodeURIComponent(e.data)}}else if(c){return c.call(l,e)}};p.revokeObjectURL=function(e){if(e.substring(0,5)!=="data:"&&h){h.call(l,e)}};i.append=function(e){var n=this.data;if(b&&e instanceof y){if(m){n.push(String.fromCharCode.apply(String,new b(e)))}else{var i="",s=new b(e),a=0,f=s.length;for(;a1?t:this.data.length),n,this.encoding)};s.toString=function(){return"[object Blob]"};return n}(self);var saveAs=saveAs||navigator.msSaveOrOpenBlob&&navigator.msSaveOrOpenBlob.bind(navigator)||function(e){if(navigator.userAgent.indexOf("MSIE")!=-1&&navigator.userAgent.indexOf("MSIE 10")==-1){console.log("Unsupported Browser");return}"use strict";var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=e.URL||e.webkitURL||e,i=t.createElementNS("http://www.w3.org/1999/xhtml","a"),s=!e.externalHost&&"download"in i,o=function(n){var r=t.createEvent("MouseEvents");r.initMouseEvent("click",true,false,e,0,0,0,0,0,false,false,false,false,0,null);n.dispatchEvent(r)},u=e.webkitRequestFileSystem,a=e.requestFileSystem||u||e.mozRequestFileSystem,f=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},l="application/octet-stream",c=0,h=[],p=function(){var e=h.length;while(e--){var t=h[e];if(typeof t==="string"){r.revokeObjectURL(t)}else{t.remove()}}h.length=0},d=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var i=e["on"+t[r]];if(typeof i==="function"){try{i.call(e,n||e)}catch(s){f(s)}}}},v=function(t,r){var f=this,p=t.type,v=false,m,g,y=function(){var e=n().createObjectURL(t);h.push(e);return e},b=function(){d(f,"writestart progress write writeend".split(" "))},w=function(){if(v||!m){m=y(t)}if(g){g.location.href=m}else{window.open(m,"_blank")}f.readyState=f.DONE;b()},E=function(e){return function(){if(f.readyState!==f.DONE){return e.apply(this,arguments)}}},S={create:true,exclusive:false},x;f.readyState=f.INIT;if(!r){r="download"}if(s){m=y(t);i.href=m;i.download=r;o(i);f.readyState=f.DONE;b();return}if(e.chrome&&p&&p!==l){x=t.slice||t.webkitSlice;t=x.call(t,0,t.size,l);v=true}if(u&&r!=="download"){r+=".download"}if(p===l||u){g=e}if(!a){w();return}c+=t.size;a(e.TEMPORARY,c,E(function(e){e.root.getDirectory("saved",S,E(function(e){var n=function(){e.getFile(r,S,E(function(e){e.createWriter(E(function(n){n.onwriteend=function(t){g.location.href=e.toURL();h.push(e);f.readyState=f.DONE;d(f,"writeend",t)};n.onerror=function(){var e=n.error;if(e.code!==e.ABORT_ERR){w()}};"writestart progress write abort".split(" ").forEach(function(e){n["on"+e]=f["on"+e]});n.write(t);f.abort=function(){n.abort();f.readyState=f.DONE};f.readyState=f.WRITING}),w)}),w)};e.getFile(r,{create:false},E(function(e){e.remove();n()}),E(function(e){if(e.code===e.NOT_FOUND_ERR){n()}else{w()}}))}),w)}),w)},m=v.prototype,g=function(e,t){return new v(e,t)};m.abort=function(){var e=this;e.readyState=e.DONE;d(e,"abort")};m.readyState=m.INIT=0;m.WRITING=1;m.DONE=2;m.error=m.onwritestart=m.onprogress=m.onwrite=m.onabort=m.onerror=m.onwriteend=null;e.addEventListener("unload",p,false);return g}(self);download_vcs=function(e,t,n,r,i,s){if(navigator.userAgent.indexOf("MSIE")>-1&&navigator.userAgent.indexOf("MSIE 10")==-1){console.log("Unsupported Browser");return}var t=t;var n=n;var o=r;var u=new Date(i);var a=new Date(s);var f=("0000"+u.getFullYear().toString()).slice(-4);var l=("00"+u.getMonth().toString()).slice(-2);var c=("00"+u.getDate().toString()).slice(-2);var h=f+l+c;var p=("0000"+a.getFullYear().toString()).slice(-4);var d=("00"+a.getMonth().toString()).slice(-2);var v=("00"+(a.getDate()+1).toString()).slice(-2);var s=p+d+v;var m=["BEGIN:VCALENDAR","VERSION:2.0","BEGIN:VEVENT","CLASS:PUBLIC","DESCRIPTION:"+n,"DTSTART;VALUE=DATE:"+h,"DTEND;VALUE=DATE:"+s,"LOCATION:"+o,"SUMMARY;LANGUAGE=en-us:"+t,"TRANSP:TRANSPARENT","END:VEVENT","END:VCALENDAR"].join("\n");if(navigator.userAgent.indexOf("MSIE 10")>-1){var g=new Blob([m])}else{var y=new BlobBuilder;y.append(m);var g=y.getBlob("text/x-vCalendar;charset="+document.characterSet)}saveAs(g,e+".vcs")} \ No newline at end of file diff --git a/vcs-maker-nolibs.js b/vcs-maker-nolibs.js new file mode 100644 index 0000000..6d82715 --- /dev/null +++ b/vcs-maker-nolibs.js @@ -0,0 +1,48 @@ +/* VCS-Maker.js */ +download_vcs = function(filename, subject, description, location, begin, end) { + if (navigator.userAgent.indexOf('MSIE') > -1 && navigator.userAgent.indexOf('MSIE 10') == -1) { + console.log('Unsupported Browser'); + return; + }; + + var subject = subject; + var description = description; + var address = location; + var start_date = new Date(begin); + var end_date = new Date(end); + + var start_year = ("0000" + (start_date.getFullYear().toString())).slice(-4); + var start_month = ("00" + (start_date.getMonth().toString())).slice(-2); + var start_day = ("00" + (start_date.getDate().toString())).slice(-2); + var start = start_year + start_month + start_day; + + var end_year = ("0000" + (end_date.getFullYear().toString())).slice(-4); + var end_month = ("00" + (end_date.getMonth().toString())).slice(-2); + var end_day = ("00" + ((end_date.getDate()+1).toString())).slice(-2); + var end = end_year + end_month + end_day; + + var calendar = [ + "BEGIN:VCALENDAR", + "VERSION:2.0", + "BEGIN:VEVENT", + "CLASS:PUBLIC", + "DESCRIPTION:"+description, + "DTSTART;VALUE=DATE:"+start, + "DTEND;VALUE=DATE:"+end, + "LOCATION:"+address, + "SUMMARY;LANGUAGE=en-us:"+subject, + "TRANSP:TRANSPARENT", + "END:VEVENT", + "END:VCALENDAR" + ].join('\n'); + + if (navigator.userAgent.indexOf('MSIE 10') > -1) { // chrome or firefox + var blob = new Blob([calendar]); + } + else { // ie + var bb = new BlobBuilder(); + bb.append(calendar); + var blob = bb.getBlob("text/x-vCalendar;charset=" + document.characterSet); + } + saveAs(blob, filename+".vcs"); +} diff --git a/vcs-maker.js b/vcs-maker.js new file mode 100644 index 0000000..171a5b5 --- /dev/null +++ b/vcs-maker.js @@ -0,0 +1,412 @@ + + + +// FileSaver.js +var BlobBuilder = BlobBuilder || self.WebKitBlobBuilder || self.MozBlobBuilder || self.MSBlobBuilder || (function(view) { + if (navigator.userAgent.indexOf('MSIE') > -1 && navigator.userAgent.indexOf('MSIE 10') == -1) { + console.log('Unsupported Browser'); + return; + }; + + "use strict"; + var get_class = function(object) { + return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; + } + , FakeBlobBuilder = function(){ + this.data = []; + } + , FakeBlob = function(data, type, encoding) { + this.data = data; + this.size = data.length; + this.type = type; + this.encoding = encoding; + } + , FBB_proto = FakeBlobBuilder.prototype + , FB_proto = FakeBlob.prototype + , FileReaderSync = view.FileReaderSync + , FileException = function(type) { + this.code = this[this.name = type]; + } + , file_ex_codes = ( + "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " + + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" + ).split(" ") + , file_ex_code = file_ex_codes.length + , real_URL = view.URL || view.webkitURL || view + , real_create_object_URL = real_URL.createObjectURL + , real_revoke_object_URL = real_URL.revokeObjectURL + , URL = real_URL + , btoa = view.btoa + , atob = view.atob + , can_apply_typed_arrays = false + , can_apply_typed_arrays_test = function(pass) { + can_apply_typed_arrays = !pass; + } + + , ArrayBuffer = view.ArrayBuffer + , Uint8Array = view.Uint8Array + ; + FakeBlobBuilder.fake = FB_proto.fake = true; + while (file_ex_code--) { + FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; + } + try { + if (Uint8Array) { + can_apply_typed_arrays_test.apply(0, new Uint8Array(1)); + } + } catch (ex) {} + if (!real_URL.createObjectURL) { + URL = view.URL = {}; + } + URL.createObjectURL = function(blob) { + var + type = blob.type + , data_URI_header + ; + if (type === null) { + type = "application/octet-stream"; + } + if (blob instanceof FakeBlob) { + data_URI_header = "data:" + type; + if (blob.encoding === "base64") { + return data_URI_header + ";base64," + blob.data; + } else if (blob.encoding === "URI") { + return data_URI_header + "," + decodeURIComponent(blob.data); + } if (btoa) { + return data_URI_header + ";base64," + btoa(blob.data); + } else { + return data_URI_header + "," + encodeURIComponent(blob.data); + } + } else if (real_create_object_URL) { + return real_create_object_URL.call(real_URL, blob); + } + }; + URL.revokeObjectURL = function(object_URL) { + if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { + real_revoke_object_URL.call(real_URL, object_URL); + } + }; + FBB_proto.append = function(data/*, endings*/) { + var bb = this.data; + // decode data to a binary string + if (Uint8Array && data instanceof ArrayBuffer) { + if (can_apply_typed_arrays) { + bb.push(String.fromCharCode.apply(String, new Uint8Array(data))); + } else { + var + str = "" + , buf = new Uint8Array(data) + , i = 0 + , buf_len = buf.length + ; + for (; i < buf_len; i++) { + str += String.fromCharCode(buf[i]); + } + } + } else if (get_class(data) === "Blob" || get_class(data) === "File") { + if (FileReaderSync) { + var fr = new FileReaderSync; + bb.push(fr.readAsBinaryString(data)); + } else { + // async FileReader won't work as BlobBuilder is sync + throw new FileException("NOT_READABLE_ERR"); + } + } else if (data instanceof FakeBlob) { + if (data.encoding === "base64" && atob) { + bb.push(atob(data.data)); + } else if (data.encoding === "URI") { + bb.push(decodeURIComponent(data.data)); + } else if (data.encoding === "raw") { + bb.push(data.data); + } + } else { + if (typeof data !== "string") { + data += ""; // convert unsupported types to strings + } + // decode UTF-16 to binary string + bb.push(unescape(encodeURIComponent(data))); + } + }; + FBB_proto.getBlob = function(type) { + if (!arguments.length) { + type = null; + } + return new FakeBlob(this.data.join(""), type, "raw"); + }; + FBB_proto.toString = function() { + return "[object BlobBuilder]"; + }; + FB_proto.slice = function(start, end, type) { + var args = arguments.length; + if (args < 3) { + type = null; + } + return new FakeBlob( + this.data.slice(start, args > 1 ? end : this.data.length) + , type + , this.encoding + ); + }; + FB_proto.toString = function() { + return "[object Blob]"; + }; + return FakeBlobBuilder; + }(self)); + + +// Blob.js +var saveAs = saveAs + || (navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) + || (function(view) { + if (navigator.userAgent.indexOf('MSIE') != -1 && navigator.userAgent.indexOf('MSIE 10') == -1) { + console.log('Unsupported Browser'); + return; + }; + "use strict"; + var + doc = view.document + // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet + , get_URL = function() { + return view.URL || view.webkitURL || view; + } + , URL = view.URL || view.webkitURL || view + , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") + , can_use_save_link = !view.externalHost && "download" in save_link + , click = function(node) { + var event = doc.createEvent("MouseEvents"); + event.initMouseEvent( + "click", true, false, view, 0, 0, 0, 0, 0 + , false, false, false, false, 0, null + ); + node.dispatchEvent(event); + } + , webkit_req_fs = view.webkitRequestFileSystem + , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem + , throw_outside = function (ex) { + (view.setImmediate || view.setTimeout)(function() { + throw ex; + }, 0); + } + , force_saveable_type = "application/octet-stream" + , fs_min_size = 0 + , deletion_queue = [] + , process_deletion_queue = function() { + var i = deletion_queue.length; + while (i--) { + var file = deletion_queue[i]; + if (typeof file === "string") { // file is an object URL + URL.revokeObjectURL(file); + } else { // file is a File + file.remove(); + } + } + deletion_queue.length = 0; // clear queue + } + , dispatch = function(filesaver, event_types, event) { + event_types = [].concat(event_types); + var i = event_types.length; + while (i--) { + var listener = filesaver["on" + event_types[i]]; + if (typeof listener === "function") { + try { + listener.call(filesaver, event || filesaver); + } catch (ex) { + throw_outside(ex); + } + } + } + } + , FileSaver = function(blob, name) { + // First try a.download, then web filesystem, then object URLs + var + filesaver = this + , type = blob.type + , blob_changed = false + , object_url + , target_view + , get_object_url = function() { + var object_url = get_URL().createObjectURL(blob); + deletion_queue.push(object_url); + return object_url; + } + , dispatch_all = function() { + dispatch(filesaver, "writestart progress write writeend".split(" ")); + } + // on any filesys errors revert to saving with object URLs + , fs_error = function() { + // don't create more object URLs than needed + if (blob_changed || !object_url) { + object_url = get_object_url(blob); + } + if (target_view) { + target_view.location.href = object_url; + } else { + window.open(object_url, "_blank"); + } + filesaver.readyState = filesaver.DONE; + dispatch_all(); + } + , abortable = function(func) { + return function() { + if (filesaver.readyState !== filesaver.DONE) { + return func.apply(this, arguments); + } + }; + } + , create_if_not_found = {create: true, exclusive: false} + , slice + ; + filesaver.readyState = filesaver.INIT; + if (!name) { + name = "download"; + } + if (can_use_save_link) { + object_url = get_object_url(blob); + save_link.href = object_url; + save_link.download = name; + click(save_link); + filesaver.readyState = filesaver.DONE; + dispatch_all(); + return; + } + // Object and web filesystem URLs have a problem saving in Google Chrome when + // viewed in a tab, so I force save with application/octet-stream + // http://code.google.com/p/chromium/issues/detail?id=91158 + if (view.chrome && type && type !== force_saveable_type) { + slice = blob.slice || blob.webkitSlice; + blob = slice.call(blob, 0, blob.size, force_saveable_type); + blob_changed = true; + } + // Since I can't be sure that the guessed media type will trigger a download + // in WebKit, I append .download to the filename. + // https://bugs.webkit.org/show_bug.cgi?id=65440 + if (webkit_req_fs && name !== "download") { + name += ".download"; + } + if (type === force_saveable_type || webkit_req_fs) { + target_view = view; + } + if (!req_fs) { + fs_error(); + return; + } + fs_min_size += blob.size; + req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { + fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { + var save = function() { + dir.getFile(name, create_if_not_found, abortable(function(file) { + file.createWriter(abortable(function(writer) { + writer.onwriteend = function(event) { + target_view.location.href = file.toURL(); + deletion_queue.push(file); + filesaver.readyState = filesaver.DONE; + dispatch(filesaver, "writeend", event); + }; + writer.onerror = function() { + var error = writer.error; + if (error.code !== error.ABORT_ERR) { + fs_error(); + } + }; + "writestart progress write abort".split(" ").forEach(function(event) { + writer["on" + event] = filesaver["on" + event]; + }); + writer.write(blob); + filesaver.abort = function() { + writer.abort(); + filesaver.readyState = filesaver.DONE; + }; + filesaver.readyState = filesaver.WRITING; + }), fs_error); + }), fs_error); + }; + dir.getFile(name, {create: false}, abortable(function(file) { + // delete file if it already exists + file.remove(); + save(); + }), abortable(function(ex) { + if (ex.code === ex.NOT_FOUND_ERR) { + save(); + } else { + fs_error(); + } + })); + }), fs_error); + }), fs_error); + } + , FS_proto = FileSaver.prototype + , saveAs = function(blob, name) { + return new FileSaver(blob, name); + } + ; + FS_proto.abort = function() { + var filesaver = this; + filesaver.readyState = filesaver.DONE; + dispatch(filesaver, "abort"); + }; + FS_proto.readyState = FS_proto.INIT = 0; + FS_proto.WRITING = 1; + FS_proto.DONE = 2; + + FS_proto.error = + FS_proto.onwritestart = + FS_proto.onprogress = + FS_proto.onwrite = + FS_proto.onabort = + FS_proto.onerror = + FS_proto.onwriteend = + null; + view.addEventListener("unload", process_deletion_queue, false); + return saveAs; +}(self)); + + + +/* The meat and potatoes! */ +download_vcs = function(filename, subject, description, location, begin, end) { + if (navigator.userAgent.indexOf('MSIE') > -1 && navigator.userAgent.indexOf('MSIE 10') == -1) { + console.log('Unsupported Browser'); + return; + }; + + var subject = subject; + var description = description; + var address = location; + var start_date = new Date(begin); + var end_date = new Date(end); + + var start_year = ("0000" + (start_date.getFullYear().toString())).slice(-4); + var start_month = ("00" + (start_date.getMonth().toString())).slice(-2); + var start_day = ("00" + (start_date.getDate().toString())).slice(-2); + var start = start_year + start_month + start_day; + + var end_year = ("0000" + (end_date.getFullYear().toString())).slice(-4); + var end_month = ("00" + (end_date.getMonth().toString())).slice(-2); + var end_day = ("00" + ((end_date.getDate()+1).toString())).slice(-2); + var end = end_year + end_month + end_day; + + var calendar = [ + "BEGIN:VCALENDAR", + "VERSION:2.0", + "BEGIN:VEVENT", + "CLASS:PUBLIC", + "DESCRIPTION:"+description, + "DTSTART;VALUE=DATE:"+start, + "DTEND;VALUE=DATE:"+end, + "LOCATION:"+address, + "SUMMARY;LANGUAGE=en-us:"+subject, + "TRANSP:TRANSPARENT", + "END:VEVENT", + "END:VCALENDAR" + ].join('\n'); + + if (navigator.userAgent.indexOf('MSIE 10') > -1) { // chrome or firefox + var blob = new Blob([calendar]); + } + else { // ie + var bb = new BlobBuilder(); + bb.append(calendar); + var blob = bb.getBlob("text/x-vCalendar;charset=" + document.characterSet); + } + saveAs(blob, filename+".vcs"); +}