| Current File : /home/bwalansa/www/wp-content/plugins/event-organiser/js/event.js |
var eo_include_dates;
var eo_exclude_dates;
var eo_viewing_month;
(function($) {
//Workaround for indexOf in IE 7&8
if (!Array.prototype.indexOf){
Array.prototype.indexOf = function(elt /*, from*/){
var len = this.length;
var from = Number(arguments[1]) || 0;
from = (from < 0)? Math.ceil(from) : Math.floor(from);
if (from < 0)
from += len;
for (; from < len; from++){
if (from in this &&
this[from] === elt)
return from;
}
return -1;
};
}
/**
* Returns the ordinal suffix of the date
*/
Date.prototype.eoGetOrdinal = function () {
var d = this.getDate();
switch( d ){
case 1:
case 21:
case 31:
return 'st';
case 2:
case 22:
return 'nd';
case 3:
case 23:
return 'rd';
default:
return 'th';
}
};
/**
* Given a month (start & end ) and event schedule, calculates
* the dates which occur by rule in that month.
*/
function eo_generate_dates_by_schedule_rule( rule, month_start,month_end ){
//Helper array
var ical_weekdays = new Array("SU", "MO", "TU", "WE", "TH", "FR", "SA"),
eo_occurrences_by_rule = [],
count_days, pointer = false;
//If event starts in previous month - how many days from start to first occurrence in current month?
// Depends on occurrence (and 'stream' for weekly events.
switch (rule.schedule) {
case 'once':
case 'custom':
var formateddate = $.datepicker.formatDate('yy-mm-dd', rule.start);
eo_occurrences_by_rule.push(formateddate);
return eo_occurrences_by_rule;
/*break;*/
case 'daily':
if ( rule.start < month_start ) {
count_days = Math.abs((month_start - rule.start) / (1000 * 60 * 60 * 24)) - 1;
count_days = count_days % rule.frequency;
} else {
count_days = parseInt( rule.start.getDate(), 10 );
}
var skip = rule.frequency;
var streams = [];
var start_stream = new Date(month_start);
start_stream.setDate(month_start.getDate() + (count_days - 1));
streams.push(start_stream);
break;
case 'weekly':
var month_start_day = month_start.getDay();
streams = [];
$.each(rule.schedule_meta, function(index, value ) {
index = ical_weekdays.indexOf(value);
start_stream = new Date(rule.start);
start_stream.setDate(rule.start.getDate() + (index - rule.start.getDay() + 7) % 7);
if (start_stream < month_start) {
count_days = Math.abs((month_start - rule.start) / (1000 * 60 * 60 * 24));
count_days = count_days - count_days % (rule.frequency * 7);
start_stream.setDate(start_stream.getDate() + count_days);
}
streams.push(start_stream);
});
skip = 7 * rule.frequency;
break;
//These are easy
case 'monthly':
var month_difference = (month_start.getFullYear() - rule.start.getFullYear()) * 12 + ( month_start.getMonth() - rule.start.getMonth() );
if (month_difference % rule.frequency !== 0) {
return;
}
if ( rule.schedule_meta.match(/BYMONTHDAY=(\d+)/) ) {
var day = rule.start.getDate();
var daysinmonth = month_end.getDate();
//Check for short months
if ( day <= daysinmonth) {
//If valid date
pointer = new Date( month_start.getFullYear(), month_start.getMonth(), day);
}
} else {
//e.g. 3rd friday of month:
var matches = rule.schedule_meta.match(/BYDAY=(\d+)(MO|TU|WE|TH|FR|SA|SU)/);
var n = parseInt( matches[1], 10 ) -1; //0=>first,1=>second,...,4=>last
var occurrence_day = rule.start.getDay(), occurence_date;
if (n >= 4) {
//Last day
var month_end_day = month_end.getDay();
occurence_date = month_end.getDate() + (occurrence_day - month_end_day - 7) % 7;
} else {
//Want date of (n+1)th X of month.
month_start_day = month_start.getDay();//0=sun,..
var offset = (occurrence_day - month_start_day + 7) % 7;//How many days till first X of the month
occurence_date = offset + n * 7 + 1;
}
pointer = new Date(month_start);
pointer.setDate(occurence_date);
}
if ( pointer && pointer <= rule.schedule_last ) {
//If before end
formateddate = $.datepicker.formatDate('yy-mm-dd', pointer);
eo_occurrences_by_rule.push(formateddate);
}
return eo_occurrences_by_rule;
/*break;*/
case 'yearly':
var year_difference = (month_start.getFullYear() - rule.start.getFullYear());
if (year_difference % rule.frequency !== 0) {
return eo_occurrences_by_rule;
}
var dateCheck = new Date( month_start.getFullYear(), rule.start.getMonth(), rule.start.getDate() );
if ( month_start.getMonth() == rule.start.getMonth() && dateCheck.getMonth() == rule.start.getMonth()) {
pointer = new Date(rule.start);
pointer.setYear(month_start.getFullYear());
if (pointer <= rule.schedule_last ) {
//If before end
formateddate = $.datepicker.formatDate('yy-mm-dd', pointer);
eo_occurrences_by_rule.push(formateddate);
}
}
return eo_occurrences_by_rule;
/*break;*/
default:
return eo_occurrences_by_rule;
/*break;*/
}
//End switch
//While in current month, and event has not finished - generate occurrences.
for (var x in streams) {
pointer = new Date(streams[x]);
while (pointer <= month_end && pointer <= rule.schedule_last) {
formateddate = $.datepicker.formatDate('yy-mm-dd', pointer);
eo_occurrences_by_rule.push(formateddate);
pointer.setDate(pointer.getDate() + skip);
}
}
return eo_occurrences_by_rule;
}
/**
* Schedule picker 'view'/'controller' object
*/
window.eventOrganiserSchedulePicker = {
/**
* @this {Type}
*/
init: function( options ){
var self = this;
this.options = options;
this.schedule = options.schedule;
this.set_up_datepickers();
this.set_up_timepickers();
//On input, update form
$(".event-date :input, .eo-all-day-toggle").on('change', function(o) {
self.update_schedule();
self.update_form();
if ( !$(this).hasClass('eo-all-day-toggle') ) {
//When rule changes, wipe include/exclude dates clean
//TODO
self.update_occurrencepicker_rules();
}
});
//Initiate form
this.update_schedule();
this.update_form();
var now = new Date();
eo_viewing_month = [ now.getFullYear(), now.getMonth() + 1 ];
this.schedule.generate_dates_by_rule(now.getFullYear(), now.getMonth() + 1, {});
},
set_up_datepickers: function(){
var self = this;
var views = this.options.views;
var locale = this.options.locale;
//Init data
var start = $(views.start_date).data('eo-datepicker','start');
var end = $(views.end_date).data('eo-datepicker','end');
$(views.is_all_day).addClass('eo-all-day-toggle');
//Date pickers
//Schedule last
if( $(views.schedule_last_date) ){
var schedule_last = $(views.schedule_last_date)
.datepicker({
nextText: '>',
prevText: '<',
dateFormat: this.options.format,
changeMonth: true,
changeYear: true,
monthNamesShort: locale.monthAbbrev,
dayNamesMin: locale.dayAbbrev,
isRTL: locale.isrtl,
firstDay: parseInt( this.options.startday, 10 ),
beforeShow: function(input, inst) {
if( inst.hasOwnProperty( 'dpDiv' ) ){
inst.dpDiv.addClass('eo-datepicker');
}else{
$('#ui-datepicker-div').addClass('eo-datepicker');
}
},
})
.data('eo-datepicker','schedule_last');
}
//Start & End
var dates = $( views.start_date + ', ' + views.end_date).datepicker({
dateFormat: this.options.format,
nextText: '>',
prevText: '<',
changeMonth: true,
changeYear: true,
monthNamesShort: locale.monthAbbrev,
dayNamesMin: locale.dayAbbrev,
firstDay: parseInt( this.options.startday, 10 ),
onSelect: function(selectedDate) {
//Ensure that start date comes before end date
var option = ( 'start' == $(this).data('eo-datepicker')? "minDate": "maxDate" ),
instance = $(this).data("datepicker"),
date = $.datepicker.parseDate(instance.settings.dateFormat || $.datepicker._defaults.dateFormat, selectedDate, instance.settings);
dates.not(this).datepicker("option", option, date);
if (this.id == "from_date") {
//If updating start date, ensure recurrence end falls after this
schedule_last.datepicker("option", "minDate", date);
}
var startDate = $( views.start_date ).datepicker( 'getDate' );
var endDate = $( views.end_date ).datepicker( 'getDate' );
if( startDate.getTime() != endDate.getTime() ){
var time = { hour: null, minute: null };
$( views.start_time + ", " + views.end_time ).eotimepicker('option', { maxTime: time, minTime: time });
}
//Replace with do_action
self.update_schedule();
self.update_occurrencepicker_rules();
self.update_form();
},
beforeShow: function(input, inst) {
if( inst.hasOwnProperty( 'dpDiv' ) ){
inst.dpDiv.addClass('eo-datepicker');
}else{
$('#ui-datepicker-div').addClass('eo-datepicker');
}
},
});
//Occurrence picker
var dp = $(views.occurrence_picker);
if (dp.length > 0) {
dp.datepicker({
dateFormat: "yy-mm-dd",
nextText: '>',
prevText: '<',
changeMonth: true,
changeYear: true,
monthNamesShort: locale.monthAbbrev,
dayNamesMin: locale.dayAbbrev,
firstDay: parseInt( this.options.startday, 10 ),
onSelect: function( date ){
eventOrganiserSchedule.add_or_remove_date( date );
$( eventOrganiserSchedulePicker.options.views.include ).val(eventOrganiserSchedule.include.join(',\r\n'));
$( eventOrganiserSchedulePicker.options.views.exclude ).val(eventOrganiserSchedule.exclude.join(',\r\n'));
},
beforeShowDay: function (date) {
var date_str = $.datepicker.formatDate('yy-mm-dd', date);
var isEventful = eventOrganiserSchedule.is_date_eventful(date_str);
if (isEventful[0]) {
return [true, "eo-op-date-selected", ""];
}
return [true, "eo-op-date-not-selected", ''];
},
beforeShow: function(input, inst) {
if( inst.hasOwnProperty( 'dpDiv' ) ){
inst.dpDiv.addClass('eo-datepicker');
}else{
$('#ui-datepicker-div').addClass('eo-datepicker');
}
},
onChangeMonthYear: eventOrganiserSchedule.generate_dates_by_rule
})
.hide().find('.ui-datepicker-inline').on('click', function(e) {
if (!e)
e = window.event;
e.cancelBubble = true;
if (e.stopPropagation)
e.stopPropagation();
});
$('html').on('click', function() {
dp.hide();
$(views.occurrence_picker_toggle).val(locale.showDates);
});
}
//Show/hide calendar
$(views.occurrence_picker_toggle).on('click', function(e) {
e.preventDefault();
e.stopPropagation();
dp.toggle();
if( dp.is(":visible") ){
$(this).val(locale.hideDates);
$( views.occurrence_picker ).datepicker("refresh");
}else{
$(this).val(locale.showDates);
}
});
},
//When rule changes, wipe include/exclude dates clean
update_occurrencepicker_rules: function() {
eo_exclude_dates = [];
eo_include_dates = [];
//eo_update_inc_ex_Input();
this.schedule.generate_dates_by_rule(eo_viewing_month[0], eo_viewing_month[1], {});
$(this.options.views.occurrence_picker).datepicker("refresh");
},
set_up_timepickers: function(){
var options = this.options;
var views = this.options.views;
//Time pickers
$( views.start_time ).data( 'eo-event-data', 'start-time' );
$( views.end_time ).data( 'eo-event-data', 'end-time' );
$( views.start_time + ', ' + views.end_time).eotimepicker({
showPeriodLabels: !options.is24hour,
showPeriod: !this.options.is24hour,
showLeadingZero: options.is24hour,
periodSeparator: '',
amPmText: options.locale.meridian,
hourText: options.locale.hour,
minuteText: options.locale.minute,
isRTL: options.locale.isrtl,
onSelect: function( timeString, timePickerInst ){
var startDate = $( views.start_date ).datepicker( 'getDate' );
var endDate = $( views.end_date ).datepicker( 'getDate' );
//If dates are the same update timepicker...
if( startDate.getTime() == endDate.getTime() ){
var time = {
hour: timePickerInst.hours,
minute: timePickerInst.minutes,
};
if( 'start-time' == $( timePickerInst.input ).data( 'eo-event-data' ) ){
//We have selected start time, update end time
$( views.end_time ).eotimepicker('option', { minTime: time });
/*
var endTime = {
hour: $( views.end_time ).eotimepicker( 'getHour' ),
minute: $( views.end_time ).eotimepicker( 'getMinute' ),
};
if( time.hour > endTime.hour || ( ( time.hour = endTime.hour ) && time.minute > endTime.minute ) ){
//Correct end:
var newEndTime = new Date('2012-11-24 ' + endTime.hour +":"+endTime.minute );
$( views.end_time ).eotimepicker( 'setTime', newEndTime );
}*/
}else{
$( views.start_time ).eotimepicker('option', { maxTime: time });
/*
var startTime = {
hour: $( views.end_time ).eotimepicker( 'getHour' ),
minute: $( views.end_time ).eotimepicker( 'getMinute' ),
};
if( time.hour < startTime.hour || ( ( time.hour = startTime.hour ) && time.minute < startTime.minute ) ){
console.log( 'end before start!');
//Correct start:
var newStartTime = new Date('2012-11-24 ' + startTime.hour +":"+startTime.minute );
$( views.end_time ).eotimepicker( 'setTime', newStartTime );
}
*/
}
}
}
}).addClass('eo-time-picker');
},
/**
* @this;
*/
update_schedule: function(){
var c = new Array("SU", "MO", "TU", "WE", "TH", "FR", "SA");
var views = this.options.views;
var schedule ={
schedule: $(views.schedule).val(),
frequency: parseInt( $(views.frequency).val(), 10 ),
schedule_last: $(views.schedule_last_date).datepicker("getDate"),
start: $(views.start_date).datepicker("getDate"),
end: $(views.end_date).datepicker("getDate"),
is_all_day: $(views.is_all_day).prop("checked"),
include: $(views.include).length > 0 ? $(views.include).val().split(",") : [],
exclude: $(views.exclude).length > 0 ? $(views.exclude).val().split(",") : []
};
if( schedule.schedule == 'weekly' ){
schedule.schedule_meta = [];
if ( $(views.week_repeat+" :checkbox:checked").length === 0) {
var day = schedule.start.getDay();
$(views.week_repeat+" :checkbox[value='" + c[day] + "']").prop("checked", true);
}
$(views.week_repeat+" :checkbox:checked").each(function() {
schedule.schedule_meta.push( $(this).val() );
});
}else if( schedule.schedule == 'monthly' ){
if( $(views.month_repeat+" :radio:checked").val() == "BYMONTHDAY=" ){
schedule.schedule_meta = "BYMONTHDAY=" + schedule.start.getDate();
}else{
var dayInt = schedule.start.getDay() % 7;
var n = parseInt( Math.floor((schedule.start.getDate() - 1) / 7), 10 );
schedule.schedule_meta = "BYDAY=" + (n+1) + c[dayInt];
}
}
this.schedule = eventOrganiserSchedule.init(schedule);
//Backwards compat:
eo_exclude_dates = schedule.exclude;
eo_include_dates = schedule.include;
},
update_form: function(){
var view = this.options.views;
var locale = this.options.locale;
var schedule = this.schedule;
var speed = 700;
$(".event-date :input").attr("disabled", !this.options.editable).toggleClass("ui-state-disabled", !this.options.editable);
$("label[for=eo-all-day]").toggleClass("ui-state-disabled", !this.options.editable);
if( this.options.editable ){
$(view.start_time+', '+view.end_time).attr("disabled", schedule.is_all_day ).toggleClass("ui-state-disabled", schedule.is_all_day );
}
if( schedule.schedule == 'once' || schedule.schedule == 'custom' ){
$(view.recurrence_section+" :input").attr("disabled", true );
$(view.recurrence_section).hide();
}else{
$(view.recurrence_section+" :input").attr("disabled", false );
$(view.recurrence_section).fadeIn(speed);
}
switch ( schedule.schedule ) {
case "once":
case "custom":
$(schedule.frequency).val("1");
$(view.month_repeat+', '+view.week_repeat).show();
break;
case "weekly":
if ( schedule.frequency > 1) {
$(view.schedule_span).text(locale.weeks);
} else {
$(view.schedule_span).text(locale.week);
}
$(view.week_repeat).fadeIn(speed);
$(view.week_repeat+" :input").attr("disabled", false);
$(view.month_repeat).hide();
$(view.month_repeat+" :input").attr("disabled", true );
break;
case "monthly":
if ( schedule.frequency > 1 ) {
$(view.schedule_span).text(locale.months);
} else {
$(view.schedule_span).text(locale.month);
}
$(view.month_repeat).fadeIn(speed);
$(view.month_repeat+" :input").attr("disabled", false);
$(view.week_repeat).hide();
$(view.week_repeat+" :input").attr("disabled", true );
break;
case "daily":
if ( schedule.frequency > 1 ) {
$(view.schedule_span).text(locale.days);
} else {
$(view.schedule_span).text(locale.day);
}
$(view.week_repeat + ', ' + view.month_repeat).hide();
$(view.week_repeat + ' :input, ' + view.month_repeat+" :input").attr("disabled", true );
break;
case "yearly":
if ( schedule.frequency > 1 ) {
$(view.schedule_span).text(locale.years);
} else {
$(view.schedule_span).text(locale.year);
}
$(view.week_repeat + ', ' + view.month_repeat).hide();
$(view.week_repeat + ' :input, ' + view.month_repeat+" :input").attr("disabled", true );
break;
}
if ($("#venue_select").val() === null) {
$(".venue_row").hide();
}
//Generate summary
$(view.summary).html( schedule.generate_summary( locale ) );
}
};
eventOrganiserSchedule = {
self: this,
/**
* Schedule picker 'model' object
* @this element
*/
init: function ( schedule ) {
var self = this;
var defaults = {
schedule: 'once',
frequency: 1,
schedule_last: new Date(),
start: new Date(),
end: new Date(),
is_all_day: false,
dates_by_rule: []
};
schedule = $.extend({}, defaults, schedule);
for(var prop in schedule) {
this[prop] = schedule[prop];
}
return this;
},
/**
* @this element
*/
generate_dates_by_rule: function(year,month,inst){
//month is 1-12.
var eo_occurrences_by_rule = [], eo_viewing_month = [year, month];
//Get month start/end dates. Date expects month 0-11.
var month_start = new Date(year, month-1, 1);
var nxt_mon = new Date(year, month, 1);
var month_end = new Date(nxt_mon - 1);
if ( eventOrganiserSchedule.schedule_last < month_start || eventOrganiserSchedule.start > month_end) {
return;
}
eventOrganiserSchedule.dates_by_rule = eo_generate_dates_by_schedule_rule( eventOrganiserSchedule, month_start,month_end );
},
/**
* Given an event schedule returns a string summary describing it.
* Schedule is an object with similar properties as those accepted by
* eo_insert_event() (in php).
*
* @this element
*/
generate_summary: function( locale ){
//Locale
var b = locale.weekDay;
var summary = locale.summary + " ";
var options = {
monthNamesShort: locale.monthAbbrev,
dayNamesMin: locale.dayAbbrev,
monthNames: locale.monthNames
};
var schedule = this.schedule;
//Helper array
var c = new Array("SU", "MO", "TU", "WE", "TH", "FR", "SA");
switch ( schedule ) {
case "once":
return "This event will be a one-time event";
/*break;*/
case "custom":
case "daily":
if ( this.frequency > 1) {
summary += sprintf(locale.dayPlural, this.frequency);
} else {
summary += locale.daySingle;
}
break;
case "weekly":
if ( this.frequency > 1 ) {
summary += sprintf( locale.weekPlural, this.frequency );
} else {
summary += locale.weekSingle;
}
var days = $.map( this.schedule_meta, function(value, index){ return b[c.indexOf(value)]; } );
summary += " " + days.join(', ');
break;
case "monthly":
if ( this.frequency > 1 ) {
summary += sprintf(locale.monthPlural, this.frequency);
} else {
summary += locale.monthSingle;
}
if ( this.schedule_meta.match(/BYMONTHDAY=(\d+)/) ) {
summary = summary + " " + this.start.getDate() + this.start.eoGetOrdinal();
} else {
var matches = this.schedule_meta.match(/BYDAY=(\d+)(MO|TU|WE|TH|FR|SA|SU)/);
var n = parseInt( matches[1], 10 ) -1;
summary = summary + " " + locale.occurrence[n] + " " + b[c.indexOf(matches[2])];
}
break;
case "yearly":
if (this.frequency > 1) {
summary += sprintf(locale.yearPlural, this.frequency);
} else {
summary += locale.yearSingle;
}
var formattedDate;
if(locale.isUsingOrdinal){
formattedDate = $.datepicker.formatDate("MM d", this.start, options) + this.start.eoGetOrdinal();
} else {
formattedDate = $.datepicker.formatDate("MM d", this.start, options);
}
summary = summary + " " + formattedDate;
break;
}
if ( this.schedule_last !== null ) {
var formattedUntilDate;
if(locale.isUsingOrdinal){
formattedUntilDate = $.datepicker.formatDate("MM d'" + this.schedule_last.eoGetOrdinal() + "' yy", this.schedule_last, options);
} else {
formattedUntilDate = $.datepicker.formatDate("MM d yy", this.schedule_last, options);
}
summary = summary + " " + locale.until + " " + formattedUntilDate;
}
return summary;
},
//Is given date an occurrence of the event?
is_date_eventful: function(date) {
var index = $.inArray(date, eventOrganiserSchedule.dates_by_rule);
var excludedIndex = $.inArray(date, eventOrganiserSchedule.exclude);
var includedIndex = $.inArray(date, eventOrganiserSchedule.include);
if (index > -1) {
// This date occurs by recurrence rule, but might be excluded manually.
// However, it might also be included manually as well, in the case that
// the occurrence has moved time within the same day
if ( excludedIndex > -1 && includedIndex == -1 ) {
//Excluded
return [false, excludedIndex];
} else if ( excludedIndex > -1 && includedIndex > -1 ) {
// Occurrence has moved time within same date
return [true, includedIndex];
}
// Not excluded manually
return [true, -1];
} else {
//Doesn't occurs by rule - is it included manually?
if (includedIndex > -1) {
return [true, includedIndex];
}
return [false, -1];
}
},
//When a date is selected, add or remove it based on current state
add_or_remove_date: function (date, inst) {
var isEventful = eventOrganiserSchedule.is_date_eventful(date),index;
if ( isEventful[0] ) {
//Date is eventful. Remove date
index = isEventful[1];
if ( index > -1 ) {
//Date was manually included
eventOrganiserSchedule.include.splice(index, 1);
} else {
//Date was eventful by rule
if ( $.inArray( date, eventOrganiserSchedule.exclude ) < 0)
eventOrganiserSchedule.exclude.push(date);
}
} else {
//Date is not eventful. Add date
index = isEventful[1];
if (index > -1) {
//Date was manually excluded
eventOrganiserSchedule.exclude.splice(index, 1);
} else {
//Date was not an event by rule
if ( $.inArray( date, eventOrganiserSchedule.include ) < 0)
eventOrganiserSchedule.include.push(date);
}
}
//Backwards compat:
eo_exclude_dates = eventOrganiserSchedule.exclude;
eo_include_dates = eventOrganiserSchedule.include;
}
};
})(jQuery);
/*!
* sprintf.js | Copyright (c) 2007-2013 Alexandru Marasteanu <hello at alexei dot ro> | 3 clause BSD license
* https://github.com/alexei/sprintf.js
* */
(function(ctx) {
var sprintf = function() {
if (!sprintf.cache.hasOwnProperty(arguments[0])) {
sprintf.cache[arguments[0]] = sprintf.parse(arguments[0]);
}
return sprintf.format.call(null, sprintf.cache[arguments[0]], arguments);
};
sprintf.format = function(parse_tree, argv) {
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
for (i = 0; i < tree_length; i++) {
node_type = get_type(parse_tree[i]);
if (node_type === 'string') {
output.push(parse_tree[i]);
}
else if (node_type === 'array') {
match = parse_tree[i]; // convenience purposes only
if (match[2]) { // keyword argument
arg = argv[cursor];
for (k = 0; k < match[2].length; k++) {
if (!arg.hasOwnProperty(match[2][k])) {
throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
}
arg = arg[match[2][k]];
}
}
else if (match[1]) { // positional argument (explicit)
arg = argv[match[1]];
}
else { // positional argument (implicit)
arg = argv[cursor++];
}
if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
}
switch (match[8]) {
case 'b': arg = arg.toString(2); break;
case 'c': arg = String.fromCharCode(arg); break;
case 'd': arg = parseInt(arg, 10); break;
case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
case 'o': arg = arg.toString(8); break;
case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
case 'u': arg = arg >>> 0; break;
case 'x': arg = arg.toString(16); break;
case 'X': arg = arg.toString(16).toUpperCase(); break;
}
arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
pad_length = match[6] - String(arg).length;
pad = match[6] ? str_repeat(pad_character, pad_length) : '';
output.push(match[5] ? arg + pad : pad + arg);
}
}
return output.join('');
};
sprintf.cache = {};
sprintf.parse = function(fmt) {
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
while (_fmt) {
if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
parse_tree.push(match[0]);
}
else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
parse_tree.push('%');
}
else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
if (match[2]) {
arg_names |= 1;
var field_list = [], replacement_field = match[2], field_match = [];
if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
field_list.push(field_match[1]);
while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
field_list.push(field_match[1]);
}
else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
field_list.push(field_match[1]);
}
else {
throw('[sprintf] huh?');
}
}
}
else {
throw('[sprintf] huh?');
}
match[2] = field_list;
}
else {
arg_names |= 2;
}
if (arg_names === 3) {
throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
}
parse_tree.push(match);
}
else {
throw('[sprintf] huh?');
}
_fmt = _fmt.substring(match[0].length);
}
return parse_tree;
};
var vsprintf = function(fmt, argv, _argv) {
_argv = argv.slice(0);
_argv.splice(0, 0, fmt);
return sprintf.apply(null, _argv);
};
/**
* helpers
*/
function get_type(variable) {
return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
}
function str_repeat(input, multiplier) {
for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
return output.join('');
}
/**
* export to either browser or node.js
*/
ctx.sprintf = sprintf;
ctx.vsprintf = vsprintf;
})(typeof exports != "undefined" ? exports : window);