/**
*
* Crunchbutton
*
* @author: Devin Smith (http://devin.la)
* @date: 2012-06-20
*
*/
var App = {
cartHighlightEnabled: false,
currentPage: null,
tagline: '',
service: '/api/',
cached: {},
community: null,
page: {},
locs: [],
config: null,
forceHome: false,
cookieExpire: new Date(3000,01,01),
order: {
cardChanged: false,
pay_type: 'card',
delivery_type: 'delivery',
tip: 'autotip'
},
signin : {},
suggestion : {},
restaurants: {
permalink : 'food-delivery',
list: false
},
defaultTip: 'autotip',
defaultRange : 2,
modal: {},
hasBack: false,
_init: false,
_pageInit: false,
_identified: false,
isDeliveryAddressOk : false,
tips: [0,10,15,18,20,25,30],
touchX: null,
touchY: null,
touchOffset: null,
crunchSoundAlreadyPlayed : false,
useCompleteAddress : false, /* if true it means the address field will be fill with the address found by google api */
completeAddressWithZipCode : true,
boundingBoxMeters : 8000,
useRestaurantBoundingBox : false
};
App.alert = function(txt) {
setTimeout(function() {
alert(txt);
});
};
App.loadRestaurant = function(id) {
};
/**
* Loads up "community" keyword pages
*/
App.routeAlias = function(id, success, error) {
id = id.toLowerCase();
alias = App.aliases[id] || false;
success = success || function(){};
error = error || function(){};
if (alias) {
// Get the location of the alias
var loc = App.locations[alias.id_community];
if (loc.loc_lat && loc.loc_lon) {
var res = new Location({
lat: loc.loc_lat,
lon: loc.loc_lon,
type: 'alias',
verified: true,
prep: alias.prep,
city: alias.name_alt,
address: alias.name_alt
});
success({alias: res});
return;
}
}
error();
};
App.showPage = function(params) {
// Hides the pacman
App.controlMobileIcons.hidePacman();
// Hides the gift card message
App.credit.hide();
// switch here for AB testing
App.currentPage = params.page;
if (params.title) {
document.title = params.title;
}
// #1227 - on mobile view switch change location and profile buttons
App.controlMobileIcons.process( params.page );
// track different AB pages
if (params.tracking) {
App.track(params.tracking.title, params.tracking.data);
}
};
App.NGinit = function() {
$('body').attr('ng-controller', 'AppController');
angular.bootstrap(document,['NGApp']);
App.loc.init();
App.signin.init();
App.signup.init();
App.suggestion.init();
App.recommend.init();
App.credit.tooltip.init();
if (!App.isMobile()) {
App.support.init();
}
if (App.config.env == 'live') {
$('.footer').addClass('footer-hide');
}
setTimeout( function(){ App.signin.checkUser(); }, 300 );
};
var NGApp = angular.module('NGApp', []);
NGApp.config(function($compileProvider){
$compileProvider.urlSanitizationWhitelist(/.*/);
});
NGApp.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/location', {
action: 'location',
controller: 'location',
templateUrl: 'view/location.html'
})
.when('/' + App.restaurants.permalink, {
action: 'restaurants',
controller: 'restaurants',
templateUrl: 'view/restaurants.html'
})
.when('/' + App.restaurants.permalink + '/:id', {
action: 'restaurant',
controller: 'restaurant',
templateUrl: 'view/restaurant.html'
})
.when('/legal', {
action: 'legal',
controller: 'legal',
templateUrl: 'view/legal.html'
})
.when('/help', {
action: 'help',
controller: 'help',
templateUrl: 'view/help.html'
})
.when('/order/:id', {
action: 'order',
controller: 'order',
templateUrl: 'view/order.html'
})
.when('/cities', {
action: 'cities',
controller: 'cities',
templateUrl: 'view/cities.html'
})
.when('/giftcard/:id', {
action: 'giftcard',
controller: 'giftcard',
templateUrl: 'view/giftcard.html'
})
.when('/reset', {
action: 'reset',
controller: 'reset',
templateUrl: 'view/reset.html'
})
.when('/', {
action: 'home',
controller: 'home',
templateUrl: 'view/home.html'
})
.otherwise({
action: 'home.default',
controller: 'default',
templateUrl: 'view/home.html'
})
;
$locationProvider.html5Mode(true);
}]);
// global route change items
NGApp.controller('AppController', function ($scope, $route, $routeParams, $rootScope) {
render = function() {
var renderAction = $route.current.action;
var renderPath = renderAction.split('.');
$scope.renderAction = renderAction;
$scope.renderPath = renderPath;
};
$scope.$on(
'$routeChangeSuccess',
function ($currentRoute, $previousRoute) {
console.debug('ROUTE >',$route.current.action, $rootScope)
$rootScope.blah = function() {
alert('asd');
};
// Update the rendering.
render();
if (App.isChromeForIOS()){
App.message.chrome();
}
}
);
});
/**
* Refresh the pages layout for a blank page
*/
App.refreshLayout = function() {
setTimeout(function() {
scrollTo(0, 1);
}, 80);
};
/**
* Sends a tracking item to mixpanel, or to google ads if its an order
*/
App.track = function() {
if (App.config.env != 'live') {
// return;
}
if (arguments[0] == 'Ordered') {
$('img.conversion').remove();
mixpanel.people.track_charge(arguments[1].total);
var i = $('
').appendTo($('body'));
}
if (arguments[1]) {
mixpanel.track(arguments[0],arguments[1]);
} else {
mixpanel.track(arguments[0]);
}
};
/**
* Tracks a property to mixpanel
*/
App.trackProperty = function(prop, value) {
// || App.config.env != 'live'
if (!App.config) {
return;
}
var params = {};
params[prop] = value;
mixpanel.register_once(params);
};
/**
* Itendity the user to mixpanel
*/
App.identify = function() {
if (App.config.env != 'live') {
//return;
}
if (App.config.user.uuid) {
mixpanel.identify(App.config.user.uuid);
mixpanel.people.set({
$name: App.config.user.name,
$ip: App.config.user.ip,
$email: App.config.user.email
});
}
};
/**
* controls the busy state of the app
*/
App.busy = {
isBusy: function() {
return $('.app-busy').length ? true : false;
},
makeBusy: function() {
$('body').append($('
').append($('')));
},
unBusy: function() {
$('.app-busy').remove();
}
};
/**
* stuff for testing
*/
App.test = {
card: function() {
$('[name="pay-card-number"]').val('4242424242424242');
$('[name="pay-card-month"]').val('1');
$('[name="pay-card-year"]').val('2020');
$('[name="pay-name"]').val('MR TEST');
$('[name="pay-phone"]').val('***REMOVED***');
$('[name="pay-address"]').val( App.restaurant.address || "123 main\nsanta monica ca" );
App.order.cardChanged = true;
App.creditCard.changeIcons( $( '[name="pay-card-number"]' ).val() );
},
logout: function() {
$.getJSON('/api/logout',function(){ location.reload()});
},
cart: function() {
App.alert(JSON.stringify(App.cart.items));
},
clearloc: function() {
$.cookie('community', '', { expires: new Date(3000,01,01), path: '/'});
$.cookie('location_lat', '', { expires: new Date(3000,01,01), path: '/'});
$.cookie('location_lon', '', { expires: new Date(3000,01,01), path: '/'});
location.href = '/';
},
init: function() {
$('.test-card').tap(function() {
App.test.card();
});
$('.test-logout').tap(function() {
App.test.logout();
});
$('.test-cart').tap(function() {
App.test.cart();
});
$('.test-clearloc').tap(function() {
App.test.clearloc();
});
}
};
App.processConfig = function(json, user) {
if (user && !json) {
App.config.user = user;
} else {
App.config = json;
}
App.AB.init();
if (App.config.user) {
App.identify();
App.order['pay_type'] = App.config.user['pay_type'];
App.order['delivery_type'] = App.config.user['delivery_type'];
var lastTip = App.config.user['last_tip'] || 'autotip';
lastTip = App.lastTipNormalize( lastTip );
App.order['tip'] = lastTip;
}
};
App.updateAutotipValue = function() {
var subtotal = App.cart.totalbreakdown().subtotal;
var autotipValue
if(subtotal === 0) {
autotipValue = 0;
}
else {
// the holy formula - see github/#940
autotipValue = Math.ceil(4*(subtotal * 0.107 + 0.85)) / 4;
}
$('[name="pay-autotip-value"]').val(autotipValue);
var autotipText = autotipValue ? ' (' + ( App.config.ab && App.config.ab.dollarSign == 'show' ? '$' : '' ) + autotipValue + ')' : '';
$('[name=pay-tip] [value=autotip]').html('Autotip' + autotipText);
};
App.lastTipNormalize = function( lastTip ){
if( lastTip === 'autotip' ) {
return lastTip;
}
lastTip = parseInt( lastTip );
if( App.config.user && App.config.user.last_tip_type && App.config.user.last_tip_type == 'number' ){
return App.defaultTip;
}
// it means the last tipped value is not at the permitted value, return default.
if( App.tips.indexOf( lastTip ) > 0 ){
lastTip = lastTip;
} else {
lastTip = App.defaultTip;
}
return lastTip;
}
App.trigger = {
delivery: function() {
$('.delivery-toggle-takeout').removeClass('toggle-active');
$('.delivery-toggle-delivery').addClass('toggle-active');
$('.delivery-only').show();
App.order['delivery_type'] = 'delivery';
App.cart.updateTotal();
},
takeout: function() {
$('.delivery-toggle-delivery').removeClass('toggle-active');
$('.delivery-toggle-takeout').addClass('toggle-active');
$('.delivery-only, .field-error-zip').hide();
App.order['delivery_type'] = 'takeout';
App.cart.updateTotal();
},
credit: function() {
$('.pay-toggle-cash').removeClass('toggle-active');
$('.pay-toggle-credit').addClass('toggle-active');
$('.card-only').show();
App.order['pay_type'] = 'card';
App.cart.updateTotal();
},
cash: function() {
$('.pay-toggle-credit').removeClass('toggle-active');
$('.pay-toggle-cash').addClass('toggle-active');
$('.card-only').hide();
App.order['pay_type'] = 'cash';
App.cart.updateTotal();
}
}
/**
* global event binding and init
*/
$(function() {
App.test.init();
$(document).on('touchclick', '.signout-button', function() {
App.signin.signOut();
});
$(document).on('touchclick', '.signup-add-facebook-button', function() {
App.signin.facebook.login();
});
$(document).on('touchclick', '.change-location-inline', function() {
App.loadHome(true);
});
$(document).on('submit', '.button-letseat-formform', function() {
$('.button-letseat-form').trigger('touchup');
return false;
});
$(document).on('touchclick', '.delivery-toggle-delivery', function(e) {
e.preventDefault();
e.stopPropagation();
App.trigger.delivery();
App.track('Switch to delivery');
});
$(document).on('touchclick', '.delivery-toggle-takeout', function(e) {
e.preventDefault();
e.stopPropagation();
App.trigger.takeout();
App.track('Switch to takeout');
});
$(document).on('touchclick', '.pay-toggle-credit', function(e) {
e.preventDefault();
e.stopPropagation();
App.trigger.credit();
App.track('Switch to card');
App.giftcard.notesField.listener();
});
$(document).on('touchclick', '.pay-toggle-cash', function(e) {
e.preventDefault();
e.stopPropagation();
App.trigger.cash();
App.track('Switch to cash');
App.giftcard.notesField.listener();
});
$(document).on('touchclick', '.location-detect', function() {
// detect location from the browser
$('.location-detect-loader').show();
$('.location-detect-icon').hide();
var error = function() {
$('.location-address').val('Oh no! We couldn\'t locate you');
$('.location-detect-loader').hide();
$('.location-detect-icon').show();
};
var success = function() {
App.page.foodDelivery();
// $('.location-detect-loader').hide();
// $('.location-detect-icon').show();
// $('.button-letseat-form').click();
};
App.loc.getLocationByBrowser(success, error);
});
$(document).on({
mousedown: function() {
$(this).addClass('location-detect-click');
},
touchstart: function() {
$(this).addClass('location-detect-click');
},
mouseup: function() {
$(this).removeClass('location-detect-click');
},
touchend: function() {
$(this).removeClass('location-detect-click');
}
}, '.location-detect');
$('.link-help').tap(function(e) {
e.stopPropagation();
e.preventDefault();
History.pushState({}, 'Crunchbutton - About', '/help');
});
$('.link-legal').tap(function(e) {
e.stopPropagation();
e.preventDefault();
history.pushState({}, 'Crunchbutton - Legal', '/legal');
});
$('.link-orders').tap(function(e) {
e.stopPropagation();
e.preventDefault();
history.pushState({}, 'Crunchbutton - Orders', '/orders');
});
if (App.isMobile()) {
// prevent double trigger
$(document).on('touchclick','input[type="checkbox"]', function(e) {
e.stopPropagation();
e.preventDefault();
});
// manually rebind checkbox events
$('input[type="checkbox"]').tap(function(e) {
e.stopPropagation();
e.preventDefault();
$(this).checkToggle();
});
// manually rebind labels
$('label[for]').tap(function(e) {
e.stopPropagation();
e.preventDefault();
var target = document.getElementById($(this).attr('for'));
if (target && target.tagName == 'INPUT') {
switch ($(target).attr('type')) {
case 'text':
case 'password':
case 'number':
case 'phone':
case 'tel':
$(target).focus();
break;
case 'checkbox':
$(target).checkToggle();
break;
}
}
$(this).checkToggle();
});
// manually bind links
// @todo: intercept for native app
$('a[href]').tap(function(e) {
var el = $(this);
var href = el.attr('href');
if (!href || e.defaultPrevented) {
return;
}
if ($(this).attr('target')) {
window.open($(this).attr('href'), $(this).attr('target'));
} else {
location.href = $(this).attr('href');
}
});
// ignore all click events from acidently triggering on mobile. only use touchclick
$(document).on('click', function(e, force) {
e.stopPropagation();
e.preventDefault();
});
}
$('.dish-item').tap(function() {
App.cart.add($(this).attr('data-id_dish'));
});
$('.your-orders a').tap(function() {
if ($(this).attr('data-id_order')) {
History.pushState({},'Crunchbutton - Your Order', '/order/' + $(this).attr('data-id_order'));
}
});
$('.cart-button-remove').tap(function() {
App.cart.remove($(this).closest('.cart-item'));
});
$('.cart-button-add').tap(function() {
App.cart.clone($(this).closest('.cart-item'));
});
$('.cart-item-config a').tap(function() {
App.cart.customize($(this).closest('.cart-item'));
});
$('.button-submitorder-form').tap(function(e) {
e.preventDefault();
e.stopPropagation();
App.crunchSoundAlreadyPlayed = false;
App.isDeliveryAddressOk = false;
App.cart.submit($(this),true);
});
$(document).on('touchclick', '.button-deliver-payment, .dp-display-item a, .dp-display-item .clickable', function() {
$('.payment-form').show();
$('.delivery-payment-info, .content-padder-before').hide();
});
$(document).on({
mousedown: function() {
$(this).addClass('button-bottom-click');
},
touchstart: function() {
$(this).addClass('button-bottom-click');
},
mouseup: function() {
$(this).removeClass('button-bottom-click');
},
touchend: function() {
$(this).removeClass('button-bottom-click');
}
}, '.button-bottom');
$(document).on('change', '.cart-customize-select', function() {
App.cart.customizeItem($(this));
});
$( '.default-order-check' ).tap( function(){
setTimeout( function(){
$( '#default-order-check' ).checkToggle();
}, 1 );
} );
$('.cart-customize-check').tap( function() {
var checkbox = $(this);
setTimeout( function(){
if( !App.isMobile() ){
checkbox.checkToggle();
}
App.cart.customizeItem( checkbox );
}, 1 );
});
$('.cart-item-customize-item label').tap(function() {
$(this).prev('input').checkToggle();
App.cart.customizeItem( $(this).prev('input') );
});
$(document).on('change', '[name="pay-tip"]', function() {
App.order.tip = $(this).val();
App.order.tipHasChanged = true;
var total = App.cart.total();
App.cart.updateTotal();
});
$('.nav-back').tap(function() {
// App.controlMobileIcons.showPacman( 'left', function(){ $('.nav-back').removeClass('nav-back-show'); } );
$('.nav-back').removeClass('nav-back-show');
if( App.loc.locationNotServed ){
App.loc.locationNotServed = false;
App.loadHome(true);
} else {
History.back();
}
});
$('.link-home').tap(function() {
if( App.restaurants.list && App.restaurants.list.length > 0 ){
App.page.foodDelivery();
} else {
App.loadHome(true);
}
});
$(document).on('change', '[name="pay-card-number"], [name="pay-card-month"], [name="pay-card-year"]', function() {
if( !App.order.cardChanged ){
var self = $( this );
var cardInfo = [ '[name="pay-card-number"]', '[name="pay-card-month"]', '[name="pay-card-year"]' ];
$( cardInfo ).each( function( index, value ){
var input = $( value );
if( self.attr( 'name' ) != input.attr( 'name' ) ){
input.val( '' );
}
} )
}
App.order.cardChanged = true;
});
// Listener to verify if the user typed a gift card at the notes field
$(document).on('blur', '[name=notes]', function() {
App.giftcard.notesField.listener();
});
$(document).on('change, keyup', '[name="pay-card-number"]', function() {
App.creditCard.changeIcons( $(this).val() );
});
$(document).on('keyup', '[name="pay-phone"]', function() {
$(this).val( App.phone.format($(this).val()) );
});
$(document).trigger('have-config');
App.processConfig(App.config);
App._init = true;
App.NGinit();
$('.cart-summary').tap(function(e) {
e.stopPropagation();
e.preventDefault();
$('html, body').animate({
scrollTop: $('.cart-items').position().top-80
}, {
duration: 500,
specialEasing: {
scrollTop: 'easeInOutQuart'
}
});
});
// hide the top bar when any input is focused
if (App.isMobile() && !App.isAndroid()) {
setInterval(function() {
var focused = $(':focus');
if (!focused.length) {
$('[data-position="fixed"]').show();
return;
}
focused = focused.get(0);
if (focused.tagName == 'SELECT' || focused.tagName == 'INPUT' || focused.tagName == 'TEXTAREA') {
$('[data-position="fixed"]').hide();
} else {
$('[data-position="fixed"]').show();
}
}, 100);
}
var checkForDistance = function() {
if (App.order['delivery_type'] == 'takeout') {
return;
}
};
$(document).on('blur', '[name="pay-address"]', function() {
clearTimeout(App.checkForDistance);
App.checkForDistance = setTimeout(checkForDistance, 100);
});
$(document).on('change', '[name="pay-address"]', function() {
clearTimeout(App.checkForDistance);
App.checkForDistance = setTimeout(checkForDistance, 1000);
});
$(document).on('touchclick', '.config-icon', function() {
if (App.isNarrowScreen() && $(this).hasClass('config-icon-back-home')) {
App.controlMobileIcons.backHome();
} else {
var pacmanSide = (App.currentPage == 'restaurants') ? 'right' : 'left';
App.controlMobileIcons.showPacman( pacmanSide, function(){ $( '.sign-in-icon' ).addClass( 'config-icon-mobile-hide' ); } );
App.loadHome(true);
}
});
$(document).on('change', '[name="pay-address"], [name="pay-name"], [name="pay-phone"], [name="pay-card-number"], [name="notes"]', function() {
App.config.user.name = $('[name="pay-name"]').val();
App.config.user.phone = App.phone.format($('[name="pay-phone"]').val());
App.config.user.address = $('[name="pay-address"]').val();
App.config.user.card = $('[name="pay-card-number"]').val();
App.config.user.notes = $('[name="notes"]').val();
App.config.user.card_exp_month = $('[name="pay-card-month"]').val();
App.config.user.card_exp_year = $('[name="pay-card-year"]').val();
});
$(document).on('touchclick', '.content-item-locations-city', function() {
$( '.main-content' ).html( '' );
var permalink = $( this ).attr( 'permalink' );
App.routeAlias( permalink, function( result ){
App.loc.realLoc = {
addressAlias: result.alias.address,
lat: result.alias.lat,
lon: result.alias.lon,
prep: result.alias.prep,
city: result.alias.city
};
App.loc.setFormattedLocFromResult();
App.page.foodDelivery( true );
});
});
$( '.ui-dialog-titlebar-close' ).tap( function(){
try{
$( '.ui-dialog-content' ).dialog( 'close' );
} catch(e){}
} );
});
App.modal.contentWidth = function(){
if( $( window ).width() > 700 ){
return 280;
}
if( $( window ).width() <= 700 ){
return $( window ).width() - 50;
}
}
App.getCommunityById = function( id ){
for (x in App.communities) {
if( App.communities[x].id_community == id ){
return App.communities[x];
}
}
return false;
}
App.message = {};
App.message.show = function( title, message ) {
if( $( '.message-container' ).length > 0 ){
$( '.message-container' ).html( '' + title + '
' + message + '
' );
} else {
var html = '' +
'
' + title + '
' +
'
' +
message +
'
' +
'
';
$('.wrapper').append(html);
}
$('.message-container')
.dialog({
modal: true,
dialogClass: 'modal-fixed-dialog',
width: App.modal.contentWidth(),
close: function( event, ui ) { App.modal.shield.close(); },
});
}
App.playAudio = function( audio, callback ){
var audio = $( '#' + audio ).get(0);
try{
audio.addEventListener( 'ended', function() {
if( callback ){
callback();
}
});
audio.play();
} catch( e ){}
}
App.registerLocationsCookies = function() {
$.cookie('location_lat', App.loc.lat, { expires: new Date(3000,01,01), path: '/'});
$.cookie('location_lon', App.loc.lon, { expires: new Date(3000,01,01), path: '/'});
$.cookie('location_range', ( App.loc.range || App.defaultRange ), { expires: new Date(3000,01,01), path: '/'});
}
App.message.chrome = function( ){
var title = 'How to use Chrome',
message = '' +
'Just tap "Request Desktop Site.' +
'
' +
'' +
'
' +
'
';
App.message.show(title, message);
}
// Issue #1227
App.controlMobileIcons = {};
App.controlMobileIcons.process = function( page ){
if( !App.isNarrowScreen() ){
return false;
}
App.controlMobileIcons.normalize();
App.loc.locationNotServed = false;
$( '.sign-in-icon' ).removeClass( 'config-icon-mobile-hide' );
$( '.config-icon' ).removeClass( 'config-icon-mobile-hide' );
switch( page ){
case 'restaurant':
case 'order':
$( '.config-icon' ).addClass( 'config-icon-mobile-hide' );
break;
case 'home':
$( '.config-icon' ).addClass( 'config-icon-back-home' );
break;
case 'orders':
$( '.sign-in-icon' ).addClass( 'config-icon-mobile-hide' );
$( '.config-icon' ).addClass( 'config-icon-mobile-hide' );
break;
case 'restaurants':
$( '.sign-in-icon' ).addClass( 'left' );
$( '.config-icon' ).addClass( 'right' );
break;
}
}
App.controlMobileIcons.backHome = function(){
if( App.loc.locationNotServed ){
App.page.home( true );
} else {
if( App.restaurants.list && App.restaurants.list.length > 0 ){
App.page.foodDelivery();
} else {
History.pushState( {}, 'Crunchbutton', '/bycity' );
}
}
}
App.controlMobileIcons.normalize = function(){
$( '.sign-in-icon' ).removeClass( 'left' );
$( '.config-icon' ).removeClass( 'right' );
$( '.config-icon' ).removeClass( 'config-icon-back-home' );
}
App.controlMobileIcons.showPacman = function( side, call ){
$( '.pacman-' + side ).addClass( 'pacman-show' );
if( call ){ call(); }
}
App.controlMobileIcons.hidePacman = function(){
$( '.pacman-loading' ).removeClass( 'pacman-show' );
}