basic-shamsi
Version:
Converts, validate, manipulate, and display Shamsi (Jalaali) and Miladi (Gregorian) dates
336 lines (300 loc) • 15 kB
JavaScript
(function ($, window, document, undefined) {
//this == $
var pluginName = 'shamsiPicker';
var Plugin = function (elem, options) {
elem = $(elem);
var self = this;
var today = null;
var today_ymd = null;
var cal = null;
var cal_ym;
var selected_ymd;
var viewmode = 0;
options = $.extend(true, {}, $.fn[pluginName].defaults, options);
//----------------
this.close = function () {
elem.focus();
cal.hide();
}
//----------------
this.open = function () {
if (cal.is(':visible') || elem.is('[readonly]')) {
self.close();
return;
}
set_date(elem.val());
var pos = elem.offset();
if (!options.anchorRight)
if (!options.anchorTop) cal.css(adjust_pos({ left: pos.left, top: pos.top + elem.outerHeight() }));
else cal.css(adjust_pos({ left: pos.left, top: pos.top - cal.outerHeight() }));
else
if (!options.anchorTop) cal.css(adjust_pos({ left: pos.left + elem.outerWidth() - cal.outerWidth(), top: pos.top + elem.outerHeight() }));
else cal.css(adjust_pos({ left: pos.left + elem.outerWidth() - cal.outerWidth(), top: pos.top - cal.outerHeight() }));
setTimeout(function () {
cal.show();
cal.focus();
}, 100)
}
function adjust_pos(pos) {
var W = $(window).width();
var H = $(window).height();
//-------
var r = pos.left + cal.outerWidth();
if (r > W) pos.left += W - r;
//-------
var b = pos.top + cal.outerHeight();
if (b > H) pos.top += H - b;
//-------
if (pos.left < 0) pos.left = 0;
if (pos.top < 0) pos.top = 0;
return pos;
}
this.changeDate = function (value, autoclose) {
var x = DateHelper.YMD(value);
if (x[0] < Calendar.year_start) x[0] = Calendar.year_start;
if (x[0] >= Calendar.year_end) x[0] = Calendar.year_end - 1;
value = DateHelper.format('yyyy/MM/dd', x);
set_date(value);
if (autoclose) {
elem.val(value);
elem.change();
self.close();
}
}
function set_date(value) {
today = Calendar.now();
today_ymd = DateHelper.YMD(today);
if (!value || value.trim().length < 10) value = today;
selected_ymd = Calendar.Validate(value);
if (selected_ymd.length) {
if (selected_ymd[0] < Calendar.year_start) selected_ymd[0] = Calendar.year_start;
if (selected_ymd[0] >= Calendar.year_end) selected_ymd[0] = Calendar.year_end - 1;
}
set_cal(selected_ymd[0], selected_ymd[1]);
}
//----------------
function set_viewmode(value) {
viewmode = value % 3;
cal.removeClass('shp-viewmode-1');
cal.removeClass('shp-viewmode-2');
if (viewmode > 0) cal.addClass('shp-viewmode-' + viewmode);
}
//----------------
function set_cal(y, m) {
m = m < 1 ? 1 : (m > 12 ? 12 : m);
y = y < Calendar.year_start ? Calendar.year_start : (y >= Calendar.year_end ? Calendar.year_end - 1 : y);
cal_ym = [y, m];
//-------------
var title_elem = cal.find('.shp-header li:eq(1)');
title_elem.text(y + ' ' + Calendar.getMonthName(m));
//-------------
var dow = Calendar.DOW(y, m, 1);
if (dow == 0) dow = 7;
var last_month = Calendar.Validate([y, m - 1, 1]);
var next_month = Calendar.Validate([y, m + 1, 1]);
var days_in_month = Calendar.daysInMonth(y, m);
for (var i = 0; i <= 7 * 6; i++) {
if (i < dow) set_day(i, last_month[0], last_month[1], Calendar.daysInMonth(last_month[0], last_month[1]) - dow + i + 1, true);
else if (i < dow + days_in_month) set_day(i, y, m, i - dow + 1, false);
else set_day(i, next_month[0], next_month[1], i - dow - days_in_month + 1, true);
}
//-------------
for (var i = 0; i < 12; i++) set_month(i, i + 1);
//-------------
var start_y = y - (y % 20);
if (start_y < Calendar.year_start) start_y = Calendar.year_start;
if (start_y + 20 > Calendar.year_end) start_y = Calendar.year_end - 20;
for (var i = 0; i < 20; i++) set_year(i, i + start_y);
}
function set_day(i, y, m, d, is_gray) {
var c = i % 7;
var r = i / 7 >> 0;
var _rows = cal.find('.shp-days tbody tr');
var _cells = $(_rows[r]).find('td');
var cell = $(_cells[c]);
var curr = DateHelper.format('yyyy/MM/dd', [y, m, d]);
if (y == selected_ymd[0] && m == selected_ymd[1] && d == selected_ymd[2]) cell.addClass('shp-selected'); else cell.removeClass('shp-selected');
if (curr == today) cell.addClass('shp-today'); else cell.removeClass('shp-today');
if (is_gray) cell.addClass('shp-gray'); else cell.removeClass('shp-gray');
cell.text(d);
cell.data('shp-date', curr);
}
function set_month(i, m) {
var c = i % 3;
var r = i / 3 >> 0;
var _rows = cal.find('.shp-months tbody tr');
var _cells = $(_rows[r]).find('td');
var cell = $(_cells[c]);
if (cal_ym[0] == selected_ymd[0] && m == selected_ymd[1]) cell.addClass('shp-selected'); else cell.removeClass('shp-selected');
if (cal_ym[0] == today_ymd[0] && m == today_ymd[1]) cell.addClass('shp-today'); else cell.removeClass('shp-today');
cell.text(Calendar.getMonthName(m));
cell.data('shp-month', m);
}
function set_year(i, y) {
var c = i % 5;
var r = i / 5 >> 0;
var _rows = cal.find('.shp-years tbody tr');
var _cells = $(_rows[r]).find('td');
var cell = $(_cells[c]);
if (y == selected_ymd[0]) cell.addClass('shp-selected'); else cell.removeClass('shp-selected');
if (y == today_ymd[0]) cell.addClass('shp-today'); else cell.removeClass('shp-today');
cell.text(y);
}
//----------------
function change_cal(dy, dm) {
var x = Calendar.addMonths(cal_ym, dm);
set_cal(x[0] + dy, x[1]);
}
function change_selected_date_by_viewmode(dy, dm, dd) {
if (viewmode == 0) selected_ymd = Calendar.addDays(selected_ymd, dd);
else if (viewmode == 1) selected_ymd = Calendar.addMonths(selected_ymd, dm);
else selected_ymd = Calendar.addMonths(selected_ymd, dy);
var new_date = DateHelper.format('yyyy/MM/dd', selected_ymd);
self.changeDate(new_date, false);
}
//----------------
this.init = function () {
cal = generateHtml();
cal.keydown(function (e) {
switch (e.keyCode) {
case 27: self.close(); break;
case 32: set_viewmode(viewmode + 1); break;
case 13:
if (viewmode == 0) self.changeDate(DateHelper.format('yyyy/MM/dd', selected_ymd), true);
else set_viewmode(viewmode - 1);
stop_event(e);
break;
case 33: change_selected_date_by_viewmode(-5 * 12 * 4, -12, -5 * 7); break;// pg-up
case 34: change_selected_date_by_viewmode(5 * 12 * 4, 12, 5 * 7); break;// pg-dn
case 37: change_selected_date_by_viewmode(12, 1, 1); break;// left
case 38: change_selected_date_by_viewmode(-5 * 12, -3, -7); break;// up
case 39: change_selected_date_by_viewmode(-12, -1, -1); break;// right
case 40: change_selected_date_by_viewmode(5 * 12, 3, 7); break;// down
case 46: self.changeDate(today, false); break;// del
default: return;
}
return stop_event(e);
});
//-----
var next_button_month_steps = [1, 12, 12 * 20];
cal.find('.shp-header li:eq(0)').click(function () { change_cal(viewmode == 1 ? 1 : (viewmode == 2 ? 20 : 0), viewmode == 0 ? 1 : 0); });
cal.find('.shp-header li:eq(2)').click(function () { change_cal(viewmode == 1 ? -1 : (viewmode == 2 ? -20 : 0), viewmode == 0 ? -1 : 0); });
cal.find('.shp-header li:eq(1)').click(function () {
set_viewmode(viewmode + 1);
});
//-----
cal.find('.shp-days td').click(function () {
var d = $(this).data('shp-date');
var ymd = DateHelper.YMD(d);
if (ymd[1] != cal_ym[1]) set_cal(ymd[0], ymd[1]);
else self.changeDate(d, true);
})
cal.find('.shp-months td').click(function () {
var m = $(this).data('shp-month');
set_cal(cal_ym[0], m);
set_viewmode(0);
})
cal.find('.shp-years td').click(function () {
var y = $(this).text();
set_cal(y, cal_ym[1]);
set_viewmode(1);
})
//-----
cal.find('.shp-footer a').click(function (e) { self.changeDate(today, false); cal.focus(); stop_event(e); return false; })
//-----
cal.find('.shp-days')[0].addEventListener("wheel", function (e) {
if (e.deltaY > 0) change_cal(e.ctrlKey ? 1 : 0, e.ctrlKey ? 0 : 1);
if (e.deltaY < 0) change_cal(e.ctrlKey ? -1 : 0, e.ctrlKey ? 0 : -1);
return stop_event(e);
})
cal.find('.shp-months')[0].addEventListener("wheel", function (e) {
if (e.deltaY > 0) change_cal(e.ctrlKey ? 10 : 1, 0);
if (e.deltaY < 0) change_cal(e.ctrlKey ? -10 : -1, 0);
return stop_event(e);
})
cal.find('.shp-years')[0].addEventListener("wheel", function (e) {
if (e.deltaY > 0) change_cal(e.ctrlKey ? 50 : 20, 0);
if (e.deltaY < 0) change_cal(e.ctrlKey ? -50 : -20, 0);
return stop_event(e);
})
//-----
cal.on('click contextmenu', function (e) { stop_event(e); return false; })
$(window).on('click resize contextmenu blur', function () { cal.hide() });
//elem.on("click", function () {
// self.open();
//});
$('body').append(cal);
}
function stop_event(e) {
e.preventDefault();
e.stopPropagation();
return false;
}
function generateHtml() {
var header = '<ul class="shp-header"><li title="' + Calendar.NextMonthText + '"><i class="fa fa-chevron-left"></i></li><li>1397 مهر</li><li title="' + Calendar.PrevMonthText + '"><i class="fa fa-chevron-right"></i></li></ul>';
var footer = '<small class="shp-footer"><a href="javascript:void(0)">' + Calendar.GoToTodayText + '</a></small>';
var tb_months = '<div class="shp-months"><table><tr><td>فروردین</td><td>اردیبهشت</td><td>خرداد</td></tr><tr><td>تیر</td><td>مرداد</td><td>شهریور</td></tr><tr><td>مهر</td><td>آبان</td><td>آذر</td></tr><tr><td>دی</td><td>بهمن</td><td>اسفند</td></tr></table></div>';
tb_months = '<div class="shp-months"><table>';
var m = 1;
for (var r = 0; r < 4; r++) {
tb_months += '<tr>';
for (var c = 0; c < 3; c++)
tb_months += '<td>' + Calendar.getMonthName(m++) + '</td>';
tb_months += '</tr>';
}
tb_months += '</table></div>';
return $('<div class="shp" tabindex=0>' + header + get_table_html('shp-days', 6, 7, Calendar.short_dow_names) + tb_months + get_table_html('shp-years', 4, 5) + footer + '<div>');
}
function get_table_html(css, rows, cols, titles) {
var thead = '';
if (titles) {
//var list = titles.split(',')
for (var i = 0; i < titles.length; i++) thead += '<th>' + titles[i] + '</th>';
thead = '<thead><tr>' + thead + '</tr></thead>'
}
var tbody = '';
for (var r = 0; r < rows; r++) {
tbody += '<tr>'
for (var c = 0; c < cols; c++) tbody += '<td></td>'
tbody += '</tr>'
}
tbody = '<tbody>' + tbody + '</tbody>';
return '<div class="' + css + '"><table>' + thead + tbody + '</table></div>';
}
this.init();
}
//Plugin.prototype = {
// init: function () {
// },
// destroy: function () {
// this.$elem.removeData();
// }
//}
$.fn[pluginName] = function (options) {
var args = arguments;
if (options === undefined || typeof options === 'object') {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName, new Plugin(this, options));
}
});
} else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
if (Array.prototype.slice.call(args, 1).length == 0 && $.inArray(options, $.fn[pluginName].getters) != -1) {
var instance = $.data(this[0], 'plugin_' + pluginName);
return instance[options].apply(instance, Array.prototype.slice.call(args, 1));
}
else {
return this.each(function () {
var instance = $.data(this, 'plugin_' + pluginName);
if (instance instanceof Plugin && typeof instance[options] === 'function') {
instance[options].apply(instance, Array.prototype.slice.call(args, 1));
}
});
}
}
};
$.fn[pluginName].defaults = {
anchorRight: true,
anchorTop: false,
};
}(jQuery, window, document));