settings.js

Timed Widget

Author:

Daniel Yule

Version:

0.2

Overview:

This file is responsible for providing the interface logic for the Timed Widget Settings Page. In essence, it ties together the various elements on the page with jQuery and handles AJAX communication with the server.

Dependencies:

  • jQuery
  • jQueryUI
  • Date.js
  • jquery-weekcalendar
  • jquery-datepicker
  • jQuery {buttons, dialog, accordion, tabs}
  • custom-colorpicker

Details:

The html code that this javascript interacts with is found in tw-settings.php, within the function tw_settings_display(). There are three major objects in use throughout this code. The first is code blocks.

Codeblocks are simply an arbitrary string that will be displayed on the page at a scheduled time. They can be html elements, javascript or some combination of the two. Each codeblock has a name, a color and the associated string. The name and color are for readabilty for the user, so it is easy to tell which timeslot is associated with which codeblock. Internally, they are tracked using an id, but this is never shown to the user. Codeblocks are stored in a global array, which is indexed by the codeblock's id.

Timeslots are designed to be a recurring sheduled event. Timeslots start on a particular day, end on either the same day or a later day, and occur only on selected days of the week, between specific hours. A timeslot is a recurring event, wherein a codeblock is displayed for as long as that timeslot is active. A timeslot has a start date, an end date, a start time, an end time and an associated codeblock. A timeslot also has seven flags, one for each day of the week that specifies whether or not the timeslot is active on that day of the week. The codeblock is displayed from the start time to the end time, every day, starting on the starting date and ending on the ending date, so long as the day of the week has been selected.

Global Declarations

var codeblocks = [];
var current_block_id = 0;
var current_schedule_id = 0;

function htmlDecode(input) {
	var e = document.createElement('div');
	e.innerHTML = input;
	return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

function HexToRGB(hex) {
	var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
	return {
		r : hex >> 16,
		g : (hex & 0x00FF00) >> 8,
		b : (hex & 0x0000FF)
	};
}

function HexToHSB(hex) {
	return RGBToHSB(HexToRGB(hex));
}
function RGBToHSB(rgb) {
	var hsb = {
		h : 0,
		s : 0,
		b : 0
	};
	var min = Math.min(rgb.r, rgb.g, rgb.b);
	var max = Math.max(rgb.r, rgb.g, rgb.b);
	var delta = max - min;
	hsb.b = max;
	if (max != 0) {

	}
	hsb.s = max != 0 ? 255 * delta / max : 0;
	if (hsb.s != 0) {
		if (rgb.r == max) {
			hsb.h = (rgb.g - rgb.b) / delta;
		} else if (rgb.g == max) {
			hsb.h = 2 + (rgb.b - rgb.r) / delta;
		} else {
			hsb.h = 4 + (rgb.r - rgb.g) / delta;
		}
	} else {
		hsb.h = -1;
	}
	hsb.h *= 60;
	if (hsb.h < 0) {
		hsb.h += 360;
	}
	hsb.s *= 100 / 255;
	hsb.b *= 100 / 255;
	return hsb;
}

function checkVisibility() {
	if (current_block_id && codeblocks.length > 0) {
		jQuery('#codeblock_select').removeClass("tb-hidden");
		jQuery('#codeblock_info').removeClass("tb-hidden");
	} else {
		jQuery('#codeblock_select').addClass("tb-hidden");
		jQuery('#codeblock_info').addClass("tb-hidden");
	}
}

function updateCodeblockForm() {
	if (codeblocks[current_block_id] !== undefined) {
		var $panel = jQuery('#codeblock_panel').detach();
		jQuery('#codeblock_tab_' + current_block_id).append($panel);
		current_block = codeblocks[current_block_id];
		jQuery('#codeblock_name').val(current_block.block_name);
		jQuery('#codeblock_code').val(current_block.block_code);
		jQuery('#codeblock_color').val(current_block.block_color);
		jQuery('#colorpicker').css('background-color',
				"#" + current_block.block_color);
		jQuery('#colorpicker').ColorPickerSetColor(
				"#" + current_block.block_color);
	}
}

function saveCodeblockForm() {
	jQuery.post(ajaxurl, {
		action : 'tw-ajax-codeblock-save',
		block_id : current_block_id,
		block_name : jQuery('#codeblock_name').val(),
		block_code : jQuery('#codeblock_code').val(),
		block_color : jQuery('#codeblock_color').val()
	}, function(response) {
		if (response.saved) {

jQuery('#codeblockselect option[value="' + response.blockid + '"]').html(response.block_name);

			jQuery(
					'#codeblock_tabs>ul>li>a[href=#codeblock_tab_'
							+ response.block_id + ']')
					.text(response.block_name);
			codeblocks[response.block_id].block_name = response.block_name;
			codeblocks[response.block_id].block_code = response.block_code;
			codeblocks[response.block_id].block_color = response.block_color;
			jQuery('#calendar').weekCalendar('refresh');
		}
	});
}

function removeCodeblock() {
	jQuery.post(ajaxurl, {
		action : 'tw-ajax-codeblock-remove',
		block_id : current_block_id
	}, function(response) {
		if (response.removed) {
			delete codeblocks[response.block_id];

$panel = jQuery('#codeblockpanel').detach(); codeblocks.splice(currentblockid, 1); populateWithCodeblocks(jQuery('#codeblockselect'));

			jQuery('#codeblock_tabs').tabs("select",
					"#codeblock_tab_" + response.prev_id);
			jQuery('#codeblock_tabs').tabs("remove",
					"#codeblock_tab_" + response.block_id);

			current_block_id = response.prev_id;

jQuery("#codeblockselect")[0].selectedIndex = currentblockid; checkVisibility(); if(currentblock_id && codeblocks.length > 0) updateCodeblockForm();

			jQuery('#calendar').weekCalendar('refresh');
		}
	});
}

function removeSchedule() {
	jQuery.post(ajaxurl, {
		action : 'tw-ajax-schedule-remove',
		schedule_id : current_schedule_id
	}, function(response) {
		if (response.removed) {
			if (!response.replaced) {
				jQuery('#schedule_tabs').tabs("select",
						"#schedule_tab_" + response.prev_id);
				jQuery('#schedule_tabs').tabs("remove",
						"#schedule_tab_" + response.schedule_id);
			} else {
				jQuery(
						'#schedule_tabs>ul>li>a[href=#schedule_tab_'
								+ response.schedule_id + ']').text(
						"Default Schedule");
			}

			current_schedule_id = response.prev_id;

jQuery("#codeblockselect")[0].selectedIndex = currentblockid; checkVisibility(); if(currentblock_id && codeblocks.length > 0) updateCodeblockForm();

			jQuery('#calendar').weekCalendar('refresh');
		}
	});
}

function populateWithCodeblocks(element) {
	element.html("");
	jQuery.each(codeblocks, function(key, value) {
		if (value) {
			element.append(jQuery('<option>', {
				value : key
			}).text(value.block_name));
		}
	});
}

function generateTimeSuggestions(txt) {

	var cTime = tryToParse(txt);
	if (cTime) {
		tTime = cTime.addMinutes(-720);
		times = new Array();
		for ( var minuteOffset = -720; minuteOffset <= 720; minuteOffset += 30) {
			times.push(tTime.toString("h:mm tt"));
			tTime.addMinutes(30);
		}
		return times.join("\n");
	}
	return "";
}

function tryToParse(txt) {
	txt = txt.replace(/\s/g, "");
	formatArray = Array("H", "HH", "HHm", "HHmm", "H:", "HH:", "H:m", "HH:m",
			"H:mm", "HH:mm", "H:mt", "HH:mt", "H:mmt", "HH:mmt", "H:mtt",
			"HH:mtt", "H:mmtt", "HH:mmtt");
	for (formatIdx in formatArray) {
		var cTime = Date.parseExact(txt, formatArray[formatIdx]);
		if (cTime)
			return cTime;
	}
	return null;
}

function addNewTimeslot(event) {
	populateWithCodeblocks(jQuery('#timeslot_codeblock'));

	jQuery('#timeslot_dialog').bind('dialogclose', function(closeEvent) {
		jQuery('#calendar').weekCalendar('refresh');
	});

	jQuery('#timeslot_start_time').val(event.start.toString("hh:mm tt"));
	jQuery('#timeslot_end_time').val(event.end.toString("hh:mm tt"));

	jQuery('#timeslot_start_date').val(event.start.toString("dd/MM/yyyy"));
	jQuery('#timeslot_end_date').val(event.end.toString("dd/MM/yyyy"));

	jQuery('.timeslot_day').prop('checked', false);

	switch (event.start.getDay()) {
	case 1:
		jQuery('#timeslot_on_monday').prop('checked', true);
		break;
	case 2:
		jQuery('#timeslot_on_tuesday').prop('checked', true);
		break;
	case 3:
		jQuery('#timeslot_on_wednesday').prop('checked', true);
		break;
	case 4:
		jQuery('#timeslot_on_thursday').prop('checked', true);
		break;
	case 5:
		jQuery('#timeslot_on_friday').prop('checked', true);
		break;
	case 6:
		jQuery('#timeslot_on_saturday').prop('checked', true);
		break;
	case 0:
		jQuery('#timeslot_on_sunday').prop('checked', true);
		break;
	}

	jQuery('#timeslot_dialog')
			.dialog(
					'option',
					'buttons',
					{
						"Save" : function() {

							var startTime = tryToParse(jQuery(
									'#timeslot_start_time').val());
							var endTime = tryToParse(jQuery(
									'#timeslot_end_time').val());
							var startDate = Date.parse(jQuery(
									'#timeslot_start_date').val());
							var endDate = Date.parse(jQuery(
									'#timeslot_end_date').val());
							jQuery.post(ajaxurl, {
								action : "tw-ajax-timeslot-add-update",
								codeblock_id : jQuery('#timeslot_codeblock')
										.val(),
								schedule_id : current_schedule_id,
								start_time : startTime.toString("HHmm"),
								end_time : endTime.toString("HHmm"),
								start_date : startDate.toString("yyyyMMdd"),
								end_date : endDate.toString("yyyyMMdd"),
								on_monday : jQuery(
										'#timeslot_on_monday:checked').prop(
										'checked'),
								on_tuesday : jQuery(
										'#timeslot_on_tuesday:checked').prop(
										'checked'),
								on_wednesday : jQuery(
										'#timeslot_on_wednesday:checked').prop(
										'checked'),
								on_thursday : jQuery(
										'#timeslot_on_thursday:checked').prop(
										'checked'),
								on_friday : jQuery(
										'#timeslot_on_friday:checked').prop(
										'checked'),
								on_saturday : jQuery(
										'#timeslot_on_saturday:checked').prop(
										'checked'),
								on_sunday : jQuery(
										'#timeslot_on_sunday:checked').prop(
										'checked')
							}, function() {
								jQuery('#timeslot_dialog').dialog('close');
							});
						},
						"Delete" : function() {
							jQuery('#timeslot_dialog').dialog('close');
						},
						"Cancel" : function() {
							jQuery('#timeslot_dialog').dialog('close');
						}
					});
	jQuery('#timeslot_dialog').dialog('open');
}

function getCalendarData(start, end, callback) {
	var interval_begin = start.toString("yyyyMMdd");
	var interval_end = end.toString("yyyyMMdd");

	jQuery.post(ajaxurl, {
		"interval_begin" : interval_begin,
		"interval_end" : interval_end,
		"schedule_id" : current_schedule_id,
		"action" : "tw-ajax-list-events"
	}, function(response) {
		var calEvents = Array();
		var calEvent;
		var event;
		if (response.success) {
			for (eventIdx in response.events) {
				event = response.events[eventIdx];
				calEvent = new Object();
				calEvent.id = event.id;
				calEvent.title = event.title;
				calEvent.start = Date.parseExact(event.date + event.starttime,
						"yyyyMMddHHmm");
				calEvent.end = Date.parseExact(event.date + event.endtime,
						"yyyyMMddHHmm");
				calEvent.timeslot_id = event.timeslot_id;
				calEvent.color = event.color;
				calEvents.push(calEvent);
			}
			callback(calEvents);
		}
	});
}

function updateTimeslot(calEvent) {
	jQuery.post(ajaxurl, {
		action : "tw-ajax-get-timeslot",
		timeslot_id : calEvent.timeslot_id
	}, function(response) {
		var start;
		var end;
		if (response.success) {
			populateWithCodeblocks(jQuery('#timeslot_codeblock'));
			jQuery('#timeslot_codeblock').val(response.timeslot.codeblock_id);

			jQuery('#timeslot_start_time').val(
					Date.parseExact(response.timeslot.start_time, "HHmm")
							.toString("hh:mm tt"));
			jQuery('#timeslot_end_time').val(
					Date.parseExact(response.timeslot.end_time, "HHmm")
							.toString("hh:mm tt"));

			jQuery('#timeslot_start_date').val(
					Date.parseExact(response.timeslot.start_date, "yyyyMMdd")
							.toString("dd/MM/yyyy"));
			jQuery('#timeslot_end_date').val(
					Date.parseExact(response.timeslot.end_date, "yyyyMMdd")
							.toString("dd/MM/yyyy"));

			jQuery('#timeslot_on_monday').prop('checked',
					response.timeslot.onMonday);
			jQuery('#timeslot_on_tuesday').prop('checked',
					response.timeslot.onTuesday);
			jQuery('#timeslot_on_wednesday').prop('checked',
					response.timeslot.onWednesday);
			jQuery('#timeslot_on_thursday').prop('checked',
					response.timeslot.onThursday);
			jQuery('#timeslot_on_friday').prop('checked',
					response.timeslot.onFriday);
			jQuery('#timeslot_on_saturday').prop('checked',
					response.timeslot.onSaturday);
			jQuery('#timeslot_on_sunday').prop('checked',
					response.timeslot.onSunday);

			jQuery('#timeslot_dialog').bind('dialogclose',
					function(closeEvent) {
						jQuery('#calendar').weekCalendar('refresh');
					});

			jQuery('#timeslot_dialog').dialog(
					'option',
					'buttons',
					{
						"Save" : function() {

							var startTime = tryToParse(jQuery(
									'#timeslot_start_time').val());
							var endTime = tryToParse(jQuery(
									'#timeslot_end_time').val());
							var startDate = Date.parse(jQuery(
									'#timeslot_start_date').val());
							var endDate = Date.parse(jQuery(
									'#timeslot_end_date').val());
							jQuery.post(ajaxurl, {
								action : "tw-ajax-timeslot-add-update",
								timeslot_id : calEvent.timeslot_id,
								schedule_id : current_schedule_id,
								codeblock_id : jQuery('#timeslot_codeblock')
										.val(),
								start_time : startTime.toString("HHmm"),
								end_time : endTime.toString("HHmm"),
								start_date : startDate.toString("yyyyMMdd"),
								end_date : endDate.toString("yyyyMMdd"),
								on_monday : jQuery(
										'#timeslot_on_monday:checked').prop(
										'checked'),
								on_tuesday : jQuery(
										'#timeslot_on_tuesday:checked').prop(
										'checked'),
								on_wednesday : jQuery(
										'#timeslot_on_wednesday:checked').prop(
										'checked'),
								on_thursday : jQuery(
										'#timeslot_on_thursday:checked').prop(
										'checked'),
								on_friday : jQuery(
										'#timeslot_on_friday:checked').prop(
										'checked'),
								on_saturday : jQuery(
										'#timeslot_on_saturday:checked').prop(
										'checked'),
								on_sunday : jQuery(
										'#timeslot_on_sunday:checked').prop(
										'checked')
							}, function() {
								jQuery('#timeslot_dialog').dialog('close');
							});
						},
						"Delete" : function() {
							jQuery.post(ajaxurl, {
								action : "tw-ajax-timeslot-remove",
								timeslot_id : calEvent.timeslot_id
							}, function() {
								jQuery('#timeslot_dialog').dialog('close');
							});
						},
						"Cancel" : function() {
							jQuery('#timeslot_dialog').dialog('close');
						}
					});
			jQuery('#timeslot_dialog').dialog('open');
		}

	});
}

function readEmbeddedJSON($) {
	var codeblocks_obj;

	current_block_id = tw_ajax.current_block;

	codeblocks_obj = $.parseJSON(htmlDecode(tw_ajax.codeblocks));
	$.each(codeblocks_obj, function(key, value) {
		codeblocks[key] = value;
	});

	current_schedule_id = tw_ajax.current_schedule;
}

function initCodeblockForm($) {
	var $codeblock_tabs = $('#codeblock_tabs');
	$codeblock_tabs.tabs( {
		select : function(event, ui) {
			saveCodeblockForm();
			current_block_id = parseInt(ui.panel.id.substring(14));
			updateCodeblockForm();
		},
		selected : current_block_id
	});
	updateCodeblockForm();

	$('#colorpicker').ColorPicker(
			{
				onChange : function(hsb, hex, rgb) {
					$('#colorpicker').css('backgroundColor', '#' + hex);
					$('#codeblock_color').val(hex);
				},
				onBeforeShow : function() {
					$('#colorpicker').ColorPickerSetColor(
							'#' + codeblocks[current_block_id].block_color);
				}

			});

	$('#codeblock_add').button();
	$('#codeblock_add').button("enable");
	$('#codeblock_add')
			.click(
					function($) {
						jQuery("#codeblock_add").button("disable");
						jQuery("#codeblock_add").button("option", "label",
								"Adding...");

						jQuery
								.post(
										ajaxurl,
										{

											action : 'tw-ajax-codeblock-add'

										},
										function(response) {
											if (response.success) {
												codeblocks[response.block_id] = new Object();
												codeblocks[response.block_id].block_name = response.block_name;
												codeblocks[response.block_id].block_code = response.block_code;
												codeblocks[response.block_id].block_color = response.block_color;
												$codeblock_tabs
														.tabs(
																"add",
																"#codeblock_tab_"
																		+ response.block_id,
																response.block_name);
												$codeblock_tabs
														.tabs(
																"select",
																"#codeblock_tab_"
																		+ response.block_id);
											}
											jQuery("#codeblock_add").button(
													"enable");
											jQuery("#codeblock_add").button(
													"option", "label",
													"Add New Code Block");
										});
					});
	$('#codeblock_save').button();
	$('#codeblock_save').click(function($) {
		saveCodeblockForm();
	});

	$('#codeblock_remove').button();
	$('#codeblock_remove').click(function($) {
		if (codeblocks.length > 1)
			removeCodeblock();
		else {
			codeblocks[current_block_id].block_name = "Default Codeblock";
			codeblocks[current_block_id].block_code = "";
			updateCodeblockForm();
			saveCodeblockForm();
		}

	});

	$('#codeblock_name').keyup(
			function($) {
				jQuery(
						'#codeblock_tabs>ul>li>a[href=#codeblock_tab_'
								+ current_block_id + ']').text(
						jQuery('#codeblock_name').val());
			});

	$('#codeblock_reset').button();
	$('#codeblock_reset').click(
			function($) {
				updateCodeblockForm();
				jQuery(
						'#codeblock_tabs>ul>li>a[href=#codeblock_tab_'
								+ current_block_id + ']').text(
						jQuery('#codeblock_name').val());
			});
}

function initScheduleForm($) {
	var $schedule_tabs = $('#schedule_tabs');
	$schedule_tabs.tabs( {
		select : function(event, ui) {

saveCodeblockForm();

			current_schedule_id = parseInt(ui.panel.id.substring(13));
			var $panel = jQuery('#schedule_panel').detach();
			jQuery('#schedule_tab_' + current_schedule_id).append($panel);
			jQuery('#calendar').weekCalendar('refresh');

		},
		selected : current_schedule_id
	});
	jQuery('#schedule_tab_' + current_schedule_id).append(
			jQuery('#schedule_panel').detach());

	$('#schedule_dialog')
			.dialog(
					{
						autoOpen : false,
						modal : true,
						resizable : false,
						buttons : {
							"Save" : function() {

								jQuery
										.post(
												ajaxurl,
												{

													action : 'tw-ajax-schedule-update',
													schedule_id : current_schedule_id,
													schedule_title : jQuery(
															'#schedule_name')
															.val(),
													schedule_default : jQuery(
															'#schedule_default')
															.val()

												},
												function(response) {
													jQuery(
															'#schedule_tabs>ul>li>a[href=#schedule_tab_'
																	+ current_schedule_id
																	+ ']')
															.text(
																	jQuery(
																			'#schedule_name')
																			.val());
													jQuery('#schedule_dialog')
															.dialog('close');
												});
							},
							"Cancel" : function() {
								jQuery('#schedule_dialog').dialog('close');
							}
						},
						open : function(event, ui) {
							var $default_select = jQuery('#schedule_default');
							var select_html;
							jQuery('#schedule_name')
									.val(
											jQuery(
													'#schedule_tabs>ul>li>a[href=#schedule_tab_'
															+ current_schedule_id
															+ ']').text());
							populateWithCodeblocks($default_select);
							select_html = $default_select.html();
							select_html = "<option value='none'>Nothing</option>"
									+ select_html;
							$default_select.html(select_html);
						}
					});

	$('#schedule_add').button();
	$('#schedule_add').button("enable");
	$('#schedule_add').click(
			function($) {
				jQuery("#schedule_add").button("disable");
				jQuery("#schedule_add").button("option", "label", "Adding...");

				jQuery.post(ajaxurl, {

					action : 'tw-ajax-schedule-add'

				}, function(response) {

					$schedule_tabs.tabs("add", "#schedule_tab_"
							+ response.schedule_id,
							response.schedules[response.schedule_id].title);
					$schedule_tabs.tabs("select", "#schedule_tab_"
							+ response.schedule_id);
					jQuery("#schedule_add").button("enable");
					jQuery("#schedule_add").button("option", "label",
							"Add Schedule");
				});
			});

	$('#schedule_edit').button();
	$('#schedule_edit').click(function($) {
		jQuery('#schedule_dialog').dialog('open');
	});

	$('#schedule_remove').button();
	$('#schedule_remove').click(function($) {
		removeSchedule();
	});

}

function initTimeslotForm($) {
	$('#timeslot_start_time').suggest(generateTimeSuggestions, {});
	$('#timeslot_end_time').suggest(generateTimeSuggestions, {});

	$('#timeslot_start_date').datepicker();
	$('#timeslot_end_date').datepicker();

	$('#timeslot_dialog').dialog( {
		autoOpen : false,
		modal : true,
		resizable : false
	});
}

function initCalendar($) {
	$('#calendar').weekCalendar( {
		timeslotsPerHour : 2,
		height : function($calendar) {
			return $(window).height() * 0.6;
		},
		draggable : function(calEvent, eventElement) {
			return false;
		},
		resizable : function(calEvent, eventElement) {
			return false;
		},

		allowCalEventOverlap : true,
		overlapEventsSeparate : true,
		eventRender : function(calEvent, $event) {
			if (calEvent.color !== undefined) {
				var rgb = HexToRGB(calEvent.color);
				var v = (rgb.r + rgb.g + rgb.b) / 3
				if (v > 128) {
					$event.css("color", "#000000");
				} else {
					$event.css("color", "#FFFFFF");
				}
				$event.css("backgroundColor", "#" + calEvent.color);
			}

		},
		eventNew : function(calEvent, $event) {
			addNewTimeslot(calEvent);
		},

		eventClick : function(calEvent, $event) {
			updateTimeslot(calEvent);
		},

		title : function(date, calendar) {
			return "Scheduled Codeblocks";
		},

		data : getCalendarData
	});
}

jQuery(document).ready(function($) {

	readEmbeddedJSON($);

	initCodeblockForm($);
	initScheduleForm($);
	initTimeslotForm($);
	initCalendar($);

	$("#accordion").accordion( {
		header : 'h3',
		autoHeight : false,
		change : function(event, ui) {
			$('#calendar').weekCalendar('refresh');
		}
	});
});