11cb0ef41Sopenharmony_ci/**
21cb0ef41Sopenharmony_ci * Supports pseudo-"namespacing" for window-posted messages for a given test
31cb0ef41Sopenharmony_ci * by generating and using a unique prefix that gets wrapped into message
41cb0ef41Sopenharmony_ci * objects. This makes it more feasible to have multiple tests that use
51cb0ef41Sopenharmony_ci * `window.postMessage` in a single test file. Basically, make it possible
61cb0ef41Sopenharmony_ci * for the each test to listen for only the messages that are pertinent to it.
71cb0ef41Sopenharmony_ci *
81cb0ef41Sopenharmony_ci * 'Prefix' not an elegant term to use here but this models itself after
91cb0ef41Sopenharmony_ci * PrefixedLocalStorage.
101cb0ef41Sopenharmony_ci *
111cb0ef41Sopenharmony_ci * PrefixedMessageTest: Instantiate in testharness.js tests to generate
121cb0ef41Sopenharmony_ci *   a new unique-ish prefix that can be used by other test support files
131cb0ef41Sopenharmony_ci * PrefixedMessageResource: Instantiate in supporting test resource
141cb0ef41Sopenharmony_ci *   files to use/share a prefix generated by a test.
151cb0ef41Sopenharmony_ci */
161cb0ef41Sopenharmony_civar PrefixedMessage = function () {
171cb0ef41Sopenharmony_ci  this.prefix = '';
181cb0ef41Sopenharmony_ci  this.param = 'prefixedMessage'; // Param to use in querystrings
191cb0ef41Sopenharmony_ci};
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci/**
221cb0ef41Sopenharmony_ci * Generate a URL that adds/replaces param with this object's prefix
231cb0ef41Sopenharmony_ci * Use to link to test support files that make use of
241cb0ef41Sopenharmony_ci * PrefixedMessageResource.
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_ciPrefixedMessage.prototype.url = function (uri) {
271cb0ef41Sopenharmony_ci  function updateUrlParameter (uri, key, value) {
281cb0ef41Sopenharmony_ci    var i         = uri.indexOf('#');
291cb0ef41Sopenharmony_ci    var hash      = (i === -1) ? '' : uri.substr(i);
301cb0ef41Sopenharmony_ci    uri           = (i === -1) ? uri : uri.substr(0, i);
311cb0ef41Sopenharmony_ci    var re        = new RegExp(`([?&])${key}=.*?(&|$)`, 'i');
321cb0ef41Sopenharmony_ci    var separator = uri.indexOf('?') !== -1 ? '&' : '?';
331cb0ef41Sopenharmony_ci    uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) :
341cb0ef41Sopenharmony_ci      `${uri}${separator}${key}=${value}`;
351cb0ef41Sopenharmony_ci    return uri + hash;
361cb0ef41Sopenharmony_ci  }
371cb0ef41Sopenharmony_ci  return updateUrlParameter(uri, this.param, this.prefix);
381cb0ef41Sopenharmony_ci};
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_ci/**
411cb0ef41Sopenharmony_ci * Add an eventListener on `message` but only invoke the given callback
421cb0ef41Sopenharmony_ci * for messages whose object contains this object's prefix. Remove the
431cb0ef41Sopenharmony_ci * event listener once the anticipated message has been received.
441cb0ef41Sopenharmony_ci */
451cb0ef41Sopenharmony_ciPrefixedMessage.prototype.onMessage = function (fn) {
461cb0ef41Sopenharmony_ci  window.addEventListener('message', e => {
471cb0ef41Sopenharmony_ci    if (typeof e.data === 'object' && e.data.hasOwnProperty('prefix')) {
481cb0ef41Sopenharmony_ci      if (e.data.prefix === this.prefix) {
491cb0ef41Sopenharmony_ci        // Only invoke callback when `data` is an object containing
501cb0ef41Sopenharmony_ci        // a `prefix` key with this object's prefix value
511cb0ef41Sopenharmony_ci        // Note fn is invoked with "unwrapped" data first, then the event `e`
521cb0ef41Sopenharmony_ci        // (which contains the full, wrapped e.data should it be needed)
531cb0ef41Sopenharmony_ci        fn.call(this, e.data.data, e);
541cb0ef41Sopenharmony_ci        window.removeEventListener('message', fn);
551cb0ef41Sopenharmony_ci      }
561cb0ef41Sopenharmony_ci    }
571cb0ef41Sopenharmony_ci  });
581cb0ef41Sopenharmony_ci};
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci/**
611cb0ef41Sopenharmony_ci * Instantiate in a test file (e.g. during `setup`) to create a unique-ish
621cb0ef41Sopenharmony_ci * prefix that can be shared by support files
631cb0ef41Sopenharmony_ci */
641cb0ef41Sopenharmony_civar PrefixedMessageTest = function () {
651cb0ef41Sopenharmony_ci  PrefixedMessage.call(this);
661cb0ef41Sopenharmony_ci  this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`;
671cb0ef41Sopenharmony_ci};
681cb0ef41Sopenharmony_ciPrefixedMessageTest.prototype = Object.create(PrefixedMessage.prototype);
691cb0ef41Sopenharmony_ciPrefixedMessageTest.prototype.constructor = PrefixedMessageTest;
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci/**
721cb0ef41Sopenharmony_ci * Instantiate in a test support script to use a "prefix" generated by a
731cb0ef41Sopenharmony_ci * PrefixedMessageTest in a controlling test file. It will look for
741cb0ef41Sopenharmony_ci * the prefix in a URL param (see also PrefixedMessage#url)
751cb0ef41Sopenharmony_ci */
761cb0ef41Sopenharmony_civar PrefixedMessageResource = function () {
771cb0ef41Sopenharmony_ci  PrefixedMessage.call(this);
781cb0ef41Sopenharmony_ci  // Check URL querystring for prefix to use
791cb0ef41Sopenharmony_ci  var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`),
801cb0ef41Sopenharmony_ci    results = regex.exec(document.location.href);
811cb0ef41Sopenharmony_ci  if (results && results[2]) {
821cb0ef41Sopenharmony_ci    this.prefix = results[2];
831cb0ef41Sopenharmony_ci  }
841cb0ef41Sopenharmony_ci};
851cb0ef41Sopenharmony_ciPrefixedMessageResource.prototype = Object.create(PrefixedMessage.prototype);
861cb0ef41Sopenharmony_ciPrefixedMessageResource.prototype.constructor = PrefixedMessageResource;
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci/**
891cb0ef41Sopenharmony_ci * This is how a test resource document can "send info" to its
901cb0ef41Sopenharmony_ci * opener context. It will whatever message is being sent (`data`) in
911cb0ef41Sopenharmony_ci * an object that injects the prefix.
921cb0ef41Sopenharmony_ci */
931cb0ef41Sopenharmony_ciPrefixedMessageResource.prototype.postToOpener = function (data) {
941cb0ef41Sopenharmony_ci  if (window.opener) {
951cb0ef41Sopenharmony_ci    window.opener.postMessage({
961cb0ef41Sopenharmony_ci      prefix: this.prefix,
971cb0ef41Sopenharmony_ci      data: data
981cb0ef41Sopenharmony_ci    }, '*');
991cb0ef41Sopenharmony_ci  }
1001cb0ef41Sopenharmony_ci};
101