jquery.businessHours icon indicating copy to clipboard operation
jquery.businessHours copied to clipboard

Add multiple hours in one day

Open newmesiss opened this issue 7 years ago • 7 comments

If an employee has a variable schedule in a day, enters at 9 and leaves at 13:00 then reenters at 15:00 and goes home at 19:00. Is this possible?

newmesiss avatar Jun 09 '17 12:06 newmesiss

http://jsfiddle.net/b8pfm3zu/

Sadly the dev who added that functionality didn't code the ability to initialise the plugin from the new modified json object. So its one way and basically useless.

If you manage to get it working would be great if you could share the code

silentjay avatar Jun 13 '17 19:06 silentjay

Are there any news about this functionality. I am also interested because splitting business hours is necessary most of the time. Unfortunately I am more into PHP than in Jquery, so its for me a little bit to difficult to get it working.

juergenweb avatar Sep 21 '17 18:09 juergenweb

Hi all, I've quickly added the ability to do two time-sets on my fork here https://github.com/danalaw/jquery.businessHours

danalaw avatar Mar 14 '18 01:03 danalaw

@danalaw i couldn't found it :(

Daniel-HBK avatar May 08 '18 12:05 Daniel-HBK

any news?

GuilhermeCouto avatar Sep 19 '19 14:09 GuilhermeCouto

Hello All, I hope it may help someone. Thanks @danalaw, I used your code and improved it a bit, Thanks @Astoroth for the PHP part

@juergenweb I believe it might help you

Fiddle http://jsfiddle.net/hossam_abdelmajeed/no4vs6ru/7/

JS code:

(function($) {
		$.fn.businessHours = function(opts) {
			var defaults = {
				preInit: function(){},
				postInit: function() {
					$('.operationTimeFrom, .operationTimeTill').timepicker({
						'timeFormat': 'H:i',
						'step': 15
					});

					$('.operationTimeFrom, .operationTimeTill').on('changeTime hideTimepicker', function() {
						var $that = $(this);
						if ($that.val() && /^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test( $that.val() )) {
							$that.parent().removeClass('has-error');
						} else {
							$that.parent().addClass('has-error');
						}
					});
					$('.operationTimeFrom, .operationTimeTill').on('timeFormatError timeRangeError', function() {
						var $that = $(this);
						$that.parent().addClass('has-error');
						$that.focus();
					});
				},
				checkedColorClass: "WorkingDayState",
				uncheckedColorClass: "RestDayState",
				colorBoxValContainerClass: "colorBoxContainer",
				weekdays: ['Sat', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
				operationTime: [
					{isActive: ""},
					{isActive: ""},
					{isActive: ""},
					{isActive: ""},
					{isActive: ""},
					{isActive: ""},
					{isActive: ""}
				],
				defaultOperationTimeFrom: '',
				defaultOperationTimeTill: '',
				defaultActive: false,
				//labelOn: "Working day",
				//labelOff: "Day off",
				//labelTimeFrom: "from:",
				//labelTimeTill: "till:",
				containerTmpl: '<div class="clean"/>',
				dayTmpl: '<div class="dayContainer">' +
					'<div data-original-title="" class="colorBox"><input type="checkbox" class="invisible operationState"/></div>' +
					'<div class="weekday"></div>' +
					'<div class="operationDayTimeContainer">' +
					'<div class="operationTime"><input type="text" name="startTime" class="mini-time operationTimeFrom" value=""/></div>' +
					'<div class="operationTime"><input type="text" name="endTime" class="mini-time operationTimeTill" value=""/></div>' +
					'<div class="operationTime"><input type="text" name="startTime_1" class="mini-time operationTimeFrom" value=""/></div>' +
					'<div class="operationTime"><input type="text" name="endTime_1" class="mini-time operationTimeTill" value=""/></div>' +
					'</div></div>'
			};

			var container = $(this);
			var methods = {
				getValueOrDefault: function(val, defaultVal) {
					return (jQuery.type(val) === "undefined" || val == null) ? defaultVal : val;
				},
				init: function(opts) {
					this.options = $.extend(defaults, opts);
					container.html("");

					if(typeof this.options.preInit === "function") {
						this.options.preInit();
					}

					this.initView(this.options);

					if(typeof this.options.postInit === "function") {
						//$('.operationTimeFrom, .operationTimeTill').timepicker(options.timepickerOptions);
						this.options.postInit();
					}

					return {
						serialize: function() {
							var data = [];

							container.find(".operationState").each(function(num, item) {
								var isWorkingDay = $(item).prop("checked");
								var dayContainer = $(item).parents(".dayContainer");
								data.push({
									isActive: isWorkingDay,
									timeFrom: isWorkingDay ? dayContainer.find("[name='startTime']").val() : null,
									timeTill: isWorkingDay ? dayContainer.find("[name='endTime']").val() : null,
									timeFrom_1: isWorkingDay ? dayContainer.find("[name='startTime_1']").val() : null,
									timeTill_1: isWorkingDay ? dayContainer.find("[name='endTime_1']").val() : null
								});
							});
							return data;
						},
						serializeObject: function() {
							var data = [];

							container.find(".operationState").each(function(num, item) {
								var isWorkingDay = $(item).prop("checked"),
									dayContainer = $(item).parents(".dayContainer"),
									dayName      = dayContainer.find('.weekday').text().toLowerCase();

								data[dayName + '_1_open'] = isWorkingDay ? dayContainer.find("[name='startTime']").val() : null;
								data[dayName + '_1_close'] = isWorkingDay ? dayContainer.find("[name='endTime']").val() : null;

								// generally remove all unwanted error classes
								container.find('.operationTime').removeClass('has-error');

								// Validation Start
								if (data[dayName + '_1_open'] && !data[dayName + '_1_close']) {
									data = [];

									// time to show some errors to the user
									container.find('[data-weekday="'+ dayName +'"]').parent()
										.find('[name="endTime"]').parent()
											.addClass('has-error');
									return false;
								}

								if (data[dayName + '_1_close'] && !data[dayName + '_1_open']) {
									data = [];

									// time to show some errors to the user
									container.find('[data-weekday="'+ dayName +'"]').parent()
										.find('[name="startTime"]').parent()
											.addClass('has-error');
									return false;
								}

								// Ignore the null value as it will be a day off
								if (!/^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(data[dayName + '_1_close']) && data[dayName + '_1_close'] !== null ) {
									data = [];

									// time to show some errors to the user
									container.find('[data-weekday="'+ dayName +'"]').parent()
										.find('[name="endTime"]').parent()
											.addClass('has-error');
									return false;
								}

								// Ignore the null value as it will be a day off
								if (!/^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(data[dayName + '_1_open']) && data[dayName + '_1_open'] !== null) {
									data = [];
									// time to show some errors to the user
									container.find('[data-weekday="'+ dayName +'"]').parent()
										.find('[name="startTime"]').parent()
											.addClass('has-error');
									return false;
								}


								  // if the hidden class cannot be seen then add the secondary times as well
								if (!dayContainer.find('.operationTime.hidden').length) {
									data[dayName + '_2_open'] = isWorkingDay ? dayContainer.find("[name='startTime_1']").val() : null;
									data[dayName + '_2_close'] = isWorkingDay ? dayContainer.find("[name='endTime_1']").val() : null;


									if (data[dayName + '_2_open'] && !data[dayName + '_2_close']) {
										data = [];

										// time to show some errors to the user
										container.find('[data-weekday="'+ dayName +'"]').parent()
											.find('[name="endTime_1"]').parent()
												.addClass('has-error');
										return false;
									}

									if (data[dayName + '_2_close'] && !data[dayName + '_2_open']) {
										data = [];

										// time to show some errors to the user
										container.find('[data-weekday="'+ dayName +'"]').parent()
											.find('[name="startTime_1"]').parent()
												.addClass('has-error');
										return false;
									}

									// Ignore the null value as it will be a day off
									if (!/^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(data[dayName + '_2_close']) && data[dayName + '_2_close'] !== null ) {
										data = [];

										// time to show some errors to the user
										container.find('[data-weekday="'+ dayName +'"]').parent()
											.find('[name="endTime_1"]').parent()
												.addClass('has-error');
										return false;
									}

									// Ignore the null value as it will be a day off
									if (!/^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/.test(data[dayName + '_2_open']) && data[dayName + '_2_open'] !== null) {
										data = [];
										// time to show some errors to the user
										container.find('[data-weekday="'+ dayName +'"]').parent()
											.find('[name="startTime_1"]').parent()
												.addClass('has-error');
										return false;
									}
								}

								// Validation End
							});
							
							return $.extend({}, data);
						}
					};
				},
				initView: function(options) {
					var stateClasses = [options.checkedColorClass, options.uncheckedColorClass];
					var subContainer = container.append($(options.containerTmpl));
					var $this = this;

					for(var i = 0; i < options.weekdays.length; i++) {
						subContainer.append(options.dayTmpl);
					}

					$.each(options.weekdays, function(pos, weekday) {
						// populate form
						var day = options.operationTime[pos];
						var operationDayNode = container.find(".dayContainer").eq(pos);
						operationDayNode.find('.weekday').html(weekday);
						
										operationDayNode.attr('id', 'bhday' + pos); /* ----- Added for PHP (not used yet)------ */




						// this used to get a specific node using jquery
						operationDayNode.find('.weekday').attr('data-weekday', weekday.toLowerCase());

						var isWorkingDay = $this.getValueOrDefault(day.isActive, options.defaultActive);
						operationDayNode.find('.operationState').prop('checked', isWorkingDay);
										
										operationDayNode.find('.operationState').attr('id', 'checkbox' + pos); /* ----- Added for PHP (not used yet) ------ */




						var timeFrom = $this.getValueOrDefault(day.timeFrom, options.defaultOperationTimeFrom);
						operationDayNode.find('[name="startTime"]').val(timeFrom);
										
										operationDayNode.find('[name="startTime"]').attr('id', 'start_1_' + pos); /* /* ----- Added for PHP ------ */




						var endTime = $this.getValueOrDefault(day.timeTill, options.defaultOperationTimeTill);
						operationDayNode.find('[name="endTime"]').val(endTime);
										
										operationDayNode.find('[name="endTime"]').attr('id', 'end_1_' + pos); /* ----- Added for PHP ------ */


							
						//check if second period has valus
						if(day.timeFrom_1){
							var btnNewSlot = operationDayNode.find('.addTimeSlot');								
							$secondTimeSlot = btnNewSlot.parent().find('[name="startTime_1"], [name="endTime_1"]').parent();

							$secondTimeSlot.toggleClass('hidden');
							if ($secondTimeSlot.is(':visible')) {
								btnNewSlot.html('<span class="fa fa-minus-square"></span> Remove');
							} else {
								btnNewSlot.html('<span class="fa fa-plus-square"></span> Add');
							}
						}

							
							
							var timeFrom = $this.getValueOrDefault(day.timeFrom_1, options.defaultOperationTimeFrom);
							operationDayNode.find('[name="startTime_1"]').val(timeFrom);
											
											operationDayNode.find('[name="startTime_1"]').attr('id', 'start_2_' + pos); /* /* ----- Added for PHP ------ */

							var endTime = $this.getValueOrDefault(day.timeTill_1, options.defaultOperationTimeTill);
							operationDayNode.find('[name="endTime_1"]').val(endTime);
											
											operationDayNode.find('[name="endTime_1"]').attr('id', 'end_2_' + pos); /* ----- Added for PHP ------ */
						
					});

					container.find(".operationState").change(function() {
						var checkbox = $(this);
						var boxClass = options.checkedColorClass;
						var timeControlDisabled = false;

						if(!checkbox.prop("checked")) {
							// disabled
							boxClass = options.uncheckedColorClass;
							timeControlDisabled = true;
						}

						checkbox.parents(".colorBox").removeClass(stateClasses.join(' ')).addClass(boxClass);
						checkbox.parents(".dayContainer").find(".operationTime").toggle(!timeControlDisabled);
					}).trigger("change");

					container.find(".colorBox").on("click", function() {
						var checkbox = $(this).find(".operationState");
						checkbox.prop("checked", !checkbox.prop('checked')).trigger("change");
					});

					// add time slot button click event will show the additional time slot
					container.find('.addTimeSlot').on('click', function(e) {
						e.preventDefault();
						var $that = $(this);
						
						//check if isWorkingDay
						var dayChk = $that.parent().find(".operationState");
						if(dayChk.prop("checked") === false){
							// is dayOff, the we need to open the 1st slot
							dayChk.prop('checked', true);
							container.find(".operationState").change(function() {
								var checkbox = $(this);
								var boxClass = options.checkedColorClass;
								var timeControlDisabled = false;

								if(!checkbox.prop("checked")) {
									// disabled
									boxClass = options.uncheckedColorClass;
									timeControlDisabled = true;
								}

								checkbox.parents(".colorBox").removeClass(stateClasses.join(' ')).addClass(boxClass);
								checkbox.parents(".dayContainer").find(".operationTime").toggle(!timeControlDisabled);
							}).trigger("change");
								
						} else {
							$secondTimeSlot = $that.parent().find('[name="startTime_1"], [name="endTime_1"]').parent();
							$secondTimeSlot.toggleClass('hidden');
							if ($secondTimeSlot.is(':visible')) {
								$that.html('<span class="fa fa-minus-square"></span> Remove');
							} else {
								$that.html('<span class="fa fa-plus-square"></span> Add');
								//clear second period values
								$that.parent().find('[name="startTime_1"]').val('');
								$that.parent().find('[name="endTime_1"]').val('');
							}
						}
					});
					
					
					
									

				}
			};
			return methods.init(opts);
		};
	})(jQuery);

	 window.sahan = $("#businessHoursContainer").businessHours({
		 dayTmpl:'<div class="dayContainer" style="width: 80px;">' +
				'<div data-original-title="" class="colorBox"><input type="checkbox" class="invisible operationState"></div>' +
				'<div class="weekday"></div>' +
				'<div class="operationDayTimeContainer">' +
				'<div class="operationTime input-group"><span class="input-group-addon"><i class="fa fa-sun-o"></i></span><input type="text" name="startTime" class="mini-time form-control operationTimeFrom" value=""></div>' +
				'<div class="operationTime input-group"><span class="input-group-addon"><i class="fa fa-moon-o"></i></span><input type="text" name="endTime" class="mini-time form-control operationTimeTill" value=""></div>' +
				'<div class="operationTime input-group hidden" style="display: table;"><span class="input-group-addon"><i class="fa fa-sun-o"></i></span><input type="text" name="startTime_1" class="mini-time form-control operationTimeFrom" value=""></div>' +
				'<div class="operationTime input-group hidden" style="display: table;"><span class="input-group-addon"><i class="fa fa-moon-o"></i></span><input type="text" name="endTime_1" class="mini-time form-control operationTimeTill" value=""></div>' +
				'</div><a class="btn btn-default btn-sm addTimeSlot"><span class="fa fa-plus-square"></span> Add</a></div>'
	});

	
	$(document).ready(function(){
		var optsTimes = 
				[{"isActive":false,"timeFrom":null,"timeTill":null},
                {"isActive":false,"timeFrom":null,"timeTill":null},
                {"isActive":false,"timeFrom":null,"timeTill":null},
                {"isActive":true,"timeFrom":"7:15","timeTill":"18:00"},
                {"isActive":true,"timeFrom":"9:00","timeTill":"18:00","timeFrom_1":"19:00","timeTill_1":"21:00"},
                {"isActive":false,"timeFrom":null,"timeTill":null},
                {"isActive":false,"timeFrom":null,"timeTill":null}];
        $("#businessHoursContainer").businessHours({operationTime: optsTimes, 
			 dayTmpl:'<div class="dayContainer" style="width: 80px;">' +
					'<div data-original-title="" class="colorBox"><input type="checkbox" class="invisible operationState"></div>' +
					'<div class="weekday"></div>' +
					'<div class="operationDayTimeContainer">' +
					'<div class="operationTime input-group"><span class="input-group-addon"><i class="fa fa-sun-o"></i></span><input type="text" name="startTime" class="mini-time form-control operationTimeFrom" value=""></div>' +
					'<div class="operationTime input-group"><span class="input-group-addon"><i class="fa fa-moon-o"></i></span><input type="text" name="endTime" class="mini-time form-control operationTimeTill" value=""></div>' +
					'<div class="operationTime input-group hidden" style="display: table;"><span class="input-group-addon"><i class="fa fa-sun-o"></i></span><input type="text" name="startTime_1" class="mini-time form-control operationTimeFrom" value=""></div>' +
					'<div class="operationTime input-group hidden" style="display: table;"><span class="input-group-addon"><i class="fa fa-moon-o"></i></span><input type="text" name="endTime_1" class="mini-time form-control operationTimeTill" value=""></div>' +
					'</div><a class="btn btn-default btn-sm addTimeSlot"><span class="fa fa-plus-square"></span> Add</a></div>'
		});
	});
	
	
	$(document).on('click','#submit_wh',function(){
		/* ----- Added for PHP ------ */
		var container = $('#businessHoursContainer');
		container.find(".operationState").each(function()
		{
			var i = $(this).attr('id').replace(/\D/g,'');
				
			//if($(this).is(':checked')) var checked = 1; else var checked = 0;
				
			var startTime_1 = $("#start_1_" + i).val();
			var endTime_1 = $("#end_1_" + i).val();
			//if(){
				var startTime_2 = $("#start_2_" + i).val();
				var endTime_2 = $("#end_2_" + i).val();
			//}
			console.log('#' + i + ' - Start_1: ' + startTime_1 + ' End_1: '+ endTime_1 + ' - Start_2: ' + startTime_2 + ' End_2: '+ endTime_2);
			// this is being replaced by a js ajax function to send the information to the PHP server!
				
		});
		/* ----- Added for PHP ------ */
		
	});

hossam-abdelmajeed avatar Jul 13 '22 05:07 hossam-abdelmajeed

Wow, that looks really cool!!

Thanks Hossam for sharing it with us!!

juergenweb avatar Jul 13 '22 05:07 juergenweb