[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/ -> interactivity-router.js (source)

   1  import * as __WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__ from "@wordpress/interactivity";
   2  /******/ // The require scope
   3  /******/ var __webpack_require__ = {};
   4  /******/ 
   5  /************************************************************************/
   6  /******/ /* webpack/runtime/define property getters */
   7  /******/ (() => {
   8  /******/     // define getter functions for harmony exports
   9  /******/     __webpack_require__.d = (exports, definition) => {
  10  /******/         for(var key in definition) {
  11  /******/             if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  12  /******/                 Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  13  /******/             }
  14  /******/         }
  15  /******/     };
  16  /******/ })();
  17  /******/ 
  18  /******/ /* webpack/runtime/hasOwnProperty shorthand */
  19  /******/ (() => {
  20  /******/     __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
  21  /******/ })();
  22  /******/ 
  23  /************************************************************************/
  24  var __webpack_exports__ = {};
  25  
  26  // EXPORTS
  27  __webpack_require__.d(__webpack_exports__, {
  28    o: () => (/* binding */ actions),
  29    w: () => (/* binding */ state)
  30  });
  31  
  32  ;// CONCATENATED MODULE: external "@wordpress/interactivity"
  33  var x = (y) => {
  34      var x = {}; __webpack_require__.d(x, y); return x
  35  } 
  36  var y = (x) => (() => (x))
  37  const interactivity_namespaceObject = x({ ["getConfig"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.getConfig), ["privateApis"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.privateApis), ["store"]: () => (__WEBPACK_EXTERNAL_MODULE__wordpress_interactivity_8e89b257__.store) });
  38  ;// CONCATENATED MODULE: ./node_modules/@wordpress/interactivity-router/build-module/index.js
  39  /**
  40   * WordPress dependencies
  41   */
  42  
  43  const {
  44    directivePrefix,
  45    getRegionRootFragment,
  46    initialVdom,
  47    toVdom,
  48    render,
  49    parseInitialData,
  50    populateInitialData,
  51    batch
  52  } = (0,interactivity_namespaceObject.privateApis)('I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WordPress.');
  53  
  54  // The cache of visited and prefetched pages.
  55  const pages = new Map();
  56  
  57  // Helper to remove domain and hash from the URL. We are only interesting in
  58  // caching the path and the query.
  59  const getPagePath = url => {
  60    const u = new URL(url, window.location);
  61    return u.pathname + u.search;
  62  };
  63  
  64  // Fetch a new page and convert it to a static virtual DOM.
  65  const fetchPage = async (url, {
  66    html
  67  }) => {
  68    try {
  69      if (!html) {
  70        const res = await window.fetch(url);
  71        if (res.status !== 200) return false;
  72        html = await res.text();
  73      }
  74      const dom = new window.DOMParser().parseFromString(html, 'text/html');
  75      return regionsToVdom(dom);
  76    } catch (e) {
  77      return false;
  78    }
  79  };
  80  
  81  // Return an object with VDOM trees of those HTML regions marked with a
  82  // `router-region` directive.
  83  const regionsToVdom = (dom, {
  84    vdom
  85  } = {}) => {
  86    const regions = {};
  87    const attrName = `data-$directivePrefix}-router-region`;
  88    dom.querySelectorAll(`[$attrName}]`).forEach(region => {
  89      const id = region.getAttribute(attrName);
  90      regions[id] = vdom?.has(region) ? vdom.get(region) : toVdom(region);
  91    });
  92    const title = dom.querySelector('title')?.innerText;
  93    const initialData = parseInitialData(dom);
  94    return {
  95      regions,
  96      title,
  97      initialData
  98    };
  99  };
 100  
 101  // Render all interactive regions contained in the given page.
 102  const renderRegions = page => {
 103    batch(() => {
 104      populateInitialData(page.initialData);
 105      const attrName = `data-$directivePrefix}-router-region`;
 106      document.querySelectorAll(`[$attrName}]`).forEach(region => {
 107        const id = region.getAttribute(attrName);
 108        const fragment = getRegionRootFragment(region);
 109        render(page.regions[id], fragment);
 110      });
 111      if (page.title) {
 112        document.title = page.title;
 113      }
 114    });
 115  };
 116  
 117  /**
 118   * Load the given page forcing a full page reload.
 119   *
 120   * The function returns a promise that won't resolve, useful to prevent any
 121   * potential feedback indicating that the navigation has finished while the new
 122   * page is being loaded.
 123   *
 124   * @param {string} href The page href.
 125   * @return {Promise} Promise that never resolves.
 126   */
 127  const forcePageReload = href => {
 128    window.location.assign(href);
 129    return new Promise(() => {});
 130  };
 131  
 132  // Listen to the back and forward buttons and restore the page if it's in the
 133  // cache.
 134  window.addEventListener('popstate', async () => {
 135    const pagePath = getPagePath(window.location); // Remove hash.
 136    const page = pages.has(pagePath) && (await pages.get(pagePath));
 137    if (page) {
 138      renderRegions(page);
 139      // Update the URL in the state.
 140      state.url = window.location.href;
 141    } else {
 142      window.location.reload();
 143    }
 144  });
 145  
 146  // Cache the initial page using the intially parsed vDOM.
 147  pages.set(getPagePath(window.location), Promise.resolve(regionsToVdom(document, {
 148    vdom: initialVdom
 149  })));
 150  
 151  // Variable to store the current navigation.
 152  let navigatingTo = '';
 153  const {
 154    state,
 155    actions
 156  } = (0,interactivity_namespaceObject.store)('core/router', {
 157    state: {
 158      url: window.location.href,
 159      navigation: {
 160        hasStarted: false,
 161        hasFinished: false,
 162        texts: {}
 163      }
 164    },
 165    actions: {
 166      /**
 167       * Navigates to the specified page.
 168       *
 169       * This function normalizes the passed href, fetchs the page HTML if
 170       * needed, and updates any interactive regions whose contents have
 171       * changed. It also creates a new entry in the browser session history.
 172       *
 173       * @param {string}  href                               The page href.
 174       * @param {Object}  [options]                          Options object.
 175       * @param {boolean} [options.force]                    If true, it forces re-fetching the URL.
 176       * @param {string}  [options.html]                     HTML string to be used instead of fetching the requested URL.
 177       * @param {boolean} [options.replace]                  If true, it replaces the current entry in the browser session history.
 178       * @param {number}  [options.timeout]                  Time until the navigation is aborted, in milliseconds. Default is 10000.
 179       * @param {boolean} [options.loadingAnimation]         Whether an animation should be shown while navigating. Default to `true`.
 180       * @param {boolean} [options.screenReaderAnnouncement] Whether a message for screen readers should be announced while navigating. Default to `true`.
 181       *
 182       * @return {Promise} Promise that resolves once the navigation is completed or aborted.
 183       */
 184      *navigate(href, options = {}) {
 185        const {
 186          clientNavigationDisabled
 187        } = (0,interactivity_namespaceObject.getConfig)();
 188        if (clientNavigationDisabled) {
 189          yield forcePageReload(href);
 190        }
 191        const pagePath = getPagePath(href);
 192        const {
 193          navigation
 194        } = state;
 195        const {
 196          loadingAnimation = true,
 197          screenReaderAnnouncement = true,
 198          timeout = 10000
 199        } = options;
 200        navigatingTo = href;
 201        actions.prefetch(pagePath, options);
 202  
 203        // Create a promise that resolves when the specified timeout ends.
 204        // The timeout value is 10 seconds by default.
 205        const timeoutPromise = new Promise(resolve => setTimeout(resolve, timeout));
 206  
 207        // Don't update the navigation status immediately, wait 400 ms.
 208        const loadingTimeout = setTimeout(() => {
 209          if (navigatingTo !== href) return;
 210          if (loadingAnimation) {
 211            navigation.hasStarted = true;
 212            navigation.hasFinished = false;
 213          }
 214          if (screenReaderAnnouncement) {
 215            navigation.message = navigation.texts.loading;
 216          }
 217        }, 400);
 218        const page = yield Promise.race([pages.get(pagePath), timeoutPromise]);
 219  
 220        // Dismiss loading message if it hasn't been added yet.
 221        clearTimeout(loadingTimeout);
 222  
 223        // Once the page is fetched, the destination URL could have changed
 224        // (e.g., by clicking another link in the meantime). If so, bail
 225        // out, and let the newer execution to update the HTML.
 226        if (navigatingTo !== href) return;
 227        if (page && !page.initialData?.config?.['core/router']?.clientNavigationDisabled) {
 228          renderRegions(page);
 229          window.history[options.replace ? 'replaceState' : 'pushState']({}, '', href);
 230  
 231          // Update the URL in the state.
 232          state.url = href;
 233  
 234          // Update the navigation status once the the new page rendering
 235          // has been completed.
 236          if (loadingAnimation) {
 237            navigation.hasStarted = false;
 238            navigation.hasFinished = true;
 239          }
 240          if (screenReaderAnnouncement) {
 241            // Announce that the page has been loaded. If the message is the
 242            // same, we use a no-break space similar to the @wordpress/a11y
 243            // package: https://github.com/WordPress/gutenberg/blob/c395242b8e6ee20f8b06c199e4fc2920d7018af1/packages/a11y/src/filter-message.js#L20-L26
 244            navigation.message = navigation.texts.loaded + (navigation.message === navigation.texts.loaded ? '\u00A0' : '');
 245          }
 246        } else {
 247          yield forcePageReload(href);
 248        }
 249      },
 250      /**
 251       * Prefetchs the page with the passed URL.
 252       *
 253       * The function normalizes the URL and stores internally the fetch
 254       * promise, to avoid triggering a second fetch for an ongoing request.
 255       *
 256       * @param {string}  url             The page URL.
 257       * @param {Object}  [options]       Options object.
 258       * @param {boolean} [options.force] Force fetching the URL again.
 259       * @param {string}  [options.html]  HTML string to be used instead of
 260       *                                  fetching the requested URL.
 261       */
 262      prefetch(url, options = {}) {
 263        const {
 264          clientNavigationDisabled
 265        } = (0,interactivity_namespaceObject.getConfig)();
 266        if (clientNavigationDisabled) return;
 267        const pagePath = getPagePath(url);
 268        if (options.force || !pages.has(pagePath)) {
 269          pages.set(pagePath, fetchPage(pagePath, options));
 270        }
 271      }
 272    }
 273  });
 274  
 275  var __webpack_exports__actions = __webpack_exports__.o;
 276  var __webpack_exports__state = __webpack_exports__.w;
 277  export { __webpack_exports__actions as actions, __webpack_exports__state as state };


Generated : Sat Apr 27 08:20:02 2024 Cross-referenced by PHPXref