<commit_before>!function(document,window,index){"use strict";var responsiveNav=function(el,options){!!window.getComputedStyle||(window.getComputedStyle=function(el){return this.el=el,this.getPropertyValue=function(prop){var re=/(\-([a-z]){1})/g;return"float"===prop&&(prop="styleFloat"),re.test(prop)&&(prop=prop.replace(re,function(){return arguments[2].toUpperCase()})),el.currentStyle[prop]?el.currentStyle[prop]:null},this});var nav,opts,navToggle,hasAnimFinished,isMobile,navOpen,addEvent=function(el,evt,fn,bubble){if("addEventListener"in el)try{el.addEventListener(evt,fn,bubble)}catch(e){if("object"!=typeof fn||!fn.handleEvent)throw e;el.addEventListener(evt,function(e){fn.handleEvent.call(fn,e)},bubble)}else"attachEvent"in el&&("object"==typeof fn&&fn.handleEvent?el.attachEvent("on"+evt,function(){fn.handleEvent.call(fn)}):el.attachEvent("on"+evt,fn))},removeEvent=function(el,evt,fn,bubble){if("removeEventListener"in el)try{el.removeEventListener(evt,fn,bubble)}catch(e){if("object"!=typeof fn||!fn.handleEvent)throw e;el.removeEventListener(evt,function(e){fn.handleEvent.call(fn,e)},bubble)}else"detachEvent"in el&&("object"==typeof fn&&fn.handleEvent?el.detachEvent("on"+evt,function(){fn.handleEvent.call(fn)}):el.detachEvent("on"+evt,fn))},getChildren=function(e){if(e.children.length<1)throw new Error("The Nav container has no containing elements");for(var children=[],i=0;i<e.children.length;i++)1===e.children[i].nodeType&&children.push(e.children[i]);return children},setAttributes=function(el,attrs){for(var key in attrs)el.setAttribute(key,attrs[key])},addClass=function(el,cls){0!==el.className.indexOf(cls)&&(el.className+=" "+cls,el.className=el.className.replace(/(^\s*)|(\s*$)/g,""))},removeClass=function(el,cls){var reg=new RegExp("(\\s|^)"+cls+"(\\s|$)");el.className=el.className.replace(reg," ").replace(/(^\s*)|(\s*$)/g,"")},forEach=function(array,callback,scope){for(var i=0;i<array.length;i++)callback.call(scope,i,array[i])},styleElement=document.createElement("style"),htmlEl=document.documentElement,ResponsiveNav=function(el,options){var i;this.options={animate:!0,transition:284,label:"Menu",insert:"before",customToggle:"",closeOnNavClick:!1,openPos:"relative",navClass:"nav-collapse",navActiveClass:"js-nav-active",jsClass:"js",init:function(){},open:function(){},close:function(){}};for(i in options)this.options[i]=options[i];if(addClass(htmlEl,this.options.jsClass),this.wrapperEl=el.replace("#",""),document.getElementById(this.wrapperEl))this.wrapper=document.getElementById(this.wrapperEl);else{if(!document.querySelector(this.wrapperEl))throw new Error("The nav element you are trying to select doesn't exist");this.wrapper=document.querySelector(this.wrapperEl)}this.wrapper.inner=getChildren(this.wrapper),opts=this.options,nav=this.wrapper,this._init(this)};return ResponsiveNav.prototype={destroy:function(){this._removeStyles(),removeClass(nav,"closed"),removeClass(nav,"opened"),removeClass(nav,opts.navClass),removeClass(nav,opts.navClass+"-"+this.index),removeClass(htmlEl,opts.navActiveClass),nav.removeAttribute("style"),nav.removeAttribute("aria-hidden"),removeEvent(window,"resize",this,!1),removeEvent(window,"focus",this,!1),removeEvent(document.body,"touchmove",this,!1),removeEvent(navToggle,"touchstart",this,!1),removeEvent(navToggle,"touchend",this,!1),removeEvent(navToggle,"mouseup",this,!1),removeEvent(navToggle,"keyup",this,!1),removeEvent(navToggle,"click",this,!1),opts.customToggle?navToggle.removeAttribute("aria-hidden"):navToggle.parentNode.removeChild(navToggle)},toggle:function(){!0===hasAnimFinished&&(navOpen?this.close():this.open())},open:function(){navOpen||(removeClass(nav,"closed"),addClass(nav,"opened"),addClass(htmlEl,opts.navActiveClass),addClass(navToggle,"active"),nav.style.position=opts.openPos,setAttributes(nav,{"aria-hidden":"false"}),navOpen=!0,opts.open())},close:function(){navOpen&&(addClass(nav,"closed"),removeClass(nav,"opened"),removeClass(htmlEl,opts.navActiveClass),removeClass(navToggle,"active"),setAttributes(nav,{"aria-hidden":"true"}),opts.animate?(hasAnimFinished=!1,setTimeout(function(){nav.style.position="absolute",hasAnimFinished=!0},opts.transition+10)):nav.style.position="absolute",navOpen=!1,opts.close())},resize:function(){"none"!==window.getComputedStyle(navToggle,null).getPropertyValue("display")?(isMobile=!0,setAttributes(navToggle,{"aria-hidden":"false"}),nav.className.match(/(^|\s)closed(\s|$)/)&&(setAttributes(nav,{"aria-hidden":"true"}),nav.style.position="absolute"),this._createStyles(),this._calcHeight()):(isMobile=!1,setAttributes(navToggle,{"aria-hidden":"true"}),setAttributes(nav,{"aria-hidden":"false"}),nav.style.position=opts.openPos,this._removeStyles())},handleEvent:function(e){var evt=e||window.event;switch(evt.type){case"touchstart":this._onTouchStart(evt);break;case"touchmove":this._onTouchMove(evt);break;case"touchend":case"mouseup":this._onTouchEnd(evt);break;case"click":this._preventDefault(evt);break;case"keyup":this._onKeyUp(evt);break;case"focus":case"resize":this.resize(evt)}},_init:function(){this.index=index++,addClass(nav,opts.navClass),addClass(nav,opts.navClass+"-"+this.index),addClass(nav,"closed"),hasAnimFinished=!0,navOpen=!1,this._closeOnNavClick(),this._createToggle(),this._transitions(),this.resize();var self=this;setTimeout(function(){self.resize()},20),addEvent(window,"resize",this,!1),addEvent(window,"focus",this,!1),addEvent(document.body,"touchmove",this,!1),addEvent(navToggle,"touchstart",this,!1),addEvent(navToggle,"touchend",this,!1),addEvent(navToggle,"mouseup",this,!1),addEvent(navToggle,"keyup",this,!1),addEvent(navToggle,"click",this,!1),opts.init()},_createStyles:function(){styleElement.parentNode||(styleElement.type="text/css",document.getElementsByTagName("head")[0].appendChild(styleElement))},_removeStyles:function(){styleElement.parentNode&&styleElement.parentNode.removeChild(styleElement)},_createToggle:function(){if(opts.customToggle){var toggleEl=opts.customToggle.replace("#","");if(document.getElementById(toggleEl))navToggle=document.getElementById(toggleEl);else{if(!document.querySelector(toggleEl))throw new Error("The custom nav toggle you are trying to select doesn't exist");navToggle=document.querySelector(toggleEl)}}else{var toggle=document.createElement("a");toggle.innerHTML=opts.label,setAttributes(toggle,{href:"#",class:"nav-toggle"}),"after"===opts.insert?nav.parentNode.insertBefore(toggle,nav.nextSibling):nav.parentNode.insertBefore(toggle,nav),navToggle=toggle}},_closeOnNavClick:function(){if(opts.closeOnNavClick){var links=nav.getElementsByTagName("a"),self=this;forEach(links,function(i,el){addEvent(links[i],"click",function(){isMobile&&self.toggle()},!1)})}},_preventDefault:function(e){if(e.preventDefault)return e.stopImmediatePropagation&&e.stopImmediatePropagation(),e.preventDefault(),e.stopPropagation(),!1;e.returnValue=!1},_onTouchStart:function(e){Event.prototype.stopImmediatePropagation||this._preventDefault(e),this.startX=e.touches[0].clientX,this.startY=e.touches[0].clientY,this.touchHasMoved=!1,removeEvent(navToggle,"mouseup",this,!1)},_onTouchMove:function(e){(Math.abs(e.touches[0].clientX-this.startX)>10||Math.abs(e.touches[0].clientY-this.startY)>10)&&(this.touchHasMoved=!0)},_onTouchEnd:function(e){if(this._preventDefault(e),isMobile&&!this.touchHasMoved){if("touchend"===e.type)return void this.toggle();var evt=e||window.event;3!==evt.which&&2!==evt.button&&this.toggle()}},_onKeyUp:function(e){13===(e||window.event).keyCode&&this.toggle()},_transitions:function(){if(opts.animate){var objStyle=nav.style,transition="max-height "+opts.transition+"ms";objStyle.WebkitTransition=objStyle.MozTransition=objStyle.OTransition=objStyle.transition=transition}},_calcHeight:function(){for(var savedHeight=0,i=0;i<nav.inner.length;i++)savedHeight+=nav.inner[i].offsetHeight;var innerStyles="."+opts.jsClass+" ."+opts.navClass+"-"+this.index+".opened{max-height:"+savedHeight+"px !important} ."+opts.jsClass+" ."+opts.navClass+"-"+this.index+".opened.dropdown-active {max-height:9999px !important}";styleElement.styleSheet?styleElement.styleSheet.cssText=innerStyles:styleElement.innerHTML=innerStyles,innerStyles=""}},new ResponsiveNav(el,options)};"undefined"!=typeof module&&module.exports?module.exports=responsiveNav:window.responsiveNav=responsiveNav}(document,window,0),$("html").toggleClass("no-js js"),$(document).ready(function(){function isNarrowScreen(){var size=window.getComputedStyle(document.body,":after").getPropertyValue("content");return-1==size.indexOf("smallscreen")&&-1==size.indexOf("mediumscreen")&&-1==size.indexOf("widescreen")}function closeModal(){$("#overlayer").fadeOut(300,function(){$(this).remove()}),$("#dim").remove()}$("td.actions form").each(function(){$(this).after('Delete')}),$(".delete").click(function(){$("td.actions a").css("visibility","hidden");var formname="#"+$(this).data("formname"),cells=$("table tr:nth-child(2) td").length;return $(this).parent().parent().addClass("delete_selected").after('
Do you really want to delete this? No Yes
'),$("#confirm_delete").click(function(){var formid=$(this).data("form");return $(formid).submit(),!1}),$("#cancel_delete").click(function(){$("#delete_choices").remove(),$("tr.delete_selected").removeClass("delete_selected"),$("td.actions a").removeAttr("style")}),!1});var success=$(".message");success.length&&(success.animate({opacity:1},2e3).fadeOut(),success.fadeOut(3e3));var nav=responsiveNav(".nav-collapse",{open:function(){var subnav=$(".sub-nav");subnav.is(":visible")&&subnav.hide()}});window.getComputedStyle,$(".parent").click(function(e){$(".sub-nav").slideToggle(200),isNarrowScreen()&&nav.close()}).find(".sub-nav a").click(function(e){e.stopPropagation()}),$(document).click(function(e){var subnav=$(".sub-nav");$(e.target).closest(".parent").length||subnav.is(":visible")&&subnav.slideUp()}),$(".hijax").on("click",function(e){if(!1===isNarrowScreen()){$("#loading").remove(),$("#dim").remove(),$(e.target).prepend('

'),$("body").prepend('

');var modal=$("#overlayer");return $(modal.length)&&modal.remove(),$(".main").prepend('
X

'),$("#mcontent").load($(e.target).attr("href"),function(){$("#overlayer").css({display:"none",visibility:"visible"}),$("#loading").remove(),$("#overlayer").fadeIn(300),$("#number-booked").length&&$("#number-booked").focus()}),!1}}),$(document).on("click","body",function(e){if($("#overlayer").length){var clicked=$(e.target);return clicked.is("#mcontent")||clicked.parents().is("#mcontent")?void 0:(closeModal(),!1)}}),$(document).on("click","#overlayer a.close",function(){return closeModal(),!1}),$(document).keyup(function(e){if(27==e.keyCode)return closeModal(),!1})});<commit_msg>update file.<commit_after>!function(document,window,index){"use strict";var responsiveNav=function(el,options){!!window.getComputedStyle||(window.getComputedStyle=function(el){return this.el=el,this.getPropertyValue=function(prop){var re=/(\-([a-z]){1})/g;return"float"===prop&&(prop="styleFloat"),re.test(prop)&&(prop=prop.replace(re,function(){return arguments[2].toUpperCase()})),el.currentStyle[prop]?el.currentStyle[prop]:null},this});var nav,opts,navToggle,hasAnimFinished,isMobile,navOpen,addEvent=function(el,evt,fn,bubble){if("addEventListener"in el)try{el.addEventListener(evt,fn,bubble)}catch(e){if("object"!=typeof fn||!fn.handleEvent)throw e;el.addEventListener(evt,function(e){fn.handleEvent.call(fn,e)},bubble)}else"attachEvent"in el&&("object"==typeof fn&&fn.handleEvent?el.attachEvent("on"+evt,function(){fn.handleEvent.call(fn)}):el.attachEvent("on"+evt,fn))},removeEvent=function(el,evt,fn,bubble){if("removeEventListener"in el)try{el.removeEventListener(evt,fn,bubble)}catch(e){if("object"!=typeof fn||!fn.handleEvent)throw e;el.removeEventListener(evt,function(e){fn.handleEvent.call(fn,e)},bubble)}else"detachEvent"in el&&("object"==typeof fn&&fn.handleEvent?el.detachEvent("on"+evt,function(){fn.handleEvent.call(fn)}):el.detachEvent("on"+evt,fn))},getChildren=function(e){if(e.children.length<1)throw new Error("The Nav container has no containing elements");for(var children=[],i=0;i<e.children.length;i++)1===e.children[i].nodeType&&children.push(e.children[i]);return children},setAttributes=function(el,attrs){for(var key in attrs)el.setAttribute(key,attrs[key])},addClass=function(el,cls){0!==el.className.indexOf(cls)&&(el.className+=" "+cls,el.className=el.className.replace(/(^\s*)|(\s*$)/g,""))},removeClass=function(el,cls){var reg=new RegExp("(\\s|^)"+cls+"(\\s|$)");el.className=el.className.replace(reg," ").replace(/(^\s*)|(\s*$)/g,"")},forEach=function(array,callback,scope){for(var i=0;i<array.length;i++)callback.call(scope,i,array[i])},styleElement=document.createElement("style"),htmlEl=document.documentElement,ResponsiveNav=function(el,options){var i;this.options={animate:!0,transition:284,label:"Menu",insert:"before",customToggle:"",closeOnNavClick:!1,openPos:"relative",navClass:"nav-collapse",navActiveClass:"js-nav-active",jsClass:"js",init:function(){},open:function(){},close:function(){}};for(i in options)this.options[i]=options[i];if(addClass(htmlEl,this.options.jsClass),this.wrapperEl=el.replace("#",""),document.getElementById(this.wrapperEl))this.wrapper=document.getElementById(this.wrapperEl);else{if(!document.querySelector(this.wrapperEl))throw new Error("The nav element you are trying to select doesn't exist");this.wrapper=document.querySelector(this.wrapperEl)}this.wrapper.inner=getChildren(this.wrapper),opts=this.options,nav=this.wrapper,this._init(this)};return ResponsiveNav.prototype={destroy:function(){this._removeStyles(),removeClass(nav,"closed"),removeClass(nav,"opened"),removeClass(nav,opts.navClass),removeClass(nav,opts.navClass+"-"+this.index),removeClass(htmlEl,opts.navActiveClass),nav.removeAttribute("style"),nav.removeAttribute("aria-hidden"),removeEvent(window,"resize",this,!1),removeEvent(window,"focus",this,!1),removeEvent(document.body,"touchmove",this,!1),removeEvent(navToggle,"touchstart",this,!1),removeEvent(navToggle,"touchend",this,!1),removeEvent(navToggle,"mouseup",this,!1),removeEvent(navToggle,"keyup",this,!1),removeEvent(navToggle,"click",this,!1),opts.customToggle?navToggle.removeAttribute("aria-hidden"):navToggle.parentNode.removeChild(navToggle)},toggle:function(){!0===hasAnimFinished&&(navOpen?this.close():this.open())},open:function(){navOpen||(removeClass(nav,"closed"),addClass(nav,"opened"),addClass(htmlEl,opts.navActiveClass),addClass(navToggle,"active"),nav.style.position=opts.openPos,setAttributes(nav,{"aria-hidden":"false"}),navOpen=!0,opts.open())},close:function(){navOpen&&(addClass(nav,"closed"),removeClass(nav,"opened"),removeClass(htmlEl,opts.navActiveClass),removeClass(navToggle,"active"),setAttributes(nav,{"aria-hidden":"true"}),opts.animate?(hasAnimFinished=!1,setTimeout(function(){nav.style.position="absolute",hasAnimFinished=!0},opts.transition+10)):nav.style.position="absolute",navOpen=!1,opts.close())},resize:function(){"none"!==window.getComputedStyle(navToggle,null).getPropertyValue("display")?(isMobile=!0,setAttributes(navToggle,{"aria-hidden":"false"}),nav.className.match(/(^|\s)closed(\s|$)/)&&(setAttributes(nav,{"aria-hidden":"true"}),nav.style.position="absolute"),this._createStyles(),this._calcHeight()):(isMobile=!1,setAttributes(navToggle,{"aria-hidden":"true"}),setAttributes(nav,{"aria-hidden":"false"}),nav.style.position=opts.openPos,this._removeStyles())},handleEvent:function(e){var evt=e||window.event;switch(evt.type){case"touchstart":this._onTouchStart(evt);break;case"touchmove":this._onTouchMove(evt);break;case"touchend":case"mouseup":this._onTouchEnd(evt);break;case"click":this._preventDefault(evt);break;case"keyup":this._onKeyUp(evt);break;case"focus":case"resize":this.resize(evt)}},_init:function(){this.index=index++,addClass(nav,opts.navClass),addClass(nav,opts.navClass+"-"+this.index),addClass(nav,"closed"),hasAnimFinished=!0,navOpen=!1,this._closeOnNavClick(),this._createToggle(),this._transitions(),this.resize();var self=this;setTimeout(function(){self.resize()},20),addEvent(window,"resize",this,!1),addEvent(window,"focus",this,!1),addEvent(document.body,"touchmove",this,!1),addEvent(navToggle,"touchstart",this,!1),addEvent(navToggle,"touchend",this,!1),addEvent(navToggle,"mouseup",this,!1),addEvent(navToggle,"keyup",this,!1),addEvent(navToggle,"click",this,!1),opts.init()},_createStyles:function(){styleElement.parentNode||(styleElement.type="text/css",document.getElementsByTagName("head")[0].appendChild(styleElement))},_removeStyles:function(){styleElement.parentNode&&styleElement.parentNode.removeChild(styleElement)},_createToggle:function(){if(opts.customToggle){var toggleEl=opts.customToggle.replace("#","");if(document.getElementById(toggleEl))navToggle=document.getElementById(toggleEl);else{if(!document.querySelector(toggleEl))throw new Error("The custom nav toggle you are trying to select doesn't exist");navToggle=document.querySelector(toggleEl)}}else{var toggle=document.createElement("a");toggle.innerHTML=opts.label,setAttributes(toggle,{href:"#",class:"nav-toggle"}),"after"===opts.insert?nav.parentNode.insertBefore(toggle,nav.nextSibling):nav.parentNode.insertBefore(toggle,nav),navToggle=toggle}},_closeOnNavClick:function(){if(opts.closeOnNavClick){var links=nav.getElementsByTagName("a"),self=this;forEach(links,function(i,el){addEvent(links[i],"click",function(){isMobile&&self.toggle()},!1)})}},_preventDefault:function(e){if(e.preventDefault)return e.stopImmediatePropagation&&e.stopImmediatePropagation(),e.preventDefault(),e.stopPropagation(),!1;e.returnValue=!1},_onTouchStart:function(e){Event.prototype.stopImmediatePropagation||this._preventDefault(e),this.startX=e.touches[0].clientX,this.startY=e.touches[0].clientY,this.touchHasMoved=!1,removeEvent(navToggle,"mouseup",this,!1)},_onTouchMove:function(e){(Math.abs(e.touches[0].clientX-this.startX)>10||Math.abs(e.touches[0].clientY-this.startY)>10)&&(this.touchHasMoved=!0)},_onTouchEnd:function(e){if(this._preventDefault(e),isMobile&&!this.touchHasMoved){if("touchend"===e.type)return void this.toggle();var evt=e||window.event;3!==evt.which&&2!==evt.button&&this.toggle()}},_onKeyUp:function(e){13===(e||window.event).keyCode&&this.toggle()},_transitions:function(){if(opts.animate){var objStyle=nav.style,transition="max-height "+opts.transition+"ms";objStyle.WebkitTransition=objStyle.MozTransition=objStyle.OTransition=objStyle.transition=transition}},_calcHeight:function(){for(var savedHeight=0,i=0;i<nav.inner.length;i++)savedHeight+=nav.inner[i].offsetHeight;var innerStyles="."+opts.jsClass+" ."+opts.navClass+"-"+this.index+".opened{max-height:"+savedHeight+"px !important} ."+opts.jsClass+" ."+opts.navClass+"-"+this.index+".opened.dropdown-active {max-height:9999px !important}";styleElement.styleSheet?styleElement.styleSheet.cssText=innerStyles:styleElement.innerHTML=innerStyles,innerStyles=""}},new ResponsiveNav(el,options)};"undefined"!=typeof module&&module.exports?module.exports=responsiveNav:window.responsiveNav=responsiveNav}(document,window,0),$("html").toggleClass("no-js js"),$(document).ready(function(){function isNarrowScreen(){var size=window.getComputedStyle(document.body,":after").getPropertyValue("content");return-1==size.indexOf("smallscreen")&&-1==size.indexOf("mediumscreen")&&-1==size.indexOf("widescreen")}function closeModal(){$("#overlayer").fadeOut(300,function(){$(this).remove()}),$("#dim").remove()}$("td.actions form").each(function(){$(this).after('Delete')}),$(".delete").click(function(){$("td.actions a").css("visibility","hidden");var formname="#"+$(this).data("formname"),cells=$("table tr:nth-child(2) td").length;return $(this).parent().parent().addClass("delete_selected").after('
Do you really want to delete this? No Yes
'),$("#confirm_delete").click(function(){var formid=$(this).data("form");return $(formid).submit(),!1}),$("#cancel_delete").click(function(){$("#delete_choices").remove(),$("tr.delete_selected").removeClass("delete_selected"),$("td.actions a").removeAttr("style")}),!1});var success=$(".message");success.length&&(success.animate({opacity:1},2e3).fadeOut(),success.fadeOut(3e3));var nav=responsiveNav(".nav-collapse",{open:function(){var subnav=$(".sub-nav");subnav.is(":visible")&&subnav.hide()}});window.getComputedStyle,$(".parent").click(function(e){$(".sub-nav").slideToggle(200),isNarrowScreen()&&nav.close()}).find(".sub-nav a").click(function(e){e.stopPropagation()}),$(document).click(function(e){var subnav=$(".sub-nav");$(e.target).closest(".parent").length||subnav.is(":visible")&&subnav.slideUp()}),$(".hijax").on("click",function(e){if(!1===isNarrowScreen()){$("#loading").remove(),$("#dim").remove(),$(e.target).prepend('

'),$("body").prepend('

');var modal=$("#overlayer");return $(modal.length)&&modal.remove(),$("main").prepend('
X

'),$("#mcontent").load($(e.target).attr("href"),function(){$("#overlayer").css({display:"none",visibility:"visible"}),$("#loading").remove(),$("#overlayer").fadeIn(300),$("#number-booked").length&&$("#number-booked").focus()}),!1}}),$(document).on("click","body",function(e){if($("#overlayer").length){var clicked=$(e.target);return clicked.is("#mcontent")||clicked.parents().is("#mcontent")?void 0:(closeModal(),!1)}}),$(document).on("click","#overlayer a.close",function(){return closeModal(),!1}),$(document).keyup(function(e){if(27==e.keyCode)return closeModal(),!1})});<|endoftext|>


<commit_before>(function($) {
    var months = new Array(12);
    months[0] = "January";
    months[1] = "February";
    months[2] = "March";
    months[3] = "April";
    months[4] = "May";
    months[5] = "June";
    months[6] = "July";
    months[7] = "August";
    months[8] = "September";
    months[9] = "October";
    months[10] = "November";
    months[11] = "December";

    var form = $('#form-cart');
    if(!form.length)
        return;

    function setup_period_range(e) {
        var days = Number(e.attr('data-steps'));

        var period_start = new Date(e.parent().parent().attr('data-period-start'));
        var label = e.prevAll('p');

        function format_date(d) {
            return d.getDate() + ' ' + months[d.getMonth()];
        }
        function set_label(values) {
            if(!values) {
                values = e.slider('values');
            }
            var txt = "from ";
            var d = new Date(period_start);
            d.setDate(d.getDate() + values[0]);
            txt += format_date(d) + " to ";
            d.setDate(d.getDate() + (values[1]-values[0]));
            txt += format_date(d);
            label.text(txt);
        }
        /*
         * questi sono gli input da mantenere sincronizzati con i valore dello
         * slider
         */
        var inputs = $('input[type=hidden]', e.parent());
        /*
         * questa funzione viene chiamata anche su elementi clonati dove è già
         * presente il markup dello slider; la chiamata .html('') anche se poco
         * elegante mi permette di fare tabula rasa e ripartire da zero.
         */
        function cap_values(slider, handle, values) {
            var hix = handle.data('index.uiSliderHandle');
            var max = slider.slider('option', 'max');
            var min = slider.slider('option', 'min');
            if(hix == 1) {
                values = [ values[1] - 3, values[1] ];
            }
            else {
                values = [ values[0], values[0] + 3 ];
            }
            if(values[0] <= min) {
                values[0] = min;
                values[1] = min + 3;
            }
            else if(values[1] >= max) {
                values[0] = max - 3;
                values[1] = max;
            }
            return values;
        }
        e.html('').slider({
            range: true,
            min: 0,
            max: days,
            values: [ Number(inputs.eq(0).val()), Number(inputs.eq(1).val())],
            slide: function(evt, ui) {
                var values = ui.values;
                var diff = values[1] - values[0];
                if(diff < 3) {
                    var w = $(this);
                    w.slider('values', cap_values(w, $(ui.handle), values));
                }
                else {
                    set_label(values);
                    inputs.eq(0).val(values[0]);
                    inputs.eq(1).val(values[1]);
                    $('input[type=text]', e.parent().next()).change();
                }
            },
            change: function(evt, ui) {
                if(!evt.originalEvent)
                    return;
                var w = $(this);
                var values = ui.values;
                var diff = values[1] - values[0];
                if(diff < 3) {
                    values = cap_values(w, $(ui.handle), values);
                    w.slider('values', values);
                }
                set_label(values);
                inputs.eq(0).val(values[0]);
                inputs.eq(1).val(values[1]);
                $('input[type=text]', e.parent().next()).change();
            }
        });
        set_label();
    };

    function setup_reservation_rows(rows) {
        $(rows).each(function() {
            var reservation = $(this);
            $('.room-type select', reservation).change(function(e) {
                $('td[data-fare]', reservation).attr('data-fare', $('option:selected', this).val());
                $('input[type=text]', reservation).change();
            }).change();

            setup_period_range($('.period', reservation));
        });
    }

    setup_reservation_rows($('.hotel-reservation-type', form));

    $('.cart-hotel-another-reservation', form).click(function(e) {
        e.preventDefault();
        var type = $(this).attr('data-type');
        var rows = $('tr[data-reservation-type=' + type + ']', form);

        var orig = rows.eq(rows.length-1);
        var main = orig.clone();

        orig.parents('tbody')
            .append(main)

        setup_reservation_rows(main);
        setup_cart_input($('input', main));
    });

    function calcTotal() {

        form.ajaxSubmit({
            url: '/p3/cart/calculator/',
            dataType: 'json',
            success: function(data, text, jqHXR) {
                $('fieldset .total', form)
                    .data('total', 0)
                    .children('b')
                    .html('€ 0');

                /*
                 * data contiene il totale generale, lo sconto ottenuto tramite
                 * coupon e il dettaglio dei costi dei singoli biglietti
                 */
                var feedback = $('.coupon .cms span');
                feedback.text((data.coupon || 0 ) != 0 ? 'coupon accepted' : '');
                $('.coupon .total b', form).html('€ ' + (data.coupon || 0));
                $('.grand.total b', form).html('€ ' + (data.total || 0));
                $('.hotel-reservations td[data-fare]', form).next().html('');
                $('.hotel-reservations tr').removeClass('error');
                $('.hotel-reservations tr .errors').html('');

                if(typeof(data.total) == "undefined") {
                    /* la validazione della form passata ha ritornato un errore,
                     * devo mostrare i messaggi accanto ai campi corrispondenti
                     */

                    /* XXX: in teoria qualunque campo della form potrebbe avere
                     * problemi di validazione, in pratica solo quelli relativi
                     * alle prenotazioni alberghiere.
                     */

                    function hotel_row_error(type, ix, msg) {
                        var row = $('tr[data-reservation-type=' + type + ']', form)
                            .eq(ix)
                            .addClass('error');
                        var fare_cell = $('td[data-fare]', row);
                        var feedback = $('.errors', fare_cell);
                        if(feedback.length) {
                            feedback.html(msg);
                        }
                        else {
                            $('

')
                                .appendTo(fare_cell)
                                .html(msg);
                        }
                    }
                    for(var fname in data) {
                        switch(fname) {
                            case 'bed_reservations':
                            case 'room_reservations':
                                var type = fname.split('_')[0];
                                for(var ix=0; ix<data[fname].length; ix++) {
                                    var p = data[fname][ix].split(':');
                                    hotel_row_error(type, p[0], p[1]);
                                }
                                break;
                            case '__all__':
                                break;
                            default:
                                // ops qualcosa di inatteso
                                throw("invalid field");
                                break;
                        }
                    }
                    return;
                }
                /*
                 * ...il problema con i costi dei singoli biglietti è quello di
                 * mostrare per ogni prenotazione alberghiera il prezzo
                 * corrispondente.
                 * Il prezzo degli altri biglietti non varia con i parametri
                 * inseriti dall'utente, ad esempio non abbiamo lo sconto
                 * quantità, quindi posso mostrare il prezzo del singolo
                 * biglietto in anticipo inserendolo nell'html. Con le
                 * prenotazioni alberghiere invece il prezzo varia sia con il
                 * tipo di camera (ma qui sono fare diverse è la nostra UI che
                 * le vuol far vedere su una singola riga) sia con il periodo
                 * di pernottamento, inoltre possiamo avere più biglietti dello
                 * stesso tipo ma con periodi diversi (ad esempio potrei voler
                 * prenotare 1 biglietto HB3 per le date X e Y e 1 biglietto
                 * sempre HB3 ma per le date X' e Y')
                 */
                function update_total(parent, value) {
                    var e = $('.total', parent);
                    var total = e.data('total') + Number(value);
                    e.data('total', total);
                    e.children('b').html('€ ' + total.toFixed(2));
                }
                $(data.tickets).each(function() {
                    var code = this[0];
                    var params = this[1];
                    var total = this[2];
                    /*
                     * per tutti i biglietti, ad eccezioni delle prenotazioni
                     * alberghiere, posso limitarmi ad aggiungere il valore nel
                     * totale di sezione (identificato con la prima lettera del
                     * codice tariffa)...
                     */
                    var group = '';
                    switch(code.substr(0, 1)) {
                        case 'H':
                            if(code.length == 3)
                                group = 'H';
                            break;
                        case 'T':
                            if(code.length == 4)
                                group = 'T';
                            break;
                        case 'P':
                            group = 'P';
                            break;
                    }
                    switch(group) {
                        case 'H':
                            /*
                             * ...ma per le tariffe alberghiere devo anche
                             * mostrare il valore del biglietto nella riga
                             * corrispondente. E non basta usare il codice
                             * tariffa, devo fare anche il match con il periodo
                             */
                            $('.hotel-reservations td[data-fare=' + code + ']', form).each(function() {
                                var qty = $(this);
                                if($('input[type=text]', qty).val() == params.qty) {
                                    // ho trovato un input con la stessa quantità e
                                    // lo stesso codice tariffa, ora devo
                                    // controllare il periodo
                                    var period = $('.period', qty.prev()).slider('values');
                                    if(params.period[0] == period[0] && params.period[1] == period[1]) {
                                        // trovato!
                                        var price = qty.next();
                                        price.html('€ ' + total);
                                        update_total(price.parents('.hotel-reservations'), total);
                                    }
                                }
                            });
                            break;
                        case 'T':
                            update_total($('.conference-tickets', form), total);
                            break;
                        case 'P':
                            update_total($('.partner-program', form), total);
                            break;
                        default:
                            update_total($('.other-goodies', form), total);
                            break;
                    }
                });
            }
        });
    }
    function setup_cart_input(inputs) {
        inputs
            .change(calcTotal)
            .not('[name=coupon]')
            .keypress(function(e) {
                if((e.which < 48 || e.which > 57) && e.which != 13 && e.which != 0 && e.which != 8) {
                    e.preventDefault()
                }
            });
    }
    setup_cart_input($('input', form));

    function _enableFares(personal) {
        $('.conference-tickets td.fare', form).each(function() {
            var td = $(this);
            var fare_code = td.attr('data-fare');
            var e = ((fare_code.substr(3, 1) == 'C' && !personal) || (fare_code.substr(3, 1) != 'C' && personal));
            var inputs = $('input', td);
            if(e) {
                td.removeClass('disabled');
                inputs.attr('disabled', false);
            }
            else {
                td.addClass('disabled');
                inputs.attr('disabled', true);
            }
        });
    }
    $('#id_order_type').change(function() {
        _enableFares($(this).val() != 'deductible');
        calcTotal();
    });

    if(document.location.search.substr(0, 3) == '?f=') {
        var highligh_fare = document.location.search.substr(3);
        var i = $('td[data-fare=' + highligh_fare + '] input');
        if(!i.val())
            i.val(1);
        i.addClass('selected')
            .focus()
            .parents('tr')
            .addClass('selected');
        i.eq(0)[0].scrollIntoView();
    }

    $('#id_order_type').change();
})(jQuery);
<commit_msg>gestisco gli errori di validazione del calcolo totali<commit_after>(function($) {
    var months = new Array(12);
    months[0] = "January";
    months[1] = "February";
    months[2] = "March";
    months[3] = "April";
    months[4] = "May";
    months[5] = "June";
    months[6] = "July";
    months[7] = "August";
    months[8] = "September";
    months[9] = "October";
    months[10] = "November";
    months[11] = "December";

    var form = $('#form-cart');
    if(!form.length)
        return;

    function setup_period_range(e) {
        var days = Number(e.attr('data-steps'));

        var period_start = new Date(e.parent().parent().attr('data-period-start'));
        var label = e.prevAll('p');

        function format_date(d) {
            return d.getDate() + ' ' + months[d.getMonth()];
        }
        function set_label(values) {
            if(!values) {
                values = e.slider('values');
            }
            var txt = "from ";
            var d = new Date(period_start);
            d.setDate(d.getDate() + values[0]);
            txt += format_date(d) + " to ";
            d.setDate(d.getDate() + (values[1]-values[0]));
            txt += format_date(d);
            label.text(txt);
        }
        /*
         * questi sono gli input da mantenere sincronizzati con i valore dello
         * slider
         */
        var inputs = $('input[type=hidden]', e.parent());
        /*
         * questa funzione viene chiamata anche su elementi clonati dove è già
         * presente il markup dello slider; la chiamata .html('') anche se poco
         * elegante mi permette di fare tabula rasa e ripartire da zero.
         */
        function cap_values(slider, handle, values) {
            var hix = handle.data('index.uiSliderHandle');
            var max = slider.slider('option', 'max');
            var min = slider.slider('option', 'min');
            if(hix == 1) {
                values = [ values[1] - 3, values[1] ];
            }
            else {
                values = [ values[0], values[0] + 3 ];
            }
            if(values[0] <= min) {
                values[0] = min;
                values[1] = min + 3;
            }
            else if(values[1] >= max) {
                values[0] = max - 3;
                values[1] = max;
            }
            return values;
        }
        e.html('').slider({
            range: true,
            min: 0,
            max: days,
            values: [ Number(inputs.eq(0).val()), Number(inputs.eq(1).val())],
            slide: function(evt, ui) {
                var values = ui.values;
                var diff = values[1] - values[0];
                if(diff < 3) {
                    var w = $(this);
                    w.slider('values', cap_values(w, $(ui.handle), values));
                }
                else {
                    set_label(values);
                    inputs.eq(0).val(values[0]);
                    inputs.eq(1).val(values[1]);
                    $('input[type=text]', e.parent().next()).change();
                }
            },
            change: function(evt, ui) {
                if(!evt.originalEvent)
                    return;
                var w = $(this);
                var values = ui.values;
                var diff = values[1] - values[0];
                if(diff < 3) {
                    values = cap_values(w, $(ui.handle), values);
                    w.slider('values', values);
                }
                set_label(values);
                inputs.eq(0).val(values[0]);
                inputs.eq(1).val(values[1]);
                $('input[type=text]', e.parent().next()).change();
            }
        });
        set_label();
    };

    function setup_reservation_rows(rows) {
        $(rows).each(function() {
            var reservation = $(this);
            $('.room-type select', reservation).change(function(e) {
                $('td[data-fare]', reservation).attr('data-fare', $('option:selected', this).val());
                $('input[type=text]', reservation).change();
            }).change();

            setup_period_range($('.period', reservation));
        });
    }

    setup_reservation_rows($('.hotel-reservation-type', form));

    $('.cart-hotel-another-reservation', form).click(function(e) {
        e.preventDefault();
        var type = $(this).attr('data-type');
        var rows = $('tr[data-reservation-type=' + type + ']', form);

        var orig = rows.eq(rows.length-1);
        var main = orig.clone();

        orig.parents('tbody')
            .append(main)

        setup_reservation_rows(main);
        setup_cart_input($('input', main));
    });

    function calcTotal() {

        function _clearTotals() {
            $('fieldset .total', form)
                .data('total', 0)
                .children('b')
                .html('€ 0');
        }

        form.ajaxSubmit({
            url: '/p3/cart/calculator/',
            dataType: 'json',
            success: function(data, text, jqHXR) {
                _clearTotals()

                /*
                 * data contiene il totale generale, lo sconto ottenuto tramite
                 * coupon e il dettaglio dei costi dei singoli biglietti
                 */
                var feedback = $('.coupon .cms span');
                feedback.text((data.coupon || 0 ) != 0 ? 'coupon accepted' : '');
                $('.coupon .total b', form).html('€ ' + (data.coupon || 0));
                $('.grand.total b', form).html('€ ' + (data.total || 0));
                $('.hotel-reservations td[data-fare]', form).next().html('');
                $('.hotel-reservations tr').removeClass('error');
                $('.hotel-reservations tr .errors').html('');

                /*
                 * ...il problema con i costi dei singoli biglietti è quello di
                 * mostrare per ogni prenotazione alberghiera il prezzo
                 * corrispondente.
                 * Il prezzo degli altri biglietti non varia con i parametri
                 * inseriti dall'utente, ad esempio non abbiamo lo sconto
                 * quantità, quindi posso mostrare il prezzo del singolo
                 * biglietto in anticipo inserendolo nell'html. Con le
                 * prenotazioni alberghiere invece il prezzo varia sia con il
                 * tipo di camera (ma qui sono fare diverse è la nostra UI che
                 * le vuol far vedere su una singola riga) sia con il periodo
                 * di pernottamento, inoltre possiamo avere più biglietti dello
                 * stesso tipo ma con periodi diversi (ad esempio potrei voler
                 * prenotare 1 biglietto HB3 per le date X e Y e 1 biglietto
                 * sempre HB3 ma per le date X' e Y')
                 */
                function update_total(parent, value) {
                    var e = $('.total', parent);
                    var total = e.data('total') + Number(value);
                    e.data('total', total);
                    e.children('b').html('€ ' + total.toFixed(2));
                }
                $(data.tickets).each(function() {
                    var code = this[0];
                    var params = this[1];
                    var total = this[2];
                    /*
                     * per tutti i biglietti, ad eccezioni delle prenotazioni
                     * alberghiere, posso limitarmi ad aggiungere il valore nel
                     * totale di sezione (identificato con la prima lettera del
                     * codice tariffa)...
                     */
                    var group = '';
                    switch(code.substr(0, 1)) {
                        case 'H':
                            if(code.length == 3)
                                group = 'H';
                            break;
                        case 'T':
                            if(code.length == 4)
                                group = 'T';
                            break;
                        case 'P':
                            group = 'P';
                            break;
                    }
                    switch(group) {
                        case 'H':
                            /*
                             * ...ma per le tariffe alberghiere devo anche
                             * mostrare il valore del biglietto nella riga
                             * corrispondente. E non basta usare il codice
                             * tariffa, devo fare anche il match con il periodo
                             */
                            $('.hotel-reservations td[data-fare=' + code + ']', form).each(function() {
                                var qty = $(this);
                                if($('input[type=text]', qty).val() == params.qty) {
                                    // ho trovato un input con la stessa quantità e
                                    // lo stesso codice tariffa, ora devo
                                    // controllare il periodo
                                    var period = $('.period', qty.prev()).slider('values');
                                    if(params.period[0] == period[0] && params.period[1] == period[1]) {
                                        // trovato!
                                        var price = qty.next();
                                        price.html('€ ' + total);
                                        update_total(price.parents('.hotel-reservations'), total);
                                    }
                                }
                            });
                            break;
                        case 'T':
                            update_total($('.conference-tickets', form), total);
                            break;
                        case 'P':
                            update_total($('.partner-program', form), total);
                            break;
                        default:
                            update_total($('.other-goodies', form), total);
                            break;
                    }
                });
            },
            error: function(response) {
                var err = null;
                if(response.status == 400) {
                    try {
                        err = JSON.parse(response.responseText);
                    }
                    catch(_) {
                    }
                }

                _clearTotals();
                if(err == null) {
                    alert(response.responseText);
                    return;
                }

                /* la validazione della form passata ha ritornato un errore,
                 * devo mostrare i messaggi accanto ai campi corrispondenti
                 */

                /* XXX: in teoria qualunque campo della form potrebbe avere
                 * problemi di validazione, in pratica solo quelli relativi
                 * alle prenotazioni alberghiere.
                 */

                function hotel_row_error(type, ix, msg) {
                    var row = $('tr[data-reservation-type=' + type + ']', form)
                        .eq(ix)
                        .addClass('error');
                    var fare_cell = $('td[data-fare]', row);
                    var feedback = $('.errors', fare_cell);
                    if(feedback.length) {
                        feedback.html(msg);
                    }
                    else {
                        $('

')
                            .appendTo(fare_cell)
                            .html(msg);
                    }
                }
                for(var fname in err) {
                    switch(fname) {
                        case 'bed_reservations':
                        case 'room_reservations':
                            var type = fname.split('_')[0];
                            for(var ix=0; ix<err[fname].length; ix++) {
                                var p = err[fname][ix].split(':');
                                hotel_row_error(type, p[0], p[1]);
                            }
                            break;
                        case '__all__':
                            break;
                        default:
                            // ops qualcosa di inatteso
                            throw("invalid field");
                            break;
                    }
                }
                return;
            }
        });
    }
    function setup_cart_input(inputs) {
        inputs
            .change(calcTotal)
            .not('[name=coupon]')
            .keypress(function(e) {
                if((e.which < 48 || e.which > 57) && e.which != 13 && e.which != 0 && e.which != 8) {
                    e.preventDefault()
                }
            });
    }
    setup_cart_input($('input', form));

    function _enableFares(personal) {
        $('.conference-tickets td.fare', form).each(function() {
            var td = $(this);
            var fare_code = td.attr('data-fare');
            var e = ((fare_code.substr(3, 1) == 'C' && !personal) || (fare_code.substr(3, 1) != 'C' && personal));
            var inputs = $('input', td);
            if(e) {
                td.removeClass('disabled');
                inputs.attr('disabled', false);
            }
            else {
                td.addClass('disabled');
                inputs.attr('disabled', true);
            }
        });
    }
    $('#id_order_type').change(function() {
        _enableFares($(this).val() != 'deductible');
        calcTotal();
    });

    if(document.location.search.substr(0, 3) == '?f=') {
        var highligh_fare = document.location.search.substr(3);
        var i = $('td[data-fare=' + highligh_fare + '] input');
        if(!i.val())
            i.val(1);
        i.addClass('selected')
            .focus()
            .parents('tr')
            .addClass('selected');
        i.eq(0)[0].scrollIntoView();
    }

    $('#id_order_type').change();
})(jQuery);
<|endoftext|>


<commit_before>// var colors = ["#8DBDC7","#FFE37F","#F0C271","#E3A368","#D18461"];
var colors = ["#0A87BF","#03657F","#00F2FF","#011940","#0781E5", "#BF09A1","#13207F","#E098FF","#120040","#A841E5"];
var titleArray1 = ["HACK","THIS","MUSIC","NOW!"];
var titleArray2 = ["MEDIA HACKATHON","Zat. 15/03","AB BRUSSEL","-> Inschrijven! <-"];
var hasStarted = false;
var interval = 0;
var currentSequence = 0;
var altSequence = 0;
var context;
var bufferLoader;
var leftArray = [false,false,false,false];
var middleArray = [false,false,false,false];
var rightArray = [false,false,false,false];
var startTime;
var tempo = 80; // BPM (beats per minute)
var eighthNoteTime = (60 / tempo) / 2;
var bufferList;
var sources = [];
var gains = [];
var backPLaying = false;
var gainNode1;
var gainNode2;

function init(){
	initSound();
	initMotionsound();
	initClickHandlers();

	$("#flow-sequencer").css("height",$(".sequence-left-group > .sequence").height()  +30);
	interval = setInterval("sequenceTick();", 458);

	//fastclick for mobile devices:
	FastClick.attach(document.body);
}

function initClickHandlers () {

	$(".sequence-group > .sequence").click(function(event){
		event.preventDefault();
		if($(this).hasClass("sequence-left")||$(this).hasClass("sequence-left-off")){
			//left
			$(this).toggleClass("sequence-left");
			$(this).toggleClass("sequence-left-off");
		}else if($(this).hasClass("sequence-middle")||$(this).hasClass("sequence-middle-off")){
			//MIDDLE
			$(this).toggleClass("sequence-middle");
			$(this).toggleClass("sequence-middle-off");
		}else if($(this).hasClass("sequence-right")||$(this).hasClass("sequence-right-off")){
			//RIGHT
			$(this).toggleClass("sequence-right");
			$(this).toggleClass("sequence-right-off");
		}
		updateSequenceArrays();

		// CHECK for start
		if(!hasStarted){
			// $(".title > h2").text(titleArray[currentSequence]);
			$(".title").css("background-image", "url(/img/gear.png)");
			playSound(bufferList[0],0);
			$(".title-container > span").css("font-size","10vw");
			$(".title-container > span").text(titleArray2[0]);
			// interval = setInterval("sequenceTick();", 400);
			hasStarted = true;
		}

		return false;
	});

	$(".title").click(function(event){
		event.preventDefault();
		$(".title").hide();

		return false;
	});

	/*$("#helmet-left").click(function(event){
		if(hasStarted){
			activeBlocks--;
			if(activeBlocks<0)
				activeBlocks = 0;
			// console.log("helmet left");
			$(".sequence-container").css("left", activeBlocks*-50 +"%");
		}
	});

	$("#helmet-right").click(function(event){
		if(hasStarted){
			activeBlocks++;
			if(activeBlocks==4)
				activeBlocks = 3;
			// console.log("helmet right");
			$(".sequence-container").css("left", activeBlocks*-50 +"%");
		}
	});*/
}

function updateSequenceArrays(){
	$(".sequence-left-group > .sequence").each(function(i,el){
		leftArray[i] = $(el).hasClass("sequence-left");
	});
	$(".sequence-middle-group > .sequence").each(function(i,el){
		middleArray[i] = $(el).hasClass("sequence-middle");
	});
	$(".sequence-right-group > .sequence").each(function(i,el){
		rightArray[i] = $(el).hasClass("sequence-right");
	});
}
function updateMiddleArray(){
	$(".sequence-middle-group > .sequence").each(function(i,el){
		middleArray[i] = $(el).hasClass("sequence-middle");
	})
}
function updateRightArray(){
	$(".sequence-right-group > .sequence").each(function(i,el){
		rightArray[i] = $(el).hasClass("sequence-right");
	})
}

function sequenceTick(){
	if(currentSequence==3){
		currentSequence = 0;
		$("#flow-sequencer").css("height",$(".sequence-left-group > .sequence").height()  +30);
		if(hasStarted){
			if(!backPLaying){
				initBackSound1();
				initBackSound2();
				backPLaying = true;
			}
		}

	}else{
		currentSequence ++;
	}
	$("body").css("background-color","rgb("+(Math.floor(Math.random()*128))+","+(Math.floor(Math.random()*64))+","+(Math.floor(Math.random()*128)+128)+")");

	var top = parseInt($("#flow-sequencer").css("top"), 10);
	// console.log("rgb("+(Math.floor(Math.random()*128))+","+(Math.floor(Math.random()*64))+","+(Math.floor(Math.random()*255))+")");
	$("#flow-sequencer").css("top",currentSequence*$("#flow-sequencer").height() +5);
	// $("body").css("background-color",colors[Math.floor(Math.random()*colors.length)]);

	if(!hasStarted){
		$(".title-container > span").text(titleArray1[currentSequence]);

	}else{
		$(".title-container > span").text(titleArray2[currentSequence]);
	}
	// console.log(leftArray);
	// console.log(middleArray);
	// console.log(rightArray);

	if(leftArray[(currentSequence + 1) % 4])
		playSound(bufferList[0],startTime);
	if(middleArray[currentSequence])
		playSound(bufferList[1],startTime);
	if(rightArray[currentSequence])
		playSound(bufferList[2],startTime);
}

function initSound() {
  // Fix up prefixing
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  context = new AudioContext();

  bufferLoader = new BufferLoader(
    context,
    [
      '/sounds/original/Snare.wav',
      '/sounds/original/Hihat.wav',
      '/sounds/original/Kick.wav',
      '/sounds/original/Bassline.wav',
      '/sounds/original/sequencer2.wav',
    ],
    finishedLoading
    );

  bufferLoader.load();
  startTime = context.currentTime + 0.0100;
}

function initBackSound1(){
	var source = context.createBufferSource();
	source.buffer = bufferList[3];
	source.loop = true;
	gainNode1 = context.createGainNode();
	source.connect(gainNode1);
	gainNode1.connect(context.destination);
	if (!source.start)
	  source.start = source.noteOn;
	source.start(startTime);
}

function initBackSound2(){
	var source = context.createBufferSource();
	source.buffer = bufferList[4];
	source.loop = true;
	gainNode2 = context.createGainNode();
	source.connect(gainNode2);
	gainNode2.connect(context.destination);
	if (!source.start)
	  source.start = source.noteOn;
	source.start(startTime+0.24);
}

function finishedLoading(_bufferList) {
	bufferList = _bufferList;
}

function playSound(buffer, time) {
	var source = context.createBufferSource();
	source.buffer = buffer;
	source.connect(context.destination);
	if (!source.start)
	  source.start = source.noteOn;
	source.start(time);
}

function initMotionsound () {
	var motionsound = new Motionsound({
		onLeftVolumeChanged: leftVolumeChanged,
		onRightVolumeChanged: rightVolumeChanged
	});
	motionsound.init();
}

function leftVolumeChanged(value){
	// value is een waarde tussen 0 en 1
	// konsole.log( 'left volume: ' + Math.round(value*100)/100 );

	if(gainNode2){
		gainNode2.gain.value = value;
	}
}

function rightVolumeChanged(value){
	// value is een waarde tussen 0 en 1
	// konsole.log( 'right volume: ' + Math.round(value*100)/100 );

	if(gainNode2){
		gainNode2.gain.value = value;
	}
}

window.onload = init;

<commit_msg>tweede sequencer er ook in<commit_after>// var colors = ["#8DBDC7","#FFE37F","#F0C271","#E3A368","#D18461"];
var colors = ["#0A87BF","#03657F","#00F2FF","#011940","#0781E5", "#BF09A1","#13207F","#E098FF","#120040","#A841E5"];
var titleArray1 = ["HACK","THIS","MUSIC","NOW!"];
var titleArray2 = ["MEDIA HACKATHON","Zat. 15/03","AB BRUSSEL","-> Inschrijven! <-"];
var hasStarted = false;
var interval = 0;
var currentSequence = 0;
var altSequence = 0;
var context;
var bufferLoader;
var leftArray = [false,false,false,false];
var middleArray = [false,false,false,false];
var rightArray = [false,false,false,false];
var startTime;
var tempo = 80; // BPM (beats per minute)
var eighthNoteTime = (60 / tempo) / 2;
var bufferList;
var sources = [];
var gains = [];
var backPLaying = false;
var gainNodeLeft;
var gainNodeRight;

function init(){
	initSound();
	initMotionsound();
	initClickHandlers();

	$("#flow-sequencer").css("height",$(".sequence-left-group > .sequence").height()  +30);
	interval = setInterval("sequenceTick();", 458);

	//fastclick for mobile devices:
	FastClick.attach(document.body);
}

function initClickHandlers () {

	$(".sequence-group > .sequence").click(function(event){
		event.preventDefault();
		if($(this).hasClass("sequence-left")||$(this).hasClass("sequence-left-off")){
			//left
			$(this).toggleClass("sequence-left");
			$(this).toggleClass("sequence-left-off");
		}else if($(this).hasClass("sequence-middle")||$(this).hasClass("sequence-middle-off")){
			//MIDDLE
			$(this).toggleClass("sequence-middle");
			$(this).toggleClass("sequence-middle-off");
		}else if($(this).hasClass("sequence-right")||$(this).hasClass("sequence-right-off")){
			//RIGHT
			$(this).toggleClass("sequence-right");
			$(this).toggleClass("sequence-right-off");
		}
		updateSequenceArrays();

		// CHECK for start
		if(!hasStarted){
			// $(".title > h2").text(titleArray[currentSequence]);
			$(".title").css("background-image", "url(/img/gear.png)");
			playSound(bufferList[0],0);
			$(".title-container > span").css("font-size","10vw");
			$(".title-container > span").text(titleArray2[0]);
			// interval = setInterval("sequenceTick();", 400);
			hasStarted = true;
		}

		return false;
	});

	$(".title").click(function(event){
		event.preventDefault();
		$(".title").hide();

		return false;
	});

	/*$("#helmet-left").click(function(event){
		if(hasStarted){
			activeBlocks--;
			if(activeBlocks<0)
				activeBlocks = 0;
			// console.log("helmet left");
			$(".sequence-container").css("left", activeBlocks*-50 +"%");
		}
	});

	$("#helmet-right").click(function(event){
		if(hasStarted){
			activeBlocks++;
			if(activeBlocks==4)
				activeBlocks = 3;
			// console.log("helmet right");
			$(".sequence-container").css("left", activeBlocks*-50 +"%");
		}
	});*/
}

function updateSequenceArrays(){
	$(".sequence-left-group > .sequence").each(function(i,el){
		leftArray[i] = $(el).hasClass("sequence-left");
	});
	$(".sequence-middle-group > .sequence").each(function(i,el){
		middleArray[i] = $(el).hasClass("sequence-middle");
	});
	$(".sequence-right-group > .sequence").each(function(i,el){
		rightArray[i] = $(el).hasClass("sequence-right");
	});
}
function updateMiddleArray(){
	$(".sequence-middle-group > .sequence").each(function(i,el){
		middleArray[i] = $(el).hasClass("sequence-middle");
	})
}
function updateRightArray(){
	$(".sequence-right-group > .sequence").each(function(i,el){
		rightArray[i] = $(el).hasClass("sequence-right");
	})
}

function sequenceTick(){
	if(currentSequence==3){
		currentSequence = 0;
		$("#flow-sequencer").css("height",$(".sequence-left-group > .sequence").height()  +30);
		if(hasStarted){
			if(!backPLaying){
				initBackSoundBassline();
				initBackSoundLeft();
				initBackSoundRight();
				backPLaying = true;
			}
		}

	}else{
		currentSequence ++;
	}
	$("body").css("background-color","rgb("+(Math.floor(Math.random()*128))+","+(Math.floor(Math.random()*64))+","+(Math.floor(Math.random()*128)+128)+")");

	var top = parseInt($("#flow-sequencer").css("top"), 10);
	// console.log("rgb("+(Math.floor(Math.random()*128))+","+(Math.floor(Math.random()*64))+","+(Math.floor(Math.random()*255))+")");
	$("#flow-sequencer").css("top",currentSequence*$("#flow-sequencer").height() +5);
	// $("body").css("background-color",colors[Math.floor(Math.random()*colors.length)]);

	if(!hasStarted){
		$(".title-container > span").text(titleArray1[currentSequence]);

	}else{
		$(".title-container > span").text(titleArray2[currentSequence]);
	}
	// console.log(leftArray);
	// console.log(middleArray);
	// console.log(rightArray);

	if(leftArray[(currentSequence + 1) % 4])
		playSound(bufferList[0],startTime);
	if(middleArray[currentSequence])
		playSound(bufferList[1],startTime);
	if(rightArray[currentSequence])
		playSound(bufferList[2],startTime);
}

function initSound() {
  // Fix up prefixing
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  context = new AudioContext();

  bufferLoader = new BufferLoader(
    context,
    [
      '/sounds/original/Snare.wav',
      '/sounds/original/Hihat.wav',
      '/sounds/original/Kick.wav',
      '/sounds/original/Bassline.wav',
      '/sounds/original/sequencer.wav',
      '/sounds/original/sequencer2.wav',
    ],
    finishedLoading
    );

  bufferLoader.load();
  startTime = context.currentTime + 0.0100;
}

function initBackSoundBassline(){
	var source = context.createBufferSource();
	source.buffer = bufferList[3];
	source.loop = true;
	source.connect(context.destination);
	if (!source.start)
	  source.start = source.noteOn;
	source.start(startTime);
}

function initBackSoundLeft(){
	var source = context.createBufferSource();
	source.buffer = bufferList[4];
	source.loop = true;
	gainNodeLeft = context.createGainNode();
	source.connect(gainNodeLeft);
	gainNodeLeft.connect(context.destination);
	if (!source.start)
	  source.start = source.noteOn;
	source.start(startTime);
}
function initBackSoundRight(){
	var source = context.createBufferSource();
	source.buffer = bufferList[5];
	source.loop = true;
	gainNodeRight = context.createGainNode();
	source.connect(gainNodeRight);
	gainNodeRight.connect(context.destination);
	if (!source.start)
	  source.start = source.noteOn;
	source.start(startTime);
}

function finishedLoading(_bufferList) {
	bufferList = _bufferList;
}

function playSound(buffer, time) {
	var source = context.createBufferSource();
	source.buffer = buffer;
	source.connect(context.destination);
	if (!source.start)
	  source.start = source.noteOn;
	source.start(time);
}

function initMotionsound () {
	var motionsound = new Motionsound({
		onLeftVolumeChanged: leftVolumeChanged,
		onRightVolumeChanged: rightVolumeChanged
	});
	motionsound.init();
}

function leftVolumeChanged(value){
	// value is een waarde tussen 0 en 1
	// konsole.log( 'left volume: ' + Math.round(value*100)/100 );

	if(gainNodeLeft){
		gainNodeLeft.gain.value = value;
	}
}

function rightVolumeChanged(value){
	// value is een waarde tussen 0 en 1
	// konsole.log( 'right volume: ' + Math.round(value*100)/100 );

	if(gainNodeRight){
		gainNodeRight.gain.value = value;
	}
}

window.onload = init;

<|endoftext|>


<commit_before>(function(){
    'use strict';

    /* global myApp */
    myApp.controller('AddCtrl', ['$q', 'notifier', '$location', '$rootScope', '$scope', '$window', '$routeParams', 'AppsService', 'UrlCleanup', function($q, notifier, $location, $rootScope, $scope, $window, $routeParams, AppsService, UrlCleanup) {
        $scope.editing = $routeParams.appId;
        var editingApp;

        $rootScope.appTitle = $scope.editing ? 'Edit App' : 'Add App';

        if ($scope.editing) {
            AppsService.getAppList().then(function(appList) {
                appList.forEach(function(app) {
                    if (app.appId == $scope.editing) {
                        editingApp = app;
                        $scope.editingApp = app;
                        $scope.appData = {
                            appId: app.appId,
                            appUrl: app.url,
                            installerType: app.type
                        };
                    }
                });
                if (!$scope.appData) {
                    var err = 'Could not find app to edit';
                    console.error(err);
                    notifier.error(err);
                }
            });
        } else {
            $scope.appData = {
                appUrl : '',
                installerType: 'serve'
            };
        }

        $scope.selectTemplate = function() {
            $scope.appData.appUrl = $scope.appData.serveTemplateValue;
        };

        $scope.addApp = function() {
            if ($scope.editing) {
                // Update the app, write them out, and return to the list.
                // We deliberately disallow changing the type, since that wouldn't work at all.
                var oldUrl = editingApp.url;
                editingApp.appId = $scope.appData.appId;
                editingApp.url = UrlCleanup($scope.appData.appUrl);
                var urlChanged = oldUrl != editingApp.url;
                var p = AppsService.editApp($scope.editing, editingApp).then(function() {
                    console.log('App edited');
                    notifier.success('App edited');
                    $location.path('/');
                });

                if (urlChanged) {
                    p.then(function() {
                        // If the URL changed, trigger an update.
                        return AppsService.updateApp(editingApp);
                    }).then(function() {
                        console.log('Updated app due to URL change');
                        notifier.success('Updated app due to URL change');
                    }, function(err) {
                        var msg = 'Failed to update app: ' + err.message;
                        console.error(msg);
                        notifier.error(msg);
                    });
                }
            } else {
                var serviceCall = AppsService.addApp($scope.appData.installerType, $scope.appData.appUrl);

                serviceCall.then(function(handler) {
                    console.log('App Added');
                    notifier.success('App Added');
                    $location.path('/');
                    return AppsService.updateApp(handler);
                }, function(error) {
                    console.error(error);
                    notifier.error('Unable to add application because: ' + error.message);
                });
            }
        };

        // True if the optional barcodescanner plugin is installed.
        $scope.qrEnabled = !!(cordova.plugins && cordova.plugins.barcodeScanner);

        // Scans a QR code, placing the URL into the currently selected of source and pattern.
        $scope.fetchQR = function() {
            var deferred = $q.defer();
            $window.cordova.plugins.barcodeScanner.scan(function(result) {
                if (!result || result.cancelled || !result.text) {
                    notifier.error('No QR code received.');
                    deferred.reject('No QR code received.');
                } else {
                    $scope.appData.appUrl = result.text;
                    notifier.success('QR code received');
                    deferred.resolve();
                }
            },
            function(error) {
                console.log('QR Error: ' + error);
                notifier.error('Error retrieving QR code: ' + error);
                deferred.reject(error);
            });
            return deferred.promise;
        };
    }]);
})();
<commit_msg>Fix addApp returning a promise in the middle of the promise chain (hid error messages)<commit_after>(function(){
    'use strict';

    /* global myApp */
    myApp.controller('AddCtrl', ['$q', 'notifier', '$location', '$rootScope', '$scope', '$window', '$routeParams', 'AppsService', 'UrlCleanup', function($q, notifier, $location, $rootScope, $scope, $window, $routeParams, AppsService, UrlCleanup) {
        $scope.editing = $routeParams.appId;
        var editingApp;

        $rootScope.appTitle = $scope.editing ? 'Edit App' : 'Add App';

        if ($scope.editing) {
            AppsService.getAppList().then(function(appList) {
                appList.forEach(function(app) {
                    if (app.appId == $scope.editing) {
                        editingApp = app;
                        $scope.editingApp = app;
                        $scope.appData = {
                            appId: app.appId,
                            appUrl: app.url,
                            installerType: app.type
                        };
                    }
                });
                if (!$scope.appData) {
                    var err = 'Could not find app to edit';
                    console.error(err);
                    notifier.error(err);
                }
            });
        } else {
            $scope.appData = {
                appUrl: '',
                installerType: 'serve'
            };
        }

        $scope.selectTemplate = function() {
            $scope.appData.appUrl = $scope.appData.serveTemplateValue;
        };

        $scope.addApp = function() {
            if ($scope.editing) {
                // Update the app, write them out, and return to the list.
                // We deliberately disallow changing the type, since that wouldn't work at all.
                var oldUrl = editingApp.url;
                editingApp.appId = $scope.appData.appId;
                editingApp.url = UrlCleanup($scope.appData.appUrl);
                var urlChanged = oldUrl != editingApp.url;
                var p = AppsService.editApp($scope.editing, editingApp).then(function() {
                    console.log('App edited');
                    notifier.success('App edited');
                    $location.path('/');
                });

                if (urlChanged) {
                    return p.then(function() {
                        // If the URL changed, trigger an update.
                        return AppsService.updateApp(editingApp);
                    }).then(function() {
                        console.log('Updated app due to URL change');
                        notifier.success('Updated app due to URL change');
                    }, function(err) {
                        var msg = 'Failed to update app: ' + err.message;
                        console.error(msg);
                        notifier.error(msg);
                    });
                }
                return p;
            }
            return AppsService.addApp($scope.appData.installerType, $scope.appData.appUrl)
            .then(function(handler) {
                console.log('App Added');
                notifier.success('App Added');
                $location.path('/');
                return AppsService.updateApp(handler);
            }, function(error) {
                console.error(error);
                notifier.error('Unable to add application because: ' + error.message);
            });
        };

        // True if the optional barcodescanner plugin is installed.
        $scope.qrEnabled = !!(cordova.plugins && cordova.plugins.barcodeScanner);

        // Scans a QR code, placing the URL into the currently selected of source and pattern.
        $scope.fetchQR = function() {
            var deferred = $q.defer();
            $window.cordova.plugins.barcodeScanner.scan(function(result) {
                if (!result || result.cancelled || !result.text) {
                    notifier.error('No QR code received.');
                    deferred.reject('No QR code received.');
                } else {
                    $scope.appData.appUrl = result.text;
                    notifier.success('QR code received');
                    deferred.resolve();
                }
            },
            function(error) {
                console.log('QR Error: ' + error);
                notifier.error('Error retrieving QR code: ' + error);
                deferred.reject(error);
            });
            return deferred.promise;
        };
    }]);
})();
<|endoftext|>


<commit_before>'use strict';

/**
 * UI controller.
 *
 * author: Michael Liao
 */
var
    _ = require('lodash'),
    api = require('../api'),
    db = require('../db'),
    md = require('../md'),
    auth = require('../auth'),
    config = require('../config'),
    cache = require('../cache'),
    helper = require('../helper'),
    logger = require('../logger'),
    constants = require('../constants'),
    searchEngine = require('../search/search').engine;

var
    User = db.user,
    Article = db.article,
    Category = db.category,
    Text = db.text,
    warp = db.warp;

var
    userApi = require('./userApi'),
    wikiApi = require('./wikiApi'),
    settingApi = require('./settingApi'),
    discussApi = require('./discussApi'),
    webpageApi = require('./webpageApi'),
    articleApi = require('./articleApi'),
    categoryApi = require('./categoryApi'),
    navigationApi = require('./navigationApi');

var
    signins = _.reduce(config.oauth2, function (results, conf, oauthId) {
        results.push({
            id: oauthId,
            icon: conf.icon,
            name: conf.name
        });
        return results;
    }, []);

var
    searchTypes = [
        {
            label: 'All',
            value: ''
        },
        {
            label: 'Article',
            value: 'article'
        },
        {
            label: 'Wiki',
            value: 'wiki'
        },
        {
            label: 'Discuss',
            value: 'discuss'
        }
    ],
    searchTypeValues = _.reduce(searchTypes, function (r, t) {
        r[t.value] = t.label;
        return r;
    }, {});

var
    WRITE_VIEWS_BACK = 100,
    THEME = config.theme,
    PRODUCTION = process.productionMode;

async function getNavigations() {
    return await cache.get(constants.cache.NAVIGATIONS, navigationApi.getNavigations);
};

async function getModel(model) {
    model.__production__ = PRODUCTION;
    model.__navigations__ = await getNavigations();
    model.__website__ = await settingApi.getWebsiteSettings();
    model.__snippets__ = await settingApi.getSnippets();
    model.__signins__ = signins;
    return model;
}

async function updateEntityViews(entity) {
    console.log('Update views to: ' + entity.views);
    await cache.set(entity.id, 0);
    await entity.update(['views']);
}

function getView(view) {
    return 'themes/default/' + view;
}

async function getIndexModel() {
    var
        i, a, hotArticles,
        categories = await categoryApi.getCategories(),
        recentArticles = await articleApi.getRecentArticles(20),
        nums = await cache.counts(_.map(recentArticles, function (a) {
            return a.id;
        })),
        getCategoryName = function (cid) {
            var c, i;
            for (i = 0; i < categories.length; i++) {
                c = categories[i];
                if (c.id === cid) {
                    return c.name;
                }
            }
            return '';
        };
    for (i = 0; i < recentArticles.length; i++) {
        a = recentArticles[i];
        a.views = a.views + nums[i];
    }
    hotArticles = _.take(_.sortBy(recentArticles, function (a) {
        return 0 - a.views;
    }), 5);
    return {
        recentArticles: recentArticles,
        hotArticles: hotArticles
    };
}

module.exports = {

    'GET /': async (ctx, next) => {
        var model = await cache.get('INDEX-MODEL', getIndexModel);
        ctx.render('index.html', await getModel(model));
    },

    'GET /category/:id': async (ctx, next) => {
        var
            a,
            page = helper.getPage(this.request, 10),
            model = {
                page: page,
                category: await categoryApi.getCategory(id),
                articles: await articleApi.getArticlesByCategory(id, page)
            },
            nums = await cache.counts(_.map(model.articles, function (a) {
                return a.id;
            })),
            i;
        for (i = 0; i < nums.length; i++) {
            a = model.articles[i];
            a.views = a.views + nums[i];
        }
        ctx.render('article/category.html', await getModel(model));
    },

    'GET /article/:id': async (ctx, next) => {
        var
            article = await articleApi.getArticle(id, true),
            num = await cache.incr(id),
            category = await categoryApi.getCategory(article.category_id),
            model = {
                article: article,
                category: category
            };
        article.views = article.views + num;
        if (num > WRITE_VIEWS_BACK) {
            await updateEntityViews(article);
        }
        article.content = md.systemMarkdownToHtml(article.content);
        this.render(getView('article/article.html'), await getModel(model));
    },

    'GET /webpage/:alias': async (ctx, next) => {
        var
            webpage = await webpageApi.getWebpageByAlias(alias, true),
            model;
        if (webpage.draft) {
            ctx.response.status = 404;
            return;
        }
        webpage.content = md.systemMarkdownToHtml(webpage.content);
        model = {
            webpage: webpage
        };
        ctx.render('webpage/webpage.html', await getModel(model));
    },

    'GET /wikipage/:id': async (ctx, next) => {
        var wp = await wikiApi.getWikiPage(id);
        ctx.response.redirect('/wiki/' + wp.wiki_id + '/' + wp.id);
    },

    'GET /wiki/:id': async (ctx, next) => {
        var
            model,
            wiki = await wikiApi.getWiki(id, true),
            num = await cache.incr(wiki.id),
            tree = await wikiApi.getWikiTree(wiki.id, true);
        wiki.type = 'wiki';
        wiki.content = md.systemMarkdownToHtml(wiki.content, true);
        wiki.views = wiki.views + num;
        if (num > WRITE_VIEWS_BACK) {
            await updateEntityViews(wiki);
        }
        model = {
            wiki: wiki,
            current: wiki,
            tree: tree.children
        };
        ctx.render('wiki/wiki.html', await getModel(model));
    },

    'GET /wiki/:wid/:pid': async (ctx, next) => {
        var
            model, wiki, tree, num,
            wikipage = await wikiApi.getWikiPage(pid, true);
        if (wikipage.wiki_id !== id) {
            this.throw(404);
        }
        num = await cache.incr(wikipage.id);
        wiki = await wikiApi.getWiki(id);
        tree = await wikiApi.getWikiTree(id, true);
        wikipage.type = 'wikipage';
        wikipage.views = wikipage.views + num;
        if (num > WRITE_VIEWS_BACK) {
            await updateEntityViews(wikipage);
        }
        wikipage.content = helper.md2html(wikipage.content, true);
        model = {
            wiki: await wikiApi.getWiki(id),
            current: wikipage,
            tree: tree.children
        };
        ctx.render('wiki/wiki.html', await getModel(model));
    },

    'POST /api/comments/:ref_type/:ref_id': async (ctx, next) => {
        ctx.checkPermission(constants.role.SUBSCRIBER);
        ctx.validate('createComment');
        let
            ref_type = ctx.request.params.ref_type,
            ref_id = ctx.request.params.ref_id,
            board,
            user = ctx.state.__user__,
            data = ctx.request.body;
        if (!data.content.trim()) {
            throw api.invalidParam('content', 'Empty input.');
        }
        if (ref_type === 'article') {
            await articleApi.getArticle(ref_id);
        }
        else if (ref_type === 'wiki') {
            await wikiApi.getWiki(ref_id);
        }
        else if (ref_type === 'wikipage') {
            await wikiApi.getWikiPage(ref_id);
        }
        else {
            throw api.invalidParam('ref_type', 'Invalid type.');
        }
        board = await discussApi.getBoardByTag(data.tag);
        ctx.rest(await discussApi.createTopic(user, board.id, ref_type, ref_id, data));
    },

    'GET /discuss': async (ctx, next) => {
        var
            model,
            boards = await discussApi.getBoards();
        model = {
            boards: boards
        };
        ctx.render('discuss/boards.html', await getModel(model));
    },

    'GET /discuss/:id': async (ctx, next) => {
        var
            page = helper.getPage(ctx.request),
            board = await discussApi.getBoard(id),
            topics = await discussApi.getTopics(id, page),
            model;
        await userApi.bindUsers(topics);
        model = {
            page: page,
            board: board,
            topics: topics
        };
        ctx.render('discuss/board.html', await getModel(model));
    },

    'GET /discuss/:bid/:tid': async (ctx, next) => {
        var
            topic = await discussApi.getTopic(tid),
            page,
            board,
            replies,
            model;
        if (topic.board_id !== bid) {
            ctx.response.status = 404;
            return;
        }
        page = helper.getPage(ctx.request);
        board = await discussApi.getBoard(bid);
        replies = await discussApi.getReplies(tid, page);
        if (page.index === 1) {
            replies.unshift(topic);
        }
        await userApi.bindUsers(replies);
        model = {
            page: page,
            board: board,
            topic: topic,
            replies: replies
        };
        this.render('discuss/topic.html', await getModel(model));
    },

    'GET /discuss/:bid/topics/create': async (ctx, next) => {
        if (ctx.state.__user__ === null) {
            ctx.response.redirect('/auth/signin');
            return;
        }
        var
            board = await discussApi.getBoard(bid),
            model = {
                board: board
            };
        ctx.render('discuss/topic_form.html', await getModel(model));
    },

    'GET /discuss/topic/:tid/find/:rid': async (ctx, next) => {
        var
            topic = await discussApi.getTopic(tid),
            p = await discussApi.getReplyPageIndex(tid, rid);
        ctx.response.redirect('/discuss/' + topic.board_id + '/' + tid + '?page=' + p + '#' + rid);
    },

    'GET /user/:id': async (ctx, next) => {
        var
            user = await userApi.getUser(id),
            model = {
                user: user
            };
        ctx.render('user/profile.html', await getModel(model));
    },

    'GET /me/profile': async (ctx, next) => {
        var
            user = this.request.user,
            model = {
                user: user
            };
        if (user === null) {
            ctx.response.redirect('/auth/signin');
            return;
        }
        ctx.render('user/profile.html', await getModel(model));
    },

    'GET /auth/signin': async (ctx, next) => {
        var
            referer = ctx.request.get('referer') || '/',
            user = ctx.state.__user__;
        logger.info('Referer: ' + referer);
        if (user !== null) {

        }
        ctx.render('signin.html', await getModel({}));
    },

    'GET /search': async (ctx, next) => {
        ctx.response.body = 'blank';
        // var
        //     page,
        //     q = req.query.q || '',
        //     type = req.query.type,
        //     opt = {};
        // if (searchEngine.external) {
        //     return res.redirect(searchEngine.search(q));
        // }
        // console.log(JSON.stringify(searchTypeValues));
        // if (!searchTypeValues[type]) {
        //     type = searchTypes[0].value;
        // }
        // if (type) {
        //     opt.filter = {
        //         field: 'type',
        //         value: type
        //     };
        // }
        // page = utils.getPage(req);
        // opt.start = page.offset;
        // opt.hit = page.itemsPerPage;

        // searchEngine.search(q.replace(/\'/g, '').replace(/\"/g, ''), opt, function (err, r) {
        //     if (err) {
        //         return next(err);
        //     }
        //     if (r.status !== 'OK') {
        //         return res.send(500);
        //     }
        //     page.totalItems = r.result.total;
        //     var model = {
        //         searchTypes: searchTypes,
        //         type: type,
        //         page: page,
        //         q: q,
        //         results: r.result.items
        //     };
        //     return processTheme('search.html', model, req, res, next);
        // });
    }
};
<commit_msg>refactor<commit_after>'use strict';

/**
 * UI controller.
 *
 * author: Michael Liao
 */
var
    _ = require('lodash'),
    api = require('../api'),
    db = require('../db'),
    md = require('../md'),
    auth = require('../auth'),
    config = require('../config'),
    cache = require('../cache'),
    helper = require('../helper'),
    logger = require('../logger'),
    constants = require('../constants'),
    searchEngine = require('../search/search').engine;

var
    User = db.user,
    Article = db.article,
    Category = db.category,
    Text = db.text,
    warp = db.warp;

var
    userApi = require('./userApi'),
    wikiApi = require('./wikiApi'),
    settingApi = require('./settingApi'),
    discussApi = require('./discussApi'),
    webpageApi = require('./webpageApi'),
    articleApi = require('./articleApi'),
    categoryApi = require('./categoryApi'),
    navigationApi = require('./navigationApi');

var
    signins = _.reduce(config.oauth2, function (results, conf, oauthId) {
        results.push({
            id: oauthId,
            icon: conf.icon,
            name: conf.name
        });
        return results;
    }, []);

var
    searchTypes = [
        {
            label: 'All',
            value: ''
        },
        {
            label: 'Article',
            value: 'article'
        },
        {
            label: 'Wiki',
            value: 'wiki'
        },
        {
            label: 'Discuss',
            value: 'discuss'
        }
    ],
    searchTypeValues = _.reduce(searchTypes, function (r, t) {
        r[t.value] = t.label;
        return r;
    }, {});

var
    WRITE_VIEWS_BACK = 100,
    THEME = config.theme,
    PRODUCTION = process.productionMode;

async function getNavigations() {
    return await cache.get(constants.cache.NAVIGATIONS, navigationApi.getNavigations);
};

async function getModel(model) {
    model.__production__ = PRODUCTION;
    model.__navigations__ = await getNavigations();
    model.__website__ = await settingApi.getWebsiteSettings();
    model.__snippets__ = await settingApi.getSnippets();
    model.__signins__ = signins;
    return model;
}

async function updateEntityViews(entity) {
    console.log('Update views to: ' + entity.views);
    await cache.set(entity.id, 0);
    await entity.update(['views']);
}

function getView(view) {
    return 'themes/default/' + view;
}

async function getIndexModel() {
    var
        i, a, hotArticles,
        categories = await categoryApi.getCategories(),
        recentArticles = await articleApi.getRecentArticles(20),
        nums = await cache.counts(_.map(recentArticles, function (a) {
            return a.id;
        })),
        getCategoryName = function (cid) {
            var c, i;
            for (i = 0; i < categories.length; i++) {
                c = categories[i];
                if (c.id === cid) {
                    return c.name;
                }
            }
            return '';
        };
    for (i = 0; i < recentArticles.length; i++) {
        a = recentArticles[i];
        a.views = a.views + nums[i];
    }
    hotArticles = _.take(_.sortBy(recentArticles, function (a) {
        return 0 - a.views;
    }), 5);
    return {
        recentArticles: recentArticles,
        hotArticles: hotArticles
    };
}

module.exports = {

    'GET /': async (ctx, next) => {
        var model = await cache.get('INDEX-MODEL', getIndexModel);
        ctx.render('index.html', await getModel(model));
    },

    'GET /category/:id': async (ctx, next) => {
        var
            a,
            page = helper.getPage(this.request, 10),
            model = {
                page: page,
                category: await categoryApi.getCategory(id),
                articles: await articleApi.getArticlesByCategory(id, page)
            },
            nums = await cache.counts(_.map(model.articles, function (a) {
                return a.id;
            })),
            i;
        for (i = 0; i < nums.length; i++) {
            a = model.articles[i];
            a.views = a.views + nums[i];
        }
        ctx.render('article/category.html', await getModel(model));
    },

    'GET /article/:id': async (ctx, next) => {
        var
            article = await articleApi.getArticle(id, true),
            num = await cache.incr(id),
            category = await categoryApi.getCategory(article.category_id),
            model = {
                article: article,
                category: category
            };
        article.views = article.views + num;
        if (num > WRITE_VIEWS_BACK) {
            await updateEntityViews(article);
        }
        article.content = md.systemMarkdownToHtml(article.content);
        this.render(getView('article/article.html'), await getModel(model));
    },

    'GET /webpage/:alias': async (ctx, next) => {
        var
            alias = ctx.params.alias,
            webpage = await webpageApi.getWebpageByAliasWithContent(alias);
        if (webpage.draft) {
            ctx.response.status = 404;
            return;
        }
        webpage.content = md.systemMarkdownToHtml(webpage.content);
        ctx.render('webpage/webpage.html', await getModel({
            webpage: webpage
        }));
    },

    'GET /wikipage/:id': async (ctx, next) => {
        var
            id = ctx.params.id,
            wp = await wikiApi.getWikiPage(id);
        ctx.response.redirect('/wiki/' + wp.wiki_id + '/' + wp.id);
    },

    'GET /wiki/:id': async (ctx, next) => {
        var
            id = ctx.params.id,
            wiki = await wikiApi.getWiki(id, true),
            num = await cache.incr(wiki.id),
            tree = await wikiApi.getWikiTree(wiki.id, true);
        wiki.type = 'wiki';
        wiki.content = md.systemMarkdownToHtml(wiki.content, true);
        wiki.views = wiki.views + num;
        if (num > WRITE_VIEWS_BACK) {
            await updateEntityViews(wiki);
        }
        ctx.render('wiki/wiki.html', await getModel({
            wiki: wiki,
            current: wiki,
            tree: tree.children
        }));
    },

    'GET /wiki/:wid/:pid': async (ctx, next) => {
        var
            wid = ctx.params.wid,
            pid = ctx.params.pid,
            wiki, tree, num,
            wikipage = await wikiApi.getWikiPage(pid, true);
        if (wikipage.wiki_id !== id) {
            this.throw(404);
        }
        num = await cache.incr(wikipage.id);
        wiki = await wikiApi.getWiki(id);
        tree = await wikiApi.getWikiTree(id, true);
        wikipage.type = 'wikipage';
        wikipage.views = wikipage.views + num;
        if (num > WRITE_VIEWS_BACK) {
            await updateEntityViews(wikipage);
        }
        wikipage.content = helper.md2html(wikipage.content, true);
        ctx.render('wiki/wiki.html', await getModel({
            wiki: await wikiApi.getWiki(id),
            current: wikipage,
            tree: tree.children
        }));
    },

    'POST /api/comments/:ref_type/:ref_id': async (ctx, next) => {
        ctx.checkPermission(constants.role.SUBSCRIBER);
        ctx.validate('createComment');
        let
            board,
            ref_type = ctx.params.ref_type,
            ref_id = ctx.params.ref_id,
            user = ctx.state.__user__,
            data = ctx.request.body;
        if (!data.content.trim()) {
            throw api.invalidParam('content', 'Empty input.');
        }
        if (ref_type === 'article') {
            await articleApi.getArticle(ref_id);
        }
        else if (ref_type === 'wiki') {
            await wikiApi.getWiki(ref_id);
        }
        else if (ref_type === 'wikipage') {
            await wikiApi.getWikiPage(ref_id);
        }
        else {
            throw api.invalidParam('ref_type', 'Invalid type.');
        }
        board = await discussApi.getBoardByTag(data.tag);
        ctx.rest(await discussApi.createTopic(user, board.id, ref_type, ref_id, data));
    },

    'GET /discuss': async (ctx, next) => {
        var boards = await discussApi.getBoards();
        ctx.render('discuss/boards.html', await getModel({
            boards: boards
        }));
    },

    'GET /discuss/:id': async (ctx, next) => {
        var
            id = ctx.params.id,
            page = helper.getPage(ctx.request),
            board = await discussApi.getBoard(id),
            topics = await discussApi.getTopics(id, page),
            model;
        await userApi.bindUsers(topics);
        model = {
            page: page,
            board: board,
            topics: topics
        };
        ctx.render('discuss/board.html', await getModel(model));
    },

    'GET /discuss/:bid/:tid': async (ctx, next) => {
        var
            bid = ctx.params.bid,
            tid = ctx.params.tid,
            topic = await discussApi.getTopic(tid),
            page,
            board,
            replies,
            model;
        if (topic.board_id !== bid) {
            ctx.response.status = 404;
            return;
        }
        page = helper.getPage(ctx.request);
        board = await discussApi.getBoard(bid);
        replies = await discussApi.getReplies(tid, page);
        if (page.index === 1) {
            replies.unshift(topic);
        }
        await userApi.bindUsers(replies);
        model = {
            page: page,
            board: board,
            topic: topic,
            replies: replies
        };
        this.render('discuss/topic.html', await getModel(model));
    },

    'GET /discuss/:bid/topics/create': async (ctx, next) => {
        if (ctx.state.__user__ === null) {
            ctx.response.redirect('/auth/signin');
            return;
        }
        var
            board = await discussApi.getBoard(bid),
            model = {
                board: board
            };
        ctx.render('discuss/topic_form.html', await getModel(model));
    },

    'GET /discuss/topic/:tid/find/:rid': async (ctx, next) => {
        var
            topic = await discussApi.getTopic(tid),
            p = await discussApi.getReplyPageIndex(tid, rid);
        ctx.response.redirect('/discuss/' + topic.board_id + '/' + tid + '?page=' + p + '#' + rid);
    },

    'GET /user/:id': async (ctx, next) => {
        var
            user = await userApi.getUser(id),
            model = {
                user: user
            };
        ctx.render('user/profile.html', await getModel(model));
    },

    'GET /me/profile': async (ctx, next) => {
        var
            user = ctx.state.__user__,
            model = {
                user: user
            };
        if (user === null) {
            ctx.response.redirect('/auth/signin');
            return;
        }
        ctx.render('user/profile.html', await getModel(model));
    },

    'GET /auth/signin': async (ctx, next) => {
        var
            referer = ctx.request.get('referer') || '/',
            user = ctx.state.__user__;
        logger.info('Referer: ' + referer);
        if (user !== null) {

        }
        ctx.render('signin.html', await getModel({}));
    },

    'GET /search': async (ctx, next) => {
        ctx.response.body = 'blank';
        // var
        //     page,
        //     q = req.query.q || '',
        //     type = req.query.type,
        //     opt = {};
        // if (searchEngine.external) {
        //     return res.redirect(searchEngine.search(q));
        // }
        // console.log(JSON.stringify(searchTypeValues));
        // if (!searchTypeValues[type]) {
        //     type = searchTypes[0].value;
        // }
        // if (type) {
        //     opt.filter = {
        //         field: 'type',
        //         value: type
        //     };
        // }
        // page = utils.getPage(req);
        // opt.start = page.offset;
        // opt.hit = page.itemsPerPage;

        // searchEngine.search(q.replace(/\'/g, '').replace(/\"/g, ''), opt, function (err, r) {
        //     if (err) {
        //         return next(err);
        //     }
        //     if (r.status !== 'OK') {
        //         return res.send(500);
        //     }
        //     page.totalItems = r.result.total;
        //     var model = {
        //         searchTypes: searchTypes,
        //         type: type,
        //         page: page,
        //         q: q,
        //         results: r.result.items
        //     };
        //     return processTheme('search.html', model, req, res, next);
        // });
    }
};
<|endoftext|>