function DateField(scope){ var _today=scope.min_date; var _90_days_from_now=_today.clone().addDays(scope.day_range); var _valid_years=null; var _valid_months=null; var _valid_dates=null; var _selected_year=null; var _selected_month=null; var _selected_date=null; var _selected_date=scope.selected_date; var _rendering=false; /** * @para Date : date1 - the date to start checking from * @para Date : date2 - */ function get_valid_dates_between(date1,date2){ //console.log("Getting valid dates between ",date1,date2) var d=date1.clone(); var fardate=_90_days_from_now.clone(); d.moveToFirstDayOfMonth(); if(d.compareTo(date2)==-1){d=date2;} var new_date=d.clone().moveToLastDayOfMonth(); // << problem here, should not be last day of month // If the new date is after the far date set it to the fardate if(new_date.compareTo(fardate)>0) new_date=fardate.clone().addDays(1); var count_date=d.clone(); var _dates=[]; while(count_date.compareTo(new_date)!=1){ _dates.push(count_date.clone()); count_date.addDays(1); }; return _dates; } function get_valid_months_between(date1,date2,date3){ var d1=date1.clone();d1.set({day:1}); var d2=date2.clone();d2.set({day:1}); var d3=(date3.clone());d3.set({month:11,day:1}); // Check the first date is past date3 else set the year to date3 and to the first month if(d1.getYear()d3.getYear()){ d2=(d3.clone()).set({month:11}).moveToLastDayOfMonth(); }else{ } // Get the start date var start_date=(d1.clone()).clearTime(); var count_date=start_date.clone(); var _months=[]; var _finding_months=true; while(count_date.getYear()<=d2.getYear() && _finding_months){ if(count_date.getYear()"); if(n.getDate()==date.getDate()){ _option.attr('selected','selected') } _option.html(n.toString("dd")); _option.val(n.getDate()); select.append(_option); }); // Set selected } function update_months_in_year(date,valid_months,select){ // Add months to dropdown select.html(""); $.each(valid_months,function(i,n){ var _option=$(""); if(n.getMonth()==date.getMonth()){ _option.attr('selected','selected') } _option.html(n.toString("MMMM")); _option.val(n.getMonth()); select.append(_option); }); } function update_years(date,valid_years,select){ select.html(""); $.each(valid_years,function(i,n){ var _option=$(""); _option.html(n.toString("yyyy")); if(n.getYear() == date.getYear()){ _option.attr('selected','selected'); } select.append(_option); }); } function update_year(){ update_month(); update_years(_selected_year,_valid_years,$("select[name='calendar_year']",scope.element)); } function update_month(){ update_day(); update_months_in_year(_selected_date,_valid_months,$("select[name='calendar_month']",scope.element)); } function update_day(){ update_days_in_month(_selected_date,_valid_dates,$("select[name='calendar_day']",scope.element)); update_em(_selected_date); } function update_em(date){ $("em",scope.element).html(date.toString("dddd, d") + getSuffix(date.toString("dd")) + date.toString(" MMMM yyyy")); } function render(){ if(_rendering==false){ _rendering=true; _selected_year=_selected_date.clone(); _selected_month=_selected_date.clone(); _selected_date=_selected_date.clone(); dp.dpSetSelected(_selected_date.toString("dd/MM/yyyy")) // Get a list of valid years _valid_years = get_valid_years_between(_today,_90_days_from_now.clone()); _valid_months = get_valid_months_between(_today,_90_days_from_now,_selected_year); _valid_dates = get_valid_dates_between(_selected_month,_today); update_year(); } _rendering=false; } // Check in day changed $("select[name='calendar_day']",scope.element).bind('change',function(e){ _selected_date.setDate($(this).val()); update_day(); if(scope.on_change) scope.on_change(_selected_date); }); // Check in month changed $("select[name='calendar_month']",scope.element).bind('change',function(e){ _selected_date.set({month:parseInt($(this).val())}); _selected_month =_selected_date.clone(); _valid_dates = get_valid_dates_between(_selected_date,_today); update_month(); if(scope.on_change) scope.on_change(_selected_date); }); // Check in year changed $("select[name='calendar_year']",scope.element).bind('change',function(e){ _selected_year.set({year:parseInt($(this).val()),month:11}); _valid_months = get_valid_months_between(_today,_90_days_from_now,_selected_year); _selected_month =_valid_months[0]; _selected_date = (_selected_month.clone()).set({day:_selected_date.getDate()}); _valid_dates = get_valid_dates_between(_selected_month,_today); update_year(); if(scope.on_change) scope.on_change(_selected_date); }); var monthLimit = $('meta[name="calendar.dayrange.room"]').attr("content"); var endingDate = (_90_days_from_now.clone()).addDays(0); var startDate = (_today.clone()).addDays(0); var dp=$('a',scope.element).datePicker({ createButton:false, endDate:endingDate.toString("dd/MM/yyyy"), startDate:startDate.toString("dd/MM/yyyy") }).dpSetOffset(24,-164).bind('click', function() { $(this).dpDisplay(); $('a',scope.element).blur(); return false; } ).bind( 'dateSelected', function(e, selectedDate, $td, state) { _selected_date=selectedDate; $('a',scope.element).blur(); render(); if(scope.on_change) scope.on_change(_selected_date); return false; } ); render(); this.render=function(model){ try { if(Date.parseExact(model, "dd/MM/yyyy")){ _selected_date = Date.parseExact(model, "dd/MM/yyyy"); } } catch (e) { throw(e); } render(); }; this.get_date=function(){ return _selected_date; }; this.setScope=function(_scope){ // get selected date if(_scope.min_date) _today=_scope.min_date; if(_scope.selected_date) _selected_date=_scope.selected_date; //render(); } function getSuffix(date){ switch (parseInt(date)) { case 1: case 21: case 31: return "st"; case 2: case 22: return "nd"; case 3: case 23: return "rd"; default: return "th"; } } } function Templating(){ } Templating.parseTemplate=parseTemplate; if (!Templating) { function TemplateTank(){ var _templates = null; this.get_template=function(name){ var d=scanElm($(".__templates__")[0]); if(!_templates){ _templates={}; $.each(d,function(i,n){ //alert(n.match); // Rest is code var y=n.match(/[a-z0-9]{1,}/i)[0]; var u=n.replace(y,''); y=$.trim(y); _templates[y]=u; }); } return _templates[name]; } this.get_template_from_URI=function(uri,callback){ if(!_templates){ _templates={}; } if(_templates[uri]!=null){ //alert(uri); callback(_templates[uri]); }else{ now = new Date(); $.get("/template/ejs/"+uri+".ejs?"+now.toString(),{},function(data){ _templates[uri]=data; callback(_templates[uri]); }); } } }; TemplateTank = new TemplateTank(); } function scanElm(elm){ var rc = []; for(var c = 0; c < elm.childNodes.length; c++) { var child = elm.childNodes[c]; if (child.nodeType == 8){ rc.push(child.nodeValue); } }; return rc; } function parseTemplate(options){ var _string=sanatise(options.template); var _data=options.data; var _view=options.view || {}; var _del="[]"; var _left_caret=0; var _right_caret=0; var _code=""; //add_code("var output=\"\";"); while(_right_caret<_string.length){ var tag_left_caret=_string.indexOf("[%",_right_caret); if (tag_left_caret != -1) { add_code("output+=\""+_string.substring(_right_caret,tag_left_caret)+"\";"); var tag_right_caret = _string.indexOf("%]",tag_left_caret); var _adder=0; var _c=""; if(_string.substr(tag_left_caret,3)=="[%="){ _c="output+="+_string.substring(tag_left_caret+3,tag_right_caret)+";"; _adder=2; }else{ _c=_string.substring(tag_left_caret+2,tag_right_caret); _adder=2; } add_code(_c); _right_caret=tag_left_caret+(tag_right_caret-tag_left_caret)+_adder; }else{ add_code("output+=\""+_string.substr(_right_caret,_string.length-1)+"\";"); _right_caret=_string.length; } } // Evaluated the code on context of the data with(_view){ with(_data){ var output=""; //alert("Template\n\n"+_code); //alert(">> "+_code); try{ eval(_code); }catch(e){ alert(e); } //alert("Template\n\n"+output); return output; } } // Helper to append code to code string function add_code(string){ //alert(">>"+string); _code+=string;//+"\n"; } function sanatise(string){ var _string=string; _string=_string.replace(/\"/gi,'\\"'); // Replace quotes with \" to prevent eval breaking _string=_string.replace(/[\n\t\r]/gi,''); // Replace all tabs and newlines return _string; } } $.fn.x = function(n) { var result = null; this.each(function() { var o = this; if (n === undefined) { var x = 0; if (o.offsetParent) { while (o.offsetParent) { x += o.offsetLeft; o = o.offsetParent; } } if (result === null) { result = x; } else { result = Math.min(result, x); } } else { o.style.left = n + 'px'; } }); return result; }; $.fn.y = function(n) { var result = null; this.each(function() { var o = this; if (n === undefined) { var y = 0; if (o.offsetParent) { while (o.offsetParent) { y += o.offsetTop; o = o.offsetParent; } } if (result === null) { result = y; } else { result = Math.min(result, y); } } else { o.style.top = n + 'px'; } }); return result; }; /** * @author hedgehog */ function EventDelegator(options){ if(this.__EVENT_DELEGATOR__) return; this.__EVENT_DELEGATOR__=true; var _subscriptions={}; this.subscribe_to=function(event_key,event_delegate){ if(!_subscriptions[event_key]){ _subscriptions[event_key]=[]; } _subscriptions[event_key].push(event_delegate); }; this.unsubscribe_to=function(event_key,event_delegate){ $.each(_subscriptions[event_key],function(i,n){ if(event_delegate==n){ _subscriptions[event_key][i]=null; } }); } this.raise_event=function(event_name,args){ function each_subscription(index,item){ if(item){ item(args); } } if (_subscriptions[event_name]) { $.each(_subscriptions[event_name], each_subscription); } }; } /** * @author hedgehog */ function BaseModel(scope){ EventDelegator.call(this,scope); } // Static helper method to convert models that should be arrays into arrays BaseModel.to_array=function(obj){ if (obj.constructor.toString().indexOf("Array") == -1) obj=[obj]; return obj } function AvailabilityView(){} AvailabilityView.show_overlay=function(){}; $(function(e){ // Create overlay and append to body: $('

Checking Availability

').hide().appendTo('body'); function show_overlay(){ $('#overlay').show(); } AvailabilityView.show_overlay=show_overlay; }); function SpaBookAvailabilityCalendarView(scope){ BaseView.call(this,scope); var _helper=new GolfBookAvailabilityCalendarHelper(); var _this=this; var _today=Date.today(); var _valid_months=null; var _valid_years=null; var _guests=$("select[name='guests']",scope.element).val(); if(Date.parse($('meta[name=spa_availability_date]').attr("content"))){ var _selected_date=Date.parseExact($('meta[name=spa_availability_date]').attr("content"),"dd/MM/yy"); var new_guests = $("meta[name='guests']").attr("content"); $.each($("select[name='guests'] option",scope.element),function(i,n){ if($(n).val() == new_guests){ $(n).attr("selected","selected"); } }); }else{ var _selected_date=Date.today().addDays(1); var new_guests = $("meta[name='guests']").attr("content"); $.each($("select[name='guests'] option",scope.element),function(i,n){ if($(n).val() == new_guests){ $(n).attr("selected","selected"); } }); } var cod=new DateField({ element:$("#bookdate",scope.element), selected_date:(_selected_date.clone()), month_range:scope.month_range, day_range:scope.day_range, min_date:(_today.addDays(1).clone()), on_change:function(e){ _selected_date=e.clone(); } }); function render(){ cod.setScope({ selected_date:_selected_date }); } this.render=function(model){ try { if(Date.parseExact(model, "dd/MM/yyyy")){ _selected_date = Date.parseExact(model, "dd/MM/yyyy"); } } catch (e) { throw(e); } render(); }; $("select[name='guests']",scope.element).bind("change",function(e){ _guests=$(this).val(); }); // Need to implement a jquery date component to handle selecting a date $("button[id='check_availability_action']",scope.element).bind('click',function(e){ _this.raise_event('check_availability_clicked',{date:_selected_date,guests:_guests}); return false; }) var monthLimit = $('meta[name="calendar.dayrange.spa"]').attr("content"); var endingDate = Date.today().addMonths(parseInt(monthLimit)).toString("dd/MM/yyyy"); } function RoomBookAvailabilityCalendarView(scope){ var _this=this; BaseView.call(this,scope); var _helper=new GolfBookAvailabilityCalendarHelper(); var _today = Date.today(); var _guests=$("select[name='guests']",scope.element).val(); if(Date.parse($("meta[name='checkInDate']").attr("content"))){ var _selected_date=Date.parseExact($("meta[name='checkInDate']").attr("content"),"dd/MM/yy"); var _checkout_date=Date.parseExact($("meta[name='checkOutDate']").attr("content"),"dd/MM/yy"); var new_guests = $("meta[name='guests']").attr("content"); $.each($("select[name='guests'] option",scope.element),function(i,n){ if($(n).val() == new_guests){ $(n).attr("selected","selected"); } }); }else{ var _selected_date=Date.today(); var _checkout_date=_selected_date.clone(); } var cod=new DateField({ element:$("#check-out-date",scope.element), selected_date:(_selected_date.clone()).addDays(1), month_range:scope.month_range, day_range:scope.day_range, min_date:(_today.clone()).addDays(1), on_change:function(e){ _checkout_date=e.clone(); } }); var cid=new DateField({ element:$("#check-in-date",scope.element), selected_date:_selected_date, month_range:scope.month_range, day_range:scope.day_range, min_date:(_today.clone()), on_change:function(e){ if(e.compareTo(cod.get_date())>=0){ cod.setScope({ selected_date:(e.clone()).addDays(1) }); } // cod.setScope({min_date:(e.clone()).addDays(1)}); cod.render(); _selected_date=e.clone(); } }); $("select[name='guests']",scope.element).bind("change",function(e){ _guests=$(this).val(); }); // Need to implement a jquery date component to handle selecting a date $("button[id='check_availability_action']",scope.element).bind('click',function(e){ _this.raise_event('check_availability_clicked',{date:_selected_date,checkout_date:_checkout_date,guests:_guests}); return false; }); } function GolfBookAvailabilityCalendarHelper(){ // this.get_suitable_date_range_with_restriction(date,) function date_in_future_by_days(date,days){ return (date.clone()).addDays(days); } // Returns the remaining days in the month this.get_suitable_day_range=function(date){ // Clear the day // If the day is lower than today set it to today else leave it var d=date.clone(); d.moveToFirstDayOfMonth(); if(d.compareTo(Date.today())==-1){d=date;} var new_date=(d.clone()).moveToLastDayOfMonth(); var count_date=d.clone(); var _dates=[]; while(count_date.compareTo(new_date)==-1){ _dates.push(count_date.clone()); count_date.addDays(1); }; return _dates; } this.get_suitable_date_range=function(date,range){ var new_date=date.clone().addMonths(range); var count_date=date.clone(); var _months=[]; while(count_date.compareTo(new_date)==-1){ _months.push(count_date.clone()); count_date.addMonths(1); }; return _months; } this.get_suitable_month_range=function(date,range){ var new_date=date.clone().addMonths(range); var count_date=date.clone(); var _months=[]; while(count_date.compareTo(new_date)==-1){ _months.push(count_date.clone()); count_date.addMonths(1); }; return _months; } this.get_suitable_year_range=function(date,range){ var new_date=date.clone().addYears(range); var count_date=date.clone(); var _years=[]; while(count_date.compareTo(new_date)==-1){ _years.push(count_date.clone()); count_date.addYears(1); }; return _years; } this.get_suitable_date_range_res=function(date,range){ var new_date=(date.clone()).moveToLastDayOfMonth(); var count_date=date.clone(); var _dates=[]; while(count_date.compareTo(new_date)==-1){ _dates.push(count_date.clone()); count_date.addDays(1); }; return _dates; } this.get_suitable_month_range_res=function(date,range){ var new_date=date_in_future_by_days(date,range); var count_date=date.clone(); var _months=[]; while(count_date.compareTo(new_date)==-1){ _months.push(count_date.clone()); count_date.addMonths(1); }; return _months; } this.get_suitable_year_range_res=function(date,range){ var new_date=date_in_future_by_days(date,range); var count_date=date.clone(); var _years=[]; while(count_date.compareTo(new_date)==-1){ _years.push(count_date.clone()); count_date.addYears(1); }; return _years; } }; function GolfBookAvailabilityCalendarView(scope){ BaseView.call(this,scope); var _helper=new GolfBookAvailabilityCalendarHelper(); var _this=this; var _today=Date.today(); var _valid_months=null; var _valid_years=null; if(Date.parse($('meta[name=availability_date]').attr("content"))){ var _selected_date=Date.parseExact($('meta[name=availability_date]').attr("content"),"dd/MM/yy"); }else{ var _selected_date=Date.today(); } var _players=1; var _selected_players = $('meta[name=Players]').attr("content"); var cod=new DateField({ element:$(".date-field",scope.element), selected_date:(_selected_date.clone()), month_range:scope.month_range, day_range:scope.day_range, min_date:(_today.clone()), on_change:function(e){ _selected_date=e.clone(); } }); function update_players(num){ $("select[name='players']",scope.element).html(""); for(i=1;i<=num;i++){ var _option=$(""); _option.html(i); _option.val(i); if(i == _selected_players){ _option.attr('selected','selected'); } $("select[name='players']",scope.element).append(_option); } } function render(){ update_players(8); //alert(selected_date); cod.setScope({ selected_date:_selected_date }); $("select[name='players']",scope.element).bind('change',function(e){ _selected_players = $("select[name='players']",scope.element).val(); }); } this.render=function(model){ try { if(Date.parseExact(model, "dd/MM/yyyy")){ _selected_date = Date.parseExact(model, "dd/MM/yyyy"); } } catch (e) { throw(e); } render(); }; // Need to implement a jquery date component to handle selecting a date $("button[id='check_availability_action']",scope.element).bind('click',function(e){ _this.raise_event('check_availability_clicked',{date:_selected_date,players:_selected_players}); return false; }) var monthLimit = $('meta[name="calender.dayrange.golf"]').attr("content"); var endingDate = Date.today().addMonths(parseInt(monthLimit)).toString("dd/MM/yyyy"); } function BookingIndexController(scope){ BaseView.call(this,scope); var _this=this; //console.log(scope.meta_model.subscribe_to); // subcribe to the models changed mathod scope.meta_model.subscribe_to('on_model_changed',function(e){ scope.calendar_view.render(e.availability_date); //scope.room_view.render(e.availability_date); }); // on check availability view delegate check event scope.calendar_view.subscribe_to('check_availability_clicked',function(e){ if(e.players){ $("input[name='Players']").val(e.players); } var date=e.date.toString("dd/MM/yy");//(//e.date.getDate()+"/"+e.date.getMonth()+"/"+e.date.getYear(); $("input[name='availability_date']").val(date); AvailabilityView.show_overlay(); $('#golf_book_availability_form').submit(); }); /* This is the event the room calendar view will raise The model returned from this view may change slightly depending on the requirements of the room date chooser i.e. two dates... ...need to check this // on check availability view delegate check event for room dates */ scope.room_view.subscribe_to('check_availability_clicked',function(e){ var date=e.date.toString("dd/MM/yy"); $("input[name='checkInDate']").val(date); var date=e.checkout_date.toString("dd/MM/yy"); $("input[name='checkOutDate']").val(date); var guests=e.guests; $("input[name='guests']").val(guests); AvailabilityView.show_overlay(); $('#room_book_availability_form').submit(); }); // Update the metadata model scope.meta_model.model(); scope.spa_view.subscribe_to('check_availability_clicked',function(e){ var date=e.date.toString("dd/MM/yy");//(//e.date.getDate()+"/"+e.date.getMonth()+"/"+e.date.getYear(); $("input[name='availability_date']").val(date); var guests=e.guests; $("input[name='guests']").val(guests); AvailabilityView.show_overlay(); $('#spa_book_availability_form').submit(); }); // Update the metadata model scope.meta_model.model(); } /** * @author hedgehog */ function BaseView(scope){ EventDelegator.call(this,scope); this.render_template=function(template,data,callback){ TemplateTank.get_template_from_URI(template,function(_data){ callback(Templating.parseTemplate({ data:data, template:_data })); }); }; this.render_template_with_view=function(template,data,view,callback){ TemplateTank.get_template_from_URI(template,function(_data){ callback(Templating.parseTemplate({ data:data, view:view, template:_data })); }); }; this.render_template_from_markup=function(obj,callback){ var temp = Templating.parseTemplate({ data:obj.data, view:obj.view, template:obj.template }); callback(temp); }; } /** * @author markforster */ function MetaDataModel(scope){ BaseModel.call(this,scope); var _this=this; var _model=null; this.model=function(){ if(_model==null){ //_model= _model={}; var meta=$("meta",document.head); $.each(meta,function(i,n){ _model[$(n).attr('name')]=$(n).attr('content'); }); _this.raise_event('on_model_changed',_model); } return _model; } } $(function(){ // Services var _meta_model=new MetaDataModel(); // Get the day range from the meta tag var golf_day_range=$('meta[name=calender.dayrange.golf]').attr("content"); var room_day_range=$('meta[name=calender.dayrange.room]').attr("content"); var spa_day_range=$('meta[name=calender.dayrange.spa]').attr("content"); // Views var _calendar_view=new GolfBookAvailabilityCalendarView({ "element":$("#golf_calendar"), month_range:3, day_range:golf_day_range }); var _room_calendar_view=new RoomBookAvailabilityCalendarView({ "element":$("#room_calendar"), month_range:3, day_range:room_day_range }); var _spa_calendar_view=new SpaBookAvailabilityCalendarView({ "element":$("#spa_calendar"), month_range:3, day_range:spa_day_range }); // Controllers var _booking_controller=new BookingIndexController({ calendar_view:_calendar_view, room_view:_room_calendar_view, //<< this is where the room_calendar_view is passed in to the controller spa_view:_spa_calendar_view, meta_model:_meta_model }); /* Tab panel for availability checker */ var _tab_panel=new TabPanel({ element:$('.availability-checker'), tabs:$('.availability-checker .tab-navigation li'), panes:$('.availability-checker .tab-panes .tab-pane'), current:location.hash.replace('#','') }); }); function TabPanel(scope){ BaseView.call(this,scope); var _current_pane_index=null; function show_pane(index){ if(_current_pane_index!=null) hide_pane(_current_pane_index); $(scope.tabs[index]).addClass('current'); $(scope.panes[index]).show(); _current_pane_index=index; } function hide_pane(index){ $(scope.tabs[index]).removeClass('current'); $(scope.panes[index]).hide(); } // Each Tab $.each(scope.tabs,function(i,n){ // Check for current or selected if($(n).hasClass('current')){ _current_pane_index=i; }else{ // Hide the pane $(scope.panes[i]).hide().removeClass('hide'); } $('a',this).bind('click',function(e){ show_pane(i); }); }); }