bcmoney

iOS debugging

Nov 17th, 2017
963
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 68.44 KB | None | 0 0
  1. Search codebase for "visible-xs navbar-fixed-top mobile header-en"
  2. (class attribute values of top header which is getting injected after page-load by JS)
  3.  
  4. ------------------------------------------------------------
  5. // ALC COMMON FUNCTIONS
  6. var ALC = ALC || {};
  7.  
  8. ALC.constants = {
  9. CONTENT_ROOT: '/content/alc/',
  10. MY_PROFILE_PATH : '/my-account/my-profile.html',
  11. REINSTATEMENT_CONFIRMATION_PATH: '/self-exclusion-reinstatement/reinstatement-confirmation.html',
  12. SELF_EXCLUSION_PATH: '/my-account/play-responsibly.html#3',
  13. DIGITAL_INSTANTS_WRAPPER: '/play-online/instant-win-games/game.html?',
  14. REVERIFY_PATH: '/registration/reverify-account.html',
  15. LOGIN_REDIRECT_PATH: '/login.html?redirectUrl=',
  16. CART_PATH: '/cart.html',
  17. CHECKOUT_PATH: '/checkout.html',
  18. CHECKOUT_PENDING_PATH: '/checkout-pending.html',
  19. CONFIRMATION_REDIRECT_PATH: '/confirmation.html',
  20. ADD_FUNDS_PATH: '/my-account/add-withdraw-funds.html#0_1',
  21. PAYMENT_PREFERENCES_PATH: '/my-account/add-withdraw-funds.html#1',
  22. AEM_DISPATCHER_FAILOVER_PATH: '/errors/error.html',
  23. LOTTOMAX_JPID: ALC.applicationProperties.LottoMax_JPID,
  24. LOTTO649_JPID: ALC.applicationProperties.Lotto649_JPID,
  25. SALSABINGO_JPID: ALC.applicationProperties.SalsaBingo_JPID,
  26. ATLANTIC49_JPID: ALC.applicationProperties.Atlantic49_JPID,
  27. KENOATLANTIC_JPID: ALC.applicationProperties.KenoAtlantic_JPID,
  28. BUCKO_JPID: ALC.applicationProperties.Bucko_JPID,
  29. POKERLOTTO_JPID: ALC.applicationProperties.PokerLotto_JPID,
  30. DAILYGRAND_JPID: ALC.applicationProperties.DailyGrand_JPID,
  31. LOTTO4_JPID: ALC.applicationProperties.Lotto4_JPID,
  32. lottoTicketErrorStates: [-1,0,4,6],
  33. lottoTicketAdvanceErrorStates: [-1,0,2,7,8]
  34. };
  35.  
  36.  
  37. /**
  38. * isMobileSafari
  39. * Fixes long-standing iOS "fixed position modal" bug
  40. * @returns boolean true if the RegEx of the User Agent string evaluates as iOS/WebKit
  41. */
  42. function isMobileSafari () {
  43. return ( /iP(hone|od|ad)/i.test(navigator.userAgent) && /WebKit/i.test(navigator.userAgent) && !/Chrome|CriOS|OPiOS/i.test(navigator.userAgent) );
  44. }
  45.  
  46. // Modal on iOS Safari needs a window listener to maintain 100% WxH scale (orientation flips or screen focus/resize)
  47. if ( isMobileSafari() ) {
  48. $(window).resize(function(){
  49. $(".modal-login").css("width","100vw");
  50. $(".modal-login").css("height","100vh");
  51. $("body").css("height","100vh");
  52. });
  53. }
  54.  
  55.  
  56.  
  57. ALC.common = {
  58. dashboardPromise: null,
  59. termsOfServicePromise: null,
  60. lang: $("html").attr("lang"),
  61. allowCharacters: function(myfield, event, allowedType) {
  62. if(event.altKey){
  63. event.preventDefault();
  64. return;
  65. }
  66. var elm = $(myfield),
  67. elmVal = elm.val(),
  68. code;
  69. if (event.keyCode){
  70. code = event.keyCode;
  71. } else if(event.which){
  72. code = event.which;
  73. }
  74.  
  75.  
  76. // Allow: backspace, insert, delete, tab, escape, enter, home, end, left, right, num lock
  77. if ($.inArray(code, [45, 46, 8, 9, 27, 13, 35, 36, 37, 39, 144]) !== -1 ||
  78. // Allow: Ctrl+A, Command+A
  79. (code == 65 && ( event.ctrlKey === true || event.metaKey === true ))){
  80. return;
  81. }
  82. if(elm.attr('arrowinput') === 'disabled'){
  83. if($.inArray(code, [38, 40]) !== -1){
  84. event.preventDefault();
  85. return;
  86. }
  87. } else {
  88. if($.inArray(code, [38, 40]) !== -1){
  89. // Allow up and down
  90. return;
  91. }
  92. }
  93.  
  94. if(allowedType === 'numericonly'){
  95. if(elm.attr('step') === '1'){
  96. if($.inArray(code, [110, 190]) !== -1){
  97. event.preventDefault();
  98. return;
  99. }
  100. } else if(elm.attr('step') === '0.01'){
  101. if($.inArray(code, [110, 190]) !== -1 && $.inArray(ALC.common.numericOnly.lastTyped, [110, 190]) !== -1){ // prevent 2 consecutive decimal points
  102. event.preventDefault();
  103. return;
  104. } else if(elmVal.indexOf('.') !== -1) {
  105. var fraction = elmVal.split('.')[1];
  106. if(fraction && fraction.length === 2){
  107. event.preventDefault();
  108. return;
  109. }
  110. }
  111. ALC.common.numericOnly.lastTyped = code;
  112. }
  113. // If not a number or decimal point stop the event
  114. if ((event.shiftKey || (code < 48 || code > 57)) &&
  115. (code < 96 || code > 105) &&
  116. $.inArray(code, [110, 190]) === -1){
  117. event.preventDefault();
  118. }
  119. } else if(allowedType === 'alphanumericonly'){
  120. //Detect Chrome for Android
  121. if (code === 0 || code === 229){
  122. var regexSpecialChars = new RegExp("/[^A-Z0-9]/gi");
  123. if (regexSpecialChars.test(myfield.value)){
  124. myfield.value = myfield.value.replace(/[^A-Z0-9]/gi, '');
  125. return;
  126. }
  127. }
  128. // If not alphanumeric stop the event
  129. if (event.originalEvent.type === "keypress"){
  130. if(!((code >= 97) && (code <= 122) || (code >= 48) && (code <= 57))){
  131. event.preventDefault();
  132. return;
  133. }
  134. }else{
  135. //for keyup & keydown
  136. if(!((code >= 65) && (code <= 90) || (code >= 96) && (code <= 105) || (code >= 48) && (code <= 57))){
  137. event.preventDefault();
  138. return;
  139. }
  140. }
  141. //Includes french language special characters
  142. var regex = new RegExp("^[a-zA-Z0-9]+$");
  143. var regexAlphaOnly = new RegExp("^[a-zA-Z]+$");
  144. var key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
  145.  
  146. if ((!regex.test(event.key) || !regex.test(key)) || (event.key === undefined && event.shiftKey === true)) {
  147. if(!regexAlphaOnly.test(key)){
  148. event.preventDefault();
  149. return;
  150. }
  151. }
  152. }
  153. },
  154. numericOnly: function(event) {
  155. ALC.common.allowCharacters(this, event, 'numericonly');
  156. },
  157. alphaNumericOnly: function(event){
  158. ALC.common.allowCharacters(this, event, 'alphanumericonly');
  159. },
  160. shortProvince: function(province){
  161. switch (province){
  162. case "Nova Scotia":
  163. return Granite.I18n.get("NS");
  164. case "New Brunswick":
  165. return Granite.I18n.get("NB");
  166. case "PEI":
  167. return Granite.I18n.get("PE");
  168. case "Newfoundland":
  169. return Granite.I18n.get("NL");
  170. default:
  171. return "No Atlantic Province Found";
  172. }
  173. },
  174. numberFormat: function(number, locale){
  175. if (locale === 'en-ca' || locale === 'en') {
  176. return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  177. } else {
  178. //FRENCH NUMBER
  179. return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
  180. }
  181. },
  182. priceFormat: function(number, locale, digits, dollarspan){
  183. var fixedDigits = isNaN(digits) ? 2 : digits,
  184. dollarSign;
  185. number = parseFloat(number).toFixed(fixedDigits);
  186. if(dollarspan === true){
  187. dollarSign = "<span class='dollarSign'>$</span>"
  188. } else {
  189. dollarSign = "$";
  190. }
  191.  
  192. if (locale === 'en-ca' || locale === 'en') {
  193. //ENGLISH PRICE Negative
  194. if (number < 0){
  195. number = number.replace(/[^0-9.]/g, "");
  196. return '-'+dollarSign + number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  197. }
  198. //ENGLISH PRICE
  199. return dollarSign + number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  200. } else {
  201. //FRENCH PRICE
  202. return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ").replace('.', ',') + " " + dollarSign;
  203. }
  204. },
  205. priceFormatHTML: function(number){
  206. var twoDecimalPlaces = (number % 1 != 0) ? parseFloat(Math.round(number * 100) / 100).toFixed(2) : number;
  207. return '<span>' + twoDecimalPlaces.toString().replace(/\B(?=(\d{3})+(?!\d))|(?=(\.))/g, "</span><span>") + "</span>";
  208. },
  209. getLang : function(){
  210. return Cookies.get('locale');
  211. },
  212. getShortLang : function() {
  213. return ALC.common.getLang() === "fr-ca" ? "fr" : "en";
  214. },
  215. getLocale : function() {
  216. return ALC.common.getLang() === "fr-ca" ? "fr_CA" : "en_CA";
  217. },
  218. isEditMode : function() {
  219. return (CQ.WCM !== null && typeof CQ.WCM === 'object' && typeof CQ.WCM.isEditMode === 'function' && CQ.WCM.isEditMode());
  220. },
  221. enableButton : function(targetButton) {
  222. targetButton.prop('disabled', false);
  223. },
  224. parseMomentDateFromFeed : function(rawDateString){
  225. // Assumes rawDateString is "\/Date(1435719600000-0300)\/" format
  226. var parsedDate = rawDateString.match(/\d+/g);
  227. return moment(parseInt(parsedDate[0])).utcOffset("-" + parsedDate[1]);
  228. },
  229. scrollTop: function(rootEl){
  230. $(rootEl).find('.scroll-top').on('click', function(e){
  231. e.preventDefault();
  232.  
  233. $("html, body").animate({ scrollTop: 0 }, "slow");
  234. });
  235. },
  236. breadcrumbsPathChange: function(pageID, pageTitle) {
  237. $(pageID).find('.currentPage').text(pageTitle);
  238. },
  239. getHashParams : function() {
  240.  
  241. var hashParams = {};
  242. var e,
  243. a = /\+/g, // Regex for replacing addition symbol with a space
  244. r = /([^&;=]+)=?([^&;]*)/g,
  245. d = function (s) { return decodeURIComponent(s.replace(a, " ")); },
  246. q = window.location.hash.substring(1);
  247.  
  248. while (e = r.exec(q))
  249. hashParams[d(e[1])] = d(e[2]);
  250.  
  251. return hashParams;
  252. },
  253. fetchNewTermsOfService: function() {
  254. var locale = Cookies.get("locale");
  255. if (!locale) locale = "en-ca";
  256. ALC.common.termsOfServicePromise = Q($.ajax({
  257. url : "/services/pam/GetTermsOfService?subJurisdictionId=1&locale=" + locale,
  258. dataType: "json"
  259. }));
  260. return ALC.common.termsOfServicePromise;
  261. },
  262. fetchTermsOfService: function() {
  263. if (!ALC.common.termsOfServicePromise) ALC.common.fetchNewTermsOfService();
  264. return ALC.common.termsOfServicePromise;
  265. },
  266. termsModalLaunch : function() {
  267. ALC.common.fetchTermsOfService().then(function(data) {
  268. var termsText = data.TermsOfService || "";
  269. $('#terms-modal .modal-body').html(termsText);
  270. $('#termsId').val(data.TermsOfServiceId);
  271. }).fail(function(errordata) {
  272. console.log("CAN'T GET TERMS: ", errordata);
  273. });
  274. },
  275. privacyModalLaunch : function() {
  276. var lang = (Cookies.get("locale") == "fr-ca") ? "fr" : "en";
  277. $.ajax({
  278. url : "/content/alc/" + lang + "/legal/privacy-policy.infinity.json",
  279. success : function(data){
  280. var policyText = data['jcr:content']['privacyPolicy'].text;
  281. $('#privacy-modal .modal-body').html(policyText);
  282. },
  283. error : function(errordata){
  284. console.log("CAN'T GET PRIVACY POLICY: ", errordata);
  285. }
  286. });
  287. },
  288. getQueryParameters : function(str) {
  289. return (str || document.location.search).replace(/(^\?)/,'').split("&").map(function(n){return n = n.split("="),this[n[0]] = n[1],this}.bind({}))[0];
  290. },
  291. fetchNewUserDashboard : function() {
  292. var dashboardAjax = function(){
  293. return $.ajax({
  294. url: "/services/pam/Dashboard",
  295. dataType: "json",
  296. cache: false
  297. });
  298. };
  299.  
  300. ALC.common.dashboardPromise = Q(dashboardAjax()).then(function(data){
  301. if(data.error_code === 500 || data.error_code === 408){
  302. // Add a one-time retry in the event the dashboard call fails
  303. return Q(dashboardAjax());
  304. }
  305. return data;
  306. });
  307. return ALC.common.dashboardPromise;
  308. },
  309. fetchUserDashboard : function(){
  310. if (!ALC.common.dashboardPromise) ALC.common.fetchNewUserDashboard();
  311. return ALC.common.dashboardPromise;
  312. },
  313.  
  314. /**
  315. * Updates the data-verify-url data attr or returns the users login+verified status.
  316. *
  317. * @param {object} dashboard - The expectation is that this will be
  318. * a dashboard object retrieved from a fetchUserDashboard call.
  319. *
  320. * @param {jQuery object} $linkEl - A jQuery wrapped <a> element
  321. * If this parameter is included, then the function will update
  322. * the element's data attr accordingly. If it isn't included, then
  323. * the function will return the state (for a knockout bind to use)
  324. * (Optional)
  325. */
  326. verifyLink : function(dashboard, $linkEl){
  327. var userLimitStatus,
  328. userLimitOnly;
  329. if (!dashboard || !ALC.UserInfo.isLoggedIn()) {
  330. userLimitStatus = 'GUEST';
  331. } else if (dashboard.IsAgeVerified === false){
  332. userLimitStatus = 'REVERIFY';
  333. } else if (dashboard.IsAgeVerified === true) {
  334. if (dashboard.ExclusionType && dashboard.ExclusionType != "NotExcluded"){
  335. userLimitStatus = "EXCLUDED";
  336. } else {
  337. userLimitStatus = null;
  338. }
  339. } else {
  340. userLimitStatus = 'GUEST';
  341. }
  342.  
  343. if ($linkEl) {
  344. userLimitOnly = $linkEl.attr('data-verify-only');
  345. if (!userLimitStatus) {
  346. $linkEl.removeAttr('data-verify-url');
  347. if(userLimitOnly){
  348. $linkEl.removeAttr('data-verify-only');
  349. }
  350. } else {
  351. if(userLimitOnly){
  352. if(userLimitOnly.indexOf(userLimitStatus) === -1){
  353. $linkEl.removeAttr('data-verify-url');
  354. } else {
  355. $linkEl.attr('data-verify-url', userLimitStatus);
  356. }
  357. $linkEl.removeAttr('data-verify-only');
  358. } else {
  359. $linkEl.attr('data-verify-url', userLimitStatus);
  360. }
  361. }
  362. }
  363.  
  364. return userLimitStatus;
  365. },
  366. launchLoginModal : function(){
  367. if (typeof NativeApp === 'object' && NativeApp !== null && typeof NativeApp.login === 'function') {
  368. NativeApp.login();
  369. return false;
  370. }
  371. return ALC.Modal.showModal({
  372. id: "modal-login",
  373. onShow: function() {
  374. if(ALC.common.sessionStorage.getItem('sessionExpires', true)) {
  375. $('.modal-login').find('.account-timeout').removeClass('hidden');
  376. ALC.common.sessionStorage.removeItem('sessionExpires', true);
  377. }
  378. if(ALC.common.sessionStorage.getItem('sessionError', true)) {
  379. $('.modal-login').find('.session-error').removeClass('hidden');
  380. ALC.common.sessionStorage.removeItem('sessionError', true);
  381. }
  382. //iOS fix
  383. if ( isMobileSafari() ) {
  384. //set modal to have absolute positioning rather than Fixed for iOS/Safari combo
  385. $(".modal-login").css("position","absolute");
  386. //all other elements need to be hidden
  387. $("body > :not(.modal-login)").hide();
  388. $(window).trigger("resize");
  389. }
  390. },
  391. onHidden: function() {
  392. $('.modal-login').find('.account-timeout, .session-error').addClass('hidden');
  393. if(ALC.common.sessionStorage.getItem('sessionExpires', true)) {
  394. ALC.common.sessionStorage.removeItem('sessionExpires', true);
  395. }
  396. if(ALC.common.sessionStorage.getItem('sessionError', true)) {
  397. ALC.common.sessionStorage.removeItem('sessionError', true);
  398. }
  399. //iOS fix
  400. if ( isMobileSafari() ) {
  401. //all other elements shown again
  402. $("body > :not(.modal-login)").show();
  403. $(window).trigger("resize");
  404. }
  405. }
  406. });
  407. },
  408. alcLogin : function(email, password, componentRoot, reloadPage, mobileapp) {
  409. function requestLogin(loginData) {
  410. Q(mobileapp || loginRequest(loginData))
  411. .then(checkLoginResponseMessage)
  412. .then(promoteAnonymousCartRequest)
  413. .then(reloadPageOnSuccess);
  414. }
  415. var loginRequest = function(loginData) {
  416. return Q($.ajax({
  417. type: 'POST',
  418. dataType: 'json',
  419. contentType: "application/json",
  420. url:'/services/pam/Login',
  421. data: loginData
  422. }));
  423. };
  424. var checkLoginResponseMessage = function(response) {
  425. if (response.error_code) {
  426. loginFail(response.message || response.MessageCode || Granite.I18n.get('Login Error'));
  427. // AJAX was successful but service threw an error
  428. throw response;
  429. } else {
  430. // if player has Post-Exclusion Reinstatement flag set, redirect to self-exclusion-reinstatement video page
  431. if ($.inArray("MUST_ACCEPT_EXCLUSION_EXPIRE", response.Player.playerStateFlag) !== -1) {
  432. ALC.common.sessionStorage.setItem('REVERIFY_URL',ALC.constants.CONTENT_ROOT + ALC.common.getShortLang() + '/self-exclusion-reinstatement.html');
  433. }
  434. }
  435. };
  436. var promoteAnonymousCartRequest = function() {
  437. var anonCartId = Cookies.get('AnonymousCartId');
  438. if (!anonCartId) return true;
  439. return Q($.ajax({
  440. type: 'POST',
  441. url: '/services/cart/PromoteAnonymousCart?AnonCartId=' + anonCartId,
  442. contentType: 'application/json'
  443. })).then(function(response) {
  444. if (response.error_code) {
  445. // AJAX was successful but service threw an error
  446. if(!mobileapp){
  447. promoteAnonymousCartFail(response.error_code);
  448. }
  449. throw response;
  450. } else {
  451. Cookies.remove('AnonymousCartId', { path: '/' }, {domain: 'alc.ca'});
  452. return response;
  453. }
  454. });
  455. };
  456. var promoteAnonymousCartFail = function(err) {
  457. $('.modal-body, .modal-header').addClass('hidden');
  458. $('#promote-anonymous-cart-alert').removeClass('hidden').insertAfter('.modal-header');
  459. };
  460. var loginFail = function(err) {
  461. $(componentRoot).find('.wrong-credentials').removeClass('hidden').html('<div class="error-message-content">' + $("<textarea/>").html(err).text() + '</div>');
  462. };
  463. var reloadPageOnSuccess = function() {
  464.  
  465. if ($('#page-login').length) {
  466. window.location.href = decodeURIComponent(ALC.common.getQueryParameters().redirectUrl);
  467. } else if (ALC.common.sessionStorage.getItem('sessionReturnURL')) {
  468. var returnURL = ALC.common.sessionStorage.getItem('sessionReturnURL');
  469. ALC.common.sessionStorage.removeItem('sessionReturnURL');
  470. window.location = returnURL;
  471. } else if (ALC.common.sessionStorage.getItem('REVERIFY_URL')) {
  472. var reverifyUrl = ALC.common.sessionStorage.getItem('REVERIFY_URL');
  473. ALC.common.sessionStorage.removeItem('REVERIFY_URL');
  474. window.location.href = reverifyUrl;
  475. } else if (reloadPage) {
  476. window.location.reload(true);
  477. }
  478. };
  479.  
  480. var geoRequestLogin = function (geoData) {
  481. var geoLocation = {
  482. IpAddress : JSON.parse(geoData).IpAddress,
  483. GeoLocation: JSON.parse(geoData)
  484. };
  485.  
  486. // Get User Credentials
  487. var userCredentials = {
  488. EmailUserName: email,
  489. Password: password,
  490. AuditData : geoLocation
  491. };
  492.  
  493. if (Cookies.get("Referrer")) {
  494. userCredentials.Referrer = Cookies.get("Referrer");
  495. }
  496. var userCredentialsJSON = JSON.stringify(userCredentials);
  497. requestLogin(userCredentialsJSON);
  498. };
  499.  
  500. ALC.common.getIPGeolocation()
  501. .then(function(data){
  502. geoRequestLogin(data);
  503. })
  504. .fail(function (error) {
  505. loginFail("Geolocation Failed");
  506. });
  507. },
  508. alcLogout : function(redirecturl){
  509. var userCookies = ["PlayerCardId","LoginTime","CartHandle","AnonymousCartId","WalletId","locale","AuthTokenExpires","AuthSignature","InactivitySeconds","SessionSignature","Province","NickName", "LastActivity"];
  510. var endSession = function(){
  511. //Clear cookies/data before calling BE endSession service
  512. ALC.UserInfo.isLoggedIn(false);
  513. for (var i = 0; i < userCookies.length; ++i) {
  514. Cookies.remove(userCookies[i], { path: '/', domain: '.alc.ca'});
  515. }
  516. ALC.userUrchinTracking.removeUTMString();
  517.  
  518. return Q($.ajax({
  519. url: '/services/pam/EndSession',
  520. type: 'POST'
  521. }).then(function(response){
  522. if(response !== "success"){
  523. throw response;
  524. }
  525. return response;
  526. }));
  527. };
  528.  
  529. endSession().then(function(){
  530. if(redirecturl) {
  531. window.location.href = redirecturl;
  532. }
  533.  
  534. if(typeof NativeApp === 'object'){
  535. NativeApp.logout();
  536. }
  537. }).fail(function(error){
  538. console.error('endSession() =>', error);
  539. });
  540. },
  541. ticketsSubmit: function( ticketsArr ){
  542. Q( ALC.common.packageTicketsJSON( ticketsArr ) )
  543. .then( ALC.common.sendToCart )
  544. .then( ALC.common.handleCartResponse )
  545. .fail( ALC.common.handleSubmitFail );
  546. },
  547. lookupBetTypeId : function(jackpotId, betType) {
  548. switch(jackpotId){
  549. case ALC.constants.DAILYGRAND_JPID : // Daily Grand
  550. switch(betType){
  551. case "CBO5" :
  552. return "105";
  553. default:
  554. return "100";
  555. }
  556. case ALC.constants.LOTTOMAX_JPID : // Lotto Max
  557. switch(betType){
  558. case "CBO6" :
  559. return "106";
  560. case "CBO8" :
  561. return "108";
  562. case "CBO9" :
  563. return "109";
  564. default :
  565. return "100";
  566. }
  567. case ALC.constants.LOTTO649_JPID : // Lotto 6/49
  568. switch(betType){
  569. case "CBO5" :
  570. return "105";
  571. case "CBO7" :
  572. return "107";
  573. case "CBO8" :
  574. return "108";
  575. case "CBO9" :
  576. return "109";
  577. default :
  578. return "100";
  579. }
  580. case ALC.constants.KENOATLANTIC_JPID : // Keno-Atlantic
  581. switch(betType){
  582. case "2Spot" :
  583. return "102";
  584. case "3Spot" :
  585. return "103";
  586. case "4Spot" :
  587. return "104";
  588. case "5Spot" :
  589. return "105";
  590. case "6Spot" :
  591. return "106";
  592. case "7Spot" :
  593. return "107";
  594. case "8Spot" :
  595. return "108";
  596. case "9Spot" :
  597. return "109";
  598. case "10Spot" :
  599. return "110";
  600. default :
  601. return "100";
  602. }
  603. default :
  604. return "100";
  605. }
  606. },
  607. getCombinationName : function(combination){
  608. if(typeof combination === "string"){
  609. return Granite.I18n.get("Combination - {0}", [parseInt(combination.slice(3), 10)])
  610. }
  611. },
  612. distributeAddons : function(tickets, addons, index) {
  613. var fatTickets = addons % tickets,
  614. commonNumber = Math.floor(addons/tickets);
  615. return (index < fatTickets) ? commonNumber + 1 : commonNumber;
  616. },
  617. packageTicketsJSON: function(response){
  618. var ItemsObj = [];
  619.  
  620. $(response.itemsConfig.games).each(function(index){
  621. var addonsObj = this.AddOns,
  622. itemsObj = this.Items,
  623. totalCost = 0,
  624. jackpotId = String(itemsObj.JackpotId),
  625. jackpotName = String(itemsObj.JackpotName),
  626. inPerpetuity = Boolean(this.Subscribe),
  627. advanceDraws = parseInt(this.AdvanceDraws);
  628.  
  629. $(itemsObj.Numbers).each(function(index){
  630. var addonsCost = 0;
  631. if( addonsObj ){
  632. var AddOns = $.map(addonsObj, function(data) {
  633. var count = ALC.common.distributeAddons(itemsObj.Numbers.length, parseInt(data.count), index),
  634. cost = parseInt(data.cost);
  635. if(count){
  636. addonsCost += count * cost;
  637. }
  638. return {
  639. "AddonName": String(data.name),
  640. "Count": count,
  641. "Numbers": "",
  642. "Cost": count * cost,
  643. "UnitCost": cost
  644. };
  645. });
  646. }
  647.  
  648. var Panels = [],
  649. panelNumbers = this[0].toString(),
  650. betType = this[1].toString(),
  651. ticketCost = parseInt(this[2]),
  652. quickPicks = parseInt(this[3]),
  653. totalCost = (addonsCost + ticketCost)*advanceDraws,
  654. panel = {
  655. "Numbers": panelNumbers,
  656. "BetType": betType,
  657. "QuickPicks": quickPicks,
  658. "CostPerDraw": ticketCost + addonsCost,
  659. "CostBasis": ticketCost,
  660. "ComboBet": ""
  661. };
  662.  
  663. Panels.push(panel);
  664. //Daily Grand -- Only add if NOT a combo play
  665. if (jackpotName === "DailyGrand" && this[1].toString().substring(0,3) !== "CBO"){
  666. var grandNumber = {
  667. "Numbers": this[4],
  668. "BetType":this[1].toString(),
  669. "QuickPicks":(quickPicks) ? 1 : 0,
  670. "CostPerDraw":0,
  671. "CostBasis":0,
  672. "ComboBet":""
  673. };
  674. Panels.push(grandNumber);
  675. }
  676.  
  677. var subscriptionItem = {
  678. "SubscriptionItem":{
  679. "LottoPanelsContainer": {
  680. "JackpotId": jackpotId,
  681. "Multiplier": false,
  682. "MidDay":false,
  683. "Panels": Panels
  684. },
  685. "AddonPanelsContainer": {
  686. "AddonsCostPerDraw": addonsCost,
  687. "Panels": AddOns
  688. },
  689. "PlayerGroupId": null,
  690. "JackpotId": jackpotId,
  691. "NumDraws": advanceDraws,
  692. "InPerpetuity": inPerpetuity,
  693. "TotalCost": totalCost,
  694. "JackpotName": jackpotName,
  695. "BetTypeId": ALC.common.lookupBetTypeId(itemsObj.JackpotId, betType),
  696. "BetTypeCost": ticketCost,
  697. "CostPerDraw": ticketCost + addonsCost
  698. }
  699. };
  700. ItemsObj.push(subscriptionItem);
  701. });
  702.  
  703. });
  704.  
  705. ALC.common.gaECommerce.addToCartItems = ItemsObj;
  706.  
  707. var itemsJSON = JSON.stringify({"Items": ItemsObj});
  708.  
  709. return itemsJSON;
  710. },
  711.  
  712. sendToCart : function( itemsJSON ){
  713. return Q($.ajax({
  714. url :'/services/cart/AddItemsToCart',
  715. data : itemsJSON,
  716. dataType: 'json',
  717. contentType: "application/json",
  718. type: 'POST'
  719. }));
  720. },
  721.  
  722. handleCartResponse : function(response) {
  723. if(response.error_code) {
  724. throw response;
  725. } else {
  726. ALC.common.gaECommerce.addToCart(ALC.common.gaECommerce.createProductsList(ALC.common.gaECommerce.addToCartItems));
  727. ALC.common.gaECommerce.addToCartItems = null;
  728.  
  729. var locale = locale || ALC.common.getShortLang();
  730. window.location = ALC.constants.CONTENT_ROOT + locale + ALC.constants.CART_PATH + '?Updated=' + new Date().getTime();
  731. }
  732. },
  733.  
  734. gaECommerce : {
  735. productImpression : function(products) {
  736. dataLayer.push({
  737. 'ecommerce' : {
  738. 'detail' : {
  739. 'products' : products
  740. }
  741. }
  742. });
  743. },
  744. addToCartItems : null,
  745. createProductsList : function(items) {
  746. var products = [];
  747.  
  748. items.forEach(function(ticket){
  749. products.push(
  750. {
  751. 'name': ticket.SubscriptionItem.JackpotName,
  752. 'id': ticket.SubscriptionItem.JackpotId,
  753. 'price': ticket.SubscriptionItem.BetTypeCost/100,
  754. 'brand': ticket.SubscriptionItem.JackpotName,
  755. 'category': ALC.common.gaECommerce.lookUpGTMCategory(ticket.SubscriptionItem.JackpotName),
  756. 'quantity': ticket.SubscriptionItem.NumDraws
  757. }
  758. );
  759. ticket.SubscriptionItem.AddonPanelsContainer.Panels.forEach(function(addon){
  760. products.push(
  761. {
  762. 'name': addon.AddonName,
  763. 'id': ALC.common.gaECommerce.lookUpGTMAddonId(addon.AddonName),
  764. 'price': addon.UnitCost/100,
  765. 'brand': addon.AddonName,
  766. 'category': ALC.common.gaECommerce.lookUpGTMCategory(addon.AddonName),
  767. 'quantity': addon.Count * ticket.SubscriptionItem.NumDraws
  768. }
  769. );
  770. });
  771. });
  772.  
  773. var productsCollection = products.reduce(function(collection, product){
  774. if(!collection[product.name]){
  775. collection[product.name] = product;
  776. } else {
  777. collection[product.name].quantity += product.quantity;
  778. }
  779. return collection;
  780. }, Object.create(null));
  781.  
  782. products.length = 0;
  783. Object.keys(productsCollection).forEach(function(key){
  784. products.push(productsCollection[key]);
  785. });
  786.  
  787. return products;
  788. },
  789. addToCart : function(products) {
  790. if(!products.length) return;
  791.  
  792. dataLayer.push({
  793. 'event': 'addToCart',
  794. 'ecommerce': {
  795. 'currencyCode': 'CAD',
  796. 'add': {
  797. 'products': products
  798. }
  799. }
  800. });
  801. },
  802. removeFromCart : function(products) {
  803. if(!products.length) return;
  804.  
  805. dataLayer.push({
  806. 'event': 'removeFromCart',
  807. 'ecommerce': {
  808. 'currencyCode': 'CAD',
  809. 'add': {
  810. 'products': products
  811. }
  812. }
  813. });
  814. },
  815. cartCheckout : function(products) {
  816. if(!products.length) return;
  817.  
  818. dataLayer.push({
  819. 'event': 'checkout',
  820. 'ecommerce': {
  821. 'checkout': {
  822. 'actionField': {
  823. 'step': 1,
  824. 'option': 'Wallet'
  825. },
  826. 'products': products
  827. }
  828. }
  829. });
  830. },
  831. cartConfirmation : function(order, products) {
  832. if(!products.length) return;
  833.  
  834. dataLayer.push({
  835. 'event': 'purchase',
  836. 'ecommerce': {
  837. 'purchase': {
  838. 'actionField': {
  839. 'id': order.PurchaseId,
  840. 'revenue': (order.TotalCost/100).toFixed(2)
  841. },
  842. 'products': products
  843. }
  844. }
  845. });
  846. },
  847. lookUpGTMCategory : function(name){
  848. switch(name) {
  849. case 'Lotto649' :
  850. case 'LottoMax' :
  851. case 'Atlantic 49' :
  852. case 'Tag' :
  853. case 'Bucko' :
  854. case 'SalsaBingo' :
  855. case 'KenoAtlantic' :
  856. case 'DailyGrand' :
  857. case 'Twist' :
  858. return 'Lottery';
  859. default :
  860. return '';
  861. }
  862. },
  863. lookUpGTMAddonId : function(name){
  864. switch(name) {
  865. case 'Atlantic 49' :
  866. return '6';
  867. case 'Tag' :
  868. return '9';
  869. case 'Twist' :
  870. return '3';
  871. default :
  872. return '';
  873. }
  874. }
  875. },
  876.  
  877.  
  878.  
  879. handleSubmitFail : function(error){
  880. console.log("Fail to submit to cart:", error);
  881. ALC.common.enableButton($('button[data-action="addtocart"]'));
  882. },
  883. getSubscriptionDraws : function(gameid) {
  884. switch(gameid) {
  885. case ALC.constants.ATLANTIC49_JPID : // atlantic-49 ex 17
  886. return 2*4;
  887. case ALC.constants.BUCKO_JPID : // bucko ex 20
  888. return 7*4;
  889. case ALC.constants.KENOATLANTIC_JPID : // kenoatlantic ex 18
  890. return 7*4;
  891. case ALC.constants.LOTTO649_JPID : // lotto-649 ex 15
  892. return 2*4;
  893. case ALC.constants.LOTTOMAX_JPID : // lotto-max ex 16
  894. return 1*4;
  895. case ALC.constants.POKERLOTTO_JPID : // poker-lotto ex 23
  896. return 7*4;
  897. case ALC.constants.SALSABINGO_JPID : // salsa-bingo ex 22
  898. return 7*4;
  899. case ALC.constants.DAILYGRAND_JPID : // daily-grand ex 21
  900. return 2*4;
  901. default :
  902. return 1;
  903. };
  904. },
  905. getParameterByName : function(name, url) {
  906. if (!url) url = window.location.href;
  907. name = name.replace(/[\[\]]/g, "\\$&");
  908. var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
  909. results = regex.exec(url);
  910. if (!results) return null;
  911. if (!results[2]) return '';
  912. return decodeURIComponent(results[2].replace(/\+/g, " "));
  913. },
  914. QueryStringToJSON : function(qs) {
  915. qs = qs || location.search.slice(1);
  916.  
  917. var pairs = qs.split('&');
  918. var result = {};
  919. pairs.forEach(function(pair) {
  920. var pair = pair.split('=');
  921. var key = pair[0];
  922. var value = decodeURIComponent(pair[1] || '');
  923.  
  924. if( result[key] ) {
  925. if(result[key].constructor === Array) {
  926. result[key].push( value );
  927. } else {
  928. result[key] = [ result[key], value ];
  929. }
  930. } else {
  931. result[key] = value;
  932. }
  933. });
  934.  
  935. return JSON.parse(JSON.stringify(result));
  936. },
  937. padDigits : function(number, digits) {
  938. return Array(Math.max(digits - String(number).length + 1, 0)).join(0) + number;
  939. },
  940. formatPrizeNumber: function(number) {
  941. return number.slice(0, -2) + '-' + number.slice(-2);
  942. },
  943. validationUtils:{
  944. /**
  945. * Validate postal code against Atlantic province prefixes. If a spefic province is selected then it will be used instead
  946. */
  947. postalCode: function(value, requirements){
  948. var postalValue = ALC.common.multiFieldUtils.concatMultiField(requirements, '', true);
  949. var provinces = {'NL' : 'A', 'NS' : 'B', 'PE' : 'C', 'NB' : 'E'};
  950. var postalPrefix = ($('#province').val()) ? provinces[$('#province').val()] : 'ABCE';
  951. var rxString = '^['+postalPrefix+'][0-9][ABCEGHJKLMNPRSTVWXYZ][0-9][ABCEGHJKLMNPRSTVWXYZ][0-9]';
  952. var validPostalRX = new RegExp( rxString, 'i' );
  953. return validPostalRX.test(postalValue);
  954. },
  955. /**
  956. * Opposite of built-in Equalto validator.
  957. * @param {string} requirements - set on the validator data attr
  958. * requirements starting with # will use the value of the element with that id
  959. * otherwise, requirements are used directly as the value to compare against
  960. *
  961. * Updated functionality to do a 'fuzzy' match that converts everything to lowercase before comparing
  962. */
  963. notEqualto: function(value, requirements){
  964. if (requirements.charAt(0) === '#'){
  965. return $(requirements).toArray()
  966. .every( function(elem) {
  967. return $(elem).val().toLowerCase() !== value.toLowerCase();
  968. });
  969. }else {
  970. return value.toLowerCase() !== requirements.toLowerCase();
  971. }
  972. },
  973. /**
  974. * Parsley has a built-in phone validator, but we have specific requirements:
  975. * 1. Merge three separate input fields and validate as one string
  976. * 2. SGI has the following field validation that must be duplicated on the FE:
  977. * - The First two "exchanges" can't be 0 or 1 (Essentially the 1st and 4th character can't be 0 or 1)
  978. */
  979. phoneNumber: function(value, requirements) {
  980. var phoneValue = ALC.common.multiFieldUtils.concatMultiField(requirements);
  981. var rxString = /^[2-9]\d{2}[2-9]\d{6}$/;
  982. return rxString.test(phoneValue);
  983. },
  984. checkPassword: function(password, requirements){
  985. var rx = {
  986. number: /[0-9]/,
  987. lowerCase: /[a-z]/,
  988. upperCase: /[A-Z]/,
  989. full: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z!@#$%^&*()_+-=<>?,.|{}`~]{8,}$/
  990. };
  991. var errorMessage = $('.password-criteria').first().clone().removeClass('hidden');
  992. errorMessage.find('.psw-count').toggleClass('checked', password.length >= 8);
  993. errorMessage.find('.psw-num').toggleClass('checked', rx.number.test(password));
  994. errorMessage.find('.psw-lwr').toggleClass('checked', rx.lowerCase.test(password));
  995. errorMessage.find('.psw-uppr').toggleClass('checked', rx.upperCase.test(password));
  996. $('[name='+requirements+']').parsley().options.passwordValidMessage = errorMessage[0].outerHTML;
  997. return rx.full.test(password);
  998. },
  999. nameWithSpecialChars: function(value) {
  1000. /*
  1001. * Name Regex:
  1002. * Valid: roman letters, fr-ca accented letters, hypens, spaces, apostrophes
  1003. * Invalid: Numbers, symbols, foreign characters (ie: asian, arabic)
  1004. */
  1005. var validNameRX = /^[-'’\sa-zàâçéèêëîïôûùüÿ]+$/i;
  1006. return validNameRX.test(value);
  1007. }
  1008. },
  1009. popoverDefaults : {
  1010. // For list of options check http://www.w3schools.com/bootstrap/bootstrap_ref_js_popover.asp
  1011. animation : true,
  1012. html : true,
  1013. container: 'body',
  1014. title: '',
  1015. trigger : "focus",
  1016. placement : function(el, triggerEl){
  1017. if($(window).width() >= 768) {
  1018. return "right";
  1019. } else {
  1020. return "bottom";
  1021. }
  1022. }
  1023. },
  1024. multiFieldUtils : {
  1025. arrayHasUndefined: function(arr){
  1026. return arr.indexOf("") >= 0;
  1027. },
  1028. concatMultiField : function(requirements, sep, allFieldsRequired){
  1029. /**
  1030. * Returns a concatenated string from all the fields in a multi-field-group
  1031. * allFieldsRequired = true will trigger an additional check to make sure all the fields have values. Returns false if there are undefined values
  1032. */
  1033. var separator = sep || '';
  1034. var fieldValues = $( '[data-multi-field="'+requirements+'"]' ).map(function() {
  1035. return $(this).val();
  1036. }).get();
  1037.  
  1038. if(allFieldsRequired && this.arrayHasUndefined(fieldValues)){
  1039. return false;
  1040. }else{
  1041. return fieldValues.join(separator);
  1042. }
  1043. },
  1044. multiFieldIsDirty : function(fieldGroup){
  1045. //Returns true if all the fields in the group have been blurred (using pristine vs dirty states)
  1046. var fieldsInGroup = $('[data-multi-field="'+fieldGroup+'"]').length;
  1047. var dirtyFieldsInGroup = $('[data-multi-field="'+fieldGroup+'"][data-validation-state="dirty"]').length;
  1048. return fieldsInGroup === dirtyFieldsInGroup;
  1049. },
  1050. clearPopover : function(multiFieldsGroup, triggerField){
  1051. //Only clear popover if entire multi-field group is blurred
  1052. setTimeout(function(){
  1053. if(!multiFieldsGroup.is(':focus')){
  1054. triggerField.popover('hide');
  1055. }
  1056. }, 10); //Delayed functions are undesirable but the focus event is only _nearly_ instantaneous after a blur when tabbing or clicking, so it has to be this way
  1057. }
  1058. },
  1059. parsleyValidation : (function() {
  1060. var isInitialized = false;
  1061. return {
  1062. init: function(formEls, validationOptions){
  1063. var initForm = function(formEl){
  1064. formEl.parsley({
  1065. errorClass: 'has-error',
  1066. successClass: 'has-success',
  1067. classHandler: function(el) {
  1068. // classes added on closest .form-group element
  1069. return el.$element.closest('.form-group');
  1070. },
  1071. errorsWrapper: '',
  1072. errorTemplate: '',
  1073. validationOptions: validationOptions
  1074. });
  1075. }
  1076. //Add support for handling an array of forms on one page or just one
  1077. if($.isArray(formEls)){
  1078. formEls.forEach(function(el){
  1079. initForm(el);
  1080. });
  1081. }else{
  1082. initForm(formEls);
  1083. }
  1084. if(!isInitialized){
  1085. isInitialized = true;
  1086. window.Parsley.on('field:success', function(fieldInstance) {
  1087. var elm = $(this.$element);
  1088. var targetElm = elm;
  1089. if(elm.closest('.validation-container').length){
  1090. //Conditional parent target class for fields like radio and checkbox that have hidden inputs with styled replacements
  1091. targetElm = elm.closest('.validation-container');
  1092. }
  1093. // This global callback will be called for any field that passes validation.
  1094. targetElm.popover("destroy");
  1095. });
  1096. window.Parsley.on('field:error', function(fieldInstance) {
  1097. // This global callback will be called for any field that fails validation.
  1098. var elm = $(this.$element);
  1099. var targetElm = elm;
  1100. var arrErrorMsg = targetElm.parsley().getErrorsMessages(fieldInstance);
  1101. var errorMsg = arrErrorMsg.join(';');
  1102. var content = errorMsg;
  1103.  
  1104. var popoverClass = 'error-popover';
  1105. var validationOptions = fieldInstance.parent.options.validationOptions;
  1106. var options = (validationOptions && validationOptions.popoverOptions) ? validationOptions.popoverOptions : {};
  1107.  
  1108. if(validationOptions){
  1109. if(validationOptions.extraMargins){
  1110. popoverClass += (elm.closest('.validation-container').length) ? ' extra-margin-group' : ' extra-margin';
  1111. }
  1112. if(validationOptions.modalPopover){
  1113. popoverClass += ' modal-popover';
  1114. }
  1115. }
  1116.  
  1117. //Conditional parent target class for fields like radio and checkbox that have hidden inputs with styled replacements
  1118. if(elm.closest('.validation-container').length){
  1119. targetElm = elm.closest('.validation-container');
  1120. }
  1121.  
  1122. if(targetElm.data && targetElm.data('bs.popover')){
  1123. //Element already has popover initialized -- check if message has changed
  1124. var popover = targetElm.data('bs.popover');
  1125.  
  1126. if(popover.options.content != content){
  1127. popover.options.content = content;
  1128. if(popover.$tip){
  1129. //Dynamically trigger a redraw of content for an active popup. Most of the positioning/calcuation stuff is repurposed from the original bootstrap/js/tooltip.js file
  1130. var pos, actualWidth, actualHeight, calculatedOffset;
  1131. var placement = typeof popover.options.placement == 'function' ?
  1132. popover.options.placement.call(popover, popover.$tip[0], popover.$element[0]) :
  1133. popover.options.placement;
  1134.  
  1135. popover.setContent();
  1136. popover.$tip.addClass(placement);
  1137. // Recalculate popover and tip positioning
  1138. pos = popover.getPosition();
  1139. actualWidth = popover.$tip[0].offsetWidth;
  1140. actualHeight = popover.$tip[0].offsetHeight;
  1141. calculatedOffset = popover.getCalculatedOffset(placement, pos, actualWidth, actualHeight);
  1142. popover.applyPlacement(calculatedOffset, placement);
  1143.  
  1144. }
  1145. }
  1146. }else{
  1147. if(elm.is('[data-multi-field]')){
  1148. options.trigger = 'manual';
  1149. }
  1150. //Popover not initialized
  1151. targetElm.popover(
  1152. $.extend({}, ALC.common.popoverDefaults, {
  1153. content: content,
  1154. template: '<div class="popover '+popoverClass+'" role="tooltip"><div class="arrow"></div><div class="popover-content"></div></div>'
  1155. }, options)
  1156. );
  1157. //Only show if the field is currently in focus
  1158. if(elm.is(':focus')){
  1159. targetElm.popover('show');
  1160. }
  1161. }
  1162. });
  1163.  
  1164. window.Parsley.on('field:validated', function(fieldInstance) {
  1165. var validationOptions = fieldInstance.parent.options.validationOptions;
  1166. //Submit button will only be enabled if the form is visible
  1167. if(!validationOptions || (validationOptions && !validationOptions.enableSubmit)){
  1168. var parentForm = fieldInstance.parent.$element,
  1169. submitBtn = parentForm.find('[type="submit"]'),
  1170. hasErrorClasses = parentForm.find('.has-error').length > 0;
  1171.  
  1172. var hasEmptyRequired = parentForm.find('input').prop('required', true).filter(function () {
  1173. return !this.value;
  1174. }).length > 0;
  1175.  
  1176. submitBtn.toggleClass('disabled', hasErrorClasses || hasEmptyRequired);
  1177. }
  1178. });
  1179.  
  1180. /**
  1181. * Multi-field extension for Parsley, which currently has no built-in support for this feature
  1182. * Uses the pristine vs. dirty concept from Angular JS to track/detect if a field has been 'touched'. Validation for the group shouldn't happen until all the fields are dirty
  1183. * Adds the ability to trigger the error popover from the focus event a non-trigger field and other manual popover show/clear functions
  1184. */
  1185. $('[data-multi-field]').each(function(){
  1186. var fieldGroup = $(this).data('multiField');
  1187. var multiFields = $('[data-multi-field="'+fieldGroup+'"]');
  1188. var triggerField = $('[data-multi-field="'+fieldGroup+'"][data-parsley-trigger]');
  1189.  
  1190. //Apply pristine field state to all fields by default
  1191. $(this).attr('data-validation-state', 'pristine');
  1192.  
  1193. $(this).on('focus', function(){
  1194. //Set field state to 'dirty' on focus
  1195. $(this).attr('data-validation-state', 'dirty');
  1196.  
  1197. //Check for and fire popover on trigger field
  1198. var targetElm = triggerField;
  1199. if(targetElm.data && targetElm.data('bs.popover')){
  1200. var popover = targetElm.data('bs.popover');
  1201. if(!popover.$tip || (popover.$tip && !popover.$tip.hasClass('in'))){
  1202. popover.show();
  1203. }
  1204. }
  1205. });
  1206.  
  1207. if(!this.hasAttribute('data-parsley-trigger')){
  1208. // Run validation on trigger field from any of the other fields in the group if all fields are dirty
  1209. $(this).on('change', function(){
  1210. if(ALC.common.multiFieldUtils.multiFieldIsDirty(fieldGroup)){
  1211. triggerField.parsley().validate();
  1212. }
  1213. });
  1214.  
  1215. $(this).on('blur', function(){
  1216. //Manual clearing of popover on blur
  1217. ALC.common.multiFieldUtils.clearPopover(multiFields, triggerField);
  1218. });
  1219. }else{
  1220. $(this).on('blur', function(){
  1221. // Automatically set all fields to dirty once the trigger field has been changed
  1222. multiFields.each(function(){
  1223. $(this).attr('data-validation-state', 'dirty');
  1224. });
  1225. //Manual clearing of popover on blur
  1226. ALC.common.multiFieldUtils.clearPopover(multiFields, triggerField);
  1227. });
  1228. }
  1229. });
  1230.  
  1231. // Equalto validation (such as 'Confirm Email') works in reverse
  1232. // if first input is edited/re-edited after Confirm input
  1233. $('[data-parsley-equalto]').each(function() {
  1234. var firstFieldId = $(this).attr('data-parsley-equalto');
  1235. var secondField = $(this);
  1236. $(firstFieldId).on('input', function() {
  1237. if ($(secondField).val()) {
  1238. $(secondField).parsley().validate();
  1239. }
  1240. });
  1241. });
  1242.  
  1243. //Generic validation/input helpers
  1244. $(document).on('input', '[data-autoadvance-after]', function (e) {
  1245.  
  1246. if ( $(this)[0].hasAttribute('data-validate-type') && $(this)[0].hasAttribute('pattern') ){
  1247. var regexPattern = '^' + $(this).attr('pattern') + '$';
  1248. var regexSpecialChars = new RegExp ( regexPattern );
  1249. if(regexSpecialChars.test(this.value) && $(this).val().length === $(this).data('autoadvanceAfter')) {
  1250. $(this).nextAll("input")[0].focus();
  1251. }
  1252. }else{
  1253. if($(this).val().length === $(this).data('autoadvanceAfter')) {
  1254. $(this).nextAll("input")[0].focus();
  1255. }
  1256. }
  1257. });
  1258. }
  1259.  
  1260. }
  1261. };
  1262.  
  1263. })(),
  1264. getUrlParameter: function(paramName) {
  1265. //gets all url parameters and returns the value of the paramters name passed in
  1266. var searchString = window.location.search.substring(1),
  1267. i,
  1268. val;
  1269.  
  1270. if (searchString.indexOf('?') !== -1) {
  1271. params = searchString.split("?")[1].split("&");
  1272. } else {
  1273. params = searchString.split("&");
  1274. }
  1275.  
  1276. for (i=0; i<params.length; i++) {
  1277. val = params[i].split("=");
  1278. if (val[0] === paramName) {
  1279. return val[1];
  1280. }
  1281. }
  1282.  
  1283. return null;
  1284. },
  1285. getMobileUserAgent: function(){
  1286. return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
  1287. },
  1288. /**
  1289. * HTML5 Geolocation API
  1290. *
  1291. * returns: a Q promise based on user's browser settings/choices regarding sharing of Geolocation data
  1292. */
  1293. getGeolocation: function(geoOptions){
  1294. var deferred = Q.defer();
  1295. var geoData = {
  1296. Latitude : "",
  1297. Longitude : ""
  1298. };
  1299. var options = geoOptions || {};
  1300. options.timeout = 5000;
  1301.  
  1302. function resolvePromise(){
  1303. deferred.resolve(geoData);
  1304. }
  1305. function getPositionSuccess(position) {
  1306. //Truncate geo values for SGI API if enableHighaccuracy flag isn't set
  1307. if(!options.enableHighAccuracy){
  1308. geoData.Latitude = position.coords.latitude.toString().substr(0,10);
  1309. geoData.Longitude = position.coords.longitude.toString().substr(0,10);
  1310. }else{
  1311. geoData.Latitude = position.coords.latitude.toString();
  1312. geoData.Longitude = position.coords.longitude.toString();
  1313. }
  1314. resolvePromise();
  1315. }
  1316. function getPositionFailure() {
  1317. resolvePromise();
  1318. return;
  1319. }
  1320.  
  1321. if (!navigator.geolocation) {
  1322. getPositionFailure();
  1323. } else {
  1324. navigator.geolocation.getCurrentPosition(getPositionSuccess, getPositionFailure, options);
  1325. }
  1326.  
  1327. // Trigger timeout manually since Edge doesn't trigger fail
  1328. setTimeout(getPositionFailure, options.timeout);
  1329.  
  1330. return deferred.promise;
  1331. },
  1332. geolocationDebug: {
  1333. //Debugging object allows QA/Devs to manually override Browser geolocation (lat/long) values
  1334. settings : {
  1335. enabled: false,
  1336. geoData:{
  1337. Latitude : "",
  1338. Longitude : "",
  1339. IpAddress: ""
  1340. }
  1341. },
  1342. setValues: function(latitude, longitude, ipAddress){
  1343. if(ALC.applicationProperties.enableDebugging == 'true'){
  1344. //Override is only availble in specific environments
  1345. this.settings.enabled = true;
  1346. this.settings.geoData.Latitude = latitude.toString().substr(0,10);
  1347. this.settings.geoData.Longitude = longitude.toString().substr(0,10);
  1348. this.settings.geoData.IpAddress = ipAddress;
  1349. }
  1350. }
  1351. },
  1352. getIP: function(forceIP){
  1353. var environment = ALC.applicationProperties.envName;
  1354. if(environment === 'sgiprod' && forceIP){
  1355. return Q($.ajax({
  1356. url: '/services/GetClientIp',
  1357. dataType: 'text',
  1358. cache: true
  1359. }));
  1360. }else if(environment !== 'sgiprod'){
  1361. return Q($.ajax({
  1362. url: 'https://api.ipify.org',
  1363. dataType: 'text',
  1364. cache: true
  1365. }));
  1366. }else{
  1367. return Q('');
  1368. }
  1369. },
  1370. convertLotto4WinningNumbers: function (lotto4WinningNumbers) {
  1371. //Lotto4 is a Digit game and comes with a single 0-9999 digit. We want to split up the numbers for display purposes.
  1372. return lotto4WinningNumbers[0].split("");
  1373. },
  1374. getIPGeolocation: function(geoOptions, forceIP) {
  1375. if(ALC.common.geolocationDebug.settings.enabled && ALC.applicationProperties.enableDebugging == 'true'){
  1376. //Override is only availble in specific environments
  1377. return Q.when(JSON.stringify(ALC.common.geolocationDebug.settings.geoData));
  1378. }
  1379.  
  1380. if(typeof NativeApp === 'object'){
  1381. return ALC.common.getIP(true).then(function(ipAddress){
  1382. var nativeGeoIP = {
  1383. Latitude: 45.2597798,
  1384. Longitude: -66.1090706,
  1385. IpAddress: ipAddress
  1386. };
  1387.  
  1388. return JSON.stringify(nativeGeoIP);
  1389. });
  1390. }
  1391.  
  1392. var options = geoOptions || {};
  1393. var geoPromises = [ALC.common.getGeolocation(options), ALC.common.getIP(forceIP)];
  1394.  
  1395. return Q.all(geoPromises).spread(function(geoData, ipData){
  1396. var geoIPData = {
  1397. IpAddress: ipData
  1398. };
  1399.  
  1400. if (options.enableHighAccuracy) {
  1401. geoIPData.latitude = geoData.Latitude;
  1402. geoIPData.longitude = geoData.Longitude;
  1403. } else {
  1404. geoIPData.Latitude = geoData.Latitude;
  1405. geoIPData.Longitude = geoData.Longitude;
  1406. }
  1407. return JSON.stringify(geoIPData);
  1408. });
  1409. },
  1410. getGameName: function(gameId){
  1411. switch(gameId){
  1412. case 'Lotto649' :
  1413. return Granite.I18n.get('LOTTO 6/49');
  1414. case 'Atlantic49' :
  1415. return Granite.I18n.get('Atlantic 49');
  1416. case 'DailyGrand' :
  1417. return Granite.I18n.get('DAILY GRAND');
  1418. case 'KenoAtlantic' :
  1419. return Granite.I18n.get('Keno Atlantic');
  1420. case 'LottoMax' :
  1421. return Granite.I18n.get('LOTTO MAX');
  1422. case 'SalsaBingo' :
  1423. return Granite.I18n.get('Salsa Bingo');
  1424. case 'AllLotto' :
  1425. return Granite.I18n.get('All Lotto Games');
  1426. case 'ScratchNWin' :
  1427. return Granite.I18n.get('All Scratch N\' Win Games');
  1428. case "Lotto4":
  1429. return Granite.I18n.get('LOTTO 4');
  1430. case 'PokerLotto' :
  1431. return Granite.I18n.get('POKER LOTTO');
  1432. default :
  1433. return Granite.I18n.get(gameId);
  1434. }
  1435. },
  1436. getCustomTranslation: function(key){
  1437. switch(key){
  1438. case 'All Lotto649 Winners' :
  1439. return Granite.I18n.get('All LOTTO 6/49 Winners');
  1440. case 'All Atlantic49 Winners' :
  1441. return Granite.I18n.get('All Atlantic 49 Winners');
  1442. case 'All DailyGrand Winners' :
  1443. return Granite.I18n.get('All DAILY GRAND Winners');
  1444. case 'All KenoAtlantic Winners' :
  1445. return Granite.I18n.get('All Keno Atlantic Winners');
  1446. case 'All LottoMax Winners' :
  1447. return Granite.I18n.get('All LOTTO MAX Winners');
  1448. case 'All SalsaBingo Winners' :
  1449. return Granite.I18n.get('All Salsa Bingo Winners');
  1450. case 'All Lotto4 Winners' :
  1451. return Granite.I18n.get('All LOTTO 4 Winners');
  1452. case 'All PokerLotto Winners' :
  1453. return Granite.I18n.get('All POKER LOTTO Winners');
  1454. default :
  1455. return Granite.I18n.get(key);
  1456. }
  1457. },
  1458. sessionStorageSupported: undefined,
  1459. sessionStorage: {
  1460. setItem: function(key, value, forceCookie){
  1461. if(!forceCookie && ALC.common.sessionStorage.checkSessionStorage()) {
  1462. window.sessionStorage.setItem(key, value);
  1463. } else {
  1464. Cookies.set(key, value, {path: '/', domain: 'alc.ca'});
  1465. }
  1466. },
  1467. getItem: function(key, forceCookie){
  1468. var keyValue;
  1469. if(!forceCookie && ALC.common.sessionStorage.checkSessionStorage()) {
  1470. keyValue = window.sessionStorage.getItem(key);
  1471. } else {
  1472. keyValue = Cookies.get(key);
  1473. keyValue = (keyValue !== undefined) ? keyValue : null;
  1474. }
  1475. return keyValue;
  1476. },
  1477. removeItem: function(key, forceCookie){
  1478. if(!forceCookie && ALC.common.sessionStorage.checkSessionStorage()) {
  1479. window.sessionStorage.removeItem(key);
  1480. } else {
  1481. Cookies.remove(key, { path: '/', domain: '.alc.ca'});
  1482. }
  1483. },
  1484. clear: function(keys, forceCookie){
  1485. if(!forceCookie && ALC.common.sessionStorage.checkSessionStorage()) {
  1486. if(keys instanceof Array){
  1487. keys.forEach(function(key){
  1488. ALC.common.sessionStorage.removeItem(key);
  1489. });
  1490. } else {
  1491. window.sessionStorage.clear();
  1492. }
  1493. } else {
  1494. if(keys instanceof Array){
  1495. keys.forEach(function(key){
  1496. Cookies.remove(key, { path: '/', domain: '.alc.ca'});
  1497. });
  1498. }
  1499. }
  1500. },
  1501. checkSessionStorage: function(){
  1502. var testKey = 'test',
  1503. storage = window.sessionStorage;
  1504.  
  1505. if(ALC.common.sessionStorageSupported === undefined){
  1506. try {
  1507. storage.setItem(testKey, '1');
  1508. storage.removeItem(testKey);
  1509. ALC.common.sessionStorageSupported = true;
  1510. } catch (error) {
  1511. ALC.common.sessionStorageSupported = false;
  1512. }
  1513. }
  1514. return ALC.common.sessionStorageSupported;
  1515. }
  1516. },
  1517. createAbsoluteURL: function(path) {
  1518. var a = document.createElement('a');
  1519. a.href = path;
  1520.  
  1521. return a.href;
  1522. },
  1523. detectKeyInObject: function(obj, key) {
  1524. var type = typeof key,
  1525. keyParts;
  1526.  
  1527. if(!obj || !key) return null;
  1528.  
  1529. if (type === 'string' || type === 'number') {
  1530. keyParts = String(key).replace(/\[(.*?)\]/g, function (m, keyPart) {
  1531. return '.' + keyPart.replace(/^['']|['']$/g, '');
  1532. }).split('.');
  1533. } else {
  1534. return null;
  1535. }
  1536.  
  1537. for (var i = 0; i < keyParts.length; i++) {
  1538. if (obj.hasOwnProperty(keyParts[i])) obj = obj[keyParts[i]];
  1539. else return null;
  1540. }
  1541.  
  1542. return obj;
  1543. }
  1544. }; //end of ALC.common
  1545.  
  1546.  
  1547. ALC.AjaxLoader = (function() {
  1548.  
  1549. /* CONSTANTS */
  1550. var initialTheta = 0; // The initial rotation angle, in degrees.
  1551. var thetaDelta = 5; // The amount to rotate the square about every 16.7 milliseconds, in degrees.
  1552. var defaultDelayTime = 750; // default time delay to initializing spinner after AJAX call is made.
  1553.  
  1554. var requestAnimationFrameID;
  1555. var ajaxLoader;
  1556.  
  1557. var doAnimation = function() {
  1558. if (ajaxLoader) {
  1559. ajaxLoader.setAttribute("transform", "rotate(" + ajaxLoader.currentTheta + ")"); // Rotate the widget by a small amount.
  1560. ajaxLoader.currentTheta += thetaDelta; // Increase the angle that the widget will be rotated to, by a small amount.
  1561. requestAnimationFrameID = requestAnimationFrame(doAnimation); // Call the doAnimation() function about 60 times per second (60 FPS), or about once every 16.7 milliseconds until cancelAnimationFrame() is called.
  1562. }
  1563. };
  1564.  
  1565. var initLoaderDimensions = function() {
  1566. var scrollPosition = window.scrollY || window.pageYOffset;
  1567. var viewportHeight = window.innerHeight;
  1568. var documentHeight = document.body.clientHeight + "px";
  1569.  
  1570. $("#ajaxLoaderContainer")
  1571. .css("height", documentHeight)
  1572. .find("svg");
  1573. };
  1574.  
  1575. var initLoader = function() {
  1576. var ajaxLoaderContainer = $("#ajaxLoaderContainer");
  1577.  
  1578. if (ajaxLoaderContainer.length > 0) {
  1579. ajaxLoaderContainer.show();
  1580. }
  1581. else {
  1582. var svgLoaderHtml = '<div id="ajaxLoaderContainer"><svg width="80px" height="80px" xmlns="http://www.w3.org/2000/svg" viewBox="-50 -50 100 100" preserveAspectRatio="xMidYMid"><rect id="ajaxLoaderBG" x="-50" y="-50" width="100" height="100" fill="none"></rect><circle id="ajaxLoader" cx="0" cy="0" r="30" stroke-dasharray="143.36281798666926 87.9645943005142" stroke="#d9534f" fill="none" stroke-width="10"><animateTransform attributeName="transform" type="rotate" values="0 0 0;180 0 0;360 0 0;" keyTimes="0;0.5;1" dur="1s" repeatCount="indefinite" begin="0s"></animateTransform></circle></svg></div>';
  1583.  
  1584. $(document.body).append(svgLoaderHtml);
  1585. }
  1586.  
  1587. initLoaderDimensions();
  1588. };
  1589.  
  1590. return {
  1591. /**
  1592. * @param {object}: options - loader config options
  1593. * options.noBlock: loader will not spawn the translucent gray bg to block the page if set to true
  1594. * options.size: pixel size of the loader (i.e. "100px")
  1595. * options.color: spinner color (i.e. "#FFFFFF")
  1596. * options.bgColor: background color of the loader (i.e. "#000000")
  1597. */
  1598. setOptions : function(options) {
  1599. if (!options) { return; }
  1600.  
  1601. if (options.noBlock) {
  1602. $("#ajaxLoaderContainer").css("height", 0);
  1603. }
  1604. if (options.size) {
  1605. var ajaxLoaderSVG = $("#ajaxLoaderContainer svg")[0];
  1606. if (ajaxLoaderSVG) {
  1607. ajaxLoaderSVG.setAttribute("width", options.size);
  1608. ajaxLoaderSVG.setAttribute("height", options.size);
  1609. }
  1610. }
  1611. if (options.color) {
  1612. ajaxLoader = ajaxLoader || document.getElementById("ajaxLoader");
  1613. ajaxLoader.setAttribute("stroke", options.color);
  1614. }
  1615. if (options.bgColor) {
  1616. var ajaxLoaderBG = document.getElementById("ajaxLoaderBG");
  1617. if (ajaxLoaderBG) {
  1618. ajaxLoaderBG.setAttribute("fill", options.bgColor);
  1619. }
  1620. }
  1621. },
  1622. ajaxRequestCount: 0,
  1623.  
  1624. start : function(options) {
  1625. var self = this;
  1626. var delayTime = (options && options.delayTime !== null) ? options.delayTime : defaultDelayTime;
  1627. self.delayTimer = setTimeout((function() {
  1628. initLoader();
  1629. if (options) {
  1630. self.setOptions(options);
  1631. }
  1632.  
  1633. if (!Modernizr.smil) {
  1634. // only do JS animation for IE
  1635. ajaxLoader = document.getElementById("ajaxLoader");
  1636. ajaxLoader.currentTheta = initialTheta; // The initial rotation angle to use when the animation starts, stored in a custom property.
  1637. requestAnimationFrameID = requestAnimationFrame(doAnimation); // Start the loop.
  1638. }
  1639. }), delayTime);
  1640. },
  1641.  
  1642. stop : function() {
  1643. clearTimeout(this.delayTimer);
  1644.  
  1645. var ajaxLoaderContainer = $("#ajaxLoaderContainer");
  1646.  
  1647. if (ajaxLoaderContainer.length > 0) {
  1648. ajaxLoaderContainer.hide();
  1649. }
  1650.  
  1651. if (requestAnimationFrameID) {
  1652. cancelAnimationFrame(requestAnimationFrameID);
  1653. }
  1654. }
  1655. };
  1656. })();
  1657.  
  1658. /**
  1659. * Global AJAX defaults
  1660. * Unless the they are specifically defined in 'local' $.ajax() calls,
  1661. * the options below will replace the AJAX defaults for ALL AJAX calls
  1662. */
  1663. (function($){
  1664. $.ajaxSetup({
  1665. cache: false,
  1666. error: function(response){
  1667. var responseData;
  1668.  
  1669. try{
  1670. responseData = JSON.parse(response);
  1671. }catch(err){
  1672. responseData = response;
  1673. }
  1674. if(response.readyState == 0 && response.status == 0){
  1675. window.location = ALC.constants.CONTENT_ROOT + ALC.common.getShortLang() + ALC.constants.AEM_DISPATCHER_FAILOVER_PATH;
  1676. return;
  1677. }
  1678. },
  1679. success: function(response){
  1680. if(response.error_code === 401 && response.MessageCode === "SessionExpired"){
  1681. ALC.common.sessionStorage.setItem('sessionExpires', true, true);
  1682. ALC.common.sessionStorage.setItem('sessionReturnURL', window.location.href);
  1683. ALC.common.alcLogout(ALC.constants.CONTENT_ROOT + ALC.common.getShortLang() + '.html');
  1684. }
  1685. }
  1686. });
  1687. })(jQuery);
  1688.  
  1689. // AJAX Loader
  1690. (function($){
  1691. var clearAjaxLoader = function(){
  1692. ALC.AjaxLoader.stop();
  1693. if (ALC.activityTimer) {
  1694. ALC.activityTimer.refreshActivityCookie();
  1695. }
  1696. };
  1697.  
  1698. $(document).ajaxSend(function() {
  1699. if (ALC.AjaxLoader.ajaxRequestCount < 1) {
  1700. ALC.AjaxLoader.start();
  1701. }
  1702. ALC.AjaxLoader.ajaxRequestCount++;
  1703. });
  1704. $(document).ajaxComplete(function() {
  1705. ALC.AjaxLoader.ajaxRequestCount--;
  1706. if (ALC.AjaxLoader.ajaxRequestCount <= 0) {
  1707. clearAjaxLoader();
  1708. }
  1709. });
  1710. })(jQuery);
  1711.  
  1712.  
  1713.  
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.  
  1721.  
  1722.  
  1723.  
  1724. -------------------------------------------
  1725. LOGIN MODAL Mobile
  1726. -------------------------------------------
  1727. $(window).resize(function(){
  1728. $("#page-en").css(“width”,“100vh”);
  1729. $("#page-en").css(“height”,“100vh”);
  1730. });
  1731.  
  1732.  
  1733. SIGN IN link (button, uggh...)
  1734. body > header.visible-xs.navbar-fixed-top.mobile.header-en > div.nav-right-side.clearfix > div.account-holder
  1735. //*[@id="page-en"]/header[2]/div[2]/div[2]
  1736. <div class="account-holder">
  1737. <button class="account-login dropdown-toggle sign-in-circle link-button" data-toggle="dropdown" type="button" data-bind="visible : !isLoggedIn()" aria-expanded="false"><span class="button-text-underline">Sign In</span> <span class="material-icons md-18">lock</span>
  1738. </button>
  1739. </div>
  1740.  
  1741.  
  1742. Login Modal body > div.parbase.modal-base.section.modal-login
  1743.  
  1744. <div class="parbase modal-base section modal-login" style="width:100%"><div id="modal-login" class="alc-modal modal-login login modal fade in" tabindex="-1" role="dialog" aria-hidden="false" style="z-index: 1040; display: block; width: 100%; padding-left: 0px;">
  1745. <div class="modal-dialog" style="width:100%; height:100%">
  1746. <div class="modal-content">
  1747. <div class="modal-header">
  1748. <button type="button" class="close close-modal" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  1749. </div>
  1750. <div class="modal-body state-login">
  1751. <div class="container-fluid">
  1752. <div class="row">
  1753. <div class="col-xs-12 col-sm-6 signin-form">
  1754. <div class="modal-title">
  1755. <h2>Sign In</h2>
  1756. </div>
  1757. <div class="account-timeout error-message hidden">
  1758. <p><strong>Sorry your session has timed out.</strong></p>
  1759. <p>Please sign in and try again.</p>
  1760. </div>
  1761. <div class="session-error error-message hidden">
  1762. <p><strong>Sorry, there was an error with your session</strong></p>
  1763.  
  1764. </div>
  1765. <div class="wrong-credentials hidden error-message"></div>
  1766. <form id="login-submit-form" novalidate="">
  1767. <div class="form-group">
  1768. <label for="exampleInputEmail1">Email</label>
  1769. <input type="text" class="form-control" id="exampleInputEmail1" placeholder="Email" required="" data-parsley-required-message="Enter Email address (myname@emaildomain.ca)">
  1770. </div>
  1771. <div class="form-group">
  1772. <label for="exampleInputPassword1">Password</label>
  1773. <input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password" required="" data-parsley-required-message="Enter Password">
  1774. </div>
  1775. <div class="modal-actions">
  1776. <a href="/content/alc/en/registration/password-reset.html" class="forgot-password chevron-link">Forgot Password?</a>
  1777. <button type="submit" id="login-submit-btn" class="button arrow-button orange btn-default btn-primary login-submit">Sign In</button>
  1778. </div>
  1779. <div class="help-block">
  1780. <p>By signing in you confirm that you are 19 years of age or older, a resident of and physically located in Atlantic Canada.</p>
  1781.  
  1782.  
  1783.  
  1784.  
  1785. </div>
  1786. </form>
  1787. </div>
  1788. <div class="col-xs-12 col-sm-6 register-today">
  1789. <div class="modal-title">
  1790. <h3>Create an Account</h3>
  1791. </div>
  1792. <div class="account-benefits">
  1793. <h4>Register today to start playing</h4>
  1794.  
  1795. <ul>
  1796. <li>Buy lottery tickets on the go</li>
  1797. <li>Play the all new iBingo and Instant Win games</li>
  1798. <li>Subscribe to your favourite draw games</li>
  1799. <li>It’s fast, safe and secure<br>
  1800. </li>
  1801. </ul>
  1802.  
  1803.  
  1804.  
  1805. </div>
  1806.  
  1807. <div class="modal-actions">
  1808. <a href="/content/alc/en/registration/create-account.html" class="button arrow-button gray btn-primary">Create an Account</a>
  1809. </div>
  1810. </div>
  1811. </div>
  1812. </div>
  1813. </div>
  1814. <div class="modal-body account-error">
  1815. <h3>We are sorry, there is a problem with your account</h3>
  1816. <div class="account-error-container">
  1817. <div class="account-error-info self-exclusion">
  1818. <h4>Self Exclusion Period</h4>
  1819. <p>You've indicated you do not want us to let you in for a little while...</p>
  1820. <p>For help with Self Exclusion settings, please contact our <a href="">Customer Care Centre</a> at <a href="tel:1-877-252-3287">1-877-252-3287</a>.</p>
  1821. </div>
  1822. <div class="account-error-info locked-account">
  1823. <h4>Locked Account</h4>
  1824. <p>We're sorry, but your account has been temporarily locked for security reasons. This means you will need to reset your password to continue.</p>
  1825. <button>Reset Password</button>
  1826. <p>Contact the <a href="">Customer Care Centre</a> at <a href="tel:1-877-252-3287">1-877-252-3287</a>.</p>
  1827. </div>
  1828. <div class="account-error-info customer-suspended">
  1829. <h4>Customer Suspended</h4>
  1830. <p>You could not be signed in. Please contact our <a href="">Customer Care Centre</a> at <a href="tel:1-877-252-3287">1-877-252-3287</a>.</p>
  1831. </div>
  1832. <div class="account-error-info geoip">
  1833. <h4>GEOIP</h4>
  1834. <p>Sorry your IP address has been identified as being located outside Atlantic Canada. As per the alc.ca terms and conditions you are not permitted to play or purchase on our site. You have still have access to your account but you will not be able play/purchase any games or add any funds. If you have questions, please contact our <a href="">Customer Care Centre</a> at <a href="tel:1-877-252-3287">1-877-252-3287</a>.</p>
  1835. </div>
  1836. <div class="account-error-info connection-issues1">
  1837. <h4>Connection Issues</h4>
  1838. <p>Network Unavailable</p>
  1839. </div>
  1840. <div class="account-error-info connection-issues2">
  1841. <h4>Connection Issues</h4>
  1842. <p>No network connection available. Please check your settings.</p>
  1843. </div>
  1844. <div class="account-error-info connection-issues3">
  1845. <h4>Connection Issues</h4>
  1846. <p>Session Expired</p>
  1847. </div>
  1848. <div class="account-error-info connection-issues4">
  1849. <h4>Connection Issues</h4>
  1850. <p>Please sign in again.</p>
  1851. </div>
  1852. <div class="account-error-info connection-issues5">
  1853. <h4>Connection Issues</h4>
  1854. <p>We're sorry but the request could not be completed at this time.</p>
  1855. </div>
  1856. </div>
  1857. </div>
  1858. <div class="modal-footer">
  1859. <div><section>
  1860. <footer>
  1861. <div><div class="parsys"><div class="parbase section text">
  1862. <div class="clearfix"><div class="need-help"><h2>Need help?</h2>
  1863. <p>Contact our Customer Care</p>
  1864. </div>
  1865. <div class="contact"><p><a href="#" class="link-phone">1-877-252-3287</a> <a href="mailto:info@alc.ca" class="link-email">Email Us</a></p>
  1866. </div>
  1867. </div>
  1868.  
  1869.  
  1870. </div>
  1871.  
  1872. </div>
  1873. </div>
  1874. </footer>
  1875. </section></div>
  1876. </div>
  1877. <div id="promote-anonymous-cart-alert" class="hidden">
  1878. <div class="container-fluid">
  1879. <div class="row">
  1880. <div class="col-xs-12 error-body">
  1881. <h3>Error transferring guest cart</h3>
  1882. <p>We were unable to transfer items in your cart. You are successfully signed in, but your cart will be empty.</p>
  1883. <button class="button arrow-button orange btn-default login-anon-cart-error">OK</button>
  1884. </div>
  1885. </div>
  1886. </div>
  1887. </div>
  1888. </div>
  1889. </div>
  1890. </div>
  1891.  
  1892. <script>
  1893. ;(function($, ALC) {
  1894. "use strict";
  1895.  
  1896. var loginModal = $("#modal-login");
  1897. loginModal.find("[data-action='action']").click(function(){
  1898. var successCallback = loginModal.data("successCallback");
  1899. if (typeof successCallback === "function") {
  1900. successCallback(loginModal);
  1901. }
  1902. });
  1903.  
  1904. var validationOptions = {
  1905. modalPopover: true,
  1906. popoverOptions: {
  1907. container: '#modal-login'
  1908. }
  1909. }
  1910. ALC.common.parsleyValidation.init($('#login-submit-form'), validationOptions);
  1911.  
  1912.  
  1913. $('#login-submit-form').submit( function (event) {
  1914. if($('#login-submit-form').parsley().validate()){
  1915. ALC.common.alcLogin($('#exampleInputEmail1').val(), $('#exampleInputPassword1').val(), '.modal-body', true, false);
  1916. }
  1917. event.preventDefault();
  1918. });
  1919.  
  1920. $('.modal-login').on('hide.bs.modal', function(ev){
  1921. ALC.common.sessionStorage.removeItem('sessionReturnURL');
  1922. $(ev.target).find('.account-timeout').addClass('hidden');
  1923. });
  1924. })(jQuery, (ALC || (ALC = {})));
  1925. </script>
  1926. </div>
  1927.  
  1928.  
  1929.  
  1930. -------------------------------------------
  1931. ADD FUNDS Mobile
  1932. -------------------------------------------
  1933. {"locale":"en_CA","Amount":1000,"RedirectUrl":"https://www.alc.ca/content/alc-mobile/en/my-account/add-withdraw-funds.html","CancelUrl":"https://www.alc.ca/content/alc-mobile/en/my-account/add-withdraw-funds.html?cancelled=true","TimeoutUrl":"https://www.alc.ca/content/alc-mobile/en/my-account/add-withdraw-funds.html?timeout=true","HostedPageType":2,"ClientIpAddress":""}
  1934.  
  1935.  
  1936.  
  1937. Cookie: _ga=GA1.2.2116113668.1510940598; _gid=GA1.2.1623536659.1510940598; userId=481933; TS012e1e73=0183e022d95e631a6a7a03a215e3b58e6325f7b35aee2c978998199514b02ebd0767a5c4c828c94908a04a3a2e3f0d83bea6ce0c16; LastActivity=1510940597; __qca=P0-900281888-1510940598474; _gat_UA-49662628-7=1; ALC-browser-check=checked; SciplayAuthToken=dmdDV2JlTjh5K7uhFF1wKna+OlbTKUbJ5TZX4J4n3G5SZusDu9JFqXy6LloFYafgDBxzRql2mtHSaJrEMJ4eieriTziQvgIYHsfauMRCGYTCpyjcPUeJPaULJjCvqHFZizg1ctB9b/oHnpMbEPAWlQs61be/TAl0m3GL4tflrqbr8oxLH0wItrcjZDKjaHgZJRAA+pU+Acb/TyFM2ud9KZPckxftfLZhytV79+4ZhZ9pXzfGjhTlxtPscHFK7vwC/Nx3NIyrotLYZX+tswr0Td3GM/cskOdz7Pca+8R+JNluS8r9vn7z+o11jC+Tp4yyIz5/78AZrix2IS7BzJOVn+J8pAoJI39fo+kH4Gt0/2e29d4szq7ujmkHS0pnROogpnbQTjZYzsfvIcWDZyC/d1PE4iQDK19uvpEWvgyxXPv8YqVg1jmE8X5xnwl8H4yaMbkrpQTkjFdVnc0WcV9Nvrhp0UvWo71MWRcApcBaYahdnQIFu1dLkX1YtNuD7sAbPF9ljHWQ4w0=; TS01d84674=0183e022d9dc15ccee30fe1f625c86b06d88f38a92ee2c978998199514b02ebd0767a5c4c8e37c5dc289d269768a04ddaa7dc0406afc907302ea2e24545b495f55a9f10bf75400e3235c5ed42406832e5618fd343f10416e0d9d8f44fa7e21646bda968c56; locale=en-ca; AuthSignature=2372C620258A42B6AB1C435180A2A74EA305FDBC2A225ACC2DE3C4731B847BCC; AuthTokenExpires=1510944184.0; CartHandle=3ad9d3e5-778f-4060-8d6f-402ba7f178a2; LoginTime=1510940584.0; NickName=bcmoney; PlayerCardId=481933; Province=NB; WalletId=481933; cust_xl=en
  1938.  
  1939.  
  1940. Accept: application/json, text/javascript; */*; q=0.01
  1941.  
  1942.  
  1943. Keep-Alive: timeout=30, max=100
  1944.  
  1945.  
  1946.  
  1947.  
  1948.  
  1949.  
  1950.  
  1951. {"locale":"en_CA","Amount":1000,"RedirectUrl":"https://www.alc.ca/content/alc-mobile/en/my-account/add-withdraw-funds.html","CancelUrl":"https://www.alc.ca/content/alc-mobile/en/my-account/add-withdraw-funds.html?cancelled=true","TimeoutUrl":"https://www.alc.ca/content/alc-mobile/en/my-account/add-withdraw-funds.html?timeout=true","HostedPageType":2,"ClientIpAddress":""}
  1952.  
  1953.  
  1954.  
  1955.  
  1956. FUNDS ERROR
  1957. "{
  1958. \"error_code\": 408,
  1959. \"message\": \"\"
  1960. }"
  1961.  
  1962.  
  1963.  
  1964.  
  1965. FUNDS ERROR
  1966. Object
  1967.  
  1968. abort: function(i)
  1969.  
  1970. always: function()
  1971.  
  1972. complete: function()
  1973.  
  1974. done: function()
  1975.  
  1976. error: function()
  1977.  
  1978. fail: function()
  1979.  
  1980. getAllResponseHeaders: function()
  1981.  
  1982. getResponseHeader: function(i)
  1983.  
  1984. overrideMimeType: function(e)
  1985.  
  1986. pipe: function()
  1987.  
  1988. progress: function()
  1989.  
  1990. promise: function(b8)
  1991.  
  1992. readyState: 4
  1993.  
  1994. responseText: ""
  1995.  
  1996. setRequestHeader: function(i,cs)
  1997.  
  1998. state: function()
  1999.  
  2000. status: 200
  2001.  
  2002. statusCode: function(i)
  2003.  
  2004. statusText: "OK"
  2005.  
  2006. success: function()
  2007.  
  2008. then: function()
  2009.  
  2010. arguments: null
  2011.  
  2012. caller: null
  2013.  
  2014. length: 0
  2015.  
  2016. name: "then"
  2017.  
  2018. prototype: then {}
  2019.  
  2020. Function Prototype
  2021.  
  2022. apply(thisObject, [argumentsArray])
  2023.  
  2024. arguments
  2025.  
  2026. bind(thisObject, ...arguments)
  2027.  
  2028. call(thisObject, ...arguments)
  2029.  
  2030. caller
  2031.  
  2032. constructor: function()
  2033.  
  2034. arguments: TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context.
  2035.  
  2036. caller: TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context.
  2037.  
  2038. length: 1
  2039.  
  2040. name: "Function"
  2041.  
  2042. prototype()
  2043.  
  2044. Function Prototype
  2045.  
  2046. apply(thisObject, [argumentsArray])
  2047.  
  2048. arguments
  2049.  
  2050. bind(thisObject, ...arguments)
  2051.  
  2052. call(thisObject, ...arguments)
  2053.  
  2054. caller
  2055.  
  2056. constructor: function()
  2057.  
  2058. length: 0
  2059.  
  2060. name: ""
  2061.  
  2062. toString()
  2063.  
  2064. Symbol(Symbol.hasInstance)()
  2065.  
  2066. Object Prototype
  2067.  
  2068. length: 0
  2069.  
  2070. name: ""
  2071.  
  2072. toString()
  2073.  
  2074. Symbol(Symbol.hasInstance)()
  2075.  
  2076. Object Prototype
  2077.  
  2078.  
  2079.  
  2080.  
  2081.  
  2082.  
  2083. * Using the browser console: https://www.wickedlysmart.com/hfjsconsole/
  2084. * Log to Safari JavaScript Console: https://stackoverflow.com/questions/3748809/log-to-safari-javascript-console
  2085. * Save Safari javascript console to file?: https://stackoverflow.com/questions/15507059/save-safari-javascript-console-to-file
  2086. * JavaScript Debugging Tips You Probably Didn’t Know: https://raygun.com/blog/javascript-debugging/
  2087. * Copy JSON from console.log in developer tool to clipboard?: https://superuser.com/questions/777213/copy-json-from-console-log-in-developer-tool-to-clipboard
  2088. * How to save the output of a console.log(object) to a file?: https://stackoverflow.com/questions/11849562/how-to-save-the-output-of-a-console-logobject-to-a-file
  2089. * Javascript / Chrome - How to copy an object from the webkit inspector as code: https://stackoverflow.com/questions/10305365/javascript-chrome-how-to-copy-an-object-from-the-webkit-inspector-as-code
  2090. * JS files under clientlibs are not getting loaded: https://stackoverflow.com/questions/12281311/js-files-under-clientlibs-are-not-getting-loaded
Add Comment
Please, Sign In to add comment