PageSourceSearch

https://international.standardbank.com/static_file/assets/SmartBanner/jquery.smartbanner.js

js standardbank.com collected 2026-09-24 07:58:32 UTC 17,948 bytes, 541 lines download raw bytes

1/*!
2 * jQuery Smart Banner
3 * Copyright (c) 2012 Arnold Daniels <[email protected]>
4 * Based on 'jQuery Smart Web App Banner' by Kurt Zenisek @ kzeni.com
5 */
6(function (root, factory) {
7  if (typeof define == "function" && define.amd) {
8    define(["jquery"], factory);
9  } else {
10    factory(root.jQuery);
11  }
12})(this, function ($) {
13  var UA = navigator.userAgent;
14  var isEdge = /Edge/i.test(UA);
15
16  var SmartBanner = function (options) {
17    // Get the original margin-top of the HTML element so we can take that into account.
18    this.origHtmlMargin = parseFloat($("html").css("margin-top"));
19    this.options = $.extend({}, $.smartbanner.defaults, options);
20
21    // Check if it's already a standalone web app or running within a webui view of an app (not mobile safari).
22    var standalone = navigator.standalone;
23
24    // Detect banner type (iOS or Android).
25    if (this.options.force) {
26      this.type = this.options.force;
27    } else if (
28      UA.match(/Windows Phone/i) !== null &&
29      UA.match(/Edge|Touch/i) !== null
30    ) {
31      this.type = "windows";
32    } else if (
33      UA.match(/iPhone|iPod/i) !== null ||
34      (UA.match(/iPad/) && this.options.iOSUniversalApp)
35    ) {
36      if (
37        UA.match(/Safari/i) !== null ||
38        UA.match(/CriOS/i) !== null ||
39        UA.match(/FxiOS/i) != null
40      ) {
41        // Check webview and native smart banner support (iOS 6+).
42        this.type = "ios";
43      }
44    } else if (
45      UA.match(/\bSilk\/(.*\bMobile Safari\b)?/) ||
46      UA.match(/\bKF\w/) ||
47      UA.match("Kindle Fire")
48    ) {
49      this.type = "kindle";
50    } else if (UA.match(/Android/i) !== null) {
51      this.type = "android";
52    }
53    // Don't show banner if device isn't iOS or Android, website is loaded in app or user dismissed banner.
54    if (
55      !this.type ||
56      standalone ||
57      this.getCookie("sb-closed") ||
58      this.getCookie("sb-installed")
59    ) {
60      return;
61    }
62    // Calculate scale.
63    this.scale =
64      this.options.scale == "auto"
65        ? $(window).width() / window.screen.width
66        : this.options.scale;
67    if (this.scale < 1) {
68      this.scale = 1;
69    }
70    // Get info from meta data.
71    var meta = $(
72      this.type == "android"
73        ? 'meta[name="google-play-app"]'
74        : this.type == "ios"
75          ? 'meta[name="apple-app-store"]'
76          : this.type == "kindle"
77            ? 'meta[name="kindle-fire-app"]'
78            : 'meta[name="msApplication-ID"]'
79    );
80
81    if (!meta.length) {
82      return;
83    }
84    // For Windows Store apps, get the PackageFamilyName for protocol launch.
85    if (this.type == "windows") {
86      if (isEdge) {
87        this.appId = $('meta[name="msApplication-PackageEdgeName"]').attr(
88          "content"
89        );
90      }
91      if (!this.appId) {
92        this.appId = $('meta[name="msApplication-PackageFamilyName"]').attr(
93          "content"
94        );
95      }
96    } else {
97      // Try to pull the appId out of the meta tag and store the result.
98      var parsedMetaContent = /app-id=([^\s,]+)/.exec(meta.attr("content"));
99      if (parsedMetaContent) {
100        this.appId = parsedMetaContent[1];
101      } else {
102        return;
103      }
104    }
105    this.title = this.options.title
106      ? this.options.title
107      : meta.data("title") ||
108        $("title")
109          .text()
110          .replace(/\s*[|\-·].*$/, "");
111
112    this.author = this.options.author
113      ? this.options.author
114      : meta.data("author") ||
115        ($('meta[name="author"]').length
116          ? $('meta[name="author"]').attr("content")
117          : window.location.hostname);
118
119    this.iconUrl = meta.data("icon-url");
120    this.price = meta.data("price");
121
122    // Set default onInstall callback if not set in options.
123    if (typeof this.options.onInstall == "function") {
124      this.options.onInstall = this.options.onInstall;
125    } else {
126      this.options.onInstall = function () {};
127    }
128    // Set default onClose callback if not set in options.
129    if (typeof this.options.onClose == "function") {
130      this.options.onClose = this.options.onClose;
131    } else {
132      this.options.onClose = function () {};
133    }
134    // Create banner.
135    this.create();
136    this.show();
137    this.listen();
138  };
139
140  SmartBanner.prototype = {
141    constructor: SmartBanner,
142
143    create: function () {
144      var iconURL;
145      var price = this.price || this.options.price;
146
147      var link =
148        this.options.url ||
149        function () {
150          switch (this.type) {
151            case "android":
152              return "market://details?id=";
153            case "kindle":
154              return "amzn://apps/android?asin=";
155            case "windows":
156              return isEdge
157                ? "ms-windows-store://pdp/?productid="
158                : "ms-windows-store:navigate?appid=";
159          }
160          return (
161            "https://itunes.apple.com/" +
162            this.options.appStoreLanguage +
163            "/app/id"
164          );
165        }.call(this) + this.appId;
166
167      var inStore = !price
168        ? ""
169        : function () {
170            var result = price + " - ";
171            switch (this.type) {
172              case "android":
173                return result + this.options.inGooglePlay;
174              case "kindle":
175                return result + this.options.inAmazonAppStore;
176              case "windows":
177                return result + this.options.inWindowsStore;
178            }
179            return result + this.options.inAppStore;
180          }.call(this);
181
182      var gloss =
183        this.options.iconGloss == null
184          ? this.type == "ios"
185          : this.options.iconGloss;
186
187      if (this.type == "android" && this.options.GooglePlayParams) {
188        link += "&referrer=" + this.options.GooglePlayParams;
189      }
190      var banner =
191        '<div id="smartbanner" class="' +
192        this.type +
193        '">' +
194        '<div class="sb-container">' +
195        '<button type="button" class="sb-close"><img src="/file_source/assets/icons/icon-close.svg"></button>' +
196        '<span class="sb-icon"></span>' +
197        '<div class="sb-info">' +
198        '<span class="sb-info__title">' +
199        this.title +
200        "</span>" +
201        '<span class="sb-info__author">' +
202        this.author +
203        "</span>" +
204        //'<span class="sb-info__price">' + inStore + '</span>' +
205        "</div>" +
206        '<a href="' +
207        link +
208        '" class="sb-button button button--small" data-id="link_content_app smart banner" data-text="view button click">' +
209        "<span>" +
210        this.options.button +
211        "</span>" +
212        "</a>" +
213        "</div>" +
214        "</div>";
215      if (this.options.layer) {
216        $(this.options.appendToSelector).append(banner);
217      } else {
218        $(this.options.appendToSelector).prepend(banner);
219      }
220      if (this.options.icon) {
221        iconURL = this.options.icon;
222      } else if (this.iconUrl) {
223        iconURL = this.iconUrl;
224      } else if ($('link[rel="apple-touch-icon-precomposed"]').length > 0) {
225        iconURL = $('link[rel="apple-touch-icon-precomposed"]').attr("href");
226        if (this.options.iconGloss == null) {
227          gloss = false;
228        }
229      } else if ($('link[rel="apple-touch-icon"]').length > 0) {
230        iconURL = $('link[rel="apple-touch-icon"]').attr("href");
231      } else if ($('meta[name="msApplication-TileImage"]').length > 0) {
232        iconURL = $('meta[name="msApplication-TileImage"]').attr("content");
233      } else if ($('meta[name="msapplication-TileImage"]').length > 0) {
234        // Redundant because ms docs show two case usages.
235        iconURL = $('meta[name="msapplication-TileImage"]').attr("content");
236      }
237      if (iconURL) {
238        $("#smartbanner .sb-icon").css(
239          "background-image",
240          "url(" + iconURL + ")"
241        );
242        if (gloss) {
243          $("#smartbanner .sb-icon").addClass("gloss");
244        }
245      } else {
246        $("#smartbanner").addClass("no-icon");
247      }
248      this.bannerHeight = $("#smartbanner").outerHeight() + 2;
249
250      if (this.scale > 1) {
251        $("#smartbanner")
252          .css("top", parseFloat($("#smartbanner").css("top")) * this.scale)
253          .css(
254            "height",
255            parseFloat($("#smartbanner").css("height")) * this.scale
256          )
257          .hide();
258        $("#smartbanner .sb-container")
259          .css("-webkit-transform", "scale(" + this.scale + ")")
260          .css("-msie-transform", "scale(" + this.scale + ")")
261          .css("-moz-transform", "scale(" + this.scale + ")")
262          .css("width", $(window).width() / this.scale);
263      }
264      $("#smartbanner").css(
265        "position",
266        this.options.layer ? "absolute" : "static"
267      );
268    },
269
270    listen: function () {
271      $("#smartbanner .sb-close").on("click", $.proxy(this.close, this));
272      $("#smartbanner .sb-button").on("click", $.proxy(this.install, this));
273    },
274
275    show: function (callback) {
276      var banner = $("#smartbanner");
277      banner.stop();
278
279      if (this.options.layer) {
280        banner
281          .animate(
282            {
283              top: 0,
284              display: "block",
285            },
286            this.options.speedIn
287          )
288          .addClass("shown")
289          .show();
290        $(this.pushSelector).animate(
291          {
292            paddingTop: this.origHtmlMargin + this.bannerHeight * this.scale,
293          },
294          this.options.speedIn,
295          "swing",
296          callback
297        );
298      } else {
299        if ($.support.transition) {
300          banner
301            .animate(
302              {
303                top: 0,
304              },
305              this.options.speedIn
306            )
307            .addClass("shown");
308          var transitionCallback = function () {
309            $("html").removeClass("sb-animation");
310            if (callback) {
311              callback();
312            }
313          };
314          $(this.pushSelector)
315            .addClass("sb-animation")
316            .one($.support.transition.end, transitionCallback)
317            .emulateTransitionEnd(this.options.speedIn)
318            .css(
319              "margin-top",
320              this.origHtmlMargin + this.bannerHeight * this.scale
321            );
322        } else {
323          banner.slideDown(this.options.speedIn).addClass("shown");
324        }
325      }
326    },
327
328    hide: function (callback) {
329      var banner = $("#smartbanner");
330      banner.stop();
331
332      if (this.options.layer) {
333        banner
334          .animate(
335            {
336              top: -1 * this.bannerHeight * this.scale,
337              display: "block",
338            },
339            this.options.speedIn
340          )
341          .removeClass("shown");
342
343        $(this.pushSelector).animate(
344          {
345            paddingTop: this.origHtmlMargin,
346          },
347          this.options.speedIn,
348          "swing",
349          callback
350        );
351      } else {
352        if ($.support.transition) {
353          if (this.type !== "android") {
354            banner
355              .css({
356                display: "none",
357              })
358              .removeClass("shown");
359          } else {
360            banner
361              .css({
362                display: "none",
363              })
364              .removeClass("shown");
365          }
366          var transitionCallback = function () {
367            $("html").removeClass("sb-animation");
368            if (callback) {
369              callback();
370            }
371          };
372          $(this.pushSelector)
373            .addClass("sb-animation")
374            .one($.support.transition.end, transitionCallback)
375            .emulateTransitionEnd(this.options.speedOut)
376            .css("margin-top", this.origHtmlMargin);
377        } else {
378          banner.slideUp(this.options.speedOut).removeClass("shown");
379        }
380      }
381    },
382
383    close: function (e) {
384      e.preventDefault();
385      this.hide();
386      this.setCookie("sb-closed", "true", this.options.daysHidden);
387      this.options.onClose(e);
388    },
389
390    install: function (e) {
391      if (this.options.hideOnInstall) {
392        this.hide();
393      }
394      this.setCookie("sb-installed", "true", this.options.daysReminder);
395      this.options.onInstall(e);
396    },
397
398    setCookie: function (name, value, exdays) {
399      var exdate = new Date();
400      exdate.setDate(exdate.getDate() + exdays);
401      value =
402        encodeURI(value) +
403        (exdays == null ? "" : "; expires=" + exdate.toUTCString());
404      document.cookie = name + "=" + value + "; path=/;";
405    },
406
407    getCookie: function (name) {
408      var i,
409        x,
410        y,
411        ARRcookies = document.cookie.split(";");
412      for (i = 0; i < ARRcookies.length; i++) {
413        x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
414        y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
415        x = x.replace(/^\s+|\s+$/g, "");
416        if (x == name) {
417          return decodeURI(y);
418        }
419      }
420      return null;
421    },
422
423    // Demo only.
424    switchType: function () {
425      var that = this;
426
427      this.hide(function () {
428        that.type = that.type == "android" ? "ios" : "android";
429        var meta = $(
430          that.type == "android"
431            ? 'meta[name="google-play-app"]'
432            : 'meta[name="apple-app-store"]'
433        ).attr("content");
434        that.appId = /app-id=([^\s,]+)/.exec(meta)[1];
435
436        $("#smartbanner").detach();
437        that.create();
438        that.show();
439      });
440    },
441  };
442
443  $.smartbanner = function (option) {
444    var $window = $(window);
445    var data = $window.data("smartbanner");
446    var options = typeof option == "object" && option;
447    if (!data) {
448      $window.data("smartbanner", (data = new SmartBanner(options)));
449    }
450    if (typeof option == "string") {
451      data[option]();
452    }
453  };
454
455  // override these globally if you like (they are all optional)
456  $.smartbanner.defaults = {
457    title: "Standard Bank / Stanbic Bank App", // What the title of the app should be in the banner (defaults to <title>)
458    author: "Standard Bank Group", // What the author of the app should be in the banner (defaults to <meta name="author"> or hostname)
459    price: "FREE", // Price of the app
460    appStoreLanguage: "us", // Language code for App Store
461    inAppStore: "On the App Store", // Text of price for iOS
462    inGooglePlay: "In Google Play", // Text of price for Android
463    inAmazonAppStore: "In the Amazon Appstore",
464    inWindowsStore: "In the Windows Store", //Text of price for Windows
465    GooglePlayParams: null, // Aditional parameters for the market
466    icon: "https://www.standardbank.co.za/static_file/assets/favicons/apple-icon-180x180.png", // The URL of the icon (defaults to <meta name="apple-touch-icon">)
467    iconGloss: null, // Force gloss effect for iOS even for precomposed
468    button: "OPEN", // Text for the install button
469    url: null, // The URL for the button. Keep null if you want the button to link to the app store.
470    scale: "auto", // Scale based on viewport size (set to 1 to disable)
471    speedIn: 300, // Show animation speed of the banner
472    speedOut: 400, // Close animation speed of the banner
473    daysHidden: 15, // Duration to hide the banner after being closed (0 = always show banner)
474    daysReminder: 90, // Duration to hide the banner after "VIEW" is clicked *separate from when the close button is clicked* (0 = always show banner)
475    force: null, // Choose 'ios', 'android' or 'windows'. Don't do a browser check, just always show this banner
476    hideOnInstall: true, // Hide the banner after "VIEW" is clicked.
477    layer: false, // Display as overlay layer or slide down the page
478    iOSUniversalApp: true, // If the iOS App is a universal app for both iPad and iPhone, display Smart Banner to iPad users, too.
479    appendToSelector: "body", //Append the banner to a specific selector
480    pushSelector: "html", // What element is going to push the site content down; this is where the banner append animation will start.
481  };
482
483  $.smartbanner.Constructor = SmartBanner;
484
485  // ============================================================
486  // Bootstrap transition
487  // Copyright 2011-2014 Twitter, Inc.
488  // Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
489
490  function transitionEnd() {
491    var el = document.createElement("smartbanner");
492
493    var transEndEventNames = {
494      WebkitTransition: "webkitTransitionEnd",
495      MozTransition: "transitionend",
496      OTransition: "oTransitionEnd otransitionend",
497      transition: "transitionend",
498    };
499
500    for (var name in transEndEventNames) {
501      if (el.style[name] !== undefined) {
502        return {
503          end: transEndEventNames[name],
504        };
505      }
506    }
507    // Explicit for ie8.
508    return false;
509  }
510  if ($.support.transition !== undefined) {
511    // Prevent conflict with Twitter Bootstrap.
512    return;
513  }
514
515  // http://blog.alexmaccaw.com/css-transitions
516  $.fn.emulateTransitionEnd = function (duration) {
517    var called = false,
518      $el = this;
519    $(this).one($.support.transition.end, function () {
520      called = true;
521    });
522    var callback = function () {
523      if (!called) {
524        $($el).trigger($.support.transition.end);
525      }
526    };
527    setTimeout(callback, duration);
528    return this;
529  };
530
531  $(function () {
532    $.support.transition = transitionEnd();
533  });
534  // ============================================================
535});
536
537$(function () {
538  // if (!(/(iPad|iPhone|iPod).*OS [6-7].*AppleWebKit.*Mobile.*Safari/.test(navigator.userAgent))) {
539  $.smartbanner();
540  // }
541});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.