├── MIT-LICENSE.txt ├── demo.html ├── jw-jqm-cal.css ├── jw-jqm-cal.ios7.css ├── README.md └── jw-jqm-cal.js /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2013 Jan-Willem Gmelig Meyling and other contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My Page 5 | 6 | 7 | 8 | 9 | 10 | 11 | 21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 |

My Title

29 |
30 | 31 |
32 |
33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /jw-jqm-cal.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | /* CSS Document */ 3 | .jq-calendar-wrapper { padding: 0; margin: -15px -15px 0 -15px; display: block; } 4 | .jq-calendar-wrapper table { margin:0; width: 100%; color: #333; border-collapse: collapse; table-layout: fixed; } 5 | .jq-calendar-wrapper .ui-listview { margin: 0; } 6 | .jq-calendar-wrapper th { padding: .2em 0; text-align: center; } 7 | .jq-calendar-wrapper th.header { line-height: 33px; } 8 | .jq-calendar-wrapper .previous-btn { float: left; margin: .2em .5em; } 9 | .jq-calendar-wrapper .next-btn { float: right; margin: .2em .5em; } 10 | .jq-calendar-wrapper td { text-align:center; padding: 0; } 11 | .jq-calendar-wrapper td.darker, .jq-calendar-wrapper span.darker { opacity: 0.3; } 12 | .jq-calendar-wrapper td a,.jq-calendar-wrapper td button { padding: .5em 0; margin:0; border:0; } 13 | .jq-calendar-wrapper td span { position: absolute; top: 20px; left: 0; width: 100%; text-align: center; } 14 | .jq-calendar-wrapper .importance-1:not(.ui-btn-active) { background-image: -webkit-gradient(linear, left top, left bottom, from( #FFFFc7 ), to( #d3c190 )); background-image: -webkit-linear-gradient( #FFFFc7, #d3c190 ); background-image: -moz-linear-gradient( #FFFFc7 , #d3c190 ); background-image: -ms-linear-gradient( #FFFFc7 , #d3c190 ); background-image: -o-linear-gradient( #FFFFc7 , #d3c190 ); background-image: linear-gradient( #FFFFc7 , #d3c190 ); } 15 | .jq-calendar-wrapper .importance-2:not(.ui-btn-active) { background-image: -webkit-gradient(linear, left top, left bottom, from( #FFd4a2), to( #e0ad85)); background-image: -webkit-linear-gradient( #FFd4a2, #e0ad85); background-image: -moz-linear-gradient( #FFd4a2, #e0ad85); background-image: -ms-linear-gradient( #FFd4a2, #e0ad85); background-image: -o-linear-gradient( #FFd4a2, #e0ad85); background-image: linear-gradient( #FFd4a2, #e0ad85); } 16 | .jq-calendar-wrapper .ui-btn-today { background-image: -webkit-gradient(linear, left top, left bottom, from( #fd8255), to( #d46d46)); background-image: -webkit-linear-gradient( #fd8255, #d46d46); background-image: -moz-linear-gradient( #fd8255, #d46d46); background-image: -ms-linear-gradient( #fd8255, #d46d46); background-image: -o-linear-gradient( #fd8255, #d46d46); background-image: linear-gradient( #fd8255, #d46d46); color: #fff; text-shadow: 0 1px 0 #000; } 17 | -------------------------------------------------------------------------------- /jw-jqm-cal.ios7.css: -------------------------------------------------------------------------------- 1 | #view-calendar .ui-content { 2 | overflow:hidden; 3 | } 4 | 5 | .jq-calendar-wrapper { 6 | padding: 0; 7 | margin: -17px; 8 | display: block; 9 | } 10 | 11 | .jq-calendar-wrapper table { 12 | margin: 0; 13 | width: 100%; 14 | color: #333; 15 | border-collapse: collapse; 16 | table-layout: fixed; 17 | } 18 | 19 | .jq-calendar-wrapper .ui-listview { 20 | margin: 0; 21 | } 22 | 23 | .jq-calendar-wrapper th { 24 | padding: .2em 0; 25 | text-align: center; 26 | } 27 | 28 | .jq-calendar-wrapper th.header { 29 | line-height: 33px; 30 | } 31 | 32 | .jq-calendar-wrapper .previous-btn { 33 | float: left; 34 | margin: .2em .5em; 35 | } 36 | 37 | .jq-calendar-wrapper .next-btn { 38 | float: right; 39 | margin: .2em .5em; 40 | } 41 | 42 | .jq-calendar-wrapper td { 43 | text-align: center; 44 | background-color: #fff; 45 | line-height: 0; 46 | padding: 1px 0; 47 | } 48 | 49 | .jq-calendar-wrapper td.hidden,.jq-calendar-wrapper span.hidden { 50 | opacity: 0.3; 51 | } 52 | 53 | .jq-calendar-wrapper td a,.jq-calendar-wrapper td button { 54 | margin: 0; 55 | border: 0; 56 | border-radius: 20px; 57 | width: 40px; 58 | height: 40px; 59 | padding: 0; 60 | display: inline-block; 61 | line-height: 40px; 62 | } 63 | 64 | .jq-calendar-wrapper td span { 65 | position: absolute; 66 | top: 12px; 67 | left: 0; 68 | width: 100%; 69 | text-align: center; 70 | } 71 | 72 | #view-calendar .ui-listview li { 73 | font-weight: bold; 74 | } 75 | 76 | .jq-calendar-wrapper .importance-1:not(.ui-btn-active) { background-image: -webkit-gradient(linear, left top, left bottom, from( #FFFFc7 ), to( #d3c190 )); background-image: -webkit-linear-gradient( #FFFFc7, #d3c190 ); background-image: -moz-linear-gradient( #FFFFc7 , #d3c190 ); background-image: -ms-linear-gradient( #FFFFc7 , #d3c190 ); background-image: -o-linear-gradient( #FFFFc7 , #d3c190 ); background-image: linear-gradient( #FFFFc7 , #d3c190 ); } 77 | .jq-calendar-wrapper .importance-2:not(.ui-btn-active) { background-image: -webkit-gradient(linear, left top, left bottom, from( #FFd4a2), to( #e0ad85)); background-image: -webkit-linear-gradient( #FFd4a2, #e0ad85); background-image: -moz-linear-gradient( #FFd4a2, #e0ad85); background-image: -ms-linear-gradient( #FFd4a2, #e0ad85); background-image: -o-linear-gradient( #FFd4a2, #e0ad85); background-image: linear-gradient( #FFd4a2, #e0ad85); } 78 | .jq-calendar-wrapper .ui-btn-today { background-image: -webkit-gradient(linear, left top, left bottom, from( #fd8255), to( #d46d46)); background-image: -webkit-linear-gradient( #fd8255, #d46d46); background-image: -moz-linear-gradient( #fd8255, #d46d46); background-image: -ms-linear-gradient( #fd8255, #d46d46); background-image: -o-linear-gradient( #fd8255, #d46d46); background-image: linear-gradient( #fd8255, #d46d46); color: #fff; text-shadow: 0 1px 0 #000; } 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | jqm-calendar 2 | ============ 3 | 4 | Simple iOS-style calendar plugin for jQuery Mobile for both showing activities or picking dates. Events are showed with a bullet point on the date, and when the date is picked, the date appears with its summary in the list below. 5 | 6 | The options Object for the jqmCaldender takes several attributes, all of which are *optional*. 7 | 8 | * `events` : An Array of Objects, which represent the events in the calendar. Events should have a `summary`, `begin` and `end`. The attributes names can be changed if needed, by setting creating an attribute: `settings.summary = "mySummaryIdentifier"`. You can let this point to another array in your program or access this array later on to inject new events to the calendar. Be sure to call a refresh when doing so. 9 | * `months` : Labels for the months, this might be useful for using the jqm-calendar in other languages. The English values are set by default, so there is no need to set them. 10 | * `days` : Same as for months 11 | * `startOfWeek` : integer from 0 to 6 to tell jqm-calendar at which day to start painting the week (eg. sunday) 12 | * `weeksInMonth` : How many weeks to show in a month. Normally this varies between 4 and 6, depending on the given start of the week and the start of the month. You can fix the amount of weeks by setting this attribute. Additional days will be filled with dates from the month before and after. 13 | * `yearArrow` : if true it shows arrows to go to previous and next year 14 | * `disableDates` : default 0 (no dates disabled), -1 disable past dates, 1 disable future dates (today is always enabled) 15 | 16 | Some example that sets some attributes: 17 | 18 | ```js 19 | $("#calendar").jqmCalendar({ 20 | events : [ { "summary" : "Test event", "begin" : new Date(), "end" : new Date() } ], 21 | months : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], 22 | days : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], 23 | startOfWeek : 0 24 | }); 25 | ``` 26 | 27 | Dates should be given as JavaScript `Date` Object, which takes several arguments: 28 | 29 | ```js 30 | new Date(); // now 31 | new Date(value); // Integer value of milliseconds since 1 January 1970 00:00:00 UTC 32 | new Date(dateString); // Date string RFC/ISO 33 | new Date(year, month [, day, hour, minute, second, millisecond]); 34 | ``` 35 | 36 | Listen to changes via the event: 37 | ```js 38 | $("#calendar").bind('change', function(event, date) { 39 | console.log(date); 40 | }); 41 | ``` 42 | for example to show a text on a day without events: 43 | ```js 44 | $("#calendar").bind('change', function(event, date) { 45 | // Fetch the events from the jqm-calendar object stored in the jQuery data 46 | var events = $("#calendar").data("jqm-calendar").settings.events; 47 | // Check if any events on this date exist 48 | for ( var i = 0; i < events.length; i++ ) { 49 | if ( events[i].begin.getFullYear() == date.getFullYear() && // same year? 50 | events[i].begin.getMonth() == date.getMonth() && // same month? 51 | events[i].begin.getDate() == date.getDate() ) { // same date? 52 | // There is an event! 53 | $("#message").html(""); 54 | return false; 55 | } 56 | } 57 | // There is no event! 58 | $("#message").html('

There is No event at '+date+'

'); 59 | }); 60 | ``` 61 | (http://stackoverflow.com/questions/18850906/how-to-check-the-jqm-calendar-date-have-event-or-no-event-in-jquery-mobile) 62 | 63 | For example to show a text on a day without events: 64 | ```js 65 | $("#calendar").bind('change', function(event, date) { 66 | // Fetch the events from the jqm-calendar object stored in the jQuery data 67 | var events = $("#calendar").data("jqm-calendar").settings.events; 68 | // Check if any events on this date exist 69 | for ( var i = 0; i < events.length; i++ ) { 70 | if ( events[i].begin.getFullYear() == date.getFullYear() && // same year? 71 | events[i].begin.getMonth() == date.getMonth() && // same month? 72 | events[i].begin.getDate() == date.getDate() ) { // same date? 73 | // There is an event! 74 | $("#message").html(""); 75 | return false; 76 | } 77 | } 78 | // There is no event! 79 | $("#message").html('

There is No event at '+date+'

'); 80 | }); 81 | ``` 82 | (http://stackoverflow.com/questions/18850906/how-to-check-the-jqm-calendar-date-have-event-or-no-event-in-jquery-mobile) 83 | 84 | Change the current month by calling refresh: 85 | ```js 86 | $("#calendar").trigger('refresh'); 87 | // or : 88 | $("#calendar").trigger('refresh', new Date("2013-01-01")); 89 | ``` 90 | 91 | 92 | `bg` parameter can be used to change the color of the event in the event list 93 | -------------------------------------------------------------------------------- /jw-jqm-cal.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.jqmCalendar = function(element, options) { 3 | 4 | var defaults = { 5 | // Array of events 6 | events : [], 7 | // Event handler, 8 | eventHandler : { 9 | // getImportanceOfDay (date, callback). callback should be called 10 | // with importance as an argument. Currently, 0 (no events), 1 (e.g. 11 | // one event) and 2 (more than one event) are supported. 12 | getImportanceOfDay : getImportanceOfDay, 13 | // getEventOnDay (begin, end, callback). callback should be called 14 | // with the list of events 15 | getEventsOnDay : getEventsOnDay 16 | }, 17 | // Default properties for events 18 | begin : "begin", 19 | end : "end", 20 | summary : "summary", 21 | bg: "bg", // as per http://stackoverflow.com/questions/18782689/how-to-change-the-background-image-on-particular-date-in-calendar-based-on-event 22 | itemIndex: "itemIndex", 23 | icon: "icon", 24 | url: "url", 25 | // Sting to use when event is all day 26 | allDayTimeString: '', 27 | // Theme 28 | theme : "c", 29 | // Date variable to determine which month to show and which date to select 30 | date : new Date(), 31 | // Version 32 | version: "1.0.1", 33 | // Array of month strings (calendar header) 34 | months : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], 35 | // Array of day strings (calendar header) 36 | days : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"], 37 | yearArrow : false, 38 | disableDates : 0, //0 none, -1 past, +1 future 39 | // Most months contain 5 weeks, some 6. Set this to six if you don't want the amount of rows to change when switching months. 40 | weeksInMonth : undefined, 41 | // Start the week at the day of your preference, 0 for sunday, 1 for monday, and so on. 42 | startOfWeek : 0, 43 | // List Item formatter, allows a callback to be passed to alter the contect of the list item 44 | listItemFormatter : listItemFormatter 45 | }; 46 | 47 | var plugin = this, 48 | today = new Date(); 49 | plugin.settings = null; 50 | 51 | var $element = $(element).addClass("jq-calendar-wrapper"), 52 | $table, 53 | $header, 54 | $tbody, 55 | $listview; 56 | 57 | function init() { 58 | plugin.settings = $.extend({}, defaults, options); 59 | plugin.settings.theme = $.mobile.getInheritedTheme($element, plugin.settings.theme); 60 | 61 | $table = $(""); 62 | 63 | // Build the header 64 | var $thead = $("").appendTo($table), 65 | $tr = $("").appendTo($thead), 66 | $th = $("").appendTo($thead); 105 | 106 | // The way of determing the labels for the days is a bit awkward, but works. 107 | for ( var i = 0, days = [].concat(plugin.settings.days, plugin.settings.days).splice(plugin.settings.startOfWeek, 7); i < 7; i++ ) { 108 | $tr.append(""); //lp20150515 109 | } 110 | 111 | $tbody = $("").appendTo($table); 112 | 113 | $table.appendTo($element); 114 | $listview = $("").appendTo($tbody); 297 | 298 | // Previous month 299 | while ( daysBefore > 0 ) { 300 | addCell(row, new Date(year, month, 1 - daysBefore), true); 301 | daysBefore--; 302 | daysInWeekCount++; 303 | } 304 | 305 | // Current month 306 | while ( daysInWeekCount < 7 && daysInMonthCount <= daysInMonth ) { 307 | addCell(row, new Date(year, month, daysInMonthCount), false, daysInMonthCount === date.getDate() ); 308 | daysInWeekCount++; 309 | daysInMonthCount++; 310 | } 311 | 312 | // Next month 313 | while ( daysInMonthCount > daysInMonth && daysInWeekCount < 7 ) { 314 | addCell(row, new Date(year, month, daysInMonth + daysAfterCount), true); 315 | daysInWeekCount++; 316 | daysAfterCount++; 317 | } 318 | } 319 | 320 | //lp20150515 321 | for ( var i = 0, days = [].concat(plugin.settings.days, plugin.settings.days).splice(plugin.settings.startOfWeek, 7); i < 7; i++ ) { 322 | document.getElementById('nameday'+i).innerHTML=days[i]; 323 | } 324 | 325 | 326 | $element.trigger('create'); 327 | } 328 | 329 | $element.bind('change', function(originalEvent, begin) { 330 | var end = new Date(begin.getFullYear(), begin.getMonth(), begin.getDate() + 1, 0,0,0,0); 331 | // Empty the list 332 | $listview.empty(); 333 | 334 | plugin.settings.eventHandler.getEventsOnDay(begin, end, function(list_of_events) { 335 | for(var i = 0, event; event = list_of_events[i]; i++ ) { 336 | var summary = event[plugin.settings.summary], 337 | bg = event[plugin.settings.bg], 338 | itemIndex = event[plugin.settings.itemIndex], 339 | beginTime = (( event[plugin.settings.begin] > begin ) ? event[plugin.settings.begin] : begin ).toTimeString().substr(0,5), 340 | endTime = (( event[plugin.settings.end] < end ) ? event[plugin.settings.end] : end ).toTimeString().substr(0,5), 341 | timeString = beginTime + "-" + endTime, 342 | $listItem = $("
  • ").appendTo($listview); 343 | plugin.settings.listItemFormatter( $listItem, timeString, summary, event ); 344 | } 345 | $listview.trigger('create').filter(".ui-listview").listview('refresh'); 346 | }); 347 | }); 348 | 349 | function listItemFormatter($listItem, timeString, summary, event) { 350 | var text = ( ( timeString != "00:00-00:00" ) ? timeString : plugin.settings.allDayTimeString ) + " " + summary; 351 | if (event[plugin.settings.icon]) { 352 | // $listItem.attr('data-role', 'button'); 353 | // $listItem.attr('data-icon', event.icon); 354 | // $listItem.attr('data-iconpos', "left"); 355 | $listItem.addClass("ui-icon-"+event.icon); 356 | $listItem.addClass("ui-btn-icon-right"); 357 | } 358 | if (event[plugin.settings.bg]) { 359 | $listItem.addClass(event.bg); 360 | } 361 | if (event[plugin.settings.itemIndex]) { 362 | $listItem.attr('id','id'+event.itemIndex); 363 | } 364 | if (event[plugin.settings.url]) { 365 | $('').text( text ).attr( 'href', event[plugin.settings.url] ).appendTo($listItem); 366 | } else { 367 | $listItem.text( text ); 368 | } 369 | 370 | } 371 | 372 | $element.bind('refresh', function(event, date) { 373 | refresh(date); 374 | }); 375 | 376 | init(); 377 | }; 378 | 379 | $.fn.jqmCalendar = function(options) { 380 | return this.each(function() { 381 | if (!$(this).data('jqmCalendar')) { 382 | $(this).data('jqmCalendar', new $.jqmCalendar(this, options)); 383 | } 384 | }); 385 | } 386 | 387 | })(jQuery); 388 | --------------------------------------------------------------------------------
    "); 67 | 68 | $("Previous").click(function() { 69 | refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() - 1, 70 | plugin.settings.date.getDate()<=_daysInMonth(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() - 1))?plugin.settings.date.getDate():_daysInMonth(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() - 1)) 71 | 72 | )); 73 | }).appendTo($th); 74 | 75 | if (plugin.settings.yearArrow) { 76 | $("Previous").click(function() { 77 | refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() - 12, 78 | plugin.settings.date.getDate()<=_daysInMonth(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() -12))?plugin.settings.date.getDate():_daysInMonth(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() -12)) 79 | 80 | )); 81 | }).appendTo($th); 82 | } 83 | 84 | $header = $("").appendTo($th); 85 | 86 | $("Next").click(function() { 87 | var newDay= plugin.settings.date.getDate(); 88 | var maxDay=_daysInMonth(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() + 1),0); 89 | if (newDay>maxDay) {newDay=maxDay;} 90 | refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() + 1, newDay)); 91 | }).appendTo($th); 92 | 93 | if (plugin.settings.yearArrow) { 94 | $("Next").click(function() { 95 | refresh(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() + 12, 96 | plugin.settings.date.getDate()<=_daysInMonth(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() + 12))?plugin.settings.date.getDate():_daysInMonth(new Date(plugin.settings.date.getFullYear(), plugin.settings.date.getMonth() + 12)) 97 | 98 | )); 99 | }).appendTo($th); 100 | } 101 | 102 | $th.appendTo($tr); 103 | 104 | $tr = $("
    " + days[i] + "
    ").appendTo($row), 176 | $a = $("