-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscript.js
397 lines (363 loc) · 34.3 KB
/
script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
// ==UserScript==
// @name Workflowier
// @namespace Workflowier
// @include https://workflowy.com/*
// @author Nick Busey
// @grant none
// @description User Script for Workflowy.com that adds some extra features.
// @version 0.2
// @license MIT
// @homepageURL http://workflowier.com/
// @updateURL https://openuserjs.org/meta/NickBusey/Workflowier.meta.js
// ==/UserScript==
// a function that loads jQuery and calls a callback function when jQuery has finished loading
function addJQuery(callback) {
var script = document.createElement("script");
script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js");
script.addEventListener('load', function() {
var script = document.createElement("script");
script.textContent = "window.jQ=jQuery.noConflict(true);(" + callback.toString() + ")();";
document.body.appendChild(script);
}, false);
document.body.appendChild(script);
}
searching = false;
// the guts of this userscript
function main() {
// Note, jQ replaces jQ to avoid conflicts.
// Calendar
// Find due date items
calendarCreated = false;
function myDateFunction(id, fromModal) {
var date = $("#" + id).data("date");
var hasEvent = $("#" + id).data("hasEvent");
search.searchProjectTree('#due-'+date);
calendarCreated = false;
jQ('.cal_wrap').slideToggle();
return true;
}
jQ('#savedViewHUDButton').after("<div class='menuButton button'><div class='topBarButtonTextContainer'><a href='#' id='showCalendar'>Calendar</a></div></div>");
jQ('#showCalendar').click(function(e) {
e.preventDefault();
if (!calendarCreated) {
$('body').append('<div id="calendar" class="cal_wrap"></div>')
var dates = generateCalendarData();
$("#calendar").zabuto_calendar({
data: dates,
action: function () {
return myDateFunction(this.id, false);
},
action_nav: function() {
setTimeout(function() {
$('.glyphicon-chevron-right').html('>');
$('.glyphicon-chevron-left').html('<');
},100);
},
legend: [
{type: "text", label: "Tasks Incomplete"},
{type: "list", list: ["grade-1", "grade-2", "grade-3", "grade-4", "grade-5"]},
{type: "text", label: "Tasks Completed"}
],
});
$('.glyphicon-chevron-right').html('>');
$('.glyphicon-chevron-left').html('<');
calendarCreated = true;
} else {
calendarCreated = false;
jQ('.zabuto_calendar').remove();
}
jQ('.cal_wrap').slideToggle();
});
// Insert recent links
var recentLinks = "<div class='menu-options' id='recentLinksMenu'>"+
"<div class='button'><div class='topBarButtonTextContainer'><a href='#' id='recentLink_1wk'>This Week</a></div></div>"+
"<div class='button'><div class='topBarButtonTextContainer'><a href='#' class='button' id='recentLink_24hrs'>Today</a></div></div>"+
"<div class='button'><div class='topBarButtonTextContainer'><a href='#' class='button' id='recentLink_1hr'>Last Hour</a></div></div>"+
"</div>";
jQ('#savedViewHUDButton').after("<div class='menuButton button'><div class='topBarButtonTextContainer'><a href='#' id='showRecentLinks'>Recent</a></div></div>"+recentLinks);
jQ('#showRecentLinks').click(function(e) {
e.preventDefault();
jQ('#recentLinksMenu').slideToggle();
});
jQ('#recentLink_1wk').click(function(e) {
e.preventDefault();
if (jQ('#searchBox').val()=='last-changed:7d') {
search.searchProjectTree('');
} else {
search.searchProjectTree('last-changed:7d');
}
});
jQ('#recentLink_24hrs').click(function(e) {
e.preventDefault();
if (jQ('#searchBox').val()=='last-changed:1d') {
search.searchProjectTree('');
} else {
search.searchProjectTree('last-changed:1d');
}
});
jQ('#recentLink_1hr').click(function(e) {
e.preventDefault();
if (jQ('#searchBox').val()=='last-changed:1h') {
search.searchProjectTree('');
} else {
search.searchProjectTree('last-changed:1h');
}
});
var generateTagList = function() {
// Generate list of all hashtags
var tags = $('.contentTagText');
var tagObjs = {};
tags.each(function(ii, obj) {
var tag = jQ(obj).text().toLowerCase();
var tagObj = tagObjs[tag];
if (!tagObj) {
tagObj = {'count':1};
} else {
tagObj.count++;
}
tagObjs[tag] = tagObj;
});
var tagObjsArray = [];
for (var tag in tagObjs) {
var tagObj = tagObjs[tag];
tagObj.tag = tag;
tagObjsArray.push(tagObj);
}
return tagObjsArray.sort(function (a, b) {
return b.count - a.count;
});
};
var generateCalendarData = function() {
var currentSearch = jQ('#searchBox').val();
// First let's delete the existing tags index, or else it will count those and old tags are never removed.
search.searchProjectTree('#wf-tag-list');
$('.project.matches:last .notes .content').text('');
$('.project.matches:last .content').trigger('blur');
// Now find existing tags.
showCompleted();
search.searchProjectTree('#due-');
var allDatedItems = generateTagList();
search.searchProjectTree('#due- is:complete');
var completedDateItems = generateTagList();
search.searchProjectTree(currentSearch);
var dates = [];
for (var ii in allDatedItems) {
var dateItem = allDatedItems[ii];
console.log(dateItem);
var tag = dateItem.tag;
if (tag.substr(0,4)=='due-') {
var count = dateItem.count;
var completed = completedDateItems.filter(function (obj) {
return obj.tag === tag;
});
var completed_count = (completed[0]) ? completed[0].count : 0;
var completed_pct = Math.round(100*(completed_count/count));
var className = 'grade-5';
switch (true) {
case (completed_pct < 20):
className = 'grade-1';
break;
case (completed_pct > 20 && completed_pct < 40):
className = 'grade-2';
break;
case (completed_pct > 40 && completed_pct < 60):
className = 'grade-3';
break;
case (completed_pct > 60 && completed_pct < 80):
className = 'grade-4';
break;
case (completed_pct > 80):
className = 'grade-5';
break;
}
dates.push({
"date":dateItem.tag.substr(4),
"classname": className,
"title": Math.round(100*(completed_count/count))+"% complete"
});
}
}
console.log(dates);
return dates;
};
var generateTags = function() {
var currentSearch = jQ('#searchBox').val();
// First let's delete the existing tags index, or else it will count those and old tags are never removed.
search.searchProjectTree('#wf-tag-list');
$('.project.matches:last .notes .content').text('');
$('.project.matches:last .content').trigger('blur');
// Now find existing tags.
search.searchProjectTree('#');
var allTags = generateTagList();
// Now find which of those are completed
search.searchProjectTree('# is:complete');
var completedTags = generateTagList();
// Store the list of tags
updateTagsNote(allTags);
// Update the menu
var tagLinkOutput = '';
for (var ii in allTags) {
var count = allTags[ii]['count'];
var tag = allTags[ii]['tag'];
var completed = completedTags.filter(function (obj) {
return obj.tag === tag;
});
var completed_count = (completed[0]) ? completed[0].count : 0;
tagLinkOutput += "<a href='/#/"+tag+"?q=%23"+tag+"' title='"+Math.round(100*(completed_count/count))+"% "+completed_count+"/"+count+" complete.'><strong>"+count+"</strong> #"+tag+"</a>";
}
$('#tagsMenu').html(tagLinkOutput);
search.searchProjectTree(currentSearch);
};
var generateTagsMenu = function () {
// Ensure the search is ready. This will throw an exception if not.
var currentSearch = jQ('#searchBox').val();
search.searchProjectTree('#wf-tag-list');
search.searchProjectTree(currentSearch);
generateTags();
jQ('#savedViewHUDButton').after("<div class='button menuButton'><div class='topBarButtonTextContainer'><a href='#' class='button' id='openTags'>View Tags</a></div></div><div class='menu-options' id='tagsMenu'></div>");
jQ('#openTags').on('click',function(e) {
e.preventDefault();
// If we're showing the tags menu, regenerate the tags list. Don't do it on hide.
if ($('#tagsMenu:visible').length < 1) {
generateTags();
}
jQ('#tagsMenu').slideToggle();
});
};
var updateTagsNote = function(tagArray) {
window.location.hash='';
search.searchProjectTree('#wf-tag-list');
var tagList = '';
for (var ii in tagArray) {
var count = tagArray[ii]['count'];
var tag = tagArray[ii]['tag'];
tagList += count+" #"+tag+" - ";
}
$('.project.matches:last .notes .content').text('View Full List: '+tagList);
$('.project.matches:last .content').trigger('blur');
};
var attemptTags = function() {
setTimeout(function() {
try {
generateTagsMenu();
} catch(e) {
attemptTags();
}
},500);
};
attemptTags();
// Add -rand functionality
jQ(window).on('hashchange',function(e) {
if (searching) {
return false;
}
var query = jQ('#searchBox').val();
var needle=/(%23\w*-rand)+/;
var match = window.location.href.match(needle);
if (match) {
// A tag with -rand on the end has been clicked. Locate another.
searching = true;
var tag = match[0]; //matches "2 chapters"
tag = "#"+tag.slice(3);
window.location.href='/#';
search.searchProjectTree(tag);
var target = null;
var count = 0;
var tags = $('.contentMatch');
var random = $(tags[Math.floor(Math.random()*tags.length)])[0];
var parent = jQ(random).parents('.name').find('a').first();
var href = jQ(parent).attr('href');
window.location.href = href;
setTimeout(function() {
searching = false;
},100);
}
});
// Add image popups
var addImagePreviews = function() {
jQ('a').each(function() {
if (jQ(this).data('previewLoaded')) {
return;
}
var url = this.href;
var target = this;
var img = null;
function testImage(url, callback, timeout) {
timeout = timeout || 5000;
var timedOut = false, timer;
img = new Image();
img.onerror = img.onabort = function() {
if (!timedOut) {
clearTimeout(timer);
callback(url, 0);
}
};
img.onload = function() {
if (!timedOut) {
clearTimeout(timer);
callback(url, 1);
}
};
img.src = url;
timer = setTimeout(function() {
timedOut = true;
// reset .src to invalid URL so it stops previous
// loading, but doesn't trigger new load
img.src = "//!!!!/test.jpg";
callback(url, "timeout");
}, timeout);
}
testImage(url,function(url,loaded) {
jQ(target).data('previewLoaded',true);
if (loaded) {
jQ(target).after(jQ(img).addClass('image-preview'));
}
},2000);
});
};
// Add styles
jQ('body').append("<style>"+
".image-preview { height: 100px; display: block; } "+
".image-preview:hover { height: initial; display: block; } "+
"#tagsMenu{ height:300px; overflow:scroll; max-width: 250px; right: 140px; }"+
"#tagsMenu a { margin: 0 5px; display: block; }"+
"#recentLinksMenu{ right:400px; }"+
".menuButton{ display: block; color: white; margin-left: -1px; padding: 8px 1em; font-size: 13px; text-align: center; float: right; border-bottom: none; border-left: 1px solid #111; border-right: 1px solid #111; border-radius: 0; background-color: #555; position: relative;}"+
"div.zabuto_calendar{margin:0;padding:0}div.zabuto_calendar .table{width:100%;margin:0;padding:0}div.zabuto_calendar .table th,div.zabuto_calendar .table td{padding:4px 2px;text-align:center}div.zabuto_calendar .table tr th,div.zabuto_calendar .table tr td{background-color:#fff}div.zabuto_calendar .table tr.calendar-month-header th{background-color:#fafafa}div.zabuto_calendar .table tr.calendar-month-header th span{cursor:pointer;display:inline-block;padding-bottom:10px}div.zabuto_calendar .table tr.calendar-dow-header th{background-color:#f0f0f0}div.zabuto_calendar .table tr:last-child{border-bottom:1px solid #ddd}div.zabuto_calendar .table tr.calendar-month-header th{padding-top:12px;padding-bottom:4px}div.zabuto_calendar .table-bordered tr.calendar-month-header th{border-left:0;border-right:0}div.zabuto_calendar .table-bordered tr.calendar-month-header th:first-child{border-left:1px solid #ddd}div.zabuto_calendar div.calendar-month-navigation{cursor:pointer;margin:0;padding:0;padding-top:5px}div.zabuto_calendar tr.calendar-dow-header th,div.zabuto_calendar tr.calendar-dow td{width:14%}div.zabuto_calendar .table tr td div.day{margin:0;padding-top:7px;padding-bottom:7px}div.zabuto_calendar .table tr td.event div.day,div.zabuto_calendar ul.legend li.event{background-color:#fff0c3}div.zabuto_calendar .table tr td.dow-clickable,div.zabuto_calendar .table tr td.event-clickable{cursor:pointer}div.zabuto_calendar .badge-today,div.zabuto_calendar div.legend span.badge-today{background-color:#357ebd;color:#fff;text-shadow:none}div.zabuto_calendar .badge-event,div.zabuto_calendar div.legend span.badge-event{background-color:#ff9b08;color:#fff;text-shadow:none}div.zabuto_calendar .badge-event{font-size:.95em;padding-left:8px;padding-right:8px;padding-bottom:4px}div.zabuto_calendar div.legend{margin-top:5px;text-align:right}div.zabuto_calendar div.legend span{color:#999;font-size:10px;font-weight:normal}div.zabuto_calendar div.legend span.legend-text:after,div.zabuto_calendar div.legend span.legend-block:after,div.zabuto_calendar div.legend span.legend-list:after,div.zabuto_calendar div.legend span.legend-spacer:after{content:' '}div.zabuto_calendar div.legend span.legend-spacer{padding-left:25px}div.zabuto_calendar ul.legend>span{padding-left:2px}div.zabuto_calendar ul.legend{display:inline-block;list-style:none outside none;margin:0;padding:0}div.zabuto_calendar ul.legend li{display:inline-block;height:11px;width:11px;margin-left:5px}div.zabuto_calendar ul.legend div.zabuto_calendar ul.legend li:first-child{margin-left:7px}div.zabuto_calendar ul.legend li:last-child{margin-right:5px}div.zabuto_calendar div.legend span.badge{font-size:.9em;border-radius:5px 5px 5px 5px;padding-left:5px;padding-right:5px;padding-top:2px;padding-bottom:3px}@media(max-width:979px){div.zabuto_calendar .table th,div.zabuto_calendar .table td{padding:2px 1px}}"+
".cal_wrap { position: absolute; top: 2em; z-index: 2000; display: none; background-color: white;padding: 1em;border: solid gray 3px;border-radius: 5px;} "+
".grade-1 {background-color: #FA2601;} .grade-2 {background-color: #FA8A00;} .grade-3 {background-color: #FFEB00;} .grade-4 {background-color: #27AB00;} .grade-5 {background-color: #27AB00;} "+
"</style>");
// "<link rel='stylesheet' href='//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css'>"+
// "<script src='//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min.js'></script>");
// Add coloring styles (ala Paintly, stolen from: https://userstyles.org/styles/125832/re-workflowy-re-painter)
setInterval(function() {
$('.content').css('background-color','');
var colors = {
'red':'#FFB5B5',
'orange':'#FFD8B5',
'yellow':'#FFFAB5',
'lime':'#E1FFB5',
'olive':'#B5FFC9',
'green':'#CCFFB5',
'teal':'#B5FFD7',
'aquea':'#B5FFFC',
'blu':'#B5E8FF',
'navy':'#B9B5FF',
'fuchia':'#F1B5FF',
'purple':'#D3B5FF',
'maroon':'#C08F8F',
'silver':'silver',
'gray':'gray',
'black':'black',
'white':'white'
};
for (var ii in colors) {
var color = colors[ii];
$('.content:contains("#'+ii+'")').css('background-color',color);
}
addImagePreviews();
},500);
}
if(typeof jQuery=="undefined"){throw new Error("jQuery is not loaded")}$.fn.zabuto_calendar=function(options){var opts=$.extend({},$.fn.zabuto_calendar_defaults(),options);var languageSettings=$.fn.zabuto_calendar_language(opts.language);opts=$.extend({},opts,languageSettings);this.each(function(){var $calendarElement=$(this);$calendarElement.attr("id","zabuto_calendar_"+Math.floor(Math.random()*99999).toString(36));$calendarElement.data("initYear",opts.year);$calendarElement.data("initMonth",opts.month);$calendarElement.data("monthLabels",opts.month_labels);$calendarElement.data("weekStartsOn",opts.weekstartson);$calendarElement.data("navIcons",opts.nav_icon);$calendarElement.data("dowLabels",opts.dow_labels);$calendarElement.data("showToday",opts.today);$calendarElement.data("showDays",opts.show_days);$calendarElement.data("showPrevious",opts.show_previous);$calendarElement.data("showNext",opts.show_next);$calendarElement.data("cellBorder",opts.cell_border);$calendarElement.data("jsonData",opts.data);$calendarElement.data("ajaxSettings",opts.ajax);$calendarElement.data("legendList",opts.legend);$calendarElement.data("actionFunction",opts.action);$calendarElement.data("actionNavFunction",opts.action_nav);drawCalendar();function drawCalendar(){var dateInitYear=parseInt($calendarElement.data("initYear"));var dateInitMonth=parseInt($calendarElement.data("initMonth"))-1;var dateInitObj=new Date(dateInitYear,dateInitMonth,1,0,0,0,0);$calendarElement.data("initDate",dateInitObj);var tableClassHtml=$calendarElement.data("cellBorder")===true?" table-bordered":"";$tableObj=$('<table class="table'+tableClassHtml+'"></table>');$tableObj=drawTable($calendarElement,$tableObj,dateInitObj.getFullYear(),dateInitObj.getMonth());$legendObj=drawLegend($calendarElement);var $containerHtml=$('<div class="zabuto_calendar" id="'+$calendarElement.attr("id")+'"></div>');$containerHtml.append($tableObj);$containerHtml.append($legendObj);$calendarElement.append($containerHtml);var jsonData=$calendarElement.data("jsonData");if(false!==jsonData){checkEvents($calendarElement,dateInitObj.getFullYear(),dateInitObj.getMonth())}}function drawTable($calendarElement,$tableObj,year,month){var dateCurrObj=new Date(year,month,1,0,0,0,0);$calendarElement.data("currDate",dateCurrObj);$tableObj.empty();$tableObj=appendMonthHeader($calendarElement,$tableObj,year,month);$tableObj=appendDayOfWeekHeader($calendarElement,$tableObj);$tableObj=appendDaysOfMonth($calendarElement,$tableObj,year,month);checkEvents($calendarElement,year,month);return $tableObj}function drawLegend($calendarElement){var $legendObj=$('<div class="legend" id="'+$calendarElement.attr("id")+'_legend"></div>');var legend=$calendarElement.data("legendList");if(typeof legend=="object"&&legend.length>0){$(legend).each(function(index,item){if(typeof item=="object"){if("type"in item){var itemLabel="";if("label"in item){itemLabel=item.label}switch(item.type){case"text":if(itemLabel!==""){var itemBadge="";if("badge"in item){if(typeof item.classname==="undefined"){var badgeClassName="badge-event"}else{var badgeClassName=item.classname}itemBadge='<span class="badge '+badgeClassName+'">'+item.badge+"</span> "}$legendObj.append('<span class="legend-'+item.type+'">'+itemBadge+itemLabel+"</span>")}break;case"block":if(itemLabel!==""){itemLabel="<span>"+itemLabel+"</span>"}if(typeof item.classname==="undefined"){var listClassName="event"}else{var listClassName="event-styled "+item.classname}$legendObj.append('<span class="legend-'+item.type+'"><ul class="legend"><li class="'+listClassName+'"></li></u>'+itemLabel+"</span>");break;case"list":if("list"in item&&typeof item.list=="object"&&item.list.length>0){var $legendUl=$('<ul class="legend"></u>');$(item.list).each(function(listIndex,listClassName){$legendUl.append('<li class="'+listClassName+'"></li>')});$legendObj.append($legendUl)}break;case"spacer":$legendObj.append('<span class="legend-'+item.type+'"> </span>');break}}}})}return $legendObj}function appendMonthHeader($calendarElement,$tableObj,year,month){var navIcons=$calendarElement.data("navIcons");var $prevMonthNavIcon=$('<span><span class="glyphicon glyphicon-chevron-left"></span></span>');var $nextMonthNavIcon=$('<span><span class="glyphicon glyphicon-chevron-right"></span></span>');if(typeof navIcons==="object"){if("prev"in navIcons){$prevMonthNavIcon.html(navIcons.prev)}if("next"in navIcons){$nextMonthNavIcon.html(navIcons.next)}}var prevIsValid=$calendarElement.data("showPrevious");if(typeof prevIsValid==="number"||prevIsValid===false){prevIsValid=checkMonthLimit($calendarElement.data("showPrevious"),true)}var $prevMonthNav=$('<div class="calendar-month-navigation"></div>');$prevMonthNav.attr("id",$calendarElement.attr("id")+"_nav-prev");$prevMonthNav.data("navigation","prev");if(prevIsValid!==false){prevMonth=month-1;prevYear=year;if(prevMonth==-1){prevYear=prevYear-1;prevMonth=11}$prevMonthNav.data("to",{year:prevYear,month:prevMonth+1});$prevMonthNav.append($prevMonthNavIcon);if(typeof $calendarElement.data("actionNavFunction")==="function"){$prevMonthNav.click($calendarElement.data("actionNavFunction"))}$prevMonthNav.click(function(e){drawTable($calendarElement,$tableObj,prevYear,prevMonth)})}var nextIsValid=$calendarElement.data("showNext");if(typeof nextIsValid==="number"||nextIsValid===false){nextIsValid=checkMonthLimit($calendarElement.data("showNext"),false)}var $nextMonthNav=$('<div class="calendar-month-navigation"></div>');$nextMonthNav.attr("id",$calendarElement.attr("id")+"_nav-next");$nextMonthNav.data("navigation","next");if(nextIsValid!==false){nextMonth=month+1;nextYear=year;if(nextMonth==12){nextYear=nextYear+1;nextMonth=0}$nextMonthNav.data("to",{year:nextYear,month:nextMonth+1});$nextMonthNav.append($nextMonthNavIcon);if(typeof $calendarElement.data("actionNavFunction")==="function"){$nextMonthNav.click($calendarElement.data("actionNavFunction"))}$nextMonthNav.click(function(e){drawTable($calendarElement,$tableObj,nextYear,nextMonth)})}var monthLabels=$calendarElement.data("monthLabels");var $prevMonthCell=$("<th></th>").append($prevMonthNav);var $nextMonthCell=$("<th></th>").append($nextMonthNav);var $currMonthLabel=$("<span>"+monthLabels[month]+" "+year+"</span>");$currMonthLabel.dblclick(function(){var dateInitObj=$calendarElement.data("initDate");drawTable($calendarElement,$tableObj,dateInitObj.getFullYear(),dateInitObj.getMonth())});var $currMonthCell=$('<th colspan="5"></th>');$currMonthCell.append($currMonthLabel);var $monthHeaderRow=$('<tr class="calendar-month-header"></tr>');$monthHeaderRow.append($prevMonthCell,$currMonthCell,$nextMonthCell);$tableObj.append($monthHeaderRow);return $tableObj}function appendDayOfWeekHeader($calendarElement,$tableObj){if($calendarElement.data("showDays")===true){var weekStartsOn=$calendarElement.data("weekStartsOn");var dowLabels=$calendarElement.data("dowLabels");if(weekStartsOn===0){var dowFull=$.extend([],dowLabels);var sunArray=new Array(dowFull.pop());dowLabels=sunArray.concat(dowFull)}var $dowHeaderRow=$('<tr class="calendar-dow-header"></tr>');$(dowLabels).each(function(index,value){$dowHeaderRow.append("<th>"+value+"</th>")});$tableObj.append($dowHeaderRow)}return $tableObj}function appendDaysOfMonth($calendarElement,$tableObj,year,month){var ajaxSettings=$calendarElement.data("ajaxSettings");var weeksInMonth=calcWeeksInMonth(year,month);var lastDayinMonth=calcLastDayInMonth(year,month);var firstDow=calcDayOfWeek(year,month,1);var lastDow=calcDayOfWeek(year,month,lastDayinMonth);var currDayOfMonth=1;var weekStartsOn=$calendarElement.data("weekStartsOn");if(weekStartsOn===0){if(lastDow==6){weeksInMonth++}if(firstDow==6&&(lastDow==0||lastDow==1||lastDow==5)){weeksInMonth--}firstDow++;if(firstDow==7){firstDow=0}}for(var wk=0;wk<weeksInMonth;wk++){var $dowRow=$('<tr class="calendar-dow"></tr>');for(var dow=0;dow<7;dow++){if(dow<firstDow||currDayOfMonth>lastDayinMonth){$dowRow.append("<td></td>")}else{var dateId=$calendarElement.attr("id")+"_"+dateAsString(year,month,currDayOfMonth);var dayId=dateId+"_day";var $dayElement=$('<div id="'+dayId+'" class="day" >'+currDayOfMonth+"</div>");$dayElement.data("day",currDayOfMonth);if($calendarElement.data("showToday")===true){if(isToday(year,month,currDayOfMonth)){$dayElement.html('<span class="badge badge-today">'+currDayOfMonth+"</span>")}}var $dowElement=$('<td id="'+dateId+'"></td>');$dowElement.append($dayElement);$dowElement.data("date",dateAsString(year,month,currDayOfMonth));$dowElement.data("hasEvent",false);if(typeof $calendarElement.data("actionFunction")==="function"){$dowElement.addClass("dow-clickable");$dowElement.click(function(){$calendarElement.data("selectedDate",$(this).data("date"))});$dowElement.click($calendarElement.data("actionFunction"))}$dowRow.append($dowElement);currDayOfMonth++}if(dow==6){firstDow=0}}$tableObj.append($dowRow)}return $tableObj}function createModal(id,title,body,footer){var $modalHeaderButton=$('<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>');var $modalHeaderTitle=$('<h4 class="modal-title" id="'+id+'_modal_title">'+title+"</h4>");var $modalHeader=$('<div class="modal-header"></div>');$modalHeader.append($modalHeaderButton);$modalHeader.append($modalHeaderTitle);var $modalBody=$('<div class="modal-body" id="'+id+'_modal_body">'+body+"</div>");var $modalFooter=$('<div class="modal-footer" id="'+id+'_modal_footer"></div>');if(typeof footer!=="undefined"){var $modalFooterAddOn=$("<div>"+footer+"</div>");$modalFooter.append($modalFooterAddOn)}var $modalContent=$('<div class="modal-content"></div>');$modalContent.append($modalHeader);$modalContent.append($modalBody);$modalContent.append($modalFooter);var $modalDialog=$('<div class="modal-dialog"></div>');$modalDialog.append($modalContent);var $modalFade=$('<div class="modal fade" id="'+id+'_modal" tabindex="-1" role="dialog" aria-labelledby="'+id+'_modal_title" aria-hidden="true"></div>');$modalFade.append($modalDialog);$modalFade.data("dateId",id);$modalFade.attr("dateId",id);return $modalFade}function checkEvents($calendarElement,year,month){var jsonData=$calendarElement.data("jsonData");var ajaxSettings=$calendarElement.data("ajaxSettings");$calendarElement.data("events",false);if(false!==jsonData){return jsonEvents($calendarElement)}else if(false!==ajaxSettings){return ajaxEvents($calendarElement,year,month)}return true}function jsonEvents($calendarElement){var jsonData=$calendarElement.data("jsonData");$calendarElement.data("events",jsonData);drawEvents($calendarElement,"json");return true}function ajaxEvents($calendarElement,year,month){var ajaxSettings=$calendarElement.data("ajaxSettings");if(typeof ajaxSettings!="object"||typeof ajaxSettings.url=="undefined"){alert("Invalid calendar event settings");return false}var data={year:year,month:month+1};$.ajax({type:"GET",url:ajaxSettings.url,data:data,dataType:"json"}).done(function(response){var events=[];$.each(response,function(k,v){events.push(response[k])});$calendarElement.data("events",events);drawEvents($calendarElement,"ajax")});return true}function drawEvents($calendarElement,type){var jsonData=$calendarElement.data("jsonData");var ajaxSettings=$calendarElement.data("ajaxSettings");var events=$calendarElement.data("events");if(events!==false){$(events).each(function(index,value){var id=$calendarElement.attr("id")+"_"+value.date;var $dowElement=$("#"+id);var $dayElement=$("#"+id+"_day");$dowElement.data("hasEvent",true);if(typeof value.title!=="undefined"){$dowElement.attr("title",value.title)}if(typeof value.classname==="undefined"){$dowElement.addClass("event")}else{$dowElement.addClass("event-styled");$dayElement.addClass(value.classname)}if(typeof value.badge!=="undefined"&&value.badge!==false){var badgeClass=value.badge===true?"":" badge-"+value.badge;var dayLabel=$dayElement.data("day");$dayElement.html('<span class="badge badge-event'+badgeClass+'">'+dayLabel+"</span>")}if(typeof value.body!=="undefined"){var modalUse=false;if(type==="json"&&typeof value.modal!=="undefined"&&value.modal===true){modalUse=true}else if(type==="ajax"&&"modal"in ajaxSettings&&ajaxSettings.modal===true){modalUse=true}if(modalUse===true){$dowElement.addClass("event-clickable");var $modalElement=createModal(id,value.title,value.body,value.footer);$("body").append($modalElement);$("#"+id).click(function(){$("#"+id+"_modal").modal()})}}})}}function isToday(year,month,day){var todayObj=new Date;var dateObj=new Date(year,month,day);return dateObj.toDateString()==todayObj.toDateString()}function dateAsString(year,month,day){d=day<10?"0"+day:day;m=month+1;m=m<10?"0"+m:m;return year+"-"+m+"-"+d}function calcDayOfWeek(year,month,day){var dateObj=new Date(year,month,day,0,0,0,0);var dow=dateObj.getDay();if(dow==0){dow=6}else{dow--}return dow}function calcLastDayInMonth(year,month){var day=28;while(checkValidDate(year,month+1,day+1)){day++}return day}function calcWeeksInMonth(year,month){var daysInMonth=calcLastDayInMonth(year,month);var firstDow=calcDayOfWeek(year,month,1);var lastDow=calcDayOfWeek(year,month,daysInMonth);var days=daysInMonth;var correct=firstDow-lastDow;if(correct>0){days+=correct}return Math.ceil(days/7)}function checkValidDate(y,m,d){return m>0&&m<13&&y>0&&y<32768&&d>0&&d<=new Date(y,m,0).getDate()}function checkMonthLimit(count,invert){if(count===false){count=0}var d1=$calendarElement.data("currDate");var d2=$calendarElement.data("initDate");var months;months=(d2.getFullYear()-d1.getFullYear())*12;months-=d1.getMonth()+1;months+=d2.getMonth();if(invert===true){if(months<parseInt(count)-1){return true}}else{if(months>=0-parseInt(count)){return true}}return false}});return this};$.fn.zabuto_calendar_defaults=function(){var now=new Date;var year=now.getFullYear();var month=now.getMonth()+1;var settings={language:false,year:year,month:month,show_previous:true,show_next:true,cell_border:false,today:false,show_days:true,weekstartson:1,nav_icon:false,data:false,ajax:false,legend:false,action:false,action_nav:false};return settings};$.fn.zabuto_calendar_language=function(lang){if(typeof lang=="undefined"||lang===false){lang="en"}switch(lang.toLowerCase()){case"de":return{month_labels:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],dow_labels:["Mo","Di","Mi","Do","Fr","Sa","So"]};break;case"en":return{month_labels:["January","February","March","April","May","June","July","August","September","October","November","December"],dow_labels:["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]};break;case"ar":return{month_labels:["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"],dow_labels:["أثنين","ثلاثاء","اربعاء","خميس","جمعه","سبت","أحد"]};break;case"es":return{month_labels:["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],dow_labels:["Lu","Ma","Mi","Ju","Vi","Sá","Do"]};break;case"fr":return{month_labels:["Janvier","Février","Mars","Avril","Mai","Juin","Juillet","Août","Septembre","Octobre","Novembre","Décembre"],dow_labels:["Lun","Mar","Mer","Jeu","Ven","Sam","Dim"]};break;case"it":return{month_labels:["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"],dow_labels:["Lun","Mar","Mer","Gio","Ven","Sab","Dom"]};break;case"nl":return{month_labels:["Januari","Februari","Maart","April","Mei","Juni","Juli","Augustus","September","Oktober","November","December"],dow_labels:["Ma","Di","Wo","Do","Vr","Za","Zo"]};break;case"pl":return{month_labels:["Styczeń","Luty","Marzec","Kwiecień","Maj","Czerwiec","Lipiec","Sierpień","Wrzesień","Październik","Listopad","Grudzień"],dow_labels:["pon.","wt.","śr.","czw.","pt.","sob.","niedz."]};break;case"pt":return{month_labels:["Janeiro","Fevereiro","Marco","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],dow_labels:["S","T","Q","Q","S","S","D"]};break;case"ru":return{month_labels:["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"],dow_labels:["Пн","Вт","Ср","Чт","Пт","Сб","Вск"]};break;case"se":return{month_labels:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],dow_labels:["Mån","Tis","Ons","Tor","Fre","Lör","Sön"]};break;case"tr":return{month_labels:["Ocak","Şubat","Mart","Nisan","Mayıs","Haziran","Temmuz","Ağustos","Eylül","Ekim","Kasım","Aralık"],dow_labels:["Pts","Salı","Çar","Per","Cuma","Cts","Paz"]};break}};
// load jQuery and execute the main function
addJQuery(main);