@saasquatch/squatch-js 2.6.0-3 → 2.6.0-5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.github/workflows/static.yml +89 -0
  2. package/coverage/clover.xml +843 -3
  3. package/coverage/coverage-final.json +20 -1
  4. package/coverage/lcov-report/DeclarativeWidget.ts.html +790 -0
  5. package/coverage/lcov-report/Widgets.ts.html +1105 -0
  6. package/coverage/lcov-report/api/AnalyticsApi.ts.html +22 -22
  7. package/coverage/lcov-report/api/EventsApi.ts.html +352 -0
  8. package/coverage/lcov-report/api/WidgetApi.ts.html +84 -57
  9. package/coverage/lcov-report/api/graphql.ts.html +1 -1
  10. package/coverage/lcov-report/squatch.ts.html +721 -0
  11. package/coverage/lcov-report/utils/cookieUtils.ts.html +1 -1
  12. package/coverage/lcov-report/utils/decodeUserJwt.ts.html +1 -1
  13. package/coverage/lcov-report/utils/domready.ts.html +1 -1
  14. package/coverage/lcov-report/utils/io.ts.html +7 -7
  15. package/coverage/lcov-report/utils/utmUtils.ts.html +22 -22
  16. package/coverage/lcov-report/utils/validate.ts.html +41 -41
  17. package/coverage/lcov-report/validate.ts.html +1 -1
  18. package/coverage/lcov-report/widgets/EmbedWidget.ts.html +24 -3
  19. package/coverage/lcov-report/widgets/PopupWidget.ts.html +17 -2
  20. package/coverage/lcov-report/widgets/Widget.ts.html +1 -1
  21. package/coverage/lcov-report/widgets/Widgets.ts.html +110 -68
  22. package/coverage/lcov-report/widgets/declarative/DeclarativeWidget.ts.html +368 -74
  23. package/coverage/lcov-report/widgets/declarative/DeclarativeWidgets.ts.html +388 -0
  24. package/coverage/lcov.info +1561 -0
  25. package/dist/api/WidgetApi.d.ts +2 -2
  26. package/dist/squatch.d.ts +28 -1
  27. package/dist/squatch.esm.js +205 -47
  28. package/dist/squatch.esm.js.map +1 -1
  29. package/dist/squatch.js +205 -47
  30. package/dist/squatch.js.map +1 -1
  31. package/dist/squatch.min.js +1 -1
  32. package/dist/widgets/EmbedWidget.d.ts +8 -0
  33. package/dist/widgets/PopupWidget.d.ts +6 -1
  34. package/dist/widgets/Widgets.d.ts +15 -2
  35. package/dist/widgets/declarative/DeclarativeWidget.d.ts +66 -2
  36. package/dist/widgets/declarative/DeclarativeWidgets.d.ts +22 -0
  37. package/package.json +2 -2
package/dist/squatch.js CHANGED
@@ -216,7 +216,7 @@ class WidgetApi {
216
216
  this.npmCdn = clean.npmCdn;
217
217
  }
218
218
  /**
219
- * Creates/upserts user.
219
+ * Creates/upserts user, requests widget template.
220
220
  *
221
221
  * @param {Object} params Parameters for request
222
222
  * @param {Object?} params.user The user details
@@ -238,6 +238,7 @@ class WidgetApi {
238
238
  widgetType,
239
239
  engagementMedium = "POPUP",
240
240
  jwt,
241
+ locale,
241
242
  user
242
243
  } = clean;
243
244
  var tenantAlias = encodeURIComponent(this.tenantAlias);
@@ -246,7 +247,8 @@ class WidgetApi {
246
247
 
247
248
  var optionalParams = _buildParams({
248
249
  widgetType,
249
- engagementMedium
250
+ engagementMedium,
251
+ locale
250
252
  });
251
253
 
252
254
  var path = "/api/v1/" + tenantAlias + "/widget/account/" + accountId + "/user/" + userId + "/upsert" + optionalParams;
@@ -256,7 +258,7 @@ class WidgetApi {
256
258
  return doPut(url, JSON.stringify(user), jwt);
257
259
  }
258
260
  /**
259
- * Description here.
261
+ * Requests widget template
260
262
  *
261
263
  * @param {Object} params Parameters for request
262
264
  * @param {Object} params.user The user details
@@ -331,12 +333,15 @@ class WidgetApi {
331
333
  function _buildParams(_ref) {
332
334
  var {
333
335
  widgetType,
334
- engagementMedium
336
+ engagementMedium,
337
+ locale
335
338
  } = _ref;
336
- var widgetTypeP = widgetType ? "?widgetType=" + encodeURIComponent(widgetType) : "";
337
- var engagementMediumP = (widgetType ? "&" : "?") + "engagementMedium=" + encodeURIComponent(engagementMedium);
338
- var optionalParams = widgetTypeP + engagementMediumP;
339
- return optionalParams;
339
+ var engagementMediumP = "engagementMedium=" + encodeURIComponent(engagementMedium);
340
+ var widgetTypeP = widgetType && "widgetType=" + encodeURIComponent(widgetType);
341
+ var localeP = locale && "locale=" + encodeURIComponent(locale);
342
+ var params = [engagementMediumP, widgetTypeP, localeP].filter(x => !!x);
343
+ var queryString = "?" + params.join("&");
344
+ return queryString;
340
345
  }
341
346
 
342
347
  // @ts-check
@@ -475,8 +480,7 @@ class Widget {
475
480
  }
476
481
 
477
482
  _findFrame() {
478
- var element = this._findElement();
479
-
483
+ var element = this.container ? this._findElement() : document.body;
480
484
  var parent = element.shadowRoot || element;
481
485
  return parent.querySelector("iframe#squatchFrame");
482
486
  }
@@ -682,10 +686,7 @@ class Widget {
682
686
 
683
687
  function delay(duration) {
684
688
  return new Promise(function (resolve, reject) {
685
- setTimeout(function () {
686
- /* istanbul ignore next */
687
- resolve(() => {});
688
- }, duration);
689
+ setTimeout(resolve, duration);
689
690
  });
690
691
  }
691
692
 
@@ -720,6 +721,11 @@ var _log$6 = debug.debug("squatch-js:EMBEDwidget");
720
721
  *
721
722
  * To create an EmbedWidget use {@link Widgets}
722
723
  *
724
+ * @example
725
+ * const widget = new EmbedWidget({ ... })
726
+ * widget.load() // Loads widget into the DOM
727
+ * widget.open() // Makes the iframe container visible
728
+ * widget.close() // Hides the iframe container
723
729
  */
724
730
 
725
731
 
@@ -771,6 +777,8 @@ class EmbedWidget extends Widget {
771
777
 
772
778
  frame.height = frameDoc.body.scrollHeight; // Adjust frame height when size of body changes
773
779
 
780
+ /* istanbul ignore next: hard to test */
781
+
774
782
  var ro = new contentWindow["ResizeObserver"](entries => {
775
783
  for (var entry of entries) {
776
784
  var {
@@ -780,15 +788,19 @@ class EmbedWidget extends Widget {
780
788
  frame.height = height;
781
789
  }
782
790
  });
783
- ro.observe(await this._findInnerContainer(frame)); // Regular load - trigger event
791
+ var container = await this._findInnerContainer(frame);
792
+ ro.observe(container); // Regular load - trigger event
784
793
 
785
- if (!this.container) {
794
+ if (!this.container || this.container instanceof HTMLElement && this.container.tagName.startsWith("SQUATCH-")) {
786
795
  this._loadEvent(_sqh);
787
796
 
788
797
  _log$6("loaded");
789
798
  }
790
799
  });
791
- } // Un-hide if element is available and refresh data
800
+ }
801
+ /**
802
+ * Un-hide if element is available and refresh data
803
+ */
792
804
 
793
805
 
794
806
  open() {
@@ -851,6 +863,11 @@ var popupId = 0;
851
863
  *
852
864
  * To create a PopupWidget use {@link Widgets}
853
865
  *
866
+ * @example
867
+ * const widget = new PopupWidget({ ... })
868
+ * widget.load() // Loads the widget into a dialog element
869
+ * widget.open() // Opens the dialog element
870
+ * widget.close() // Hides the dialog element
854
871
  */
855
872
 
856
873
  class PopupWidget extends Widget {
@@ -876,7 +893,7 @@ class PopupWidget extends Widget {
876
893
  document.head.insertAdjacentHTML("beforeend", "<style>#" + this.id + "::-webkit-scrollbar { display: none; }</style>");
877
894
  }
878
895
 
879
- _initialiseCTA(frame) {
896
+ _initialiseCTA() {
880
897
  if (!this.trigger) return;
881
898
  var triggerElement;
882
899
 
@@ -924,10 +941,9 @@ class PopupWidget extends Widget {
924
941
 
925
942
  var frame = this._createFrame();
926
943
 
927
- this._initialiseCTA(frame);
928
-
929
- var element = this._findElement();
944
+ this._initialiseCTA();
930
945
 
946
+ var element = this.container ? this._findElement() : document.body;
931
947
  var dialogParent = element.shadowRoot || element;
932
948
 
933
949
  var dialog = this._createPopupDialog();
@@ -993,8 +1009,7 @@ class PopupWidget extends Widget {
993
1009
  }
994
1010
 
995
1011
  open() {
996
- var element = this._findElement();
997
-
1012
+ var element = this.container ? this._findElement() : document.body;
998
1013
  var parent = element.shadowRoot || element;
999
1014
  var dialog = parent.querySelector("#" + this.id);
1000
1015
  if (!dialog) throw new Error("Could not determine container div");
@@ -1023,8 +1038,7 @@ class PopupWidget extends Widget {
1023
1038
  }
1024
1039
 
1025
1040
  close() {
1026
- var element = this._findElement();
1027
-
1041
+ var element = this.container ? this._findElement() : document.body;
1028
1042
  var parent = element.shadowRoot || element;
1029
1043
  var dialog = parent.querySelector("#" + this.id);
1030
1044
  if (!dialog) throw new Error("Could not determine container div");
@@ -1053,14 +1067,31 @@ class PopupWidget extends Widget {
1053
1067
 
1054
1068
  var _log$4 = debug.debug("squatch-js:widgets");
1055
1069
  /**
1056
- *
1057
1070
  * `Widgets` is a factory for creating widgets. It's possible to build your own widgets using the
1058
1071
  * {@link WidgetApi} but most people will prefer to use these easy methods.
1059
- *
1072
+ * @class
1060
1073
  */
1061
1074
 
1062
1075
 
1063
1076
  class Widgets {
1077
+ /**
1078
+ * Instance of {@link WidgetApi}
1079
+ */
1080
+
1081
+ /**
1082
+ * Tenant alias of SaaSquatch tenant.
1083
+ */
1084
+
1085
+ /**
1086
+ * SaaSquatch domain for API requests.
1087
+ * @default "https://app.referralsaasquatch.com"
1088
+ */
1089
+
1090
+ /**
1091
+ * Hosted CDN for npm packages
1092
+ * @default "https://fast.ssqt.io/npm"
1093
+ */
1094
+
1064
1095
  /**
1065
1096
  * Initialize a new {@link Widgets} instance.
1066
1097
  *
@@ -1086,7 +1117,7 @@ class Widgets {
1086
1117
  this.tenantAlias = config.tenantAlias;
1087
1118
  this.domain = config.domain;
1088
1119
  this.npmCdn = config.npmCdn;
1089
- this.api = new WidgetApi(config); // listens to a 'submit_email' event in the theme.
1120
+ this.api = new WidgetApi(config);
1090
1121
  }
1091
1122
  /**
1092
1123
  * This function calls the {@link WidgetApi.upsertUser} method, and it renders
@@ -1158,7 +1189,9 @@ class Widgets {
1158
1189
  return {
1159
1190
  widget: this._renderWidget(response, clean, {
1160
1191
  type: "passwordless",
1161
- engagementMedium: clean.engagementMedium
1192
+ engagementMedium: clean.engagementMedium,
1193
+ container: clean.container,
1194
+ trigger: clean.trigger
1162
1195
  }),
1163
1196
  user: response.user
1164
1197
  };
@@ -1249,13 +1282,7 @@ class Widgets {
1249
1282
  if (Widgets._matchesUrl(rule.url)) {
1250
1283
  var _response$user, _response$user$referr;
1251
1284
 
1252
- console.log({
1253
- response,
1254
- rule
1255
- });
1256
-
1257
1285
  if (rule.widgetType !== "CONVERSION_WIDGET" || (_response$user = response.user) != null && (_response$user$referr = _response$user.referredBy) != null && _response$user$referr.code) {
1258
- console.log("HERE");
1259
1286
  displayOnLoad = rule.displayOnLoad;
1260
1287
 
1261
1288
  _log$4("Display " + rule.widgetType + " on " + rule.url);
@@ -1667,8 +1694,62 @@ function decodeUserJwt(tokenStr) {
1667
1694
  }
1668
1695
 
1669
1696
  debug__default['default']("sqh:DeclarativeWidget");
1697
+ /**
1698
+ * Abstract class for building web-components that render SaaSquatch widgets to the DOM.
1699
+ * @abstract
1700
+ * @example
1701
+ * class TestWidgetElement extends DeclarativeWidget {}
1702
+ * const testWidget = new TestWidgetElement()
1703
+ * testWidget.widgetType = 'w/widget-type'
1704
+ * testWidget.type = 'EMBED'
1705
+ * testWidget.renderWidget()
1706
+ */
1707
+
1670
1708
 
1671
1709
  class DeclarativeWidget extends HTMLElement {
1710
+ /**
1711
+ * Configuration overrides
1712
+ * @default window.squatchConfig
1713
+ */
1714
+
1715
+ /**
1716
+ * Signed JWT containing user information
1717
+ * @default window.squatchToken
1718
+ */
1719
+
1720
+ /**
1721
+ * Tenant alias of SaaSquatch tenant
1722
+ * @default window.squatchTenant
1723
+ */
1724
+
1725
+ /**
1726
+ * widgetType of widget to load
1727
+ */
1728
+
1729
+ /**
1730
+ * Locale to render the widget in
1731
+ */
1732
+
1733
+ /**
1734
+ * Instance of {@link WidgetApi}
1735
+ */
1736
+
1737
+ /**
1738
+ * Instance of {@link AnalyticsApi}
1739
+ */
1740
+
1741
+ /**
1742
+ * Instance of {@link EmbedWidget} or {@link PopupWidget}
1743
+ */
1744
+
1745
+ /**
1746
+ * Determines whether to render the widget as an embedding widget or popup widget.
1747
+ */
1748
+
1749
+ /**
1750
+ * Container element to contain the widget iframe
1751
+ * @default this
1752
+ */
1672
1753
  constructor() {
1673
1754
  super();
1674
1755
  this.config = void 0;
@@ -1678,11 +1759,10 @@ class DeclarativeWidget extends HTMLElement {
1678
1759
  this.locale = void 0;
1679
1760
  this.widgetApi = void 0;
1680
1761
  this.analyticsApi = void 0;
1681
- this.type = void 0;
1682
1762
  this.widgetInstance = void 0;
1763
+ this.type = void 0;
1683
1764
  this.container = void 0;
1684
1765
  this.element = void 0;
1685
- this._hasChildren = void 0;
1686
1766
 
1687
1767
  this._setWidget = (template, config) => {
1688
1768
  var _this$config;
@@ -1729,6 +1809,7 @@ class DeclarativeWidget extends HTMLElement {
1729
1809
  }
1730
1810
  };
1731
1811
 
1812
+ this.reload = this.renderWidget;
1732
1813
  this.show = this.open;
1733
1814
  this.hide = this.close;
1734
1815
  this.attachShadow({
@@ -1738,7 +1819,6 @@ class DeclarativeWidget extends HTMLElement {
1738
1819
  this.token = window.squatchToken;
1739
1820
  this.tenant = window.squatchTenant;
1740
1821
  this.container = this;
1741
- this.locale = validateLocale(navigator.language.replace(/\-/g, "_"));
1742
1822
  }
1743
1823
 
1744
1824
  _setupApis(config) {
@@ -1777,6 +1857,7 @@ class DeclarativeWidget extends HTMLElement {
1777
1857
  if (!userObj) throw new Error("Could not load user information from jwt");
1778
1858
  var widgetInstance = await this.widgetApi.upsertUser({
1779
1859
  user: userObj,
1860
+ locale: this.locale,
1780
1861
  engagementMedium: this.type,
1781
1862
  widgetType: this.widgetType,
1782
1863
  jwt: this.token
@@ -1786,6 +1867,11 @@ class DeclarativeWidget extends HTMLElement {
1786
1867
  return widgetInstance;
1787
1868
  }
1788
1869
 
1870
+ /**
1871
+ * Fetches widget content from SaaSquatch and builds a Widget instance to support rendering the widget in the DOM.
1872
+ * @returns Instance of either {@link EmbedWidget} or {@link PopupWidget} depending on `this.type`
1873
+ * @throws Throws an Error if `widgetType` is undefined
1874
+ */
1789
1875
  async getWidgetInstance() {
1790
1876
  var widgetInstance;
1791
1877
  this.widgetType = this.getAttribute("widget") || undefined;
@@ -1798,29 +1884,64 @@ class DeclarativeWidget extends HTMLElement {
1798
1884
  widgetInstance = await this.renderUserUpsertVariant();
1799
1885
  }
1800
1886
 
1801
- if (!widgetInstance) throw new Error("Could not create widget.");
1802
1887
  this.widgetInstance = widgetInstance;
1803
1888
  return widgetInstance;
1804
1889
  }
1890
+ /**
1891
+ * Calls {@link getWidgetInstance} to build the Widget instance and loads the widget iframe into the DOM.
1892
+ */
1893
+
1805
1894
 
1806
1895
  async renderWidget() {
1807
1896
  await this.getWidgetInstance();
1808
1897
  await this.widgetInstance.load();
1809
1898
  }
1899
+ /**
1900
+ * Builds a Widget instance for the default error widget.
1901
+ * @returns Instance of either {@link EmbedWidget} or {@link PopupWidget} depending on `this.type`
1902
+ */
1903
+
1810
1904
 
1905
+ /**
1906
+ * Calls `open` method of `widgetInstance`
1907
+ * @throws Throws an Error if called before the widget has loaded
1908
+ */
1811
1909
  open() {
1910
+ if (!this.widgetInstance) throw new Error("Widget has not loaded yet");
1812
1911
  this.widgetInstance.open();
1813
1912
  }
1913
+ /**
1914
+ * Calls `close` method of `widgetInstance`
1915
+ * @throws Throws an Error if called before the widget has loaded
1916
+ */
1917
+
1814
1918
 
1815
1919
  close() {
1920
+ if (!this.widgetInstance) throw new Error("Widget has not loaded yet");
1816
1921
  this.widgetInstance.close();
1817
1922
  }
1818
1923
 
1819
1924
  }
1820
1925
 
1926
+ /**
1927
+ * Base class for `squatch-embed` web-component
1928
+ * @extends {DeclarativeWidget}
1929
+ * @class
1930
+ * @example
1931
+ * window.createCustomElement('squatch-embed', DeclarativeEmbedWidget)
1932
+ * const widget = document.querySelector('squatch-embed') as DeclarativeEmbedWidget
1933
+ * widget.open()
1934
+ * widget.close()
1935
+ * widget.reload()
1936
+ */
1937
+
1821
1938
  class DeclarativeEmbedWidget extends DeclarativeWidget {
1822
1939
  constructor() {
1823
1940
  super();
1941
+ /**
1942
+ * @static
1943
+ */
1944
+
1824
1945
  this.type = "EMBED";
1825
1946
  }
1826
1947
 
@@ -1836,11 +1957,6 @@ class DeclarativeEmbedWidget extends DeclarativeWidget {
1836
1957
  case "widget":
1837
1958
  this.connectedCallback();
1838
1959
  break;
1839
- // // Specific to embed widgets
1840
- // case "container":
1841
- // if (this.widgetInstance._findElement()) this.close();
1842
- // this.connectedCallback();
1843
- // break;
1844
1960
  }
1845
1961
  }
1846
1962
 
@@ -1854,9 +1970,25 @@ class DeclarativeEmbedWidget extends DeclarativeWidget {
1854
1970
  }
1855
1971
 
1856
1972
  }
1973
+ /**
1974
+ * Base class for `squatch-popup` web-component
1975
+ * @extends {DeclarativeWidget}
1976
+ * @class
1977
+ * @example
1978
+ * window.createCustomElement('squatch-popup', DeclarativePopupWidget)
1979
+ * const widget = document.querySelector('squatch-popup') as DeclarativePopupWidget
1980
+ * widget.open()
1981
+ * widget.close()
1982
+ * widget.reload()
1983
+ */
1984
+
1857
1985
  class DeclarativePopupWidget extends DeclarativeWidget {
1858
1986
  constructor() {
1859
1987
  super();
1988
+ /**
1989
+ * @static
1990
+ */
1991
+
1860
1992
  this.type = "POPUP";
1861
1993
  this.addEventListener("click", e => {
1862
1994
  e.stopPropagation(); // SQUATCH-POPUP target means something in the shadowDOM was clicked (i.e. the dialog element)
@@ -1866,14 +1998,13 @@ class DeclarativePopupWidget extends DeclarativeWidget {
1866
1998
  }
1867
1999
 
1868
2000
  static get observedAttributes() {
1869
- return ["widget", "id", "open", "locale"];
2001
+ return ["widget", "locale"];
1870
2002
  }
1871
2003
 
1872
2004
  attributeChangedCallback(attr, oldVal, newVal) {
1873
2005
  if (oldVal === newVal || !oldVal) return; // nothing to do
1874
2006
 
1875
2007
  switch (attr) {
1876
- case "open":
1877
2008
  case "locale":
1878
2009
  case "widget":
1879
2010
  this.connectedCallback();
@@ -1916,6 +2047,10 @@ var _events = null;
1916
2047
  * Read the {@link WidgetApi} docs.
1917
2048
  *
1918
2049
  * @returns WidgetApi static instance
2050
+ * @example
2051
+ * squatch.api().render({ ... })
2052
+ * squatch.api().upsertUser({ ... })
2053
+ * squatch.api().squatchReferralCookie()
1919
2054
  */
1920
2055
 
1921
2056
  function api() {
@@ -1928,6 +2063,10 @@ function api() {
1928
2063
  * Read the {@link Widgets} docs.
1929
2064
  *
1930
2065
  * @returns static instance
2066
+ * @example
2067
+ * squatch.widgets().render({ widgetType: "w/widget-type" })
2068
+ * squatch.widgets().upsertUser({ user: { ... }, widgetType: "w/widget-type" })
2069
+ * squatch.widgets().autofill(".referral-code")
1931
2070
  */
1932
2071
 
1933
2072
  function widgets() {
@@ -1940,6 +2079,9 @@ function widgets() {
1940
2079
  * Read the {@link EventsApi} docs.
1941
2080
  *
1942
2081
  * @returns EventsApi static instance
2082
+ *
2083
+ * @example
2084
+ * squatch.events().track({ ... })
1943
2085
  */
1944
2086
 
1945
2087
  function events() {
@@ -1948,6 +2090,13 @@ function events() {
1948
2090
  }
1949
2091
  /**
1950
2092
  * Entry-point for high level API to render a widget using the instance of {@link Widgets} created when you call {@link #init init}.
2093
+ *
2094
+ * Read the {@link Widgets.render} docs.
2095
+ *
2096
+ * @example
2097
+ * squatch.widget().then(res => {
2098
+ * const widget = res.widget
2099
+ * }).catch(e => console.error("Did not render widget:", e))
1951
2100
  */
1952
2101
 
1953
2102
  function widget(widgetConfig) {
@@ -1957,6 +2106,9 @@ function widget(widgetConfig) {
1957
2106
  }
1958
2107
  /**
1959
2108
  * Extracts widget configuration from `_saasquatchExtra` UTM parameter. Initialises `squatch` and renders the widget as a {@link PopupWidget} via static instanct of {@link Widgets}.
2109
+ *
2110
+ * Called by default on startup via the loader script.
2111
+ * @private
1960
2112
  */
1961
2113
 
1962
2114
  function _auto(configIn) {
@@ -1983,7 +2135,9 @@ function _auto(configIn) {
1983
2135
  * @param config Configuration details
1984
2136
  *
1985
2137
  * @example
1986
- * squatch.init({tenantAlias:'test_basbtabstq51v'});
2138
+ * squatch.init({
2139
+ * tenantAlias:'test_basbtabstq51v',
2140
+ * });
1987
2141
  */
1988
2142
 
1989
2143
  function init(configIn) {
@@ -2028,6 +2182,10 @@ function ready(fn) {
2028
2182
  *
2029
2183
  * @param {string} selector Element class/id
2030
2184
  * @returns {void}
2185
+ *
2186
+ * @example
2187
+ * squatch.autofill("input.referral-code")
2188
+ * squatch.autofill("input#referral-code")
2031
2189
  */
2032
2190
 
2033
2191
  function autofill(selector) {