{"id":524,"date":"2009-04-03T02:19:02","date_gmt":"2009-04-03T08:19:02","guid":{"rendered":"http:\/\/bililite.nfshost.com\/blog\/?p=524"},"modified":"2015-02-25T11:55:05","modified_gmt":"2015-02-25T17:55:05","slug":"new-jquery-widget-flexcal","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2009\/04\/03\/new-jquery-widget-flexcal\/","title":{"rendered":"New jQuery Widget: <code>flexcal<\/code>"},"content":{"rendered":"<p><strong>Updated 2015-02-25 to version 3.0, with the new subclassing code.<\/strong><\/p>\r\n<p><strong>Updated 2015-02-16 to document changes in default URL and need for separate CSS file.<\/strong><\/p>\r\n<p><strong>Updated 2015-02-13 to document additional parameters.<\/strong><\/p>\r\n<p><strong>Updated 2015-01-28 to link to github.<\/strong><\/p>\r\n<script src=\"\/inc\/jquery.ui.subclass.js\"><\/script>\r\n<script src=\"\/inc\/jquery.textpopup.js\"><\/script>\r\n<script src=\"\/inc\/jquery.flexcal.js\"><\/script>\r\n<script src=\"\/inc\/jquery.scrollintoview.js\"><\/script>\r\n<script>\r\n  $('<link rel=stylesheet href=\"\/inc\/flexcal.css\" \/>').appendTo('head');\r\n<\/script>\r\n<h4>Just what the world needs&mdash;another date picker<\/h4>\r\n<p><a href=\"https:\/\/github.com\/dwachss\/flexcal\">Download the code from github<\/a>. You need <code>jquery.ui.subclass.js<\/code>, <code>jquery.textpopup.js<\/code>, <code>\/inc\/jquery.flexcal.js<\/code> and <code>flexcal.css<\/code>.<\/p>\r\n<!--more-->\r\n<p>The current incarnation of the <a href=\"http:\/\/jqueryui.com\/demos\/datepicker\/\">jQuery UI datepicker<\/a> works fine, but I needed something that could handle the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Jewish_calendar\">Jewish calendar<\/a>. This is not the same as localizing <code>datepicker<\/code> to use Hebrew;that just translates the month and day names but uses the same <a href=\"http:\/\/en.wikipedia.org\/wiki\/Gregorian_calendar\">Gregorian calendar<\/a> as everyone uses. I needed a calendar that could switch between multiple, completely different calendar systems.<\/p>\r\n<p>The algorithms for converting dates from Jewish to Gregorian are readily available <a href=\"http:\/\/sourceforge.net\/projects\/hebcal\/\">open-source<\/a>, so that was easy. <a href=\"\/blog\/2009\/01\/02\/new-ui-widgets-textpopup-and-hebrewkeyboard\/\"><code>textpopup<\/code><\/a> is exactly what I need to create the pop-up box for the calendar, and I had already created my own date picker for my old <a href=\"http:\/\/bililite.com\">bililite site<\/a> (don't look at it too closely; it's ugly and I used an old version of Prototype. I was still learning! It works, though). So the pieces were all there.<\/p>\r\n<p>And so was born <code>flexcal<\/code>. In its simplest form, it looks like <code>datepicker<\/code>:<\/p>\r\n<pre><code class=\"language-html demo\">&lt;span&gt;Using &lt;code&gt;datepicker&lt;\/code&gt;: &lt;\/span&gt;&lt;input id=&quot;date1&quot;\/&gt;\r\n&lt;br\/&gt;\r\n&lt;span&gt;Using &lt;code&gt;flexcal&lt;\/code&gt;: &lt;\/span&gt;&lt;input id=&quot;date2&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">$('#date1').datepicker();$('#date2').flexcal();<\/code><\/pre>\r\n<p>But it can show multiple calendars and allows localization to different calendar systems:<\/p>\r\n<pre><code class=\"language-html demo\">&lt;span&gt;Jewish\/civil calendar: &lt;\/span&gt;&lt;input id=&quot;date3&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">$('#date3').flexcal({\r\n  position: 'bl',\r\n  calendars: ['en', 'jewish', 'he-jewish'],\r\n  'class': 'multicalendar'\r\n});<\/code><\/pre>\r\n<p>And it allows animated transitions (which I think is in the works for datepicker as well):<\/p>\r\n<pre><code class=\"language-html demo\">&lt;span&gt;Fading transition: &lt;\/span&gt;&lt;input id=&quot;date3-1&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">$('#date3-1').flexcal({\r\n  position: 'bl',\r\n  transition: function(o){\r\n    o.elements.eq(o.currSlide).fadeOut(o.duration);\r\n    o.elements.eq(1-o.currSlide).fadeIn(o.duration);\r\n  },\r\n  transitionOptions: {duration: 'slow'}\t\r\n});<\/code><\/pre>\r\n<h4>Options<\/h4>\r\n<p>It's a subclass of <a href=\"\/blog\/2009\/01\/02\/new-ui-widgets-textpopup-and-hebrewkeyboard\/\"><code>textpopup<\/code><\/a>, so all the options from <a href=\"\/blog\/2009\/01\/02\/new-ui-widgets-textpopup-and-hebrewkeyboard\/\"><code>textpopup<\/code><\/a> and <a href=\"\/blog\/2009\/03\/25\/new-widgets-googlesearch-and-ajaxpopup\/\"><code>ajaxpopup<\/code><\/a> are available. The <code>url<\/code> defaults to a data URL (so no waiting for AJAX loading), which contains:<\/p>\r\n<div id=\"htmldisplay\">\r\n<pre><code><\/code><\/pre><\/div>\r\n<script>\r\n  $('#htmldisplay code').html($.bililite.flexcal.prototype.options.url.replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;'));\r\n<\/script>\r\n<p>Note that all the required CSS is the flexcal.css file, and that it uses the <a href=\"http:\/\/jqueryui.com\/themeroller\/\">themeable jQuery classes<\/a>. Setting the <code>'class'<\/code> option to <code>multicalendar<\/code> makes the date rectangles longer, giving more room for the tab bar. Setting <code>'class'<\/code> to <code>fontawesome<\/code> makes the calendar use <a href=\"http:\/\/fortawesome.github.io\/Font-Awesome\/\">Font Awesome<\/a> icons rather than the jQuery UI ones.<\/p>\r\n<p>The <code>flexcal<\/code> options themselves are:<\/p>\r\n\r\n<div class=\"prelike\"><dl>\r\n<dt><code>calendars {Array(String || Object)}<\/code><\/dt>\r\n<dd>Array of calendars to display. Each string is a key into the $.bililite.flexcal.l10n object.\r\nDefault is ['en'], which means that the default is one calendar, using the localization of\r\n$.bililite.flexcal.l10n.en. Calendar names are always of the form <strong>lowercase two-letter language code, then optionally an upper case two letter country code, then optionally a lower case calendar system name (default: 'gregorian')<\/strong>, all delimited by hyphens. Thus, <code>'zh-TW-islamic'<\/code>. The code will try to find a localization in the <a href=\"http:\/\/jqueryui.com\/datepicker\/#localization\">jQuery UI datepicker<\/a> or in <a href=\"http:\/\/keith-wood.name\/calendarsRef.html\">Keith Woods's calendarspicker<\/a> if available. If the string cannot be recognized as a calendar name, it is assumed to mean <code class=\"language-javascript\" >{name: name}<\/code>, a localization object where everything is the default except the displayed name of the calendar.<\/dd>\r\n<dd>If the item is an object then it is the localization object itself. If the item is itself an array, then each item is recursively evaluated and all the resulting localization objects are<code class=\"language-javascript\" > $.extend<\/code>ed together.<\/dd>\r\n<dd>Thus, <code class=\"language-javascript\" >calendars: ['en', 'he-jewish', ['ar-islamic', 'Arabic']]<\/code> displays three calendars, an English Gregorian calendar, a Hebrew Jewish calendar (both with their default names) and an Arabic Islamic calendar named <code class=\"language-javascript\" >'Arabic'<\/code> (the string is not a calendar name, so it is interpreted as <code class=\"language-javascript\" >{name: 'Arabic'}<\/code> which modifies the <code class=\"language-javascript\" >$.bililite.flexcal.l10n['ar-islamic']<\/code> object.<\/dd>\r\n<dt><code>tab {Number}<\/code><\/dt>\r\n<dd>Index into the <code>calendars<\/code> array of the one to display when initially shown<\/dd>\r\n<dt><code>current {Date|String}<\/code><\/dt>\r\n<dd>If the element value is not set to a valid date, then use this as the initial display date.<\/dd>\r\n<dt><code>filter {undefined|Function}<\/code><\/dt>\r\n<dd>Function to filter dates. Function is of the form f(d) where d is a <a href=\"http:\/\/www.w3schools.com\/jsref\/jsref_obj_date.asp\">Date object<\/a>; it should return true enable that date or false to disable it. <code class=\"language-javascript\">this<\/code> is set to the &lt;a&gt; element that contains the date number. See the examples below.<\/dd>\r\n<dt><code>transitionOptions<\/code><\/dt>\r\n<dd>Options to pass to the transition function, below<\/dd>\r\n<dt><code>transition {Function}<\/code><\/dt>\r\n<dd>Function to handle the transition from one calendar or month to another.\r\nSignature is function(options), where options is copied from transitionOptions,\r\naugmented by the following fields:\r\n  <dl>\r\n  <dt><code>options.$cont<\/code><\/dt>\r\n  <dd>jQuery object that is the container for the calendars<\/dd>\r\n  <dt><code>options.elements<\/code><\/dt>\r\n  <dd>jQuery object that has two elements, each an absolutely-positioned &lt;div&gt;\r\none on top of the other, that are the calendars to be transitioned<\/dd>\r\n  <dt><code>options.currSlide<\/code><\/dt>\r\n  <dd>The index of the current calendar. Thus, options.elements.eq(options.currSlide)\r\nis the currently-showing calendar and options.elements.eq(1-options.currSlide)\r\nis the currently hidden calendar that needs to be shown<\/dd>\r\n  <dt><code>options.rev<\/code><\/dt>\r\n  <dd>Boolean to indicate that the animation should show a \"reverse\" transition,\r\ngoing to a previous month.<\/dd>\r\n  <dt><code>options.l10n<\/code><\/dt>\r\n  <dd>Localization object for the calendar to be displayed\r\n<code class=\"language-javascript\" >(options.elements.eq(1-options.currSlide))<\/code>. The transition function can\r\nuse <code class=\"language-javascript\" >options.l10n.isRTL<\/code> to determine if \"next month\" should be animated\r\nright-to-left or left-to-right<\/dd>\r\n  <\/dl>\r\nThe default is function(o){\r\n\t\to.elements.eq(o.currSlide).hide();\r\n\t\to.elements.eq(1-o.currSlide).show();\r\n\t}<\/dd>\r\n<dt><code>hidetabs {true|false|'conditional'}<\/code><\/dt>\r\n<dd>True to hide the tab bar, false to show it and 'conditional' to\r\nhide it if there is only one calendar to display. Default is 'conditional'.<\/dd>\r\n<dt><code>reposition {true|false}<\/code><\/dt>\r\n<dd>True to reposition the calendar with every transition; useful if the calendar is above the text element and transitions to months with more weeks obscures the box. Default is True.<\/dd>\r\n<dt><code>l10n {Object (see below)}<\/code><\/dt>\r\n<dd>Localization object to use if one of the fields in the calendar array item is undefined<\/dd>\r\n<\/dl><\/div>\r\n\r\n\r\n\r\n\r\n<p>The localization (<a href=\"http:\/\/en.wiktionary.org\/wiki\/L10n\">l10n<\/a> for short) object is the key to the whole thing. $.flexcal.l10n contains objects, each of which is a localization object with the following fields (named to match the corresponding fields in $.datepicker.regional):<\/p>\r\n<div class=\"prelike\"><dl>\r\n<dt><code>name {String}<\/code><\/dt><dd>Default display name<\/dd>\r\n<dt><code>calendar {Function}<\/code><\/dt><dd>Calendar generating function, defaults to Gregorian calendar.\r\nTakes a Date object, <code>d<\/code>,  and returns an object with the following fields:\r\n<dl>\r\n  <dt><code>first {Date}<\/code><\/dt><dd>First date of the month containing <code>d<\/code><\/dd>\r\n  <dt><code>last {Date}<\/code><\/dt><dd>Last date of the month containing <code>d<\/code><\/dd>\r\n  <dt><code>prev {Date}<\/code><\/dt><dd>Date one month before <code>d<\/code><\/dd>\r\n  <dt><code>next {Date}<\/code><\/dt><dd>Date one month after <code>d<\/code><\/dd>\r\n  <dt><code>prevYear {Date}<\/code><\/dt><dd>Date one year before <code>d<\/code><\/dd>\r\n  <dt><code>nextYear {Date}<\/code><\/dt><dd>Date one year after <code>d<\/code><\/dd>\r\n  <dt><code>y {Number}<\/code><\/dt><dd>Number of the year of <code>d<\/code><\/dd>\r\n  <dt><code>m {Number}<\/code><\/dt><dd>0-indexed number of the month of <code>d<\/code><\/dd>\r\n  <dt><code>d {Number}<\/code><\/dt><dd>Date of the month of <code>d<\/code><\/dd>\r\n  <dt><code>dow {Number}<\/code><\/dt><dd>0-indexed number of the day of the week of the first day of the month. Note that this is not necessarily just first.getDay(), since this calendar system may use some other \"week\" system.<\/dd>\r\n  <dt><code>toDate {Function}<\/code><\/dt><dd>Function that takes an object <code class=\"language-javascript\" >{y: y, m: m, d: d}<\/code> representing the date in this calendar and returns the corresponding Javascript Date. Not currently used; I plan on implementing some sort of date parsing (<a href=\"https:\/\/github.com\/dwachss\/flexcal\/issues\/4\">Issue #4<\/a>) that will use this. It is optional; if not present, will use a binary search to find the right date. If the values given are invalid, should either return <code class=\"language-javascript\" >new Date(undefined)<\/code> or do some error correcting the way <code class=\"language-javascript\" >new Date(y, m, d)<\/code> does, e.g. turning 0 dates into the last day of the previous month.<\/dd>\r\n<\/dl>\r\n<\/dd>\r\n<dt><code>monthNames {Array(String)}<\/code><\/dt><dd>Names of the months<\/dd>\r\n<dt><code>dayNamesMin {Array(String)}<\/code><\/dt><dd>Names of the days of the week<\/dd>\r\n<dt><code>isRTL {Boolean}<\/code><\/dt><dd>True if the calendar should display right-to-left<\/dd>\r\n<dt><code>firstDay {Number}<\/code><\/dt><dd>Day of the week (0-indexed) that the calendar should start. Not currently implemented (<a href=\"https:\/\/github.com\/dwachss\/flexcal\/issues\/5\">Issue #5<\/a>), always assumes 0.\r\n<dt><code>prevText {String}<\/code><\/dt><dd>Wording on the \"previous month\" button. The CSS for\r\njQuery UI replaces this with an icon but still uses the text for the title. By the jQuery UI\r\nguidelines, it should not include an arrow or chevron<\/dd>\r\n<dt><code>nextText {String}<\/code><\/dt><dd>Wording on the \"next month\" button<\/dd>\r\n<dt><code>years {Function}<\/code><\/dt><dd>Function to convert a year number to the displayed string.\r\nDefault is function(n) {return n}<\/dd>\r\n<dt><code>fromYears {Function}<\/code><\/dt><dd>Inverse of years, above. Function to convert a string into a number. If undefined, will not parse year strings but only allow numbers. Not currently used; I plan on implementing some sort of date parsing (<a href=\"https:\/\/github.com\/dwachss\/flexcal\/issues\/4\">Issue #4<\/a>) that will use this.<\/dd>\r\n<dt><code>dates{Function}<\/code><\/dt><dd>Function to convert a date number to the displayed string. Default is function(n) {return n}<\/dd>\r\n<dt><code>fromDates {Function}<\/code><\/dt><dd>Inverse of years, above. Function to convert a string into a number.  If undefined, will not parse date strings but only allow numbers.. Not currently used; I plan on implementing some sort of date parsing (<a href=\"https:\/\/github.com\/dwachss\/flexcal\/issues\/4\">Issue #4<\/a>) that will use this.<\/dd>\r\n<\/dl>\r\n<\/div>\r\n\r\n\r\n<pre><code class=\"language-javascript\">\r\n\/\/ default l10n calendar\r\n$.bililite.flexcal.prototype.options.l10n = {\r\n\tname: 'flexcal',\r\n\tcalendar: function(d){\r\n\t\tvar m = d.getMonth(), y = d.getFullYear(), date = d.getDate(), first = new Date (y, m, 1);\r\n\t\tvar prev = new Date (y, m-1, date), next = new Date (y, m+1, date);\r\n\t\tif (prev.getDate() != date) prev = new Date (y, m, 0); \/\/ adjust for too-short months\r\n\t\tif (next.getDate() != date) next = new Date (y, m+2, 0);\r\n\t\treturn {\r\n\t\t\tfirst: first,\r\n\t\t\tlast: new Date (y, m+1, 0),\r\n\t\t\tprev: prev,\r\n\t\t\tnext: next,\r\n\t\t\tm: m,\r\n\t\t\ty: y,\r\n\t\t\tdow: first.getDay()\r\n\t\t};\r\n\t},\r\n\tmonthNames: ['January','February','March','April','May','June',\r\n\t\t'July','August','September','October','November','December'],\r\n\tdayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'],\r\n\tisRTL: false,\r\n\tprevText: 'Previous',\r\n\tnextText: 'Next',\r\n\tyears: function(n) {return n},\r\n\tdays: function(n) {return n}\r\n};\r\n<\/code><\/pre>\r\n<p>The API (publicly accessible methods) is documented in <a href=\"\/blog\/2011\/10\/26\/the-flexcal-api-and-an-inline-flexcal\/\" title=\"The flexcal API and an inline flexcal\">a later post<\/a>.<\/p>\r\n<p>The plugin comes with three localizations defined (the ones I wanted): <code>$.bililite.flexcal.l10n.en<\/code> (English-language civil calendar), <code>$.bililite.flexcal.l10n.jewish<\/code> (Jewish  calendar with English names) and <code>$.bililite.flexcal.l10n['he-jewish']<\/code> (Jewish  calendar with Hebrew names), and two calendar-generating functions:  <code>$.bililite.flexcal.calendars.gregorian<\/code> and <code>$.bililite.flexcal.calendars.jewish<\/code>.<\/p>\r\n<p>The options object that is passed to the transition function was designed to allow drop-in use of Mike Alsup's excellent <a href=\"http:\/\/www.malsup.com\/jquery\/cycle\/\">cycle plugin<\/a>, with <code class=\"language-javascript\">$(selector).flexcal({transition: $.fn.cycle.next})<\/code>, though it <a href=\"http:\/\/bililite.com\/blog\/2009\/05\/05\/flexcal-and-cycle\/\" title=\"flexcal and cycle\">doesn't work that easily<\/a>.<\/p>\r\n<h4>Examples<\/h4>\r\n<p>French\/English calendar. We grab the French localization from the <a href=\"https:\/\/rawgit.com\/jquery\/jquery-ui\/master\/ui\/i18n\/datepicker-fr.js\"><code>datepicker<\/code> svn<\/a>.<\/p>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date4&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">$.getScript('https:\/\/rawgit.com\/jquery\/jquery-ui\/master\/ui\/i18n\/datepicker-fr.js', function(){\r\n  $.datepicker.setDefaults($.datepicker.regional['']);\r\n  $.bililite.flexcal.l10n.fr = $.datepicker.regional.fr;\r\n  $('#date4').flexcal({\r\n    position: 'rt',\r\n    calendars: [['fr', 'Fran&#231;ais'], ['en','Anglais']]\r\n  });\r\n});<\/code><\/pre>\r\n<p>The <a href=\"http:\/\/en.wikipedia.org\/wiki\/French_Revolutionary_Calendar\">French Revolutionary calendar<\/a>. This is just to show off how flexible the widget is; 10-day weeks and 5-day months are no problem. View source to see the calendar algorithms.<\/p>\r\n<script>\r\n$.bililite.flexcal.l10n.jacobin = {\r\n\tname: 'Jacobin',\r\n\tcalendar: function(d){\r\n\t\tvar j = (function (d){\r\n\t\t\t\/\/ algorithm from Romme's rule; valid 1992-2091. See http:\/\/en.wikipedia.org\/wiki\/French_Revolutionary_Calendar#Converting_from_the_Gregorian_Calendar\r\n\t\t\t\/\/ look at  http:\/\/www.fourmilab.ch\/documents\/calendar\/ for more accurate algorithms\r\n\t\t\tvar y = d.getFullYear();\r\n\t\t\tvar jNY = new Date(y, 8, 22); \/\/ Jacobin New Year\r\n\t\t\tif (jNY > d) jNY = new Date(y-1, 8, 22);\r\n\t\t\tvar jD = (d-jNY)\/(24*60*60*1000); \/\/ day of the Jacobin year, 0-indexed\r\n\t\t\treturn {y: jNY.getFullYear()-1791, m: Math.floor(jD\/30), d: Math.floor(jD % 30)+1};\r\n\t\t})(d);\r\n\t\t\/\/ number of Sans-culottide days this year (5 for regular year, 6 for leap year. Our algorithm is only accurate for 1992-2091, so this is simple\r\n\t\tfunction sc() {return d.getFullYear() % 4 == 0 ? 6 : 5}\r\n\t\tfunction addDay(d, n){\r\n\t\t\tif (n === undefined) n = 1;\r\n\t\t\treturn new Date(d.getFullYear(), d.getMonth(), d.getDate()+n);\r\n\t\t}\r\n\t\tvar prev = addDay(d, -30);\r\n\t\tif (j.m == 0) if (j.d > sc()) prev = addDay(prev, 31-sc()-j.d);\r\n\t\tvar next = addDay(d, 30);\r\n\t\tif (j.m == 11) if (j.d > sc()) next = addDay(next, -j.d+sc());\r\n\t\tvar first = addDay(d, -j.d+1)\r\n\t\treturn {\r\n\t\t\tfirst: first,\r\n\t\t\tlast: addDay(first, j.m == 12 ? sc()-1 : 29),\r\n\t\t\tprev: prev,\r\n\t\t\tnext: next,\r\n\t\t\tm: j.m, \r\n\t\t\ty: j.y,\r\n\t\t\tdow: 0\r\n\t\t};\r\n\t},\r\n\tmonthNames: [\"Vend&#233;miaire\", \"Brumaire\", \"Frimaire\", \"Niv&#244;se\",\r\n\t\t\"Pluvi&#244;se\", \"Vent&#244;se\", \"Germinal\", \"Flor&#233;al\", \"Prairial\",\r\n\t\t\"Messidor\", \"Thermidor\", \"Fructidor\", \"Sans-culottide\"],\r\n\tdayNamesMin: ['1<sup>i<\/sup>','2<sup>i<\/sup>','3<sup>i<\/sup>','4<sup>i<\/sup>','5<sup>i<\/sup>',\r\n\t\t'6<sup>i<\/sup>','7<sup>i<\/sup>','8<sup>i<\/sup>','9<sup>i<\/sup>','10<sup>i<\/sup>'],\r\n\tyears: archaicNumbers([ \r\n\t\t[1000, 'M'], \r\n\t\t[900, 'CM'], \r\n\t\t[500, 'D'], \r\n\t\t[400, 'CD'], \r\n\t\t[100, 'C'], \r\n\t\t[90, 'XC'], \r\n\t\t[50, 'L'], \r\n\t\t[40, 'XL'], \r\n\t\t[10, 'X'], \r\n\t\t[9, 'IX'], \r\n\t\t[5, 'V'], \r\n\t\t[4, 'IV'], \r\n\t\t[1, 'I'] \r\n\t])\r\n};\r\n<\/script>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date5&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">$('#date5').flexcal({\r\n  position: 'rt',\r\n  calendars: ['en', 'jacobin']\r\n});\r\n<\/code><\/pre>\r\n<p><code>flexcal<\/code> with fancier transitions and using my <code>scrollIntoView<\/code> plugin (put the input box at the bottom of the window to see the scrolling effect)<\/p>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date6&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">$('#date6').flexcal({\r\n\tposition: 'bl',\r\n\tcalendars: ['en', 'jewish'],\r\n\ttransition: function(o){\r\n\t\tvar dir = o.rev ^ o.l10n.isRTL;\r\n\t\tvar first = o.elements.eq(o.currSlide), second = o.elements.eq(1-o.currSlide);\r\n\t\tvar h = o.$cont.height(), w = o.$cont.width();\r\n\t\tfirst.css({zIndex: 1});\r\n\t\tsecond.css({zIndex: 0}).show();\r\n\t\tfirst.animate({foo: 0}, { \/\/ the {foo:0} seems necessary because we need to animate some property, even if it isn't real\r\n\t\t\tduration: o.speed,\r\n\t\t\tstep: function(now, fx){\r\n\t\t\t\tif (fx.state == 0){\r\n\t\t\t\t\tfx.start = now = dir ? 0 : w;\r\n\t\t\t\t\tfx.end = dir ? w : 0;\r\n\t\t\t\t}\r\n\t\t\t\tif (dir){\r\n\t\t\t\t\tfirst.css('clip', 'rect(0px '+w+'px '+h+'px '+now+'px)');\r\n\t\t\t\t\tsecond.css('clip', 'rect(0px '+now+'px '+h+'px 0px)');\r\n\t\t\t\t}else{\r\n\t\t\t\t\tfirst.css('clip', 'rect(0px '+now+'px '+h+'px 0px)');\r\n\t\t\t\t\tsecond.css('clip', 'rect(0px '+w+'px '+h+'px '+now+'px)');\r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\tcomplete: function() {\r\n\t\t\t\t\/\/ clip is so inconsistently implemented. This way works in FF3, Opera 9, Safari 3,  IE7\r\n\t\t\t\tfirst.hide().css('clip', 'rect(auto)');\r\n\t\t\t\tsecond.css('clip', 'rect(auto)');\r\n\t\t\t}\r\n\t\t});\r\n\t},\r\n\ttransitionOptions: {speed: 'slow'},\r\n\tshown: function() {$(this).flexcal('box').scrollIntoView()}\r\n});\r\n<\/code><\/pre>\r\n<p>Using <a href=\"http:\/\/docs.jquery.com\/UI\/Draggable\"><code>draggable<\/code><\/a>. The option <code>cancel:  '.ui-state-default'<\/code> makes sure that clickable elements aren't used as drag handles.  A real draggable calendar probably should have the cursor change on hover also.<\/p>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date7&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date8&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">$('#date7').flexcal({\r\n  position: 'rt',\r\n  calendars: ['en', ['fr', 'French']],\r\n  reposition: false\r\n}).flexcal('box').draggable({cancel: '.ui-state-default', cursor: 'move'});\r\n\r\n$('#date8').flexcal({\r\n  position: 'lt',\r\n  calendars: ['en',  ['fr', 'French']],\r\n  reposition: false\r\n}).flexcal('box').draggable({\r\n  cancel: '.ui-state-default',\r\n  cursor: 'move',\r\n  start: function(){\r\n    $(this).css({right: 'auto', bottom: 'auto'});\r\n  }\r\n});\r\n<\/code><\/pre>\r\n<h4>Differences from <code>datepicker<\/code><\/h4>\r\n<p>I intentionally gave this widget fewer options than <code>datepicker<\/code>; I just included what I thought I would need. Since it uses my <a href=\"http:\/\/github.bililite.com\/extending-widgets.html\">subclass-able widget framework<\/a>, it can easily be extended to be more capable. One thing that is still definitely lacking is keyboard accessibility; I don't know anything about that and have to start experimenting. To be added in some later version, for sure.<\/p>\r\n<h4>The power of <a href=\"\/blog\/extending-jquery-ui-widgets\/\">Extending Widgets<\/a><\/h4>\r\n<p>Some examples of extending <code>flexcal<\/code> to be more <code>datepicker<\/code>-like.<\/p>\r\n<h5>Date formatting<\/h5>\r\n<p>The format for the date that is inserted into the text box is very simple; mm\/dd\/yyyy. You can subclass <code>flexcal<\/code> to use <code>datepicker<\/code>'s formatting (as with any subclassing, you should look at the <a href=\"\/inc\/jquery.flexcal.js\">source code<\/a> to figure out what the code is doing):<\/p>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date9&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date10&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">\r\n$.widget('bililite.fancyflexcal', $.bililite.flexcal, {\r\n  format: function(d){\r\n    return $.datepicker.formatDate (this.options.dateFormat, d);\r\n  },\r\n  options: {\r\n    dateFormat: $.datepicker.W3C\r\n  }\r\n});\r\n\r\n$('#date9').fancyflexcal();\r\n$('#date10').fancyflexcal({dateFormat: 'D, M d, yy'});\r\n<\/code><\/pre>\r\n<h5>Filtering dates<\/h5>\r\n<p>Filter dates with the <code>filter<\/code> option:<\/p>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date11&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">\/\/ allow weekdays only\r\n$('#date11').flexcal({\r\n  filter: function(d){ return d.getDay() != 0 && d.getDay() != 6; }\r\n});<\/code><\/pre>\r\n<p>Using the <code>filter<\/code> option to manipulate the css of the calendar:<\/p>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date12&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">\/\/ Put a border around every other Thursday (it's payday!)\r\n$('#date12').flexcal({\r\n  filter: function(d){\r\n    \/\/ is it Thursday and is it an even numbered week since the epoch?\r\n    if (d.getDay() == 4 && Math.floor(d.getTime()\/(1000*60*60*24*7)) %2 == 0){\r\n      $(this).css('border', '2px solid purple'); \/\/ put a nice border on it\r\n    }\r\n    return true; \/\/ don't disable anything\r\n  }\r\n});<\/code><\/pre><h5>Drop-down menus<\/h5>\r\n<p>Creating drop-down menus is a bit more complicated, because we can't assume that all the month names in the <code>monthNames<\/code> array are present in every year, and the definition of the localization calendar routine does not provide with us with a way to get the alternate calendar date for a given <code>Date<\/code>. The following routines help:<\/p>\r\n<div style=\"border: 1px solid black; overflow: scroll; height: 250px\"><pre><code class=\"language-javascript demo\">\r\nfunction option(d, l10n, cal, isMonth, selected){\r\n  return [\r\n    '&lt;option',\r\n    selected ? ' selected=\"selected\"' : '',\r\n    ' value=\"', d.toString(), '\"&gt;',\r\n    isMonth ? l10n.monthNames[cal.m] : l10n.years(cal.y), \r\n    '&lt;\/option&gt;'\r\n  ].join('');\r\n}\r\nwindow.monthSelect = function(currentdate, l10n){\r\n  var f = l10n.calendar;\r\n  var currentcal = f(currentdate), ret = [option(currentdate, l10n, currentcal , true, true)], d = currentdate;\r\n  for (var cal = currentcal; d = cal.prev, cal = f(d), cal.y == currentcal.y; ){\r\n    ret.unshift(option(d, l10n, cal, true, false));\r\n  }\r\n  for (cal = currentcal; d = cal.next, cal = f(d), cal.y == currentcal.y; ){\r\n    ret.push(option(d, l10n, cal, true, false));\r\n  }\r\n  return $('&lt;select&gt;').html(ret.join(''));\r\n};\r\nwindow.yearSelect = function(currentdate, l10n, n){\r\n  var f = l10n.calendar;\r\n  var currentcal = f(currentdate), ret = [option(currentdate, l10n, currentcal , false, true)], d = currentdate;\r\n  for (var i = 0, cal = currentcal; d = cal.prevYear, cal = f(d), i < n; ++i){\r\n    ret.unshift(option(d, l10n, cal, false, false));\r\n  }\r\n  for (var i = 0, cal = currentcal; d = cal.nextYear, cal = f(d), i < n; ++i){\r\n    ret.push(option(d, l10n, cal, false, false));\r\n  }\r\n  return $('&lt;select&gt;').html(ret.join(''));\r\n};\r\n<\/code><\/pre><\/div>\r\n<pre><code class=\"language-html demo\">&lt;input id=&quot;date13&quot;\/&gt;<\/code><\/pre>\r\n<pre><code class=\"language-javascript demo\">\r\n$('#date13').flexcal({'class': 'multicalendar', calendars: ['en','he-jewish']}).flexcal('after', '_adjustHTML', function (cal){\r\n  cal.find('.ui-datepicker-month').html(monthSelect(this.options.current, this.o.l10n));\r\n  cal.find('.ui-datepicker-year').html(yearSelect(this.options.current, this.o.l10n, 5));\r\n  var self = this;\r\n  cal.find('select').bind('change', function(){\r\n    self._setDate(new Date($(this).val()))\r\n  }); \r\n});\r\n<\/code><\/pre>","protected":false},"excerpt":{"rendered":"Updated 2015-02-25 to version 3.0, with the new subclassing code. Updated 2015-02-16 to document changes in default URL and need for separate CSS file. Updated 2015-02-13 to document additional parameters. Updated 2015-01-28 to link to github. Just what the world needs&mdash;another date picker Download the code from github. You need jquery.ui.subclass.js, jquery.textpopup.js, \/inc\/jquery.flexcal.js and flexcal.css.","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/524"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=524"}],"version-history":[{"count":104,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/524\/revisions"}],"predecessor-version":[{"id":577,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/524\/revisions\/577"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=524"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=524"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=524"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}