39 Commits

Author SHA1 Message Date
Travis Krause 4f2e67a79a fix 2017-09-14 16:02:38 -05:00
Travis Krause 69c046615f fix 2017-09-14 15:58:10 -05:00
Travis Krause 75ced77d82 fix 2017-09-14 15:56:16 -05:00
Travis Krause 895485354a fix 2017-09-14 15:47:13 -05:00
Travis Krause f755c00fad fix 2017-09-14 15:34:32 -05:00
Travis Krause f803d79295 fix 2017-09-14 15:32:55 -05:00
Travis Krause 67cef7f101 fix 2017-09-14 15:31:06 -05:00
Travis Krause f811f5cfa4 fixed demo 2017-09-14 15:28:28 -05:00
Travis Krause 85825f5a7b update 2017-09-14 13:58:56 -05:00
Travis Krause acdaa716ca Updated minified version 2017-09-14 13:56:08 -05:00
Travis Krause e07db639f1 fixed typo 2017-09-14 12:23:18 -05:00
Travis Krause 6677d0568b Fixed bad name 2017-09-14 11:48:28 -05:00
Travis Krause ce02e5d8a9 Adding additional stuff 2017-09-14 11:19:37 -05:00
Travis Krause 1425bdfad3 Merge branch 'master' of https://github.com/nwcell/ics.js 2017-09-14 11:05:22 -05:00
Travis Krause 1edd227f13 Merging bugfix 2017-09-14 11:05:04 -05:00
Travis Krause f8dbe2c5c5 Merge pull request #32 from GeoffreyPlitt/master
fixing "main" section of package.json
2017-09-14 11:04:16 -05:00
Travis Krause 82a31cb801 Merge pull request #29 from blaiseIT/patch-1
grammatical fix on JavaScript
2017-09-14 10:41:47 -05:00
Travis Krause 358d4f4f18 Merge pull request #12 from connorbode/master
create recurring events
2017-09-14 10:35:54 -05:00
Adam Brown fd2d0a81aa Output now passes ical validation
- A few required fields were missing for proper ical validation: PRODID,
UID, DTSTAMP
- Added optional params to configure prodid and uid
- Fixed bug: Start and End times were reporting DATE instead of
DATE-TIME, so some consumers would ignore event times
- Fixed bug: If start/end times only contained hours, no time would be
reported at all
- Added a new method: "build" which simply returns the ical contents
instead of trying to trigger a download
2016-07-31 02:00:23 -07:00
Geoffrey Plitt 40a2c1244c fixing "main" section of package.json 2016-06-06 13:01:35 -07:00
Connor Bode a12cab01e5 Merge pull request #5 from nhunt3/patch-1
Multi-line description bug
2016-05-09 09:29:34 -04:00
Nick Hunt 28cf7546ef Multi-line description bug
I have multi-line descriptions in the calendar I'm exporting from. When I try to import the file that your ics.js program generates into Outlook or Google Calendar, it only pulls in the first line in and it ignores the rest. My solution fixes this. I tested it in both Outlook and Google Calendar and it works and also follows generally accepted ics file formatting standards I believe. As far as I can tell, it doesn't seem to break anything.

Let me know what you think.
Thanks.
2016-05-05 18:05:38 -04:00
Blaise Petric ef20bfeea4 grammatical fix on JavaScript 2016-03-05 01:17:38 -05:00
Connor Bode 17a1b06fdd Merge pull request #2 from jmuia/master
BYDAY property for recurrence events
2015-10-05 20:33:57 -04:00
Connor Bode 387392d04b Merge pull request #1 from asr1/master
Fix minute/second discrepancy
2015-08-17 20:49:52 -04:00
Alex Rinehart e7c3489c2d Fix minute/second bug 2015-08-17 12:18:33 -05:00
Alex Rinehart b18b40fa03 Update README.md
Fixed the 30 minute event to be spelled correctly and actually be 30 minutes (and not 1470 minutes).
2015-06-02 23:56:43 -07:00
jmuia 592454900c Add DTSTAMP to events and remove VALUE=DATE from DTSTART and DTEND properties 2014-08-20 17:29:53 -04:00
jmuia 6502ca83df Add .DS_Store to .gitignore 2014-08-20 17:28:58 -04:00
jmuia 98b22dd60a add BYDAY property to recurrence events 2014-08-20 14:46:26 -04:00
Connor Bode 75369c0184 update readme for recurring events 2014-08-18 20:21:28 -04:00
Connor Bode 64eaacd0b9 add functionality for recurring events 2014-08-18 20:13:42 -04:00
Connor Bode c86d55ac39 failing spec for recurring events 2014-08-18 19:20:30 -04:00
Connor Bode 762d842513 fix tests 2014-08-18 18:53:34 -04:00
Connor Bode 4790ef4156 fix lint 2014-08-18 18:50:17 -04:00
Travis Krause d0359a5e06 Updated js link for mimetype workaround 2014-03-20 00:59:44 -07:00
Travis Krause 2a5ea5d165 Update readme
Documented the new time feature.
2014-03-11 23:05:54 -07:00
Travis Krause b479d03dff Updated versions... 2014-03-11 21:58:38 -08:00
Travis Krause 6369bb98f3 Added time 2014-03-11 21:56:36 -08:00
14 changed files with 498 additions and 210 deletions
+11
View File
@@ -0,0 +1,11 @@
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
# editorconfig-tools is unable to ignore longs strings or urls
max_line_length = null
+1
View File
@@ -1,2 +1,3 @@
node_modules/ node_modules/
bower_components/ bower_components/
.DS_Store
+23 -5
View File
@@ -1,7 +1,7 @@
ics.js ics.js
============ ============
A browser firendly .ics/.vcs file generator written entirely in javascript!!!!!! A browser friendly .ics/.vcs file generator written entirely in JavaScript!
Now you can make calendar friendly files client-side. It outputs .ics files, so the files are compatible with all modern calendar software (Outlook, Apple Calendar, Google, etc.) Now you can make calendar friendly files client-side. It outputs .ics files, so the files are compatible with all modern calendar software (Outlook, Apple Calendar, Google, etc.)
@@ -17,14 +17,32 @@ Simply use invoke the object and use the functions...
`begin` and `end` need to be formatted in a way that is friendly to `Date()` `begin` and `end` need to be formatted in a way that is friendly to `Date()`
Recurring Events
----------------
Recurring events can be added with the `rrule` object.
`cal.addEvent(subject, description, location, begin, end, rrule)`
The `rrule` object has the following properties:
- `freq` : __Required.__ The frequency of event recurrence. Can be `DAILY`, `WEEKLY`, `MONTHLY`, or `YEARLY`.
- `until` : A date string representing the date on which to end repitition. Must be friendly to `Date()`
- `count` : Alternative to until. Repeat the event `count` times. Must be an integer
- `interval` : The interval of `freq` to recur at. For example, if `freq` is `WEEKLY` and `interval` is `2`, the event will repeat every 2 weeks. Must be an integer.
- `byday` : Which days of the week the event is to occur. An array containing any of `SU`, `MO`, `TU`, `WE`, `TH`, `FR`, `SA`.
The four properties described above are not exhaustive of recurrence rule capabilities. If extra functionality is required, you can set the `rrule.rule` property to a full recurrence rule string. In this case, none of the four properties described above are necessary. See [this page](http://www.kanzaki.com/docs/ical/rrule.html) for a description of recurrence rules.
Example Example
------- -------
* **[Demo](http://htmlpreview.github.io/?https://github.com/nwcell/ics.js/blob/master/demo/demo.html)** * **[Demo](https://rawgit.com/nwcell/ics.js/master/demo/demo.html)**
``` ```
<script> <script>
var cal = ics(); var cal = ics();
cal.addEvent('Demo Event', 'This is an awesome demo event', 'Nome, AK', '8/7/2013', '8/9/2013'); cal.addEvent('Demo Event', 'This is an all day event', 'Nome, AK', '8/7/2013', '8/7/2013');
cal.addEvent('Demo Event', 'This is thirty minute event', 'Nome, AK', '8/7/2013 5:30 pm', '8/7/2013 6:00 pm');
</script> </script>
<a href="javascript:cal.download()">Demo</a> <a href="javascript:cal.download()">Demo</a>
``` ```
@@ -38,7 +56,7 @@ The tool uses 2 libraries from the following projects:
I've compressed them and included them into the source for the normal file. Other variations are available in the repo. I've compressed them and included them into the source for the normal file. Other variations are available in the repo.
If you want IE to allow for either opening documents as well as saving documents, you can use my fork of FileSaver.js (https://github.com/nwcell/FileSaver.js) If you want IE to allow for either opening documents as well as saving documents, you can use my fork of FileSaver.js (https://github.com/nwcell/FileSaver.js)... Though you honestly are probebly best off using their main.
Supported Browsers Supported Browsers
------------------ ------------------
@@ -58,4 +76,4 @@ Supported Browsers
Credits Credits
------------------ ------------------
* [Travis Krause](https://github.com/nwcell): Me * [Travis Krause](https://github.com/nwcell): Me
* [Kyle Hornberg](https://github.com/khornberg): Added multi event functionality and made everything a package firendly * [Kyle Hornberg](https://github.com/khornberg): Added multi event functionality and made everything a package firendly
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "ics.js", "name": "ics.js",
"main": "ics.js", "main": "ics.js",
"version": "0.1.2", "version": "0.1.3",
"homepage": "https://github.com/nwcell/ics.js", "homepage": "https://github.com/nwcell/ics.js",
"contributors": [ "contributors": [
"Travis Krause <travis@codeforemen.com>", "Travis Krause <travis@codeforemen.com>",
+87 -50
View File
@@ -1,55 +1,92 @@
<!DOCTYPE html> <!DOCTYPE html>
<head> <head>
<script type="text/javascript" src="../ics.deps.min.js"></script> <style type="text/css">
<script type="text/javascript" src="demo.js"></script> html,
<style> body {
html, body { height: 100%;
height: 100%; width: 100%;
width: 100%; }
}
.wrap { .wrap {
margin: auto; margin: auto;
position: absolute; position: absolute;
top: 0; left: 0; bottom: 0; right: 0; top: 0;
height: 50px; left: 0;
width: 100px; bottom: 0;
} right: 0;
a { height: 50px;
margin-top: 5px; width: 100px;
margin-bottom: 5px; }
display: inline-block;
padding: 6px 12px; a {
margin-bottom: 0; margin-top: 5px;
font-size: 14px; margin-bottom: 5px;
font-weight: normal; display: inline-block;
line-height: 1.428571429; padding: 6px 12px;
text-align: center; margin-bottom: 0;
white-space: nowrap; font-size: 14px;
vertical-align: middle; font-weight: normal;
cursor: pointer; line-height: 1.428571429;
border: 1px solid transparent; text-align: center;
border-radius: 4px; white-space: nowrap;
-webkit-user-select: none; vertical-align: middle;
-moz-user-select: none; cursor: pointer;
-ms-user-select: none; border: 1px solid transparent;
-o-user-select: none; border-radius: 4px;
cursor: pointer; -webkit-user-select: none;
color: #ffffff; -moz-user-select: none;
text-decoration: none; -ms-user-select: none;
font-weight: bold; -o-user-select: none;
background-color: #428bca; cursor: pointer;
border-color: #357ebd; color: #ffffff;
font-family: sans-serif; text-decoration: none;
width: 120px; font-weight: bold;
} background-color: #428bca;
</style> border-color: #357ebd;
font-family: sans-serif;
width: 120px;
}
</style>
<script type="text/javascript">
/*! ics.js Wed Aug 20 2014 17:23:02 */
var saveAs=saveAs||function(e){"use strict";if(typeof e==="undefined"||typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),o="download"in r,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,f=/CriOS\/[\d]+/.test(navigator.userAgent),u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",d=1e3*40,c=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,d)},l=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(a){u(a)}}}},p=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},v=function(t,u,d){if(!d){t=p(t)}var v=this,w=t.type,m=w===s,y,h=function(){l(v,"writestart progress write writeend".split(" "))},S=function(){if((f||m&&i)&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=f?r.result:r.result.replace(/^data:[^;]*;/,"data:attachment/file;");var n=e.open(t,"_blank");if(!n)e.location.href=t;t=undefined;v.readyState=v.DONE;h()};r.readAsDataURL(t);v.readyState=v.INIT;return}if(!y){y=n().createObjectURL(t)}if(m){e.location.href=y}else{var o=e.open(y,"_blank");if(!o){e.location.href=y}}v.readyState=v.DONE;h();c(y)};v.readyState=v.INIT;if(o){y=n().createObjectURL(t);setTimeout(function(){r.href=y;r.download=u;a(r);h();c(y);v.readyState=v.DONE});return}S()},w=v.prototype,m=function(e,t,n){return new v(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=p(e)}return navigator.msSaveOrOpenBlob(e,t)}}w.abort=function(){};w.readyState=w.INIT=0;w.WRITING=1;w.DONE=2;w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null;return m}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!==null){define("FileSaver.js",function(){return saveAs})}
var ics=function(e,t){"use strict";{if(!(navigator.userAgent.indexOf("MSIE")>-1&&-1==navigator.userAgent.indexOf("MSIE 10"))){void 0===e&&(e="default"),void 0===t&&(t="Calendar");var r=-1!==navigator.appVersion.indexOf("Win")?"\r\n":"\n",n=[],i=["BEGIN:VCALENDAR","PRODID:"+t,"VERSION:2.0"].join(r),o=r+"END:VCALENDAR",a=["SU","MO","TU","WE","TH","FR","SA"];return{events:function(){return n},calendar:function(){return i+r+n.join(r)+o},addEvent:function(t,i,o,l,u,s){if(void 0===t||void 0===i||void 0===o||void 0===l||void 0===u)return!1;if(s&&!s.rrule){if("YEARLY"!==s.freq&&"MONTHLY"!==s.freq&&"WEEKLY"!==s.freq&&"DAILY"!==s.freq)throw"Recurrence rrule frequency must be provided and be one of the following: 'YEARLY', 'MONTHLY', 'WEEKLY', or 'DAILY'";if(s.until&&isNaN(Date.parse(s.until)))throw"Recurrence rrule 'until' must be a valid date string";if(s.interval&&isNaN(parseInt(s.interval)))throw"Recurrence rrule 'interval' must be an integer";if(s.count&&isNaN(parseInt(s.count)))throw"Recurrence rrule 'count' must be an integer";if(void 0!==s.byday){if("[object Array]"!==Object.prototype.toString.call(s.byday))throw"Recurrence rrule 'byday' must be an array";if(s.byday.length>7)throw"Recurrence rrule 'byday' array must not be longer than the 7 days in a week";s.byday=s.byday.filter(function(e,t){return s.byday.indexOf(e)==t});for(var c in s.byday)if(a.indexOf(s.byday[c])<0)throw"Recurrence rrule 'byday' values must include only the following: 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'"}}var g=new Date(l),d=new Date(u),f=new Date,S=("0000"+g.getFullYear().toString()).slice(-4),E=("00"+(g.getMonth()+1).toString()).slice(-2),v=("00"+g.getDate().toString()).slice(-2),y=("00"+g.getHours().toString()).slice(-2),A=("00"+g.getMinutes().toString()).slice(-2),T=("00"+g.getSeconds().toString()).slice(-2),b=("0000"+d.getFullYear().toString()).slice(-4),D=("00"+(d.getMonth()+1).toString()).slice(-2),N=("00"+d.getDate().toString()).slice(-2),h=("00"+d.getHours().toString()).slice(-2),I=("00"+d.getMinutes().toString()).slice(-2),R=("00"+d.getMinutes().toString()).slice(-2),M=("0000"+f.getFullYear().toString()).slice(-4),w=("00"+(f.getMonth()+1).toString()).slice(-2),L=("00"+f.getDate().toString()).slice(-2),O=("00"+f.getHours().toString()).slice(-2),p=("00"+f.getMinutes().toString()).slice(-2),Y=("00"+f.getMinutes().toString()).slice(-2),U="",V="";y+A+T+h+I+R!=0&&(U="T"+y+A+T,V="T"+h+I+R);var B,C=S+E+v+U,j=b+D+N+V,m=M+w+L+("T"+O+p+Y);if(s)if(s.rrule)B=s.rrule;else{if(B="rrule:FREQ="+s.freq,s.until){var x=new Date(Date.parse(s.until)).toISOString();B+=";UNTIL="+x.substring(0,x.length-13).replace(/[-]/g,"")+"000000Z"}s.interval&&(B+=";INTERVAL="+s.interval),s.count&&(B+=";COUNT="+s.count),s.byday&&s.byday.length>0&&(B+=";BYDAY="+s.byday.join(","))}(new Date).toISOString();var H=["BEGIN:VEVENT","UID:"+n.length+"@"+e,"CLASS:PUBLIC","DESCRIPTION:"+i,"DTSTAMP;VALUE=DATE-TIME:"+m,"DTSTART;VALUE=DATE-TIME:"+C,"DTEND;VALUE=DATE-TIME:"+j,"LOCATION:"+o,"SUMMARY;LANGUAGE=en-us:"+t,"TRANSP:TRANSPARENT","END:VEVENT"];return B&&H.splice(4,0,B),H=H.join(r),n.push(H),H},download:function(e,t){if(n.length<1)return!1;t=void 0!==t?t:".ics",e=void 0!==e?e:"calendar";var a,l=i+r+n.join(r)+o;if(-1===navigator.userAgent.indexOf("MSIE 10"))a=new Blob([l]);else{var u=new BlobBuilder;u.append(l),a=u.getBlob("text/x-vCalendar;charset="+document.characterSet)}return saveAs(a,e+t),l},build:function(){return!(n.length<1)&&i+r+n.join(r)+o}}}console.log("Unsupported Browser")}};
</script>
<script type="text/javascript">
// Demo
cal = ics();
cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2013', '12/25/2013');
cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2014', '12/25/2014');
cal.addEvent('New Years', 'Watch the ball drop!', 'New York', '01/01/2015', '01/01/2015');
cal.addEvent('New Years', 'Watch the ball drop!', 'New York', '01/01/2016', '01/01/2016');
cal_single = ics();
cal_single.addEvent('Best Day', 'This is the best day to demonstrate a single event.', 'New York', '11/12/1987', '11/12/1987');
// You can use this for easy debugging
makelogs = function(obj) {
console.log('Events Array');
console.log('=================');
console.log(obj.events());
console.log('Calendar With Header');
console.log('=================');
console.log(obj.calendar());
}
</script>
</head> </head>
<body> <body>
<div class="wrap"> <div class="wrap">
<a href="javascript:cal_single.download('Awesome Day')">Single Event</a> <a href="#" onclick="javascript:cal_single.download('Awesome Day')">Single Event</a>
<br> <br>
<a href="javascript:cal.download('Holidays')">Multiple Events</a> <a href="#" onclick="javascript:cal.download('Holidays')">Multiple Events</a>
<br> <br>
<a href="javascript:makelogs(cal)">Console Output</a> <a href="#" onclick="javascript:makelogs(cal)">Console Output</a>
</div> </div>
</html> </html>
+10 -10
View File
@@ -1,20 +1,20 @@
// Demo // Demo
var cal = ics(); cal = ics();
cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2013', '12/25/2013'); cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2013', '12/25/2013');
cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2014', '12/25/2014'); cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2014', '12/25/2014');
cal.addEvent('New Years', 'Watch the ball drop!', 'New York', '01/01/2015', '01/01/2015'); cal.addEvent('New Years', 'Watch the ball drop!', 'New York', '01/01/2015', '01/01/2015');
cal.addEvent('New Years', 'Watch the ball drop!', 'New York', '01/01/2016', '01/01/2016'); cal.addEvent('New Years', 'Watch the ball drop!', 'New York', '01/01/2016', '01/01/2016');
var cal_single = ics(); cal_single = ics();
cal_single.addEvent('Best Day', 'This is the best day to demonstrate a single event.', 'New York', '11/12/1987', '11/12/1987'); cal_single.addEvent('Best Day', 'This is the best day to demonstrate a single event.', 'New York', '11/12/1987', '11/12/1987');
// You can use this for easy debugging // You can use this for easy debugging
var makelogs = function(obj) { makelogs = function(obj) {
console.log('Events Array'); console.log('Events Array');
console.log('================='); console.log('=================');
console.log(obj.events()); console.log(obj.events());
console.log('Calendar With Header'); console.log('Calendar With Header');
console.log('================='); console.log('=================');
console.log(obj.calendar()); console.log(obj.calendar());
} }
+4
View File
@@ -0,0 +1,4 @@
/*! ics.js Wed Aug 20 2014 17:23:02 */
var saveAs=saveAs||function(e){"use strict";if(typeof e==="undefined"||typeof navigator!=="undefined"&&/MSIE [1-9]\./.test(navigator.userAgent)){return}var t=e.document,n=function(){return e.URL||e.webkitURL||e},r=t.createElementNS("http://www.w3.org/1999/xhtml","a"),o="download"in r,a=function(e){var t=new MouseEvent("click");e.dispatchEvent(t)},i=/constructor/i.test(e.HTMLElement)||e.safari,f=/CriOS\/[\d]+/.test(navigator.userAgent),u=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},s="application/octet-stream",d=1e3*40,c=function(e){var t=function(){if(typeof e==="string"){n().revokeObjectURL(e)}else{e.remove()}};setTimeout(t,d)},l=function(e,t,n){t=[].concat(t);var r=t.length;while(r--){var o=e["on"+t[r]];if(typeof o==="function"){try{o.call(e,n||e)}catch(a){u(a)}}}},p=function(e){if(/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(e.type)){return new Blob([String.fromCharCode(65279),e],{type:e.type})}return e},v=function(t,u,d){if(!d){t=p(t)}var v=this,w=t.type,m=w===s,y,h=function(){l(v,"writestart progress write writeend".split(" "))},S=function(){if((f||m&&i)&&e.FileReader){var r=new FileReader;r.onloadend=function(){var t=f?r.result:r.result.replace(/^data:[^;]*;/,"data:attachment/file;");var n=e.open(t,"_blank");if(!n)e.location.href=t;t=undefined;v.readyState=v.DONE;h()};r.readAsDataURL(t);v.readyState=v.INIT;return}if(!y){y=n().createObjectURL(t)}if(m){e.location.href=y}else{var o=e.open(y,"_blank");if(!o){e.location.href=y}}v.readyState=v.DONE;h();c(y)};v.readyState=v.INIT;if(o){y=n().createObjectURL(t);setTimeout(function(){r.href=y;r.download=u;a(r);h();c(y);v.readyState=v.DONE});return}S()},w=v.prototype,m=function(e,t,n){return new v(e,t||e.name||"download",n)};if(typeof navigator!=="undefined"&&navigator.msSaveOrOpenBlob){return function(e,t,n){t=t||e.name||"download";if(!n){e=p(e)}return navigator.msSaveOrOpenBlob(e,t)}}w.abort=function(){};w.readyState=w.INIT=0;w.WRITING=1;w.DONE=2;w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null;return m}(typeof self!=="undefined"&&self||typeof window!=="undefined"&&window||this.content);if(typeof module!=="undefined"&&module.exports){module.exports.saveAs=saveAs}else if(typeof define!=="undefined"&&define!==null&&define.amd!==null){define("FileSaver.js",function(){return saveAs})}
var ics=function(e,t){"use strict";{if(!(navigator.userAgent.indexOf("MSIE")>-1&&-1==navigator.userAgent.indexOf("MSIE 10"))){void 0===e&&(e="default"),void 0===t&&(t="Calendar");var r=-1!==navigator.appVersion.indexOf("Win")?"\r\n":"\n",n=[],i=["BEGIN:VCALENDAR","PRODID:"+t,"VERSION:2.0"].join(r),o=r+"END:VCALENDAR",a=["SU","MO","TU","WE","TH","FR","SA"];return{events:function(){return n},calendar:function(){return i+r+n.join(r)+o},addEvent:function(t,i,o,l,u,s){if(void 0===t||void 0===i||void 0===o||void 0===l||void 0===u)return!1;if(s&&!s.rrule){if("YEARLY"!==s.freq&&"MONTHLY"!==s.freq&&"WEEKLY"!==s.freq&&"DAILY"!==s.freq)throw"Recurrence rrule frequency must be provided and be one of the following: 'YEARLY', 'MONTHLY', 'WEEKLY', or 'DAILY'";if(s.until&&isNaN(Date.parse(s.until)))throw"Recurrence rrule 'until' must be a valid date string";if(s.interval&&isNaN(parseInt(s.interval)))throw"Recurrence rrule 'interval' must be an integer";if(s.count&&isNaN(parseInt(s.count)))throw"Recurrence rrule 'count' must be an integer";if(void 0!==s.byday){if("[object Array]"!==Object.prototype.toString.call(s.byday))throw"Recurrence rrule 'byday' must be an array";if(s.byday.length>7)throw"Recurrence rrule 'byday' array must not be longer than the 7 days in a week";s.byday=s.byday.filter(function(e,t){return s.byday.indexOf(e)==t});for(var c in s.byday)if(a.indexOf(s.byday[c])<0)throw"Recurrence rrule 'byday' values must include only the following: 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'"}}var g=new Date(l),d=new Date(u),f=new Date,S=("0000"+g.getFullYear().toString()).slice(-4),E=("00"+(g.getMonth()+1).toString()).slice(-2),v=("00"+g.getDate().toString()).slice(-2),y=("00"+g.getHours().toString()).slice(-2),A=("00"+g.getMinutes().toString()).slice(-2),T=("00"+g.getSeconds().toString()).slice(-2),b=("0000"+d.getFullYear().toString()).slice(-4),D=("00"+(d.getMonth()+1).toString()).slice(-2),N=("00"+d.getDate().toString()).slice(-2),h=("00"+d.getHours().toString()).slice(-2),I=("00"+d.getMinutes().toString()).slice(-2),R=("00"+d.getMinutes().toString()).slice(-2),M=("0000"+f.getFullYear().toString()).slice(-4),w=("00"+(f.getMonth()+1).toString()).slice(-2),L=("00"+f.getDate().toString()).slice(-2),O=("00"+f.getHours().toString()).slice(-2),p=("00"+f.getMinutes().toString()).slice(-2),Y=("00"+f.getMinutes().toString()).slice(-2),U="",V="";y+A+T+h+I+R!=0&&(U="T"+y+A+T,V="T"+h+I+R);var B,C=S+E+v+U,j=b+D+N+V,m=M+w+L+("T"+O+p+Y);if(s)if(s.rrule)B=s.rrule;else{if(B="rrule:FREQ="+s.freq,s.until){var x=new Date(Date.parse(s.until)).toISOString();B+=";UNTIL="+x.substring(0,x.length-13).replace(/[-]/g,"")+"000000Z"}s.interval&&(B+=";INTERVAL="+s.interval),s.count&&(B+=";COUNT="+s.count),s.byday&&s.byday.length>0&&(B+=";BYDAY="+s.byday.join(","))}(new Date).toISOString();var H=["BEGIN:VEVENT","UID:"+n.length+"@"+e,"CLASS:PUBLIC","DESCRIPTION:"+i,"DTSTAMP;VALUE=DATE-TIME:"+m,"DTSTART;VALUE=DATE-TIME:"+C,"DTEND;VALUE=DATE-TIME:"+j,"LOCATION:"+o,"SUMMARY;LANGUAGE=en-us:"+t,"TRANSP:TRANSPARENT","END:VEVENT"];return B&&H.splice(4,0,B),H=H.join(r),n.push(H),H},download:function(e,t){if(n.length<1)return!1;t=void 0!==t?t:".ics",e=void 0!==e?e:"calendar";var a,l=i+r+n.join(r)+o;if(-1===navigator.userAgent.indexOf("MSIE 10"))a=new Blob([l]);else{var u=new BlobBuilder;u.append(l),a=u.getBlob("text/x-vCalendar;charset="+document.characterSet)}return saveAs(a,e+t),l},build:function(){return!(n.length<1)&&i+r+n.join(r)+o}}}console.log("Unsupported Browser")}};
+45
View File
@@ -0,0 +1,45 @@
html,
body {
height: 100%;
width: 100%;
}
.wrap {
margin: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
height: 50px;
width: 100px;
}
a {
margin-top: 5px;
margin-bottom: 5px;
display: inline-block;
padding: 6px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.428571429;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
border-radius: 4px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
cursor: pointer;
color: #ffffff;
text-decoration: none;
font-weight: bold;
background-color: #428bca;
border-color: #357ebd;
font-family: sans-serif;
width: 120px;
}
+4 -2
View File
File diff suppressed because one or more lines are too long
+225 -82
View File
@@ -1,97 +1,240 @@
/* global saveAs, Blob, BlobBuilder, console */ /* global saveAs, Blob, BlobBuilder, console */
/* exported ics */ /* exported ics */
var ics = function() { var ics = function(uidDomain, prodId) {
'use strict'; 'use strict';
if (navigator.userAgent.indexOf('MSIE') > -1 && navigator.userAgent.indexOf('MSIE 10') == -1) { if (navigator.userAgent.indexOf('MSIE') > -1 && navigator.userAgent.indexOf('MSIE 10') == -1) {
console.log('Unsupported Browser'); console.log('Unsupported Browser');
return; return;
} }
var SEPARATOR = (navigator.appVersion.indexOf('Win') !== -1) ? '\r\n' : '\n'; if (typeof uidDomain === 'undefined') { uidDomain = 'default'; }
var calendarEvents = []; if (typeof prodId === 'undefined') { prodId = 'Calendar'; }
var calendarStart = [
'BEGIN:VCALENDAR',
'VERSION:2.0'
].join(SEPARATOR);
var calendarEnd = SEPARATOR + 'END:VCALENDAR';
return { var SEPARATOR = (navigator.appVersion.indexOf('Win') !== -1) ? '\r\n' : '\n';
/** var calendarEvents = [];
* Returns events array var calendarStart = [
* @return {array} Events 'BEGIN:VCALENDAR',
*/ 'PRODID:' + prodId,
'events' : function () { 'VERSION:2.0'
return calendarEvents; ].join(SEPARATOR);
}, var calendarEnd = SEPARATOR + 'END:VCALENDAR';
var BYDAY_VALUES = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
/** return {
* Returns calendar /**
* @return {string} Calendar in iCalendar format * Returns events array
*/ * @return {array} Events
'calendar' : function () { */
return calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd; 'events': function() {
}, return calendarEvents;
},
/** /**
* Add event to the calendar * Returns calendar
* @param {string} subject Subject/Title of event * @return {string} Calendar in iCalendar format
* @param {string} description Description of event */
* @param {string} location Location of event 'calendar': function() {
* @param {string} begin Beginning date of event return calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd;
* @param {string} stop Ending date of event },
*/
'addEvent' : function (subject, description, location, begin, stop) {
//TODO add time and time zone? use moment to format?
var start_date = new Date(begin);
var end_date = new Date(stop);
var start_year = ('0000' + (start_date.getFullYear().toString())).slice(-4); /**
var start_month = ('00' + ((start_date.getMonth() + 1).toString())).slice(-2); * Add event to the calendar
var start_day = ('00' + (start_date.getDate().toString())).slice(-2); * @param {string} subject Subject/Title of event
var start = start_year + start_month + start_day; * @param {string} description Description of event
* @param {string} location Location of event
* @param {string} begin Beginning date of event
* @param {string} stop Ending date of event
*/
'addEvent': function(subject, description, location, begin, stop, rrule) {
// I'm not in the mood to make these optional... So they are all required
if (typeof subject === 'undefined' ||
typeof description === 'undefined' ||
typeof location === 'undefined' ||
typeof begin === 'undefined' ||
typeof stop === 'undefined'
) {
return false;
}
var end_year = ('0000' + (end_date.getFullYear().toString())).slice(-4); // validate rrule
var end_month = ('00' + ((end_date.getMonth() + 1).toString())).slice(-2); if (rrule) {
var end_day = ('00' + (end_date.getDate().toString())).slice(-2); if (!rrule.rrule) {
var end = end_year + end_month + end_day; if (rrule.freq !== 'YEARLY' && rrule.freq !== 'MONTHLY' && rrule.freq !== 'WEEKLY' && rrule.freq !== 'DAILY') {
throw "Recurrence rrule frequency must be provided and be one of the following: 'YEARLY', 'MONTHLY', 'WEEKLY', or 'DAILY'";
}
var calendarEvent = [ if (rrule.until) {
'BEGIN:VEVENT', if (isNaN(Date.parse(rrule.until))) {
'CLASS:PUBLIC', throw "Recurrence rrule 'until' must be a valid date string";
'DESCRIPTION:'+description, }
'DTSTART;VALUE=DATE:'+start, }
'DTEND;VALUE=DATE:'+end,
'LOCATION:'+location,
'SUMMARY;LANGUAGE=en-us:'+subject,
'TRANSP:TRANSPARENT',
'END:VEVENT'
].join(SEPARATOR);
calendarEvents.push(calendarEvent); if (rrule.interval) {
}, if (isNaN(parseInt(rrule.interval))) {
throw "Recurrence rrule 'interval' must be an integer";
}
}
/** if (rrule.count) {
* Download calendar using the saveAs function from filesave.js if (isNaN(parseInt(rrule.count))) {
* @param {string} filename Filename throw "Recurrence rrule 'count' must be an integer";
* @param {string} ext Extention }
*/ }
'download' : function (filename, ext) {
ext = (typeof ext !== 'undefined') ? ext : '.ics';
filename = (typeof filename !== 'undefined') ? filename : 'calendar';
var calendar = calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd;
var blob; if (typeof rrule.byday !== 'undefined') {
if (navigator.userAgent.indexOf('MSIE 10') === -1) { // chrome or firefox if ((Object.prototype.toString.call(rrule.byday) !== '[object Array]')) {
blob = new Blob([calendar]); throw "Recurrence rrule 'byday' must be an array";
} }
else { // ie
var bb = new BlobBuilder(); if (rrule.byday.length > 7) {
bb.append(calendar); throw "Recurrence rrule 'byday' array must not be longer than the 7 days in a week";
blob = bb.getBlob('text/x-vCalendar;charset=' + document.characterSet); }
}
saveAs(blob, filename+ext); // Filter any possible repeats
} rrule.byday = rrule.byday.filter(function(elem, pos) {
}; return rrule.byday.indexOf(elem) == pos;
});
for (var d in rrule.byday) {
if (BYDAY_VALUES.indexOf(rrule.byday[d]) < 0) {
throw "Recurrence rrule 'byday' values must include only the following: 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'";
}
}
}
}
}
//TODO add time and time zone? use moment to format?
var start_date = new Date(begin);
var end_date = new Date(stop);
var now_date = new Date();
var start_year = ("0000" + (start_date.getFullYear().toString())).slice(-4);
var start_month = ("00" + ((start_date.getMonth() + 1).toString())).slice(-2);
var start_day = ("00" + ((start_date.getDate()).toString())).slice(-2);
var start_hours = ("00" + (start_date.getHours().toString())).slice(-2);
var start_minutes = ("00" + (start_date.getMinutes().toString())).slice(-2);
var start_seconds = ("00" + (start_date.getSeconds().toString())).slice(-2);
var end_year = ("0000" + (end_date.getFullYear().toString())).slice(-4);
var end_month = ("00" + ((end_date.getMonth() + 1).toString())).slice(-2);
var end_day = ("00" + ((end_date.getDate()).toString())).slice(-2);
var end_hours = ("00" + (end_date.getHours().toString())).slice(-2);
var end_minutes = ("00" + (end_date.getMinutes().toString())).slice(-2);
var end_seconds = ("00" + (end_date.getMinutes().toString())).slice(-2);
var now_year = ("0000" + (now_date.getFullYear().toString())).slice(-4);
var now_month = ("00" + ((now_date.getMonth() + 1).toString())).slice(-2);
var now_day = ("00" + ((now_date.getDate()).toString())).slice(-2);
var now_hours = ("00" + (now_date.getHours().toString())).slice(-2);
var now_minutes = ("00" + (now_date.getMinutes().toString())).slice(-2);
var now_seconds = ("00" + (now_date.getMinutes().toString())).slice(-2);
// Since some calendars don't add 0 second events, we need to remove time if there is none...
var start_time = '';
var end_time = '';
if (start_hours + start_minutes + start_seconds + end_hours + end_minutes + end_seconds != 0) {
start_time = 'T' + start_hours + start_minutes + start_seconds;
end_time = 'T' + end_hours + end_minutes + end_seconds;
}
var now_time = 'T' + now_hours + now_minutes + now_seconds;
var start = start_year + start_month + start_day + start_time;
var end = end_year + end_month + end_day + end_time;
var now = now_year + now_month + now_day + now_time;
// recurrence rrule vars
var rruleString;
if (rrule) {
if (rrule.rrule) {
rruleString = rrule.rrule;
} else {
rruleString = 'rrule:FREQ=' + rrule.freq;
if (rrule.until) {
var uDate = new Date(Date.parse(rrule.until)).toISOString();
rruleString += ';UNTIL=' + uDate.substring(0, uDate.length - 13).replace(/[-]/g, '') + '000000Z';
}
if (rrule.interval) {
rruleString += ';INTERVAL=' + rrule.interval;
}
if (rrule.count) {
rruleString += ';COUNT=' + rrule.count;
}
if (rrule.byday && rrule.byday.length > 0) {
rruleString += ';BYDAY=' + rrule.byday.join(',');
}
}
}
var stamp = new Date().toISOString();
var calendarEvent = [
'BEGIN:VEVENT',
'UID:' + calendarEvents.length + "@" + uidDomain,
'CLASS:PUBLIC',
'DESCRIPTION:' + description,
'DTSTAMP;VALUE=DATE-TIME:' + now,
'DTSTART;VALUE=DATE-TIME:' + start,
'DTEND;VALUE=DATE-TIME:' + end,
'LOCATION:' + location,
'SUMMARY;LANGUAGE=en-us:' + subject,
'TRANSP:TRANSPARENT',
'END:VEVENT'
];
if (rruleString) {
calendarEvent.splice(4, 0, rruleString);
}
calendarEvent = calendarEvent.join(SEPARATOR);
calendarEvents.push(calendarEvent);
return calendarEvent;
},
/**
* Download calendar using the saveAs function from filesave.js
* @param {string} filename Filename
* @param {string} ext Extention
*/
'download': function(filename, ext) {
if (calendarEvents.length < 1) {
return false;
}
ext = (typeof ext !== 'undefined') ? ext : '.ics';
filename = (typeof filename !== 'undefined') ? filename : 'calendar';
var calendar = calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd;
var blob;
if (navigator.userAgent.indexOf('MSIE 10') === -1) { // chrome or firefox
blob = new Blob([calendar]);
} else { // ie
var bb = new BlobBuilder();
bb.append(calendar);
blob = bb.getBlob('text/x-vCalendar;charset=' + document.characterSet);
}
saveAs(blob, filename + ext);
return calendar;
},
/**
* Build and return the ical contents
*/
'build': function() {
if (calendarEvents.length < 1) {
return false;
}
var calendar = calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd;
return calendar;
}
};
}; };
Vendored
+2 -2
View File
@@ -1,2 +1,2 @@
/*! ics.js Thu Dec 19 2013 14:54:06 */ /*! ics.js Wed Sept 14 2017 */
var ics=function(){"use strict";if(navigator.userAgent.indexOf("MSIE")>-1&&-1==navigator.userAgent.indexOf("MSIE 10"))return console.log("Unsupported Browser"),void 0;var a=-1!==navigator.appVersion.indexOf("Win")?"\r\n":"\n",b=[],c=["BEGIN:VCALENDAR","VERSION:2.0"].join(a),d=a+"END:VCALENDAR";return{events:function(){return b},calendar:function(){return c+a+b.join(a)+d},addEvent:function(c,d,e,f,g){var h=new Date(f),i=new Date(g),j=("0000"+h.getFullYear().toString()).slice(-4),k=("00"+(h.getMonth()+1).toString()).slice(-2),l=("00"+h.getDate().toString()).slice(-2),m=j+k+l,n=("0000"+i.getFullYear().toString()).slice(-4),o=("00"+(i.getMonth()+1).toString()).slice(-2),p=("00"+i.getDate().toString()).slice(-2),q=n+o+p,r=["BEGIN:VEVENT","CLASS:PUBLIC","DESCRIPTION:"+d,"DTSTART;VALUE=DATE:"+m,"DTEND;VALUE=DATE:"+q,"LOCATION:"+e,"SUMMARY;LANGUAGE=en-us:"+c,"TRANSP:TRANSPARENT","END:VEVENT"].join(a);b.push(r)},download:function(e,f){f="undefined"!=typeof f?f:".ics",e="undefined"!=typeof e?e:"calendar";var g,h=c+a+b.join(a)+d;if(-1===navigator.userAgent.indexOf("MSIE 10"))g=new Blob([h]);else{var i=new BlobBuilder;i.append(h),g=i.getBlob("text/x-vCalendar;charset="+document.characterSet)}saveAs(g,e+f)}}}; var ics=function(e,t){"use strict";{if(!(navigator.userAgent.indexOf("MSIE")>-1&&-1==navigator.userAgent.indexOf("MSIE 10"))){void 0===e&&(e="default"),void 0===t&&(t="Calendar");var r=-1!==navigator.appVersion.indexOf("Win")?"\r\n":"\n",n=[],i=["BEGIN:VCALENDAR","PRODID:"+t,"VERSION:2.0"].join(r),o=r+"END:VCALENDAR",a=["SU","MO","TU","WE","TH","FR","SA"];return{events:function(){return n},calendar:function(){return i+r+n.join(r)+o},addEvent:function(t,i,o,l,u,s){if(void 0===t||void 0===i||void 0===o||void 0===l||void 0===u)return!1;if(s&&!s.rrule){if("YEARLY"!==s.freq&&"MONTHLY"!==s.freq&&"WEEKLY"!==s.freq&&"DAILY"!==s.freq)throw"Recurrence rrule frequency must be provided and be one of the following: 'YEARLY', 'MONTHLY', 'WEEKLY', or 'DAILY'";if(s.until&&isNaN(Date.parse(s.until)))throw"Recurrence rrule 'until' must be a valid date string";if(s.interval&&isNaN(parseInt(s.interval)))throw"Recurrence rrule 'interval' must be an integer";if(s.count&&isNaN(parseInt(s.count)))throw"Recurrence rrule 'count' must be an integer";if(void 0!==s.byday){if("[object Array]"!==Object.prototype.toString.call(s.byday))throw"Recurrence rrule 'byday' must be an array";if(s.byday.length>7)throw"Recurrence rrule 'byday' array must not be longer than the 7 days in a week";s.byday=s.byday.filter(function(e,t){return s.byday.indexOf(e)==t});for(var c in s.byday)if(a.indexOf(s.byday[c])<0)throw"Recurrence rrule 'byday' values must include only the following: 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'"}}var g=new Date(l),d=new Date(u),f=new Date,S=("0000"+g.getFullYear().toString()).slice(-4),E=("00"+(g.getMonth()+1).toString()).slice(-2),v=("00"+g.getDate().toString()).slice(-2),y=("00"+g.getHours().toString()).slice(-2),A=("00"+g.getMinutes().toString()).slice(-2),T=("00"+g.getSeconds().toString()).slice(-2),b=("0000"+d.getFullYear().toString()).slice(-4),D=("00"+(d.getMonth()+1).toString()).slice(-2),N=("00"+d.getDate().toString()).slice(-2),h=("00"+d.getHours().toString()).slice(-2),I=("00"+d.getMinutes().toString()).slice(-2),R=("00"+d.getMinutes().toString()).slice(-2),M=("0000"+f.getFullYear().toString()).slice(-4),w=("00"+(f.getMonth()+1).toString()).slice(-2),L=("00"+f.getDate().toString()).slice(-2),O=("00"+f.getHours().toString()).slice(-2),p=("00"+f.getMinutes().toString()).slice(-2),Y=("00"+f.getMinutes().toString()).slice(-2),U="",V="";y+A+T+h+I+R!=0&&(U="T"+y+A+T,V="T"+h+I+R);var B,C=S+E+v+U,j=b+D+N+V,m=M+w+L+("T"+O+p+Y);if(s)if(s.rrule)B=s.rrule;else{if(B="rrule:FREQ="+s.freq,s.until){var x=new Date(Date.parse(s.until)).toISOString();B+=";UNTIL="+x.substring(0,x.length-13).replace(/[-]/g,"")+"000000Z"}s.interval&&(B+=";INTERVAL="+s.interval),s.count&&(B+=";COUNT="+s.count),s.byday&&s.byday.length>0&&(B+=";BYDAY="+s.byday.join(","))}(new Date).toISOString();var H=["BEGIN:VEVENT","UID:"+n.length+"@"+e,"CLASS:PUBLIC","DESCRIPTION:"+i,"DTSTAMP;VALUE=DATE-TIME:"+m,"DTSTART;VALUE=DATE-TIME:"+C,"DTEND;VALUE=DATE-TIME:"+j,"LOCATION:"+o,"SUMMARY;LANGUAGE=en-us:"+t,"TRANSP:TRANSPARENT","END:VEVENT"];return B&&H.splice(4,0,B),H=H.join(r),n.push(H),H},download:function(e,t){if(n.length<1)return!1;t=void 0!==t?t:".ics",e=void 0!==e?e:"calendar";var a,l=i+r+n.join(r)+o;if(-1===navigator.userAgent.indexOf("MSIE 10"))a=new Blob([l]);else{var u=new BlobBuilder;u.append(l),a=u.getBlob("text/x-vCalendar;charset="+document.characterSet)}return saveAs(a,e+t),l},build:function(){return!(n.length<1)&&i+r+n.join(r)+o}}}console.log("Unsupported Browser")}};
+5 -4
View File
@@ -1,15 +1,16 @@
{ {
"name": "ics.js", "name": "ics.js",
"version": "0.1.2", "version": "0.1.3",
"description": "A browser firendly .ics/.vcs file generator written entirely in javascript", "description": "A browser firendly .ics/.vcs file generator written entirely in javascript",
"main": "icsjs", "main": "ics.js",
"dependencies": { "dependencies": {
"bower": "~1.2.8",
"file-saver": "^1.3.3",
"grunt": "~0.4.2", "grunt": "~0.4.2",
"grunt-contrib-concat": "~0.3.0", "grunt-contrib-concat": "~0.3.0",
"grunt-contrib-jshint": "~0.7.2", "grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-uglify": "~0.2.7", "grunt-contrib-uglify": "~0.2.7",
"grunt-mocha": "~0.4.6", "grunt-mocha": "~0.4.6"
"bower": "~1.2.8"
}, },
"devDependencies": {}, "devDependencies": {},
"scripts": { "scripts": {
+15 -15
View File
@@ -1,24 +1,24 @@
<!doctype html> <!doctype html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Mocha Spec Runner</title> <title>Mocha Spec Runner</title>
<link rel="stylesheet" href="lib/mocha/mocha.css"> <link rel="stylesheet" href="lib/mocha/mocha.css">
</head> </head>
<body> <body>
<div id="mocha"></div> <div id="mocha"></div>
<script src="lib/mocha/mocha.js"></script> <script src="lib/mocha/mocha.js"></script>
<script>mocha.setup('bdd')</script> <script>mocha.setup('bdd')</script>
<!-- assertion framework --> <!-- assertion framework -->
<script src="lib/chai.js"></script> <script src="lib/chai.js"></script>
<script>var assert = chai.assert</script> <script>var assert = chai.assert</script>
<!-- include source files here... --> <!-- include source files here... -->
<script src="../ics.js"></script> <script src="../ics.js"></script>
<script>var cal = ics();</script> <script>var cal = ics();</script>
<!-- include spec files here... --> <!-- include spec files here... -->
<script src="spec/test.js"></script> <script src="spec/test.js"></script>
</body> </body>
</html> </html>
+65 -39
View File
@@ -1,45 +1,71 @@
/*global describe, it, cal, assert */ /*global describe, it, cal, assert */
(function () { (function () {
'use strict'; 'use strict';
describe('Load ics Object', function () {
describe('Calendar Events Array', function () { var stamp = new Date().toISOString();
it('should be an empty array initially', function () { stamp = stamp.substring(0, stamp.length - 13).replace(/[-]/g, '') + '000000Z';
assert.isArray(cal.events(), 'calendarEvents not an array');
assert.lengthOf(cal.events(), '0'); describe('Load ics Object', function () {
}); describe('Calendar Events Array', function () {
}); it('should be an empty array initially', function () {
describe('Calendar String', function () { assert.isArray(cal.events(), 'calendarEvents not an array');
it('should be a string with no events', function () { assert.lengthOf(cal.events(), '0');
assert.strictEqual(cal.calendar(), 'BEGIN:VCALENDAR\nVERSION:2.0\n\nEND:VCALENDAR', 'calendar does not match'); });
});
});
}); });
describe('Add 1 Event', function () { describe('Calendar String', function () {
describe('Calendar Events Array', function () { it('should be a string with no events', function () {
it('should have one event', function () { assert.strictEqual(cal.calendar(), 'BEGIN:VCALENDAR\nVERSION:2.0\n\nEND:VCALENDAR', 'calendar does not match');
cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2013', '12/25/2013'); });
assert.isArray(cal.events(), 'calendarEvents not an array');
assert.lengthOf(cal.events(), '1');
assert.strictEqual(cal.events()[0], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Christian holiday celebrating the birth of Jesus Christ\nDTSTART;VALUE=DATE:20131225\nDTEND;VALUE=DATE:20131225\nLOCATION:Bethlehem\nSUMMARY;LANGUAGE=en-us:Christmas\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
});
describe('Calendar String', function () {
it('should have one event', function () {
assert.strictEqual(cal.calendar(), 'BEGIN:VCALENDAR\nVERSION:2.0\nBEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Christian holiday celebrating the birth of Jesus Christ\nDTSTART;VALUE=DATE:20131225\nDTEND;VALUE=DATE:20131225\nLOCATION:Bethlehem\nSUMMARY;LANGUAGE=en-us:Christmas\nTRANSP:TRANSPARENT\nEND:VEVENT\nEND:VCALENDAR', 'calendar does not match');
});
});
describe('Calendar String of Single Digit Months', function () {
it('should have one event', function () {
cal.addEvent('Easter', 'Christian holiday celebrating the resurrection of Jesus Christ', 'Jerusalem', '04/20/2014', '04/20/2014');
assert.strictEqual(cal.events()[1], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Christian holiday celebrating the resurrection of Jesus Christ\nDTSTART;VALUE=DATE:20140420\nDTEND;VALUE=DATE:20140420\nLOCATION:Jerusalem\nSUMMARY;LANGUAGE=en-us:Easter\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
});
describe('Calendar String of Single Digit Day', function () {
it('should have one event', function () {
cal.addEvent('April Fools Day', 'What isn\'t is', 'America', '4/1/2014', '4/1/2014');
assert.strictEqual(cal.events()[2], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:What isn\'t is\nDTSTART;VALUE=DATE:20140401\nDTEND;VALUE=DATE:20140401\nLOCATION:America\nSUMMARY;LANGUAGE=en-us:April Fools Day\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
});
}); });
});
describe('Add 1 Event', function () {
describe('Calendar Events Array', function () {
it('should have one event', function () {
cal.addEvent('Christmas', 'Christian holiday celebrating the birth of Jesus Christ', 'Bethlehem', '12/25/2013', '12/25/2013');
assert.isArray(cal.events(), 'calendarEvents not an array');
assert.lengthOf(cal.events(), '1');
assert.strictEqual(cal.events()[0], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Christian holiday celebrating the birth of Jesus Christ\nDTSTART:20131225T000000\nDTEND:20131225T000000\nDTSTAMP:' + stamp + '\nLOCATION:Bethlehem\nSUMMARY;LANGUAGE=en-us:Christmas\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
});
describe('Calendar String', function () {
it('should have one event', function () {
assert.strictEqual(cal.calendar(), 'BEGIN:VCALENDAR\nVERSION:2.0\nBEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Christian holiday celebrating the birth of Jesus Christ\nDTSTART:20131225T000000\nDTEND:20131225T000000\nDTSTAMP:' + stamp + '\nLOCATION:Bethlehem\nSUMMARY;LANGUAGE=en-us:Christmas\nTRANSP:TRANSPARENT\nEND:VEVENT\nEND:VCALENDAR', 'calendar does not match');
});
});
describe('Calendar String of Single Digit Months', function () {
it('should have one event', function () {
cal.addEvent('Easter', 'Christian holiday celebrating the resurrection of Jesus Christ', 'Jerusalem', '04/20/2014', '04/20/2014');
assert.strictEqual(cal.events()[1], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Christian holiday celebrating the resurrection of Jesus Christ\nDTSTART:20140420T000000\nDTEND:20140420T000000\nDTSTAMP:' + stamp + '\nLOCATION:Jerusalem\nSUMMARY;LANGUAGE=en-us:Easter\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
});
describe('Calendar String of Single Digit Day', function () {
it('should have one event', function () {
cal.addEvent('April Fools Day', 'What isn\'t is', 'America', '4/1/2014', '4/1/2014');
assert.strictEqual(cal.events()[2], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:What isn\'t is\nDTSTART:20140401T000000\nDTEND:20140401T000000\nDTSTAMP:' + stamp + '\nLOCATION:America\nSUMMARY;LANGUAGE=en-us:April Fools Day\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
});
describe('Recurring Events', function () {
it('should add recurring events using frequency and until', function () {
cal.addEvent('Soccer Practice', 'Practice kicking the ball in the net! YAYY!!', 'Soccer field', '08/18/2014', '09/18/2014', {freq: 'WEEKLY', until: '08/18/2014'});
assert.strictEqual(cal.events()[3], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Practice kicking the ball in the net! YAYY!!\nDTSTART:20140818T000000\nRRULE:FREQ=WEEKLY;UNTIL=20140818T000000Z\nDTEND:20140918T000000\nDTSTAMP:' + stamp + '\nLOCATION:Soccer field\nSUMMARY;LANGUAGE=en-us:Soccer Practice\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
it('should add recurring events using interval and count', function () {
cal.addEvent('Soccer Practice', 'Practice kicking the ball in the net! YAYY!!', 'Soccer field', '08/18/2014', '09/18/2014', {freq: 'WEEKLY', interval: 2, count: 10});
assert.strictEqual(cal.events()[4], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Practice kicking the ball in the net! YAYY!!\nDTSTART:20140818T000000\nRRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=10\nDTEND:20140918T000000\nDTSTAMP:' + stamp + '\nLOCATION:Soccer field\nSUMMARY;LANGUAGE=en-us:Soccer Practice\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
it('should add recurring events using interval and until and byday', function () {
cal.addEvent('Soccer Practice', 'Practice kicking the ball in the net! YAYY!!', 'Soccer field', '08/18/2014', '09/18/2014', {freq: 'WEEKLY', interval: 1, until: '08/18/2014', byday: ['MO','WE','FR']});
assert.strictEqual(cal.events()[5], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Practice kicking the ball in the net! YAYY!!\nDTSTART:20140818T000000\nRRULE:FREQ=WEEKLY;UNTIL=20140818T000000Z;INTERVAL=1;BYDAY=MO,WE,FR\nDTEND:20140918T000000\nDTSTAMP:' + stamp + '\nLOCATION:Soccer field\nSUMMARY;LANGUAGE=en-us:Soccer Practice\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
it('should add recurring events using interval and until and ignore duplicates in byday array', function () {
cal.addEvent('Soccer Practice', 'Practice kicking the ball in the net! YAYY!!', 'Soccer field', '08/18/2014', '09/18/2014', {freq: 'WEEKLY', interval: 1, until: '08/18/2014', byday: ['MO', 'WE', 'MO']});
assert.strictEqual(cal.events()[6], 'BEGIN:VEVENT\nCLASS:PUBLIC\nDESCRIPTION:Practice kicking the ball in the net! YAYY!!\nDTSTART:20140818T000000\nRRULE:FREQ=WEEKLY;UNTIL=20140818T000000Z;INTERVAL=1;BYDAY=MO,WE\nDTEND:20140918T000000\nDTSTAMP:' + stamp + '\nLOCATION:Soccer field\nSUMMARY;LANGUAGE=en-us:Soccer Practice\nTRANSP:TRANSPARENT\nEND:VEVENT');
});
});
});
})(); })();