Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfec67f37a | ||
|
|
af1d393a10 | ||
|
|
aadebcff53 | ||
|
|
981e460c1d | ||
|
|
026753d4ff | ||
|
|
4f2e67a79a | ||
|
|
69c046615f | ||
|
|
75ced77d82 | ||
|
|
895485354a | ||
|
|
f755c00fad | ||
|
|
f803d79295 | ||
|
|
67cef7f101 | ||
|
|
f811f5cfa4 | ||
|
|
85825f5a7b | ||
|
|
acdaa716ca | ||
|
|
e07db639f1 | ||
|
|
6677d0568b | ||
|
|
ce02e5d8a9 | ||
|
|
1425bdfad3 | ||
|
|
1edd227f13 | ||
|
|
f8dbe2c5c5 | ||
|
|
82a31cb801 | ||
|
|
358d4f4f18 | ||
|
|
fd2d0a81aa | ||
|
|
40a2c1244c | ||
|
|
a12cab01e5 | ||
|
|
28cf7546ef | ||
|
|
ef20bfeea4 | ||
|
|
17a1b06fdd | ||
|
|
387392d04b | ||
|
|
e7c3489c2d | ||
|
|
b18b40fa03 | ||
|
|
592454900c | ||
|
|
6502ca83df | ||
|
|
98b22dd60a | ||
|
|
75369c0184 | ||
|
|
64eaacd0b9 | ||
|
|
c86d55ac39 | ||
|
|
762d842513 | ||
|
|
4790ef4156 | ||
|
|
d0359a5e06 | ||
|
|
2a5ea5d165 | ||
|
|
b479d03dff | ||
|
|
6369bb98f3 |
@@ -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,2 +1,3 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
bower_components/
|
bower_components/
|
||||||
|
.DS_Store
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Travis Krause
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -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
|
||||||
------------------
|
------------------
|
||||||
|
|||||||
+1
-1
@@ -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 <[email protected]>",
|
"Travis Krause <[email protected]>",
|
||||||
|
|||||||
+87
-50
@@ -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>
|
||||||
|
|||||||
+9
-9
@@ -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());
|
||||||
}
|
}
|
||||||
Vendored
+4
@@ -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")}};
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
Vendored
+4
-2
File diff suppressed because one or more lines are too long
@@ -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.getSeconds().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.getSeconds().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
@@ -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
@@ -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
@@ -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
@@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user