Object.size = function(obj) { var size = 0, key; for (key in obj) { if (obj.hasOwnProperty(key)) size++; } return size; }; /** * Default selectors and template if they are not provided. **/ const _defaultHoursConfig = { selectors:{ container: '.footer-column--hours', title:'.footer-column__header', hoursData: '.footer-column__list', day:'.day', time:'.time' }, template: '' } /** * Format provided time for display on front end of website * Formatting includes converting from military time, adding AM/PM and dropping seconds * @param {string} time A time that will be displayed on the front end */ const parseMil = (time) => { try { const timeArr = time.split(':'); const hours = Number(timeArr[0]); const minutes = Number(timeArr[1]); let timeValue; if (hours > 0 && hours <=12){ timeValue = "" + hours; } else if (hours > 12){ timeValue = "" + (hours - 12); } else if (hours == 0){ timeValue = "12"; } timeValue += (minutes < 10) ? ":0" + minutes : ":" + minutes; timeValue += (hours >= 12) ? " PM" : " AM"; return timeValue; } catch (error) { console.error('Hours Editor Error:',error); } } /** * Creates and returns an array of openingHoursSpecification objects for the provided hours group * @param {string} group The group to create the schema json ld for */ const renderHoursSchema = (group) => { try { const days = oOperatingHours[group].days; let openingHoursSpecification=[] // loop through days in hour editor json for (const day of Object.keys(days)) { if (days[day].status === "inactive") { if (days[day].alternate) { openingHoursSpecification.push({"@type":"OpeningHoursSpecification","closes":"00:00:00","dayOfWeek":days[day].name,"opens":"00:00:00","description":days[day].alternate}); } else { openingHoursSpecification.push({"@type":"OpeningHoursSpecification","closes":"00:00:00","dayOfWeek":days[day].name,"opens":"00:00:00"}); } } else { if (days[day].alternate) { openingHoursSpecification.push({"@type":"OpeningHoursSpecification","closes":days[day].closed,"dayOfWeek":days[day].name,"opens":days[day].open,"description":days[day].alternate}); } else { openingHoursSpecification.push({"@type":"OpeningHoursSpecification","closes":days[day].closed,"dayOfWeek":days[day].name,"opens":days[day].open}); } } } return openingHoursSpecification; } catch (error) { console.error('Hours Editor Error:',error); } } /** * Reorder the week starting at a specified day or Monday if no day provided * @param {object} groupObj hours group days object * @param {int} weekStart day of the week (0=Sunday and 6=Saturday) */ const _reOrderWeek = (groupObj,weekStart=1) => { try { // default week cycle, starting on sunday let stdWeekCycle = ["sunday","monday","tuesday","wednesday","thursday","friday","saturday"]; let weekCycle = []; // create weekCycle based on days in hours group days object for (let x=0;x { try { for (const day in days) { days[day].name=days[day].name.substring(0,3); } return days; } catch (error) { console.error('Hours Editor Error:',error); } } /** * Convert time from milatary to standard and abbreviate hours if desired * @param {object} days json object of hours group days * @param {bool} hoursAbbr abbreviate hours to hour position */ const _formatHours = (days,hoursAbbr) => { try { for (const day in days) { if (days[day].open!=='closed' && hoursAbbr===true) { days[day].open=parseMil(days[day].open).replace(':00','') days[day].closed=parseMil(days[day].closed).replace(':00','') } else if (days[day].open!=='closed') { days[day].open=parseMil(days[day].open); days[day].closed=parseMil(days[day].closed); } } return days; } catch (error) { console.error('Hours Editor Error:',error); } } /** * Combine consecutive days that have the same opening and closing time * @param {object} days json of hours group days * @param {weekCycle} arrray array of days with first index the requested start of week day */ const _combineDays = (days,hoursGroup,weekCycle) => { try { const daysTemp={} let current={}; let previous={}; const matches=[]; let day={} for (var i=0;i<=Object.size(days);i++) { day=days[weekCycle[i]]; if (day===undefined) { current={} } else { current=day; } if (previous['alternate']===undefined && Object.keys(previous).length) { previous['alternate']=''; } if (current['alternate']===undefined && Object.keys(current).length) { current['alternate']=''; } if ((current['open']===previous['open'] && current['closed']===previous['closed']) && (current['alternate']===previous['alternate'])) { matches.push(current); } else { if (matches.length>1) { daysTemp[matches[0]['name']+' - '+matches[matches.length-1]['name']]={ name:matches[0]['name']+' - '+matches[matches.length-1]['name'], status:matches[0]['status'], open:matches[0]['open'], closed:matches[0]['closed'], alternate:matches[0]['alternate'] } } else if (matches.length===1) { daysTemp[matches[0]['name']]={ name:matches[0]['name'], status:matches[0]['status'], open:matches[0]['open'], closed:matches[0]['closed'], alternate:matches[0]['alternate'] } } // reset matches to empty array while(matches.length > 0) { matches.pop(); } matches.push(current); } previous=current; } return daysTemp; } catch (error) { console.error('Hours Editor Error:',error); } } /** * Insert created hours HTML into provided css selector for provided hours group * @param {object} hoursConfig Object containing all settings for rendering the hours * @param {string} target css selector for element to insert newly rendered hours html * @param {string} group hours group to use for rendering * @param {int} weekStart day to start the week on (0 is sunday and 6 is saturday) * @param {bool} daysAbbr abbreviate hours to three characters * @param {bool} hoursAbbr drop minutes placeholder * @param {bool} combineDays combine consecutive days with the same opening and closing time * @param {object} selectors css selectors used in the html template for rendering * @param {string} container css selector for container * @param {string} title css selector for title of hours group * @param {string} hoursData css selector for the container of the hours data * @param {string} day css selector for the tag used for the day * @param {string} time css selector for the tag used for the time * @param {string} template empty html template to use for rendering */ const renderHoursContent = (hoursConfig) => { try { // For readability const oOperatingHoursTemp=JSON.parse(JSON.stringify(oOperatingHours)); // make a copy of oOperatingHours. const target=hoursConfig.target; const hoursGroup=hoursConfig.group; const daysAbbr=hoursConfig.daysAbbr; const hoursAbbr=hoursConfig.hoursAbbr; const weekStart=hoursConfig.weekStart; const combineDays = (hoursConfig.combineHours===undefined) ? hoursConfig.combineDays : hoursConfig.combineHours; // const alternateText=hoursConfig.alternateText; // use default if selectors and template null const selectors=hoursConfig.selectors ? hoursConfig.selectors:_defaultHoursConfig.selectors; let $template=hoursConfig.template ? $('
').html($(hoursConfig.template)):$('
').html($(_defaultHoursConfig.template)); // wrapping template in div so it is easier to insert with jquery // determine where the new hours data will be inserted if (selectors.hoursData) { $hoursTarget=$template.find(selectors.hoursData); } else if (selectors.container) { $hoursTarget=$template.find(selectors.container); } else { $hoursTarget=$template } if (daysAbbr) { oOperatingHoursTemp[hoursGroup]['days']=_abbreviateDays(oOperatingHoursTemp[hoursGroup]['days']); } oOperatingHoursTemp[hoursGroup]['days']=_formatHours(oOperatingHoursTemp[hoursGroup]['days'],hoursAbbr); let weekCycle = _reOrderWeek(oOperatingHours[hoursGroup]['days'],weekStart); if (combineDays) { oOperatingHoursTemp[hoursGroup]['days']=_combineDays(oOperatingHoursTemp[hoursGroup]['days'],hoursGroup,weekCycle); weekCycle = Object.keys(oOperatingHoursTemp[hoursGroup]['days']); } $template.find(selectors.title).text(oOperatingHoursTemp[hoursGroup].name); // clone jquery object for day/hours let $dayHTML = $hoursTarget.find(selectors.day).clone(); let $timeHTML = $hoursTarget.find(selectors.time).clone(); // remove empty time/hours html $hoursTarget.find(selectors.day).remove(); $hoursTarget.find(selectors.time).remove(); // loop through days of the week and add to template weekCycle.forEach(function(v,i){ // for readibility const dayName=oOperatingHoursTemp[hoursGroup]['days'][v].name; const dayOpen=oOperatingHoursTemp[hoursGroup]['days'][v].open; const dayClose=oOperatingHoursTemp[hoursGroup]['days'][v].closed; // const dayHours=(oOperatingHoursTemp[hoursGroup]['days'][v].status=='active') ? dayOpen+' - '+dayClose : 'Closed'; if (oOperatingHoursTemp[hoursGroup]['days'][v].alternate /* && alternateText */) { dayHours=oOperatingHoursTemp[hoursGroup]['days'][v].alternate; } else if (oOperatingHoursTemp[hoursGroup]['days'][v].status=='active') { dayHours=dayOpen+' - '+dayClose; } else { dayHours='Closed'; } // console.log(oOperatingHoursTemp[hoursGroup]['days'][v].alternate,v); $hoursTarget.append($dayHTML.text(dayName).clone()) $hoursTarget.append($timeHTML.text(dayHours).clone()) }); $template.html($template.html()); $(target).html($template.html()); } catch (error) { console.error('Hours Editor Error:',error); } }