From 2a2fc09737c5f7f816cf1f39f41f4e62ec9e31f3 Mon Sep 17 00:00:00 2001 From: Alexander Matveyenko Date: Fri, 10 Jul 2026 20:50:42 +0200 Subject: [PATCH 1/7] Migrate to Vite 8, ESM-only TypeScript, template literals - Replace webpack 5 + ejs-loader with Vite 8 (Rolldown) driven from scripts/build.js: five single-entry IIFE builds emit the classic unhashed bundles (embed.js, embed-options.js, options.js, options.i18n.de/fr.js + .min.js variants), plus a multi-entry ESM build in dist/esm/ and tsc-generated declarations in dist/types/. - Rewrite all src/ as strict-TypeScript ES modules. Side-effectful modules now export boot() called by the entries in the original CJS execution order under the _loaded guard, so double-loading bundles still boots exactly once despite ESM import hoisting. - Replace the six EJS templates with template-literal functions in options/renderer.ts. Fixes the group template, which compiled to _.escape() without lodash bundled and threw at runtime, and adds HTML-escaping of scalar interpolations (previously raw). - Drop legacy-browser support: ActiveX/Flash detection, attachEvent, vendor-prefixed rAF/setImmediate, IE styleSheet.cssText, innerText fallbacks, and the Chrome-77 UA sniff (lazy-loading-native.js removed; SUPPORT_IFRAME_LOADING_ATTR hardcoded true). Build targets Vite's baseline-widely-available. - package.json: type=module, v2.0.0, exports map (., ./options, ./i18n/de, ./i18n/fr) pointing at dist/esm + dist/types; webpack and ejs devDependencies removed; flat ESLint config with typescript-eslint; delete stale dist/embed-autoplay*. - Add demo/ smoke-test pages used to verify script-src config parsing, API surface parity, options form + i18n, double-load, and ESM consumption in a real browser. Co-Authored-By: Claude Fable 5 --- .eslintrc | 51 - README.md | 26 +- conf/webpack.common.js | 32 - conf/webpack.development.js | 11 - conf/webpack.production.js | 14 - demo/double.html | 26 + demo/esm.html | 14 + demo/index.html | 11 + demo/new.html | 7 + demo/old.html | 7 + demo/options.html | 23 + dist/embed-autoplay.js | 100 - dist/embed-autoplay.min.js | 8 - dist/embed-options.js | 1752 +++++++++++++---- dist/embed-options.min.js | 39 +- dist/embed.js | 1284 +++++++++--- dist/embed.min.js | 2 +- dist/esm/chunks/deprecated.js | 1024 ++++++++++ {src => dist/esm/chunks}/iframely.js | 5 +- dist/esm/chunks/translator.js | 14 + dist/esm/i18n.de.js | 70 + dist/esm/i18n.fr.js | 63 + dist/esm/main-options.js | 348 ++++ dist/esm/main.js | 24 + dist/options.i18n.de.js | 164 +- dist/options.i18n.de.min.js | 2 +- dist/options.i18n.fr.js | 157 +- dist/options.i18n.fr.min.js | 2 +- dist/options.js | 502 +++-- dist/options.min.js | 39 +- dist/types/ahref.d.ts | 1 + dist/types/const.d.ts | 1 + dist/types/deprecated.d.ts | 1 + dist/types/dom-ready.d.ts | 1 + dist/types/events.d.ts | 1 + dist/types/iframely.d.ts | 3 + dist/types/import.d.ts | 1 + dist/types/index-options.d.ts | 1 + dist/types/index.d.ts | 1 + dist/types/intersection.d.ts | 1 + dist/types/lazy-iframe.d.ts | 1 + dist/types/lazy-img-placeholder.d.ts | 1 + dist/types/main-options.d.ts | 3 + dist/types/main.d.ts | 3 + dist/types/messaging.d.ts | 3 + dist/types/options/entry.d.ts | 1 + dist/types/options/form-builder.d.ts | 10 + dist/types/options/form-generator.d.ts | 2 + dist/types/options/index.d.ts | 1 + dist/types/options/lang/labels.de.d.ts | 1 + dist/types/options/lang/labels.fr.d.ts | 1 + dist/types/options/renderer.d.ts | 4 + dist/types/options/translator.d.ts | 1 + dist/types/theme.d.ts | 1 + dist/types/types.d.ts | 123 ++ dist/types/utils.d.ts | 17 + dist/types/widget-cancel.d.ts | 1 + dist/types/widget-click.d.ts | 1 + dist/types/widget-options.d.ts | 1 + dist/types/widget-resize.d.ts | 1 + eslint.config.js | 36 +- package.json | 49 +- pnpm-lock.yaml | 1584 ++++++--------- scripts/build.js | 65 + src/{ahref.js => ahref.ts} | 90 +- src/const.js | 27 - src/const.ts | 34 + src/deprecated.js | 31 - src/deprecated.ts | 34 + src/{dom-ready.js => dom-ready.ts} | 12 +- src/events.js | 43 - src/events.ts | 46 + src/iframely.ts | 9 + src/import.js | 405 ---- src/import.ts | 362 ++++ src/index-options.js | 30 - src/index-options.ts | 44 + src/index.d.ts | 1 - src/index.js | 29 - src/index.ts | 47 + src/{intersection.js => intersection.ts} | 38 +- src/lazy-iframe.js | 66 - src/lazy-iframe.ts | 68 + src/lazy-img-placeholder.js | 267 --- src/lazy-img-placeholder.ts | 271 +++ src/lazy-loading-native.js | 9 - src/main-options.ts | 6 + src/main.ts | 6 + src/messaging.js | 136 -- src/messaging.ts | 130 ++ src/options/entry.ts | 7 + src/options/form-builder.js | 167 -- src/options/form-builder.ts | 184 ++ .../{form-generator.js => form-generator.ts} | 97 +- src/options/index.js | 15 - src/options/index.ts | 16 + ...s.LAN.example.js => labels.LAN.example.ts} | 15 +- .../lang/{labels.de.js => labels.de.ts} | 6 +- .../lang/{labels.fr.js => labels.fr.ts} | 6 +- src/options/renderer.js | 21 - src/options/renderer.ts | 72 + src/options/templates/checkbox.ejs | 6 - src/options/templates/group.ejs | 5 - src/options/templates/radio.ejs | 17 - src/options/templates/range.ejs | 6 - src/options/templates/select.ejs | 10 - src/options/templates/text.ejs | 6 - src/options/translator.js | 30 - src/options/translator.ts | 33 + src/theme.js | 38 - src/theme.ts | 40 + src/types.ts | 149 ++ src/utils.js | 360 ---- src/utils.ts | 359 ++++ src/widget-cancel.js | 48 - src/widget-cancel.ts | 52 + src/widget-click.js | 25 - src/widget-click.ts | 28 + src/widget-options.js | 7 - src/widget-options.ts | 10 + src/widget-resize.js | 133 -- src/widget-resize.ts | 136 ++ tsconfig.build.json | 12 + tsconfig.json | 20 + webpack.config.js | 4 - 125 files changed, 7922 insertions(+), 4203 deletions(-) delete mode 100644 .eslintrc delete mode 100644 conf/webpack.common.js delete mode 100644 conf/webpack.development.js delete mode 100644 conf/webpack.production.js create mode 100644 demo/double.html create mode 100644 demo/esm.html create mode 100644 demo/index.html create mode 100644 demo/new.html create mode 100644 demo/old.html create mode 100644 demo/options.html delete mode 100644 dist/embed-autoplay.js delete mode 100644 dist/embed-autoplay.min.js create mode 100644 dist/esm/chunks/deprecated.js rename {src => dist/esm/chunks}/iframely.js (59%) create mode 100644 dist/esm/chunks/translator.js create mode 100644 dist/esm/i18n.de.js create mode 100644 dist/esm/i18n.fr.js create mode 100644 dist/esm/main-options.js create mode 100644 dist/esm/main.js create mode 100644 dist/types/ahref.d.ts create mode 100644 dist/types/const.d.ts create mode 100644 dist/types/deprecated.d.ts create mode 100644 dist/types/dom-ready.d.ts create mode 100644 dist/types/events.d.ts create mode 100644 dist/types/iframely.d.ts create mode 100644 dist/types/import.d.ts create mode 100644 dist/types/index-options.d.ts create mode 100644 dist/types/index.d.ts create mode 100644 dist/types/intersection.d.ts create mode 100644 dist/types/lazy-iframe.d.ts create mode 100644 dist/types/lazy-img-placeholder.d.ts create mode 100644 dist/types/main-options.d.ts create mode 100644 dist/types/main.d.ts create mode 100644 dist/types/messaging.d.ts create mode 100644 dist/types/options/entry.d.ts create mode 100644 dist/types/options/form-builder.d.ts create mode 100644 dist/types/options/form-generator.d.ts create mode 100644 dist/types/options/index.d.ts create mode 100644 dist/types/options/lang/labels.de.d.ts create mode 100644 dist/types/options/lang/labels.fr.d.ts create mode 100644 dist/types/options/renderer.d.ts create mode 100644 dist/types/options/translator.d.ts create mode 100644 dist/types/theme.d.ts create mode 100644 dist/types/types.d.ts create mode 100644 dist/types/utils.d.ts create mode 100644 dist/types/widget-cancel.d.ts create mode 100644 dist/types/widget-click.d.ts create mode 100644 dist/types/widget-options.d.ts create mode 100644 dist/types/widget-resize.d.ts create mode 100644 scripts/build.js rename src/{ahref.js => ahref.ts} (55%) delete mode 100644 src/const.js create mode 100644 src/const.ts delete mode 100644 src/deprecated.js create mode 100644 src/deprecated.ts rename src/{dom-ready.js => dom-ready.ts} (53%) delete mode 100644 src/events.js create mode 100644 src/events.ts create mode 100644 src/iframely.ts delete mode 100644 src/import.js create mode 100644 src/import.ts delete mode 100644 src/index-options.js create mode 100644 src/index-options.ts delete mode 100644 src/index.d.ts delete mode 100644 src/index.js create mode 100644 src/index.ts rename src/{intersection.js => intersection.ts} (54%) delete mode 100644 src/lazy-iframe.js create mode 100644 src/lazy-iframe.ts delete mode 100644 src/lazy-img-placeholder.js create mode 100644 src/lazy-img-placeholder.ts delete mode 100644 src/lazy-loading-native.js create mode 100644 src/main-options.ts create mode 100644 src/main.ts delete mode 100644 src/messaging.js create mode 100644 src/messaging.ts create mode 100644 src/options/entry.ts delete mode 100644 src/options/form-builder.js create mode 100644 src/options/form-builder.ts rename src/options/{form-generator.js => form-generator.ts} (69%) delete mode 100644 src/options/index.js create mode 100644 src/options/index.ts rename src/options/lang/{labels.LAN.example.js => labels.LAN.example.ts} (89%) rename src/options/lang/{labels.de.js => labels.de.ts} (97%) rename src/options/lang/{labels.fr.js => labels.fr.ts} (96%) delete mode 100644 src/options/renderer.js create mode 100644 src/options/renderer.ts delete mode 100644 src/options/templates/checkbox.ejs delete mode 100644 src/options/templates/group.ejs delete mode 100644 src/options/templates/radio.ejs delete mode 100644 src/options/templates/range.ejs delete mode 100644 src/options/templates/select.ejs delete mode 100644 src/options/templates/text.ejs delete mode 100644 src/options/translator.js create mode 100644 src/options/translator.ts delete mode 100644 src/theme.js create mode 100644 src/theme.ts create mode 100644 src/types.ts delete mode 100644 src/utils.js create mode 100644 src/utils.ts delete mode 100644 src/widget-cancel.js create mode 100644 src/widget-cancel.ts delete mode 100644 src/widget-click.js create mode 100644 src/widget-click.ts delete mode 100644 src/widget-options.js create mode 100644 src/widget-options.ts delete mode 100644 src/widget-resize.js create mode 100644 src/widget-resize.ts create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json delete mode 100644 webpack.config.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index a6f957a..0000000 --- a/.eslintrc +++ /dev/null @@ -1,51 +0,0 @@ -{ - "env": { - "browser": true, - "commonjs": true, - "es6": true, - "jest": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "sourceType": "module" - }, - "globals": { - "ActiveXObject": true - }, - "rules": { - "indent": [ - "error", - 4, - { - "ignoreComments": true - } - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single", - { - "avoidEscape": true - } - ], - "semi": [ - "error", - "always" - ], - "no-console": [ - "warn", - { - "allow": ["warn", "error"] - } - ], - "no-empty": [ - "error", - { - "allowEmptyCatch": true - } - ] - } -} \ No newline at end of file diff --git a/README.md b/README.md index a9d344e..f2e8c36 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ To serve embed.js script from your network, your reverse proxy needs to be confi You can either clone repo from GitHub, or pull library from NPM as `@iframely/embed.js`. We recommend creating a symlink to a file first for a simpler reverse proxy config. -Alternatively, you may include the contents of embed.js into your other JavaScript distributions. Include `src/index.js` main script or entire `"@iframely/embed.js"` module in your own build configuration to pull all dependencides. +Alternatively, you may include the contents of embed.js into your other JavaScript distributions. The package ships an ES module build: `import '@iframely/embed.js'` (embed only) or `import '@iframely/embed.js/options'` (embed + options form) in your own build to pull all dependencies. TypeScript declarations are included. ## Omit cloud embed.js from API responses @@ -71,9 +71,9 @@ After you run the build process, `options.js` will appear in the `dist`: * `dist/options.js` - not minified development version * `dist/options.min.js` - minified production version -To customize the script, you may consider your own HTML templates for UI elements (see [/options/tempates](https://github.com/itteco/embedjs/tree/master/src/options/templates)) or simply style the default ones with CSS. +To customize the script, you may consider editing the template literals for UI elements (see [src/options/renderer.ts](https://github.com/itteco/embedjs/tree/master/src/options/renderer.ts)) or simply style the default ones with CSS. -To add more languages with form label translations, see [labels.LAN.example.js](https://github.com/itteco/embedjs/tree/master/src/options/lang/labels.LAN.example.js). Pull-request with your translations are welcome. +To add more languages with form label translations, see [labels.LAN.example.ts](https://github.com/itteco/embedjs/tree/master/src/options/lang/labels.LAN.example.ts). Pull-request with your translations are welcome. @@ -81,31 +81,21 @@ To add more languages with form label translations, see [labels.LAN.example.js]( ### Build embed.js -Works with node 16. +The build uses [Vite](https://vite.dev) and TypeScript; sources are ES modules in `src/`. Requires Node 20.19+ (or 22.12+) and [pnpm](https://pnpm.io). Install required modules first: ```bash -npm install +pnpm install ``` -Do a dev build + watch: +Do a full build (typecheck + lint, then all bundles — both minified and not — plus the ESM build and type declarations into `dist/`): ```bash -npm start +pnpm build ``` -Do a production build: - -```bash -npm run build -``` - -Do both dev+production builds: - -```bash -npm run all -``` +The classic script bundles keep their historical names and stay plain IIFE scripts: `dist/embed.js`, `dist/embed-options.js`, `dist/options.js`, `dist/options.i18n.*.js` and their `.min.js` versions. The ES module build for bundler consumers lands in `dist/esm/` with declarations in `dist/types/`. ### Or pull from NPM diff --git a/conf/webpack.common.js b/conf/webpack.common.js deleted file mode 100644 index cabef37..0000000 --- a/conf/webpack.common.js +++ /dev/null @@ -1,32 +0,0 @@ -const path = require('path'); - -module.exports = { - - context: path.join(process.cwd(), 'src'), //the home directory for webpack - - entry: { - 'embed': './index.js', - 'embed-options': './index-options.js', - 'options': './options/index.js', - 'options.i18n.fr': './options/lang/labels.fr.js', - 'options.i18n.de': './options/lang/labels.de.js' - }, - - resolve: { - extensions: ['.js'], // extensions that are used - modules: [path.join(process.cwd(), 'src'), path.join(process.cwd(), 'node_modules'),] // directories where to look for modules - }, - - module: { - rules: [{ - test: /\.ejs$/, - loader: 'ejs-loader', - options: { - esModule: false - } - }] - }, - - plugins: [ - ] -}; diff --git a/conf/webpack.development.js b/conf/webpack.development.js deleted file mode 100644 index 5597798..0000000 --- a/conf/webpack.development.js +++ /dev/null @@ -1,11 +0,0 @@ -const { merge } = require('webpack-merge'); -const CommonConfig = require('./webpack.common.js'); -const path = require('path'); - -module.exports = merge(CommonConfig, { - mode: 'development', - output: { - path: path.join(process.cwd(), 'dist'), - filename: '[name].js' - }, -}); diff --git a/conf/webpack.production.js b/conf/webpack.production.js deleted file mode 100644 index 4376776..0000000 --- a/conf/webpack.production.js +++ /dev/null @@ -1,14 +0,0 @@ -const { merge } = require('webpack-merge'); -const CommonConfig = require('./webpack.common.js'); -const path = require('path'); - -module.exports = merge(CommonConfig, { - mode: 'production', - optimization: { - minimize: true - }, - output: { - path: path.join(process.cwd(), 'dist'), - filename: '[name].min.js' - } -}); diff --git a/demo/double.html b/demo/double.html new file mode 100644 index 0000000..ce368d8 --- /dev/null +++ b/demo/double.html @@ -0,0 +1,26 @@ + + +double-load test + + + + + + diff --git a/demo/esm.html b/demo/esm.html new file mode 100644 index 0000000..7755237 --- /dev/null +++ b/demo/esm.html @@ -0,0 +1,14 @@ + + +ESM consumer test + + + + diff --git a/demo/index.html b/demo/index.html new file mode 100644 index 0000000..a025ce8 --- /dev/null +++ b/demo/index.html @@ -0,0 +1,11 @@ + + +embed.js demo + +

embed.js smoke test

+ +
+ +
+ + diff --git a/demo/new.html b/demo/new.html new file mode 100644 index 0000000..0111f07 --- /dev/null +++ b/demo/new.html @@ -0,0 +1,7 @@ + + +new embed.js surface + + + + diff --git a/demo/old.html b/demo/old.html new file mode 100644 index 0000000..10e26cd --- /dev/null +++ b/demo/old.html @@ -0,0 +1,7 @@ + + +old embed.js surface + + + + diff --git a/demo/options.html b/demo/options.html new file mode 100644 index 0000000..12752a7 --- /dev/null +++ b/demo/options.html @@ -0,0 +1,23 @@ + + +options form demo + +

options form smoke test

+
+ + + + + diff --git a/dist/embed-autoplay.js b/dist/embed-autoplay.js deleted file mode 100644 index b65ee7b..0000000 --- a/dist/embed-autoplay.js +++ /dev/null @@ -1,100 +0,0 @@ -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = "./index-play-on-scroll.js"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ "./index-play-on-scroll.js": -/*!*********************************!*\ - !*** ./index-play-on-scroll.js ***! - \*********************************/ -/*! no static exports found */ -/***/ (function(module, exports) { - -eval("throw new Error(\"Module build failed: Error: ENOENT: no such file or directory, open '/Users/nazar/Documents/workspace/embedjs/src/index-play-on-scroll.js'\");\n\n//# sourceURL=webpack:///./index-play-on-scroll.js?"); - -/***/ }) - -/******/ }); \ No newline at end of file diff --git a/dist/embed-autoplay.min.js b/dist/embed-autoplay.min.js deleted file mode 100644 index 613e819..0000000 --- a/dist/embed-autoplay.min.js +++ /dev/null @@ -1,8 +0,0 @@ -!function(e){var t={};function r(n){if(t[n])return t[n].exports;var i=t[n]={i:n,l:!1,exports:{}};return e[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=18)}([function(e,t){var r=window.iframely=window.iframely||{};r.config=r.config||{},e.exports=r},function(e,t,r){var n=r(0),i=r(2);n.on("init",function(){n.extendOptions(function(){for(var e=document.querySelectorAll('script[src*="embed.js"], script[src*="iframely.js"]'),t=0;t0)return i}}return{}}()),function(){var e=document.getElementById("iframely-styles");if(!e){var t=".iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}";(e=document.createElement("style")).id="iframely-styles",e.type="text/css",e.styleSheet?e.styleSheet.cssText=t:e.innerHTML=t,document.getElementsByTagName("head")[0].appendChild(e)}}(),function(e){for(var t=document.querySelectorAll('iframe[src*="'+(e||n.DOMAINS).join('"], iframe[src*="')+'"]'),r=0;r2||t&&r.getAttribute("class")!==n.ASPECT_WRAPPER_CLASS||!t&&"relative"!==r.style.position&&r.getAttribute("class")!==n.ASPECT_WRAPPER_CLASS)){var i=r.parentNode;if(!(!i||"DIV"!==i.nodeName||s(i)>1||t&&i.getAttribute("class")!==n.MAXWIDTH_WRAPPER_CLASS||!t&&i.getAttribute("class")&&!i.getAttribute("class").match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}};t.addDefaultWrappers=function(e){var t=e.parentNode,r=document.createElement("div");r.className=n.MAXWIDTH_WRAPPER_CLASS;var i=document.createElement("div");return i.className=n.ASPECT_WRAPPER_CLASS,r.appendChild(i),t.insertBefore(r,e),{aspectWrapper:i,maxWidthWrapper:r}},t.getWidget=function(e){var t=o(e);if(t){var r={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper};if("A"===e.nodeName&&e.hasAttribute("href"))r.url=e.getAttribute("href");else if(e.hasAttribute("src")&&/url=/.test(e.getAttribute("src"))){var n=d(e.getAttribute("src"));n.url&&(r.url=n.url)}return r}},n.getElementComputedStyle=function(e,t){return window.getComputedStyle&&window.getComputedStyle(e).getPropertyValue(t)},t.setStyles=function(e,t){e&&Object.keys(t).forEach(function(r){var i=t[r];("number"==typeof i||"string"==typeof i&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+="px"),window.getComputedStyle&&(n.getElementComputedStyle(e,r)==i||"iframely-responsive"==e.className&&"paddingBottom"===r&&!e.style[r]&&/^56\.2\d+%$/.test(i))||(e.style[r]=i||"")})};var a=t.addQueryString=function(e,t){var r="";return Object.keys(t).forEach(function(n){var i=t[n];if("[object Array]"===Object.prototype.toString.call(i)){var o=i.map(function(e){return n+"="+encodeURIComponent(e)});r+="&"+o.join("&")}else void 0!==i&&-1===e.indexOf(n+"=")&&(!0===i&&(i=1),!1===i&&(i=0),r+="&"+n+"="+encodeURIComponent(i))}),e+(""!==r?(e.indexOf("?")>-1?"&":"?")+r.replace(/^&/,""):"")};function s(e){for(var t=0,r=0;r4&&(t=null);var n=t&&t.parentNode;n&&n.getAttribute("class")===i.MAXWIDTH_WRAPPER_CLASS&&(t.removeAttribute("style"),t.removeAttribute("class"),n.removeAttribute("style"))}i.on("load",function(e){if(!e&&!1!==i.config.import&&document.head.attachShadow&&(i.debug||"http:"===document.location.protocol||"https:"===document.location.protocol)&&!i.config.playerjs&&!i.config.lazy&&!i.import){var t=document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])");t.length>1&&function(e){var t=document.createElement("script"),r=[],a=[],u=null;function d(e,t){o[e]||(o[e]=[]),o[e].push(t)}function c(e){var t=e.getAttribute("data-iframely-url"),o=t.match(i.ID_RE),s=o&&o[1],c=n.parseQueryString(t,i.SUPPORTED_QUERY_STRING.concat("url")),l=c.url;delete c.url;var p="0"===c.import||"false"===c.import||"1"===c.playerjs||"true"===c.playerjs;if(!p){var f=t.match(i.BASE_RE);c.CDN=f&&f[0],u?JSON.stringify(c,Object.keys(c).sort())!==JSON.stringify(u,Object.keys(u).sort())&&(p=!0):u=c}if(p)i.trigger("load",e);else if(s)e.setAttribute("data-import-uri",s),-1===a.indexOf(s)&&a.push(s),d(s,e);else{l||(l=e.getAttribute("href"));var m=u.key||u.api_key||i.config.api_key||i.config.key;m&&l?(e.setAttribute("data-import-uri",l),-1===r.indexOf(l)&&r.push(l),d(l,e)):i.trigger("load",e)}}for(var l=0;l0||a.length>0?((u=u||{}).touch=i.isTouch(),u.flash=function(){var e=!1;try{var t=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");e=!!t}catch(t){e=!(!navigator.mimeTypes||null==navigator.mimeTypes["application/x-shockwave-flash"]||!navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)}return e}(),u.app=1,r.length>0&&(u.uri=r),a.length>0&&(u.ids=a.join("&")),u.v=i.VERSION,t.src=n.getEndpoint("/api/import/v2",u,i.SUPPORTED_QUERY_STRING),t.onerror=function(){s()},document.head.appendChild(t),i.import=t):(s(),i.trigger("load"))}(t)}}),i.on("load",function(e,t){if(e&&e.uri&&(e.html||e.cancel)){var r=o[e.uri];if(r)for(var n=0;n1&&function(e,t){for(var r=0,n=0;n=0;return r&&e}(e.maxWidthWrapper,n.config.parent);i&&(t=i.parentNode,r=i)}if(e.url){var o=e.iframe&&(e.iframe.textContent||e.iframe.innerText);n.triggerAsync("cancel",e.url,t,o,r.nextSibling)}t.removeChild(r)}else console.warn("iframely.cancelWidget called without widget param")}},function(e,t,r){var n=r(1),i=r(0);i.on("message",function(e,t){if("setIframelyWidgetSize"===t.method||"resize"===t.method||"setIframelyEmbedData"===t.method){var r={};t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(";").forEach(function(e){if(""!==e.trim()&&e.indexOf(":")>-1){var t=e.split(":");2===t.length&&(r[t[0].trim()]=t[1].trim())}}),s(e,r)):"setIframelyEmbedData"===t.method&&s(e,null),function(e,t){if(t&&Object.keys(t).length>0&&e){var r=function(e){var t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,r=t&&t.match(/(\d+)px/)||0;r&&(r=parseInt(r[1]),r*=2);return r}(e),o=window.getComputedStyle&&window.getComputedStyle(e.iframe).getPropertyValue("height");n.setStyles(e.maxWidthWrapper,{"max-width":t["max-width"]&&t["max-width"]+r,"min-width":t["min-width"]&&t["min-width"]+r,width:t.width&&t.width+r}),t.scrolling&&e.iframe&&e.iframe.setAttribute("scrolling",t.scrolling);var a=t["aspect-ratio"];n.setStyles(e.aspectWrapper,{paddingBottom:a?Math.round(1e5/a)/1e3+"%":0,paddingTop:a&&t["padding-bottom"],height:a?0:t.height&&t.height+r});var s=window.getComputedStyle&&window.getComputedStyle(e.iframe).getPropertyValue("height");o&&o!==s&&i.triggerAsync("heightChanged",e.iframe,o,s)}}(e,t.data&&t.data.media||{height:t.height})}});var o={border:"","border-radius":"","box-shadow":"",overflow:""},a={border:"0","border-radius":"","box-shadow":"",overflow:""};function s(e,t){t&&e&&e.iframe?t["border-radius"]?(t.overflow="hidden",n.setStyles(e.aspectWrapper,t)):n.setStyles(e.iframe,t):!t&&e&&e.iframe&&(n.setStyles(e.aspectWrapper,o),n.setStyles(e.iframe,a))}},function(e,t,r){var n=r(0);n.on("message",function(e,t){"open-href"!==t.method&&"click"!==t.method||n.trigger(t.method,t.href)}),n.on("open-href",function(e){n.triggerAsync("click",e),0===e.indexOf(window.location.origin)?window.location.href=e:window.open(e,"_blank")})},function(e,t,r){var n=r(0);n.on("message",function(e,t){"setIframelyEmbedOptions"===t.method&&n.trigger("options",e,t.data)})},function(e,t,r){var n=r(0);n.widgets=n.widgets||{},n.widgets.load=n.load,n.events||(n.events={},n.events.on=n.on,n.events.trigger=n.trigger),n.on("cancel",function(e,t,r,n){if(e&&t&&r&&""!==r){var i=document.createElement("a");i.setAttribute("href",e),i.setAttribute("target","_blank"),i.textContent=r,n?t.insertBefore(i,n):t.appendChild(i)}})},,function(e,t,r){r(3);var n=r(0);n._loaded||(n._loaded=!0,r(4),r(5),r(7),r(8),r(9),r(10),r(11),r(19),r(12),r(13),r(14),r(15),r(16),n.trigger("init")),t.iframely=n},function(e,t,r){var n,i=r(20),o=r(0),a={threshold:1};var s=[];function u(e){e.forEach(function(e){if(e.isIntersecting){var t=function(e){for(var t,r=0;r0,"Get methods require a callback."),r.unshift(t)):(/^set/.test(e)&&(a.assert(0!==r.length,"Set methods require a value."),t.value=r[0]),r=[t]),this.send.apply(this,r)}}a.DEBUG=!1,a.VERSION="0.0.11",a.CONTEXT="player.js",a.POST_MESSAGE=!!i.postMessage,a.origin=function(e){return"//"===e.substr(0,2)&&(e=i.location.protocol+e),e.split("/").slice(0,3).join("/")},a.addEvent=function(e,t,r){e&&(e.addEventListener?e.addEventListener(t,r,!1):e.attachEvent?e.attachEvent("on"+t,r):e["on"+t]=r)},a.log=function(){a.log.history=a.log.history||[],a.log.history.push(arguments),i.console&&a.DEBUG&&i.console.log(Array.prototype.slice.call(arguments))},a.isString=function(e){return"[object String]"===Object.prototype.toString.call(e)},a.isObject=function(e){return"[object Object]"===Object.prototype.toString.call(e)},a.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)},a.isNone=function(e){return null==e},a.has=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.indexOf=function(e,t){if(null==e)return-1;var r=0,n=e.length;if(Array.prototype.IndexOf&&e.indexOf===Array.prototype.IndexOf)return e.indexOf(t);for(;r-1?r.loaded=!0:this.elem.onload=function(){r.loaded=!0}},a.Player.prototype.send=function(e,t,r){if(e.context=a.CONTEXT,e.version=a.VERSION,t){var n=this.keeper.getUUID();e.listener=n,this.keeper.one(n,e.method,t,r)}return this.isReady||"ready"===e.value?(a.log("Player.send",e,this.origin),!0===this.loaded&&this.elem.contentWindow.postMessage(JSON.stringify(e),this.origin),!0):(a.log("Player.queue",e),this.queue.push(e),!1)},a.Player.prototype.receive=function(e){if(a.log("Player.receive",e),e.origin!==this.origin)return!1;var t;try{t=JSON.parse(e.data)}catch(e){return!1}if(t.context!==a.CONTEXT)return!1;"ready"===t.event&&t.value&&t.value.src===this.elem.src&&this.ready(t),this.keeper.has(t.event,t.listener)&&this.keeper.execute(t.event,t.listener,t.value,this)},a.Player.prototype.ready=function(e){if(!0===this.isReady)return!1;e.value.events&&(this.events=e.value.events),e.value.methods&&(this.methods=e.value.methods),this.isReady=!0,this.loaded=!0;for(var t=0;t0)for(var n in r)return this.send({method:"removeEventListener",value:e,listener:r[n]}),!0;return!1},a.Player.prototype.supports=function(e,t){a.assert(a.indexOf(["method","event"],e)>-1,'evtOrMethod needs to be either "event" or "method" got '+e),t=a.isArray(t)?t:[t];for(var r="event"===e?this.events:this.methods,n=0;n-1&&this.eventListeners[t.value].splice(n,1),0===this.eventListeners[t.value].length&&delete this.eventListeners[t.value]}}else this.get(t.method,t.value,r)},a.Receiver.prototype.get=function(e,t,r){var n=this;if(!this.methods.hasOwnProperty(e))return this.emit("error",{code:3,msg:'Method Not Supported"'+e+'"'}),!1;var i=this.methods[e];if("get"===e.substr(0,3)){i.call(this,function(t){n.send(e,t,r)})}else i.call(this,t)},a.Receiver.prototype.on=function(e,t){this.methods[e]=t},a.Receiver.prototype.send=function(e,t,r){if(a.log("Receiver.send",e,t,r),this.reject)return a.log("Receiver.send.reject",e,t,r),!1;var n={context:a.CONTEXT,version:a.VERSION,event:e};a.isNone(t)||(n.value=t),a.isNone(r)||(n.listener=r);var o=JSON.stringify(n);i.parent.postMessage(o,""===this.origin?"*":this.origin)},a.Receiver.prototype.emit=function(e,t){if(!this.eventListeners.hasOwnProperty(e))return!1;a.log("Instance.emit",e,t,this.eventListeners[e]);for(var r=0;r { // webpackBootstrap -/******/ var __webpack_modules__ = ({ - -/***/ "./options/templates/checkbox.ejs" -/*!****************************************!*\ - !*** ./options/templates/checkbox.ejs ***! - \****************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\nwith (obj) {\n__p += '
\\n \\n ' +\n((__t = ( label )) == null ? '' : __t) +\n'\\n \\n
\\n';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/checkbox.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/group.ejs" -/*!*************************************!*\ - !*** ./options/templates/group.ejs ***! - \*************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __e = _.escape;\nwith (obj) {\n__p += '
\\n
\\n ' +\n__e( elementsHtml ) +\n'\\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/group.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/radio.ejs" -/*!*************************************!*\ - !*** ./options/templates/radio.ejs ***! - \*************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\nwith (obj) {\n__p += '
\\n ';\n if (label) { ;\n__p += '\\n \\n ';\n } ;\n__p += '\\n
\\n ' +\n((__t = ( subContext.label )) == null ? '' : __t) +\n'\\n \\n
\\n ';\n }); ;\n__p += '\\n
\\n';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/radio.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/range.ejs" -/*!*************************************!*\ - !*** ./options/templates/range.ejs ***! - \*************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '';\nwith (obj) {\n__p += '
\\n \\n
\\n \\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/range.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/select.ejs" -/*!**************************************!*\ - !*** ./options/templates/select.ejs ***! - \**************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\nwith (obj) {\n__p += '
\\n \\n
\\n \\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/select.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/text.ejs" -/*!************************************!*\ - !*** ./options/templates/text.ejs ***! - \************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '';\nwith (obj) {\n__p += '
\\n \\n
\\n \\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/text.ejs?\n}"); - -/***/ }, - -/***/ "./ahref.js" -/*!******************!*\ - !*** ./ahref.js ***! - \******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('load', function(container, href) {\n if (container && container.nodeName && typeof href === 'string') {\n var a = document.createElement('a');\n a.setAttribute('href', href);\n container.appendChild(a);\n iframely.trigger('load', a);\n }\n});\n\niframely.on('load', function(el) {\n\n if (!el && !iframely.import) { \n\n var elements = document.querySelectorAll('a[data-iframely-url]:not([data-import-uri])');\n for(var i = 0; i < elements.length; i++) {\n iframely.trigger('load', elements[i]);\n }\n }\n \n});\n\niframely.on('load', function(el) {\n\n if (el && el.nodeName === 'A' && (el.getAttribute('data-iframely-url') || el.getAttribute('href')) && !el.hasAttribute('data-import-uri')) {\n unfurl(el);\n }\n \n});\n\nfunction unfurl(el) {\n if (!el.getAttribute('data-iframely-url') && !el.getAttribute('href')) {\n return; // isn't valid\n }\n var src;\n\n var dataIframelyUrl = el.getAttribute('data-iframely-url');\n if (dataIframelyUrl && /^((?:https?:)?\\/\\/[^/]+)\\/\\w+/i.test(dataIframelyUrl)) {\n src = utils.getEndpoint(dataIframelyUrl, {\n v: iframely.VERSION,\n app: 1,\n theme: iframely.config.theme\n });\n } else if ((iframely.config.api_key || iframely.config.key) && iframely.CDN) {\n\n if (!el.getAttribute('href')) {\n console.warn('Iframely cannot build embeds: \"href\" attribute missing in', el);\n return;\n }\n\n src = utils.getEndpoint('/api/iframe', {\n url: el.getAttribute('href'),\n v: iframely.VERSION,\n app: 1,\n theme: iframely.config.theme\n }, iframely.SUPPORTED_QUERY_STRING);\n } else {\n console.warn('Iframely cannot build embeds: api key is required as query-string of embed.js');\n }\n\n if (!src) {\n el.removeAttribute('data-iframely-url'); \n } else {\n\n var iframe = document.createElement('iframe');\n\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('allow', 'autoplay *; encrypted-media *; ch-prefers-color-scheme *');\n\n if (el.hasAttribute('data-img')) {\n iframe.setAttribute('data-img', el.getAttribute('data-img'));\n }\n\n var isLazy = el.hasAttribute('data-lazy') || el.hasAttribute('data-img') || /&lazy=1/.test(src) || iframely.config.lazy;\n\n // support restoring failed links by its text\n var text = el.textContent || el.innerText;\n \n if (text && text !== '') {\n iframe.textContent = text;\n } \n\n var wrapper = utils.getIframeWrapper(el, true);\n \n if (wrapper) {\n\n // Delete all in aspect wrapper.\n while (wrapper.aspectWrapper.lastChild) {\n wrapper.aspectWrapper.removeChild(wrapper.aspectWrapper.lastChild);\n }\n\n } else {\n wrapper = utils.addDefaultWrappers(el);\n\n var parentNode = el.parentNode;\n parentNode.removeChild(el);\n }\n\n wrapper.aspectWrapper.appendChild(iframe);\n\n if (isLazy) {\n \n // send to lazy iframe flow\n iframe.setAttribute('data-iframely-url', src);\n iframely.trigger('load', iframe);\n\n } else {\n\n iframe.setAttribute('src', src);\n iframely.trigger('iframe-ready', iframe);\t\t\t\n }\n\n\n }\n\n\n}\n\n//# sourceURL=webpack:///./ahref.js?\n}"); - -/***/ }, - -/***/ "./const.js" -/*!******************!*\ - !*** ./const.js ***! - \******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.VERSION = 1;\n\niframely.ASPECT_WRAPPER_CLASS = 'iframely-responsive';\niframely.MAXWIDTH_WRAPPER_CLASS = 'iframely-embed';\niframely.LOADER_CLASS = 'iframely-loader';\n\niframely.DOMAINS = ['cdn.iframe.ly', 'iframe.ly', 'if-cdn.com', 'iframely.net'];\niframely.CDN = iframely.CDN || iframely.DOMAINS[0]; // default domain, user or script src can change CDN\n\niframely.BASE_RE = /^(?:https?:)?\\/\\/[^/]+/i;\niframely.ID_RE = /^(?:https?:)?\\/\\/[^/]+\\/(\\w+-?\\w+)(?:\\?.*)?$/;\niframely.SCRIPT_RE = /^(?:https?:|file:\\/)?\\/\\/[^/]+(?:.+)?\\/(?:embed|iframely)\\.js(?:[^/]+)?$/i;\niframely.CDN_RE = /^(?:https?:)?\\/\\/([^/]+)\\/(?:embed|iframely)\\.js(?:[^/]+)?$/i;\n\niframely.SUPPORTED_QUERY_STRING = ['api_key', 'key', 'iframe', 'html5', 'playerjs', 'align', 'language', 'media', 'maxwidth', 'maxheight', 'lazy', 'import', 'parent', 'shadow', 'click_to_play', 'autoplay', 'mute', 'card', 'consent', 'theme', /^_.+/];\n\niframely.SUPPORTED_THEMES = ['auto', 'light', 'dark'];\n\niframely.LAZY_IFRAME_SHOW_TIMEOUT = 3000;\niframely.LAZY_IFRAME_FADE_TIMEOUT = 200;\niframely.CLEAR_WRAPPER_STYLES_TIMEOUT = 3000;\n\niframely.RECOVER_HREFS_ON_CANCEL = false;\n\niframely.SHADOW = 'iframely-shadow';\n\n//# sourceURL=webpack:///./const.js?\n}"); - -/***/ }, - -/***/ "./deprecated.js" -/*!***********************!*\ - !*** ./deprecated.js ***! - \***********************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\n// deprecated. Helper function only, for the reverse compatibility.\niframely.widgets = iframely.widgets || {};\niframely.widgets.load = iframely.load;\n\nif (!iframely.events) {\n iframely.events = {};\n iframely.events.on = iframely.on;\n iframely.events.trigger = iframely.trigger;\n}\n\niframely.on('cancel', function(url, parentNode, text, nextSibling) {\n\n if (iframely.RECOVER_HREFS_ON_CANCEL && !text) {\n text = url;\n }\n\n if (url && parentNode && text && text !== '') {\n var a = document.createElement('a');\n a.setAttribute('href', url);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.textContent = text;\n if (nextSibling) {\n parentNode.insertBefore(a, nextSibling);\n } else {\n parentNode.appendChild(a);\n }\n }\n});\n\n//# sourceURL=webpack:///./deprecated.js?\n}"); - -/***/ }, - -/***/ "./dom-ready.js" -/*!**********************!*\ - !*** ./dom-ready.js ***! - \**********************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{// TODO: rename core.js to ready.js?\n\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nvar DOMReady = function(f) {\n if (document.readyState === 'complete' || document.readyState === 'interactive') {\n // Run always (in case of async script).\n setTimeout(f, 0);\n }\n document['addEventListener'] ? document['addEventListener']('DOMContentLoaded', f) : window.attachEvent('onload', f);\n};\n\nDOMReady(function() {\n\n // Called each time on script load\n if (typeof iframely.config.autorun === 'undefined' || iframely.config.autorun !== false) {\n iframely.trigger('load');\n }\n});\n\n\n//# sourceURL=webpack:///./dom-ready.js?\n}"); - -/***/ }, - -/***/ "./events.js" -/*!*******************!*\ - !*** ./events.js ***! - \*******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nvar nextTick = (function(window, prefixes, i, fnc) {\n while (!fnc && i < prefixes.length) {\n fnc = window[prefixes[i++] + 'equestAnimationFrame'];\n }\n return (fnc && fnc.bind(window)) || window.setImmediate || function(fnc) {window.setTimeout(fnc, 0);};\n})(typeof window !== 'undefined' ? window : __webpack_require__.g, 'r webkitR mozR msR oR'.split(' '), 0);\n\nvar callbacksStack = {};\niframely.on = function(event, cb) {\n var events = callbacksStack[event] = callbacksStack[event] || [];\n events.push(cb);\n};\n\nfunction trigger(event, async, args) {\n var events = callbacksStack[event] || [];\n events.forEach(function(cb) {\n if (async) {\n nextTick(function() {\n cb.apply(iframely, args);\n });\n } else {\n cb.apply(iframely, args);\n }\n });\n\n if (event === 'init') {\n // everything inited, let's clear the callstack, just in case\n // TODO: not good.\n callbacksStack[event] = [];\n }\n}\n\niframely.trigger = function(event) {\n var args = Array.prototype.slice.call(arguments, 1);\n trigger(event, false, args);\n};\n\niframely.triggerAsync = function(event) {\n var args = Array.prototype.slice.call(arguments, 1);\n trigger(event, true, args);\n};\n\n//# sourceURL=webpack:///./events.js?\n}"); - -/***/ }, - -/***/ "./iframely.js" -/*!*********************!*\ - !*** ./iframely.js ***! - \*********************/ -(module) { - -eval("{var iframely = window.iframely = window.iframely || {};\niframely.config = iframely.config || {};\n\nmodule.exports = iframely;\n\n//# sourceURL=webpack:///./iframely.js?\n}"); - -/***/ }, - -/***/ "./import.js" -/*!*******************!*\ - !*** ./import.js ***! - \*******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\n// widgetsCache is used from inside import doc for js callbacks and custom features\nvar widgetsCache = {};\n\niframely.on('load', function(el) {\n\n // load once, if import is not in process and only if query-string from script src has not disabled import\n if (!el && iframely.config.import !== false \n && isImportAble()\n && !iframely.import) {\n\n var elements = document.querySelectorAll('a[data-iframely-url]:not([data-import-uri])');\n if (elements.length > 1) {\n makeImportAPICall(elements);\n }\n }\n\n});\n\niframely.on('load', function(widget, importOptions) {\n\n if (widget && widget.uri && (widget.html || widget.cancel)) {\n\n var els = widgetsCache[widget.uri];\n // alternatively, could as well do querySelectorAll('a[data-iframely-url][data-import=\"' + template.getAttribute('data-uri') + '\"')\n\n if (els) {\n for (var i = 0; i < els.length; i++) {\n loadImportWidget(widget, els[i], importOptions);\n }\n }\n\n delete widgetsCache[widget.uri];\n }\n});\n\nfunction makeImportAPICall(elements) {\n var script = utils.createScript();\n\n var uris = [];\n var ids = [];\n \n var import_options = null; // will be populated from first element; or will remain as null if no params in elements...\n\n // couple helper functions first\n\n function pushElement(uri, el) {\n if (!widgetsCache[uri]) {\n widgetsCache[uri] = [];\n }\n\n widgetsCache[uri].push(el);\n }\n\n function queueElement(el) {\n var src = el.getAttribute('data-iframely-url');\n\n var mId = src.match(iframely.ID_RE);\n var id = mId && mId[1];\n\n var options = utils.parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat('url'));\n\n var url = options.url; // can be undefined for IDs\n delete options.url;\n\n // skip import on import=0, playerjs=1\n var skipImport = options.import === '0' || options.import === 'false' \n || options.playerjs === '1' || options.playerjs === 'true';\n\n // or if link's query-string params or CDN are different from the others\n if (!skipImport) {\n var mBase = src.match(iframely.BASE_RE);\n options.CDN = mBase && mBase[0]; // will fall back to iframely.CDN in getEndpoint('/import...' ...)\n\n // set import options from the first el in import\n // that includes api keys \n if (!import_options) {\n import_options = options;\n\n // else check that this el's options are the same as the first one's in import\n } else if (JSON.stringify(options, Object.keys(options).sort()) \n !== JSON.stringify(import_options, Object.keys(import_options).sort())) {\n\n skipImport = true;\n }\n }\n\n\n if (skipImport) {\n // Usual build if no uri and app=1s.\n iframely.trigger('load', el);\n\n } else if (id) {\n el.setAttribute('data-import-uri', id);\n if (ids.indexOf(id) === -1) {\n ids.push(id);\n }\n pushElement(id, el);\n\n } else {\n\n if (!url) {\n url = el.getAttribute('href');\n }\n\n var key = import_options.key || import_options.api_key || iframely.config.api_key || iframely.config.key;\n\n if (key && url) {\n\n el.setAttribute('data-import-uri', url);\n if (uris.indexOf(url) === -1) {\n uris.push(url);\n }\n pushElement(url, el);\n } else {\n // Usual build if no uri.\n iframely.trigger('load', el);\n }\n }\n }\n\n\n // start actual filling up of import request\n\n for(var i = 0; i < elements.length; i++) {\n var el = elements[i];\n if (!el.getAttribute('data-import-uri') && el.hasAttribute('data-iframely-url')) {\n queueElement(el);\n }\n }\n\n if ((uris.length > 0 || ids.length > 0)) {\n\n import_options = import_options || {};\n import_options.touch = iframely.isTouch();\n import_options.flash = hasFlash();\n import_options.app = 1;\n // Do not override imports theme if global theme not set.\n if (iframely.config.theme) {\n import_options.theme = iframely.config.theme;\n }\n\n if (uris.length > 0) {\n import_options.uri = uris;\n }\n\n if (ids.length > 0) {\n import_options.ids = ids.join('&');\n }\n\n import_options.v = iframely.VERSION;\n\n script.src = utils.getEndpoint('/api/import/v2', import_options, iframely.SUPPORTED_QUERY_STRING);\n\n script.onerror = function() {\n // Error loading import. No import this time.\n importReady();\n };\n\n document.head.appendChild(script);\n iframely.import = script;\n\n } else {\n importReady();\n iframely.trigger('load');\n }\n}\n\niframely.buildImportWidgets = function(importOptions) {\n\n iframely.trigger('import-loaded', importOptions);\n\n importOptions.widgets.forEach(function(widget) {\n iframely.trigger('load', widget, importOptions);\n });\n\n importReady();\n};\n\nfunction loadImportWidget(widgetOptions, el, importOptions) {\n\n var needCancelWidget = widgetOptions.cancel;\n var shadow = widgetOptions.shadow;\n var hasRenderedEvent = widgetOptions.renderEvent;\n\n var wrapper = utils.getIframeWrapper(el, true);\n var widget;\n\n if (needCancelWidget) {\n widget = utils.getWidget(el);\n\n iframely.cancelWidget(widget || {\n maxWidthWrapper: el,\n iframe: el,\n url: el.getAttribute('href') \n });\n\n } else {\n\n widget = document.createElement('div');\n widget.innerHTML = widgetOptions.html;\n \n var parent, replacedEl;\n\n if (wrapper && !hasRenderedEvent) {\n // Inline widget will replace 'aspectWrapper' but keep 'maxWidthWrapper' as 'iframely-embed' to fix centering, etc.\n // If has rendered event - keep wrapper and remove attrs later by event.\n parent = wrapper.aspectWrapper.parentNode;\n replacedEl = wrapper.aspectWrapper;\n\n // Clear custom attributes.\n wrapper.maxWidthWrapper.removeAttribute('style');\n } else {\n // No wrapper or keep wrapper for later removal.\n parent = el.parentNode;\n replacedEl = el;\n }\n\n if (shadow) {\n\n var shadowContainer = document.createElement('div');\n var shadowRoot = shadowContainer.attachShadow({mode: 'open'});\n shadowRoot.appendChild(widget);\n\n var shadowWidgetOptions = {\n shadowRoot: shadowRoot,\n shadowContainer: shadowContainer,\n container: parent,\n context: widgetOptions.context,\n stylesIds: widgetOptions.stylesIds,\n stylesDict: importOptions.commonShadowStyles\n };\n \n iframely.trigger('import-shadow-widget-before-render', shadowWidgetOptions);\n \n parent.insertBefore(shadowContainer, replacedEl);\n\n iframely.trigger('import-shadow-widget-after-render', shadowWidgetOptions);\n \n } else {\n\n parent.insertBefore(widget, replacedEl);\n\n exec_body_scripts(widget);\n }\n\n parent.removeChild(replacedEl);\n\n if (hasRenderedEvent) {\n setTimeout(function() {\n clearWrapperStylesAndClass(parent);\n }, iframely.CLEAR_WRAPPER_STYLES_TIMEOUT);\n }\n }\n}\n\n\nfunction importReady() {\n\n delete iframely.import;\n\n // clean up all, let other loaders have a go\n var failed_elements = document.querySelectorAll('a[data-iframely-url][data-import-uri]');\n for(var i = 0; i < failed_elements.length; i++) {\n failed_elements[i].removeAttribute('data-import-uri');\n iframely.trigger('load', failed_elements[i]);\n }\n}\n\niframely.isTouch = function() {\n return 'ontouchstart' in window // works on most browsers\n || navigator.maxTouchPoints; // works on IE10/11 and Surface\n};\n\nfunction hasFlash() {\n\n var _hasFlash = false;\n\n try {\n var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');\n if (fo) {\n _hasFlash = true;\n } else {\n _hasFlash = false;\n }\n } catch (e) {\n if (navigator.mimeTypes\n && navigator.mimeTypes['application/x-shockwave-flash'] != undefined\n && navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) {\n _hasFlash = true;\n } else {\n _hasFlash = false;\n }\n }\n\n return _hasFlash;\n}\n\nfunction isImportAble() {\n\n return document.head.attachShadow\n && document.location // Prevent `Cannot read properties of null (reading 'protocol')` for sandbox iframes.\n && (iframely.debug || document.location.protocol === 'http:' || document.location.protocol === 'https:') // Skip import on file:///\n && !iframely.config.playerjs && !iframely.config.lazy;\n // && !navigator.userAgent.toLowerCase().indexOf('firefox') > -1;\n // TODO: test in Firefox 63\n}\n\nfunction clearWrapperStylesAndClass(el) {\n var aspectWrapper = el;\n var parents = 0;\n while(aspectWrapper \n && (!aspectWrapper.getAttribute('class')\n || aspectWrapper.getAttribute('class').split(' ').indexOf(iframely.ASPECT_WRAPPER_CLASS) === -1)) {\n\n aspectWrapper = aspectWrapper.parentNode;\n parents++;\n if (parents > 4) {\n // Do not search further 4 parents.\n aspectWrapper = null;\n }\n }\n\n var maxWidthWrapper = aspectWrapper && aspectWrapper.parentNode;\n if (maxWidthWrapper \n && maxWidthWrapper.getAttribute('class')\n && maxWidthWrapper.getAttribute('class').split(' ').indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) > -1) {\n\n // Remove wrapper specific data. Leave only 'iframely-embed' parent class.\n aspectWrapper.removeAttribute('style');\n aspectWrapper.removeAttribute('class');\n maxWidthWrapper.removeAttribute('style');\n }\n}\n\niframely.on('import-widget-ready', clearWrapperStylesAndClass);\n\n// used in server templates\n\nif (!iframely.addEventListener) {\n iframely.addEventListener = function(elem, type, eventHandle) {\n if (!elem) { return; }\n if ( elem.addEventListener ) {\n elem.addEventListener( type, eventHandle, false );\n } else if ( elem.attachEvent ) {\n elem.attachEvent( 'on' + type, eventHandle );\n } else {\n elem['on' + type] = eventHandle;\n }\n };\n}\n\nfunction exec_body_scripts(body_el) {\n function nodeName(elem, name) {\n return elem.nodeName && elem.nodeName.toUpperCase() ===\n name.toUpperCase();\n }\n\n function evalScript(elem) {\n var data = (elem.text || elem.textContent || elem.innerHTML || '' ),\n script = utils.createScript();\n\n // Copy all script attributes.\n script.type = 'text/javascript';\n for (var i = 0; i < elem.attributes.length; i++) {\n var attr = elem.attributes[i];\n script.setAttribute(attr.name, attr.value);\n }\n try {\n // doesn't work on ie...\n script.appendChild(document.createTextNode(data));\n } catch(e) {\n // IE has funky script nodes\n script.text = data;\n }\n\n body_el.appendChild(script);\n }\n\n // main section of function\n var scripts = [],\n script,\n children_nodes = body_el.childNodes,\n child,\n i;\n\n for (i = 0; children_nodes[i]; i++) {\n child = children_nodes[i];\n if (nodeName(child, 'script' ) &&\n (!child.type || child.type.toLowerCase() === 'text/javascript' || child.type.toLowerCase() === 'application/javascript')) {\n scripts.push(child);\n body_el.removeChild(child);\n } else {\n exec_body_scripts(child);\n }\n }\n\n for (i = 0; scripts[i]; i++) {\n script = scripts[i];\n if (script.parentNode) {script.parentNode.removeChild(script);}\n evalScript(scripts[i]);\n }\n}\n\n//# sourceURL=webpack:///./import.js?\n}"); - -/***/ }, - -/***/ "./index-options.js" -/*!**************************!*\ - !*** ./index-options.js ***! - \**************************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{__webpack_require__(/*! ./dom-ready */ \"./dom-ready.js\");\n\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nif (!iframely._loaded) {\n\n iframely._loaded = true;\n\n __webpack_require__(/*! ./const */ \"./const.js\");\n __webpack_require__(/*! ./events */ \"./events.js\");\n // require('./utils'); // Loaded by other modules.\n __webpack_require__(/*! ./intersection */ \"./intersection.js\");\n __webpack_require__(/*! ./theme */ \"./theme.js\");\n __webpack_require__(/*! ./import */ \"./import.js\");\n __webpack_require__(/*! ./ahref */ \"./ahref.js\");\n __webpack_require__(/*! ./lazy-img-placeholder */ \"./lazy-img-placeholder.js\");\n __webpack_require__(/*! ./lazy-iframe */ \"./lazy-iframe.js\");\n // require('./messaging'); // Loaded by other modules.\n __webpack_require__(/*! ./widget-cancel */ \"./widget-cancel.js\");\n __webpack_require__(/*! ./widget-resize */ \"./widget-resize.js\");\n __webpack_require__(/*! ./widget-click */ \"./widget-click.js\");\n __webpack_require__(/*! ./widget-options */ \"./widget-options.js\");\n __webpack_require__(/*! ./deprecated */ \"./deprecated.js\");\n __webpack_require__(/*! ./lazy-loading-native */ \"./lazy-loading-native.js\");\n __webpack_require__(/*! ./options */ \"./options/index.js\");\n\n iframely.trigger('init');\n}\n\nexports.iframely = iframely;\n\n\n//# sourceURL=webpack:///./index-options.js?\n}"); - -/***/ }, - -/***/ "./intersection.js" -/*!*************************!*\ - !*** ./intersection.js ***! - \*************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var messaging = __webpack_require__(/*! ./messaging */ \"./messaging.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nvar observers = {};\n\nfunction getObserver(options) {\n var optionsKey = JSON.stringify(options);\n var observer = observers[optionsKey];\n if (!observer) {\n\n observer = new IntersectionObserver(function(entries) {\n\n entries.forEach(function(entry) {\n messaging.postMessage({\n method: 'intersection',\n entry: {\n isIntersecting: entry.isIntersecting\n },\n options: options\n }, '*', entry.target.contentWindow);\n });\n\n }, getObserverOptions(options));\n\n observers[optionsKey] = observer;\n }\n return observer;\n}\n\nfunction getObserverOptions(options) {\n var result = {};\n if (options && options.threshold) {\n result.threshold = options.threshold;\n }\n if (options && options.margin) {\n result.rootMargin = options.margin + 'px ' + options.margin + 'px ' + options.margin + 'px ' + options.margin + 'px';\n }\n return result;\n}\n\nif ('IntersectionObserver' in window &&\n 'IntersectionObserverEntry' in window) {\n\n iframely.on('init', function() {\n\n iframely.extendOptions({\n intersection: 1\n });\n \n });\n\n iframely.on('message', function(widget, message) {\n if (message.method === 'send-intersections' && widget.iframe) {\n\n var options = message.options;\n\n if (!options) {\n options = {\n margin: 1000\n };\n }\n\n getObserver(options).observe(widget.iframe);\n }\n });\n}\n\n\n//# sourceURL=webpack:///./intersection.js?\n}"); - -/***/ }, - -/***/ "./lazy-iframe.js" -/*!************************!*\ - !*** ./lazy-iframe.js ***! - \************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\n// Need 'load' handler here instead of on('init') - we load lazy iframes only when DOM ready.\niframely.on('load', function(el) { \n\n if (!el) { // initial load\n\n var elements = document.querySelectorAll('iframe[data-iframely-url]');\n for(var i = 0; i < elements.length; i++) {\n iframely.trigger('load', elements[i]);\n } \n }\n \n});\n\niframely.on('load', function(el) {\n\n if (el && el.nodeName === 'IFRAME'\n && el.hasAttribute('data-iframely-url')\n && !el.hasAttribute('data-img')\n && !el.getAttribute('src')) {\n\n loadLazyIframe(el);\n }\n \n});\n\n\nfunction loadLazyIframe(el) {\n\n var widget = utils.getWidget(el);\n var src = el.getAttribute('data-iframely-url');\n var dataImg = el.hasAttribute('data-img-created') || el.hasAttribute('data-img');\n var nativeLazyLoad = !dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR;\n\n if (widget && src) {\n\n var options = {\n v: iframely.VERSION,\n app: 1, // for example, will fall back to summary card if media is not longer available\n theme: iframely.config.theme\n };\n\n if (!nativeLazyLoad && iframely.config.intersection) {\n options.lazy = 1;\n }\n\n src = utils.getEndpoint(src, options);\n\n }\n\n if (nativeLazyLoad) {\n el.setAttribute('loading', 'lazy');\n }\n\n if (dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR) {\n // Disable lazy load with `data-img`.\n el.setAttribute('loading', 'edge');\n }\n\n el.setAttribute('src', src);\n el.removeAttribute('data-iframely-url');\n\n iframely.trigger('iframe-ready', el);\n}\n\n//# sourceURL=webpack:///./lazy-iframe.js?\n}"); - -/***/ }, - -/***/ "./lazy-img-placeholder.js" -/*!*********************************!*\ - !*** ./lazy-img-placeholder.js ***! - \*********************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('load', function(el) {\n\n if (el && el.nodeName === 'IFRAME'\n && el.hasAttribute('data-iframely-url')\n && el.hasAttribute('data-img')\n && !el.getAttribute('src')) {\n\n var dataImg = el.getAttribute('data-img');\n\n el.removeAttribute('data-img');\n el.setAttribute('data-img-created', '');\n\n var widget = utils.getWidget(el);\n var src = el.getAttribute('data-iframely-url');\n\n addPlaceholderThumbnail(widget, src, dataImg);\n\n src = utils.addQueryString(src, {img: 1});\n el.setAttribute('data-iframely-url', src);\n\n new WaitingWidget(widget);\n\n iframely.trigger('load', el);\n\n }\n});\n\niframely.on('message', function(widget, message) {\n\n var waitingWidget;\n\n if (message.method === 'widgetRendered') {\n hidePlaceholderThumbnail(widget);\n\n waitingWidget = findWaitingWidget(widget);\n waitingWidget && waitingWidget.deactivate();\n }\n\n if (message.method === 'begin-waiting-widget-render') {\n waitingWidget = findWaitingWidget(widget);\n waitingWidget && waitingWidget.clearLoadingTimeout();\n }\n\n if (message.method === 'end-waiting-widget-render') {\n waitingWidget = findWaitingWidget(widget);\n waitingWidget && waitingWidget.registerLoadingTimeout();\n }\n});\n\n\nfunction addPlaceholderThumbnail(widget, href, imageUrl) {\n\n var thumbHref;\n\n if (imageUrl && /^(https?:)?\\/\\//.test(imageUrl)) {\n thumbHref = imageUrl;\n } else {\n\n // Start of image url calculation.\n \n var query = utils.parseQueryString(href);\n \n // Extract widget params to invalidate image cache.\n var _params = {};\n for(var param in query) {\n if (param.indexOf('_') === 0) {\n _params[param] = query[param];\n }\n }\n\n // Force proxy `media` param.\n if (query.media) {\n _params.media = query.media;\n }\n \n // need to run through getEndpoint at least to avoid file:///\n if (href.match(/\\/api\\/iframe/)) {\n thumbHref = utils.getEndpoint(href.match(/^(.+)\\/api\\/iframe/i)[1] + '/api/thumbnail', Object.assign({\n url: query.url,\n api_key: query.api_key,\n key: query.key\n }, _params));\n } else if (href.match(iframely.ID_RE)) {\n // RE copied from `iframely.ID_RE` and modified to replace path part.\n thumbHref = utils.getEndpoint(href.replace(/^((?:https?:)?\\/\\/[^/]+\\/(\\w+-?\\w+))(?:\\?.*)?$/, '$1/thumbnail'), _params);\n } else {\n return;\n }\n }\n\n // End of image url calculation.\n\n var thumb = document.createElement('div');\n // Parent div not always has ASPECT_WRAPPER_CLASS. Need explicit inline styles.\n utils.setStyles(thumb, {\n position: 'absolute',\n width: '100%',\n height: '100%',\n backgroundImage: \"url('\" + thumbHref + \"')\",\n backgroundSize: 'cover',\n backgroundPosition: 'center'\n });\n\n var iframelyLoaderDiv = document.createElement('div');\n iframelyLoaderDiv.setAttribute('class', iframely.LOADER_CLASS);\n thumb.appendChild(iframelyLoaderDiv);\n\n var paddingTop = iframely.getElementComputedStyle(widget.aspectWrapper, 'padding-top');\n var paddingBottom = iframely.getElementComputedStyle(widget.aspectWrapper, 'padding-bottom');\n\n var paddingTopMatch = paddingTop.match(/^(\\d+)px$/);\n var paddingTopInt = paddingTopMatch && parseInt(paddingTopMatch[1]);\n\n if (paddingTopInt && paddingBottom) {\n\n var thumbWrapper = document.createElement('div');\n\n utils.setStyles(thumbWrapper, {\n top: '-' + paddingTop,\n width: '100%',\n height: 0,\n position: 'relative',\n paddingBottom: paddingBottom\n }); \n\n thumbWrapper.appendChild(thumb);\n\n widget.aspectWrapper.appendChild(thumbWrapper);\n\n } else {\n\n widget.aspectWrapper.appendChild(thumb);\n }\n}\n\nfunction getNthNonTextChildNode(nth, element) {\n var count = 0;\n for(var i = 0; i < element.childNodes.length; i++) {\n var el = element.childNodes[i];\n if (el.nodeType === Node.TEXT_NODE) {\n // Nop.\n } else if (el.nodeType === Node.ELEMENT_NODE) {\n if (nth === count) {\n return el;\n }\n count++;\n }\n }\n}\n\nfunction nonTextChildCount(element) {\n var count = 0;\n for(var i = 0; i < element.childNodes.length; i++) {\n var el = element.childNodes[i];\n if (el.nodeType === Node.TEXT_NODE) {\n var text = el.textContent || el.innerText;\n text = text.replace(/\\s|\\n/g, '');\n if (text) {\n // Do not skip text node with text.\n count++;\n }\n } else if (el.nodeType === Node.ELEMENT_NODE) {\n count++;\n }\n }\n return count;\n}\n\nfunction hidePlaceholderThumbnail(widget) {\n var thumb = widget.aspectWrapper && nonTextChildCount(widget.aspectWrapper) > 1 && getNthNonTextChildNode(1, widget.aspectWrapper);\n if (thumb && thumb.nodeName === 'DIV') {\n widget.aspectWrapper.removeChild(thumb);\n }\n}\n\n//===\n\n// Working WaitingWidgets' collection.\n\nvar waitingWidgets = [];\n\nfunction findWaitingWidgetIdx(widget) {\n var i = 0;\n while(i < waitingWidgets.length && waitingWidgets[i].widget.iframe !== widget.iframe) {\n i++;\n }\n if (i < waitingWidgets.length && waitingWidgets[i].widget.iframe === widget.iframe) {\n return i;\n }\n}\n\nfunction findWaitingWidget(widget) {\n var idx = findWaitingWidgetIdx(widget);\n if (idx || idx === 0) {\n return waitingWidgets[idx];\n }\n}\n\nfunction removeWaitingWidget(widget) {\n var idx = findWaitingWidgetIdx(widget);\n if (idx || idx === 0) {\n waitingWidgets.splice(idx, 1);\n }\n}\n\n//===\n\n// WaitingWidget proto.\n\nfunction WaitingWidget(widget) {\n this.widget = widget;\n this.loadCount = 0;\n\n var iframe = widget.iframe;\n\n var that = this;\n function iframeOnLoad() {\n // Bind method to self.\n that.iframeOnLoad();\n }\n\n iframely.addEventListener(iframe, 'load', iframeOnLoad);\n\n this.registerLoadingTimeout();\n\n waitingWidgets.push(this);\n}\n\nWaitingWidget.prototype.iframeOnLoad = function() {\n\n this.loadCount++;\n\n // Skip first load of hosted widget OR timeout call.\n if (this.loadCount !== 2) {\n return;\n }\n\n this.deactivate();\n\n var that = this;\n setTimeout(function() {\n hidePlaceholderThumbnail(that.widget);\n }, iframely.LAZY_IFRAME_FADE_TIMEOUT);\n};\n\nWaitingWidget.prototype.deactivate = function() {\n this.clearLoadingTimeout();\n removeWaitingWidget(this);\n};\n\nWaitingWidget.prototype.clearLoadingTimeout = function() {\n this.timeoutId && clearTimeout(this.timeoutId);\n this.timeoutId = null;\n};\n\nWaitingWidget.prototype.registerLoadingTimeout = function() {\n if (this.timeoutId) {\n return;\n }\n var that = this;\n this.timeoutId = setTimeout(function() {\n that.iframeOnLoad();\n }, iframely.LAZY_IFRAME_SHOW_TIMEOUT);\n};\n\n\n//# sourceURL=webpack:///./lazy-img-placeholder.js?\n}"); - -/***/ }, - -/***/ "./lazy-loading-native.js" -/*!********************************!*\ - !*** ./lazy-loading-native.js ***! - \********************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{function getChromeVersion() { \n var raw = navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./);\n\n return raw ? parseInt(raw[2], 10) : false;\n}\nvar chromeVersion = getChromeVersion();\n\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\niframely.SUPPORT_IFRAME_LOADING_ATTR = chromeVersion && chromeVersion >= 77;\n\n//# sourceURL=webpack:///./lazy-loading-native.js?\n}"); - -/***/ }, - -/***/ "./messaging.js" -/*!**********************!*\ - !*** ./messaging.js ***! - \**********************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\nvar utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\n\nfunction receiveMessage(callback) {\n\n function cb(e) {\n var message;\n try {\n if (typeof e.data === 'string') {\n message = JSON.parse(e.data);\n } else if (typeof e.data === 'object') {\n message = e.data;\n }\n } catch (ex) {\n if (typeof e.data === 'string') {\n var m = e.data.match(/heightxPYMx(\\d+)/);\n if (m) {\n message = {\n method: 'resize',\n height: parseInt(m[1]) + 1,\n domains: 'all'\n };\n }\n }\n }\n\n callback(e, message);\n }\n\n // browser supports window.postMessage\n if (window['postMessage']) {\n if (window['addEventListener']) {\n window[callback ? 'addEventListener' : 'removeEventListener']('message', cb, !1);\n } else {\n window[callback ? 'attachEvent' : 'detachEvent']('onmessage', cb);\n }\n }\n}\n\nfunction findIframeByContentWindow(iframes, contentWindow) {\n var foundIframe;\n for(var i = 0; i < iframes.length && !foundIframe; i++) {\n var iframe = iframes[i];\n if (iframe.contentWindow === contentWindow) {\n foundIframe = iframe;\n }\n }\n return foundIframe;\n}\n\nfunction findIframeInElement(element, options) {\n var foundIframe, iframes;\n \n if (options.src) {\n iframes = element.querySelectorAll('iframe[src*=\"' + options.src.replace(/^https?:/, '') + '\"]');\n foundIframe = findIframeByContentWindow(iframes, options.contentWindow);\n }\n\n if (!foundIframe) {\n iframes = options.domains ?\n element.querySelectorAll('iframe[src*=\"' + (options.domains || iframely.DOMAINS).join('\"], iframe[src*=\"') + '\"]')\n : element.getElementsByTagName('iframe');\n foundIframe = findIframeByContentWindow(iframes, options.contentWindow);\n }\n\n return foundIframe;\n}\n\nfunction findIframeInShadowRoots(element, options) {\n var foundIframe;\n var className = '.' + (iframely.config.shadow || iframely.SHADOW);\n var shadowRoots = element.querySelectorAll(className);\n for(var i = 0; i < shadowRoots.length && !foundIframe; i++) {\n var shadowRoot = shadowRoots[i].shadowRoot;\n if (shadowRoot) {\n foundIframe = findIframeInElement(shadowRoot, options);\n if (!foundIframe) {\n foundIframe = findIframeInShadowRoots(shadowRoot, options);\n }\n }\n }\n return foundIframe;\n}\n\n// Do not override existing.\nif (!iframely.findIframe) {\n iframely.findIframe = function(options) {\n var foundIframe = findIframeInElement(document, options);\n if (!foundIframe) {\n foundIframe = findIframeInShadowRoots(document, options);\n }\n return foundIframe;\n };\n}\n\n\nreceiveMessage(function(e, message) {\n\n if (message && (message.method || message.type || message.context)) {\n\n var foundIframe = iframely.findIframe({\n contentWindow: e.source,\n src: message.src || message.context,\n domains: message.domains !== 'all' && iframely.DOMAINS.concat(iframely.CDN)\n });\n\n if (foundIframe) {\n var widget = utils.getWidget(foundIframe);\n if (widget && message.url) {\n widget.url = message.url;\n }\n iframely.trigger('message', widget, message);\n }\n }\n \n});\n\n\nexports.postMessage = function(message, target_url, target) {\n if (window['postMessage']) {\n\n if (typeof message === 'object') {\n message.context = document.location.href;\n }\n\n message = JSON.stringify(message);\n\n target_url = target_url || '*';\n\n target = target || window.parent; // default to parent\n\n // the browser supports window.postMessage, so call it with a targetOrigin\n // set appropriately, based on the target_url parameter.\n target['postMessage'](message, target_url.replace( /([^:]+:\\/\\/[^/]+).*/, '$1'));\n }\n};\n\n\n//# sourceURL=webpack:///./messaging.js?\n}"); - -/***/ }, - -/***/ "./options/form-builder.js" -/*!*********************************!*\ - !*** ./options/form-builder.js ***! - \*********************************/ -(module, __unused_webpack_exports, __webpack_require__) { - -eval("{var getFormElements = __webpack_require__(/*! ./form-generator */ \"./options/form-generator.js\");\nvar iframely = __webpack_require__(/*! ../iframely */ \"./iframely.js\");\n\nvar UIelements = {\n checkbox: {\n getValue: function(inputs) {\n var input = inputs[0];\n return input.checked;\n }\n },\n text: {\n getValue: function(inputs) {\n var input = inputs[0];\n var value = input.value;\n if (input.type === 'number') {\n value = parseInt(value);\n if (isNaN(value)) {\n value = '';\n }\n }\n return value;\n },\n customEvents: function(inputs, submitOptionsCb) {\n var input = inputs[0];\n iframely.addEventListener(input, 'click', function() {\n input.select();\n });\n iframely.addEventListener(input, 'blur', submitOptionsCb);\n iframely.addEventListener(input, 'keyup', function(e) {\n // Apply on enter.\n if (e.keyCode === 13) {\n submitOptionsCb();\n }\n });\n }\n },\n radio: {\n getValue: function(inputs) {\n var selectedInput;\n inputs.forEach(function(input) {\n if (input.checked) {\n selectedInput = input;\n }\n });\n return selectedInput.value;\n }\n }\n};\n\nvar defaultQueryById = {};\n\nmodule.exports = function(params) {\n\n var options = params.options;\n var formContainer = params.formContainer;\n\n if (!formContainer) {\n console.warn('No formContainer in form-builder options', params);\n return;\n }\n\n if (!options) {\n formContainer.innerHTML = '';\n return;\n }\n\n var elements = getFormElements(options, params.translator);\n var id = params.id;\n var renderer = params.renderer;\n\n var defaultQuery = defaultQueryById[id] = defaultQueryById[id] || {};\n // Exclude default values.\n Object.keys(options).forEach(function(key) {\n if (!options.query || options.query.indexOf(key) === -1) {\n // Store default value.\n defaultQuery[key] = options[key].value;\n }\n });\n\n function getQueryFromForm() {\n\n var query = {};\n\n var getOptionsFromElements = function(elements) {\n // Get options from all inputs.\n elements.forEach(function(element) {\n\n if (element.context && element.context.elements) {\n\n getOptionsFromElements(element.context.elements);\n\n } else if (element.inputs) {\n\n var elementUI = UIelements[element.type];\n var inputValue;\n if (elementUI && elementUI.getValue) {\n inputValue = elementUI.getValue(element.inputs);\n } else {\n inputValue = element.inputs[0].value;\n }\n Object.assign(query, element.getQuery(inputValue));\n }\n });\n };\n\n getOptionsFromElements(elements);\n \n return query;\n }\n\n function getAndSubmitOptions() {\n var query = getQueryFromForm();\n\n Object.keys(defaultQuery).forEach(function(key) {\n if (defaultQuery[key] === query[key] \n || query[key] === undefined) { // remove undefined so it's not included while JSON.stringify\n delete query[key];\n }\n });\n\n iframely.trigger('options-changed', id, formContainer, query);\n }\n\n // Render form.\n var renderElements = function(elements) {\n var html = '';\n elements.forEach(function(element) {\n if (element.context && element.context.elements) {\n element.context.elementsHtml = renderElements(element.context.elements);\n }\n html += renderer(element.type, element.context || {});\n });\n return html;\n };\n formContainer.innerHTML = renderElements(elements);\n\n // Bind events.\n var bindElements = function(elements) {\n \n elements.forEach(function(element) {\n\n if (element.context && element.context.elements) {\n\n bindElements(element.context.elements);\n\n } else {\n\n var elementUI = UIelements[element.type];\n if (element.context) {\n element.inputs = formContainer.querySelectorAll('[name=\"' + element.context.key + '\"]');\n if (element.inputs.length > 0) {\n if (elementUI && elementUI.customEvents) {\n elementUI.customEvents(element.inputs, getAndSubmitOptions);\n } else {\n element.inputs.forEach(function(input) {\n iframely.addEventListener(input, 'change', getAndSubmitOptions);\n });\n }\n } else {\n console.warn('No inputs found for option', element.key);\n }\n }\n }\n });\n };\n bindElements(elements);\n};\n\n//# sourceURL=webpack:///./options/form-builder.js?\n}"); - -/***/ }, - -/***/ "./options/form-generator.js" -/*!***********************************!*\ - !*** ./options/form-generator.js ***! - \***********************************/ -(module) { - -eval("{var _RE = /^_./;\n\nvar translate = function (label, translator) {\n return translator && typeof translator === 'function' \n ? translator (label) || label\n : label;\n};\n\nmodule.exports = function(options, translator) {\n\n if (!options) {\n return [];\n }\n\n // Remove query key.\n options = Object.assign({}, options);\n delete options.query;\n\n var items = [];\n var keys = Object.keys(options);\n var checkboxCount = 0;\n \n keys.forEach(function(key) {\n \n var context = {};\n\n var getQuery;\n var option = options[key];\n option.key = key;\n\n var forceCheckboxForSingleKeyValue;\n var valuesKeys = option.values && Object.keys(option.values);\n var singleKey, singleLabel;\n if (valuesKeys && valuesKeys.length === 1) {\n forceCheckboxForSingleKeyValue = true;\n singleKey = valuesKeys[0];\n singleLabel = option.values[singleKey];\n }\n\n context.label = translate(singleLabel || option.label, translator);\n context.key = option.key;\n\n if (forceCheckboxForSingleKeyValue || typeof option.value === 'boolean') {\n\n if (forceCheckboxForSingleKeyValue) {\n context.checked = (singleKey === option.value) || (!singleKey && !option.value);\n } else {\n context.checked = option.value;\n }\n\n checkboxCount++;\n\n items.push({\n type: 'checkbox',\n context: context,\n order: _RE.test(key) ? 0 : 1,\n getQuery: function(checked) {\n\n var value;\n if (forceCheckboxForSingleKeyValue) {\n value = checked ? singleKey : '';\n } else {\n value = checked;\n }\n\n var result = {};\n\n if (forceCheckboxForSingleKeyValue) {\n if (value === '') {\n // Empty.\n } else {\n result[option.key] = value;\n }\n } else {\n result[option.key] = checked;\n }\n return result;\n }\n });\n\n } else if ((typeof option.value === 'number' || typeof option.value === 'string') && !option.values) {\n\n var useSlider = option.range && typeof option.range.min === 'number' && typeof option.range.max === 'number';\n var useNumber = typeof option.value === 'number';\n\n context.value = option.value;\n\n getQuery = function(inputValue) {\n var result = {};\n if (inputValue === '') {\n // Empty.\n } else {\n result[option.key] = inputValue;\n }\n return result;\n };\n\n if (useSlider) {\n context.min = option.range.min;\n context.max = option.range.max;\n items.push({\n type: 'range',\n context: context,\n order: 9, // last one\n getQuery: getQuery\n });\n } else {\n context.placeholder = translate(option.placeholder || '', translator);\n context.inputType = useNumber ? 'number' : 'text';\n items.push({\n type: 'text',\n context: context,\n order: /start/i.test(key) ? 7 : 8, // start/end for player timing, ex.: youtube\n getQuery: getQuery\n });\n }\n\n } else if (option.values) {\n\n context.value = option.value + '';\n\n getQuery = function(inputValue) {\n var result = {};\n if (inputValue === '') {\n // Empty.\n } else {\n result[option.key] = inputValue;\n }\n return result;\n };\n\n if (Object.keys(option.values).length <= 3) {\n\n if (option.label) {\n context.label = translate(option.label, translator);\n } else {\n context.label = false;\n }\n\n var i = 0;\n var hasLongLabel = false;\n var values = Object.values(option.values);\n while (i < values.length && !hasLongLabel) {\n var label = values[i];\n hasLongLabel = label.length > 8;\n i++;\n }\n context.inline = !hasLongLabel;\n\n context.items = [];\n\n Object.keys(option.values).forEach(function(key, idx2) {\n context.items.push({\n id: context.key + '-' + idx2,\n value: key,\n label: translate(option.values[key], translator),\n checked: context.value === key\n });\n });\n\n items.push({\n type: 'radio',\n context: context,\n order: hasLongLabel ? -3 : (!/theme/.test(key) ? -2 : -1),\n getQuery: getQuery\n });\n\n } else {\n\n context.items = [];\n\n Object.keys(option.values).forEach(function(key) {\n context.items.push({\n value: key,\n label: translate(option.values[key], translator),\n checked: context.value === key\n });\n });\n\n items.push({\n type: 'select',\n context: context,\n order: 5,\n getQuery: getQuery\n });\n }\n }\n });\n\n items.sort(function(a, b) {\n return a.order - b.order;\n });\n\n items.forEach(function(item) {\n delete item.order;\n });\n\n if (checkboxCount > 0) {\n\n var groupedItems = [];\n var subItems;\n\n items.forEach(function(item, idx) {\n\n if (item.type === 'checkbox') {\n\n // Grouping for checkboxes.\n\n var newCheckboxGroup = \n checkboxCount > 2\n && idx > 0 \n && !_RE.test(item.context.key) \n && items[idx - 1].type === 'checkbox'\n && _RE.test(items[idx - 1].context.key);\n\n if (!subItems // First group.\n || newCheckboxGroup // Second group on _ prefix removed.\n ) {\n\n subItems = [];\n groupedItems.push({\n type: 'group',\n context: {\n elements: subItems\n }\n });\n }\n\n subItems.push(item);\n\n } else {\n // Other items. Just add.\n groupedItems.push(item);\n }\n });\n\n return groupedItems;\n\n } else {\n return items;\n }\n};\n\n//# sourceURL=webpack:///./options/form-generator.js?\n}"); - -/***/ }, - -/***/ "./options/index.js" -/*!**************************!*\ - !*** ./options/index.js ***! - \**************************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ../iframely */ \"./iframely.js\");\nvar formBuilder = __webpack_require__(/*! ./form-builder */ \"./options/form-builder.js\");\nvar renderer = __webpack_require__(/*! ./renderer */ \"./options/renderer.js\");\n\niframely.buildOptionsForm = function(id, formContainer, options, translator) {\n formBuilder({\n id: id,\n formContainer: formContainer,\n options: options,\n renderer: renderer,\n translator: translator\n });\n};\n\nexports.iframely = iframely;\n\n//# sourceURL=webpack:///./options/index.js?\n}"); - -/***/ }, - -/***/ "./options/renderer.js" -/*!*****************************!*\ - !*** ./options/renderer.js ***! - \*****************************/ -(module, __unused_webpack_exports, __webpack_require__) { - -eval("{var checkboxTemplate = __webpack_require__(/*! ./templates/checkbox.ejs */ \"./options/templates/checkbox.ejs\");\nvar rangeTemplate = __webpack_require__(/*! ./templates/range.ejs */ \"./options/templates/range.ejs\");\nvar textTemplate = __webpack_require__(/*! ./templates/text.ejs */ \"./options/templates/text.ejs\");\nvar radioTemplate = __webpack_require__(/*! ./templates/radio.ejs */ \"./options/templates/radio.ejs\");\nvar selectTemplate = __webpack_require__(/*! ./templates/select.ejs */ \"./options/templates/select.ejs\");\nvar groupTemplate = __webpack_require__(/*! ./templates/group.ejs */ \"./options/templates/group.ejs\");\n\nvar templates = {\n checkbox: checkboxTemplate,\n range: rangeTemplate,\n text: textTemplate,\n radio: radioTemplate,\n select: selectTemplate,\n group: groupTemplate\n};\n\nmodule.exports = function(type, context) {\n var template = templates[type];\n var renderedTemplate = template(context);\n return renderedTemplate;\n};\n\n//# sourceURL=webpack:///./options/renderer.js?\n}"); - -/***/ }, - -/***/ "./theme.js" -/*!******************!*\ - !*** ./theme.js ***! - \******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\nvar messaging = __webpack_require__(/*! ./messaging */ \"./messaging.js\");\n\nfunction setThemeInIframe(iframe, theme) {\n messaging.postMessage({\n method: 'setTheme',\n data: theme\n }, '*', iframe.contentWindow);\n}\n\nfunction setThemeInAllIframes(parent, theme) {\n var iframes = parent.getElementsByTagName('iframe');\n for(var i = 0; i < iframes.length; i++) {\n var iframe = iframes[i];\n setThemeInIframe(iframe, theme);\n }\n}\n\niframely.setTheme = function(theme, container) {\n if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) {\n if (container) {\n if (container.tagName === 'IFRAME') {\n setThemeInIframe(container, theme);\n } else {\n setThemeInAllIframes(container, theme);\n }\n } else {\n // Send get param to next iframes.\n iframely.extendOptions({\n theme: theme\n });\n setThemeInAllIframes(document, theme);\n iframely.trigger('set-theme', theme);\n }\n } else {\n console.warn('Using iframely.setTheme with not supported theme: \"' + theme + '\". Supported themes are: ' + iframely.SUPPORTED_THEMES.join(', '));\n }\n};\n\n//# sourceURL=webpack:///./theme.js?\n}"); - -/***/ }, - -/***/ "./utils.js" -/*!******************!*\ - !*** ./utils.js ***! - \******************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\nvar messaging = __webpack_require__(/*! ./messaging */ \"./messaging.js\");\n\niframely.on('init', function() {\n\n\n iframely.extendOptions(parseQueryStringFromScriptSrc());\n // if it's hosted from elsewhere - we don't support customizing via query-string.\n // iframely.CDN will be default one unless changed by user (?cdn= or iframely.CDN= )\n\n defineDefaultStyles();\n\n // Set theme for existing iframes.\n if (iframely.config.theme) {\n iframely.setTheme(iframely.config.theme);\n }\n\n requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\\/\\//, '')));\n \n});\n\niframely.load = function() {\n var args = Array.prototype.slice.call(arguments);\n args.unshift('load');\n iframely.trigger.apply(this, args);\n};\n\nvar getIframeWrapper = exports.getIframeWrapper = function(iframe, checkClass) {\n\n var aspectWrapper = iframe.parentNode;\n\n if (!aspectWrapper\n || aspectWrapper.nodeName !== 'DIV'\n || nonTextChildCount(aspectWrapper) > 2 /* 2 is lazy-cover */\n || (checkClass && aspectWrapper.getAttribute('class') !== iframely.ASPECT_WRAPPER_CLASS)\n || (!checkClass && aspectWrapper.style.position !== 'relative' && aspectWrapper.getAttribute('class') !== iframely.ASPECT_WRAPPER_CLASS)) {\n return;\n }\n\n var maxWidthWrapper = aspectWrapper.parentNode;\n\n if (!maxWidthWrapper\n || maxWidthWrapper.nodeName !== 'DIV'\n || nonTextChildCount(maxWidthWrapper) > 1\n || (checkClass && maxWidthWrapper.getAttribute('class') && maxWidthWrapper.getAttribute('class').split(' ').indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) === -1)\n || (!checkClass && maxWidthWrapper.getAttribute('class') && !maxWidthWrapper.getAttribute('class').match(/iframely/i) /* users can modify class */)\n ) {\n return;\n }\n\n return {\n aspectWrapper: aspectWrapper,\n maxWidthWrapper: maxWidthWrapper\n };\n};\n\nexports.addDefaultWrappers = function(el) {\n var parentNode = el.parentNode;\n\n var maxWidthWrapper = document.createElement('div');\n maxWidthWrapper.className = iframely.MAXWIDTH_WRAPPER_CLASS;\n\n var aspectWrapper = document.createElement('div');\n aspectWrapper.className = iframely.ASPECT_WRAPPER_CLASS;\n\n maxWidthWrapper.appendChild(aspectWrapper);\n\n parentNode.insertBefore(maxWidthWrapper, el);\n\n return {\n aspectWrapper: aspectWrapper,\n maxWidthWrapper: maxWidthWrapper\n };\n};\n\nexports.getWidget = function(iframe) {\n var wrapper = getIframeWrapper(iframe);\n if (!wrapper) {\n return;\n }\n var widget = {\n iframe: iframe, // can actually be ahref\n aspectWrapper: wrapper.aspectWrapper,\n maxWidthWrapper: wrapper.maxWidthWrapper\n };\n if (iframe.nodeName === 'A' && iframe.hasAttribute('href')) {\n widget.url = iframe.getAttribute('href');\n } else if (iframe.hasAttribute('src') && /url=/.test(iframe.getAttribute('src'))) {\n var qs = parseQueryString(iframe.getAttribute('src'));\n if (qs.url) {\n widget.url = qs.url;\n }\n }\n return widget;\n};\n\niframely.getElementComputedStyle = function(el, style) {\n return window.getComputedStyle && window.getComputedStyle(el).getPropertyValue(style);\n};\n\nexports.setStyles = function(el, styles) {\n if (el) { // let's check it's still defined, just in case\n Object.keys(styles).forEach(function(key) {\n\n var value = styles[key];\n if (typeof value === 'number' || (typeof value === 'string' && /^(\\d+)?\\.?(\\d+)$/.test(value))) {\n value = value + 'px';\n }\n\n var currentValue = el.style[key];\n\n if (!window.getComputedStyle ||\n // don't change CSS values in pixels, such as height:0\n (\n iframely.getElementComputedStyle(el, key) != value\n // && don't set default aspect ratio if it's defined in CSS anyway\n && !(el.className == 'iframely-responsive' && key === 'paddingBottom' && !currentValue && /^56\\.2\\d+%$/.test(value))\n // && do not change max-width if new value === 'keep'.\n && !(key === 'max-width' && value === 'keep')\n )) {\n\n el.style[key] = value || ''; // remove style that is no longer needed\n }\n });\n }\n};\n\nvar applyNonce = exports.applyNonce = function(element) {\n if (iframely.config.nonce) {\n element.nonce = iframely.config.nonce;\n }\n};\n\nfunction defineDefaultStyles() {\n\n var iframelyStylesId = 'iframely-styles';\n var styles = document.getElementById(iframelyStylesId);\n\n if (!styles) {\n // copy-paste default styles from https://iframely.com/docs/omit-css\n // box-sizing:border-box - need for iOS Safari .\n var iframelyStyles = '.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}';\n\n styles = document.createElement('style');\n styles.id = iframelyStylesId;\n styles.type = 'text/css';\n applyNonce(styles);\n\n if (styles.styleSheet) {\n // IE.\n styles.styleSheet.cssText = iframelyStyles;\n } else {\n styles.innerHTML = iframelyStyles;\n }\n document.getElementsByTagName('head')[0].appendChild(styles);\n }\n}\n\n\nvar addQueryString = exports.addQueryString = function(href, options) {\n\n var query_string = '';\n\n Object.keys(options).forEach(function(key) {\n var value = options[key];\n\n // array is used e.g. for import: uris and ids\n if (Object.prototype.toString.call(value) === '[object Array]') {\n\n var values = value.map(function(uri) {\n return key + '=' + encodeURIComponent(uri);\n });\n query_string += '&' + values.join('&'); \n\n } else if (typeof value !== 'undefined' && href.indexOf(key + '=') === -1 ) { // set explicitely in options, skip undefines\n\n // Do not convert boolean for _option.\n if (typeof value === 'boolean' && key.charAt(0) !== '_') {\n value = value ? 1 : 0;\n }\n\n query_string += '&' + key + '=' + encodeURIComponent(value);\n }\n\n });\n\n return href + (query_string !== '' ? (href.indexOf('?') > -1 ? '&' : '?') + query_string.replace(/^&/, '') : '');\n};\n\nexports.getEndpoint = function(src, options, config_params) {\n\n var endpoint = src;\n\n if (!/^(https?:)?\\/\\//i.test(src)) {\n endpoint = (options.CDN || iframely.CDN) + endpoint;\n delete options.CDN;\n }\n\n if (!/^(?:https?:)?\\/\\//i.test(endpoint)) {\n endpoint = '//' + endpoint;\n } \n\n if (options) {\n endpoint = addQueryString(endpoint, options);\n }\n\n // get additional params from config\n if (config_params && config_params.length) {\n\n var more_options = {};\n\n var iframely_config_keys = Object.keys(iframely.config);\n for (var i = 0; i < iframely_config_keys.length; i++) {\n var key = iframely_config_keys[i];\n if (containsString(config_params, key)) {\n more_options[key] = iframely.config[key];\n }\n }\n\n endpoint = addQueryString(endpoint, more_options);\n }\n\n\n if (/^(https?:)?\\/\\//i.test(endpoint) // Path is url.\n && !endpoint.match(/^(https?:)?\\/\\//i)[1] // No http protocol specified.\n && document.location.protocol !== 'http:' // Document in `file:` or other protocol.\n && document.location.protocol !== 'https:') {\n\n endpoint = 'https:' + endpoint;\n }\n\n return endpoint;\n};\n\n// helper method to init more options through js code\niframely.extendOptions = function(options) {\n\n options && Object.keys(options).forEach(function(key) {\n var new_value = (\n options[key] === 0 || options[key] === '0' || options[key] === false || options[key] === 'false'\n ? false : (options[key] === 1 || options[key] === '1' || options[key] === true || options[key] === 'true'\n ? true : options[key]));\n\n if (iframely.config[key] !== false) { // set new value only when undefined or not previously disabled\n iframely.config[key] = new_value;\n }\n });\n\n};\n\nfunction parseQueryStringFromScriptSrc() {\n\n // Extract global iframely params.\n var scripts = document.querySelectorAll('script[src*=\"embed.js\"], script[src*=\"iframely.js\"]');\n\n for(var i = 0; i < scripts.length; i++) {\n var src = scripts[i].getAttribute('src').replace(/&/gi, '&');\n\n if (iframely.SCRIPT_RE.test(src)) { // found the script on custom origin or default Iframely CDN\n\n var options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat('cdn', 'cancel', 'nonce'));\n\n var m2 = src.match(iframely.CDN_RE);\n if (m2 || options.cdn) { // ignore non-Iframely hosts such as s.imgur.com/min/embed.js\n iframely.CDN = options.cdn || m2[1];\n }\n\n if (options.cancel) {\n if (options.cancel === '0' || options.cancel === 'false') {\n iframely.RECOVER_HREFS_ON_CANCEL = true;\n }\n delete options.cancel;\n }\n\n if (Object.keys(options).length > 0) {\n // give preferrence to CDN from scripts that have query-string. \n // CDN is most critical for embeds with empty data-iframely-url\n // and those should have at least ?api_key... in script src\n\n return options;\n } // or keep searching\n }\n }\n // should have exited by now if any querystring found...\n return {};\n}\n\nfunction requestSizeOfExistingIframes(domains) {\n\n var iframes = document.querySelectorAll('iframe[src*=\"' + (domains || iframely.DOMAINS).join('\"], iframe[src*=\"') + '\"]');\n for(var i = 0; i < iframes.length; i++) {\n var iframe = iframes[i];\n var src = iframe.src;\n if (src.match(/^(https?:)?\\/\\/[^/]+\\/api\\/iframe\\?.+/)\n || src.match(/^(https?:)?\\/\\/[^/]+\\/\\w+(\\?.*)?$/)) {\n messaging.postMessage({\n method: 'getSize'\n }, '*', iframe.contentWindow);\n }\n }\n} \n\nfunction nonTextChildCount(element) {\n var count = 0;\n for(var i = 0; i < element.childNodes.length; i++) {\n var el = element.childNodes[i];\n if (el.nodeType === Node.TEXT_NODE) {\n var text = el.textContent || el.innerText;\n text = text.replace(/\\s|\\n/g, '');\n if (text) {\n // Do not skip text node with text.\n count++;\n }\n } else if (el.nodeType === Node.ELEMENT_NODE) {\n count++;\n }\n }\n return count;\n}\n\nfunction containsString(list, findValue) {\n var value, i = 0;\n while (i < list.length) {\n value = list[i];\n\n if (value == findValue) {\n return true;\n }\n\n if (value && value.test && value.test(findValue)) {\n return true;\n }\n\n i++;\n }\n}\n\nvar parseQueryString = exports.parseQueryString = function(url, allowed_query_string) {\n var query = url.match(/\\?(.+)/i);\n if (query) {\n query = query[1];\n var data = query.split('&');\n var result = {};\n for(var i=0; i= 0;\n }\n return found && el;\n }\n\n var parentNode = widget.maxWidthWrapper && widget.maxWidthWrapper.parentNode;\n var naNode = widget.maxWidthWrapper;\n\n // Try remove by parentClass first.\n if (iframely.config && iframely.config.parent) {\n // Remove by parent class.\n var parentElement = findParent(widget.maxWidthWrapper, iframely.config.parent);\n\n if (parentElement) {\n parentNode = parentElement.parentNode;\n naNode = parentElement;\n }\n }\n\n if (widget.url) {\n var text = widget.iframe && (widget.iframe.textContent || widget.iframe.innerText);\n\n iframely.triggerAsync('cancel', widget.url, parentNode, text, naNode.nextSibling);\n }\n // Re-creating a link if people had it as text is now deprecated (see in deprecated.js)\n // New use: iframely.on('cancel', function(url, parentNode, text) {...} );\n\n parentNode.removeChild(naNode);\n};\n\n//# sourceURL=webpack:///./widget-cancel.js?\n}"); - -/***/ }, - -/***/ "./widget-click.js" -/*!*************************!*\ - !*** ./widget-click.js ***! - \*************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('message', function(widget, message) {\n if (message.method === 'open-href' || message.method === 'click') {\n iframely.trigger(message.method, message.href);\n }\n});\n\n// Do not override user defined handler.\nif (!iframely.openHref) {\n iframely.openHref = function(href) {\n if (href.indexOf(window.location.origin) === 0) {\n // Redirect top on same origin.\n window.location.href = href;\n } else {\n // Open new tab on another origin.\n window.open(href, '_blank', 'noopener');\n }\n };\n}\n\niframely.on('open-href', function(href) {\n iframely.triggerAsync('click', href);\n iframely.openHref(href);\n});\n\n//# sourceURL=webpack:///./widget-click.js?\n}"); - -/***/ }, - -/***/ "./widget-options.js" -/*!***************************!*\ - !*** ./widget-options.js ***! - \***************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('message', function(widget, message) {\n if (message.method === 'setIframelyEmbedOptions') {\n iframely.trigger('options', widget, message.data);\n }\n});\n\n\n//# sourceURL=webpack:///./widget-options.js?\n}"); - -/***/ }, - -/***/ "./widget-resize.js" -/*!**************************!*\ - !*** ./widget-resize.js ***! - \**************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('message', function(widget, message) {\n\n if (message.method === 'setIframelyWidgetSize' \n || message.method === 'resize' \n || message.method === 'setIframelyEmbedData' \n || message.type === 'embed-size'\n || message.context === 'iframe.resize') {\n\n var frame_styles = null;\n\n if (message.data && message.data.media && message.data.media.frame_style) {\n\n message.data.media.frame_style.split(';').forEach(function(str) {\n\n if(str.trim() !== '' && str.indexOf(':') > -1) {\n var props = str.split(':');\n if (props.length === 2) {\n frame_styles = frame_styles || {};\n frame_styles[props[0].trim()] = props[1].trim();\n }\n }\n });\n\n widgetDecorate(widget, frame_styles);\n\n } else if (message.method === 'setIframelyEmbedData') {\n\n // setIframelyEmbedData always sets frame_style. If not - reset.\n // setIframelyEmbedData without message.data resets border.\n widgetDecorate(widget, null);\n }\n\n var media = message.data && message.data.media;\n if (!media && message.height) {\n media = {\n height: message.height,\n 'max-width': 'keep'\n };\n }\n\n widgetResize(widget, media);\n }\n});\n\n// All frame_style attributes.\nvar resetWrapperBorderStyles = {'border': '', 'border-radius': '', 'box-shadow': '', 'overflow': ''};\nvar resetIframeBorderStyles = {'border': '0', 'border-radius': '', 'box-shadow': '', 'overflow': ''};\n\nfunction widgetDecorate(widget, styles) {\n\n if (styles && widget && widget.iframe) {\n\n if (styles['border-radius']) {\n // fix for Chrome?\n styles.overflow = 'hidden';\n utils.setStyles(widget.aspectWrapper, styles);\n } else {\n utils.setStyles(widget.iframe, styles);\n }\n\n } else if (!styles && widget && widget.iframe) {\n\n utils.setStyles(widget.aspectWrapper, resetWrapperBorderStyles);\n utils.setStyles(widget.iframe, resetIframeBorderStyles);\n }\n}\n\nfunction getTotalBorderWidth(widget) {\n\n // Get frame style from iframe or aspect wrapper as in widgetDecorate for Chrome fix.\n var frameStylesBorder = \n (widget.iframe && widget.iframe.style.border) \n || (widget.aspectWrapper && widget.aspectWrapper.style.border);\n\n // Get iframe border width from frame style.\n var borderWidth = frameStylesBorder && frameStylesBorder.match(/(\\d+)px/) || 0;\n if (borderWidth) {\n borderWidth = parseInt(borderWidth[1]);\n // For width and height border size will be 2x.\n borderWidth = borderWidth * 2;\n }\n\n return borderWidth;\n}\n\nfunction widgetResize(widget, media) {\n\n if (media && Object.keys(media).length > 0 && widget) {\n\n var borderWidth = getTotalBorderWidth(widget);\n\n var oldIframeHeight = window.getComputedStyle && window.getComputedStyle(widget.iframe).getPropertyValue('height');\n\n\n var maxWidth = media['max-width'];\n if (typeof maxWidth === 'number') {\n // Can be max-width: 56vh.\n maxWidth += borderWidth;\n }\n\n utils.setStyles(widget.maxWidthWrapper, {\n 'max-width': maxWidth,\n 'min-width': media['min-width'] && (media['min-width'] + borderWidth),\n width: media.width && (media.width + borderWidth)\n });\n\n if (media.scrolling && widget.iframe) {\n widget.iframe.setAttribute('scrolling', media.scrolling);\n }\n\n var aspectRatio = media['aspect-ratio'];\n\n // If no aspect and height - do not change aspect wrapper.\n if (aspectRatio || media.height) {\n utils.setStyles(widget.aspectWrapper, {\n paddingBottom: aspectRatio ? (Math.round(1000 * 100 / aspectRatio) / 1000 + '%') : 0, // if fixed-size, it will get set to 0\n paddingTop: aspectRatio && media['padding-bottom'], // if a fixed-height padding at the bottom of responsive div is required\n height: aspectRatio ? 0 : (media.height && (media.height + borderWidth)) // if defined\n });\n }\n\n\n var currentHeight = window.getComputedStyle && window.getComputedStyle(widget.iframe).getPropertyValue('height');\n\n if (oldIframeHeight && oldIframeHeight !== currentHeight) {\n iframely.triggerAsync('heightChanged', widget.iframe, oldIframeHeight, currentHeight);\n }\n\n }\n}\n\n\n//# sourceURL=webpack:///./widget-resize.js?\n}"); - -/***/ } - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ if (!(moduleId in __webpack_modules__)) { -/******/ delete __webpack_module_cache__[moduleId]; -/******/ var e = new Error("Cannot find module '" + moduleId + "'"); -/******/ e.code = 'MODULE_NOT_FOUND'; -/******/ throw e; -/******/ } -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/global */ -/******/ (() => { -/******/ __webpack_require__.g = (function() { -/******/ if (typeof globalThis === 'object') return globalThis; -/******/ try { -/******/ return this || new Function('return this')(); -/******/ } catch (e) { -/******/ if (typeof window === 'object') return window; -/******/ } -/******/ })(); -/******/ })(); -/******/ -/************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module can't be inlined because the eval devtool is used. -/******/ var __webpack_exports__ = __webpack_require__("./index-options.js"); -/******/ -/******/ })() -; \ No newline at end of file +(function() { + + +//#region src/iframely.ts + var iframely = window.iframely = window.iframely || {}; + iframely.config = iframely.config || {}; + +//#endregion +//#region src/dom-ready.ts + var DOMReady = (f) => { + if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(f, 0); + document.addEventListener("DOMContentLoaded", f); + }; + DOMReady(() => { + if (typeof iframely.config.autorun === "undefined" || iframely.config.autorun !== false) iframely.trigger("load"); + }); + +//#endregion +//#region src/const.ts + function boot$15() { + iframely.VERSION = 1; + iframely.ASPECT_WRAPPER_CLASS = "iframely-responsive"; + iframely.MAXWIDTH_WRAPPER_CLASS = "iframely-embed"; + iframely.LOADER_CLASS = "iframely-loader"; + iframely.DOMAINS = [ + "cdn.iframe.ly", + "iframe.ly", + "if-cdn.com", + "iframely.net" + ]; + iframely.CDN = iframely.CDN || iframely.DOMAINS[0]; + iframely.BASE_RE = /^(?:https?:)?\/\/[^/]+/i; + iframely.ID_RE = /^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/; + iframely.SCRIPT_RE = /^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i; + iframely.CDN_RE = /^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i; + iframely.SUPPORTED_QUERY_STRING = [ + "api_key", + "key", + "iframe", + "html5", + "playerjs", + "align", + "language", + "media", + "maxwidth", + "maxheight", + "lazy", + "import", + "parent", + "shadow", + "click_to_play", + "autoplay", + "mute", + "card", + "consent", + "theme", + /^_.+/ + ]; + iframely.SUPPORTED_THEMES = [ + "auto", + "light", + "dark" + ]; + iframely.LAZY_IFRAME_SHOW_TIMEOUT = 3e3; + iframely.LAZY_IFRAME_FADE_TIMEOUT = 200; + iframely.CLEAR_WRAPPER_STYLES_TIMEOUT = 3e3; + iframely.RECOVER_HREFS_ON_CANCEL = false; + iframely.SHADOW = "iframely-shadow"; + iframely.SUPPORT_IFRAME_LOADING_ATTR = true; + } + +//#endregion +//#region src/events.ts + var nextTick = (fn) => { + window.requestAnimationFrame(fn); + }; + var callbacksStack = {}; + function trigger(event, async, args) { + (callbacksStack[event] || []).forEach((cb) => { + if (async) nextTick(() => { + cb.apply(iframely, args); + }); + else cb.apply(iframely, args); + }); + if (event === "init") callbacksStack[event] = []; + } + function boot$14() { + iframely.on = (event, cb) => { + (callbacksStack[event] = callbacksStack[event] || []).push(cb); + }; + iframely.trigger = (event, ...args) => { + trigger(event, false, args); + }; + iframely.triggerAsync = (event, ...args) => { + trigger(event, true, args); + }; + } + +//#endregion +//#region src/messaging.ts + function receiveMessage(callback) { + window.addEventListener("message", (e) => { + let message; + try { + if (typeof e.data === "string") message = JSON.parse(e.data); + else if (typeof e.data === "object") message = e.data; + } catch { + if (typeof e.data === "string") { + const m = e.data.match(/heightxPYMx(\d+)/); + if (m) message = { + method: "resize", + height: parseInt(m[1]) + 1, + domains: "all" + }; + } + } + callback(e, message); + }, false); + } + function findIframeByContentWindow(iframes, contentWindow) { + let foundIframe; + for (let i = 0; i < iframes.length && !foundIframe; i++) { + const iframe = iframes[i]; + if (iframe.contentWindow === contentWindow) foundIframe = iframe; + } + return foundIframe; + } + function findIframeInElement(element, options) { + let foundIframe, iframes; + if (options.src) { + iframes = element.querySelectorAll("iframe[src*=\"" + options.src.replace(/^https?:/, "") + "\"]"); + foundIframe = findIframeByContentWindow(iframes, options.contentWindow); + } + if (!foundIframe) { + iframes = options.domains ? element.querySelectorAll("iframe[src*=\"" + (options.domains || iframely.DOMAINS).join("\"], iframe[src*=\"") + "\"]") : element.querySelectorAll("iframe"); + foundIframe = findIframeByContentWindow(iframes, options.contentWindow); + } + return foundIframe; + } + function findIframeInShadowRoots(element, options) { + let foundIframe; + const className = "." + (iframely.config.shadow || iframely.SHADOW); + const shadowRoots = element.querySelectorAll(className); + for (let i = 0; i < shadowRoots.length && !foundIframe; i++) { + const shadowRoot = shadowRoots[i].shadowRoot; + if (shadowRoot) { + foundIframe = findIframeInElement(shadowRoot, options); + if (!foundIframe) foundIframe = findIframeInShadowRoots(shadowRoot, options); + } + } + return foundIframe; + } + function boot$13() { + if (!iframely.findIframe) iframely.findIframe = (options) => { + let foundIframe = findIframeInElement(document, options); + if (!foundIframe) foundIframe = findIframeInShadowRoots(document, options); + return foundIframe; + }; + receiveMessage((e, message) => { + if (message && (message.method || message.type || message.context)) { + const foundIframe = iframely.findIframe({ + contentWindow: e.source, + src: message.src || message.context, + domains: message.domains !== "all" && iframely.DOMAINS.concat(iframely.CDN) + }); + if (foundIframe) { + const widget = getWidget(foundIframe); + if (widget && message.url) widget.url = message.url; + iframely.trigger("message", widget, message); + } + } + }); + } + function postMessage(message, target_url, target) { + if (typeof message === "object") message.context = document.location.href; + const data = JSON.stringify(message); + target_url = target_url || "*"; + target = target || window.parent; + target.postMessage(data, target_url.replace(/([^:]+:\/\/[^/]+).*/, "$1")); + } + +//#endregion +//#region src/utils.ts + function boot$12() { + iframely.on("init", () => { + iframely.extendOptions(parseQueryStringFromScriptSrc()); + defineDefaultStyles(); + if (iframely.config.theme) iframely.setTheme(iframely.config.theme); + requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, ""))); + }); + iframely.load = function(...args) { + iframely.trigger("load", ...args); + }; + iframely.getElementComputedStyle = (el, style) => { + return window.getComputedStyle(el).getPropertyValue(style); + }; + iframely.extendOptions = (options) => { + if (!options) return; + Object.keys(options).forEach((key) => { + const new_value = options[key] === 0 || options[key] === "0" || options[key] === false || options[key] === "false" ? false : options[key] === 1 || options[key] === "1" || options[key] === true || options[key] === "true" ? true : options[key]; + if (iframely.config[key] !== false) iframely.config[key] = new_value; + }); + }; + } + function getIframeWrapper(iframe, checkClass) { + const aspectWrapper = iframe.parentNode; + if (!aspectWrapper || aspectWrapper.nodeName !== "DIV" || nonTextChildCount$1(aspectWrapper) > 2 || checkClass && aspectWrapper.getAttribute("class") !== iframely.ASPECT_WRAPPER_CLASS || !checkClass && aspectWrapper.style.position !== "relative" && aspectWrapper.getAttribute("class") !== iframely.ASPECT_WRAPPER_CLASS) return; + const maxWidthWrapper = aspectWrapper.parentNode; + if (!maxWidthWrapper || maxWidthWrapper.nodeName !== "DIV" || nonTextChildCount$1(maxWidthWrapper) > 1 || checkClass && maxWidthWrapper.getAttribute("class") && maxWidthWrapper.getAttribute("class").split(" ").indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) === -1 || !checkClass && maxWidthWrapper.getAttribute("class") && !maxWidthWrapper.getAttribute("class").match(/iframely/i)) return; + return { + aspectWrapper, + maxWidthWrapper + }; + } + function addDefaultWrappers(el) { + const parentNode = el.parentNode; + const maxWidthWrapper = document.createElement("div"); + maxWidthWrapper.className = iframely.MAXWIDTH_WRAPPER_CLASS; + const aspectWrapper = document.createElement("div"); + aspectWrapper.className = iframely.ASPECT_WRAPPER_CLASS; + maxWidthWrapper.appendChild(aspectWrapper); + parentNode.insertBefore(maxWidthWrapper, el); + return { + aspectWrapper, + maxWidthWrapper + }; + } + function getWidget(iframe) { + const wrapper = getIframeWrapper(iframe); + if (!wrapper) return; + const widget = { + iframe, + aspectWrapper: wrapper.aspectWrapper, + maxWidthWrapper: wrapper.maxWidthWrapper + }; + const src = iframe.getAttribute("src"); + if (iframe.nodeName === "A" && iframe.hasAttribute("href")) widget.url = iframe.getAttribute("href"); + else if (src && /url=/.test(src)) { + const qs = parseQueryString(src); + if (qs.url) widget.url = qs.url; + } + return widget; + } + function setStyles(el, styles) { + if (el) Object.keys(styles).forEach((key) => { + let value = styles[key]; + if (typeof value === "number" || typeof value === "string" && /^(\d+)?\.?(\d+)$/.test(value)) value = value + "px"; + const elStyle = el.style; + const currentValue = elStyle[key]; + if (iframely.getElementComputedStyle(el, key) != value && !(el.className == "iframely-responsive" && key === "paddingBottom" && !currentValue && /^56\.2\d+%$/.test(value)) && !(key === "max-width" && value === "keep")) elStyle[key] = value || ""; + }); + } + function applyNonce(element) { + if (iframely.config.nonce) element.nonce = iframely.config.nonce; + } + function defineDefaultStyles() { + const iframelyStylesId = "iframely-styles"; + let styles = document.getElementById(iframelyStylesId); + if (!styles) { + const iframelyStyles = ".iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}"; + styles = document.createElement("style"); + styles.id = iframelyStylesId; + applyNonce(styles); + styles.innerHTML = iframelyStyles; + document.getElementsByTagName("head")[0].appendChild(styles); + } + } + function addQueryString(href, options) { + let query_string = ""; + Object.keys(options).forEach((key) => { + let value = options[key]; + if (Array.isArray(value)) { + const values = value.map((uri) => key + "=" + encodeURIComponent(uri)); + query_string += "&" + values.join("&"); + } else if (typeof value !== "undefined" && href.indexOf(key + "=") === -1) { + if (typeof value === "boolean" && key.charAt(0) !== "_") value = value ? 1 : 0; + query_string += "&" + key + "=" + encodeURIComponent(value); + } + }); + return href + (query_string !== "" ? (href.indexOf("?") > -1 ? "&" : "?") + query_string.replace(/^&/, "") : ""); + } + function getEndpoint(src, options, config_params) { + let endpoint = src; + if (!/^(https?:)?\/\//i.test(src)) { + endpoint = (options && options.CDN || iframely.CDN) + endpoint; + if (options) delete options.CDN; + } + if (!/^(?:https?:)?\/\//i.test(endpoint)) endpoint = "//" + endpoint; + if (options) endpoint = addQueryString(endpoint, options); + if (config_params && config_params.length) { + const more_options = {}; + const iframely_config_keys = Object.keys(iframely.config); + for (let i = 0; i < iframely_config_keys.length; i++) { + const key = iframely_config_keys[i]; + if (containsString(config_params, key)) more_options[key] = iframely.config[key]; + } + endpoint = addQueryString(endpoint, more_options); + } + if (/^(https?:)?\/\//i.test(endpoint) && !endpoint.match(/^(https?:)?\/\//i)[1] && document.location.protocol !== "http:" && document.location.protocol !== "https:") endpoint = "https:" + endpoint; + return endpoint; + } + function parseQueryStringFromScriptSrc() { + const scripts = document.querySelectorAll("script[src*=\"embed.js\"], script[src*=\"iframely.js\"]"); + for (let i = 0; i < scripts.length; i++) { + const src = scripts[i].getAttribute("src").replace(/&/gi, "&"); + if (iframely.SCRIPT_RE.test(src)) { + const options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat("cdn", "cancel", "nonce")); + const m2 = src.match(iframely.CDN_RE); + if (m2 || options.cdn) iframely.CDN = options.cdn || m2[1]; + if (options.cancel) { + if (options.cancel === "0" || options.cancel === "false") iframely.RECOVER_HREFS_ON_CANCEL = true; + delete options.cancel; + } + if (Object.keys(options).length > 0) return options; + } + } + return {}; + } + function requestSizeOfExistingIframes(domains) { + const iframes = document.querySelectorAll("iframe[src*=\"" + (domains || iframely.DOMAINS).join("\"], iframe[src*=\"") + "\"]"); + for (let i = 0; i < iframes.length; i++) { + const iframe = iframes[i]; + const src = iframe.src; + if (src.match(/^(https?:)?\/\/[^/]+\/api\/iframe\?.+/) || src.match(/^(https?:)?\/\/[^/]+\/\w+(\?.*)?$/)) postMessage({ method: "getSize" }, "*", iframe.contentWindow); + } + } + function nonTextChildCount$1(element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.TEXT_NODE) { + if ((el.textContent || "").replace(/\s|\n/g, "")) count++; + } else if (el.nodeType === Node.ELEMENT_NODE) count++; + } + return count; + } + function containsString(list, findValue) { + let value, i = 0; + while (i < list.length) { + value = list[i]; + if (value == findValue) return true; + if (value instanceof RegExp && value.test(findValue)) return true; + i++; + } + return false; + } + function parseQueryString(url, allowed_query_string) { + const query = url.match(/\?(.+)/i); + if (query) { + const data = query[1].split("&"); + const result = {}; + for (let i = 0; i < data.length; i++) { + const item = data[i].split("="); + if (!allowed_query_string || containsString(allowed_query_string, item[0])) result[item[0]] = decodeURIComponent(item[1]); + } + return result; + } else return {}; + } + function createScript() { + const script = document.createElement("script"); + applyNonce(script); + return script; + } + +//#endregion +//#region src/intersection.ts + var observers = {}; + function getObserver(options) { + const optionsKey = JSON.stringify(options); + let observer = observers[optionsKey]; + if (!observer) { + observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + postMessage({ + method: "intersection", + entry: { isIntersecting: entry.isIntersecting }, + options + }, "*", entry.target.contentWindow); + }); + }, getObserverOptions(options)); + observers[optionsKey] = observer; + } + return observer; + } + function getObserverOptions(options) { + const result = {}; + if (options && options.threshold) result.threshold = options.threshold; + if (options && options.margin) result.rootMargin = options.margin + "px " + options.margin + "px " + options.margin + "px " + options.margin + "px"; + return result; + } + function boot$11() { + iframely.on("init", () => { + iframely.extendOptions({ intersection: 1 }); + }); + iframely.on("message", (widget, message) => { + if (message.method === "send-intersections" && widget.iframe) { + let options = message.options; + if (!options) options = { margin: 1e3 }; + getObserver(options).observe(widget.iframe); + } + }); + } + +//#endregion +//#region src/theme.ts + function setThemeInIframe(iframe, theme) { + postMessage({ + method: "setTheme", + data: theme + }, "*", iframe.contentWindow); + } + function setThemeInAllIframes(parent, theme) { + const iframes = parent.getElementsByTagName("iframe"); + for (let i = 0; i < iframes.length; i++) setThemeInIframe(iframes[i], theme); + } + function boot$10() { + iframely.setTheme = (theme, container) => { + if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) if (container) if (container.tagName === "IFRAME") setThemeInIframe(container, theme); + else setThemeInAllIframes(container, theme); + else { + iframely.extendOptions({ theme }); + setThemeInAllIframes(document, theme); + iframely.trigger("set-theme", theme); + } + else console.warn("Using iframely.setTheme with not supported theme: \"" + theme + "\". Supported themes are: " + iframely.SUPPORTED_THEMES.join(", ")); + }; + } + +//#endregion +//#region src/import.ts + var widgetsCache = {}; + function boot$9() { + iframely.on("load", (el) => { + if (!el && iframely.config.import !== false && isImportAble() && !iframely.import) { + const elements = document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"); + if (elements.length > 1) makeImportAPICall(elements); + } + }); + iframely.on("load", (widget, importOptions) => { + if (widget && !(widget instanceof Element) && widget.uri && (widget.html || widget.cancel)) { + const els = widgetsCache[widget.uri]; + if (els) for (let i = 0; i < els.length; i++) loadImportWidget(widget, els[i], importOptions); + delete widgetsCache[widget.uri]; + } + }); + iframely.buildImportWidgets = (importOptions) => { + iframely.trigger("import-loaded", importOptions); + importOptions.widgets.forEach((widget) => { + iframely.trigger("load", widget, importOptions); + }); + importReady(); + }; + iframely.isTouch = () => { + return "ontouchstart" in window || navigator.maxTouchPoints > 0; + }; + iframely.on("import-widget-ready", clearWrapperStylesAndClass); + if (!iframely.addEventListener) iframely.addEventListener = (elem, type, eventHandle) => { + if (!elem) return; + elem.addEventListener(type, eventHandle, false); + }; + } + function makeImportAPICall(elements) { + const script = createScript(); + const uris = []; + const ids = []; + let import_options = null; + function pushElement(uri, el) { + if (!widgetsCache[uri]) widgetsCache[uri] = []; + widgetsCache[uri].push(el); + } + function queueElement(el) { + const src = el.getAttribute("data-iframely-url"); + const mId = src.match(iframely.ID_RE); + const id = mId && mId[1]; + const options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat("url")); + let url = options.url; + delete options.url; + let skipImport = options.import === "0" || options.import === "false" || options.playerjs === "1" || options.playerjs === "true"; + if (!skipImport) { + const mBase = src.match(iframely.BASE_RE); + options.CDN = mBase && mBase[0]; + if (!import_options) import_options = options; + else if (JSON.stringify(options, Object.keys(options).sort()) !== JSON.stringify(import_options, Object.keys(import_options).sort())) skipImport = true; + } + if (skipImport) iframely.trigger("load", el); + else if (id) { + el.setAttribute("data-import-uri", id); + if (ids.indexOf(id) === -1) ids.push(id); + pushElement(id, el); + } else { + if (!url) url = el.getAttribute("href"); + if ((import_options.key || import_options.api_key || iframely.config.api_key || iframely.config.key) && url) { + el.setAttribute("data-import-uri", url); + if (uris.indexOf(url) === -1) uris.push(url); + pushElement(url, el); + } else iframely.trigger("load", el); + } + } + for (let i = 0; i < elements.length; i++) { + const el = elements[i]; + if (!el.getAttribute("data-import-uri") && el.hasAttribute("data-iframely-url")) queueElement(el); + } + if (uris.length > 0 || ids.length > 0) { + import_options = import_options || {}; + import_options.touch = iframely.isTouch(); + import_options.flash = false; + import_options.app = 1; + if (iframely.config.theme) import_options.theme = iframely.config.theme; + if (uris.length > 0) import_options.uri = uris; + if (ids.length > 0) import_options.ids = ids.join("&"); + import_options.v = iframely.VERSION; + script.src = getEndpoint("/api/import/v2", import_options, iframely.SUPPORTED_QUERY_STRING); + script.onerror = () => { + importReady(); + }; + document.head.appendChild(script); + iframely.import = script; + } else { + importReady(); + iframely.trigger("load"); + } + } + function loadImportWidget(widgetOptions, el, importOptions) { + const needCancelWidget = widgetOptions.cancel; + const shadow = widgetOptions.shadow; + const hasRenderedEvent = widgetOptions.renderEvent; + const wrapper = getIframeWrapper(el, true); + if (needCancelWidget) iframely.cancelWidget(getWidget(el) || { + maxWidthWrapper: el, + iframe: el, + url: el.getAttribute("href") + }); + else { + const widget = document.createElement("div"); + widget.innerHTML = widgetOptions.html; + let parent, replacedEl; + if (wrapper && !hasRenderedEvent) { + parent = wrapper.aspectWrapper.parentNode; + replacedEl = wrapper.aspectWrapper; + wrapper.maxWidthWrapper.removeAttribute("style"); + } else { + parent = el.parentNode; + replacedEl = el; + } + if (shadow) { + const shadowContainer = document.createElement("div"); + const shadowRoot = shadowContainer.attachShadow({ mode: "open" }); + shadowRoot.appendChild(widget); + const shadowWidgetOptions = { + shadowRoot, + shadowContainer, + container: parent, + context: widgetOptions.context, + stylesIds: widgetOptions.stylesIds, + stylesDict: importOptions.commonShadowStyles + }; + iframely.trigger("import-shadow-widget-before-render", shadowWidgetOptions); + parent.insertBefore(shadowContainer, replacedEl); + iframely.trigger("import-shadow-widget-after-render", shadowWidgetOptions); + } else { + parent.insertBefore(widget, replacedEl); + exec_body_scripts(widget); + } + parent.removeChild(replacedEl); + if (hasRenderedEvent) setTimeout(() => { + clearWrapperStylesAndClass(parent); + }, iframely.CLEAR_WRAPPER_STYLES_TIMEOUT); + } + } + function importReady() { + delete iframely.import; + const failed_elements = document.querySelectorAll("a[data-iframely-url][data-import-uri]"); + for (let i = 0; i < failed_elements.length; i++) { + failed_elements[i].removeAttribute("data-import-uri"); + iframely.trigger("load", failed_elements[i]); + } + } + function isImportAble() { + return !!(document.location && (iframely.debug || document.location.protocol === "http:" || document.location.protocol === "https:") && !iframely.config.playerjs && !iframely.config.lazy); + } + function clearWrapperStylesAndClass(el) { + let aspectWrapper = el; + let parents = 0; + while (aspectWrapper && (!aspectWrapper.getAttribute("class") || aspectWrapper.getAttribute("class").split(" ").indexOf(iframely.ASPECT_WRAPPER_CLASS) === -1)) { + aspectWrapper = aspectWrapper.parentNode; + parents++; + if (parents > 4) aspectWrapper = null; + } + const maxWidthWrapper = aspectWrapper && aspectWrapper.parentNode; + if (maxWidthWrapper && maxWidthWrapper.getAttribute("class") && maxWidthWrapper.getAttribute("class").split(" ").indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) > -1) { + aspectWrapper.removeAttribute("style"); + aspectWrapper.removeAttribute("class"); + maxWidthWrapper.removeAttribute("style"); + } + } + function exec_body_scripts(body_el) { + function nodeName(elem, name) { + return !!elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + } + function evalScript(elem) { + const data = elem.text || elem.textContent || elem.innerHTML || ""; + const script = createScript(); + script.type = "text/javascript"; + for (let i = 0; i < elem.attributes.length; i++) { + const attr = elem.attributes[i]; + script.setAttribute(attr.name, attr.value); + } + script.appendChild(document.createTextNode(data)); + body_el.appendChild(script); + } + const scripts = []; + const children_nodes = body_el.childNodes; + for (let i = 0; children_nodes[i]; i++) { + const child = children_nodes[i]; + if (nodeName(child, "script") && (!child.type || child.type.toLowerCase() === "text/javascript" || child.type.toLowerCase() === "application/javascript")) { + scripts.push(child); + body_el.removeChild(child); + } else if (child.nodeType === Node.ELEMENT_NODE) exec_body_scripts(child); + } + for (let i = 0; i < scripts.length; i++) { + const script = scripts[i]; + if (script.parentNode) script.parentNode.removeChild(script); + evalScript(script); + } + } + +//#endregion +//#region src/ahref.ts + function boot$8() { + iframely.on("load", (container, href) => { + if (container && container.nodeName && typeof href === "string") { + const a = document.createElement("a"); + a.setAttribute("href", href); + container.appendChild(a); + iframely.trigger("load", a); + } + }); + iframely.on("load", (el) => { + if (!el && !iframely.import) { + const elements = document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"); + for (let i = 0; i < elements.length; i++) iframely.trigger("load", elements[i]); + } + }); + iframely.on("load", (el) => { + if (el && el.nodeName === "A" && (el.getAttribute("data-iframely-url") || el.getAttribute("href")) && !el.hasAttribute("data-import-uri")) unfurl(el); + }); + } + function unfurl(el) { + if (!el.getAttribute("data-iframely-url") && !el.getAttribute("href")) return; + let src; + const dataIframelyUrl = el.getAttribute("data-iframely-url"); + if (dataIframelyUrl && /^((?:https?:)?\/\/[^/]+)\/\w+/i.test(dataIframelyUrl)) src = getEndpoint(dataIframelyUrl, { + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }); + else if ((iframely.config.api_key || iframely.config.key) && iframely.CDN) { + if (!el.getAttribute("href")) { + console.warn("Iframely cannot build embeds: \"href\" attribute missing in", el); + return; + } + src = getEndpoint("/api/iframe", { + url: el.getAttribute("href"), + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }, iframely.SUPPORTED_QUERY_STRING); + } else console.warn("Iframely cannot build embeds: api key is required as query-string of embed.js"); + if (!src) el.removeAttribute("data-iframely-url"); + else { + const iframe = document.createElement("iframe"); + iframe.setAttribute("allowfullscreen", ""); + iframe.setAttribute("allow", "autoplay *; encrypted-media *; ch-prefers-color-scheme *"); + if (el.hasAttribute("data-img")) iframe.setAttribute("data-img", el.getAttribute("data-img")); + const isLazy = el.hasAttribute("data-lazy") || el.hasAttribute("data-img") || /&lazy=1/.test(src) || iframely.config.lazy; + const text = el.textContent; + if (text && text !== "") iframe.textContent = text; + let wrapper = getIframeWrapper(el, true); + if (wrapper) while (wrapper.aspectWrapper.lastChild) wrapper.aspectWrapper.removeChild(wrapper.aspectWrapper.lastChild); + else { + wrapper = addDefaultWrappers(el); + el.parentNode.removeChild(el); + } + wrapper.aspectWrapper.appendChild(iframe); + if (isLazy) { + iframe.setAttribute("data-iframely-url", src); + iframely.trigger("load", iframe); + } else { + iframe.setAttribute("src", src); + iframely.trigger("iframe-ready", iframe); + } + } + } + +//#endregion +//#region src/lazy-img-placeholder.ts + function boot$7() { + iframely.on("load", (el) => { + if (el && el.nodeName === "IFRAME" && el.hasAttribute("data-iframely-url") && el.hasAttribute("data-img") && !el.getAttribute("src")) { + const dataImg = el.getAttribute("data-img"); + el.removeAttribute("data-img"); + el.setAttribute("data-img-created", ""); + const widget = getWidget(el); + let src = el.getAttribute("data-iframely-url"); + if (widget) { + addPlaceholderThumbnail(widget, src, dataImg); + src = addQueryString(src, { img: 1 }); + el.setAttribute("data-iframely-url", src); + new WaitingWidget(widget); + } + iframely.trigger("load", el); + } + }); + iframely.on("message", (widget, message) => { + if (!widget) return; + let waitingWidget; + if (message.method === "widgetRendered") { + hidePlaceholderThumbnail(widget); + waitingWidget = findWaitingWidget(widget); + waitingWidget?.deactivate(); + } + if (message.method === "begin-waiting-widget-render") { + waitingWidget = findWaitingWidget(widget); + waitingWidget?.clearLoadingTimeout(); + } + if (message.method === "end-waiting-widget-render") { + waitingWidget = findWaitingWidget(widget); + waitingWidget?.registerLoadingTimeout(); + } + }); + } + function addPlaceholderThumbnail(widget, href, imageUrl) { + let thumbHref; + if (imageUrl && /^(https?:)?\/\//.test(imageUrl)) thumbHref = imageUrl; + else { + const query = parseQueryString(href); + const _params = {}; + for (const param in query) if (param.indexOf("_") === 0) _params[param] = query[param]; + if (query.media) _params.media = query.media; + if (href.match(/\/api\/iframe/)) thumbHref = getEndpoint(href.match(/^(.+)\/api\/iframe/i)[1] + "/api/thumbnail", Object.assign({ + url: query.url, + api_key: query.api_key, + key: query.key + }, _params)); + else if (href.match(iframely.ID_RE)) thumbHref = getEndpoint(href.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/, "$1/thumbnail"), _params); + else return; + } + const thumb = document.createElement("div"); + setStyles(thumb, { + position: "absolute", + width: "100%", + height: "100%", + backgroundImage: "url('" + thumbHref + "')", + backgroundSize: "cover", + backgroundPosition: "center" + }); + const iframelyLoaderDiv = document.createElement("div"); + iframelyLoaderDiv.setAttribute("class", iframely.LOADER_CLASS); + thumb.appendChild(iframelyLoaderDiv); + const paddingTop = iframely.getElementComputedStyle(widget.aspectWrapper, "padding-top"); + const paddingBottom = iframely.getElementComputedStyle(widget.aspectWrapper, "padding-bottom"); + const paddingTopMatch = paddingTop && paddingTop.match(/^(\d+)px$/); + if (paddingTopMatch && parseInt(paddingTopMatch[1]) && paddingBottom) { + const thumbWrapper = document.createElement("div"); + setStyles(thumbWrapper, { + top: "-" + paddingTop, + width: "100%", + height: 0, + position: "relative", + paddingBottom + }); + thumbWrapper.appendChild(thumb); + widget.aspectWrapper.appendChild(thumbWrapper); + } else widget.aspectWrapper.appendChild(thumb); + } + function getNthNonTextChildNode(nth, element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.ELEMENT_NODE) { + if (nth === count) return el; + count++; + } + } + } + function nonTextChildCount(element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.TEXT_NODE) { + if ((el.textContent || "").replace(/\s|\n/g, "")) count++; + } else if (el.nodeType === Node.ELEMENT_NODE) count++; + } + return count; + } + function hidePlaceholderThumbnail(widget) { + const thumb = widget.aspectWrapper && nonTextChildCount(widget.aspectWrapper) > 1 && getNthNonTextChildNode(1, widget.aspectWrapper); + if (thumb && thumb.nodeName === "DIV") widget.aspectWrapper.removeChild(thumb); + } + var waitingWidgets = []; + function findWaitingWidgetIdx(widget) { + let i = 0; + while (i < waitingWidgets.length && waitingWidgets[i].widget.iframe !== widget.iframe) i++; + if (i < waitingWidgets.length && waitingWidgets[i].widget.iframe === widget.iframe) return i; + } + function findWaitingWidget(widget) { + const idx = findWaitingWidgetIdx(widget); + if (idx || idx === 0) return waitingWidgets[idx]; + } + function removeWaitingWidget(widget) { + const idx = findWaitingWidgetIdx(widget); + if (idx || idx === 0) waitingWidgets.splice(idx, 1); + } + var WaitingWidget = class { + widget; + loadCount = 0; + timeoutId = null; + constructor(widget) { + this.widget = widget; + iframely.addEventListener(widget.iframe, "load", () => { + this.iframeOnLoad(); + }); + this.registerLoadingTimeout(); + waitingWidgets.push(this); + } + iframeOnLoad() { + this.loadCount++; + if (this.loadCount !== 2) return; + this.deactivate(); + setTimeout(() => { + hidePlaceholderThumbnail(this.widget); + }, iframely.LAZY_IFRAME_FADE_TIMEOUT); + } + deactivate() { + this.clearLoadingTimeout(); + removeWaitingWidget(this.widget); + } + clearLoadingTimeout() { + if (this.timeoutId) clearTimeout(this.timeoutId); + this.timeoutId = null; + } + registerLoadingTimeout() { + if (this.timeoutId) return; + this.timeoutId = setTimeout(() => { + this.iframeOnLoad(); + }, iframely.LAZY_IFRAME_SHOW_TIMEOUT); + } + }; + +//#endregion +//#region src/lazy-iframe.ts + function boot$6() { + iframely.on("load", (el) => { + if (!el) { + const elements = document.querySelectorAll("iframe[data-iframely-url]"); + for (let i = 0; i < elements.length; i++) iframely.trigger("load", elements[i]); + } + }); + iframely.on("load", (el) => { + if (el && el.nodeName === "IFRAME" && el.hasAttribute("data-iframely-url") && !el.hasAttribute("data-img") && !el.getAttribute("src")) loadLazyIframe(el); + }); + } + function loadLazyIframe(el) { + const widget = getWidget(el); + let src = el.getAttribute("data-iframely-url"); + const dataImg = el.hasAttribute("data-img-created") || el.hasAttribute("data-img"); + const nativeLazyLoad = !dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR; + if (widget && src) { + const options = { + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }; + if (!nativeLazyLoad && iframely.config.intersection) options.lazy = 1; + src = getEndpoint(src, options); + } + if (nativeLazyLoad) el.setAttribute("loading", "lazy"); + if (dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR) el.setAttribute("loading", "edge"); + el.setAttribute("src", src || ""); + el.removeAttribute("data-iframely-url"); + iframely.trigger("iframe-ready", el); + } + +//#endregion +//#region src/widget-cancel.ts + function boot$5() { + iframely.on("message", (widget, message) => { + if (message.method === "cancelWidget") iframely.cancelWidget(widget); + }); + iframely.cancelWidget = (widget) => { + if (!widget) { + console.warn("iframely.cancelWidget called without widget param"); + return; + } + function findParent(el, className) { + let found = false; + while (!found && el.parentNode) { + el = el.parentNode; + found = !!el.className && typeof el.className === "string" && el.className.split(" ").indexOf(className) >= 0; + } + return found && el; + } + let parentNode = widget.maxWidthWrapper && widget.maxWidthWrapper.parentNode; + let naNode = widget.maxWidthWrapper; + if (iframely.config && iframely.config.parent) { + const parentElement = findParent(widget.maxWidthWrapper, String(iframely.config.parent)); + if (parentElement) { + parentNode = parentElement.parentNode; + naNode = parentElement; + } + } + if (widget.url) { + const text = widget.iframe && widget.iframe.textContent; + iframely.triggerAsync("cancel", widget.url, parentNode, text, naNode.nextSibling); + } + parentNode.removeChild(naNode); + }; + } + +//#endregion +//#region src/widget-resize.ts + var resetWrapperBorderStyles = { + "border": "", + "border-radius": "", + "box-shadow": "", + "overflow": "" + }; + var resetIframeBorderStyles = { + "border": "0", + "border-radius": "", + "box-shadow": "", + "overflow": "" + }; + function boot$4() { + iframely.on("message", (widget, message) => { + if (message.method === "setIframelyWidgetSize" || message.method === "resize" || message.method === "setIframelyEmbedData" || message.type === "embed-size" || message.context === "iframe.resize") { + let frame_styles = null; + if (message.data && message.data.media && message.data.media.frame_style) { + message.data.media.frame_style.split(";").forEach((str) => { + if (str.trim() !== "" && str.indexOf(":") > -1) { + const props = str.split(":"); + if (props.length === 2) { + frame_styles = frame_styles || {}; + frame_styles[props[0].trim()] = props[1].trim(); + } + } + }); + widgetDecorate(widget, frame_styles); + } else if (message.method === "setIframelyEmbedData") widgetDecorate(widget, null); + let media = message.data && message.data.media; + if (!media && message.height) media = { + height: message.height, + "max-width": "keep" + }; + widgetResize(widget, media); + } + }); + } + function widgetDecorate(widget, styles) { + if (styles && widget && widget.iframe) if (styles["border-radius"]) { + styles.overflow = "hidden"; + setStyles(widget.aspectWrapper, styles); + } else setStyles(widget.iframe, styles); + else if (!styles && widget && widget.iframe) { + setStyles(widget.aspectWrapper, resetWrapperBorderStyles); + setStyles(widget.iframe, resetIframeBorderStyles); + } + } + function getTotalBorderWidth(widget) { + const frameStylesBorder = widget.iframe && widget.iframe.style.border || widget.aspectWrapper && widget.aspectWrapper.style.border; + const borderMatch = frameStylesBorder && frameStylesBorder.match(/(\d+)px/); + if (borderMatch) return parseInt(borderMatch[1]) * 2; + return 0; + } + function widgetResize(widget, media) { + if (media && Object.keys(media).length > 0 && widget) { + const borderWidth = getTotalBorderWidth(widget); + const oldIframeHeight = window.getComputedStyle(widget.iframe).getPropertyValue("height"); + let maxWidth = media["max-width"]; + if (typeof maxWidth === "number") maxWidth += borderWidth; + setStyles(widget.maxWidthWrapper, { + "max-width": maxWidth, + "min-width": media["min-width"] && media["min-width"] + borderWidth, + width: media.width && media.width + borderWidth + }); + if (media.scrolling && widget.iframe) widget.iframe.setAttribute("scrolling", media.scrolling); + const aspectRatio = media["aspect-ratio"]; + if (aspectRatio || media.height) setStyles(widget.aspectWrapper, { + paddingBottom: aspectRatio ? Math.round(1e3 * 100 / aspectRatio) / 1e3 + "%" : 0, + paddingTop: aspectRatio && media["padding-bottom"], + height: aspectRatio ? 0 : media.height && media.height + borderWidth + }); + const currentHeight = window.getComputedStyle(widget.iframe).getPropertyValue("height"); + if (oldIframeHeight && oldIframeHeight !== currentHeight) iframely.triggerAsync("heightChanged", widget.iframe, oldIframeHeight, currentHeight); + } + } + +//#endregion +//#region src/widget-click.ts + function boot$3() { + iframely.on("message", (widget, message) => { + if (message.method === "open-href" || message.method === "click") iframely.trigger(message.method, message.href); + }); + if (!iframely.openHref) iframely.openHref = (href) => { + if (href.indexOf(window.location.origin) === 0) window.location.href = href; + else window.open(href, "_blank", "noopener"); + }; + iframely.on("open-href", (href) => { + iframely.triggerAsync("click", href); + iframely.openHref(href); + }); + } + +//#endregion +//#region src/widget-options.ts + function boot$2() { + iframely.on("message", (widget, message) => { + if (message.method === "setIframelyEmbedOptions") iframely.trigger("options", widget, message.data); + }); + } + +//#endregion +//#region src/deprecated.ts + function boot$1() { + iframely.widgets = iframely.widgets || {}; + iframely.widgets.load = iframely.load; + if (!iframely.events) { + iframely.events = {}; + iframely.events.on = iframely.on; + iframely.events.trigger = iframely.trigger; + } + iframely.on("cancel", (url, parentNode, text, nextSibling) => { + if (iframely.RECOVER_HREFS_ON_CANCEL && !text) text = url; + if (url && parentNode && text && text !== "") { + const a = document.createElement("a"); + a.setAttribute("href", url); + a.setAttribute("target", "_blank"); + a.setAttribute("rel", "noopener"); + a.textContent = text; + if (nextSibling) parentNode.insertBefore(a, nextSibling); + else parentNode.appendChild(a); + } + }); + } + +//#endregion +//#region src/options/form-generator.ts + var _RE = /^_./; + var translate = (label, translator) => { + return translator && typeof translator === "function" && label ? translator(label) || label : label; + }; + function getFormElements(options, translator) { + if (!options) return []; + options = Object.assign({}, options); + delete options.query; + const items = []; + const keys = Object.keys(options); + let checkboxCount = 0; + keys.forEach((key) => { + const context = {}; + let getQuery; + const option = options[key]; + option.key = key; + let forceCheckboxForSingleKeyValue = false; + const valuesKeys = option.values ? Object.keys(option.values) : void 0; + let singleKey, singleLabel; + if (valuesKeys && valuesKeys.length === 1) { + forceCheckboxForSingleKeyValue = true; + singleKey = valuesKeys[0]; + singleLabel = option.values[singleKey]; + } + context.label = translate(singleLabel || option.label, translator); + context.key = option.key; + if (forceCheckboxForSingleKeyValue || typeof option.value === "boolean") { + if (forceCheckboxForSingleKeyValue) context.checked = singleKey === option.value || !singleKey && !option.value; + else context.checked = option.value; + checkboxCount++; + items.push({ + type: "checkbox", + context, + order: _RE.test(key) ? 0 : 1, + getQuery: (checked) => { + let value; + if (forceCheckboxForSingleKeyValue) value = checked ? singleKey : ""; + else value = checked; + const result = {}; + if (forceCheckboxForSingleKeyValue) if (value === "") {} else result[option.key] = value; + else result[option.key] = checked; + return result; + } + }); + } else if ((typeof option.value === "number" || typeof option.value === "string") && !option.values) { + const useSlider = option.range && typeof option.range.min === "number" && typeof option.range.max === "number"; + const useNumber = typeof option.value === "number"; + context.value = option.value; + getQuery = (inputValue) => { + const result = {}; + if (inputValue === "") {} else result[option.key] = inputValue; + return result; + }; + if (useSlider) { + context.min = option.range.min; + context.max = option.range.max; + items.push({ + type: "range", + context, + order: 9, + getQuery + }); + } else { + context.placeholder = translate(option.placeholder || "", translator); + context.inputType = useNumber ? "number" : "text"; + items.push({ + type: "text", + context, + order: /start/i.test(key) ? 7 : 8, + getQuery + }); + } + } else if (option.values) { + context.value = option.value + ""; + getQuery = (inputValue) => { + const result = {}; + if (inputValue === "") {} else result[option.key] = inputValue; + return result; + }; + if (Object.keys(option.values).length <= 3) { + if (option.label) context.label = translate(option.label, translator); + else context.label = false; + let i = 0; + let hasLongLabel = false; + const values = Object.values(option.values); + while (i < values.length && !hasLongLabel) { + hasLongLabel = values[i].length > 8; + i++; + } + context.inline = !hasLongLabel; + context.items = []; + Object.keys(option.values).forEach((key, idx2) => { + context.items.push({ + id: context.key + "-" + idx2, + value: key, + label: translate(option.values[key], translator), + checked: context.value === key + }); + }); + items.push({ + type: "radio", + context, + order: hasLongLabel ? -3 : !/theme/.test(key) ? -2 : -1, + getQuery + }); + } else { + context.items = []; + Object.keys(option.values).forEach((key) => { + context.items.push({ + value: key, + label: translate(option.values[key], translator), + checked: context.value === key + }); + }); + items.push({ + type: "select", + context, + order: 5, + getQuery + }); + } + } + }); + items.sort((a, b) => a.order - b.order); + items.forEach((item) => { + delete item.order; + }); + if (checkboxCount > 0) { + const groupedItems = []; + let subItems; + items.forEach((item, idx) => { + if (item.type === "checkbox") { + const newCheckboxGroup = checkboxCount > 2 && idx > 0 && !_RE.test(item.context.key) && items[idx - 1].type === "checkbox" && _RE.test(items[idx - 1].context.key); + if (!subItems || newCheckboxGroup) { + subItems = []; + groupedItems.push({ + type: "group", + context: { elements: subItems } + }); + } + subItems.push(item); + } else groupedItems.push(item); + }); + return groupedItems; + } else return items; + } + +//#endregion +//#region src/options/form-builder.ts + var UIelements = { + checkbox: { getValue: (inputs) => { + return inputs[0].checked; + } }, + text: { + getValue: (inputs) => { + const input = inputs[0]; + let value = input.value; + if (input.type === "number") { + value = parseInt(value); + if (isNaN(value)) value = ""; + } + return value; + }, + customEvents: (inputs, submitOptionsCb) => { + const input = inputs[0]; + iframely.addEventListener(input, "click", () => { + input.select(); + }); + iframely.addEventListener(input, "blur", submitOptionsCb); + iframely.addEventListener(input, "keyup", (e) => { + if (e.keyCode === 13) submitOptionsCb(); + }); + } + }, + radio: { getValue: (inputs) => { + let selectedInput; + Array.prototype.forEach.call(inputs, (input) => { + if (input.checked) selectedInput = input; + }); + return selectedInput.value; + } } + }; + var defaultQueryById = {}; + function formBuilder(params) { + const options = params.options; + const formContainer = params.formContainer; + if (!formContainer) { + console.warn("No formContainer in form-builder options", params); + return; + } + if (!options) { + formContainer.innerHTML = ""; + return; + } + const elements = getFormElements(options, params.translator); + const id = params.id; + const renderer = params.renderer; + const defaultQuery = defaultQueryById[id] = defaultQueryById[id] || {}; + Object.keys(options).forEach((key) => { + if (!options.query || options.query.indexOf(key) === -1) defaultQuery[key] = options[key].value; + }); + function getQueryFromForm() { + const query = {}; + const getOptionsFromElements = (elements) => { + elements.forEach((element) => { + if (element.context && element.context.elements) getOptionsFromElements(element.context.elements); + else if (element.inputs) { + const elementUI = UIelements[element.type]; + let inputValue; + if (elementUI && elementUI.getValue) inputValue = elementUI.getValue(element.inputs); + else inputValue = element.inputs[0].value; + Object.assign(query, element.getQuery(inputValue)); + } + }); + }; + getOptionsFromElements(elements); + return query; + } + function getAndSubmitOptions() { + const query = getQueryFromForm(); + Object.keys(defaultQuery).forEach((key) => { + if (defaultQuery[key] === query[key] || query[key] === void 0) delete query[key]; + }); + iframely.trigger("options-changed", id, formContainer, query); + } + const renderElements = (elements) => { + let html = ""; + elements.forEach((element) => { + if (element.context && element.context.elements) element.context.elementsHtml = renderElements(element.context.elements); + html += renderer(element.type, element.context || {}); + }); + return html; + }; + formContainer.innerHTML = renderElements(elements); + const bindElements = (elements) => { + elements.forEach((element) => { + if (element.context && element.context.elements) bindElements(element.context.elements); + else { + const elementUI = UIelements[element.type]; + if (element.context) { + const inputs = formContainer.querySelectorAll("[name=\"" + element.context.key + "\"]"); + element.inputs = inputs; + if (inputs.length > 0) if (elementUI && elementUI.customEvents) elementUI.customEvents(inputs, getAndSubmitOptions); + else inputs.forEach((input) => { + iframely.addEventListener(input, "change", getAndSubmitOptions); + }); + else console.warn("No inputs found for option", element.context.key); + } + } + }); + }; + bindElements(elements); + } + +//#endregion +//#region src/options/renderer.ts + var ESCAPE_MAP = { + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'" + }; + var esc = (value) => value == null ? "" : String(value).replace(/[&<>"']/g, (c) => ESCAPE_MAP[c]); + var templates = { + checkbox: (ctx) => ` +
+ + +
`, + group: (ctx) => ` +
+
${ctx.elementsHtml ?? ""}
+
`, + radio: (ctx) => ` +
+ ${ctx.label ? `` : ""} +
+ ${(ctx.items || []).map((item) => ` +
+ + +
`).join("")} +
+
`, + range: (ctx) => ` +
+ +
+ +
+
`, + select: (ctx) => ` +
+ +
+ +
+
`, + text: (ctx) => ` +
+ +
+ +
+
` + }; + var render = (type, context) => templates[type](context); + +//#endregion +//#region src/options/index.ts + function boot() { + iframely.buildOptionsForm = (id, formContainer, options, translator) => { + formBuilder({ + id, + formContainer, + options, + renderer: render, + translator + }); + }; + } + +//#endregion +//#region src/index-options.ts + if (!iframely._loaded) { + iframely._loaded = true; + boot$15(); + boot$14(); + boot$12(); + boot$13(); + boot$11(); + boot$10(); + boot$9(); + boot$8(); + boot$7(); + boot$6(); + boot$5(); + boot$4(); + boot$3(); + boot$2(); + boot$1(); + boot(); + iframely.trigger("init"); + } + +//#endregion +})(); \ No newline at end of file diff --git a/dist/embed-options.min.js b/dist/embed-options.min.js index 0b983c2..8bedec2 100644 --- a/dist/embed-options.min.js +++ b/dist/embed-options.min.js @@ -1 +1,38 @@ -(()=>{var __webpack_modules__={530(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,"")}with(obj)__p+='
\n \n '+(null==(__t=label)?"":__t)+"\n \n
\n";return __p}},30(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;with(obj)__p+='
\n
\n '+__e(elementsHtml)+"\n
\n
";return __p}},510(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,"")}with(obj)__p+='
\n ',label&&(__p+='\n \n "),__p+='\n
\n '+(null==(__t=e.label)?"":__t)+"\n \n
\n "}),__p+="\n
\n";return __p}},300(module){module.exports=function(obj){obj||(obj={});var __t,__p="";with(obj)__p+='
\n \n
\n \n
\n
';return __p}},37(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,"")}with(obj)__p+='
\n \n
\n \n
\n
";return __p}},712(module){module.exports=function(obj){obj||(obj={});var __t,__p="";with(obj)__p+='
\n \n
\n \n
\n
';return __p}},679(e,t,r){var n=r(672),a=r(774);a.on("load",function(e,t){if(e&&e.nodeName&&"string"==typeof t){var r=document.createElement("a");r.setAttribute("href",t),e.appendChild(r),a.trigger("load",r)}}),a.on("load",function(e){if(!e&&!a.import)for(var t=document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"),r=0;r4&&(t=null);var n=t&&t.parentNode;n&&n.getAttribute("class")&&n.getAttribute("class").split(" ").indexOf(a.MAXWIDTH_WRAPPER_CLASS)>-1&&(t.removeAttribute("style"),t.removeAttribute("class"),n.removeAttribute("style"))}function s(e){function t(e,t){return e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function r(t){var r=t.text||t.textContent||t.innerHTML||"",a=n.createScript();a.type="text/javascript";for(var i=0;i1&&function(e){var t=n.createScript(),r=[],o=[],c=null;function s(e,t){i[e]||(i[e]=[]),i[e].push(t)}function d(e){var t=e.getAttribute("data-iframely-url"),i=t.match(a.ID_RE),l=i&&i[1],d=n.parseQueryString(t,a.SUPPORTED_QUERY_STRING.concat("url")),u=d.url;delete d.url;var p="0"===d.import||"false"===d.import||"1"===d.playerjs||"true"===d.playerjs;if(!p){var f=t.match(a.BASE_RE);d.CDN=f&&f[0],c?JSON.stringify(d,Object.keys(d).sort())!==JSON.stringify(c,Object.keys(c).sort())&&(p=!0):c=d}p?a.trigger("load",e):l?(e.setAttribute("data-import-uri",l),-1===o.indexOf(l)&&o.push(l),s(l,e)):(u||(u=e.getAttribute("href")),(c.key||c.api_key||a.config.api_key||a.config.key)&&u?(e.setAttribute("data-import-uri",u),-1===r.indexOf(u)&&r.push(u),s(u,e)):a.trigger("load",e))}for(var u=0;u0||o.length>0?((c=c||{}).touch=a.isTouch(),c.flash=function(){var e=!1;try{e=!!new ActiveXObject("ShockwaveFlash.ShockwaveFlash")}catch(t){e=!(!navigator.mimeTypes||null==navigator.mimeTypes["application/x-shockwave-flash"]||!navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)}return e}(),c.app=1,a.config.theme&&(c.theme=a.config.theme),r.length>0&&(c.uri=r),o.length>0&&(c.ids=o.join("&")),c.v=a.VERSION,t.src=n.getEndpoint("/api/import/v2",c,a.SUPPORTED_QUERY_STRING),t.onerror=function(){l()},document.head.appendChild(t),a.import=t):(l(),a.trigger("load"))}(t)}}),a.on("load",function(e,t){if(e&&e.uri&&(e.html||e.cancel)){var r=i[e.uri];if(r)for(var n=0;n1&&function(e,t){for(var r=0,n=0;n=77},369(e,t,r){var n=r(774),a=r(672);function i(e,t){for(var r,n=0;n0?t&&t.customEvents?t.customEvents(e.inputs,f):e.inputs.forEach(function(e){a.addEventListener(e,"change",f)}):console.warn("No inputs found for option",e.key))}})};p(l)}else r.innerHTML="";else console.warn("No formContainer in form-builder options",e);function f(){var e=function(){var e={},t=function(r){r.forEach(function(r){if(r.context&&r.context.elements)t(r.context.elements);else if(r.inputs){var n,a=i[r.type];n=a&&a.getValue?a.getValue(r.inputs):r.inputs[0].value,Object.assign(e,r.getQuery(n))}})};return t(l),e}();Object.keys(d).forEach(function(t){d[t]!==e[t]&&void 0!==e[t]||delete e[t]}),a.trigger("options-changed",c,r,e)}}},960(e){var t=/^_./,r=function(e,t){return t&&"function"==typeof t&&t(e)||e};e.exports=function(e,n){if(!e)return[];delete(e=Object.assign({},e)).query;var a=[],i=Object.keys(e),o=0;if(i.forEach(function(i){var l,c,s={},d=e[i];d.key=i;var u,p,f=d.values&&Object.keys(d.values);if(f&&1===f.length&&(c=!0,u=f[0],p=d.values[u]),s.label=r(p||d.label,n),s.key=d.key,c||"boolean"==typeof d.value)s.checked=c?u===d.value||!u&&!d.value:d.value,o++,a.push({type:"checkbox",context:s,order:t.test(i)?0:1,getQuery:function(e){var t;t=c?e?u:"":e;var r={};return c?""===t||(r[d.key]=t):r[d.key]=e,r}});else if("number"!=typeof d.value&&"string"!=typeof d.value||d.values){if(d.values)if(s.value=d.value+"",l=function(e){var t={};return""===e||(t[d.key]=e),t},Object.keys(d.values).length<=3){d.label?s.label=r(d.label,n):s.label=!1;for(var m=0,_=!1,h=Object.values(d.values);m8,m++;s.inline=!_,s.items=[],Object.keys(d.values).forEach(function(e,t){s.items.push({id:s.key+"-"+t,value:e,label:r(d.values[e],n),checked:s.value===e})}),a.push({type:"radio",context:s,order:_?-3:/theme/.test(i)?-1:-2,getQuery:l})}else s.items=[],Object.keys(d.values).forEach(function(e){s.items.push({value:e,label:r(d.values[e],n),checked:s.value===e})}),a.push({type:"select",context:s,order:5,getQuery:l})}else{var g=d.range&&"number"==typeof d.range.min&&"number"==typeof d.range.max,v="number"==typeof d.value;s.value=d.value,l=function(e){var t={};return""===e||(t[d.key]=e),t},g?(s.min=d.range.min,s.max=d.range.max,a.push({type:"range",context:s,order:9,getQuery:l})):(s.placeholder=r(d.placeholder||"",n),s.inputType=v?"number":"text",a.push({type:"text",context:s,order:/start/i.test(i)?7:8,getQuery:l}))}}),a.sort(function(e,t){return e.order-t.order}),a.forEach(function(e){delete e.order}),o>0){var l,c=[];return a.forEach(function(e,r){if("checkbox"===e.type){var n=o>2&&r>0&&!t.test(e.context.key)&&"checkbox"===a[r-1].type&&t.test(a[r-1].context.key);l&&!n||(l=[],c.push({type:"group",context:{elements:l}})),l.push(e)}else c.push(e)}),c}return a}},448(e,t,r){var n=r(774),a=r(410),i=r(505);n.buildOptionsForm=function(e,t,r,n){a({id:e,formContainer:t,options:r,renderer:i,translator:n})},t.iframely=n},505(e,t,r){var n={checkbox:r(530),range:r(300),text:r(712),radio:r(510),select:r(37),group:r(30)};e.exports=function(e,t){return(0,n[e])(t)}},908(e,t,r){var n=r(774),a=r(369);function i(e,t){a.postMessage({method:"setTheme",data:t},"*",e.contentWindow)}function o(e,t){for(var r=e.getElementsByTagName("iframe"),n=0;n-1?t?"IFRAME"===t.tagName?i(t,e):o(t,e):(n.extendOptions({theme:e}),o(document,e),n.trigger("set-theme",e)):console.warn('Using iframely.setTheme with not supported theme: "'+e+'". Supported themes are: '+n.SUPPORTED_THEMES.join(", "))}},672(e,t,r){var n=r(774),a=r(369);n.on("init",function(){n.extendOptions(function(){for(var e=document.querySelectorAll('script[src*="embed.js"], script[src*="iframely.js"]'),t=0;t0)return a}}return{}}()),function(){var e="iframely-styles",t=document.getElementById(e);if(!t){var r=".iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}";(t=document.createElement("style")).id=e,t.type="text/css",o(t),t.styleSheet?t.styleSheet.cssText=r:t.innerHTML=r,document.getElementsByTagName("head")[0].appendChild(t)}}(),n.config.theme&&n.setTheme(n.config.theme),function(e){for(var t=document.querySelectorAll('iframe[src*="'+(e||n.DOMAINS).join('"], iframe[src*="')+'"]'),r=0;r2||t&&r.getAttribute("class")!==n.ASPECT_WRAPPER_CLASS||!t&&"relative"!==r.style.position&&r.getAttribute("class")!==n.ASPECT_WRAPPER_CLASS)){var a=r.parentNode;if(!(!a||"DIV"!==a.nodeName||c(a)>1||t&&a.getAttribute("class")&&-1===a.getAttribute("class").split(" ").indexOf(n.MAXWIDTH_WRAPPER_CLASS)||!t&&a.getAttribute("class")&&!a.getAttribute("class").match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:a}}};t.addDefaultWrappers=function(e){var t=e.parentNode,r=document.createElement("div");r.className=n.MAXWIDTH_WRAPPER_CLASS;var a=document.createElement("div");return a.className=n.ASPECT_WRAPPER_CLASS,r.appendChild(a),t.insertBefore(r,e),{aspectWrapper:a,maxWidthWrapper:r}},t.getWidget=function(e){var t=i(e);if(t){var r={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper};if("A"===e.nodeName&&e.hasAttribute("href"))r.url=e.getAttribute("href");else if(e.hasAttribute("src")&&/url=/.test(e.getAttribute("src"))){var n=d(e.getAttribute("src"));n.url&&(r.url=n.url)}return r}},n.getElementComputedStyle=function(e,t){return window.getComputedStyle&&window.getComputedStyle(e).getPropertyValue(t)},t.setStyles=function(e,t){e&&Object.keys(t).forEach(function(r){var a=t[r];("number"==typeof a||"string"==typeof a&&/^(\d+)?\.?(\d+)$/.test(a))&&(a+="px");var i=e.style[r];window.getComputedStyle&&(n.getElementComputedStyle(e,r)==a||"iframely-responsive"==e.className&&"paddingBottom"===r&&!i&&/^56\.2\d+%$/.test(a)||"max-width"===r&&"keep"===a)||(e.style[r]=a||"")})};var o=t.applyNonce=function(e){n.config.nonce&&(e.nonce=n.config.nonce)},l=t.addQueryString=function(e,t){var r="";return Object.keys(t).forEach(function(n){var a=t[n];if("[object Array]"===Object.prototype.toString.call(a)){var i=a.map(function(e){return n+"="+encodeURIComponent(e)});r+="&"+i.join("&")}else void 0!==a&&-1===e.indexOf(n+"=")&&("boolean"==typeof a&&"_"!==n.charAt(0)&&(a=a?1:0),r+="&"+n+"="+encodeURIComponent(a))}),e+(""!==r?(e.indexOf("?")>-1?"&":"?")+r.replace(/^&/,""):"")};function c(e){for(var t=0,r=0;r=0;return r&&e}(e.maxWidthWrapper,n.config.parent);a&&(t=a.parentNode,r=a)}if(e.url){var i=e.iframe&&(e.iframe.textContent||e.iframe.innerText);n.triggerAsync("cancel",e.url,t,i,r.nextSibling)}t.removeChild(r)}else console.warn("iframely.cancelWidget called without widget param")}},612(e,t,r){var n=r(774);n.on("message",function(e,t){"open-href"!==t.method&&"click"!==t.method||n.trigger(t.method,t.href)}),n.openHref||(n.openHref=function(e){0===e.indexOf(window.location.origin)?window.location.href=e:window.open(e,"_blank","noopener")}),n.on("open-href",function(e){n.triggerAsync("click",e),n.openHref(e)})},742(e,t,r){var n=r(774);n.on("message",function(e,t){"setIframelyEmbedOptions"===t.method&&n.trigger("options",e,t.data)})},850(e,t,r){var n=r(672),a=r(774);a.on("message",function(e,t){if("setIframelyWidgetSize"===t.method||"resize"===t.method||"setIframelyEmbedData"===t.method||"embed-size"===t.type||"iframe.resize"===t.context){var r=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(";").forEach(function(e){if(""!==e.trim()&&e.indexOf(":")>-1){var t=e.split(":");2===t.length&&((r=r||{})[t[0].trim()]=t[1].trim())}}),l(e,r)):"setIframelyEmbedData"===t.method&&l(e,null);var i=t.data&&t.data.media;!i&&t.height&&(i={height:t.height,"max-width":"keep"}),function(e,t){if(t&&Object.keys(t).length>0&&e){var r=function(e){var t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,r=t&&t.match(/(\d+)px/)||0;return r&&(r=parseInt(r[1]),r*=2),r}(e),i=window.getComputedStyle&&window.getComputedStyle(e.iframe).getPropertyValue("height"),o=t["max-width"];"number"==typeof o&&(o+=r),n.setStyles(e.maxWidthWrapper,{"max-width":o,"min-width":t["min-width"]&&t["min-width"]+r,width:t.width&&t.width+r}),t.scrolling&&e.iframe&&e.iframe.setAttribute("scrolling",t.scrolling);var l=t["aspect-ratio"];(l||t.height)&&n.setStyles(e.aspectWrapper,{paddingBottom:l?Math.round(1e5/l)/1e3+"%":0,paddingTop:l&&t["padding-bottom"],height:l?0:t.height&&t.height+r});var c=window.getComputedStyle&&window.getComputedStyle(e.iframe).getPropertyValue("height");i&&i!==c&&a.triggerAsync("heightChanged",e.iframe,i,c)}}(e,i)}});var i={border:"","border-radius":"","box-shadow":"",overflow:""},o={border:"0","border-radius":"","box-shadow":"",overflow:""};function l(e,t){t&&e&&e.iframe?t["border-radius"]?(t.overflow="hidden",n.setStyles(e.aspectWrapper,t)):n.setStyles(e.iframe,t):!t&&e&&e.iframe&&(n.setStyles(e.aspectWrapper,i),n.setStyles(e.iframe,o))}}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var r=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](r,r.exports,__webpack_require__),r.exports}__webpack_require__.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}();var __webpack_exports__={};(()=>{__webpack_require__(331);var e=__webpack_require__(774);e._loaded||(e._loaded=!0,__webpack_require__(54),__webpack_require__(912),__webpack_require__(56),__webpack_require__(908),__webpack_require__(472),__webpack_require__(679),__webpack_require__(573),__webpack_require__(324),__webpack_require__(648),__webpack_require__(850),__webpack_require__(612),__webpack_require__(742),__webpack_require__(916),__webpack_require__(291),__webpack_require__(448),e.trigger("init"))})()})(); \ No newline at end of file +(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{},(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(e.config.autorun===void 0||e.config.autorun!==!1)&&e.trigger(`load`)});function t(){e.VERSION=1,e.ASPECT_WRAPPER_CLASS=`iframely-responsive`,e.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,e.LOADER_CLASS=`iframely-loader`,e.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],e.CDN=e.CDN||e.DOMAINS[0],e.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,e.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,e.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],e.SUPPORTED_THEMES=[`auto`,`light`,`dark`],e.LAZY_IFRAME_SHOW_TIMEOUT=3e3,e.LAZY_IFRAME_FADE_TIMEOUT=200,e.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,e.RECOVER_HREFS_ON_CANCEL=!1,e.SHADOW=`iframely-shadow`,e.SUPPORT_IFRAME_LOADING_ATTR=!0}var n=e=>{window.requestAnimationFrame(e)},r={};function i(t,i,a){(r[t]||[]).forEach(t=>{i?n(()=>{t.apply(e,a)}):t.apply(e,a)}),t===`init`&&(r[t]=[])}function a(){e.on=(e,t)=>{(r[e]=r[e]||[]).push(t)},e.trigger=(e,...t)=>{i(e,!1,t)},e.triggerAsync=(e,...t)=>{i(e,!0,t)}}function o(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function s(e,t){let n;for(let r=0;r{let t=c(document,e);return t||=l(document,e),t},o((t,n)=>{if(n&&(n.method||n.type||n.context)){let r=e.findIframe({contentWindow:t.source,src:n.src||n.context,domains:n.domains!==`all`&&e.DOMAINS.concat(e.CDN)});if(r){let t=m(r);t&&n.url&&(t.url=n.url),e.trigger(`message`,t,n)}}})}function d(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){e.on(`init`,()=>{e.extendOptions(y()),te(),e.config.theme&&e.setTheme(e.config.theme),ne(e.DOMAINS.concat(e.CDN.replace(/^https?:\/\//,``)))}),e.load=function(...t){e.trigger(`load`,...t)},e.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),e.extendOptions=t=>{t&&Object.keys(t).forEach(n=>{let r=t[n]===0||t[n]===`0`||t[n]===!1||t[n]===`false`?!1:t[n]===1||t[n]===`1`||t[n]===!0||t[n]===`true`||t[n];e.config[n]!==!1&&(e.config[n]=r)})}}function f(t,n){let r=t.parentNode;if(!r||r.nodeName!==`DIV`||b(r)>2||n&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||b(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function p(t){let n=t.parentNode,r=document.createElement(`div`);r.className=e.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=e.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,t),{aspectWrapper:i,maxWidthWrapper:r}}function m(e){let t=f(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=S(r);e.url&&(n.url=e.url)}return n}function h(t,n){t&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=t.style,o=a[r];e.getElementComputedStyle(t,r)!=i&&!(t.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function g(t){e.config.nonce&&(t.nonce=e.config.nonce)}function te(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,g(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function _(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function v(t,n,r){let i=t;if(/^(https?:)?\/\//i.test(t)||(i=(n&&n.CDN||e.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=_(i,n)),r&&r.length){let t={},n=Object.keys(e.config);for(let i=0;i0)return t}}return{}}function ne(t){let n=document.querySelectorAll(`iframe[src*="`+(t||e.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{d({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},E(e)),w[t]=n),n}function E(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function re(){e.on(`init`,()=>{e.extendOptions({intersection:1})}),e.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},T(n).observe(e.iframe)}})}function D(e,t){d({method:`setTheme`,data:t},`*`,e.contentWindow)}function O(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{t&&e.SUPPORTED_THEMES.indexOf(t)>-1?n?n.tagName===`IFRAME`?D(n,t):O(n,t):(e.extendOptions({theme:t}),O(document,t),e.trigger(`set-theme`,t)):console.warn(`Using iframely.setTheme with not supported theme: "`+t+`". Supported themes are: `+e.SUPPORTED_THEMES.join(`, `))}}var A={};function ie(){e.on(`load`,t=>{if(!t&&e.config.import!==!1&&se()&&!e.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&ae(e)}}),e.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=A[e.uri];if(n)for(let r=0;r{e.trigger(`import-loaded`,t),t.widgets.forEach(n=>{e.trigger(`load`,n,t)}),j()},e.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,e.on(`import-widget-ready`,M),e.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function ae(t){let n=C(),r=[],i=[],a=null;function o(e,t){A[e]||(A[e]=[]),A[e].push(t)}function s(t){let n=t.getAttribute(`data-iframely-url`),s=n.match(e.ID_RE),c=s&&s[1],l=S(n,e.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let t=n.match(e.BASE_RE);l.CDN=t&&t[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?e.trigger(`load`,t):c?(t.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,t)):(u||=t.getAttribute(`href`),(a.key||a.api_key||e.config.api_key||e.config.key)&&u?(t.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,t)):e.trigger(`load`,t))}for(let e=0;e0||i.length>0?(a||={},a.touch=e.isTouch(),a.flash=!1,a.app=1,e.config.theme&&(a.theme=e.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=e.VERSION,n.src=v(`/api/import/v2`,a,e.SUPPORTED_QUERY_STRING),n.onerror=()=>{j()},document.head.appendChild(n),e.import=n):(j(),e.trigger(`load`))}function oe(t,n,r){let i=t.cancel,a=t.shadow,o=t.renderEvent,s=f(n,!0);if(i)e.cancelWidget(m(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=t.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:t.context,stylesIds:t.stylesIds,stylesDict:r.commonShadowStyles};e.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),e.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),N(i);c.removeChild(l),o&&setTimeout(()=>{M(c)},e.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function j(){delete e.import;let t=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function N(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=C();r.type=`text/javascript`;for(let e=0;e{if(t&&t.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),t.appendChild(r),e.trigger(`load`,r)}}),e.on(`load`,t=>{if(!t&&!e.import){let t=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&F(e)})}function F(t){if(!t.getAttribute(`data-iframely-url`)&&!t.getAttribute(`href`))return;let n,r=t.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=v(r,{v:e.VERSION,app:1,theme:e.config.theme});else if((e.config.api_key||e.config.key)&&e.CDN){if(!t.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,t);return}n=v(`/api/iframe`,{url:t.getAttribute(`href`),v:e.VERSION,app:1,theme:e.config.theme},e.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)t.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),t.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,t.getAttribute(`data-img`));let i=t.hasAttribute(`data-lazy`)||t.hasAttribute(`data-img`)||/&lazy=1/.test(n)||e.config.lazy,a=t.textContent;a&&a!==``&&(r.textContent=a);let o=f(t,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=p(t),t.parentNode.removeChild(t);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),e.trigger(`load`,r)):(r.setAttribute(`src`,n),e.trigger(`iframe-ready`,r))}}function I(){e.on(`load`,t=>{if(t&&t.nodeName===`IFRAME`&&t.hasAttribute(`data-iframely-url`)&&t.hasAttribute(`data-img`)&&!t.getAttribute(`src`)){let n=t.getAttribute(`data-img`);t.removeAttribute(`data-img`),t.setAttribute(`data-img-created`,``);let r=m(t),i=t.getAttribute(`data-iframely-url`);r&&(L(r,i,n),i=_(i,{img:1}),t.setAttribute(`data-iframely-url`,i),new G(r)),e.trigger(`load`,t)}}),e.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(B(e),n=U(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=U(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=U(e),n?.registerLoadingTimeout())})}function L(t,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let t=S(n),r={};for(let e in t)e.indexOf(`_`)===0&&(r[e]=t[e]);if(t.media&&(r.media=t.media),n.match(/\/api\/iframe/))i=v(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:t.url,api_key:t.api_key,key:t.key},r));else if(n.match(e.ID_RE))i=v(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);h(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,e.LOADER_CLASS),a.appendChild(o);let s=e.getElementComputedStyle(t.aspectWrapper,`padding-top`),c=e.getElementComputedStyle(t.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let e=document.createElement(`div`);h(e,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),e.appendChild(a),t.aspectWrapper.appendChild(e)}else t.aspectWrapper.appendChild(a)}function R(e,t){let n=0;for(let r=0;r1&&R(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var V=[];function H(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),V.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{B(this.widget)},e.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),W(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},e.LAZY_IFRAME_SHOW_TIMEOUT)}};function K(){e.on(`load`,t=>{if(!t){let t=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&q(e)})}function q(t){let n=m(t),r=t.getAttribute(`data-iframely-url`),i=t.hasAttribute(`data-img-created`)||t.hasAttribute(`data-img`),a=!i&&e.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let t={v:e.VERSION,app:1,theme:e.config.theme};!a&&e.config.intersection&&(t.lazy=1),r=v(r,t)}a&&t.setAttribute(`loading`,`lazy`),i&&e.SUPPORT_IFRAME_LOADING_ATTR&&t.setAttribute(`loading`,`edge`),t.setAttribute(`src`,r||``),t.removeAttribute(`data-iframely-url`),e.trigger(`iframe-ready`,t)}function ce(){e.on(`message`,(t,n)=>{n.method===`cancelWidget`&&e.cancelWidget(t)}),e.cancelWidget=t=>{if(!t){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=t.maxWidthWrapper&&t.maxWidthWrapper.parentNode,i=t.maxWidthWrapper;if(e.config&&e.config.parent){let a=n(t.maxWidthWrapper,String(e.config.parent));a&&(r=a.parentNode,i=a)}if(t.url){let n=t.iframe&&t.iframe.textContent;e.triggerAsync(`cancel`,t.url,r,n,i.nextSibling)}r.removeChild(i)}}var le={border:``,"border-radius":``,"box-shadow":``,overflow:``},ue={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function de(){e.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),J(e,n)):t.method===`setIframelyEmbedData`&&J(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),pe(e,r)}})}function J(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,h(e.aspectWrapper,t)):h(e.iframe,t):!t&&e&&e.iframe&&(h(e.aspectWrapper,le),h(e.iframe,ue))}function fe(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function pe(t,n){if(n&&Object.keys(n).length>0&&t){let r=fe(t),i=window.getComputedStyle(t.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),h(t.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&t.iframe&&t.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&h(t.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(t.iframe).getPropertyValue(`height`);i&&i!==s&&e.triggerAsync(`heightChanged`,t.iframe,i,s)}}function me(){e.on(`message`,(t,n)=>{(n.method===`open-href`||n.method===`click`)&&e.trigger(n.method,n.href)}),e.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},e.on(`open-href`,t=>{e.triggerAsync(`click`,t),e.openHref(t)})}function he(){e.on(`message`,(t,n)=>{n.method===`setIframelyEmbedOptions`&&e.trigger(`options`,t,n.data)})}function ge(){e.widgets=e.widgets||{},e.widgets.load=e.load,e.events||(e.events={},e.events.on=e.on,e.events.trigger=e.trigger),e.on(`cancel`,(t,n,r,i)=>{if(e.RECOVER_HREFS_ON_CANCEL&&!r&&(r=t),t&&n&&r&&r!==``){let e=document.createElement(`a`);e.setAttribute(`href`,t),e.setAttribute(`target`,`_blank`),e.setAttribute(`rel`,`noopener`),e.textContent=r,i?n.insertBefore(e,i):n.appendChild(e)}})}var Y=/^_./,X=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function _e(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let n=[],r=Object.keys(e),i=0;if(r.forEach(r=>{let a={},o,s=e[r];s.key=r;let c=!1,l=s.values?Object.keys(s.values):void 0,u,d;if(l&&l.length===1&&(c=!0,u=l[0],d=s.values[u]),a.label=X(d||s.label,t),a.key=s.key,c||typeof s.value==`boolean`)c?a.checked=u===s.value||!u&&!s.value:a.checked=s.value,i++,n.push({type:`checkbox`,context:a,order:+!Y.test(r),getQuery:e=>{let t;t=c?e?u:``:e;let n={};return c?t===``||(n[s.key]=t):n[s.key]=e,n}});else if((typeof s.value==`number`||typeof s.value==`string`)&&!s.values){let e=s.range&&typeof s.range.min==`number`&&typeof s.range.max==`number`,i=typeof s.value==`number`;a.value=s.value,o=e=>{let t={};return e===``||(t[s.key]=e),t},e?(a.min=s.range.min,a.max=s.range.max,n.push({type:`range`,context:a,order:9,getQuery:o})):(a.placeholder=X(s.placeholder||``,t),a.inputType=i?`number`:`text`,n.push({type:`text`,context:a,order:/start/i.test(r)?7:8,getQuery:o}))}else if(s.values)if(a.value=s.value+``,o=e=>{let t={};return e===``||(t[s.key]=e),t},Object.keys(s.values).length<=3){s.label?a.label=X(s.label,t):a.label=!1;let e=0,i=!1,c=Object.values(s.values);for(;e8,e++;a.inline=!i,a.items=[],Object.keys(s.values).forEach((e,n)=>{a.items.push({id:a.key+`-`+n,value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`radio`,context:a,order:i?-3:/theme/.test(r)?-1:-2,getQuery:o})}else a.items=[],Object.keys(s.values).forEach(e=>{a.items.push({value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`select`,context:a,order:5,getQuery:o})}),n.sort((e,t)=>e.order-t.order),n.forEach(e=>{delete e.order}),i>0){let e=[],t;return n.forEach((r,a)=>{if(r.type===`checkbox`){let o=i>2&&a>0&&!Y.test(r.context.key)&&n[a-1].type===`checkbox`&&Y.test(n[a-1].context.key);(!t||o)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return n}var Z={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(t,n)=>{let r=t[0];e.addEventListener(r,`click`,()=>{r.select()}),e.addEventListener(r,`blur`,n),e.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},Q={};function ve(t){let n=t.options,r=t.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,t);return}if(!n){r.innerHTML=``;return}let i=_e(n,t.translator),a=t.id,o=t.renderer,s=Q[a]=Q[a]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(s[e]=n[e].value)});function c(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=Z[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(i),e}function l(){let t=c();Object.keys(s).forEach(e=>{(s[e]===t[e]||t[e]===void 0)&&delete t[e]}),e.trigger(`options-changed`,a,r,t)}let u=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=u(e.context.elements)),t+=o(e.type,e.context||{})}),t};r.innerHTML=u(i);let d=t=>{t.forEach(t=>{if(t.context&&t.context.elements)d(t.context.elements);else{let n=Z[t.type];if(t.context){let i=r.querySelectorAll(`[name="`+t.context.key+`"]`);t.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,l):i.forEach(t=>{e.addEventListener(t,`change`,l)}):console.warn(`No inputs found for option`,t.context.key)}}})};d(i)}var ye={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},$=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>ye[e]),be={checkbox:e=>` +
+ + +
`,group:e=>` +
+
${e.elementsHtml??``}
+
`,radio:e=>` +
+ ${e.label?``:``} +
+ ${(e.items||[]).map(t=>` +
+ + +
`).join(``)} +
+
`,range:e=>` +
+ +
+ +
+
`,select:e=>` +
+ +
+ +
+
`,text:e=>` +
+ +
+ +
+
`},xe=(e,t)=>be[e](t);function Se(){e.buildOptionsForm=(e,t,n,r)=>{ve({id:e,formContainer:t,options:n,renderer:xe,translator:r})}}e._loaded||(e._loaded=!0,t(),a(),ee(),u(),re(),k(),ie(),P(),I(),K(),ce(),de(),me(),he(),ge(),Se(),e.trigger(`init`))})(); \ No newline at end of file diff --git a/dist/embed.js b/dist/embed.js index 75718c6..f80ce39 100644 --- a/dist/embed.js +++ b/dist/embed.js @@ -1,255 +1,1069 @@ -/* - * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -/******/ (() => { // webpackBootstrap -/******/ var __webpack_modules__ = ({ +(function() { -/***/ "./ahref.js" -/*!******************!*\ - !*** ./ahref.js ***! - \******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('load', function(container, href) {\n if (container && container.nodeName && typeof href === 'string') {\n var a = document.createElement('a');\n a.setAttribute('href', href);\n container.appendChild(a);\n iframely.trigger('load', a);\n }\n});\n\niframely.on('load', function(el) {\n\n if (!el && !iframely.import) { \n\n var elements = document.querySelectorAll('a[data-iframely-url]:not([data-import-uri])');\n for(var i = 0; i < elements.length; i++) {\n iframely.trigger('load', elements[i]);\n }\n }\n \n});\n\niframely.on('load', function(el) {\n\n if (el && el.nodeName === 'A' && (el.getAttribute('data-iframely-url') || el.getAttribute('href')) && !el.hasAttribute('data-import-uri')) {\n unfurl(el);\n }\n \n});\n\nfunction unfurl(el) {\n if (!el.getAttribute('data-iframely-url') && !el.getAttribute('href')) {\n return; // isn't valid\n }\n var src;\n\n var dataIframelyUrl = el.getAttribute('data-iframely-url');\n if (dataIframelyUrl && /^((?:https?:)?\\/\\/[^/]+)\\/\\w+/i.test(dataIframelyUrl)) {\n src = utils.getEndpoint(dataIframelyUrl, {\n v: iframely.VERSION,\n app: 1,\n theme: iframely.config.theme\n });\n } else if ((iframely.config.api_key || iframely.config.key) && iframely.CDN) {\n\n if (!el.getAttribute('href')) {\n console.warn('Iframely cannot build embeds: \"href\" attribute missing in', el);\n return;\n }\n\n src = utils.getEndpoint('/api/iframe', {\n url: el.getAttribute('href'),\n v: iframely.VERSION,\n app: 1,\n theme: iframely.config.theme\n }, iframely.SUPPORTED_QUERY_STRING);\n } else {\n console.warn('Iframely cannot build embeds: api key is required as query-string of embed.js');\n }\n\n if (!src) {\n el.removeAttribute('data-iframely-url'); \n } else {\n\n var iframe = document.createElement('iframe');\n\n iframe.setAttribute('allowfullscreen', '');\n iframe.setAttribute('allow', 'autoplay *; encrypted-media *; ch-prefers-color-scheme *');\n\n if (el.hasAttribute('data-img')) {\n iframe.setAttribute('data-img', el.getAttribute('data-img'));\n }\n\n var isLazy = el.hasAttribute('data-lazy') || el.hasAttribute('data-img') || /&lazy=1/.test(src) || iframely.config.lazy;\n\n // support restoring failed links by its text\n var text = el.textContent || el.innerText;\n \n if (text && text !== '') {\n iframe.textContent = text;\n } \n\n var wrapper = utils.getIframeWrapper(el, true);\n \n if (wrapper) {\n\n // Delete all in aspect wrapper.\n while (wrapper.aspectWrapper.lastChild) {\n wrapper.aspectWrapper.removeChild(wrapper.aspectWrapper.lastChild);\n }\n\n } else {\n wrapper = utils.addDefaultWrappers(el);\n\n var parentNode = el.parentNode;\n parentNode.removeChild(el);\n }\n\n wrapper.aspectWrapper.appendChild(iframe);\n\n if (isLazy) {\n \n // send to lazy iframe flow\n iframe.setAttribute('data-iframely-url', src);\n iframely.trigger('load', iframe);\n\n } else {\n\n iframe.setAttribute('src', src);\n iframely.trigger('iframe-ready', iframe);\t\t\t\n }\n\n\n }\n\n\n}\n\n//# sourceURL=webpack:///./ahref.js?\n}"); +//#region src/iframely.ts + var iframely = window.iframely = window.iframely || {}; + iframely.config = iframely.config || {}; -/***/ }, +//#endregion +//#region src/dom-ready.ts + var DOMReady = (f) => { + if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(f, 0); + document.addEventListener("DOMContentLoaded", f); + }; + DOMReady(() => { + if (typeof iframely.config.autorun === "undefined" || iframely.config.autorun !== false) iframely.trigger("load"); + }); -/***/ "./const.js" -/*!******************!*\ - !*** ./const.js ***! - \******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { +//#endregion +//#region src/const.ts + function boot$14() { + iframely.VERSION = 1; + iframely.ASPECT_WRAPPER_CLASS = "iframely-responsive"; + iframely.MAXWIDTH_WRAPPER_CLASS = "iframely-embed"; + iframely.LOADER_CLASS = "iframely-loader"; + iframely.DOMAINS = [ + "cdn.iframe.ly", + "iframe.ly", + "if-cdn.com", + "iframely.net" + ]; + iframely.CDN = iframely.CDN || iframely.DOMAINS[0]; + iframely.BASE_RE = /^(?:https?:)?\/\/[^/]+/i; + iframely.ID_RE = /^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/; + iframely.SCRIPT_RE = /^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i; + iframely.CDN_RE = /^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i; + iframely.SUPPORTED_QUERY_STRING = [ + "api_key", + "key", + "iframe", + "html5", + "playerjs", + "align", + "language", + "media", + "maxwidth", + "maxheight", + "lazy", + "import", + "parent", + "shadow", + "click_to_play", + "autoplay", + "mute", + "card", + "consent", + "theme", + /^_.+/ + ]; + iframely.SUPPORTED_THEMES = [ + "auto", + "light", + "dark" + ]; + iframely.LAZY_IFRAME_SHOW_TIMEOUT = 3e3; + iframely.LAZY_IFRAME_FADE_TIMEOUT = 200; + iframely.CLEAR_WRAPPER_STYLES_TIMEOUT = 3e3; + iframely.RECOVER_HREFS_ON_CANCEL = false; + iframely.SHADOW = "iframely-shadow"; + iframely.SUPPORT_IFRAME_LOADING_ATTR = true; + } -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.VERSION = 1;\n\niframely.ASPECT_WRAPPER_CLASS = 'iframely-responsive';\niframely.MAXWIDTH_WRAPPER_CLASS = 'iframely-embed';\niframely.LOADER_CLASS = 'iframely-loader';\n\niframely.DOMAINS = ['cdn.iframe.ly', 'iframe.ly', 'if-cdn.com', 'iframely.net'];\niframely.CDN = iframely.CDN || iframely.DOMAINS[0]; // default domain, user or script src can change CDN\n\niframely.BASE_RE = /^(?:https?:)?\\/\\/[^/]+/i;\niframely.ID_RE = /^(?:https?:)?\\/\\/[^/]+\\/(\\w+-?\\w+)(?:\\?.*)?$/;\niframely.SCRIPT_RE = /^(?:https?:|file:\\/)?\\/\\/[^/]+(?:.+)?\\/(?:embed|iframely)\\.js(?:[^/]+)?$/i;\niframely.CDN_RE = /^(?:https?:)?\\/\\/([^/]+)\\/(?:embed|iframely)\\.js(?:[^/]+)?$/i;\n\niframely.SUPPORTED_QUERY_STRING = ['api_key', 'key', 'iframe', 'html5', 'playerjs', 'align', 'language', 'media', 'maxwidth', 'maxheight', 'lazy', 'import', 'parent', 'shadow', 'click_to_play', 'autoplay', 'mute', 'card', 'consent', 'theme', /^_.+/];\n\niframely.SUPPORTED_THEMES = ['auto', 'light', 'dark'];\n\niframely.LAZY_IFRAME_SHOW_TIMEOUT = 3000;\niframely.LAZY_IFRAME_FADE_TIMEOUT = 200;\niframely.CLEAR_WRAPPER_STYLES_TIMEOUT = 3000;\n\niframely.RECOVER_HREFS_ON_CANCEL = false;\n\niframely.SHADOW = 'iframely-shadow';\n\n//# sourceURL=webpack:///./const.js?\n}"); +//#endregion +//#region src/events.ts + var nextTick = (fn) => { + window.requestAnimationFrame(fn); + }; + var callbacksStack = {}; + function trigger(event, async, args) { + (callbacksStack[event] || []).forEach((cb) => { + if (async) nextTick(() => { + cb.apply(iframely, args); + }); + else cb.apply(iframely, args); + }); + if (event === "init") callbacksStack[event] = []; + } + function boot$13() { + iframely.on = (event, cb) => { + (callbacksStack[event] = callbacksStack[event] || []).push(cb); + }; + iframely.trigger = (event, ...args) => { + trigger(event, false, args); + }; + iframely.triggerAsync = (event, ...args) => { + trigger(event, true, args); + }; + } -/***/ }, +//#endregion +//#region src/messaging.ts + function receiveMessage(callback) { + window.addEventListener("message", (e) => { + let message; + try { + if (typeof e.data === "string") message = JSON.parse(e.data); + else if (typeof e.data === "object") message = e.data; + } catch { + if (typeof e.data === "string") { + const m = e.data.match(/heightxPYMx(\d+)/); + if (m) message = { + method: "resize", + height: parseInt(m[1]) + 1, + domains: "all" + }; + } + } + callback(e, message); + }, false); + } + function findIframeByContentWindow(iframes, contentWindow) { + let foundIframe; + for (let i = 0; i < iframes.length && !foundIframe; i++) { + const iframe = iframes[i]; + if (iframe.contentWindow === contentWindow) foundIframe = iframe; + } + return foundIframe; + } + function findIframeInElement(element, options) { + let foundIframe, iframes; + if (options.src) { + iframes = element.querySelectorAll("iframe[src*=\"" + options.src.replace(/^https?:/, "") + "\"]"); + foundIframe = findIframeByContentWindow(iframes, options.contentWindow); + } + if (!foundIframe) { + iframes = options.domains ? element.querySelectorAll("iframe[src*=\"" + (options.domains || iframely.DOMAINS).join("\"], iframe[src*=\"") + "\"]") : element.querySelectorAll("iframe"); + foundIframe = findIframeByContentWindow(iframes, options.contentWindow); + } + return foundIframe; + } + function findIframeInShadowRoots(element, options) { + let foundIframe; + const className = "." + (iframely.config.shadow || iframely.SHADOW); + const shadowRoots = element.querySelectorAll(className); + for (let i = 0; i < shadowRoots.length && !foundIframe; i++) { + const shadowRoot = shadowRoots[i].shadowRoot; + if (shadowRoot) { + foundIframe = findIframeInElement(shadowRoot, options); + if (!foundIframe) foundIframe = findIframeInShadowRoots(shadowRoot, options); + } + } + return foundIframe; + } + function boot$12() { + if (!iframely.findIframe) iframely.findIframe = (options) => { + let foundIframe = findIframeInElement(document, options); + if (!foundIframe) foundIframe = findIframeInShadowRoots(document, options); + return foundIframe; + }; + receiveMessage((e, message) => { + if (message && (message.method || message.type || message.context)) { + const foundIframe = iframely.findIframe({ + contentWindow: e.source, + src: message.src || message.context, + domains: message.domains !== "all" && iframely.DOMAINS.concat(iframely.CDN) + }); + if (foundIframe) { + const widget = getWidget(foundIframe); + if (widget && message.url) widget.url = message.url; + iframely.trigger("message", widget, message); + } + } + }); + } + function postMessage(message, target_url, target) { + if (typeof message === "object") message.context = document.location.href; + const data = JSON.stringify(message); + target_url = target_url || "*"; + target = target || window.parent; + target.postMessage(data, target_url.replace(/([^:]+:\/\/[^/]+).*/, "$1")); + } -/***/ "./deprecated.js" -/*!***********************!*\ - !*** ./deprecated.js ***! - \***********************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { +//#endregion +//#region src/utils.ts + function boot$11() { + iframely.on("init", () => { + iframely.extendOptions(parseQueryStringFromScriptSrc()); + defineDefaultStyles(); + if (iframely.config.theme) iframely.setTheme(iframely.config.theme); + requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, ""))); + }); + iframely.load = function(...args) { + iframely.trigger("load", ...args); + }; + iframely.getElementComputedStyle = (el, style) => { + return window.getComputedStyle(el).getPropertyValue(style); + }; + iframely.extendOptions = (options) => { + if (!options) return; + Object.keys(options).forEach((key) => { + const new_value = options[key] === 0 || options[key] === "0" || options[key] === false || options[key] === "false" ? false : options[key] === 1 || options[key] === "1" || options[key] === true || options[key] === "true" ? true : options[key]; + if (iframely.config[key] !== false) iframely.config[key] = new_value; + }); + }; + } + function getIframeWrapper(iframe, checkClass) { + const aspectWrapper = iframe.parentNode; + if (!aspectWrapper || aspectWrapper.nodeName !== "DIV" || nonTextChildCount$1(aspectWrapper) > 2 || checkClass && aspectWrapper.getAttribute("class") !== iframely.ASPECT_WRAPPER_CLASS || !checkClass && aspectWrapper.style.position !== "relative" && aspectWrapper.getAttribute("class") !== iframely.ASPECT_WRAPPER_CLASS) return; + const maxWidthWrapper = aspectWrapper.parentNode; + if (!maxWidthWrapper || maxWidthWrapper.nodeName !== "DIV" || nonTextChildCount$1(maxWidthWrapper) > 1 || checkClass && maxWidthWrapper.getAttribute("class") && maxWidthWrapper.getAttribute("class").split(" ").indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) === -1 || !checkClass && maxWidthWrapper.getAttribute("class") && !maxWidthWrapper.getAttribute("class").match(/iframely/i)) return; + return { + aspectWrapper, + maxWidthWrapper + }; + } + function addDefaultWrappers(el) { + const parentNode = el.parentNode; + const maxWidthWrapper = document.createElement("div"); + maxWidthWrapper.className = iframely.MAXWIDTH_WRAPPER_CLASS; + const aspectWrapper = document.createElement("div"); + aspectWrapper.className = iframely.ASPECT_WRAPPER_CLASS; + maxWidthWrapper.appendChild(aspectWrapper); + parentNode.insertBefore(maxWidthWrapper, el); + return { + aspectWrapper, + maxWidthWrapper + }; + } + function getWidget(iframe) { + const wrapper = getIframeWrapper(iframe); + if (!wrapper) return; + const widget = { + iframe, + aspectWrapper: wrapper.aspectWrapper, + maxWidthWrapper: wrapper.maxWidthWrapper + }; + const src = iframe.getAttribute("src"); + if (iframe.nodeName === "A" && iframe.hasAttribute("href")) widget.url = iframe.getAttribute("href"); + else if (src && /url=/.test(src)) { + const qs = parseQueryString(src); + if (qs.url) widget.url = qs.url; + } + return widget; + } + function setStyles(el, styles) { + if (el) Object.keys(styles).forEach((key) => { + let value = styles[key]; + if (typeof value === "number" || typeof value === "string" && /^(\d+)?\.?(\d+)$/.test(value)) value = value + "px"; + const elStyle = el.style; + const currentValue = elStyle[key]; + if (iframely.getElementComputedStyle(el, key) != value && !(el.className == "iframely-responsive" && key === "paddingBottom" && !currentValue && /^56\.2\d+%$/.test(value)) && !(key === "max-width" && value === "keep")) elStyle[key] = value || ""; + }); + } + function applyNonce(element) { + if (iframely.config.nonce) element.nonce = iframely.config.nonce; + } + function defineDefaultStyles() { + const iframelyStylesId = "iframely-styles"; + let styles = document.getElementById(iframelyStylesId); + if (!styles) { + const iframelyStyles = ".iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}"; + styles = document.createElement("style"); + styles.id = iframelyStylesId; + applyNonce(styles); + styles.innerHTML = iframelyStyles; + document.getElementsByTagName("head")[0].appendChild(styles); + } + } + function addQueryString(href, options) { + let query_string = ""; + Object.keys(options).forEach((key) => { + let value = options[key]; + if (Array.isArray(value)) { + const values = value.map((uri) => key + "=" + encodeURIComponent(uri)); + query_string += "&" + values.join("&"); + } else if (typeof value !== "undefined" && href.indexOf(key + "=") === -1) { + if (typeof value === "boolean" && key.charAt(0) !== "_") value = value ? 1 : 0; + query_string += "&" + key + "=" + encodeURIComponent(value); + } + }); + return href + (query_string !== "" ? (href.indexOf("?") > -1 ? "&" : "?") + query_string.replace(/^&/, "") : ""); + } + function getEndpoint(src, options, config_params) { + let endpoint = src; + if (!/^(https?:)?\/\//i.test(src)) { + endpoint = (options && options.CDN || iframely.CDN) + endpoint; + if (options) delete options.CDN; + } + if (!/^(?:https?:)?\/\//i.test(endpoint)) endpoint = "//" + endpoint; + if (options) endpoint = addQueryString(endpoint, options); + if (config_params && config_params.length) { + const more_options = {}; + const iframely_config_keys = Object.keys(iframely.config); + for (let i = 0; i < iframely_config_keys.length; i++) { + const key = iframely_config_keys[i]; + if (containsString(config_params, key)) more_options[key] = iframely.config[key]; + } + endpoint = addQueryString(endpoint, more_options); + } + if (/^(https?:)?\/\//i.test(endpoint) && !endpoint.match(/^(https?:)?\/\//i)[1] && document.location.protocol !== "http:" && document.location.protocol !== "https:") endpoint = "https:" + endpoint; + return endpoint; + } + function parseQueryStringFromScriptSrc() { + const scripts = document.querySelectorAll("script[src*=\"embed.js\"], script[src*=\"iframely.js\"]"); + for (let i = 0; i < scripts.length; i++) { + const src = scripts[i].getAttribute("src").replace(/&/gi, "&"); + if (iframely.SCRIPT_RE.test(src)) { + const options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat("cdn", "cancel", "nonce")); + const m2 = src.match(iframely.CDN_RE); + if (m2 || options.cdn) iframely.CDN = options.cdn || m2[1]; + if (options.cancel) { + if (options.cancel === "0" || options.cancel === "false") iframely.RECOVER_HREFS_ON_CANCEL = true; + delete options.cancel; + } + if (Object.keys(options).length > 0) return options; + } + } + return {}; + } + function requestSizeOfExistingIframes(domains) { + const iframes = document.querySelectorAll("iframe[src*=\"" + (domains || iframely.DOMAINS).join("\"], iframe[src*=\"") + "\"]"); + for (let i = 0; i < iframes.length; i++) { + const iframe = iframes[i]; + const src = iframe.src; + if (src.match(/^(https?:)?\/\/[^/]+\/api\/iframe\?.+/) || src.match(/^(https?:)?\/\/[^/]+\/\w+(\?.*)?$/)) postMessage({ method: "getSize" }, "*", iframe.contentWindow); + } + } + function nonTextChildCount$1(element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.TEXT_NODE) { + if ((el.textContent || "").replace(/\s|\n/g, "")) count++; + } else if (el.nodeType === Node.ELEMENT_NODE) count++; + } + return count; + } + function containsString(list, findValue) { + let value, i = 0; + while (i < list.length) { + value = list[i]; + if (value == findValue) return true; + if (value instanceof RegExp && value.test(findValue)) return true; + i++; + } + return false; + } + function parseQueryString(url, allowed_query_string) { + const query = url.match(/\?(.+)/i); + if (query) { + const data = query[1].split("&"); + const result = {}; + for (let i = 0; i < data.length; i++) { + const item = data[i].split("="); + if (!allowed_query_string || containsString(allowed_query_string, item[0])) result[item[0]] = decodeURIComponent(item[1]); + } + return result; + } else return {}; + } + function createScript() { + const script = document.createElement("script"); + applyNonce(script); + return script; + } -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\n// deprecated. Helper function only, for the reverse compatibility.\niframely.widgets = iframely.widgets || {};\niframely.widgets.load = iframely.load;\n\nif (!iframely.events) {\n iframely.events = {};\n iframely.events.on = iframely.on;\n iframely.events.trigger = iframely.trigger;\n}\n\niframely.on('cancel', function(url, parentNode, text, nextSibling) {\n\n if (iframely.RECOVER_HREFS_ON_CANCEL && !text) {\n text = url;\n }\n\n if (url && parentNode && text && text !== '') {\n var a = document.createElement('a');\n a.setAttribute('href', url);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.textContent = text;\n if (nextSibling) {\n parentNode.insertBefore(a, nextSibling);\n } else {\n parentNode.appendChild(a);\n }\n }\n});\n\n//# sourceURL=webpack:///./deprecated.js?\n}"); +//#endregion +//#region src/intersection.ts + var observers = {}; + function getObserver(options) { + const optionsKey = JSON.stringify(options); + let observer = observers[optionsKey]; + if (!observer) { + observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + postMessage({ + method: "intersection", + entry: { isIntersecting: entry.isIntersecting }, + options + }, "*", entry.target.contentWindow); + }); + }, getObserverOptions(options)); + observers[optionsKey] = observer; + } + return observer; + } + function getObserverOptions(options) { + const result = {}; + if (options && options.threshold) result.threshold = options.threshold; + if (options && options.margin) result.rootMargin = options.margin + "px " + options.margin + "px " + options.margin + "px " + options.margin + "px"; + return result; + } + function boot$10() { + iframely.on("init", () => { + iframely.extendOptions({ intersection: 1 }); + }); + iframely.on("message", (widget, message) => { + if (message.method === "send-intersections" && widget.iframe) { + let options = message.options; + if (!options) options = { margin: 1e3 }; + getObserver(options).observe(widget.iframe); + } + }); + } -/***/ }, +//#endregion +//#region src/theme.ts + function setThemeInIframe(iframe, theme) { + postMessage({ + method: "setTheme", + data: theme + }, "*", iframe.contentWindow); + } + function setThemeInAllIframes(parent, theme) { + const iframes = parent.getElementsByTagName("iframe"); + for (let i = 0; i < iframes.length; i++) setThemeInIframe(iframes[i], theme); + } + function boot$9() { + iframely.setTheme = (theme, container) => { + if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) if (container) if (container.tagName === "IFRAME") setThemeInIframe(container, theme); + else setThemeInAllIframes(container, theme); + else { + iframely.extendOptions({ theme }); + setThemeInAllIframes(document, theme); + iframely.trigger("set-theme", theme); + } + else console.warn("Using iframely.setTheme with not supported theme: \"" + theme + "\". Supported themes are: " + iframely.SUPPORTED_THEMES.join(", ")); + }; + } -/***/ "./dom-ready.js" -/*!**********************!*\ - !*** ./dom-ready.js ***! - \**********************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { +//#endregion +//#region src/import.ts + var widgetsCache = {}; + function boot$8() { + iframely.on("load", (el) => { + if (!el && iframely.config.import !== false && isImportAble() && !iframely.import) { + const elements = document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"); + if (elements.length > 1) makeImportAPICall(elements); + } + }); + iframely.on("load", (widget, importOptions) => { + if (widget && !(widget instanceof Element) && widget.uri && (widget.html || widget.cancel)) { + const els = widgetsCache[widget.uri]; + if (els) for (let i = 0; i < els.length; i++) loadImportWidget(widget, els[i], importOptions); + delete widgetsCache[widget.uri]; + } + }); + iframely.buildImportWidgets = (importOptions) => { + iframely.trigger("import-loaded", importOptions); + importOptions.widgets.forEach((widget) => { + iframely.trigger("load", widget, importOptions); + }); + importReady(); + }; + iframely.isTouch = () => { + return "ontouchstart" in window || navigator.maxTouchPoints > 0; + }; + iframely.on("import-widget-ready", clearWrapperStylesAndClass); + if (!iframely.addEventListener) iframely.addEventListener = (elem, type, eventHandle) => { + if (!elem) return; + elem.addEventListener(type, eventHandle, false); + }; + } + function makeImportAPICall(elements) { + const script = createScript(); + const uris = []; + const ids = []; + let import_options = null; + function pushElement(uri, el) { + if (!widgetsCache[uri]) widgetsCache[uri] = []; + widgetsCache[uri].push(el); + } + function queueElement(el) { + const src = el.getAttribute("data-iframely-url"); + const mId = src.match(iframely.ID_RE); + const id = mId && mId[1]; + const options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat("url")); + let url = options.url; + delete options.url; + let skipImport = options.import === "0" || options.import === "false" || options.playerjs === "1" || options.playerjs === "true"; + if (!skipImport) { + const mBase = src.match(iframely.BASE_RE); + options.CDN = mBase && mBase[0]; + if (!import_options) import_options = options; + else if (JSON.stringify(options, Object.keys(options).sort()) !== JSON.stringify(import_options, Object.keys(import_options).sort())) skipImport = true; + } + if (skipImport) iframely.trigger("load", el); + else if (id) { + el.setAttribute("data-import-uri", id); + if (ids.indexOf(id) === -1) ids.push(id); + pushElement(id, el); + } else { + if (!url) url = el.getAttribute("href"); + if ((import_options.key || import_options.api_key || iframely.config.api_key || iframely.config.key) && url) { + el.setAttribute("data-import-uri", url); + if (uris.indexOf(url) === -1) uris.push(url); + pushElement(url, el); + } else iframely.trigger("load", el); + } + } + for (let i = 0; i < elements.length; i++) { + const el = elements[i]; + if (!el.getAttribute("data-import-uri") && el.hasAttribute("data-iframely-url")) queueElement(el); + } + if (uris.length > 0 || ids.length > 0) { + import_options = import_options || {}; + import_options.touch = iframely.isTouch(); + import_options.flash = false; + import_options.app = 1; + if (iframely.config.theme) import_options.theme = iframely.config.theme; + if (uris.length > 0) import_options.uri = uris; + if (ids.length > 0) import_options.ids = ids.join("&"); + import_options.v = iframely.VERSION; + script.src = getEndpoint("/api/import/v2", import_options, iframely.SUPPORTED_QUERY_STRING); + script.onerror = () => { + importReady(); + }; + document.head.appendChild(script); + iframely.import = script; + } else { + importReady(); + iframely.trigger("load"); + } + } + function loadImportWidget(widgetOptions, el, importOptions) { + const needCancelWidget = widgetOptions.cancel; + const shadow = widgetOptions.shadow; + const hasRenderedEvent = widgetOptions.renderEvent; + const wrapper = getIframeWrapper(el, true); + if (needCancelWidget) iframely.cancelWidget(getWidget(el) || { + maxWidthWrapper: el, + iframe: el, + url: el.getAttribute("href") + }); + else { + const widget = document.createElement("div"); + widget.innerHTML = widgetOptions.html; + let parent, replacedEl; + if (wrapper && !hasRenderedEvent) { + parent = wrapper.aspectWrapper.parentNode; + replacedEl = wrapper.aspectWrapper; + wrapper.maxWidthWrapper.removeAttribute("style"); + } else { + parent = el.parentNode; + replacedEl = el; + } + if (shadow) { + const shadowContainer = document.createElement("div"); + const shadowRoot = shadowContainer.attachShadow({ mode: "open" }); + shadowRoot.appendChild(widget); + const shadowWidgetOptions = { + shadowRoot, + shadowContainer, + container: parent, + context: widgetOptions.context, + stylesIds: widgetOptions.stylesIds, + stylesDict: importOptions.commonShadowStyles + }; + iframely.trigger("import-shadow-widget-before-render", shadowWidgetOptions); + parent.insertBefore(shadowContainer, replacedEl); + iframely.trigger("import-shadow-widget-after-render", shadowWidgetOptions); + } else { + parent.insertBefore(widget, replacedEl); + exec_body_scripts(widget); + } + parent.removeChild(replacedEl); + if (hasRenderedEvent) setTimeout(() => { + clearWrapperStylesAndClass(parent); + }, iframely.CLEAR_WRAPPER_STYLES_TIMEOUT); + } + } + function importReady() { + delete iframely.import; + const failed_elements = document.querySelectorAll("a[data-iframely-url][data-import-uri]"); + for (let i = 0; i < failed_elements.length; i++) { + failed_elements[i].removeAttribute("data-import-uri"); + iframely.trigger("load", failed_elements[i]); + } + } + function isImportAble() { + return !!(document.location && (iframely.debug || document.location.protocol === "http:" || document.location.protocol === "https:") && !iframely.config.playerjs && !iframely.config.lazy); + } + function clearWrapperStylesAndClass(el) { + let aspectWrapper = el; + let parents = 0; + while (aspectWrapper && (!aspectWrapper.getAttribute("class") || aspectWrapper.getAttribute("class").split(" ").indexOf(iframely.ASPECT_WRAPPER_CLASS) === -1)) { + aspectWrapper = aspectWrapper.parentNode; + parents++; + if (parents > 4) aspectWrapper = null; + } + const maxWidthWrapper = aspectWrapper && aspectWrapper.parentNode; + if (maxWidthWrapper && maxWidthWrapper.getAttribute("class") && maxWidthWrapper.getAttribute("class").split(" ").indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) > -1) { + aspectWrapper.removeAttribute("style"); + aspectWrapper.removeAttribute("class"); + maxWidthWrapper.removeAttribute("style"); + } + } + function exec_body_scripts(body_el) { + function nodeName(elem, name) { + return !!elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + } + function evalScript(elem) { + const data = elem.text || elem.textContent || elem.innerHTML || ""; + const script = createScript(); + script.type = "text/javascript"; + for (let i = 0; i < elem.attributes.length; i++) { + const attr = elem.attributes[i]; + script.setAttribute(attr.name, attr.value); + } + script.appendChild(document.createTextNode(data)); + body_el.appendChild(script); + } + const scripts = []; + const children_nodes = body_el.childNodes; + for (let i = 0; children_nodes[i]; i++) { + const child = children_nodes[i]; + if (nodeName(child, "script") && (!child.type || child.type.toLowerCase() === "text/javascript" || child.type.toLowerCase() === "application/javascript")) { + scripts.push(child); + body_el.removeChild(child); + } else if (child.nodeType === Node.ELEMENT_NODE) exec_body_scripts(child); + } + for (let i = 0; i < scripts.length; i++) { + const script = scripts[i]; + if (script.parentNode) script.parentNode.removeChild(script); + evalScript(script); + } + } -eval("{// TODO: rename core.js to ready.js?\n\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nvar DOMReady = function(f) {\n if (document.readyState === 'complete' || document.readyState === 'interactive') {\n // Run always (in case of async script).\n setTimeout(f, 0);\n }\n document['addEventListener'] ? document['addEventListener']('DOMContentLoaded', f) : window.attachEvent('onload', f);\n};\n\nDOMReady(function() {\n\n // Called each time on script load\n if (typeof iframely.config.autorun === 'undefined' || iframely.config.autorun !== false) {\n iframely.trigger('load');\n }\n});\n\n\n//# sourceURL=webpack:///./dom-ready.js?\n}"); +//#endregion +//#region src/ahref.ts + function boot$7() { + iframely.on("load", (container, href) => { + if (container && container.nodeName && typeof href === "string") { + const a = document.createElement("a"); + a.setAttribute("href", href); + container.appendChild(a); + iframely.trigger("load", a); + } + }); + iframely.on("load", (el) => { + if (!el && !iframely.import) { + const elements = document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"); + for (let i = 0; i < elements.length; i++) iframely.trigger("load", elements[i]); + } + }); + iframely.on("load", (el) => { + if (el && el.nodeName === "A" && (el.getAttribute("data-iframely-url") || el.getAttribute("href")) && !el.hasAttribute("data-import-uri")) unfurl(el); + }); + } + function unfurl(el) { + if (!el.getAttribute("data-iframely-url") && !el.getAttribute("href")) return; + let src; + const dataIframelyUrl = el.getAttribute("data-iframely-url"); + if (dataIframelyUrl && /^((?:https?:)?\/\/[^/]+)\/\w+/i.test(dataIframelyUrl)) src = getEndpoint(dataIframelyUrl, { + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }); + else if ((iframely.config.api_key || iframely.config.key) && iframely.CDN) { + if (!el.getAttribute("href")) { + console.warn("Iframely cannot build embeds: \"href\" attribute missing in", el); + return; + } + src = getEndpoint("/api/iframe", { + url: el.getAttribute("href"), + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }, iframely.SUPPORTED_QUERY_STRING); + } else console.warn("Iframely cannot build embeds: api key is required as query-string of embed.js"); + if (!src) el.removeAttribute("data-iframely-url"); + else { + const iframe = document.createElement("iframe"); + iframe.setAttribute("allowfullscreen", ""); + iframe.setAttribute("allow", "autoplay *; encrypted-media *; ch-prefers-color-scheme *"); + if (el.hasAttribute("data-img")) iframe.setAttribute("data-img", el.getAttribute("data-img")); + const isLazy = el.hasAttribute("data-lazy") || el.hasAttribute("data-img") || /&lazy=1/.test(src) || iframely.config.lazy; + const text = el.textContent; + if (text && text !== "") iframe.textContent = text; + let wrapper = getIframeWrapper(el, true); + if (wrapper) while (wrapper.aspectWrapper.lastChild) wrapper.aspectWrapper.removeChild(wrapper.aspectWrapper.lastChild); + else { + wrapper = addDefaultWrappers(el); + el.parentNode.removeChild(el); + } + wrapper.aspectWrapper.appendChild(iframe); + if (isLazy) { + iframe.setAttribute("data-iframely-url", src); + iframely.trigger("load", iframe); + } else { + iframe.setAttribute("src", src); + iframely.trigger("iframe-ready", iframe); + } + } + } -/***/ }, +//#endregion +//#region src/lazy-img-placeholder.ts + function boot$6() { + iframely.on("load", (el) => { + if (el && el.nodeName === "IFRAME" && el.hasAttribute("data-iframely-url") && el.hasAttribute("data-img") && !el.getAttribute("src")) { + const dataImg = el.getAttribute("data-img"); + el.removeAttribute("data-img"); + el.setAttribute("data-img-created", ""); + const widget = getWidget(el); + let src = el.getAttribute("data-iframely-url"); + if (widget) { + addPlaceholderThumbnail(widget, src, dataImg); + src = addQueryString(src, { img: 1 }); + el.setAttribute("data-iframely-url", src); + new WaitingWidget(widget); + } + iframely.trigger("load", el); + } + }); + iframely.on("message", (widget, message) => { + if (!widget) return; + let waitingWidget; + if (message.method === "widgetRendered") { + hidePlaceholderThumbnail(widget); + waitingWidget = findWaitingWidget(widget); + waitingWidget?.deactivate(); + } + if (message.method === "begin-waiting-widget-render") { + waitingWidget = findWaitingWidget(widget); + waitingWidget?.clearLoadingTimeout(); + } + if (message.method === "end-waiting-widget-render") { + waitingWidget = findWaitingWidget(widget); + waitingWidget?.registerLoadingTimeout(); + } + }); + } + function addPlaceholderThumbnail(widget, href, imageUrl) { + let thumbHref; + if (imageUrl && /^(https?:)?\/\//.test(imageUrl)) thumbHref = imageUrl; + else { + const query = parseQueryString(href); + const _params = {}; + for (const param in query) if (param.indexOf("_") === 0) _params[param] = query[param]; + if (query.media) _params.media = query.media; + if (href.match(/\/api\/iframe/)) thumbHref = getEndpoint(href.match(/^(.+)\/api\/iframe/i)[1] + "/api/thumbnail", Object.assign({ + url: query.url, + api_key: query.api_key, + key: query.key + }, _params)); + else if (href.match(iframely.ID_RE)) thumbHref = getEndpoint(href.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/, "$1/thumbnail"), _params); + else return; + } + const thumb = document.createElement("div"); + setStyles(thumb, { + position: "absolute", + width: "100%", + height: "100%", + backgroundImage: "url('" + thumbHref + "')", + backgroundSize: "cover", + backgroundPosition: "center" + }); + const iframelyLoaderDiv = document.createElement("div"); + iframelyLoaderDiv.setAttribute("class", iframely.LOADER_CLASS); + thumb.appendChild(iframelyLoaderDiv); + const paddingTop = iframely.getElementComputedStyle(widget.aspectWrapper, "padding-top"); + const paddingBottom = iframely.getElementComputedStyle(widget.aspectWrapper, "padding-bottom"); + const paddingTopMatch = paddingTop && paddingTop.match(/^(\d+)px$/); + if (paddingTopMatch && parseInt(paddingTopMatch[1]) && paddingBottom) { + const thumbWrapper = document.createElement("div"); + setStyles(thumbWrapper, { + top: "-" + paddingTop, + width: "100%", + height: 0, + position: "relative", + paddingBottom + }); + thumbWrapper.appendChild(thumb); + widget.aspectWrapper.appendChild(thumbWrapper); + } else widget.aspectWrapper.appendChild(thumb); + } + function getNthNonTextChildNode(nth, element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.ELEMENT_NODE) { + if (nth === count) return el; + count++; + } + } + } + function nonTextChildCount(element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.TEXT_NODE) { + if ((el.textContent || "").replace(/\s|\n/g, "")) count++; + } else if (el.nodeType === Node.ELEMENT_NODE) count++; + } + return count; + } + function hidePlaceholderThumbnail(widget) { + const thumb = widget.aspectWrapper && nonTextChildCount(widget.aspectWrapper) > 1 && getNthNonTextChildNode(1, widget.aspectWrapper); + if (thumb && thumb.nodeName === "DIV") widget.aspectWrapper.removeChild(thumb); + } + var waitingWidgets = []; + function findWaitingWidgetIdx(widget) { + let i = 0; + while (i < waitingWidgets.length && waitingWidgets[i].widget.iframe !== widget.iframe) i++; + if (i < waitingWidgets.length && waitingWidgets[i].widget.iframe === widget.iframe) return i; + } + function findWaitingWidget(widget) { + const idx = findWaitingWidgetIdx(widget); + if (idx || idx === 0) return waitingWidgets[idx]; + } + function removeWaitingWidget(widget) { + const idx = findWaitingWidgetIdx(widget); + if (idx || idx === 0) waitingWidgets.splice(idx, 1); + } + var WaitingWidget = class { + widget; + loadCount = 0; + timeoutId = null; + constructor(widget) { + this.widget = widget; + iframely.addEventListener(widget.iframe, "load", () => { + this.iframeOnLoad(); + }); + this.registerLoadingTimeout(); + waitingWidgets.push(this); + } + iframeOnLoad() { + this.loadCount++; + if (this.loadCount !== 2) return; + this.deactivate(); + setTimeout(() => { + hidePlaceholderThumbnail(this.widget); + }, iframely.LAZY_IFRAME_FADE_TIMEOUT); + } + deactivate() { + this.clearLoadingTimeout(); + removeWaitingWidget(this.widget); + } + clearLoadingTimeout() { + if (this.timeoutId) clearTimeout(this.timeoutId); + this.timeoutId = null; + } + registerLoadingTimeout() { + if (this.timeoutId) return; + this.timeoutId = setTimeout(() => { + this.iframeOnLoad(); + }, iframely.LAZY_IFRAME_SHOW_TIMEOUT); + } + }; -/***/ "./events.js" -/*!*******************!*\ - !*** ./events.js ***! - \*******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { +//#endregion +//#region src/lazy-iframe.ts + function boot$5() { + iframely.on("load", (el) => { + if (!el) { + const elements = document.querySelectorAll("iframe[data-iframely-url]"); + for (let i = 0; i < elements.length; i++) iframely.trigger("load", elements[i]); + } + }); + iframely.on("load", (el) => { + if (el && el.nodeName === "IFRAME" && el.hasAttribute("data-iframely-url") && !el.hasAttribute("data-img") && !el.getAttribute("src")) loadLazyIframe(el); + }); + } + function loadLazyIframe(el) { + const widget = getWidget(el); + let src = el.getAttribute("data-iframely-url"); + const dataImg = el.hasAttribute("data-img-created") || el.hasAttribute("data-img"); + const nativeLazyLoad = !dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR; + if (widget && src) { + const options = { + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }; + if (!nativeLazyLoad && iframely.config.intersection) options.lazy = 1; + src = getEndpoint(src, options); + } + if (nativeLazyLoad) el.setAttribute("loading", "lazy"); + if (dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR) el.setAttribute("loading", "edge"); + el.setAttribute("src", src || ""); + el.removeAttribute("data-iframely-url"); + iframely.trigger("iframe-ready", el); + } -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nvar nextTick = (function(window, prefixes, i, fnc) {\n while (!fnc && i < prefixes.length) {\n fnc = window[prefixes[i++] + 'equestAnimationFrame'];\n }\n return (fnc && fnc.bind(window)) || window.setImmediate || function(fnc) {window.setTimeout(fnc, 0);};\n})(typeof window !== 'undefined' ? window : __webpack_require__.g, 'r webkitR mozR msR oR'.split(' '), 0);\n\nvar callbacksStack = {};\niframely.on = function(event, cb) {\n var events = callbacksStack[event] = callbacksStack[event] || [];\n events.push(cb);\n};\n\nfunction trigger(event, async, args) {\n var events = callbacksStack[event] || [];\n events.forEach(function(cb) {\n if (async) {\n nextTick(function() {\n cb.apply(iframely, args);\n });\n } else {\n cb.apply(iframely, args);\n }\n });\n\n if (event === 'init') {\n // everything inited, let's clear the callstack, just in case\n // TODO: not good.\n callbacksStack[event] = [];\n }\n}\n\niframely.trigger = function(event) {\n var args = Array.prototype.slice.call(arguments, 1);\n trigger(event, false, args);\n};\n\niframely.triggerAsync = function(event) {\n var args = Array.prototype.slice.call(arguments, 1);\n trigger(event, true, args);\n};\n\n//# sourceURL=webpack:///./events.js?\n}"); +//#endregion +//#region src/widget-cancel.ts + function boot$4() { + iframely.on("message", (widget, message) => { + if (message.method === "cancelWidget") iframely.cancelWidget(widget); + }); + iframely.cancelWidget = (widget) => { + if (!widget) { + console.warn("iframely.cancelWidget called without widget param"); + return; + } + function findParent(el, className) { + let found = false; + while (!found && el.parentNode) { + el = el.parentNode; + found = !!el.className && typeof el.className === "string" && el.className.split(" ").indexOf(className) >= 0; + } + return found && el; + } + let parentNode = widget.maxWidthWrapper && widget.maxWidthWrapper.parentNode; + let naNode = widget.maxWidthWrapper; + if (iframely.config && iframely.config.parent) { + const parentElement = findParent(widget.maxWidthWrapper, String(iframely.config.parent)); + if (parentElement) { + parentNode = parentElement.parentNode; + naNode = parentElement; + } + } + if (widget.url) { + const text = widget.iframe && widget.iframe.textContent; + iframely.triggerAsync("cancel", widget.url, parentNode, text, naNode.nextSibling); + } + parentNode.removeChild(naNode); + }; + } -/***/ }, +//#endregion +//#region src/widget-resize.ts + var resetWrapperBorderStyles = { + "border": "", + "border-radius": "", + "box-shadow": "", + "overflow": "" + }; + var resetIframeBorderStyles = { + "border": "0", + "border-radius": "", + "box-shadow": "", + "overflow": "" + }; + function boot$3() { + iframely.on("message", (widget, message) => { + if (message.method === "setIframelyWidgetSize" || message.method === "resize" || message.method === "setIframelyEmbedData" || message.type === "embed-size" || message.context === "iframe.resize") { + let frame_styles = null; + if (message.data && message.data.media && message.data.media.frame_style) { + message.data.media.frame_style.split(";").forEach((str) => { + if (str.trim() !== "" && str.indexOf(":") > -1) { + const props = str.split(":"); + if (props.length === 2) { + frame_styles = frame_styles || {}; + frame_styles[props[0].trim()] = props[1].trim(); + } + } + }); + widgetDecorate(widget, frame_styles); + } else if (message.method === "setIframelyEmbedData") widgetDecorate(widget, null); + let media = message.data && message.data.media; + if (!media && message.height) media = { + height: message.height, + "max-width": "keep" + }; + widgetResize(widget, media); + } + }); + } + function widgetDecorate(widget, styles) { + if (styles && widget && widget.iframe) if (styles["border-radius"]) { + styles.overflow = "hidden"; + setStyles(widget.aspectWrapper, styles); + } else setStyles(widget.iframe, styles); + else if (!styles && widget && widget.iframe) { + setStyles(widget.aspectWrapper, resetWrapperBorderStyles); + setStyles(widget.iframe, resetIframeBorderStyles); + } + } + function getTotalBorderWidth(widget) { + const frameStylesBorder = widget.iframe && widget.iframe.style.border || widget.aspectWrapper && widget.aspectWrapper.style.border; + const borderMatch = frameStylesBorder && frameStylesBorder.match(/(\d+)px/); + if (borderMatch) return parseInt(borderMatch[1]) * 2; + return 0; + } + function widgetResize(widget, media) { + if (media && Object.keys(media).length > 0 && widget) { + const borderWidth = getTotalBorderWidth(widget); + const oldIframeHeight = window.getComputedStyle(widget.iframe).getPropertyValue("height"); + let maxWidth = media["max-width"]; + if (typeof maxWidth === "number") maxWidth += borderWidth; + setStyles(widget.maxWidthWrapper, { + "max-width": maxWidth, + "min-width": media["min-width"] && media["min-width"] + borderWidth, + width: media.width && media.width + borderWidth + }); + if (media.scrolling && widget.iframe) widget.iframe.setAttribute("scrolling", media.scrolling); + const aspectRatio = media["aspect-ratio"]; + if (aspectRatio || media.height) setStyles(widget.aspectWrapper, { + paddingBottom: aspectRatio ? Math.round(1e3 * 100 / aspectRatio) / 1e3 + "%" : 0, + paddingTop: aspectRatio && media["padding-bottom"], + height: aspectRatio ? 0 : media.height && media.height + borderWidth + }); + const currentHeight = window.getComputedStyle(widget.iframe).getPropertyValue("height"); + if (oldIframeHeight && oldIframeHeight !== currentHeight) iframely.triggerAsync("heightChanged", widget.iframe, oldIframeHeight, currentHeight); + } + } -/***/ "./iframely.js" -/*!*********************!*\ - !*** ./iframely.js ***! - \*********************/ -(module) { +//#endregion +//#region src/widget-click.ts + function boot$2() { + iframely.on("message", (widget, message) => { + if (message.method === "open-href" || message.method === "click") iframely.trigger(message.method, message.href); + }); + if (!iframely.openHref) iframely.openHref = (href) => { + if (href.indexOf(window.location.origin) === 0) window.location.href = href; + else window.open(href, "_blank", "noopener"); + }; + iframely.on("open-href", (href) => { + iframely.triggerAsync("click", href); + iframely.openHref(href); + }); + } -eval("{var iframely = window.iframely = window.iframely || {};\niframely.config = iframely.config || {};\n\nmodule.exports = iframely;\n\n//# sourceURL=webpack:///./iframely.js?\n}"); +//#endregion +//#region src/widget-options.ts + function boot$1() { + iframely.on("message", (widget, message) => { + if (message.method === "setIframelyEmbedOptions") iframely.trigger("options", widget, message.data); + }); + } -/***/ }, +//#endregion +//#region src/deprecated.ts + function boot() { + iframely.widgets = iframely.widgets || {}; + iframely.widgets.load = iframely.load; + if (!iframely.events) { + iframely.events = {}; + iframely.events.on = iframely.on; + iframely.events.trigger = iframely.trigger; + } + iframely.on("cancel", (url, parentNode, text, nextSibling) => { + if (iframely.RECOVER_HREFS_ON_CANCEL && !text) text = url; + if (url && parentNode && text && text !== "") { + const a = document.createElement("a"); + a.setAttribute("href", url); + a.setAttribute("target", "_blank"); + a.setAttribute("rel", "noopener"); + a.textContent = text; + if (nextSibling) parentNode.insertBefore(a, nextSibling); + else parentNode.appendChild(a); + } + }); + } -/***/ "./import.js" -/*!*******************!*\ - !*** ./import.js ***! - \*******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { +//#endregion +//#region src/index.ts + if (!iframely._loaded) { + iframely._loaded = true; + boot$14(); + boot$13(); + boot$11(); + boot$12(); + boot$10(); + boot$9(); + boot$8(); + boot$7(); + boot$6(); + boot$5(); + boot$4(); + boot$3(); + boot$2(); + boot$1(); + boot(); + iframely.trigger("init"); + } -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\n// widgetsCache is used from inside import doc for js callbacks and custom features\nvar widgetsCache = {};\n\niframely.on('load', function(el) {\n\n // load once, if import is not in process and only if query-string from script src has not disabled import\n if (!el && iframely.config.import !== false \n && isImportAble()\n && !iframely.import) {\n\n var elements = document.querySelectorAll('a[data-iframely-url]:not([data-import-uri])');\n if (elements.length > 1) {\n makeImportAPICall(elements);\n }\n }\n\n});\n\niframely.on('load', function(widget, importOptions) {\n\n if (widget && widget.uri && (widget.html || widget.cancel)) {\n\n var els = widgetsCache[widget.uri];\n // alternatively, could as well do querySelectorAll('a[data-iframely-url][data-import=\"' + template.getAttribute('data-uri') + '\"')\n\n if (els) {\n for (var i = 0; i < els.length; i++) {\n loadImportWidget(widget, els[i], importOptions);\n }\n }\n\n delete widgetsCache[widget.uri];\n }\n});\n\nfunction makeImportAPICall(elements) {\n var script = utils.createScript();\n\n var uris = [];\n var ids = [];\n \n var import_options = null; // will be populated from first element; or will remain as null if no params in elements...\n\n // couple helper functions first\n\n function pushElement(uri, el) {\n if (!widgetsCache[uri]) {\n widgetsCache[uri] = [];\n }\n\n widgetsCache[uri].push(el);\n }\n\n function queueElement(el) {\n var src = el.getAttribute('data-iframely-url');\n\n var mId = src.match(iframely.ID_RE);\n var id = mId && mId[1];\n\n var options = utils.parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat('url'));\n\n var url = options.url; // can be undefined for IDs\n delete options.url;\n\n // skip import on import=0, playerjs=1\n var skipImport = options.import === '0' || options.import === 'false' \n || options.playerjs === '1' || options.playerjs === 'true';\n\n // or if link's query-string params or CDN are different from the others\n if (!skipImport) {\n var mBase = src.match(iframely.BASE_RE);\n options.CDN = mBase && mBase[0]; // will fall back to iframely.CDN in getEndpoint('/import...' ...)\n\n // set import options from the first el in import\n // that includes api keys \n if (!import_options) {\n import_options = options;\n\n // else check that this el's options are the same as the first one's in import\n } else if (JSON.stringify(options, Object.keys(options).sort()) \n !== JSON.stringify(import_options, Object.keys(import_options).sort())) {\n\n skipImport = true;\n }\n }\n\n\n if (skipImport) {\n // Usual build if no uri and app=1s.\n iframely.trigger('load', el);\n\n } else if (id) {\n el.setAttribute('data-import-uri', id);\n if (ids.indexOf(id) === -1) {\n ids.push(id);\n }\n pushElement(id, el);\n\n } else {\n\n if (!url) {\n url = el.getAttribute('href');\n }\n\n var key = import_options.key || import_options.api_key || iframely.config.api_key || iframely.config.key;\n\n if (key && url) {\n\n el.setAttribute('data-import-uri', url);\n if (uris.indexOf(url) === -1) {\n uris.push(url);\n }\n pushElement(url, el);\n } else {\n // Usual build if no uri.\n iframely.trigger('load', el);\n }\n }\n }\n\n\n // start actual filling up of import request\n\n for(var i = 0; i < elements.length; i++) {\n var el = elements[i];\n if (!el.getAttribute('data-import-uri') && el.hasAttribute('data-iframely-url')) {\n queueElement(el);\n }\n }\n\n if ((uris.length > 0 || ids.length > 0)) {\n\n import_options = import_options || {};\n import_options.touch = iframely.isTouch();\n import_options.flash = hasFlash();\n import_options.app = 1;\n // Do not override imports theme if global theme not set.\n if (iframely.config.theme) {\n import_options.theme = iframely.config.theme;\n }\n\n if (uris.length > 0) {\n import_options.uri = uris;\n }\n\n if (ids.length > 0) {\n import_options.ids = ids.join('&');\n }\n\n import_options.v = iframely.VERSION;\n\n script.src = utils.getEndpoint('/api/import/v2', import_options, iframely.SUPPORTED_QUERY_STRING);\n\n script.onerror = function() {\n // Error loading import. No import this time.\n importReady();\n };\n\n document.head.appendChild(script);\n iframely.import = script;\n\n } else {\n importReady();\n iframely.trigger('load');\n }\n}\n\niframely.buildImportWidgets = function(importOptions) {\n\n iframely.trigger('import-loaded', importOptions);\n\n importOptions.widgets.forEach(function(widget) {\n iframely.trigger('load', widget, importOptions);\n });\n\n importReady();\n};\n\nfunction loadImportWidget(widgetOptions, el, importOptions) {\n\n var needCancelWidget = widgetOptions.cancel;\n var shadow = widgetOptions.shadow;\n var hasRenderedEvent = widgetOptions.renderEvent;\n\n var wrapper = utils.getIframeWrapper(el, true);\n var widget;\n\n if (needCancelWidget) {\n widget = utils.getWidget(el);\n\n iframely.cancelWidget(widget || {\n maxWidthWrapper: el,\n iframe: el,\n url: el.getAttribute('href') \n });\n\n } else {\n\n widget = document.createElement('div');\n widget.innerHTML = widgetOptions.html;\n \n var parent, replacedEl;\n\n if (wrapper && !hasRenderedEvent) {\n // Inline widget will replace 'aspectWrapper' but keep 'maxWidthWrapper' as 'iframely-embed' to fix centering, etc.\n // If has rendered event - keep wrapper and remove attrs later by event.\n parent = wrapper.aspectWrapper.parentNode;\n replacedEl = wrapper.aspectWrapper;\n\n // Clear custom attributes.\n wrapper.maxWidthWrapper.removeAttribute('style');\n } else {\n // No wrapper or keep wrapper for later removal.\n parent = el.parentNode;\n replacedEl = el;\n }\n\n if (shadow) {\n\n var shadowContainer = document.createElement('div');\n var shadowRoot = shadowContainer.attachShadow({mode: 'open'});\n shadowRoot.appendChild(widget);\n\n var shadowWidgetOptions = {\n shadowRoot: shadowRoot,\n shadowContainer: shadowContainer,\n container: parent,\n context: widgetOptions.context,\n stylesIds: widgetOptions.stylesIds,\n stylesDict: importOptions.commonShadowStyles\n };\n \n iframely.trigger('import-shadow-widget-before-render', shadowWidgetOptions);\n \n parent.insertBefore(shadowContainer, replacedEl);\n\n iframely.trigger('import-shadow-widget-after-render', shadowWidgetOptions);\n \n } else {\n\n parent.insertBefore(widget, replacedEl);\n\n exec_body_scripts(widget);\n }\n\n parent.removeChild(replacedEl);\n\n if (hasRenderedEvent) {\n setTimeout(function() {\n clearWrapperStylesAndClass(parent);\n }, iframely.CLEAR_WRAPPER_STYLES_TIMEOUT);\n }\n }\n}\n\n\nfunction importReady() {\n\n delete iframely.import;\n\n // clean up all, let other loaders have a go\n var failed_elements = document.querySelectorAll('a[data-iframely-url][data-import-uri]');\n for(var i = 0; i < failed_elements.length; i++) {\n failed_elements[i].removeAttribute('data-import-uri');\n iframely.trigger('load', failed_elements[i]);\n }\n}\n\niframely.isTouch = function() {\n return 'ontouchstart' in window // works on most browsers\n || navigator.maxTouchPoints; // works on IE10/11 and Surface\n};\n\nfunction hasFlash() {\n\n var _hasFlash = false;\n\n try {\n var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');\n if (fo) {\n _hasFlash = true;\n } else {\n _hasFlash = false;\n }\n } catch (e) {\n if (navigator.mimeTypes\n && navigator.mimeTypes['application/x-shockwave-flash'] != undefined\n && navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin) {\n _hasFlash = true;\n } else {\n _hasFlash = false;\n }\n }\n\n return _hasFlash;\n}\n\nfunction isImportAble() {\n\n return document.head.attachShadow\n && document.location // Prevent `Cannot read properties of null (reading 'protocol')` for sandbox iframes.\n && (iframely.debug || document.location.protocol === 'http:' || document.location.protocol === 'https:') // Skip import on file:///\n && !iframely.config.playerjs && !iframely.config.lazy;\n // && !navigator.userAgent.toLowerCase().indexOf('firefox') > -1;\n // TODO: test in Firefox 63\n}\n\nfunction clearWrapperStylesAndClass(el) {\n var aspectWrapper = el;\n var parents = 0;\n while(aspectWrapper \n && (!aspectWrapper.getAttribute('class')\n || aspectWrapper.getAttribute('class').split(' ').indexOf(iframely.ASPECT_WRAPPER_CLASS) === -1)) {\n\n aspectWrapper = aspectWrapper.parentNode;\n parents++;\n if (parents > 4) {\n // Do not search further 4 parents.\n aspectWrapper = null;\n }\n }\n\n var maxWidthWrapper = aspectWrapper && aspectWrapper.parentNode;\n if (maxWidthWrapper \n && maxWidthWrapper.getAttribute('class')\n && maxWidthWrapper.getAttribute('class').split(' ').indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) > -1) {\n\n // Remove wrapper specific data. Leave only 'iframely-embed' parent class.\n aspectWrapper.removeAttribute('style');\n aspectWrapper.removeAttribute('class');\n maxWidthWrapper.removeAttribute('style');\n }\n}\n\niframely.on('import-widget-ready', clearWrapperStylesAndClass);\n\n// used in server templates\n\nif (!iframely.addEventListener) {\n iframely.addEventListener = function(elem, type, eventHandle) {\n if (!elem) { return; }\n if ( elem.addEventListener ) {\n elem.addEventListener( type, eventHandle, false );\n } else if ( elem.attachEvent ) {\n elem.attachEvent( 'on' + type, eventHandle );\n } else {\n elem['on' + type] = eventHandle;\n }\n };\n}\n\nfunction exec_body_scripts(body_el) {\n function nodeName(elem, name) {\n return elem.nodeName && elem.nodeName.toUpperCase() ===\n name.toUpperCase();\n }\n\n function evalScript(elem) {\n var data = (elem.text || elem.textContent || elem.innerHTML || '' ),\n script = utils.createScript();\n\n // Copy all script attributes.\n script.type = 'text/javascript';\n for (var i = 0; i < elem.attributes.length; i++) {\n var attr = elem.attributes[i];\n script.setAttribute(attr.name, attr.value);\n }\n try {\n // doesn't work on ie...\n script.appendChild(document.createTextNode(data));\n } catch(e) {\n // IE has funky script nodes\n script.text = data;\n }\n\n body_el.appendChild(script);\n }\n\n // main section of function\n var scripts = [],\n script,\n children_nodes = body_el.childNodes,\n child,\n i;\n\n for (i = 0; children_nodes[i]; i++) {\n child = children_nodes[i];\n if (nodeName(child, 'script' ) &&\n (!child.type || child.type.toLowerCase() === 'text/javascript' || child.type.toLowerCase() === 'application/javascript')) {\n scripts.push(child);\n body_el.removeChild(child);\n } else {\n exec_body_scripts(child);\n }\n }\n\n for (i = 0; scripts[i]; i++) {\n script = scripts[i];\n if (script.parentNode) {script.parentNode.removeChild(script);}\n evalScript(scripts[i]);\n }\n}\n\n//# sourceURL=webpack:///./import.js?\n}"); - -/***/ }, - -/***/ "./index.js" -/*!******************!*\ - !*** ./index.js ***! - \******************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{__webpack_require__(/*! ./dom-ready */ \"./dom-ready.js\");\n\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nif (!iframely._loaded) {\n\n iframely._loaded = true;\n\n __webpack_require__(/*! ./const */ \"./const.js\");\n __webpack_require__(/*! ./events */ \"./events.js\");\n // require('./utils'); // Loaded by other modules.\n __webpack_require__(/*! ./intersection */ \"./intersection.js\");\n __webpack_require__(/*! ./theme */ \"./theme.js\");\n __webpack_require__(/*! ./import */ \"./import.js\");\n __webpack_require__(/*! ./ahref */ \"./ahref.js\");\n __webpack_require__(/*! ./lazy-img-placeholder */ \"./lazy-img-placeholder.js\");\n __webpack_require__(/*! ./lazy-iframe */ \"./lazy-iframe.js\");\n // require('./messaging'); // Loaded by other modules.\n __webpack_require__(/*! ./widget-cancel */ \"./widget-cancel.js\");\n __webpack_require__(/*! ./widget-resize */ \"./widget-resize.js\");\n __webpack_require__(/*! ./widget-click */ \"./widget-click.js\");\n __webpack_require__(/*! ./widget-options */ \"./widget-options.js\");\n __webpack_require__(/*! ./deprecated */ \"./deprecated.js\");\n __webpack_require__(/*! ./lazy-loading-native */ \"./lazy-loading-native.js\");\n\n iframely.trigger('init'); \n}\n\nexports.iframely = iframely;\n\n//# sourceURL=webpack:///./index.js?\n}"); - -/***/ }, - -/***/ "./intersection.js" -/*!*************************!*\ - !*** ./intersection.js ***! - \*************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var messaging = __webpack_require__(/*! ./messaging */ \"./messaging.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\nvar observers = {};\n\nfunction getObserver(options) {\n var optionsKey = JSON.stringify(options);\n var observer = observers[optionsKey];\n if (!observer) {\n\n observer = new IntersectionObserver(function(entries) {\n\n entries.forEach(function(entry) {\n messaging.postMessage({\n method: 'intersection',\n entry: {\n isIntersecting: entry.isIntersecting\n },\n options: options\n }, '*', entry.target.contentWindow);\n });\n\n }, getObserverOptions(options));\n\n observers[optionsKey] = observer;\n }\n return observer;\n}\n\nfunction getObserverOptions(options) {\n var result = {};\n if (options && options.threshold) {\n result.threshold = options.threshold;\n }\n if (options && options.margin) {\n result.rootMargin = options.margin + 'px ' + options.margin + 'px ' + options.margin + 'px ' + options.margin + 'px';\n }\n return result;\n}\n\nif ('IntersectionObserver' in window &&\n 'IntersectionObserverEntry' in window) {\n\n iframely.on('init', function() {\n\n iframely.extendOptions({\n intersection: 1\n });\n \n });\n\n iframely.on('message', function(widget, message) {\n if (message.method === 'send-intersections' && widget.iframe) {\n\n var options = message.options;\n\n if (!options) {\n options = {\n margin: 1000\n };\n }\n\n getObserver(options).observe(widget.iframe);\n }\n });\n}\n\n\n//# sourceURL=webpack:///./intersection.js?\n}"); - -/***/ }, - -/***/ "./lazy-iframe.js" -/*!************************!*\ - !*** ./lazy-iframe.js ***! - \************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\n// Need 'load' handler here instead of on('init') - we load lazy iframes only when DOM ready.\niframely.on('load', function(el) { \n\n if (!el) { // initial load\n\n var elements = document.querySelectorAll('iframe[data-iframely-url]');\n for(var i = 0; i < elements.length; i++) {\n iframely.trigger('load', elements[i]);\n } \n }\n \n});\n\niframely.on('load', function(el) {\n\n if (el && el.nodeName === 'IFRAME'\n && el.hasAttribute('data-iframely-url')\n && !el.hasAttribute('data-img')\n && !el.getAttribute('src')) {\n\n loadLazyIframe(el);\n }\n \n});\n\n\nfunction loadLazyIframe(el) {\n\n var widget = utils.getWidget(el);\n var src = el.getAttribute('data-iframely-url');\n var dataImg = el.hasAttribute('data-img-created') || el.hasAttribute('data-img');\n var nativeLazyLoad = !dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR;\n\n if (widget && src) {\n\n var options = {\n v: iframely.VERSION,\n app: 1, // for example, will fall back to summary card if media is not longer available\n theme: iframely.config.theme\n };\n\n if (!nativeLazyLoad && iframely.config.intersection) {\n options.lazy = 1;\n }\n\n src = utils.getEndpoint(src, options);\n\n }\n\n if (nativeLazyLoad) {\n el.setAttribute('loading', 'lazy');\n }\n\n if (dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR) {\n // Disable lazy load with `data-img`.\n el.setAttribute('loading', 'edge');\n }\n\n el.setAttribute('src', src);\n el.removeAttribute('data-iframely-url');\n\n iframely.trigger('iframe-ready', el);\n}\n\n//# sourceURL=webpack:///./lazy-iframe.js?\n}"); - -/***/ }, - -/***/ "./lazy-img-placeholder.js" -/*!*********************************!*\ - !*** ./lazy-img-placeholder.js ***! - \*********************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('load', function(el) {\n\n if (el && el.nodeName === 'IFRAME'\n && el.hasAttribute('data-iframely-url')\n && el.hasAttribute('data-img')\n && !el.getAttribute('src')) {\n\n var dataImg = el.getAttribute('data-img');\n\n el.removeAttribute('data-img');\n el.setAttribute('data-img-created', '');\n\n var widget = utils.getWidget(el);\n var src = el.getAttribute('data-iframely-url');\n\n addPlaceholderThumbnail(widget, src, dataImg);\n\n src = utils.addQueryString(src, {img: 1});\n el.setAttribute('data-iframely-url', src);\n\n new WaitingWidget(widget);\n\n iframely.trigger('load', el);\n\n }\n});\n\niframely.on('message', function(widget, message) {\n\n var waitingWidget;\n\n if (message.method === 'widgetRendered') {\n hidePlaceholderThumbnail(widget);\n\n waitingWidget = findWaitingWidget(widget);\n waitingWidget && waitingWidget.deactivate();\n }\n\n if (message.method === 'begin-waiting-widget-render') {\n waitingWidget = findWaitingWidget(widget);\n waitingWidget && waitingWidget.clearLoadingTimeout();\n }\n\n if (message.method === 'end-waiting-widget-render') {\n waitingWidget = findWaitingWidget(widget);\n waitingWidget && waitingWidget.registerLoadingTimeout();\n }\n});\n\n\nfunction addPlaceholderThumbnail(widget, href, imageUrl) {\n\n var thumbHref;\n\n if (imageUrl && /^(https?:)?\\/\\//.test(imageUrl)) {\n thumbHref = imageUrl;\n } else {\n\n // Start of image url calculation.\n \n var query = utils.parseQueryString(href);\n \n // Extract widget params to invalidate image cache.\n var _params = {};\n for(var param in query) {\n if (param.indexOf('_') === 0) {\n _params[param] = query[param];\n }\n }\n\n // Force proxy `media` param.\n if (query.media) {\n _params.media = query.media;\n }\n \n // need to run through getEndpoint at least to avoid file:///\n if (href.match(/\\/api\\/iframe/)) {\n thumbHref = utils.getEndpoint(href.match(/^(.+)\\/api\\/iframe/i)[1] + '/api/thumbnail', Object.assign({\n url: query.url,\n api_key: query.api_key,\n key: query.key\n }, _params));\n } else if (href.match(iframely.ID_RE)) {\n // RE copied from `iframely.ID_RE` and modified to replace path part.\n thumbHref = utils.getEndpoint(href.replace(/^((?:https?:)?\\/\\/[^/]+\\/(\\w+-?\\w+))(?:\\?.*)?$/, '$1/thumbnail'), _params);\n } else {\n return;\n }\n }\n\n // End of image url calculation.\n\n var thumb = document.createElement('div');\n // Parent div not always has ASPECT_WRAPPER_CLASS. Need explicit inline styles.\n utils.setStyles(thumb, {\n position: 'absolute',\n width: '100%',\n height: '100%',\n backgroundImage: \"url('\" + thumbHref + \"')\",\n backgroundSize: 'cover',\n backgroundPosition: 'center'\n });\n\n var iframelyLoaderDiv = document.createElement('div');\n iframelyLoaderDiv.setAttribute('class', iframely.LOADER_CLASS);\n thumb.appendChild(iframelyLoaderDiv);\n\n var paddingTop = iframely.getElementComputedStyle(widget.aspectWrapper, 'padding-top');\n var paddingBottom = iframely.getElementComputedStyle(widget.aspectWrapper, 'padding-bottom');\n\n var paddingTopMatch = paddingTop.match(/^(\\d+)px$/);\n var paddingTopInt = paddingTopMatch && parseInt(paddingTopMatch[1]);\n\n if (paddingTopInt && paddingBottom) {\n\n var thumbWrapper = document.createElement('div');\n\n utils.setStyles(thumbWrapper, {\n top: '-' + paddingTop,\n width: '100%',\n height: 0,\n position: 'relative',\n paddingBottom: paddingBottom\n }); \n\n thumbWrapper.appendChild(thumb);\n\n widget.aspectWrapper.appendChild(thumbWrapper);\n\n } else {\n\n widget.aspectWrapper.appendChild(thumb);\n }\n}\n\nfunction getNthNonTextChildNode(nth, element) {\n var count = 0;\n for(var i = 0; i < element.childNodes.length; i++) {\n var el = element.childNodes[i];\n if (el.nodeType === Node.TEXT_NODE) {\n // Nop.\n } else if (el.nodeType === Node.ELEMENT_NODE) {\n if (nth === count) {\n return el;\n }\n count++;\n }\n }\n}\n\nfunction nonTextChildCount(element) {\n var count = 0;\n for(var i = 0; i < element.childNodes.length; i++) {\n var el = element.childNodes[i];\n if (el.nodeType === Node.TEXT_NODE) {\n var text = el.textContent || el.innerText;\n text = text.replace(/\\s|\\n/g, '');\n if (text) {\n // Do not skip text node with text.\n count++;\n }\n } else if (el.nodeType === Node.ELEMENT_NODE) {\n count++;\n }\n }\n return count;\n}\n\nfunction hidePlaceholderThumbnail(widget) {\n var thumb = widget.aspectWrapper && nonTextChildCount(widget.aspectWrapper) > 1 && getNthNonTextChildNode(1, widget.aspectWrapper);\n if (thumb && thumb.nodeName === 'DIV') {\n widget.aspectWrapper.removeChild(thumb);\n }\n}\n\n//===\n\n// Working WaitingWidgets' collection.\n\nvar waitingWidgets = [];\n\nfunction findWaitingWidgetIdx(widget) {\n var i = 0;\n while(i < waitingWidgets.length && waitingWidgets[i].widget.iframe !== widget.iframe) {\n i++;\n }\n if (i < waitingWidgets.length && waitingWidgets[i].widget.iframe === widget.iframe) {\n return i;\n }\n}\n\nfunction findWaitingWidget(widget) {\n var idx = findWaitingWidgetIdx(widget);\n if (idx || idx === 0) {\n return waitingWidgets[idx];\n }\n}\n\nfunction removeWaitingWidget(widget) {\n var idx = findWaitingWidgetIdx(widget);\n if (idx || idx === 0) {\n waitingWidgets.splice(idx, 1);\n }\n}\n\n//===\n\n// WaitingWidget proto.\n\nfunction WaitingWidget(widget) {\n this.widget = widget;\n this.loadCount = 0;\n\n var iframe = widget.iframe;\n\n var that = this;\n function iframeOnLoad() {\n // Bind method to self.\n that.iframeOnLoad();\n }\n\n iframely.addEventListener(iframe, 'load', iframeOnLoad);\n\n this.registerLoadingTimeout();\n\n waitingWidgets.push(this);\n}\n\nWaitingWidget.prototype.iframeOnLoad = function() {\n\n this.loadCount++;\n\n // Skip first load of hosted widget OR timeout call.\n if (this.loadCount !== 2) {\n return;\n }\n\n this.deactivate();\n\n var that = this;\n setTimeout(function() {\n hidePlaceholderThumbnail(that.widget);\n }, iframely.LAZY_IFRAME_FADE_TIMEOUT);\n};\n\nWaitingWidget.prototype.deactivate = function() {\n this.clearLoadingTimeout();\n removeWaitingWidget(this);\n};\n\nWaitingWidget.prototype.clearLoadingTimeout = function() {\n this.timeoutId && clearTimeout(this.timeoutId);\n this.timeoutId = null;\n};\n\nWaitingWidget.prototype.registerLoadingTimeout = function() {\n if (this.timeoutId) {\n return;\n }\n var that = this;\n this.timeoutId = setTimeout(function() {\n that.iframeOnLoad();\n }, iframely.LAZY_IFRAME_SHOW_TIMEOUT);\n};\n\n\n//# sourceURL=webpack:///./lazy-img-placeholder.js?\n}"); - -/***/ }, - -/***/ "./lazy-loading-native.js" -/*!********************************!*\ - !*** ./lazy-loading-native.js ***! - \********************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{function getChromeVersion() { \n var raw = navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./);\n\n return raw ? parseInt(raw[2], 10) : false;\n}\nvar chromeVersion = getChromeVersion();\n\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\niframely.SUPPORT_IFRAME_LOADING_ATTR = chromeVersion && chromeVersion >= 77;\n\n//# sourceURL=webpack:///./lazy-loading-native.js?\n}"); - -/***/ }, - -/***/ "./messaging.js" -/*!**********************!*\ - !*** ./messaging.js ***! - \**********************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\nvar utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\n\nfunction receiveMessage(callback) {\n\n function cb(e) {\n var message;\n try {\n if (typeof e.data === 'string') {\n message = JSON.parse(e.data);\n } else if (typeof e.data === 'object') {\n message = e.data;\n }\n } catch (ex) {\n if (typeof e.data === 'string') {\n var m = e.data.match(/heightxPYMx(\\d+)/);\n if (m) {\n message = {\n method: 'resize',\n height: parseInt(m[1]) + 1,\n domains: 'all'\n };\n }\n }\n }\n\n callback(e, message);\n }\n\n // browser supports window.postMessage\n if (window['postMessage']) {\n if (window['addEventListener']) {\n window[callback ? 'addEventListener' : 'removeEventListener']('message', cb, !1);\n } else {\n window[callback ? 'attachEvent' : 'detachEvent']('onmessage', cb);\n }\n }\n}\n\nfunction findIframeByContentWindow(iframes, contentWindow) {\n var foundIframe;\n for(var i = 0; i < iframes.length && !foundIframe; i++) {\n var iframe = iframes[i];\n if (iframe.contentWindow === contentWindow) {\n foundIframe = iframe;\n }\n }\n return foundIframe;\n}\n\nfunction findIframeInElement(element, options) {\n var foundIframe, iframes;\n \n if (options.src) {\n iframes = element.querySelectorAll('iframe[src*=\"' + options.src.replace(/^https?:/, '') + '\"]');\n foundIframe = findIframeByContentWindow(iframes, options.contentWindow);\n }\n\n if (!foundIframe) {\n iframes = options.domains ?\n element.querySelectorAll('iframe[src*=\"' + (options.domains || iframely.DOMAINS).join('\"], iframe[src*=\"') + '\"]')\n : element.getElementsByTagName('iframe');\n foundIframe = findIframeByContentWindow(iframes, options.contentWindow);\n }\n\n return foundIframe;\n}\n\nfunction findIframeInShadowRoots(element, options) {\n var foundIframe;\n var className = '.' + (iframely.config.shadow || iframely.SHADOW);\n var shadowRoots = element.querySelectorAll(className);\n for(var i = 0; i < shadowRoots.length && !foundIframe; i++) {\n var shadowRoot = shadowRoots[i].shadowRoot;\n if (shadowRoot) {\n foundIframe = findIframeInElement(shadowRoot, options);\n if (!foundIframe) {\n foundIframe = findIframeInShadowRoots(shadowRoot, options);\n }\n }\n }\n return foundIframe;\n}\n\n// Do not override existing.\nif (!iframely.findIframe) {\n iframely.findIframe = function(options) {\n var foundIframe = findIframeInElement(document, options);\n if (!foundIframe) {\n foundIframe = findIframeInShadowRoots(document, options);\n }\n return foundIframe;\n };\n}\n\n\nreceiveMessage(function(e, message) {\n\n if (message && (message.method || message.type || message.context)) {\n\n var foundIframe = iframely.findIframe({\n contentWindow: e.source,\n src: message.src || message.context,\n domains: message.domains !== 'all' && iframely.DOMAINS.concat(iframely.CDN)\n });\n\n if (foundIframe) {\n var widget = utils.getWidget(foundIframe);\n if (widget && message.url) {\n widget.url = message.url;\n }\n iframely.trigger('message', widget, message);\n }\n }\n \n});\n\n\nexports.postMessage = function(message, target_url, target) {\n if (window['postMessage']) {\n\n if (typeof message === 'object') {\n message.context = document.location.href;\n }\n\n message = JSON.stringify(message);\n\n target_url = target_url || '*';\n\n target = target || window.parent; // default to parent\n\n // the browser supports window.postMessage, so call it with a targetOrigin\n // set appropriately, based on the target_url parameter.\n target['postMessage'](message, target_url.replace( /([^:]+:\\/\\/[^/]+).*/, '$1'));\n }\n};\n\n\n//# sourceURL=webpack:///./messaging.js?\n}"); - -/***/ }, - -/***/ "./theme.js" -/*!******************!*\ - !*** ./theme.js ***! - \******************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\nvar messaging = __webpack_require__(/*! ./messaging */ \"./messaging.js\");\n\nfunction setThemeInIframe(iframe, theme) {\n messaging.postMessage({\n method: 'setTheme',\n data: theme\n }, '*', iframe.contentWindow);\n}\n\nfunction setThemeInAllIframes(parent, theme) {\n var iframes = parent.getElementsByTagName('iframe');\n for(var i = 0; i < iframes.length; i++) {\n var iframe = iframes[i];\n setThemeInIframe(iframe, theme);\n }\n}\n\niframely.setTheme = function(theme, container) {\n if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) {\n if (container) {\n if (container.tagName === 'IFRAME') {\n setThemeInIframe(container, theme);\n } else {\n setThemeInAllIframes(container, theme);\n }\n } else {\n // Send get param to next iframes.\n iframely.extendOptions({\n theme: theme\n });\n setThemeInAllIframes(document, theme);\n iframely.trigger('set-theme', theme);\n }\n } else {\n console.warn('Using iframely.setTheme with not supported theme: \"' + theme + '\". Supported themes are: ' + iframely.SUPPORTED_THEMES.join(', '));\n }\n};\n\n//# sourceURL=webpack:///./theme.js?\n}"); - -/***/ }, - -/***/ "./utils.js" -/*!******************!*\ - !*** ./utils.js ***! - \******************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\nvar messaging = __webpack_require__(/*! ./messaging */ \"./messaging.js\");\n\niframely.on('init', function() {\n\n\n iframely.extendOptions(parseQueryStringFromScriptSrc());\n // if it's hosted from elsewhere - we don't support customizing via query-string.\n // iframely.CDN will be default one unless changed by user (?cdn= or iframely.CDN= )\n\n defineDefaultStyles();\n\n // Set theme for existing iframes.\n if (iframely.config.theme) {\n iframely.setTheme(iframely.config.theme);\n }\n\n requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\\/\\//, '')));\n \n});\n\niframely.load = function() {\n var args = Array.prototype.slice.call(arguments);\n args.unshift('load');\n iframely.trigger.apply(this, args);\n};\n\nvar getIframeWrapper = exports.getIframeWrapper = function(iframe, checkClass) {\n\n var aspectWrapper = iframe.parentNode;\n\n if (!aspectWrapper\n || aspectWrapper.nodeName !== 'DIV'\n || nonTextChildCount(aspectWrapper) > 2 /* 2 is lazy-cover */\n || (checkClass && aspectWrapper.getAttribute('class') !== iframely.ASPECT_WRAPPER_CLASS)\n || (!checkClass && aspectWrapper.style.position !== 'relative' && aspectWrapper.getAttribute('class') !== iframely.ASPECT_WRAPPER_CLASS)) {\n return;\n }\n\n var maxWidthWrapper = aspectWrapper.parentNode;\n\n if (!maxWidthWrapper\n || maxWidthWrapper.nodeName !== 'DIV'\n || nonTextChildCount(maxWidthWrapper) > 1\n || (checkClass && maxWidthWrapper.getAttribute('class') && maxWidthWrapper.getAttribute('class').split(' ').indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) === -1)\n || (!checkClass && maxWidthWrapper.getAttribute('class') && !maxWidthWrapper.getAttribute('class').match(/iframely/i) /* users can modify class */)\n ) {\n return;\n }\n\n return {\n aspectWrapper: aspectWrapper,\n maxWidthWrapper: maxWidthWrapper\n };\n};\n\nexports.addDefaultWrappers = function(el) {\n var parentNode = el.parentNode;\n\n var maxWidthWrapper = document.createElement('div');\n maxWidthWrapper.className = iframely.MAXWIDTH_WRAPPER_CLASS;\n\n var aspectWrapper = document.createElement('div');\n aspectWrapper.className = iframely.ASPECT_WRAPPER_CLASS;\n\n maxWidthWrapper.appendChild(aspectWrapper);\n\n parentNode.insertBefore(maxWidthWrapper, el);\n\n return {\n aspectWrapper: aspectWrapper,\n maxWidthWrapper: maxWidthWrapper\n };\n};\n\nexports.getWidget = function(iframe) {\n var wrapper = getIframeWrapper(iframe);\n if (!wrapper) {\n return;\n }\n var widget = {\n iframe: iframe, // can actually be ahref\n aspectWrapper: wrapper.aspectWrapper,\n maxWidthWrapper: wrapper.maxWidthWrapper\n };\n if (iframe.nodeName === 'A' && iframe.hasAttribute('href')) {\n widget.url = iframe.getAttribute('href');\n } else if (iframe.hasAttribute('src') && /url=/.test(iframe.getAttribute('src'))) {\n var qs = parseQueryString(iframe.getAttribute('src'));\n if (qs.url) {\n widget.url = qs.url;\n }\n }\n return widget;\n};\n\niframely.getElementComputedStyle = function(el, style) {\n return window.getComputedStyle && window.getComputedStyle(el).getPropertyValue(style);\n};\n\nexports.setStyles = function(el, styles) {\n if (el) { // let's check it's still defined, just in case\n Object.keys(styles).forEach(function(key) {\n\n var value = styles[key];\n if (typeof value === 'number' || (typeof value === 'string' && /^(\\d+)?\\.?(\\d+)$/.test(value))) {\n value = value + 'px';\n }\n\n var currentValue = el.style[key];\n\n if (!window.getComputedStyle ||\n // don't change CSS values in pixels, such as height:0\n (\n iframely.getElementComputedStyle(el, key) != value\n // && don't set default aspect ratio if it's defined in CSS anyway\n && !(el.className == 'iframely-responsive' && key === 'paddingBottom' && !currentValue && /^56\\.2\\d+%$/.test(value))\n // && do not change max-width if new value === 'keep'.\n && !(key === 'max-width' && value === 'keep')\n )) {\n\n el.style[key] = value || ''; // remove style that is no longer needed\n }\n });\n }\n};\n\nvar applyNonce = exports.applyNonce = function(element) {\n if (iframely.config.nonce) {\n element.nonce = iframely.config.nonce;\n }\n};\n\nfunction defineDefaultStyles() {\n\n var iframelyStylesId = 'iframely-styles';\n var styles = document.getElementById(iframelyStylesId);\n\n if (!styles) {\n // copy-paste default styles from https://iframely.com/docs/omit-css\n // box-sizing:border-box - need for iOS Safari .\n var iframelyStyles = '.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}';\n\n styles = document.createElement('style');\n styles.id = iframelyStylesId;\n styles.type = 'text/css';\n applyNonce(styles);\n\n if (styles.styleSheet) {\n // IE.\n styles.styleSheet.cssText = iframelyStyles;\n } else {\n styles.innerHTML = iframelyStyles;\n }\n document.getElementsByTagName('head')[0].appendChild(styles);\n }\n}\n\n\nvar addQueryString = exports.addQueryString = function(href, options) {\n\n var query_string = '';\n\n Object.keys(options).forEach(function(key) {\n var value = options[key];\n\n // array is used e.g. for import: uris and ids\n if (Object.prototype.toString.call(value) === '[object Array]') {\n\n var values = value.map(function(uri) {\n return key + '=' + encodeURIComponent(uri);\n });\n query_string += '&' + values.join('&'); \n\n } else if (typeof value !== 'undefined' && href.indexOf(key + '=') === -1 ) { // set explicitely in options, skip undefines\n\n // Do not convert boolean for _option.\n if (typeof value === 'boolean' && key.charAt(0) !== '_') {\n value = value ? 1 : 0;\n }\n\n query_string += '&' + key + '=' + encodeURIComponent(value);\n }\n\n });\n\n return href + (query_string !== '' ? (href.indexOf('?') > -1 ? '&' : '?') + query_string.replace(/^&/, '') : '');\n};\n\nexports.getEndpoint = function(src, options, config_params) {\n\n var endpoint = src;\n\n if (!/^(https?:)?\\/\\//i.test(src)) {\n endpoint = (options.CDN || iframely.CDN) + endpoint;\n delete options.CDN;\n }\n\n if (!/^(?:https?:)?\\/\\//i.test(endpoint)) {\n endpoint = '//' + endpoint;\n } \n\n if (options) {\n endpoint = addQueryString(endpoint, options);\n }\n\n // get additional params from config\n if (config_params && config_params.length) {\n\n var more_options = {};\n\n var iframely_config_keys = Object.keys(iframely.config);\n for (var i = 0; i < iframely_config_keys.length; i++) {\n var key = iframely_config_keys[i];\n if (containsString(config_params, key)) {\n more_options[key] = iframely.config[key];\n }\n }\n\n endpoint = addQueryString(endpoint, more_options);\n }\n\n\n if (/^(https?:)?\\/\\//i.test(endpoint) // Path is url.\n && !endpoint.match(/^(https?:)?\\/\\//i)[1] // No http protocol specified.\n && document.location.protocol !== 'http:' // Document in `file:` or other protocol.\n && document.location.protocol !== 'https:') {\n\n endpoint = 'https:' + endpoint;\n }\n\n return endpoint;\n};\n\n// helper method to init more options through js code\niframely.extendOptions = function(options) {\n\n options && Object.keys(options).forEach(function(key) {\n var new_value = (\n options[key] === 0 || options[key] === '0' || options[key] === false || options[key] === 'false'\n ? false : (options[key] === 1 || options[key] === '1' || options[key] === true || options[key] === 'true'\n ? true : options[key]));\n\n if (iframely.config[key] !== false) { // set new value only when undefined or not previously disabled\n iframely.config[key] = new_value;\n }\n });\n\n};\n\nfunction parseQueryStringFromScriptSrc() {\n\n // Extract global iframely params.\n var scripts = document.querySelectorAll('script[src*=\"embed.js\"], script[src*=\"iframely.js\"]');\n\n for(var i = 0; i < scripts.length; i++) {\n var src = scripts[i].getAttribute('src').replace(/&/gi, '&');\n\n if (iframely.SCRIPT_RE.test(src)) { // found the script on custom origin or default Iframely CDN\n\n var options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat('cdn', 'cancel', 'nonce'));\n\n var m2 = src.match(iframely.CDN_RE);\n if (m2 || options.cdn) { // ignore non-Iframely hosts such as s.imgur.com/min/embed.js\n iframely.CDN = options.cdn || m2[1];\n }\n\n if (options.cancel) {\n if (options.cancel === '0' || options.cancel === 'false') {\n iframely.RECOVER_HREFS_ON_CANCEL = true;\n }\n delete options.cancel;\n }\n\n if (Object.keys(options).length > 0) {\n // give preferrence to CDN from scripts that have query-string. \n // CDN is most critical for embeds with empty data-iframely-url\n // and those should have at least ?api_key... in script src\n\n return options;\n } // or keep searching\n }\n }\n // should have exited by now if any querystring found...\n return {};\n}\n\nfunction requestSizeOfExistingIframes(domains) {\n\n var iframes = document.querySelectorAll('iframe[src*=\"' + (domains || iframely.DOMAINS).join('\"], iframe[src*=\"') + '\"]');\n for(var i = 0; i < iframes.length; i++) {\n var iframe = iframes[i];\n var src = iframe.src;\n if (src.match(/^(https?:)?\\/\\/[^/]+\\/api\\/iframe\\?.+/)\n || src.match(/^(https?:)?\\/\\/[^/]+\\/\\w+(\\?.*)?$/)) {\n messaging.postMessage({\n method: 'getSize'\n }, '*', iframe.contentWindow);\n }\n }\n} \n\nfunction nonTextChildCount(element) {\n var count = 0;\n for(var i = 0; i < element.childNodes.length; i++) {\n var el = element.childNodes[i];\n if (el.nodeType === Node.TEXT_NODE) {\n var text = el.textContent || el.innerText;\n text = text.replace(/\\s|\\n/g, '');\n if (text) {\n // Do not skip text node with text.\n count++;\n }\n } else if (el.nodeType === Node.ELEMENT_NODE) {\n count++;\n }\n }\n return count;\n}\n\nfunction containsString(list, findValue) {\n var value, i = 0;\n while (i < list.length) {\n value = list[i];\n\n if (value == findValue) {\n return true;\n }\n\n if (value && value.test && value.test(findValue)) {\n return true;\n }\n\n i++;\n }\n}\n\nvar parseQueryString = exports.parseQueryString = function(url, allowed_query_string) {\n var query = url.match(/\\?(.+)/i);\n if (query) {\n query = query[1];\n var data = query.split('&');\n var result = {};\n for(var i=0; i= 0;\n }\n return found && el;\n }\n\n var parentNode = widget.maxWidthWrapper && widget.maxWidthWrapper.parentNode;\n var naNode = widget.maxWidthWrapper;\n\n // Try remove by parentClass first.\n if (iframely.config && iframely.config.parent) {\n // Remove by parent class.\n var parentElement = findParent(widget.maxWidthWrapper, iframely.config.parent);\n\n if (parentElement) {\n parentNode = parentElement.parentNode;\n naNode = parentElement;\n }\n }\n\n if (widget.url) {\n var text = widget.iframe && (widget.iframe.textContent || widget.iframe.innerText);\n\n iframely.triggerAsync('cancel', widget.url, parentNode, text, naNode.nextSibling);\n }\n // Re-creating a link if people had it as text is now deprecated (see in deprecated.js)\n // New use: iframely.on('cancel', function(url, parentNode, text) {...} );\n\n parentNode.removeChild(naNode);\n};\n\n//# sourceURL=webpack:///./widget-cancel.js?\n}"); - -/***/ }, - -/***/ "./widget-click.js" -/*!*************************!*\ - !*** ./widget-click.js ***! - \*************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('message', function(widget, message) {\n if (message.method === 'open-href' || message.method === 'click') {\n iframely.trigger(message.method, message.href);\n }\n});\n\n// Do not override user defined handler.\nif (!iframely.openHref) {\n iframely.openHref = function(href) {\n if (href.indexOf(window.location.origin) === 0) {\n // Redirect top on same origin.\n window.location.href = href;\n } else {\n // Open new tab on another origin.\n window.open(href, '_blank', 'noopener');\n }\n };\n}\n\niframely.on('open-href', function(href) {\n iframely.triggerAsync('click', href);\n iframely.openHref(href);\n});\n\n//# sourceURL=webpack:///./widget-click.js?\n}"); - -/***/ }, - -/***/ "./widget-options.js" -/*!***************************!*\ - !*** ./widget-options.js ***! - \***************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('message', function(widget, message) {\n if (message.method === 'setIframelyEmbedOptions') {\n iframely.trigger('options', widget, message.data);\n }\n});\n\n\n//# sourceURL=webpack:///./widget-options.js?\n}"); - -/***/ }, - -/***/ "./widget-resize.js" -/*!**************************!*\ - !*** ./widget-resize.js ***! - \**************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { - -eval("{var utils = __webpack_require__(/*! ./utils */ \"./utils.js\");\nvar iframely = __webpack_require__(/*! ./iframely */ \"./iframely.js\");\n\niframely.on('message', function(widget, message) {\n\n if (message.method === 'setIframelyWidgetSize' \n || message.method === 'resize' \n || message.method === 'setIframelyEmbedData' \n || message.type === 'embed-size'\n || message.context === 'iframe.resize') {\n\n var frame_styles = null;\n\n if (message.data && message.data.media && message.data.media.frame_style) {\n\n message.data.media.frame_style.split(';').forEach(function(str) {\n\n if(str.trim() !== '' && str.indexOf(':') > -1) {\n var props = str.split(':');\n if (props.length === 2) {\n frame_styles = frame_styles || {};\n frame_styles[props[0].trim()] = props[1].trim();\n }\n }\n });\n\n widgetDecorate(widget, frame_styles);\n\n } else if (message.method === 'setIframelyEmbedData') {\n\n // setIframelyEmbedData always sets frame_style. If not - reset.\n // setIframelyEmbedData without message.data resets border.\n widgetDecorate(widget, null);\n }\n\n var media = message.data && message.data.media;\n if (!media && message.height) {\n media = {\n height: message.height,\n 'max-width': 'keep'\n };\n }\n\n widgetResize(widget, media);\n }\n});\n\n// All frame_style attributes.\nvar resetWrapperBorderStyles = {'border': '', 'border-radius': '', 'box-shadow': '', 'overflow': ''};\nvar resetIframeBorderStyles = {'border': '0', 'border-radius': '', 'box-shadow': '', 'overflow': ''};\n\nfunction widgetDecorate(widget, styles) {\n\n if (styles && widget && widget.iframe) {\n\n if (styles['border-radius']) {\n // fix for Chrome?\n styles.overflow = 'hidden';\n utils.setStyles(widget.aspectWrapper, styles);\n } else {\n utils.setStyles(widget.iframe, styles);\n }\n\n } else if (!styles && widget && widget.iframe) {\n\n utils.setStyles(widget.aspectWrapper, resetWrapperBorderStyles);\n utils.setStyles(widget.iframe, resetIframeBorderStyles);\n }\n}\n\nfunction getTotalBorderWidth(widget) {\n\n // Get frame style from iframe or aspect wrapper as in widgetDecorate for Chrome fix.\n var frameStylesBorder = \n (widget.iframe && widget.iframe.style.border) \n || (widget.aspectWrapper && widget.aspectWrapper.style.border);\n\n // Get iframe border width from frame style.\n var borderWidth = frameStylesBorder && frameStylesBorder.match(/(\\d+)px/) || 0;\n if (borderWidth) {\n borderWidth = parseInt(borderWidth[1]);\n // For width and height border size will be 2x.\n borderWidth = borderWidth * 2;\n }\n\n return borderWidth;\n}\n\nfunction widgetResize(widget, media) {\n\n if (media && Object.keys(media).length > 0 && widget) {\n\n var borderWidth = getTotalBorderWidth(widget);\n\n var oldIframeHeight = window.getComputedStyle && window.getComputedStyle(widget.iframe).getPropertyValue('height');\n\n\n var maxWidth = media['max-width'];\n if (typeof maxWidth === 'number') {\n // Can be max-width: 56vh.\n maxWidth += borderWidth;\n }\n\n utils.setStyles(widget.maxWidthWrapper, {\n 'max-width': maxWidth,\n 'min-width': media['min-width'] && (media['min-width'] + borderWidth),\n width: media.width && (media.width + borderWidth)\n });\n\n if (media.scrolling && widget.iframe) {\n widget.iframe.setAttribute('scrolling', media.scrolling);\n }\n\n var aspectRatio = media['aspect-ratio'];\n\n // If no aspect and height - do not change aspect wrapper.\n if (aspectRatio || media.height) {\n utils.setStyles(widget.aspectWrapper, {\n paddingBottom: aspectRatio ? (Math.round(1000 * 100 / aspectRatio) / 1000 + '%') : 0, // if fixed-size, it will get set to 0\n paddingTop: aspectRatio && media['padding-bottom'], // if a fixed-height padding at the bottom of responsive div is required\n height: aspectRatio ? 0 : (media.height && (media.height + borderWidth)) // if defined\n });\n }\n\n\n var currentHeight = window.getComputedStyle && window.getComputedStyle(widget.iframe).getPropertyValue('height');\n\n if (oldIframeHeight && oldIframeHeight !== currentHeight) {\n iframely.triggerAsync('heightChanged', widget.iframe, oldIframeHeight, currentHeight);\n }\n\n }\n}\n\n\n//# sourceURL=webpack:///./widget-resize.js?\n}"); - -/***/ } - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ if (!(moduleId in __webpack_modules__)) { -/******/ delete __webpack_module_cache__[moduleId]; -/******/ var e = new Error("Cannot find module '" + moduleId + "'"); -/******/ e.code = 'MODULE_NOT_FOUND'; -/******/ throw e; -/******/ } -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/global */ -/******/ (() => { -/******/ __webpack_require__.g = (function() { -/******/ if (typeof globalThis === 'object') return globalThis; -/******/ try { -/******/ return this || new Function('return this')(); -/******/ } catch (e) { -/******/ if (typeof window === 'object') return window; -/******/ } -/******/ })(); -/******/ })(); -/******/ -/************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module can't be inlined because the eval devtool is used. -/******/ var __webpack_exports__ = __webpack_require__("./index.js"); -/******/ -/******/ })() -; \ No newline at end of file +//#endregion +})(); \ No newline at end of file diff --git a/dist/embed.min.js b/dist/embed.min.js index efcca27..c809725 100644 --- a/dist/embed.min.js +++ b/dist/embed.min.js @@ -1 +1 @@ -(()=>{var e={679(e,t,r){var i=r(672),a=r(774);a.on("load",function(e,t){if(e&&e.nodeName&&"string"==typeof t){var r=document.createElement("a");r.setAttribute("href",t),e.appendChild(r),a.trigger("load",r)}}),a.on("load",function(e){if(!e&&!a.import)for(var t=document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"),r=0;r4&&(t=null);var i=t&&t.parentNode;i&&i.getAttribute("class")&&i.getAttribute("class").split(" ").indexOf(a.MAXWIDTH_WRAPPER_CLASS)>-1&&(t.removeAttribute("style"),t.removeAttribute("class"),i.removeAttribute("style"))}function c(e){function t(e,t){return e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function r(t){var r=t.text||t.textContent||t.innerHTML||"",a=i.createScript();a.type="text/javascript";for(var n=0;n1&&function(e){var t=i.createScript(),r=[],o=[],s=null;function c(e,t){n[e]||(n[e]=[]),n[e].push(t)}function l(e){var t=e.getAttribute("data-iframely-url"),n=t.match(a.ID_RE),d=n&&n[1],l=i.parseQueryString(t,a.SUPPORTED_QUERY_STRING.concat("url")),p=l.url;delete l.url;var u="0"===l.import||"false"===l.import||"1"===l.playerjs||"true"===l.playerjs;if(!u){var m=t.match(a.BASE_RE);l.CDN=m&&m[0],s?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(s,Object.keys(s).sort())&&(u=!0):s=l}u?a.trigger("load",e):d?(e.setAttribute("data-import-uri",d),-1===o.indexOf(d)&&o.push(d),c(d,e)):(p||(p=e.getAttribute("href")),(s.key||s.api_key||a.config.api_key||a.config.key)&&p?(e.setAttribute("data-import-uri",p),-1===r.indexOf(p)&&r.push(p),c(p,e)):a.trigger("load",e))}for(var p=0;p0||o.length>0?((s=s||{}).touch=a.isTouch(),s.flash=function(){var e=!1;try{e=!!new ActiveXObject("ShockwaveFlash.ShockwaveFlash")}catch(t){e=!(!navigator.mimeTypes||null==navigator.mimeTypes["application/x-shockwave-flash"]||!navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)}return e}(),s.app=1,a.config.theme&&(s.theme=a.config.theme),r.length>0&&(s.uri=r),o.length>0&&(s.ids=o.join("&")),s.v=a.VERSION,t.src=i.getEndpoint("/api/import/v2",s,a.SUPPORTED_QUERY_STRING),t.onerror=function(){d()},document.head.appendChild(t),a.import=t):(d(),a.trigger("load"))}(t)}}),a.on("load",function(e,t){if(e&&e.uri&&(e.html||e.cancel)){var r=n[e.uri];if(r)for(var i=0;i1&&function(e,t){for(var r=0,i=0;i=77},369(e,t,r){var i=r(774),a=r(672);function n(e,t){for(var r,i=0;i-1?t?"IFRAME"===t.tagName?n(t,e):o(t,e):(i.extendOptions({theme:e}),o(document,e),i.trigger("set-theme",e)):console.warn('Using iframely.setTheme with not supported theme: "'+e+'". Supported themes are: '+i.SUPPORTED_THEMES.join(", "))}},672(e,t,r){var i=r(774),a=r(369);i.on("init",function(){i.extendOptions(function(){for(var e=document.querySelectorAll('script[src*="embed.js"], script[src*="iframely.js"]'),t=0;t0)return a}}return{}}()),function(){var e="iframely-styles",t=document.getElementById(e);if(!t){var r=".iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}";(t=document.createElement("style")).id=e,t.type="text/css",o(t),t.styleSheet?t.styleSheet.cssText=r:t.innerHTML=r,document.getElementsByTagName("head")[0].appendChild(t)}}(),i.config.theme&&i.setTheme(i.config.theme),function(e){for(var t=document.querySelectorAll('iframe[src*="'+(e||i.DOMAINS).join('"], iframe[src*="')+'"]'),r=0;r2||t&&r.getAttribute("class")!==i.ASPECT_WRAPPER_CLASS||!t&&"relative"!==r.style.position&&r.getAttribute("class")!==i.ASPECT_WRAPPER_CLASS)){var a=r.parentNode;if(!(!a||"DIV"!==a.nodeName||s(a)>1||t&&a.getAttribute("class")&&-1===a.getAttribute("class").split(" ").indexOf(i.MAXWIDTH_WRAPPER_CLASS)||!t&&a.getAttribute("class")&&!a.getAttribute("class").match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:a}}};t.addDefaultWrappers=function(e){var t=e.parentNode,r=document.createElement("div");r.className=i.MAXWIDTH_WRAPPER_CLASS;var a=document.createElement("div");return a.className=i.ASPECT_WRAPPER_CLASS,r.appendChild(a),t.insertBefore(r,e),{aspectWrapper:a,maxWidthWrapper:r}},t.getWidget=function(e){var t=n(e);if(t){var r={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper};if("A"===e.nodeName&&e.hasAttribute("href"))r.url=e.getAttribute("href");else if(e.hasAttribute("src")&&/url=/.test(e.getAttribute("src"))){var i=l(e.getAttribute("src"));i.url&&(r.url=i.url)}return r}},i.getElementComputedStyle=function(e,t){return window.getComputedStyle&&window.getComputedStyle(e).getPropertyValue(t)},t.setStyles=function(e,t){e&&Object.keys(t).forEach(function(r){var a=t[r];("number"==typeof a||"string"==typeof a&&/^(\d+)?\.?(\d+)$/.test(a))&&(a+="px");var n=e.style[r];window.getComputedStyle&&(i.getElementComputedStyle(e,r)==a||"iframely-responsive"==e.className&&"paddingBottom"===r&&!n&&/^56\.2\d+%$/.test(a)||"max-width"===r&&"keep"===a)||(e.style[r]=a||"")})};var o=t.applyNonce=function(e){i.config.nonce&&(e.nonce=i.config.nonce)},d=t.addQueryString=function(e,t){var r="";return Object.keys(t).forEach(function(i){var a=t[i];if("[object Array]"===Object.prototype.toString.call(a)){var n=a.map(function(e){return i+"="+encodeURIComponent(e)});r+="&"+n.join("&")}else void 0!==a&&-1===e.indexOf(i+"=")&&("boolean"==typeof a&&"_"!==i.charAt(0)&&(a=a?1:0),r+="&"+i+"="+encodeURIComponent(a))}),e+(""!==r?(e.indexOf("?")>-1?"&":"?")+r.replace(/^&/,""):"")};function s(e){for(var t=0,r=0;r=0;return r&&e}(e.maxWidthWrapper,i.config.parent);a&&(t=a.parentNode,r=a)}if(e.url){var n=e.iframe&&(e.iframe.textContent||e.iframe.innerText);i.triggerAsync("cancel",e.url,t,n,r.nextSibling)}t.removeChild(r)}else console.warn("iframely.cancelWidget called without widget param")}},612(e,t,r){var i=r(774);i.on("message",function(e,t){"open-href"!==t.method&&"click"!==t.method||i.trigger(t.method,t.href)}),i.openHref||(i.openHref=function(e){0===e.indexOf(window.location.origin)?window.location.href=e:window.open(e,"_blank","noopener")}),i.on("open-href",function(e){i.triggerAsync("click",e),i.openHref(e)})},742(e,t,r){var i=r(774);i.on("message",function(e,t){"setIframelyEmbedOptions"===t.method&&i.trigger("options",e,t.data)})},850(e,t,r){var i=r(672),a=r(774);a.on("message",function(e,t){if("setIframelyWidgetSize"===t.method||"resize"===t.method||"setIframelyEmbedData"===t.method||"embed-size"===t.type||"iframe.resize"===t.context){var r=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(";").forEach(function(e){if(""!==e.trim()&&e.indexOf(":")>-1){var t=e.split(":");2===t.length&&((r=r||{})[t[0].trim()]=t[1].trim())}}),d(e,r)):"setIframelyEmbedData"===t.method&&d(e,null);var n=t.data&&t.data.media;!n&&t.height&&(n={height:t.height,"max-width":"keep"}),function(e,t){if(t&&Object.keys(t).length>0&&e){var r=function(e){var t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,r=t&&t.match(/(\d+)px/)||0;return r&&(r=parseInt(r[1]),r*=2),r}(e),n=window.getComputedStyle&&window.getComputedStyle(e.iframe).getPropertyValue("height"),o=t["max-width"];"number"==typeof o&&(o+=r),i.setStyles(e.maxWidthWrapper,{"max-width":o,"min-width":t["min-width"]&&t["min-width"]+r,width:t.width&&t.width+r}),t.scrolling&&e.iframe&&e.iframe.setAttribute("scrolling",t.scrolling);var d=t["aspect-ratio"];(d||t.height)&&i.setStyles(e.aspectWrapper,{paddingBottom:d?Math.round(1e5/d)/1e3+"%":0,paddingTop:d&&t["padding-bottom"],height:d?0:t.height&&t.height+r});var s=window.getComputedStyle&&window.getComputedStyle(e.iframe).getPropertyValue("height");n&&n!==s&&a.triggerAsync("heightChanged",e.iframe,n,s)}}(e,n)}});var n={border:"","border-radius":"","box-shadow":"",overflow:""},o={border:"0","border-radius":"","box-shadow":"",overflow:""};function d(e,t){t&&e&&e.iframe?t["border-radius"]?(t.overflow="hidden",i.setStyles(e.aspectWrapper,t)):i.setStyles(e.iframe,t):!t&&e&&e.iframe&&(i.setStyles(e.aspectWrapper,n),i.setStyles(e.iframe,o))}}},t={};function r(i){var a=t[i];if(void 0!==a)return a.exports;var n=t[i]={exports:{}};return e[i](n,n.exports,r),n.exports}r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),(()=>{r(331);var e=r(774);e._loaded||(e._loaded=!0,r(54),r(912),r(56),r(908),r(472),r(679),r(573),r(324),r(648),r(850),r(612),r(742),r(916),r(291),e.trigger("init"))})()})(); \ No newline at end of file +(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{},(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(e.config.autorun===void 0||e.config.autorun!==!1)&&e.trigger(`load`)});function t(){e.VERSION=1,e.ASPECT_WRAPPER_CLASS=`iframely-responsive`,e.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,e.LOADER_CLASS=`iframely-loader`,e.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],e.CDN=e.CDN||e.DOMAINS[0],e.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,e.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,e.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],e.SUPPORTED_THEMES=[`auto`,`light`,`dark`],e.LAZY_IFRAME_SHOW_TIMEOUT=3e3,e.LAZY_IFRAME_FADE_TIMEOUT=200,e.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,e.RECOVER_HREFS_ON_CANCEL=!1,e.SHADOW=`iframely-shadow`,e.SUPPORT_IFRAME_LOADING_ATTR=!0}var n=e=>{window.requestAnimationFrame(e)},r={};function i(t,i,a){(r[t]||[]).forEach(t=>{i?n(()=>{t.apply(e,a)}):t.apply(e,a)}),t===`init`&&(r[t]=[])}function a(){e.on=(e,t)=>{(r[e]=r[e]||[]).push(t)},e.trigger=(e,...t)=>{i(e,!1,t)},e.triggerAsync=(e,...t)=>{i(e,!0,t)}}function o(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function s(e,t){let n;for(let r=0;r{let t=c(document,e);return t||=l(document,e),t},o((t,n)=>{if(n&&(n.method||n.type||n.context)){let r=e.findIframe({contentWindow:t.source,src:n.src||n.context,domains:n.domains!==`all`&&e.DOMAINS.concat(e.CDN)});if(r){let t=m(r);t&&n.url&&(t.url=n.url),e.trigger(`message`,t,n)}}})}function d(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){e.on(`init`,()=>{e.extendOptions(b()),_(),e.config.theme&&e.setTheme(e.config.theme),x(e.DOMAINS.concat(e.CDN.replace(/^https?:\/\//,``)))}),e.load=function(...t){e.trigger(`load`,...t)},e.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),e.extendOptions=t=>{t&&Object.keys(t).forEach(n=>{let r=t[n]===0||t[n]===`0`||t[n]===!1||t[n]===`false`?!1:t[n]===1||t[n]===`1`||t[n]===!0||t[n]===`true`||t[n];e.config[n]!==!1&&(e.config[n]=r)})}}function f(t,n){let r=t.parentNode;if(!r||r.nodeName!==`DIV`||S(r)>2||n&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||S(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function p(t){let n=t.parentNode,r=document.createElement(`div`);r.className=e.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=e.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,t),{aspectWrapper:i,maxWidthWrapper:r}}function m(e){let t=f(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=w(r);e.url&&(n.url=e.url)}return n}function h(t,n){t&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=t.style,o=a[r];e.getElementComputedStyle(t,r)!=i&&!(t.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function g(t){e.config.nonce&&(t.nonce=e.config.nonce)}function _(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,g(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function v(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function y(t,n,r){let i=t;if(/^(https?:)?\/\//i.test(t)||(i=(n&&n.CDN||e.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=v(i,n)),r&&r.length){let t={},n=Object.keys(e.config);for(let i=0;i0)return t}}return{}}function x(t){let n=document.querySelectorAll(`iframe[src*="`+(t||e.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{d({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},O(e)),E[t]=n),n}function O(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function k(){e.on(`init`,()=>{e.extendOptions({intersection:1})}),e.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},D(n).observe(e.iframe)}})}function A(e,t){d({method:`setTheme`,data:t},`*`,e.contentWindow)}function j(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{t&&e.SUPPORTED_THEMES.indexOf(t)>-1?n?n.tagName===`IFRAME`?A(n,t):j(n,t):(e.extendOptions({theme:t}),j(document,t),e.trigger(`set-theme`,t)):console.warn(`Using iframely.setTheme with not supported theme: "`+t+`". Supported themes are: `+e.SUPPORTED_THEMES.join(`, `))}}var M={};function N(){e.on(`load`,t=>{if(!t&&e.config.import!==!1&&L()&&!e.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&P(e)}}),e.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=M[e.uri];if(n)for(let r=0;r{e.trigger(`import-loaded`,t),t.widgets.forEach(n=>{e.trigger(`load`,n,t)}),I()},e.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,e.on(`import-widget-ready`,R),e.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function P(t){let n=T(),r=[],i=[],a=null;function o(e,t){M[e]||(M[e]=[]),M[e].push(t)}function s(t){let n=t.getAttribute(`data-iframely-url`),s=n.match(e.ID_RE),c=s&&s[1],l=w(n,e.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let t=n.match(e.BASE_RE);l.CDN=t&&t[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?e.trigger(`load`,t):c?(t.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,t)):(u||=t.getAttribute(`href`),(a.key||a.api_key||e.config.api_key||e.config.key)&&u?(t.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,t)):e.trigger(`load`,t))}for(let e=0;e0||i.length>0?(a||={},a.touch=e.isTouch(),a.flash=!1,a.app=1,e.config.theme&&(a.theme=e.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=e.VERSION,n.src=y(`/api/import/v2`,a,e.SUPPORTED_QUERY_STRING),n.onerror=()=>{I()},document.head.appendChild(n),e.import=n):(I(),e.trigger(`load`))}function F(t,n,r){let i=t.cancel,a=t.shadow,o=t.renderEvent,s=f(n,!0);if(i)e.cancelWidget(m(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=t.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:t.context,stylesIds:t.stylesIds,stylesDict:r.commonShadowStyles};e.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),e.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),z(i);c.removeChild(l),o&&setTimeout(()=>{R(c)},e.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function I(){delete e.import;let t=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function z(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=T();r.type=`text/javascript`;for(let e=0;e{if(t&&t.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),t.appendChild(r),e.trigger(`load`,r)}}),e.on(`load`,t=>{if(!t&&!e.import){let t=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&V(e)})}function V(t){if(!t.getAttribute(`data-iframely-url`)&&!t.getAttribute(`href`))return;let n,r=t.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=y(r,{v:e.VERSION,app:1,theme:e.config.theme});else if((e.config.api_key||e.config.key)&&e.CDN){if(!t.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,t);return}n=y(`/api/iframe`,{url:t.getAttribute(`href`),v:e.VERSION,app:1,theme:e.config.theme},e.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)t.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),t.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,t.getAttribute(`data-img`));let i=t.hasAttribute(`data-lazy`)||t.hasAttribute(`data-img`)||/&lazy=1/.test(n)||e.config.lazy,a=t.textContent;a&&a!==``&&(r.textContent=a);let o=f(t,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=p(t),t.parentNode.removeChild(t);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),e.trigger(`load`,r)):(r.setAttribute(`src`,n),e.trigger(`iframe-ready`,r))}}function H(){e.on(`load`,t=>{if(t&&t.nodeName===`IFRAME`&&t.hasAttribute(`data-iframely-url`)&&t.hasAttribute(`data-img`)&&!t.getAttribute(`src`)){let n=t.getAttribute(`data-img`);t.removeAttribute(`data-img`),t.setAttribute(`data-img-created`,``);let r=m(t),i=t.getAttribute(`data-iframely-url`);r&&(U(r,i,n),i=v(i,{img:1}),t.setAttribute(`data-iframely-url`,i),new Z(r)),e.trigger(`load`,t)}}),e.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(K(e),n=Y(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=Y(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=Y(e),n?.registerLoadingTimeout())})}function U(t,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let t=w(n),r={};for(let e in t)e.indexOf(`_`)===0&&(r[e]=t[e]);if(t.media&&(r.media=t.media),n.match(/\/api\/iframe/))i=y(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:t.url,api_key:t.api_key,key:t.key},r));else if(n.match(e.ID_RE))i=y(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);h(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,e.LOADER_CLASS),a.appendChild(o);let s=e.getElementComputedStyle(t.aspectWrapper,`padding-top`),c=e.getElementComputedStyle(t.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let e=document.createElement(`div`);h(e,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),e.appendChild(a),t.aspectWrapper.appendChild(e)}else t.aspectWrapper.appendChild(a)}function W(e,t){let n=0;for(let r=0;r1&&W(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var q=[];function J(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),q.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{K(this.widget)},e.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),X(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},e.LAZY_IFRAME_SHOW_TIMEOUT)}};function ne(){e.on(`load`,t=>{if(!t){let t=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&re(e)})}function re(t){let n=m(t),r=t.getAttribute(`data-iframely-url`),i=t.hasAttribute(`data-img-created`)||t.hasAttribute(`data-img`),a=!i&&e.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let t={v:e.VERSION,app:1,theme:e.config.theme};!a&&e.config.intersection&&(t.lazy=1),r=y(r,t)}a&&t.setAttribute(`loading`,`lazy`),i&&e.SUPPORT_IFRAME_LOADING_ATTR&&t.setAttribute(`loading`,`edge`),t.setAttribute(`src`,r||``),t.removeAttribute(`data-iframely-url`),e.trigger(`iframe-ready`,t)}function ie(){e.on(`message`,(t,n)=>{n.method===`cancelWidget`&&e.cancelWidget(t)}),e.cancelWidget=t=>{if(!t){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=t.maxWidthWrapper&&t.maxWidthWrapper.parentNode,i=t.maxWidthWrapper;if(e.config&&e.config.parent){let a=n(t.maxWidthWrapper,String(e.config.parent));a&&(r=a.parentNode,i=a)}if(t.url){let n=t.iframe&&t.iframe.textContent;e.triggerAsync(`cancel`,t.url,r,n,i.nextSibling)}r.removeChild(i)}}var ae={border:``,"border-radius":``,"box-shadow":``,overflow:``},oe={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function se(){e.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),Q(e,n)):t.method===`setIframelyEmbedData`&&Q(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),le(e,r)}})}function Q(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,h(e.aspectWrapper,t)):h(e.iframe,t):!t&&e&&e.iframe&&(h(e.aspectWrapper,ae),h(e.iframe,oe))}function ce(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function le(t,n){if(n&&Object.keys(n).length>0&&t){let r=ce(t),i=window.getComputedStyle(t.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),h(t.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&t.iframe&&t.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&h(t.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(t.iframe).getPropertyValue(`height`);i&&i!==s&&e.triggerAsync(`heightChanged`,t.iframe,i,s)}}function $(){e.on(`message`,(t,n)=>{(n.method===`open-href`||n.method===`click`)&&e.trigger(n.method,n.href)}),e.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},e.on(`open-href`,t=>{e.triggerAsync(`click`,t),e.openHref(t)})}function ue(){e.on(`message`,(t,n)=>{n.method===`setIframelyEmbedOptions`&&e.trigger(`options`,t,n.data)})}function de(){e.widgets=e.widgets||{},e.widgets.load=e.load,e.events||(e.events={},e.events.on=e.on,e.events.trigger=e.trigger),e.on(`cancel`,(t,n,r,i)=>{if(e.RECOVER_HREFS_ON_CANCEL&&!r&&(r=t),t&&n&&r&&r!==``){let e=document.createElement(`a`);e.setAttribute(`href`,t),e.setAttribute(`target`,`_blank`),e.setAttribute(`rel`,`noopener`),e.textContent=r,i?n.insertBefore(e,i):n.appendChild(e)}})}e._loaded||(e._loaded=!0,t(),a(),ee(),u(),k(),te(),N(),B(),H(),ne(),ie(),se(),$(),ue(),de(),e.trigger(`init`))})(); \ No newline at end of file diff --git a/dist/esm/chunks/deprecated.js b/dist/esm/chunks/deprecated.js new file mode 100644 index 0000000..aa2f874 --- /dev/null +++ b/dist/esm/chunks/deprecated.js @@ -0,0 +1,1024 @@ +import { t as iframely } from "./iframely.js"; +//#region src/dom-ready.ts +var DOMReady = (f) => { + if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(f, 0); + document.addEventListener("DOMContentLoaded", f); +}; +DOMReady(() => { + if (typeof iframely.config.autorun === "undefined" || iframely.config.autorun !== false) iframely.trigger("load"); +}); +//#endregion +//#region src/const.ts +function boot$14() { + iframely.VERSION = 1; + iframely.ASPECT_WRAPPER_CLASS = "iframely-responsive"; + iframely.MAXWIDTH_WRAPPER_CLASS = "iframely-embed"; + iframely.LOADER_CLASS = "iframely-loader"; + iframely.DOMAINS = [ + "cdn.iframe.ly", + "iframe.ly", + "if-cdn.com", + "iframely.net" + ]; + iframely.CDN = iframely.CDN || iframely.DOMAINS[0]; + iframely.BASE_RE = /^(?:https?:)?\/\/[^/]+/i; + iframely.ID_RE = /^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/; + iframely.SCRIPT_RE = /^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i; + iframely.CDN_RE = /^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i; + iframely.SUPPORTED_QUERY_STRING = [ + "api_key", + "key", + "iframe", + "html5", + "playerjs", + "align", + "language", + "media", + "maxwidth", + "maxheight", + "lazy", + "import", + "parent", + "shadow", + "click_to_play", + "autoplay", + "mute", + "card", + "consent", + "theme", + /^_.+/ + ]; + iframely.SUPPORTED_THEMES = [ + "auto", + "light", + "dark" + ]; + iframely.LAZY_IFRAME_SHOW_TIMEOUT = 3e3; + iframely.LAZY_IFRAME_FADE_TIMEOUT = 200; + iframely.CLEAR_WRAPPER_STYLES_TIMEOUT = 3e3; + iframely.RECOVER_HREFS_ON_CANCEL = false; + iframely.SHADOW = "iframely-shadow"; + iframely.SUPPORT_IFRAME_LOADING_ATTR = true; +} +//#endregion +//#region src/events.ts +var nextTick = (fn) => { + window.requestAnimationFrame(fn); +}; +var callbacksStack = {}; +function trigger(event, async, args) { + (callbacksStack[event] || []).forEach((cb) => { + if (async) nextTick(() => { + cb.apply(iframely, args); + }); + else cb.apply(iframely, args); + }); + if (event === "init") callbacksStack[event] = []; +} +function boot$13() { + iframely.on = (event, cb) => { + (callbacksStack[event] = callbacksStack[event] || []).push(cb); + }; + iframely.trigger = (event, ...args) => { + trigger(event, false, args); + }; + iframely.triggerAsync = (event, ...args) => { + trigger(event, true, args); + }; +} +//#endregion +//#region src/messaging.ts +function receiveMessage(callback) { + window.addEventListener("message", (e) => { + let message; + try { + if (typeof e.data === "string") message = JSON.parse(e.data); + else if (typeof e.data === "object") message = e.data; + } catch { + if (typeof e.data === "string") { + const m = e.data.match(/heightxPYMx(\d+)/); + if (m) message = { + method: "resize", + height: parseInt(m[1]) + 1, + domains: "all" + }; + } + } + callback(e, message); + }, false); +} +function findIframeByContentWindow(iframes, contentWindow) { + let foundIframe; + for (let i = 0; i < iframes.length && !foundIframe; i++) { + const iframe = iframes[i]; + if (iframe.contentWindow === contentWindow) foundIframe = iframe; + } + return foundIframe; +} +function findIframeInElement(element, options) { + let foundIframe, iframes; + if (options.src) { + iframes = element.querySelectorAll("iframe[src*=\"" + options.src.replace(/^https?:/, "") + "\"]"); + foundIframe = findIframeByContentWindow(iframes, options.contentWindow); + } + if (!foundIframe) { + iframes = options.domains ? element.querySelectorAll("iframe[src*=\"" + (options.domains || iframely.DOMAINS).join("\"], iframe[src*=\"") + "\"]") : element.querySelectorAll("iframe"); + foundIframe = findIframeByContentWindow(iframes, options.contentWindow); + } + return foundIframe; +} +function findIframeInShadowRoots(element, options) { + let foundIframe; + const className = "." + (iframely.config.shadow || iframely.SHADOW); + const shadowRoots = element.querySelectorAll(className); + for (let i = 0; i < shadowRoots.length && !foundIframe; i++) { + const shadowRoot = shadowRoots[i].shadowRoot; + if (shadowRoot) { + foundIframe = findIframeInElement(shadowRoot, options); + if (!foundIframe) foundIframe = findIframeInShadowRoots(shadowRoot, options); + } + } + return foundIframe; +} +function boot$12() { + if (!iframely.findIframe) iframely.findIframe = (options) => { + let foundIframe = findIframeInElement(document, options); + if (!foundIframe) foundIframe = findIframeInShadowRoots(document, options); + return foundIframe; + }; + receiveMessage((e, message) => { + if (message && (message.method || message.type || message.context)) { + const foundIframe = iframely.findIframe({ + contentWindow: e.source, + src: message.src || message.context, + domains: message.domains !== "all" && iframely.DOMAINS.concat(iframely.CDN) + }); + if (foundIframe) { + const widget = getWidget(foundIframe); + if (widget && message.url) widget.url = message.url; + iframely.trigger("message", widget, message); + } + } + }); +} +function postMessage(message, target_url, target) { + if (typeof message === "object") message.context = document.location.href; + const data = JSON.stringify(message); + target_url = target_url || "*"; + target = target || window.parent; + target.postMessage(data, target_url.replace(/([^:]+:\/\/[^/]+).*/, "$1")); +} +//#endregion +//#region src/utils.ts +function boot$11() { + iframely.on("init", () => { + iframely.extendOptions(parseQueryStringFromScriptSrc()); + defineDefaultStyles(); + if (iframely.config.theme) iframely.setTheme(iframely.config.theme); + requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, ""))); + }); + iframely.load = function(...args) { + iframely.trigger("load", ...args); + }; + iframely.getElementComputedStyle = (el, style) => { + return window.getComputedStyle(el).getPropertyValue(style); + }; + iframely.extendOptions = (options) => { + if (!options) return; + Object.keys(options).forEach((key) => { + const new_value = options[key] === 0 || options[key] === "0" || options[key] === false || options[key] === "false" ? false : options[key] === 1 || options[key] === "1" || options[key] === true || options[key] === "true" ? true : options[key]; + if (iframely.config[key] !== false) iframely.config[key] = new_value; + }); + }; +} +function getIframeWrapper(iframe, checkClass) { + const aspectWrapper = iframe.parentNode; + if (!aspectWrapper || aspectWrapper.nodeName !== "DIV" || nonTextChildCount$1(aspectWrapper) > 2 || checkClass && aspectWrapper.getAttribute("class") !== iframely.ASPECT_WRAPPER_CLASS || !checkClass && aspectWrapper.style.position !== "relative" && aspectWrapper.getAttribute("class") !== iframely.ASPECT_WRAPPER_CLASS) return; + const maxWidthWrapper = aspectWrapper.parentNode; + if (!maxWidthWrapper || maxWidthWrapper.nodeName !== "DIV" || nonTextChildCount$1(maxWidthWrapper) > 1 || checkClass && maxWidthWrapper.getAttribute("class") && maxWidthWrapper.getAttribute("class").split(" ").indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) === -1 || !checkClass && maxWidthWrapper.getAttribute("class") && !maxWidthWrapper.getAttribute("class").match(/iframely/i)) return; + return { + aspectWrapper, + maxWidthWrapper + }; +} +function addDefaultWrappers(el) { + const parentNode = el.parentNode; + const maxWidthWrapper = document.createElement("div"); + maxWidthWrapper.className = iframely.MAXWIDTH_WRAPPER_CLASS; + const aspectWrapper = document.createElement("div"); + aspectWrapper.className = iframely.ASPECT_WRAPPER_CLASS; + maxWidthWrapper.appendChild(aspectWrapper); + parentNode.insertBefore(maxWidthWrapper, el); + return { + aspectWrapper, + maxWidthWrapper + }; +} +function getWidget(iframe) { + const wrapper = getIframeWrapper(iframe); + if (!wrapper) return; + const widget = { + iframe, + aspectWrapper: wrapper.aspectWrapper, + maxWidthWrapper: wrapper.maxWidthWrapper + }; + const src = iframe.getAttribute("src"); + if (iframe.nodeName === "A" && iframe.hasAttribute("href")) widget.url = iframe.getAttribute("href"); + else if (src && /url=/.test(src)) { + const qs = parseQueryString(src); + if (qs.url) widget.url = qs.url; + } + return widget; +} +function setStyles(el, styles) { + if (el) Object.keys(styles).forEach((key) => { + let value = styles[key]; + if (typeof value === "number" || typeof value === "string" && /^(\d+)?\.?(\d+)$/.test(value)) value = value + "px"; + const elStyle = el.style; + const currentValue = elStyle[key]; + if (iframely.getElementComputedStyle(el, key) != value && !(el.className == "iframely-responsive" && key === "paddingBottom" && !currentValue && /^56\.2\d+%$/.test(value)) && !(key === "max-width" && value === "keep")) elStyle[key] = value || ""; + }); +} +function applyNonce(element) { + if (iframely.config.nonce) element.nonce = iframely.config.nonce; +} +function defineDefaultStyles() { + const iframelyStylesId = "iframely-styles"; + let styles = document.getElementById(iframelyStylesId); + if (!styles) { + const iframelyStyles = ".iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}"; + styles = document.createElement("style"); + styles.id = iframelyStylesId; + applyNonce(styles); + styles.innerHTML = iframelyStyles; + document.getElementsByTagName("head")[0].appendChild(styles); + } +} +function addQueryString(href, options) { + let query_string = ""; + Object.keys(options).forEach((key) => { + let value = options[key]; + if (Array.isArray(value)) { + const values = value.map((uri) => key + "=" + encodeURIComponent(uri)); + query_string += "&" + values.join("&"); + } else if (typeof value !== "undefined" && href.indexOf(key + "=") === -1) { + if (typeof value === "boolean" && key.charAt(0) !== "_") value = value ? 1 : 0; + query_string += "&" + key + "=" + encodeURIComponent(value); + } + }); + return href + (query_string !== "" ? (href.indexOf("?") > -1 ? "&" : "?") + query_string.replace(/^&/, "") : ""); +} +function getEndpoint(src, options, config_params) { + let endpoint = src; + if (!/^(https?:)?\/\//i.test(src)) { + endpoint = (options && options.CDN || iframely.CDN) + endpoint; + if (options) delete options.CDN; + } + if (!/^(?:https?:)?\/\//i.test(endpoint)) endpoint = "//" + endpoint; + if (options) endpoint = addQueryString(endpoint, options); + if (config_params && config_params.length) { + const more_options = {}; + const iframely_config_keys = Object.keys(iframely.config); + for (let i = 0; i < iframely_config_keys.length; i++) { + const key = iframely_config_keys[i]; + if (containsString(config_params, key)) more_options[key] = iframely.config[key]; + } + endpoint = addQueryString(endpoint, more_options); + } + if (/^(https?:)?\/\//i.test(endpoint) && !endpoint.match(/^(https?:)?\/\//i)[1] && document.location.protocol !== "http:" && document.location.protocol !== "https:") endpoint = "https:" + endpoint; + return endpoint; +} +function parseQueryStringFromScriptSrc() { + const scripts = document.querySelectorAll("script[src*=\"embed.js\"], script[src*=\"iframely.js\"]"); + for (let i = 0; i < scripts.length; i++) { + const src = scripts[i].getAttribute("src").replace(/&/gi, "&"); + if (iframely.SCRIPT_RE.test(src)) { + const options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat("cdn", "cancel", "nonce")); + const m2 = src.match(iframely.CDN_RE); + if (m2 || options.cdn) iframely.CDN = options.cdn || m2[1]; + if (options.cancel) { + if (options.cancel === "0" || options.cancel === "false") iframely.RECOVER_HREFS_ON_CANCEL = true; + delete options.cancel; + } + if (Object.keys(options).length > 0) return options; + } + } + return {}; +} +function requestSizeOfExistingIframes(domains) { + const iframes = document.querySelectorAll("iframe[src*=\"" + (domains || iframely.DOMAINS).join("\"], iframe[src*=\"") + "\"]"); + for (let i = 0; i < iframes.length; i++) { + const iframe = iframes[i]; + const src = iframe.src; + if (src.match(/^(https?:)?\/\/[^/]+\/api\/iframe\?.+/) || src.match(/^(https?:)?\/\/[^/]+\/\w+(\?.*)?$/)) postMessage({ method: "getSize" }, "*", iframe.contentWindow); + } +} +function nonTextChildCount$1(element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.TEXT_NODE) { + if ((el.textContent || "").replace(/\s|\n/g, "")) count++; + } else if (el.nodeType === Node.ELEMENT_NODE) count++; + } + return count; +} +function containsString(list, findValue) { + let value, i = 0; + while (i < list.length) { + value = list[i]; + if (value == findValue) return true; + if (value instanceof RegExp && value.test(findValue)) return true; + i++; + } + return false; +} +function parseQueryString(url, allowed_query_string) { + const query = url.match(/\?(.+)/i); + if (query) { + const data = query[1].split("&"); + const result = {}; + for (let i = 0; i < data.length; i++) { + const item = data[i].split("="); + if (!allowed_query_string || containsString(allowed_query_string, item[0])) result[item[0]] = decodeURIComponent(item[1]); + } + return result; + } else return {}; +} +function createScript() { + const script = document.createElement("script"); + applyNonce(script); + return script; +} +//#endregion +//#region src/intersection.ts +var observers = {}; +function getObserver(options) { + const optionsKey = JSON.stringify(options); + let observer = observers[optionsKey]; + if (!observer) { + observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + postMessage({ + method: "intersection", + entry: { isIntersecting: entry.isIntersecting }, + options + }, "*", entry.target.contentWindow); + }); + }, getObserverOptions(options)); + observers[optionsKey] = observer; + } + return observer; +} +function getObserverOptions(options) { + const result = {}; + if (options && options.threshold) result.threshold = options.threshold; + if (options && options.margin) result.rootMargin = options.margin + "px " + options.margin + "px " + options.margin + "px " + options.margin + "px"; + return result; +} +function boot$10() { + iframely.on("init", () => { + iframely.extendOptions({ intersection: 1 }); + }); + iframely.on("message", (widget, message) => { + if (message.method === "send-intersections" && widget.iframe) { + let options = message.options; + if (!options) options = { margin: 1e3 }; + getObserver(options).observe(widget.iframe); + } + }); +} +//#endregion +//#region src/theme.ts +function setThemeInIframe(iframe, theme) { + postMessage({ + method: "setTheme", + data: theme + }, "*", iframe.contentWindow); +} +function setThemeInAllIframes(parent, theme) { + const iframes = parent.getElementsByTagName("iframe"); + for (let i = 0; i < iframes.length; i++) setThemeInIframe(iframes[i], theme); +} +function boot$9() { + iframely.setTheme = (theme, container) => { + if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) if (container) if (container.tagName === "IFRAME") setThemeInIframe(container, theme); + else setThemeInAllIframes(container, theme); + else { + iframely.extendOptions({ theme }); + setThemeInAllIframes(document, theme); + iframely.trigger("set-theme", theme); + } + else console.warn("Using iframely.setTheme with not supported theme: \"" + theme + "\". Supported themes are: " + iframely.SUPPORTED_THEMES.join(", ")); + }; +} +//#endregion +//#region src/import.ts +var widgetsCache = {}; +function boot$8() { + iframely.on("load", (el) => { + if (!el && iframely.config.import !== false && isImportAble() && !iframely.import) { + const elements = document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"); + if (elements.length > 1) makeImportAPICall(elements); + } + }); + iframely.on("load", (widget, importOptions) => { + if (widget && !(widget instanceof Element) && widget.uri && (widget.html || widget.cancel)) { + const els = widgetsCache[widget.uri]; + if (els) for (let i = 0; i < els.length; i++) loadImportWidget(widget, els[i], importOptions); + delete widgetsCache[widget.uri]; + } + }); + iframely.buildImportWidgets = (importOptions) => { + iframely.trigger("import-loaded", importOptions); + importOptions.widgets.forEach((widget) => { + iframely.trigger("load", widget, importOptions); + }); + importReady(); + }; + iframely.isTouch = () => { + return "ontouchstart" in window || navigator.maxTouchPoints > 0; + }; + iframely.on("import-widget-ready", clearWrapperStylesAndClass); + if (!iframely.addEventListener) iframely.addEventListener = (elem, type, eventHandle) => { + if (!elem) return; + elem.addEventListener(type, eventHandle, false); + }; +} +function makeImportAPICall(elements) { + const script = createScript(); + const uris = []; + const ids = []; + let import_options = null; + function pushElement(uri, el) { + if (!widgetsCache[uri]) widgetsCache[uri] = []; + widgetsCache[uri].push(el); + } + function queueElement(el) { + const src = el.getAttribute("data-iframely-url"); + const mId = src.match(iframely.ID_RE); + const id = mId && mId[1]; + const options = parseQueryString(src, iframely.SUPPORTED_QUERY_STRING.concat("url")); + let url = options.url; + delete options.url; + let skipImport = options.import === "0" || options.import === "false" || options.playerjs === "1" || options.playerjs === "true"; + if (!skipImport) { + const mBase = src.match(iframely.BASE_RE); + options.CDN = mBase && mBase[0]; + if (!import_options) import_options = options; + else if (JSON.stringify(options, Object.keys(options).sort()) !== JSON.stringify(import_options, Object.keys(import_options).sort())) skipImport = true; + } + if (skipImport) iframely.trigger("load", el); + else if (id) { + el.setAttribute("data-import-uri", id); + if (ids.indexOf(id) === -1) ids.push(id); + pushElement(id, el); + } else { + if (!url) url = el.getAttribute("href"); + if ((import_options.key || import_options.api_key || iframely.config.api_key || iframely.config.key) && url) { + el.setAttribute("data-import-uri", url); + if (uris.indexOf(url) === -1) uris.push(url); + pushElement(url, el); + } else iframely.trigger("load", el); + } + } + for (let i = 0; i < elements.length; i++) { + const el = elements[i]; + if (!el.getAttribute("data-import-uri") && el.hasAttribute("data-iframely-url")) queueElement(el); + } + if (uris.length > 0 || ids.length > 0) { + import_options = import_options || {}; + import_options.touch = iframely.isTouch(); + import_options.flash = false; + import_options.app = 1; + if (iframely.config.theme) import_options.theme = iframely.config.theme; + if (uris.length > 0) import_options.uri = uris; + if (ids.length > 0) import_options.ids = ids.join("&"); + import_options.v = iframely.VERSION; + script.src = getEndpoint("/api/import/v2", import_options, iframely.SUPPORTED_QUERY_STRING); + script.onerror = () => { + importReady(); + }; + document.head.appendChild(script); + iframely.import = script; + } else { + importReady(); + iframely.trigger("load"); + } +} +function loadImportWidget(widgetOptions, el, importOptions) { + const needCancelWidget = widgetOptions.cancel; + const shadow = widgetOptions.shadow; + const hasRenderedEvent = widgetOptions.renderEvent; + const wrapper = getIframeWrapper(el, true); + if (needCancelWidget) iframely.cancelWidget(getWidget(el) || { + maxWidthWrapper: el, + iframe: el, + url: el.getAttribute("href") + }); + else { + const widget = document.createElement("div"); + widget.innerHTML = widgetOptions.html; + let parent, replacedEl; + if (wrapper && !hasRenderedEvent) { + parent = wrapper.aspectWrapper.parentNode; + replacedEl = wrapper.aspectWrapper; + wrapper.maxWidthWrapper.removeAttribute("style"); + } else { + parent = el.parentNode; + replacedEl = el; + } + if (shadow) { + const shadowContainer = document.createElement("div"); + const shadowRoot = shadowContainer.attachShadow({ mode: "open" }); + shadowRoot.appendChild(widget); + const shadowWidgetOptions = { + shadowRoot, + shadowContainer, + container: parent, + context: widgetOptions.context, + stylesIds: widgetOptions.stylesIds, + stylesDict: importOptions.commonShadowStyles + }; + iframely.trigger("import-shadow-widget-before-render", shadowWidgetOptions); + parent.insertBefore(shadowContainer, replacedEl); + iframely.trigger("import-shadow-widget-after-render", shadowWidgetOptions); + } else { + parent.insertBefore(widget, replacedEl); + exec_body_scripts(widget); + } + parent.removeChild(replacedEl); + if (hasRenderedEvent) setTimeout(() => { + clearWrapperStylesAndClass(parent); + }, iframely.CLEAR_WRAPPER_STYLES_TIMEOUT); + } +} +function importReady() { + delete iframely.import; + const failed_elements = document.querySelectorAll("a[data-iframely-url][data-import-uri]"); + for (let i = 0; i < failed_elements.length; i++) { + failed_elements[i].removeAttribute("data-import-uri"); + iframely.trigger("load", failed_elements[i]); + } +} +function isImportAble() { + return !!(document.location && (iframely.debug || document.location.protocol === "http:" || document.location.protocol === "https:") && !iframely.config.playerjs && !iframely.config.lazy); +} +function clearWrapperStylesAndClass(el) { + let aspectWrapper = el; + let parents = 0; + while (aspectWrapper && (!aspectWrapper.getAttribute("class") || aspectWrapper.getAttribute("class").split(" ").indexOf(iframely.ASPECT_WRAPPER_CLASS) === -1)) { + aspectWrapper = aspectWrapper.parentNode; + parents++; + if (parents > 4) aspectWrapper = null; + } + const maxWidthWrapper = aspectWrapper && aspectWrapper.parentNode; + if (maxWidthWrapper && maxWidthWrapper.getAttribute("class") && maxWidthWrapper.getAttribute("class").split(" ").indexOf(iframely.MAXWIDTH_WRAPPER_CLASS) > -1) { + aspectWrapper.removeAttribute("style"); + aspectWrapper.removeAttribute("class"); + maxWidthWrapper.removeAttribute("style"); + } +} +function exec_body_scripts(body_el) { + function nodeName(elem, name) { + return !!elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + } + function evalScript(elem) { + const data = elem.text || elem.textContent || elem.innerHTML || ""; + const script = createScript(); + script.type = "text/javascript"; + for (let i = 0; i < elem.attributes.length; i++) { + const attr = elem.attributes[i]; + script.setAttribute(attr.name, attr.value); + } + script.appendChild(document.createTextNode(data)); + body_el.appendChild(script); + } + const scripts = []; + const children_nodes = body_el.childNodes; + for (let i = 0; children_nodes[i]; i++) { + const child = children_nodes[i]; + if (nodeName(child, "script") && (!child.type || child.type.toLowerCase() === "text/javascript" || child.type.toLowerCase() === "application/javascript")) { + scripts.push(child); + body_el.removeChild(child); + } else if (child.nodeType === Node.ELEMENT_NODE) exec_body_scripts(child); + } + for (let i = 0; i < scripts.length; i++) { + const script = scripts[i]; + if (script.parentNode) script.parentNode.removeChild(script); + evalScript(script); + } +} +//#endregion +//#region src/ahref.ts +function boot$7() { + iframely.on("load", (container, href) => { + if (container && container.nodeName && typeof href === "string") { + const a = document.createElement("a"); + a.setAttribute("href", href); + container.appendChild(a); + iframely.trigger("load", a); + } + }); + iframely.on("load", (el) => { + if (!el && !iframely.import) { + const elements = document.querySelectorAll("a[data-iframely-url]:not([data-import-uri])"); + for (let i = 0; i < elements.length; i++) iframely.trigger("load", elements[i]); + } + }); + iframely.on("load", (el) => { + if (el && el.nodeName === "A" && (el.getAttribute("data-iframely-url") || el.getAttribute("href")) && !el.hasAttribute("data-import-uri")) unfurl(el); + }); +} +function unfurl(el) { + if (!el.getAttribute("data-iframely-url") && !el.getAttribute("href")) return; + let src; + const dataIframelyUrl = el.getAttribute("data-iframely-url"); + if (dataIframelyUrl && /^((?:https?:)?\/\/[^/]+)\/\w+/i.test(dataIframelyUrl)) src = getEndpoint(dataIframelyUrl, { + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }); + else if ((iframely.config.api_key || iframely.config.key) && iframely.CDN) { + if (!el.getAttribute("href")) { + console.warn("Iframely cannot build embeds: \"href\" attribute missing in", el); + return; + } + src = getEndpoint("/api/iframe", { + url: el.getAttribute("href"), + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }, iframely.SUPPORTED_QUERY_STRING); + } else console.warn("Iframely cannot build embeds: api key is required as query-string of embed.js"); + if (!src) el.removeAttribute("data-iframely-url"); + else { + const iframe = document.createElement("iframe"); + iframe.setAttribute("allowfullscreen", ""); + iframe.setAttribute("allow", "autoplay *; encrypted-media *; ch-prefers-color-scheme *"); + if (el.hasAttribute("data-img")) iframe.setAttribute("data-img", el.getAttribute("data-img")); + const isLazy = el.hasAttribute("data-lazy") || el.hasAttribute("data-img") || /&lazy=1/.test(src) || iframely.config.lazy; + const text = el.textContent; + if (text && text !== "") iframe.textContent = text; + let wrapper = getIframeWrapper(el, true); + if (wrapper) while (wrapper.aspectWrapper.lastChild) wrapper.aspectWrapper.removeChild(wrapper.aspectWrapper.lastChild); + else { + wrapper = addDefaultWrappers(el); + el.parentNode.removeChild(el); + } + wrapper.aspectWrapper.appendChild(iframe); + if (isLazy) { + iframe.setAttribute("data-iframely-url", src); + iframely.trigger("load", iframe); + } else { + iframe.setAttribute("src", src); + iframely.trigger("iframe-ready", iframe); + } + } +} +//#endregion +//#region src/lazy-img-placeholder.ts +function boot$6() { + iframely.on("load", (el) => { + if (el && el.nodeName === "IFRAME" && el.hasAttribute("data-iframely-url") && el.hasAttribute("data-img") && !el.getAttribute("src")) { + const dataImg = el.getAttribute("data-img"); + el.removeAttribute("data-img"); + el.setAttribute("data-img-created", ""); + const widget = getWidget(el); + let src = el.getAttribute("data-iframely-url"); + if (widget) { + addPlaceholderThumbnail(widget, src, dataImg); + src = addQueryString(src, { img: 1 }); + el.setAttribute("data-iframely-url", src); + new WaitingWidget(widget); + } + iframely.trigger("load", el); + } + }); + iframely.on("message", (widget, message) => { + if (!widget) return; + let waitingWidget; + if (message.method === "widgetRendered") { + hidePlaceholderThumbnail(widget); + waitingWidget = findWaitingWidget(widget); + waitingWidget?.deactivate(); + } + if (message.method === "begin-waiting-widget-render") { + waitingWidget = findWaitingWidget(widget); + waitingWidget?.clearLoadingTimeout(); + } + if (message.method === "end-waiting-widget-render") { + waitingWidget = findWaitingWidget(widget); + waitingWidget?.registerLoadingTimeout(); + } + }); +} +function addPlaceholderThumbnail(widget, href, imageUrl) { + let thumbHref; + if (imageUrl && /^(https?:)?\/\//.test(imageUrl)) thumbHref = imageUrl; + else { + const query = parseQueryString(href); + const _params = {}; + for (const param in query) if (param.indexOf("_") === 0) _params[param] = query[param]; + if (query.media) _params.media = query.media; + if (href.match(/\/api\/iframe/)) thumbHref = getEndpoint(href.match(/^(.+)\/api\/iframe/i)[1] + "/api/thumbnail", Object.assign({ + url: query.url, + api_key: query.api_key, + key: query.key + }, _params)); + else if (href.match(iframely.ID_RE)) thumbHref = getEndpoint(href.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/, "$1/thumbnail"), _params); + else return; + } + const thumb = document.createElement("div"); + setStyles(thumb, { + position: "absolute", + width: "100%", + height: "100%", + backgroundImage: "url('" + thumbHref + "')", + backgroundSize: "cover", + backgroundPosition: "center" + }); + const iframelyLoaderDiv = document.createElement("div"); + iframelyLoaderDiv.setAttribute("class", iframely.LOADER_CLASS); + thumb.appendChild(iframelyLoaderDiv); + const paddingTop = iframely.getElementComputedStyle(widget.aspectWrapper, "padding-top"); + const paddingBottom = iframely.getElementComputedStyle(widget.aspectWrapper, "padding-bottom"); + const paddingTopMatch = paddingTop && paddingTop.match(/^(\d+)px$/); + if (paddingTopMatch && parseInt(paddingTopMatch[1]) && paddingBottom) { + const thumbWrapper = document.createElement("div"); + setStyles(thumbWrapper, { + top: "-" + paddingTop, + width: "100%", + height: 0, + position: "relative", + paddingBottom + }); + thumbWrapper.appendChild(thumb); + widget.aspectWrapper.appendChild(thumbWrapper); + } else widget.aspectWrapper.appendChild(thumb); +} +function getNthNonTextChildNode(nth, element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.ELEMENT_NODE) { + if (nth === count) return el; + count++; + } + } +} +function nonTextChildCount(element) { + let count = 0; + for (let i = 0; i < element.childNodes.length; i++) { + const el = element.childNodes[i]; + if (el.nodeType === Node.TEXT_NODE) { + if ((el.textContent || "").replace(/\s|\n/g, "")) count++; + } else if (el.nodeType === Node.ELEMENT_NODE) count++; + } + return count; +} +function hidePlaceholderThumbnail(widget) { + const thumb = widget.aspectWrapper && nonTextChildCount(widget.aspectWrapper) > 1 && getNthNonTextChildNode(1, widget.aspectWrapper); + if (thumb && thumb.nodeName === "DIV") widget.aspectWrapper.removeChild(thumb); +} +var waitingWidgets = []; +function findWaitingWidgetIdx(widget) { + let i = 0; + while (i < waitingWidgets.length && waitingWidgets[i].widget.iframe !== widget.iframe) i++; + if (i < waitingWidgets.length && waitingWidgets[i].widget.iframe === widget.iframe) return i; +} +function findWaitingWidget(widget) { + const idx = findWaitingWidgetIdx(widget); + if (idx || idx === 0) return waitingWidgets[idx]; +} +function removeWaitingWidget(widget) { + const idx = findWaitingWidgetIdx(widget); + if (idx || idx === 0) waitingWidgets.splice(idx, 1); +} +var WaitingWidget = class { + widget; + loadCount = 0; + timeoutId = null; + constructor(widget) { + this.widget = widget; + iframely.addEventListener(widget.iframe, "load", () => { + this.iframeOnLoad(); + }); + this.registerLoadingTimeout(); + waitingWidgets.push(this); + } + iframeOnLoad() { + this.loadCount++; + if (this.loadCount !== 2) return; + this.deactivate(); + setTimeout(() => { + hidePlaceholderThumbnail(this.widget); + }, iframely.LAZY_IFRAME_FADE_TIMEOUT); + } + deactivate() { + this.clearLoadingTimeout(); + removeWaitingWidget(this.widget); + } + clearLoadingTimeout() { + if (this.timeoutId) clearTimeout(this.timeoutId); + this.timeoutId = null; + } + registerLoadingTimeout() { + if (this.timeoutId) return; + this.timeoutId = setTimeout(() => { + this.iframeOnLoad(); + }, iframely.LAZY_IFRAME_SHOW_TIMEOUT); + } +}; +//#endregion +//#region src/lazy-iframe.ts +function boot$5() { + iframely.on("load", (el) => { + if (!el) { + const elements = document.querySelectorAll("iframe[data-iframely-url]"); + for (let i = 0; i < elements.length; i++) iframely.trigger("load", elements[i]); + } + }); + iframely.on("load", (el) => { + if (el && el.nodeName === "IFRAME" && el.hasAttribute("data-iframely-url") && !el.hasAttribute("data-img") && !el.getAttribute("src")) loadLazyIframe(el); + }); +} +function loadLazyIframe(el) { + const widget = getWidget(el); + let src = el.getAttribute("data-iframely-url"); + const dataImg = el.hasAttribute("data-img-created") || el.hasAttribute("data-img"); + const nativeLazyLoad = !dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR; + if (widget && src) { + const options = { + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }; + if (!nativeLazyLoad && iframely.config.intersection) options.lazy = 1; + src = getEndpoint(src, options); + } + if (nativeLazyLoad) el.setAttribute("loading", "lazy"); + if (dataImg && iframely.SUPPORT_IFRAME_LOADING_ATTR) el.setAttribute("loading", "edge"); + el.setAttribute("src", src || ""); + el.removeAttribute("data-iframely-url"); + iframely.trigger("iframe-ready", el); +} +//#endregion +//#region src/widget-cancel.ts +function boot$4() { + iframely.on("message", (widget, message) => { + if (message.method === "cancelWidget") iframely.cancelWidget(widget); + }); + iframely.cancelWidget = (widget) => { + if (!widget) { + console.warn("iframely.cancelWidget called without widget param"); + return; + } + function findParent(el, className) { + let found = false; + while (!found && el.parentNode) { + el = el.parentNode; + found = !!el.className && typeof el.className === "string" && el.className.split(" ").indexOf(className) >= 0; + } + return found && el; + } + let parentNode = widget.maxWidthWrapper && widget.maxWidthWrapper.parentNode; + let naNode = widget.maxWidthWrapper; + if (iframely.config && iframely.config.parent) { + const parentElement = findParent(widget.maxWidthWrapper, String(iframely.config.parent)); + if (parentElement) { + parentNode = parentElement.parentNode; + naNode = parentElement; + } + } + if (widget.url) { + const text = widget.iframe && widget.iframe.textContent; + iframely.triggerAsync("cancel", widget.url, parentNode, text, naNode.nextSibling); + } + parentNode.removeChild(naNode); + }; +} +//#endregion +//#region src/widget-resize.ts +var resetWrapperBorderStyles = { + "border": "", + "border-radius": "", + "box-shadow": "", + "overflow": "" +}; +var resetIframeBorderStyles = { + "border": "0", + "border-radius": "", + "box-shadow": "", + "overflow": "" +}; +function boot$3() { + iframely.on("message", (widget, message) => { + if (message.method === "setIframelyWidgetSize" || message.method === "resize" || message.method === "setIframelyEmbedData" || message.type === "embed-size" || message.context === "iframe.resize") { + let frame_styles = null; + if (message.data && message.data.media && message.data.media.frame_style) { + message.data.media.frame_style.split(";").forEach((str) => { + if (str.trim() !== "" && str.indexOf(":") > -1) { + const props = str.split(":"); + if (props.length === 2) { + frame_styles = frame_styles || {}; + frame_styles[props[0].trim()] = props[1].trim(); + } + } + }); + widgetDecorate(widget, frame_styles); + } else if (message.method === "setIframelyEmbedData") widgetDecorate(widget, null); + let media = message.data && message.data.media; + if (!media && message.height) media = { + height: message.height, + "max-width": "keep" + }; + widgetResize(widget, media); + } + }); +} +function widgetDecorate(widget, styles) { + if (styles && widget && widget.iframe) if (styles["border-radius"]) { + styles.overflow = "hidden"; + setStyles(widget.aspectWrapper, styles); + } else setStyles(widget.iframe, styles); + else if (!styles && widget && widget.iframe) { + setStyles(widget.aspectWrapper, resetWrapperBorderStyles); + setStyles(widget.iframe, resetIframeBorderStyles); + } +} +function getTotalBorderWidth(widget) { + const frameStylesBorder = widget.iframe && widget.iframe.style.border || widget.aspectWrapper && widget.aspectWrapper.style.border; + const borderMatch = frameStylesBorder && frameStylesBorder.match(/(\d+)px/); + if (borderMatch) return parseInt(borderMatch[1]) * 2; + return 0; +} +function widgetResize(widget, media) { + if (media && Object.keys(media).length > 0 && widget) { + const borderWidth = getTotalBorderWidth(widget); + const oldIframeHeight = window.getComputedStyle(widget.iframe).getPropertyValue("height"); + let maxWidth = media["max-width"]; + if (typeof maxWidth === "number") maxWidth += borderWidth; + setStyles(widget.maxWidthWrapper, { + "max-width": maxWidth, + "min-width": media["min-width"] && media["min-width"] + borderWidth, + width: media.width && media.width + borderWidth + }); + if (media.scrolling && widget.iframe) widget.iframe.setAttribute("scrolling", media.scrolling); + const aspectRatio = media["aspect-ratio"]; + if (aspectRatio || media.height) setStyles(widget.aspectWrapper, { + paddingBottom: aspectRatio ? Math.round(1e3 * 100 / aspectRatio) / 1e3 + "%" : 0, + paddingTop: aspectRatio && media["padding-bottom"], + height: aspectRatio ? 0 : media.height && media.height + borderWidth + }); + const currentHeight = window.getComputedStyle(widget.iframe).getPropertyValue("height"); + if (oldIframeHeight && oldIframeHeight !== currentHeight) iframely.triggerAsync("heightChanged", widget.iframe, oldIframeHeight, currentHeight); + } +} +//#endregion +//#region src/widget-click.ts +function boot$2() { + iframely.on("message", (widget, message) => { + if (message.method === "open-href" || message.method === "click") iframely.trigger(message.method, message.href); + }); + if (!iframely.openHref) iframely.openHref = (href) => { + if (href.indexOf(window.location.origin) === 0) window.location.href = href; + else window.open(href, "_blank", "noopener"); + }; + iframely.on("open-href", (href) => { + iframely.triggerAsync("click", href); + iframely.openHref(href); + }); +} +//#endregion +//#region src/widget-options.ts +function boot$1() { + iframely.on("message", (widget, message) => { + if (message.method === "setIframelyEmbedOptions") iframely.trigger("options", widget, message.data); + }); +} +//#endregion +//#region src/deprecated.ts +function boot() { + iframely.widgets = iframely.widgets || {}; + iframely.widgets.load = iframely.load; + if (!iframely.events) { + iframely.events = {}; + iframely.events.on = iframely.on; + iframely.events.trigger = iframely.trigger; + } + iframely.on("cancel", (url, parentNode, text, nextSibling) => { + if (iframely.RECOVER_HREFS_ON_CANCEL && !text) text = url; + if (url && parentNode && text && text !== "") { + const a = document.createElement("a"); + a.setAttribute("href", url); + a.setAttribute("target", "_blank"); + a.setAttribute("rel", "noopener"); + a.textContent = text; + if (nextSibling) parentNode.insertBefore(a, nextSibling); + else parentNode.appendChild(a); + } + }); +} +//#endregion +export { boot$4 as a, boot$7 as c, boot$10 as d, boot$11 as f, boot$14 as h, boot$3 as i, boot$8 as l, boot$13 as m, boot$1 as n, boot$5 as o, boot$12 as p, boot$2 as r, boot$6 as s, boot as t, boot$9 as u }; diff --git a/src/iframely.js b/dist/esm/chunks/iframely.js similarity index 59% rename from src/iframely.js rename to dist/esm/chunks/iframely.js index 6add09a..503ee66 100644 --- a/src/iframely.js +++ b/dist/esm/chunks/iframely.js @@ -1,4 +1,5 @@ +//#region src/iframely.ts var iframely = window.iframely = window.iframely || {}; iframely.config = iframely.config || {}; - -module.exports = iframely; \ No newline at end of file +//#endregion +export { iframely as t }; diff --git a/dist/esm/chunks/translator.js b/dist/esm/chunks/translator.js new file mode 100644 index 0000000..b910890 --- /dev/null +++ b/dist/esm/chunks/translator.js @@ -0,0 +1,14 @@ +import { t as iframely } from "./iframely.js"; +//#region src/options/translator.ts +var langs = {}; +function registerLabels(lang, labels) { + const existingLabels = langs[lang] = langs[lang] || {}; + Object.assign(existingLabels, labels); +} +iframely.optionsTranslator = (lang) => { + return (label) => { + return langs[lang] && langs[lang][label] && langs[lang][label] !== "" ? langs[lang][label] : label; + }; +}; +//#endregion +export { registerLabels as t }; diff --git a/dist/esm/i18n.de.js b/dist/esm/i18n.de.js new file mode 100644 index 0000000..e4aafb8 --- /dev/null +++ b/dist/esm/i18n.de.js @@ -0,0 +1,70 @@ +import { t as registerLabels } from "./chunks/translator.js"; +//#region src/options/lang/labels.de.ts +registerLabels("de", { + "Slimmer horizontal player": "Schlanker horizontaler Player", + "Include playlist": "Wiedergabeliste anzeigen", + "Hide artwork": "Artwork ausblenden", + "Theme color": "Theme Farbe", + "Light": "Hell", + "Dark": "Dunkel", + "Auto": "Automatisch", + "Default": "Standard", + "Adjust height": "Höhe einstellen", + "Active page": "Aktive Seite", + "Use click-to-load": "Verwende click-to-load", + "ex.: 600, in px": "Z.B. 600, in px", + "Hide timed comments": "Kommentare ausblenden", + "Let Iframely optimize player for the artwork": "Optimierung des Players durch IFramely", + "Show as slideshow": "Als Slideshow zeigen", + "Start from": "Start ab", + "ex.: 11, 1m10s": "z.B. 11, 1m10s", + "End on": "Ende an", + "Closed captions": "Untertitel", + "Include up to 20 tweets": "Bis zu 20 Tweets anzeigen", + "Hide photos, videos, and cards": "Verberge Fotos, Videos und Cards", + "Hide previous Tweet in conversation thread": "Verberge den vorigen Tweet in der Konversation", + "Use dark theme": "Verwende dunkles Farbschema", + "Adjust width": "Breite anpassen", + "Hide description": "Beschreibung verbergen", + "Widget style": "Widget-Style", + "Mini": "Mini", + "Classic": "Klassisch", + "Picture": "Bild", + "Zoom": "Zoom", + "Map orientation": "Karten-Ausrichtung", + "Album": "Album", + "Portrait": "Portrait", + "Square": "Quadratisch", + "Show context slideshow": "Als Slideshow anzeigen", + "Show description footer": "Fußzeile anzeigen", + "Show user header": "Kopfbereich anzeigen", + "Show author's text caption": "Beschriftung des Autors anzeigen", + "Hide author's text caption": "Beschriftung des Autors verbergen", + "Include parent comment (if url is a reply)": "Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)", + "Show recent posts": "Neueste Beiträge anzeigen", + "Show profile photos when friends like this": "Profilfotos anzeigen, wenn Freunde dies mögen", + "Use the small header instead": "Kleine Kopfzeile stattdessen verwenden", + "Artwork": "Artwork", + "Small": "klein", + "Big": "groß", + "None": "Keines", + "Layout": "Layout", + "Slim": "Schlank", + "Artwork-only": "Nur Artwork", + "Standard": "Standard", + "Size & style": "Größe & Stil", + "Wide image": "Breite Darstellung", + "Wide simple": "Breite Darstellung (Einfach)", + "Text language (ignored if no captions)": "Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)", + "Two letters: en, fr, es, de...": "Zwei Buchstaben: en, fr, es, de...", + "Don't include attached player": "Player nicht integrieren", + "Attached player only, no card": "Nur Player, keine Card", + "Hold load & play until clicked": "Klicken zum Abspielen", + "Make it a small card": "Kleine Card verwenden", + "Keep using full media card": "Verwende weiterhin vollständige Media-Cards", + "Don't include player": "Player nicht hinzufügen", + "Player only, no card": "Nur Player, keine Card", + "Just the player": "Nur Player", + "Just the image": "Nur Bild" +}); +//#endregion diff --git a/dist/esm/i18n.fr.js b/dist/esm/i18n.fr.js new file mode 100644 index 0000000..6cc1d74 --- /dev/null +++ b/dist/esm/i18n.fr.js @@ -0,0 +1,63 @@ +import { t as registerLabels } from "./chunks/translator.js"; +//#region src/options/lang/labels.fr.ts +registerLabels("fr", { + "Slimmer horizontal player": "Joueur de audio classique", + "Include playlist": "Inclure la playlist", + "Hide artwork": "Masquer la illustration", + "Theme color": "Couleur du thème", + "Light": "Lumière", + "Dark": "Sombre", + "Auto": "", + "Default": "Défaut", + "Adjust height": "Height", + "Active page": "Page active", + "Use click-to-load": "Utilisez click-to-load", + "ex.: 600, in px": "", + "Hide timed comments": "Masquer les commentaires", + "Let Iframely optimize player for the artwork": "Optimiser le lecteur pour l'illustration", + "Show as slideshow": "Montrer en diaporama", + "Start from": "Commencer", + "ex.: 11, 1m10s": "", + "End on": "Fin sur", + "Include up to 20 tweets": "Incluez jusqu'à 20 tweets", + "Hide photos, videos, and cards": "Masquer les photos, les vidéos et les cartes", + "Hide previous Tweet in conversation thread": "Masquer le tweet parent", + "Hide description": "Masquer la description", + "Widget style": "Style de widget", + "Mini": "", + "Classic": "Classique", + "Picture": "Image", + "Zoom": "", + "Map orientation": "Orientation de la carte", + "Album": "", + "Portrait": "", + "Square": "Carré", + "Show context slideshow": "Afficher le diaporama contextuel", + "Show description footer": "Afficher la description pied de page", + "Show user header": "Afficher l'en-tête de l'utilisateur", + "Show author's text caption": "Afficher la description de l'auteur", + "Hide author's text caption": "Masquer la description de l'auteur", + "Include parent comment (if url is a reply)": "", + "Show recent posts": "Afficher les messages récents", + "Show profile photos when friends like this": "", + "Use the small header instead": "Utilisez plutôt le petit en-tête", + "Artwork": "Ouvrages d'art", + "Small": "Petite", + "Big": "Grosse", + "None": "Aucune", + "Layout": "Disposition", + "Slim": "Svelte", + "Artwork-only": "Oeuvre seule", + "Standard": "Standard", + "Size & style": "Style", + "Wide image": "Image large", + "Wide simple": "Large simple", + "Hold load & play until clicked": "Click-to-play", + "Make it a small card": "Carte compacte", + "Keep using full media card": "Continuez à utiliser la carte média complète", + "Don't include player": "Ne pas inclure la vidéo", + "Player only, no card": "La vidéo seulement, pas de carte", + "Just the player": "Seulement la vidéo", + "Just the image": "Seulement l'image" +}); +//#endregion diff --git a/dist/esm/main-options.js b/dist/esm/main-options.js new file mode 100644 index 0000000..ed6e808 --- /dev/null +++ b/dist/esm/main-options.js @@ -0,0 +1,348 @@ +import { t as iframely } from "./chunks/iframely.js"; +import { a as boot$11, c as boot$8, d as boot$5, f as boot$3, h as boot$1, i as boot$12, l as boot$7, m as boot$2, n as boot$14, o as boot$10, p as boot$4, r as boot$13, s as boot$9, t as boot$15, u as boot$6 } from "./chunks/deprecated.js"; +//#region src/options/form-generator.ts +var _RE = /^_./; +var translate = (label, translator) => { + return translator && typeof translator === "function" && label ? translator(label) || label : label; +}; +function getFormElements(options, translator) { + if (!options) return []; + options = Object.assign({}, options); + delete options.query; + const items = []; + const keys = Object.keys(options); + let checkboxCount = 0; + keys.forEach((key) => { + const context = {}; + let getQuery; + const option = options[key]; + option.key = key; + let forceCheckboxForSingleKeyValue = false; + const valuesKeys = option.values ? Object.keys(option.values) : void 0; + let singleKey, singleLabel; + if (valuesKeys && valuesKeys.length === 1) { + forceCheckboxForSingleKeyValue = true; + singleKey = valuesKeys[0]; + singleLabel = option.values[singleKey]; + } + context.label = translate(singleLabel || option.label, translator); + context.key = option.key; + if (forceCheckboxForSingleKeyValue || typeof option.value === "boolean") { + if (forceCheckboxForSingleKeyValue) context.checked = singleKey === option.value || !singleKey && !option.value; + else context.checked = option.value; + checkboxCount++; + items.push({ + type: "checkbox", + context, + order: _RE.test(key) ? 0 : 1, + getQuery: (checked) => { + let value; + if (forceCheckboxForSingleKeyValue) value = checked ? singleKey : ""; + else value = checked; + const result = {}; + if (forceCheckboxForSingleKeyValue) if (value === "") {} else result[option.key] = value; + else result[option.key] = checked; + return result; + } + }); + } else if ((typeof option.value === "number" || typeof option.value === "string") && !option.values) { + const useSlider = option.range && typeof option.range.min === "number" && typeof option.range.max === "number"; + const useNumber = typeof option.value === "number"; + context.value = option.value; + getQuery = (inputValue) => { + const result = {}; + if (inputValue === "") {} else result[option.key] = inputValue; + return result; + }; + if (useSlider) { + context.min = option.range.min; + context.max = option.range.max; + items.push({ + type: "range", + context, + order: 9, + getQuery + }); + } else { + context.placeholder = translate(option.placeholder || "", translator); + context.inputType = useNumber ? "number" : "text"; + items.push({ + type: "text", + context, + order: /start/i.test(key) ? 7 : 8, + getQuery + }); + } + } else if (option.values) { + context.value = option.value + ""; + getQuery = (inputValue) => { + const result = {}; + if (inputValue === "") {} else result[option.key] = inputValue; + return result; + }; + if (Object.keys(option.values).length <= 3) { + if (option.label) context.label = translate(option.label, translator); + else context.label = false; + let i = 0; + let hasLongLabel = false; + const values = Object.values(option.values); + while (i < values.length && !hasLongLabel) { + hasLongLabel = values[i].length > 8; + i++; + } + context.inline = !hasLongLabel; + context.items = []; + Object.keys(option.values).forEach((key, idx2) => { + context.items.push({ + id: context.key + "-" + idx2, + value: key, + label: translate(option.values[key], translator), + checked: context.value === key + }); + }); + items.push({ + type: "radio", + context, + order: hasLongLabel ? -3 : !/theme/.test(key) ? -2 : -1, + getQuery + }); + } else { + context.items = []; + Object.keys(option.values).forEach((key) => { + context.items.push({ + value: key, + label: translate(option.values[key], translator), + checked: context.value === key + }); + }); + items.push({ + type: "select", + context, + order: 5, + getQuery + }); + } + } + }); + items.sort((a, b) => a.order - b.order); + items.forEach((item) => { + delete item.order; + }); + if (checkboxCount > 0) { + const groupedItems = []; + let subItems; + items.forEach((item, idx) => { + if (item.type === "checkbox") { + const newCheckboxGroup = checkboxCount > 2 && idx > 0 && !_RE.test(item.context.key) && items[idx - 1].type === "checkbox" && _RE.test(items[idx - 1].context.key); + if (!subItems || newCheckboxGroup) { + subItems = []; + groupedItems.push({ + type: "group", + context: { elements: subItems } + }); + } + subItems.push(item); + } else groupedItems.push(item); + }); + return groupedItems; + } else return items; +} +//#endregion +//#region src/options/form-builder.ts +var UIelements = { + checkbox: { getValue: (inputs) => { + return inputs[0].checked; + } }, + text: { + getValue: (inputs) => { + const input = inputs[0]; + let value = input.value; + if (input.type === "number") { + value = parseInt(value); + if (isNaN(value)) value = ""; + } + return value; + }, + customEvents: (inputs, submitOptionsCb) => { + const input = inputs[0]; + iframely.addEventListener(input, "click", () => { + input.select(); + }); + iframely.addEventListener(input, "blur", submitOptionsCb); + iframely.addEventListener(input, "keyup", (e) => { + if (e.keyCode === 13) submitOptionsCb(); + }); + } + }, + radio: { getValue: (inputs) => { + let selectedInput; + Array.prototype.forEach.call(inputs, (input) => { + if (input.checked) selectedInput = input; + }); + return selectedInput.value; + } } +}; +var defaultQueryById = {}; +function formBuilder(params) { + const options = params.options; + const formContainer = params.formContainer; + if (!formContainer) { + console.warn("No formContainer in form-builder options", params); + return; + } + if (!options) { + formContainer.innerHTML = ""; + return; + } + const elements = getFormElements(options, params.translator); + const id = params.id; + const renderer = params.renderer; + const defaultQuery = defaultQueryById[id] = defaultQueryById[id] || {}; + Object.keys(options).forEach((key) => { + if (!options.query || options.query.indexOf(key) === -1) defaultQuery[key] = options[key].value; + }); + function getQueryFromForm() { + const query = {}; + const getOptionsFromElements = (elements) => { + elements.forEach((element) => { + if (element.context && element.context.elements) getOptionsFromElements(element.context.elements); + else if (element.inputs) { + const elementUI = UIelements[element.type]; + let inputValue; + if (elementUI && elementUI.getValue) inputValue = elementUI.getValue(element.inputs); + else inputValue = element.inputs[0].value; + Object.assign(query, element.getQuery(inputValue)); + } + }); + }; + getOptionsFromElements(elements); + return query; + } + function getAndSubmitOptions() { + const query = getQueryFromForm(); + Object.keys(defaultQuery).forEach((key) => { + if (defaultQuery[key] === query[key] || query[key] === void 0) delete query[key]; + }); + iframely.trigger("options-changed", id, formContainer, query); + } + const renderElements = (elements) => { + let html = ""; + elements.forEach((element) => { + if (element.context && element.context.elements) element.context.elementsHtml = renderElements(element.context.elements); + html += renderer(element.type, element.context || {}); + }); + return html; + }; + formContainer.innerHTML = renderElements(elements); + const bindElements = (elements) => { + elements.forEach((element) => { + if (element.context && element.context.elements) bindElements(element.context.elements); + else { + const elementUI = UIelements[element.type]; + if (element.context) { + const inputs = formContainer.querySelectorAll("[name=\"" + element.context.key + "\"]"); + element.inputs = inputs; + if (inputs.length > 0) if (elementUI && elementUI.customEvents) elementUI.customEvents(inputs, getAndSubmitOptions); + else inputs.forEach((input) => { + iframely.addEventListener(input, "change", getAndSubmitOptions); + }); + else console.warn("No inputs found for option", element.context.key); + } + } + }); + }; + bindElements(elements); +} +//#endregion +//#region src/options/renderer.ts +var ESCAPE_MAP = { + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'" +}; +var esc = (value) => value == null ? "" : String(value).replace(/[&<>"']/g, (c) => ESCAPE_MAP[c]); +var templates = { + checkbox: (ctx) => ` +
+ + +
`, + group: (ctx) => ` +
+
${ctx.elementsHtml ?? ""}
+
`, + radio: (ctx) => ` +
+ ${ctx.label ? `` : ""} +
+ ${(ctx.items || []).map((item) => ` +
+ + +
`).join("")} +
+
`, + range: (ctx) => ` +
+ +
+ +
+
`, + select: (ctx) => ` +
+ +
+ +
+
`, + text: (ctx) => ` +
+ +
+ +
+
` +}; +var render = (type, context) => templates[type](context); +//#endregion +//#region src/options/index.ts +function boot() { + iframely.buildOptionsForm = (id, formContainer, options, translator) => { + formBuilder({ + id, + formContainer, + options, + renderer: render, + translator + }); + }; +} +//#endregion +//#region src/index-options.ts +if (!iframely._loaded) { + iframely._loaded = true; + boot$1(); + boot$2(); + boot$3(); + boot$4(); + boot$5(); + boot$6(); + boot$7(); + boot$8(); + boot$9(); + boot$10(); + boot$11(); + boot$12(); + boot$13(); + boot$14(); + boot$15(); + boot(); + iframely.trigger("init"); +} +//#endregion +export { iframely }; diff --git a/dist/esm/main.js b/dist/esm/main.js new file mode 100644 index 0000000..aa91eb0 --- /dev/null +++ b/dist/esm/main.js @@ -0,0 +1,24 @@ +import { t as iframely } from "./chunks/iframely.js"; +import { a as boot$10, c as boot$7, d as boot$4, f as boot$2, h as boot, i as boot$11, l as boot$6, m as boot$1, n as boot$13, o as boot$9, p as boot$3, r as boot$12, s as boot$8, t as boot$14, u as boot$5 } from "./chunks/deprecated.js"; +//#region src/index.ts +if (!iframely._loaded) { + iframely._loaded = true; + boot(); + boot$1(); + boot$2(); + boot$3(); + boot$4(); + boot$5(); + boot$6(); + boot$7(); + boot$8(); + boot$9(); + boot$10(); + boot$11(); + boot$12(); + boot$13(); + boot$14(); + iframely.trigger("init"); +} +//#endregion +export { iframely }; diff --git a/dist/options.i18n.de.js b/dist/options.i18n.de.js index 814415b..c2b5457 100644 --- a/dist/options.i18n.de.js +++ b/dist/options.i18n.de.js @@ -1,82 +1,92 @@ -/* - * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -/******/ (() => { // webpackBootstrap -/******/ var __webpack_modules__ = ({ +(function() { -/***/ "./iframely.js" -/*!*********************!*\ - !*** ./iframely.js ***! - \*********************/ -(module) { -eval("{var iframely = window.iframely = window.iframely || {};\niframely.config = iframely.config || {};\n\nmodule.exports = iframely;\n\n//# sourceURL=webpack:///./iframely.js?\n}"); +//#region src/iframely.ts + var iframely = window.iframely = window.iframely || {}; + iframely.config = iframely.config || {}; -/***/ }, +//#endregion +//#region src/options/translator.ts + var langs = {}; + function registerLabels(lang, labels) { + const existingLabels = langs[lang] = langs[lang] || {}; + Object.assign(existingLabels, labels); + } + iframely.optionsTranslator = (lang) => { + return (label) => { + return langs[lang] && langs[lang][label] && langs[lang][label] !== "" ? langs[lang][label] : label; + }; + }; -/***/ "./options/lang/labels.de.js" -/*!***********************************!*\ - !*** ./options/lang/labels.de.js ***! - \***********************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { +//#endregion +//#region src/options/lang/labels.de.ts + registerLabels("de", { + "Slimmer horizontal player": "Schlanker horizontaler Player", + "Include playlist": "Wiedergabeliste anzeigen", + "Hide artwork": "Artwork ausblenden", + "Theme color": "Theme Farbe", + "Light": "Hell", + "Dark": "Dunkel", + "Auto": "Automatisch", + "Default": "Standard", + "Adjust height": "Höhe einstellen", + "Active page": "Aktive Seite", + "Use click-to-load": "Verwende click-to-load", + "ex.: 600, in px": "Z.B. 600, in px", + "Hide timed comments": "Kommentare ausblenden", + "Let Iframely optimize player for the artwork": "Optimierung des Players durch IFramely", + "Show as slideshow": "Als Slideshow zeigen", + "Start from": "Start ab", + "ex.: 11, 1m10s": "z.B. 11, 1m10s", + "End on": "Ende an", + "Closed captions": "Untertitel", + "Include up to 20 tweets": "Bis zu 20 Tweets anzeigen", + "Hide photos, videos, and cards": "Verberge Fotos, Videos und Cards", + "Hide previous Tweet in conversation thread": "Verberge den vorigen Tweet in der Konversation", + "Use dark theme": "Verwende dunkles Farbschema", + "Adjust width": "Breite anpassen", + "Hide description": "Beschreibung verbergen", + "Widget style": "Widget-Style", + "Mini": "Mini", + "Classic": "Klassisch", + "Picture": "Bild", + "Zoom": "Zoom", + "Map orientation": "Karten-Ausrichtung", + "Album": "Album", + "Portrait": "Portrait", + "Square": "Quadratisch", + "Show context slideshow": "Als Slideshow anzeigen", + "Show description footer": "Fußzeile anzeigen", + "Show user header": "Kopfbereich anzeigen", + "Show author's text caption": "Beschriftung des Autors anzeigen", + "Hide author's text caption": "Beschriftung des Autors verbergen", + "Include parent comment (if url is a reply)": "Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)", + "Show recent posts": "Neueste Beiträge anzeigen", + "Show profile photos when friends like this": "Profilfotos anzeigen, wenn Freunde dies mögen", + "Use the small header instead": "Kleine Kopfzeile stattdessen verwenden", + "Artwork": "Artwork", + "Small": "klein", + "Big": "groß", + "None": "Keines", + "Layout": "Layout", + "Slim": "Schlank", + "Artwork-only": "Nur Artwork", + "Standard": "Standard", + "Size & style": "Größe & Stil", + "Wide image": "Breite Darstellung", + "Wide simple": "Breite Darstellung (Einfach)", + "Text language (ignored if no captions)": "Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)", + "Two letters: en, fr, es, de...": "Zwei Buchstaben: en, fr, es, de...", + "Don't include attached player": "Player nicht integrieren", + "Attached player only, no card": "Nur Player, keine Card", + "Hold load & play until clicked": "Klicken zum Abspielen", + "Make it a small card": "Kleine Card verwenden", + "Keep using full media card": "Verwende weiterhin vollständige Media-Cards", + "Don't include player": "Player nicht hinzufügen", + "Player only, no card": "Nur Player, keine Card", + "Just the player": "Nur Player", + "Just the image": "Nur Bild" + }); -eval("{var translator = __webpack_require__(/*! ../translator */ \"./options/translator.js\");\n\nvar lang ='de';\n\nvar labels = {\n // general options\n 'Slimmer horizontal player': 'Schlanker horizontaler Player',\n 'Include playlist': 'Wiedergabeliste anzeigen',\n 'Hide artwork': 'Artwork ausblenden',\n 'Theme color': 'Theme Farbe',\n 'Light': 'Hell',\n 'Dark': 'Dunkel',\n 'Auto': 'Automatisch',\n 'Default': 'Standard',\n 'Adjust height': 'Höhe einstellen',\n 'Active page': 'Aktive Seite',\n\n // Codepen\n 'Use click-to-load': 'Verwende click-to-load',\n 'ex.: 600, in px': 'Z.B. 600, in px',\n\n //Instagram\n 'Hide timed comments': 'Kommentare ausblenden',\n\n //Soundcloud\n 'Let Iframely optimize player for the artwork': 'Optimierung des Players durch IFramely',\n\n // scribd\n 'Show as slideshow': 'Als Slideshow zeigen',\n\n // youtube\n 'Start from': 'Start ab',\n 'ex.: 11, 1m10s': 'z.B. 11, 1m10s',\n 'End on': 'Ende an',\n 'Closed captions': 'Untertitel',\n\n // twitter\n 'Include up to 20 tweets': 'Bis zu 20 Tweets anzeigen',\n 'Hide photos, videos, and cards': 'Verberge Fotos, Videos und Cards',\n 'Hide previous Tweet in conversation thread': 'Verberge den vorigen Tweet in der Konversation',\n 'Use dark theme': 'Verwende dunkles Farbschema',\n 'Adjust width': 'Breite anpassen',\n\n // pinterest\n 'Hide description': 'Beschreibung verbergen',\n\n //mixcloud\n 'Widget style': 'Widget-Style',\n 'Mini': 'Mini',\n 'Classic': 'Klassisch',\n 'Picture': 'Bild',\n\n //google maps\n 'Zoom': 'Zoom',\n 'Map orientation': 'Karten-Ausrichtung',\n 'Album': 'Album',\n 'Portrait': 'Portrait',\n 'Square': 'Quadratisch',\n\n // Flickr\n 'Show context slideshow': 'Als Slideshow anzeigen',\n 'Show description footer': 'Fußzeile anzeigen',\n 'Show user header': 'Kopfbereich anzeigen',\n\n //facebook\n 'Show author\\'s text caption': 'Beschriftung des Autors anzeigen',\n 'Hide author\\'s text caption': 'Beschriftung des Autors verbergen',\n 'Include parent comment (if url is a reply)': 'Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)',\n\n 'Show recent posts': 'Neueste Beiträge anzeigen',\n 'Show profile photos when friends like this': 'Profilfotos anzeigen, wenn Freunde dies mögen',\n 'Use the small header instead': 'Kleine Kopfzeile stattdessen verwenden',\n\n //bandcamp\n 'Artwork': 'Artwork',\n 'Small': 'klein',\n 'Big': 'groß',\n 'None': 'Keines',\n\n 'Layout': 'Layout',\n 'Slim': 'Schlank',\n 'Artwork-only': 'Nur Artwork',\n 'Standard': 'Standard',\n\n //omny.fm\n 'Size & style': 'Größe & Stil',\n 'Wide image': 'Breite Darstellung',\n 'Wide simple': 'Breite Darstellung (Einfach)',\n\n // Vimeo\n 'Text language (ignored if no captions)': 'Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)',\n 'Two letters: en, fr, es, de...': 'Zwei Buchstaben: en, fr, es, de...',\n \n // Kickstarter\n 'Don\\'t include attached player': 'Player nicht integrieren',\n 'Attached player only, no card': 'Nur Player, keine Card',\n\n //iframely options\n 'Hold load & play until clicked': 'Klicken zum Abspielen',\n 'Make it a small card': 'Kleine Card verwenden',\n //iframely media cards\n 'Keep using full media card': 'Verwende weiterhin vollständige Media-Cards',\n 'Don\\'t include player': 'Player nicht hinzufügen',\n 'Player only, no card': 'Nur Player, keine Card',\n //iframely media=1\n 'Just the player': 'Nur Player',\n 'Just the image': 'Nur Bild'\n};\n\ntranslator.registerLabels(lang, labels);\n\n\n//# sourceURL=webpack:///./options/lang/labels.de.js?\n}"); - -/***/ }, - -/***/ "./options/translator.js" -/*!*******************************!*\ - !*** ./options/translator.js ***! - \*******************************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{/*\nTo add more languages to the translator -\nsee ./lang/labels.LAN.example.js\n\n - use the template for the list of currently available labels\n - save it as labels.LAN.js // replace LAN with your actual value, e.g. es, de, ru, etc.\n - fill in the labels translations\n - add to webpack config options as \n\t'options.i18n.fr': './options/lang/labels.fr.js' \n\t(see webpack.common.js as example)\n\nYou can then call iframely.optionsTranslator('LAN') - with your chosen language - to build the options form\n\nYou don't need to translate all the labels. The ones without a translation will be left as-is\n*/\n\nvar iframely = __webpack_require__(/*! ../iframely */ \"./iframely.js\");\n\nvar langs = {};\n\nexports.registerLabels = function(lang, labels) {\n var existingLabels = langs[lang] = langs[lang] || {};\n Object.assign(existingLabels, labels);\n};\n\niframely.optionsTranslator = function(lang) {\n return function (label) {\n return langs[lang] && langs[lang][label] && langs[lang][label] !== '' ? langs[lang][label] : label;\n };\n};\n\n//# sourceURL=webpack:///./options/translator.js?\n}"); - -/***/ } - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ if (!(moduleId in __webpack_modules__)) { -/******/ delete __webpack_module_cache__[moduleId]; -/******/ var e = new Error("Cannot find module '" + moduleId + "'"); -/******/ e.code = 'MODULE_NOT_FOUND'; -/******/ throw e; -/******/ } -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module can't be inlined because the eval devtool is used. -/******/ var __webpack_exports__ = __webpack_require__("./options/lang/labels.de.js"); -/******/ -/******/ })() -; \ No newline at end of file +//#endregion +})(); \ No newline at end of file diff --git a/dist/options.i18n.de.min.js b/dist/options.i18n.de.min.js index 1eb6778..a2abb68 100644 --- a/dist/options.i18n.de.min.js +++ b/dist/options.i18n.de.min.js @@ -1 +1 @@ -(()=>{var e={774(e){var r=window.iframely=window.iframely||{};r.config=r.config||{},e.exports=r},132(e,r,n){var i=n(774),t={};r.registerLabels=function(e,r){var n=t[e]=t[e]||{};Object.assign(n,r)},i.optionsTranslator=function(e){return function(r){return t[e]&&t[e][r]&&""!==t[e][r]?t[e][r]:r}}}},r={};(function n(i){var t=r[i];if(void 0!==t)return t.exports;var a=r[i]={exports:{}};return e[i](a,a.exports,n),a.exports})(132).registerLabels("de",{"Slimmer horizontal player":"Schlanker horizontaler Player","Include playlist":"Wiedergabeliste anzeigen","Hide artwork":"Artwork ausblenden","Theme color":"Theme Farbe",Light:"Hell",Dark:"Dunkel",Auto:"Automatisch",Default:"Standard","Adjust height":"Höhe einstellen","Active page":"Aktive Seite","Use click-to-load":"Verwende click-to-load","ex.: 600, in px":"Z.B. 600, in px","Hide timed comments":"Kommentare ausblenden","Let Iframely optimize player for the artwork":"Optimierung des Players durch IFramely","Show as slideshow":"Als Slideshow zeigen","Start from":"Start ab","ex.: 11, 1m10s":"z.B. 11, 1m10s","End on":"Ende an","Closed captions":"Untertitel","Include up to 20 tweets":"Bis zu 20 Tweets anzeigen","Hide photos, videos, and cards":"Verberge Fotos, Videos und Cards","Hide previous Tweet in conversation thread":"Verberge den vorigen Tweet in der Konversation","Use dark theme":"Verwende dunkles Farbschema","Adjust width":"Breite anpassen","Hide description":"Beschreibung verbergen","Widget style":"Widget-Style",Mini:"Mini",Classic:"Klassisch",Picture:"Bild",Zoom:"Zoom","Map orientation":"Karten-Ausrichtung",Album:"Album",Portrait:"Portrait",Square:"Quadratisch","Show context slideshow":"Als Slideshow anzeigen","Show description footer":"Fußzeile anzeigen","Show user header":"Kopfbereich anzeigen","Show author's text caption":"Beschriftung des Autors anzeigen","Hide author's text caption":"Beschriftung des Autors verbergen","Include parent comment (if url is a reply)":"Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)","Show recent posts":"Neueste Beiträge anzeigen","Show profile photos when friends like this":"Profilfotos anzeigen, wenn Freunde dies mögen","Use the small header instead":"Kleine Kopfzeile stattdessen verwenden",Artwork:"Artwork",Small:"klein",Big:"groß",None:"Keines",Layout:"Layout",Slim:"Schlank","Artwork-only":"Nur Artwork",Standard:"Standard","Size & style":"Größe & Stil","Wide image":"Breite Darstellung","Wide simple":"Breite Darstellung (Einfach)","Text language (ignored if no captions)":"Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)","Two letters: en, fr, es, de...":"Zwei Buchstaben: en, fr, es, de...","Don't include attached player":"Player nicht integrieren","Attached player only, no card":"Nur Player, keine Card","Hold load & play until clicked":"Klicken zum Abspielen","Make it a small card":"Kleine Card verwenden","Keep using full media card":"Verwende weiterhin vollständige Media-Cards","Don't include player":"Player nicht hinzufügen","Player only, no card":"Nur Player, keine Card","Just the player":"Nur Player","Just the image":"Nur Bild"})})(); \ No newline at end of file +(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{};var t={};function n(e,n){let r=t[e]=t[e]||{};Object.assign(r,n)}e.optionsTranslator=e=>n=>t[e]&&t[e][n]&&t[e][n]!==``?t[e][n]:n,n(`de`,{"Slimmer horizontal player":`Schlanker horizontaler Player`,"Include playlist":`Wiedergabeliste anzeigen`,"Hide artwork":`Artwork ausblenden`,"Theme color":`Theme Farbe`,Light:`Hell`,Dark:`Dunkel`,Auto:`Automatisch`,Default:`Standard`,"Adjust height":`Höhe einstellen`,"Active page":`Aktive Seite`,"Use click-to-load":`Verwende click-to-load`,"ex.: 600, in px":`Z.B. 600, in px`,"Hide timed comments":`Kommentare ausblenden`,"Let Iframely optimize player for the artwork":`Optimierung des Players durch IFramely`,"Show as slideshow":`Als Slideshow zeigen`,"Start from":`Start ab`,"ex.: 11, 1m10s":`z.B. 11, 1m10s`,"End on":`Ende an`,"Closed captions":`Untertitel`,"Include up to 20 tweets":`Bis zu 20 Tweets anzeigen`,"Hide photos, videos, and cards":`Verberge Fotos, Videos und Cards`,"Hide previous Tweet in conversation thread":`Verberge den vorigen Tweet in der Konversation`,"Use dark theme":`Verwende dunkles Farbschema`,"Adjust width":`Breite anpassen`,"Hide description":`Beschreibung verbergen`,"Widget style":`Widget-Style`,Mini:`Mini`,Classic:`Klassisch`,Picture:`Bild`,Zoom:`Zoom`,"Map orientation":`Karten-Ausrichtung`,Album:`Album`,Portrait:`Portrait`,Square:`Quadratisch`,"Show context slideshow":`Als Slideshow anzeigen`,"Show description footer":`Fußzeile anzeigen`,"Show user header":`Kopfbereich anzeigen`,"Show author's text caption":`Beschriftung des Autors anzeigen`,"Hide author's text caption":`Beschriftung des Autors verbergen`,"Include parent comment (if url is a reply)":`Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)`,"Show recent posts":`Neueste Beiträge anzeigen`,"Show profile photos when friends like this":`Profilfotos anzeigen, wenn Freunde dies mögen`,"Use the small header instead":`Kleine Kopfzeile stattdessen verwenden`,Artwork:`Artwork`,Small:`klein`,Big:`groß`,None:`Keines`,Layout:`Layout`,Slim:`Schlank`,"Artwork-only":`Nur Artwork`,Standard:`Standard`,"Size & style":`Größe & Stil`,"Wide image":`Breite Darstellung`,"Wide simple":`Breite Darstellung (Einfach)`,"Text language (ignored if no captions)":`Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)`,"Two letters: en, fr, es, de...":`Zwei Buchstaben: en, fr, es, de...`,"Don't include attached player":`Player nicht integrieren`,"Attached player only, no card":`Nur Player, keine Card`,"Hold load & play until clicked":`Klicken zum Abspielen`,"Make it a small card":`Kleine Card verwenden`,"Keep using full media card":`Verwende weiterhin vollständige Media-Cards`,"Don't include player":`Player nicht hinzufügen`,"Player only, no card":`Nur Player, keine Card`,"Just the player":`Nur Player`,"Just the image":`Nur Bild`})})(); \ No newline at end of file diff --git a/dist/options.i18n.fr.js b/dist/options.i18n.fr.js index 2caa881..b03a164 100644 --- a/dist/options.i18n.fr.js +++ b/dist/options.i18n.fr.js @@ -1,82 +1,85 @@ -/* - * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -/******/ (() => { // webpackBootstrap -/******/ var __webpack_modules__ = ({ +(function() { -/***/ "./iframely.js" -/*!*********************!*\ - !*** ./iframely.js ***! - \*********************/ -(module) { -eval("{var iframely = window.iframely = window.iframely || {};\niframely.config = iframely.config || {};\n\nmodule.exports = iframely;\n\n//# sourceURL=webpack:///./iframely.js?\n}"); +//#region src/iframely.ts + var iframely = window.iframely = window.iframely || {}; + iframely.config = iframely.config || {}; -/***/ }, +//#endregion +//#region src/options/translator.ts + var langs = {}; + function registerLabels(lang, labels) { + const existingLabels = langs[lang] = langs[lang] || {}; + Object.assign(existingLabels, labels); + } + iframely.optionsTranslator = (lang) => { + return (label) => { + return langs[lang] && langs[lang][label] && langs[lang][label] !== "" ? langs[lang][label] : label; + }; + }; -/***/ "./options/lang/labels.fr.js" -/*!***********************************!*\ - !*** ./options/lang/labels.fr.js ***! - \***********************************/ -(__unused_webpack_module, __unused_webpack_exports, __webpack_require__) { +//#endregion +//#region src/options/lang/labels.fr.ts + registerLabels("fr", { + "Slimmer horizontal player": "Joueur de audio classique", + "Include playlist": "Inclure la playlist", + "Hide artwork": "Masquer la illustration", + "Theme color": "Couleur du thème", + "Light": "Lumière", + "Dark": "Sombre", + "Auto": "", + "Default": "Défaut", + "Adjust height": "Height", + "Active page": "Page active", + "Use click-to-load": "Utilisez click-to-load", + "ex.: 600, in px": "", + "Hide timed comments": "Masquer les commentaires", + "Let Iframely optimize player for the artwork": "Optimiser le lecteur pour l'illustration", + "Show as slideshow": "Montrer en diaporama", + "Start from": "Commencer", + "ex.: 11, 1m10s": "", + "End on": "Fin sur", + "Include up to 20 tweets": "Incluez jusqu'à 20 tweets", + "Hide photos, videos, and cards": "Masquer les photos, les vidéos et les cartes", + "Hide previous Tweet in conversation thread": "Masquer le tweet parent", + "Hide description": "Masquer la description", + "Widget style": "Style de widget", + "Mini": "", + "Classic": "Classique", + "Picture": "Image", + "Zoom": "", + "Map orientation": "Orientation de la carte", + "Album": "", + "Portrait": "", + "Square": "Carré", + "Show context slideshow": "Afficher le diaporama contextuel", + "Show description footer": "Afficher la description pied de page", + "Show user header": "Afficher l'en-tête de l'utilisateur", + "Show author's text caption": "Afficher la description de l'auteur", + "Hide author's text caption": "Masquer la description de l'auteur", + "Include parent comment (if url is a reply)": "", + "Show recent posts": "Afficher les messages récents", + "Show profile photos when friends like this": "", + "Use the small header instead": "Utilisez plutôt le petit en-tête", + "Artwork": "Ouvrages d'art", + "Small": "Petite", + "Big": "Grosse", + "None": "Aucune", + "Layout": "Disposition", + "Slim": "Svelte", + "Artwork-only": "Oeuvre seule", + "Standard": "Standard", + "Size & style": "Style", + "Wide image": "Image large", + "Wide simple": "Large simple", + "Hold load & play until clicked": "Click-to-play", + "Make it a small card": "Carte compacte", + "Keep using full media card": "Continuez à utiliser la carte média complète", + "Don't include player": "Ne pas inclure la vidéo", + "Player only, no card": "La vidéo seulement, pas de carte", + "Just the player": "Seulement la vidéo", + "Just the image": "Seulement l'image" + }); -eval("{var translator = __webpack_require__(/*! ../translator */ \"./options/translator.js\");\n\nvar lang ='fr';\n\nvar labels = {\n // general options\n 'Slimmer horizontal player': 'Joueur de audio classique',\n 'Include playlist': 'Inclure la playlist',\n 'Hide artwork': 'Masquer la illustration',\n 'Theme color': 'Couleur du thème',\n 'Light': 'Lumière',\n 'Dark': 'Sombre',\n 'Auto': '',\n 'Default': 'Défaut',\n 'Adjust height': 'Height',\n 'Active page': 'Page active',\n\n // Codepen\n 'Use click-to-load': 'Utilisez click-to-load',\n 'ex.: 600, in px': '',\n\n //Instagram\n 'Hide timed comments': 'Masquer les commentaires',\n\n //Soundcloud\n 'Let Iframely optimize player for the artwork': 'Optimiser le lecteur pour l\\'illustration',\n\n // scribd\n 'Show as slideshow': 'Montrer en diaporama',\n\n // youtube\n 'Start from': 'Commencer',\n 'ex.: 11, 1m10s': '',\n 'End on': 'Fin sur',\n\n // twitter\n 'Include up to 20 tweets': 'Incluez jusqu\\'à 20 tweets',\n 'Hide photos, videos, and cards': 'Masquer les photos, les vidéos et les cartes',\n 'Hide previous Tweet in conversation thread': 'Masquer le tweet parent',\n\n // pinterest\n 'Hide description': 'Masquer la description',\n\n //mixcloud\n 'Widget style': 'Style de widget',\n 'Mini': '', // can leave empty - will remain as is\n 'Classic': 'Classique',\n 'Picture': 'Image',\n\n //google maps\n 'Zoom': '',\n 'Map orientation': 'Orientation de la carte',\n 'Album': '',\n 'Portrait': '',\n 'Square': 'Carré',\n\n // Flickr\n 'Show context slideshow': 'Afficher le diaporama contextuel',\n 'Show description footer': 'Afficher la description pied de page',\n 'Show user header': 'Afficher l\\'en-tête de l\\'utilisateur',\n\n //facebook\n 'Show author\\'s text caption': 'Afficher la description de l\\'auteur',\n 'Hide author\\'s text caption': 'Masquer la description de l\\'auteur',\n 'Include parent comment (if url is a reply)': '',\n\n 'Show recent posts': 'Afficher les messages récents',\n 'Show profile photos when friends like this': '',\n 'Use the small header instead': 'Utilisez plutôt le petit en-tête',\n\n //bandcamp\n 'Artwork': 'Ouvrages d\\'art',\n 'Small': 'Petite',\n 'Big': 'Grosse',\n 'None': 'Aucune',\n\n 'Layout': 'Disposition',\n 'Slim': 'Svelte',\n 'Artwork-only': 'Oeuvre seule',\n 'Standard': 'Standard',\n\n //omny.fm\n 'Size & style': 'Style',\n 'Wide image': 'Image large',\n 'Wide simple': 'Large simple',\n\n\n //iframely options\n 'Hold load & play until clicked': 'Click-to-play',\n 'Make it a small card': 'Carte compacte',\n //iframely media cards\n 'Keep using full media card': 'Continuez à utiliser la carte média complète',\n 'Don\\'t include player': 'Ne pas inclure la vidéo',\n 'Player only, no card': 'La vidéo seulement, pas de carte',\n //iframely media=1\n 'Just the player': 'Seulement la vidéo',\n 'Just the image': 'Seulement l\\'image'\n};\n\ntranslator.registerLabels(lang, labels);\n\n//# sourceURL=webpack:///./options/lang/labels.fr.js?\n}"); - -/***/ }, - -/***/ "./options/translator.js" -/*!*******************************!*\ - !*** ./options/translator.js ***! - \*******************************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{/*\nTo add more languages to the translator -\nsee ./lang/labels.LAN.example.js\n\n - use the template for the list of currently available labels\n - save it as labels.LAN.js // replace LAN with your actual value, e.g. es, de, ru, etc.\n - fill in the labels translations\n - add to webpack config options as \n\t'options.i18n.fr': './options/lang/labels.fr.js' \n\t(see webpack.common.js as example)\n\nYou can then call iframely.optionsTranslator('LAN') - with your chosen language - to build the options form\n\nYou don't need to translate all the labels. The ones without a translation will be left as-is\n*/\n\nvar iframely = __webpack_require__(/*! ../iframely */ \"./iframely.js\");\n\nvar langs = {};\n\nexports.registerLabels = function(lang, labels) {\n var existingLabels = langs[lang] = langs[lang] || {};\n Object.assign(existingLabels, labels);\n};\n\niframely.optionsTranslator = function(lang) {\n return function (label) {\n return langs[lang] && langs[lang][label] && langs[lang][label] !== '' ? langs[lang][label] : label;\n };\n};\n\n//# sourceURL=webpack:///./options/translator.js?\n}"); - -/***/ } - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ if (!(moduleId in __webpack_modules__)) { -/******/ delete __webpack_module_cache__[moduleId]; -/******/ var e = new Error("Cannot find module '" + moduleId + "'"); -/******/ e.code = 'MODULE_NOT_FOUND'; -/******/ throw e; -/******/ } -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module can't be inlined because the eval devtool is used. -/******/ var __webpack_exports__ = __webpack_require__("./options/lang/labels.fr.js"); -/******/ -/******/ })() -; \ No newline at end of file +//#endregion +})(); \ No newline at end of file diff --git a/dist/options.i18n.fr.min.js b/dist/options.i18n.fr.min.js index 486b022..0215dd3 100644 --- a/dist/options.i18n.fr.min.js +++ b/dist/options.i18n.fr.min.js @@ -1 +1 @@ -(()=>{var e={774(e){var t=window.iframely=window.iframely||{};t.config=t.config||{},e.exports=t},132(e,t,i){var r=i(774),a={};t.registerLabels=function(e,t){var i=a[e]=a[e]||{};Object.assign(i,t)},r.optionsTranslator=function(e){return function(t){return a[e]&&a[e][t]&&""!==a[e][t]?a[e][t]:t}}}},t={};(function i(r){var a=t[r];if(void 0!==a)return a.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,i),o.exports})(132).registerLabels("fr",{"Slimmer horizontal player":"Joueur de audio classique","Include playlist":"Inclure la playlist","Hide artwork":"Masquer la illustration","Theme color":"Couleur du thème",Light:"Lumière",Dark:"Sombre",Auto:"",Default:"Défaut","Adjust height":"Height","Active page":"Page active","Use click-to-load":"Utilisez click-to-load","ex.: 600, in px":"","Hide timed comments":"Masquer les commentaires","Let Iframely optimize player for the artwork":"Optimiser le lecteur pour l'illustration","Show as slideshow":"Montrer en diaporama","Start from":"Commencer","ex.: 11, 1m10s":"","End on":"Fin sur","Include up to 20 tweets":"Incluez jusqu'à 20 tweets","Hide photos, videos, and cards":"Masquer les photos, les vidéos et les cartes","Hide previous Tweet in conversation thread":"Masquer le tweet parent","Hide description":"Masquer la description","Widget style":"Style de widget",Mini:"",Classic:"Classique",Picture:"Image",Zoom:"","Map orientation":"Orientation de la carte",Album:"",Portrait:"",Square:"Carré","Show context slideshow":"Afficher le diaporama contextuel","Show description footer":"Afficher la description pied de page","Show user header":"Afficher l'en-tête de l'utilisateur","Show author's text caption":"Afficher la description de l'auteur","Hide author's text caption":"Masquer la description de l'auteur","Include parent comment (if url is a reply)":"","Show recent posts":"Afficher les messages récents","Show profile photos when friends like this":"","Use the small header instead":"Utilisez plutôt le petit en-tête",Artwork:"Ouvrages d'art",Small:"Petite",Big:"Grosse",None:"Aucune",Layout:"Disposition",Slim:"Svelte","Artwork-only":"Oeuvre seule",Standard:"Standard","Size & style":"Style","Wide image":"Image large","Wide simple":"Large simple","Hold load & play until clicked":"Click-to-play","Make it a small card":"Carte compacte","Keep using full media card":"Continuez à utiliser la carte média complète","Don't include player":"Ne pas inclure la vidéo","Player only, no card":"La vidéo seulement, pas de carte","Just the player":"Seulement la vidéo","Just the image":"Seulement l'image"})})(); \ No newline at end of file +(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{};var t={};function n(e,n){let r=t[e]=t[e]||{};Object.assign(r,n)}e.optionsTranslator=e=>n=>t[e]&&t[e][n]&&t[e][n]!==``?t[e][n]:n,n(`fr`,{"Slimmer horizontal player":`Joueur de audio classique`,"Include playlist":`Inclure la playlist`,"Hide artwork":`Masquer la illustration`,"Theme color":`Couleur du thème`,Light:`Lumière`,Dark:`Sombre`,Auto:``,Default:`Défaut`,"Adjust height":`Height`,"Active page":`Page active`,"Use click-to-load":`Utilisez click-to-load`,"ex.: 600, in px":``,"Hide timed comments":`Masquer les commentaires`,"Let Iframely optimize player for the artwork":`Optimiser le lecteur pour l'illustration`,"Show as slideshow":`Montrer en diaporama`,"Start from":`Commencer`,"ex.: 11, 1m10s":``,"End on":`Fin sur`,"Include up to 20 tweets":`Incluez jusqu'à 20 tweets`,"Hide photos, videos, and cards":`Masquer les photos, les vidéos et les cartes`,"Hide previous Tweet in conversation thread":`Masquer le tweet parent`,"Hide description":`Masquer la description`,"Widget style":`Style de widget`,Mini:``,Classic:`Classique`,Picture:`Image`,Zoom:``,"Map orientation":`Orientation de la carte`,Album:``,Portrait:``,Square:`Carré`,"Show context slideshow":`Afficher le diaporama contextuel`,"Show description footer":`Afficher la description pied de page`,"Show user header":`Afficher l'en-tête de l'utilisateur`,"Show author's text caption":`Afficher la description de l'auteur`,"Hide author's text caption":`Masquer la description de l'auteur`,"Include parent comment (if url is a reply)":``,"Show recent posts":`Afficher les messages récents`,"Show profile photos when friends like this":``,"Use the small header instead":`Utilisez plutôt le petit en-tête`,Artwork:`Ouvrages d'art`,Small:`Petite`,Big:`Grosse`,None:`Aucune`,Layout:`Disposition`,Slim:`Svelte`,"Artwork-only":`Oeuvre seule`,Standard:`Standard`,"Size & style":`Style`,"Wide image":`Image large`,"Wide simple":`Large simple`,"Hold load & play until clicked":`Click-to-play`,"Make it a small card":`Carte compacte`,"Keep using full media card":`Continuez à utiliser la carte média complète`,"Don't include player":`Ne pas inclure la vidéo`,"Player only, no card":`La vidéo seulement, pas de carte`,"Just the player":`Seulement la vidéo`,"Just the image":`Seulement l'image`})})(); \ No newline at end of file diff --git a/dist/options.js b/dist/options.js index 98d463b..f8ac59c 100644 --- a/dist/options.js +++ b/dist/options.js @@ -1,162 +1,340 @@ -/* - * ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development"). - * This devtool is neither made for production nor for readable output files. - * It uses "eval()" calls to create a separate source file in the browser devtools. - * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) - * or disable the default devtool with "devtool: false". - * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). - */ -/******/ (() => { // webpackBootstrap -/******/ var __webpack_modules__ = ({ - -/***/ "./options/templates/checkbox.ejs" -/*!****************************************!*\ - !*** ./options/templates/checkbox.ejs ***! - \****************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\nwith (obj) {\n__p += '
\\n \\n ' +\n((__t = ( label )) == null ? '' : __t) +\n'\\n \\n
\\n';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/checkbox.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/group.ejs" -/*!*************************************!*\ - !*** ./options/templates/group.ejs ***! - \*************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __e = _.escape;\nwith (obj) {\n__p += '
\\n
\\n ' +\n__e( elementsHtml ) +\n'\\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/group.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/radio.ejs" -/*!*************************************!*\ - !*** ./options/templates/radio.ejs ***! - \*************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\nwith (obj) {\n__p += '
\\n ';\n if (label) { ;\n__p += '\\n \\n ';\n } ;\n__p += '\\n
\\n ' +\n((__t = ( subContext.label )) == null ? '' : __t) +\n'\\n \\n
\\n ';\n }); ;\n__p += '\\n
\\n';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/radio.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/range.ejs" -/*!*************************************!*\ - !*** ./options/templates/range.ejs ***! - \*************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '';\nwith (obj) {\n__p += '
\\n \\n
\\n \\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/range.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/select.ejs" -/*!**************************************!*\ - !*** ./options/templates/select.ejs ***! - \**************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '', __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\nwith (obj) {\n__p += '
\\n \\n
\\n \\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/select.ejs?\n}"); - -/***/ }, - -/***/ "./options/templates/text.ejs" -/*!************************************!*\ - !*** ./options/templates/text.ejs ***! - \************************************/ -(module) { - -eval("{module.exports = function(obj) {\nobj || (obj = {});\nvar __t, __p = '';\nwith (obj) {\n__p += '
\\n \\n
\\n \\n
\\n
';\n\n}\nreturn __p\n}\n\n//# sourceURL=webpack:///./options/templates/text.ejs?\n}"); - -/***/ }, - -/***/ "./iframely.js" -/*!*********************!*\ - !*** ./iframely.js ***! - \*********************/ -(module) { - -eval("{var iframely = window.iframely = window.iframely || {};\niframely.config = iframely.config || {};\n\nmodule.exports = iframely;\n\n//# sourceURL=webpack:///./iframely.js?\n}"); - -/***/ }, - -/***/ "./options/form-builder.js" -/*!*********************************!*\ - !*** ./options/form-builder.js ***! - \*********************************/ -(module, __unused_webpack_exports, __webpack_require__) { - -eval("{var getFormElements = __webpack_require__(/*! ./form-generator */ \"./options/form-generator.js\");\nvar iframely = __webpack_require__(/*! ../iframely */ \"./iframely.js\");\n\nvar UIelements = {\n checkbox: {\n getValue: function(inputs) {\n var input = inputs[0];\n return input.checked;\n }\n },\n text: {\n getValue: function(inputs) {\n var input = inputs[0];\n var value = input.value;\n if (input.type === 'number') {\n value = parseInt(value);\n if (isNaN(value)) {\n value = '';\n }\n }\n return value;\n },\n customEvents: function(inputs, submitOptionsCb) {\n var input = inputs[0];\n iframely.addEventListener(input, 'click', function() {\n input.select();\n });\n iframely.addEventListener(input, 'blur', submitOptionsCb);\n iframely.addEventListener(input, 'keyup', function(e) {\n // Apply on enter.\n if (e.keyCode === 13) {\n submitOptionsCb();\n }\n });\n }\n },\n radio: {\n getValue: function(inputs) {\n var selectedInput;\n inputs.forEach(function(input) {\n if (input.checked) {\n selectedInput = input;\n }\n });\n return selectedInput.value;\n }\n }\n};\n\nvar defaultQueryById = {};\n\nmodule.exports = function(params) {\n\n var options = params.options;\n var formContainer = params.formContainer;\n\n if (!formContainer) {\n console.warn('No formContainer in form-builder options', params);\n return;\n }\n\n if (!options) {\n formContainer.innerHTML = '';\n return;\n }\n\n var elements = getFormElements(options, params.translator);\n var id = params.id;\n var renderer = params.renderer;\n\n var defaultQuery = defaultQueryById[id] = defaultQueryById[id] || {};\n // Exclude default values.\n Object.keys(options).forEach(function(key) {\n if (!options.query || options.query.indexOf(key) === -1) {\n // Store default value.\n defaultQuery[key] = options[key].value;\n }\n });\n\n function getQueryFromForm() {\n\n var query = {};\n\n var getOptionsFromElements = function(elements) {\n // Get options from all inputs.\n elements.forEach(function(element) {\n\n if (element.context && element.context.elements) {\n\n getOptionsFromElements(element.context.elements);\n\n } else if (element.inputs) {\n\n var elementUI = UIelements[element.type];\n var inputValue;\n if (elementUI && elementUI.getValue) {\n inputValue = elementUI.getValue(element.inputs);\n } else {\n inputValue = element.inputs[0].value;\n }\n Object.assign(query, element.getQuery(inputValue));\n }\n });\n };\n\n getOptionsFromElements(elements);\n \n return query;\n }\n\n function getAndSubmitOptions() {\n var query = getQueryFromForm();\n\n Object.keys(defaultQuery).forEach(function(key) {\n if (defaultQuery[key] === query[key] \n || query[key] === undefined) { // remove undefined so it's not included while JSON.stringify\n delete query[key];\n }\n });\n\n iframely.trigger('options-changed', id, formContainer, query);\n }\n\n // Render form.\n var renderElements = function(elements) {\n var html = '';\n elements.forEach(function(element) {\n if (element.context && element.context.elements) {\n element.context.elementsHtml = renderElements(element.context.elements);\n }\n html += renderer(element.type, element.context || {});\n });\n return html;\n };\n formContainer.innerHTML = renderElements(elements);\n\n // Bind events.\n var bindElements = function(elements) {\n \n elements.forEach(function(element) {\n\n if (element.context && element.context.elements) {\n\n bindElements(element.context.elements);\n\n } else {\n\n var elementUI = UIelements[element.type];\n if (element.context) {\n element.inputs = formContainer.querySelectorAll('[name=\"' + element.context.key + '\"]');\n if (element.inputs.length > 0) {\n if (elementUI && elementUI.customEvents) {\n elementUI.customEvents(element.inputs, getAndSubmitOptions);\n } else {\n element.inputs.forEach(function(input) {\n iframely.addEventListener(input, 'change', getAndSubmitOptions);\n });\n }\n } else {\n console.warn('No inputs found for option', element.key);\n }\n }\n }\n });\n };\n bindElements(elements);\n};\n\n//# sourceURL=webpack:///./options/form-builder.js?\n}"); - -/***/ }, - -/***/ "./options/form-generator.js" -/*!***********************************!*\ - !*** ./options/form-generator.js ***! - \***********************************/ -(module) { - -eval("{var _RE = /^_./;\n\nvar translate = function (label, translator) {\n return translator && typeof translator === 'function' \n ? translator (label) || label\n : label;\n};\n\nmodule.exports = function(options, translator) {\n\n if (!options) {\n return [];\n }\n\n // Remove query key.\n options = Object.assign({}, options);\n delete options.query;\n\n var items = [];\n var keys = Object.keys(options);\n var checkboxCount = 0;\n \n keys.forEach(function(key) {\n \n var context = {};\n\n var getQuery;\n var option = options[key];\n option.key = key;\n\n var forceCheckboxForSingleKeyValue;\n var valuesKeys = option.values && Object.keys(option.values);\n var singleKey, singleLabel;\n if (valuesKeys && valuesKeys.length === 1) {\n forceCheckboxForSingleKeyValue = true;\n singleKey = valuesKeys[0];\n singleLabel = option.values[singleKey];\n }\n\n context.label = translate(singleLabel || option.label, translator);\n context.key = option.key;\n\n if (forceCheckboxForSingleKeyValue || typeof option.value === 'boolean') {\n\n if (forceCheckboxForSingleKeyValue) {\n context.checked = (singleKey === option.value) || (!singleKey && !option.value);\n } else {\n context.checked = option.value;\n }\n\n checkboxCount++;\n\n items.push({\n type: 'checkbox',\n context: context,\n order: _RE.test(key) ? 0 : 1,\n getQuery: function(checked) {\n\n var value;\n if (forceCheckboxForSingleKeyValue) {\n value = checked ? singleKey : '';\n } else {\n value = checked;\n }\n\n var result = {};\n\n if (forceCheckboxForSingleKeyValue) {\n if (value === '') {\n // Empty.\n } else {\n result[option.key] = value;\n }\n } else {\n result[option.key] = checked;\n }\n return result;\n }\n });\n\n } else if ((typeof option.value === 'number' || typeof option.value === 'string') && !option.values) {\n\n var useSlider = option.range && typeof option.range.min === 'number' && typeof option.range.max === 'number';\n var useNumber = typeof option.value === 'number';\n\n context.value = option.value;\n\n getQuery = function(inputValue) {\n var result = {};\n if (inputValue === '') {\n // Empty.\n } else {\n result[option.key] = inputValue;\n }\n return result;\n };\n\n if (useSlider) {\n context.min = option.range.min;\n context.max = option.range.max;\n items.push({\n type: 'range',\n context: context,\n order: 9, // last one\n getQuery: getQuery\n });\n } else {\n context.placeholder = translate(option.placeholder || '', translator);\n context.inputType = useNumber ? 'number' : 'text';\n items.push({\n type: 'text',\n context: context,\n order: /start/i.test(key) ? 7 : 8, // start/end for player timing, ex.: youtube\n getQuery: getQuery\n });\n }\n\n } else if (option.values) {\n\n context.value = option.value + '';\n\n getQuery = function(inputValue) {\n var result = {};\n if (inputValue === '') {\n // Empty.\n } else {\n result[option.key] = inputValue;\n }\n return result;\n };\n\n if (Object.keys(option.values).length <= 3) {\n\n if (option.label) {\n context.label = translate(option.label, translator);\n } else {\n context.label = false;\n }\n\n var i = 0;\n var hasLongLabel = false;\n var values = Object.values(option.values);\n while (i < values.length && !hasLongLabel) {\n var label = values[i];\n hasLongLabel = label.length > 8;\n i++;\n }\n context.inline = !hasLongLabel;\n\n context.items = [];\n\n Object.keys(option.values).forEach(function(key, idx2) {\n context.items.push({\n id: context.key + '-' + idx2,\n value: key,\n label: translate(option.values[key], translator),\n checked: context.value === key\n });\n });\n\n items.push({\n type: 'radio',\n context: context,\n order: hasLongLabel ? -3 : (!/theme/.test(key) ? -2 : -1),\n getQuery: getQuery\n });\n\n } else {\n\n context.items = [];\n\n Object.keys(option.values).forEach(function(key) {\n context.items.push({\n value: key,\n label: translate(option.values[key], translator),\n checked: context.value === key\n });\n });\n\n items.push({\n type: 'select',\n context: context,\n order: 5,\n getQuery: getQuery\n });\n }\n }\n });\n\n items.sort(function(a, b) {\n return a.order - b.order;\n });\n\n items.forEach(function(item) {\n delete item.order;\n });\n\n if (checkboxCount > 0) {\n\n var groupedItems = [];\n var subItems;\n\n items.forEach(function(item, idx) {\n\n if (item.type === 'checkbox') {\n\n // Grouping for checkboxes.\n\n var newCheckboxGroup = \n checkboxCount > 2\n && idx > 0 \n && !_RE.test(item.context.key) \n && items[idx - 1].type === 'checkbox'\n && _RE.test(items[idx - 1].context.key);\n\n if (!subItems // First group.\n || newCheckboxGroup // Second group on _ prefix removed.\n ) {\n\n subItems = [];\n groupedItems.push({\n type: 'group',\n context: {\n elements: subItems\n }\n });\n }\n\n subItems.push(item);\n\n } else {\n // Other items. Just add.\n groupedItems.push(item);\n }\n });\n\n return groupedItems;\n\n } else {\n return items;\n }\n};\n\n//# sourceURL=webpack:///./options/form-generator.js?\n}"); - -/***/ }, - -/***/ "./options/index.js" -/*!**************************!*\ - !*** ./options/index.js ***! - \**************************/ -(__unused_webpack_module, exports, __webpack_require__) { - -eval("{var iframely = __webpack_require__(/*! ../iframely */ \"./iframely.js\");\nvar formBuilder = __webpack_require__(/*! ./form-builder */ \"./options/form-builder.js\");\nvar renderer = __webpack_require__(/*! ./renderer */ \"./options/renderer.js\");\n\niframely.buildOptionsForm = function(id, formContainer, options, translator) {\n formBuilder({\n id: id,\n formContainer: formContainer,\n options: options,\n renderer: renderer,\n translator: translator\n });\n};\n\nexports.iframely = iframely;\n\n//# sourceURL=webpack:///./options/index.js?\n}"); - -/***/ }, - -/***/ "./options/renderer.js" -/*!*****************************!*\ - !*** ./options/renderer.js ***! - \*****************************/ -(module, __unused_webpack_exports, __webpack_require__) { - -eval("{var checkboxTemplate = __webpack_require__(/*! ./templates/checkbox.ejs */ \"./options/templates/checkbox.ejs\");\nvar rangeTemplate = __webpack_require__(/*! ./templates/range.ejs */ \"./options/templates/range.ejs\");\nvar textTemplate = __webpack_require__(/*! ./templates/text.ejs */ \"./options/templates/text.ejs\");\nvar radioTemplate = __webpack_require__(/*! ./templates/radio.ejs */ \"./options/templates/radio.ejs\");\nvar selectTemplate = __webpack_require__(/*! ./templates/select.ejs */ \"./options/templates/select.ejs\");\nvar groupTemplate = __webpack_require__(/*! ./templates/group.ejs */ \"./options/templates/group.ejs\");\n\nvar templates = {\n checkbox: checkboxTemplate,\n range: rangeTemplate,\n text: textTemplate,\n radio: radioTemplate,\n select: selectTemplate,\n group: groupTemplate\n};\n\nmodule.exports = function(type, context) {\n var template = templates[type];\n var renderedTemplate = template(context);\n return renderedTemplate;\n};\n\n//# sourceURL=webpack:///./options/renderer.js?\n}"); - -/***/ } - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ if (!(moduleId in __webpack_modules__)) { -/******/ delete __webpack_module_cache__[moduleId]; -/******/ var e = new Error("Cannot find module '" + moduleId + "'"); -/******/ e.code = 'MODULE_NOT_FOUND'; -/******/ throw e; -/******/ } -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ -/******/ // startup -/******/ // Load entry module and return exports -/******/ // This entry module can't be inlined because the eval devtool is used. -/******/ var __webpack_exports__ = __webpack_require__("./options/index.js"); -/******/ -/******/ })() -; \ No newline at end of file +(function() { + + +//#region src/iframely.ts + var iframely = window.iframely = window.iframely || {}; + iframely.config = iframely.config || {}; + +//#endregion +//#region src/options/form-generator.ts + var _RE = /^_./; + var translate = (label, translator) => { + return translator && typeof translator === "function" && label ? translator(label) || label : label; + }; + function getFormElements(options, translator) { + if (!options) return []; + options = Object.assign({}, options); + delete options.query; + const items = []; + const keys = Object.keys(options); + let checkboxCount = 0; + keys.forEach((key) => { + const context = {}; + let getQuery; + const option = options[key]; + option.key = key; + let forceCheckboxForSingleKeyValue = false; + const valuesKeys = option.values ? Object.keys(option.values) : void 0; + let singleKey, singleLabel; + if (valuesKeys && valuesKeys.length === 1) { + forceCheckboxForSingleKeyValue = true; + singleKey = valuesKeys[0]; + singleLabel = option.values[singleKey]; + } + context.label = translate(singleLabel || option.label, translator); + context.key = option.key; + if (forceCheckboxForSingleKeyValue || typeof option.value === "boolean") { + if (forceCheckboxForSingleKeyValue) context.checked = singleKey === option.value || !singleKey && !option.value; + else context.checked = option.value; + checkboxCount++; + items.push({ + type: "checkbox", + context, + order: _RE.test(key) ? 0 : 1, + getQuery: (checked) => { + let value; + if (forceCheckboxForSingleKeyValue) value = checked ? singleKey : ""; + else value = checked; + const result = {}; + if (forceCheckboxForSingleKeyValue) if (value === "") {} else result[option.key] = value; + else result[option.key] = checked; + return result; + } + }); + } else if ((typeof option.value === "number" || typeof option.value === "string") && !option.values) { + const useSlider = option.range && typeof option.range.min === "number" && typeof option.range.max === "number"; + const useNumber = typeof option.value === "number"; + context.value = option.value; + getQuery = (inputValue) => { + const result = {}; + if (inputValue === "") {} else result[option.key] = inputValue; + return result; + }; + if (useSlider) { + context.min = option.range.min; + context.max = option.range.max; + items.push({ + type: "range", + context, + order: 9, + getQuery + }); + } else { + context.placeholder = translate(option.placeholder || "", translator); + context.inputType = useNumber ? "number" : "text"; + items.push({ + type: "text", + context, + order: /start/i.test(key) ? 7 : 8, + getQuery + }); + } + } else if (option.values) { + context.value = option.value + ""; + getQuery = (inputValue) => { + const result = {}; + if (inputValue === "") {} else result[option.key] = inputValue; + return result; + }; + if (Object.keys(option.values).length <= 3) { + if (option.label) context.label = translate(option.label, translator); + else context.label = false; + let i = 0; + let hasLongLabel = false; + const values = Object.values(option.values); + while (i < values.length && !hasLongLabel) { + hasLongLabel = values[i].length > 8; + i++; + } + context.inline = !hasLongLabel; + context.items = []; + Object.keys(option.values).forEach((key, idx2) => { + context.items.push({ + id: context.key + "-" + idx2, + value: key, + label: translate(option.values[key], translator), + checked: context.value === key + }); + }); + items.push({ + type: "radio", + context, + order: hasLongLabel ? -3 : !/theme/.test(key) ? -2 : -1, + getQuery + }); + } else { + context.items = []; + Object.keys(option.values).forEach((key) => { + context.items.push({ + value: key, + label: translate(option.values[key], translator), + checked: context.value === key + }); + }); + items.push({ + type: "select", + context, + order: 5, + getQuery + }); + } + } + }); + items.sort((a, b) => a.order - b.order); + items.forEach((item) => { + delete item.order; + }); + if (checkboxCount > 0) { + const groupedItems = []; + let subItems; + items.forEach((item, idx) => { + if (item.type === "checkbox") { + const newCheckboxGroup = checkboxCount > 2 && idx > 0 && !_RE.test(item.context.key) && items[idx - 1].type === "checkbox" && _RE.test(items[idx - 1].context.key); + if (!subItems || newCheckboxGroup) { + subItems = []; + groupedItems.push({ + type: "group", + context: { elements: subItems } + }); + } + subItems.push(item); + } else groupedItems.push(item); + }); + return groupedItems; + } else return items; + } + +//#endregion +//#region src/options/form-builder.ts + var UIelements = { + checkbox: { getValue: (inputs) => { + return inputs[0].checked; + } }, + text: { + getValue: (inputs) => { + const input = inputs[0]; + let value = input.value; + if (input.type === "number") { + value = parseInt(value); + if (isNaN(value)) value = ""; + } + return value; + }, + customEvents: (inputs, submitOptionsCb) => { + const input = inputs[0]; + iframely.addEventListener(input, "click", () => { + input.select(); + }); + iframely.addEventListener(input, "blur", submitOptionsCb); + iframely.addEventListener(input, "keyup", (e) => { + if (e.keyCode === 13) submitOptionsCb(); + }); + } + }, + radio: { getValue: (inputs) => { + let selectedInput; + Array.prototype.forEach.call(inputs, (input) => { + if (input.checked) selectedInput = input; + }); + return selectedInput.value; + } } + }; + var defaultQueryById = {}; + function formBuilder(params) { + const options = params.options; + const formContainer = params.formContainer; + if (!formContainer) { + console.warn("No formContainer in form-builder options", params); + return; + } + if (!options) { + formContainer.innerHTML = ""; + return; + } + const elements = getFormElements(options, params.translator); + const id = params.id; + const renderer = params.renderer; + const defaultQuery = defaultQueryById[id] = defaultQueryById[id] || {}; + Object.keys(options).forEach((key) => { + if (!options.query || options.query.indexOf(key) === -1) defaultQuery[key] = options[key].value; + }); + function getQueryFromForm() { + const query = {}; + const getOptionsFromElements = (elements) => { + elements.forEach((element) => { + if (element.context && element.context.elements) getOptionsFromElements(element.context.elements); + else if (element.inputs) { + const elementUI = UIelements[element.type]; + let inputValue; + if (elementUI && elementUI.getValue) inputValue = elementUI.getValue(element.inputs); + else inputValue = element.inputs[0].value; + Object.assign(query, element.getQuery(inputValue)); + } + }); + }; + getOptionsFromElements(elements); + return query; + } + function getAndSubmitOptions() { + const query = getQueryFromForm(); + Object.keys(defaultQuery).forEach((key) => { + if (defaultQuery[key] === query[key] || query[key] === void 0) delete query[key]; + }); + iframely.trigger("options-changed", id, formContainer, query); + } + const renderElements = (elements) => { + let html = ""; + elements.forEach((element) => { + if (element.context && element.context.elements) element.context.elementsHtml = renderElements(element.context.elements); + html += renderer(element.type, element.context || {}); + }); + return html; + }; + formContainer.innerHTML = renderElements(elements); + const bindElements = (elements) => { + elements.forEach((element) => { + if (element.context && element.context.elements) bindElements(element.context.elements); + else { + const elementUI = UIelements[element.type]; + if (element.context) { + const inputs = formContainer.querySelectorAll("[name=\"" + element.context.key + "\"]"); + element.inputs = inputs; + if (inputs.length > 0) if (elementUI && elementUI.customEvents) elementUI.customEvents(inputs, getAndSubmitOptions); + else inputs.forEach((input) => { + iframely.addEventListener(input, "change", getAndSubmitOptions); + }); + else console.warn("No inputs found for option", element.context.key); + } + } + }); + }; + bindElements(elements); + } + +//#endregion +//#region src/options/renderer.ts + var ESCAPE_MAP = { + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'" + }; + var esc = (value) => value == null ? "" : String(value).replace(/[&<>"']/g, (c) => ESCAPE_MAP[c]); + var templates = { + checkbox: (ctx) => ` +
+ + +
`, + group: (ctx) => ` +
+
${ctx.elementsHtml ?? ""}
+
`, + radio: (ctx) => ` +
+ ${ctx.label ? `` : ""} +
+ ${(ctx.items || []).map((item) => ` +
+ + +
`).join("")} +
+
`, + range: (ctx) => ` +
+ +
+ +
+
`, + select: (ctx) => ` +
+ +
+ +
+
`, + text: (ctx) => ` +
+ +
+ +
+
` + }; + var render = (type, context) => templates[type](context); + +//#endregion +//#region src/options/index.ts + function boot() { + iframely.buildOptionsForm = (id, formContainer, options, translator) => { + formBuilder({ + id, + formContainer, + options, + renderer: render, + translator + }); + }; + } + +//#endregion +//#region src/options/entry.ts + boot(); + +//#endregion +})(); \ No newline at end of file diff --git a/dist/options.min.js b/dist/options.min.js index 2be8265..33a640b 100644 --- a/dist/options.min.js +++ b/dist/options.min.js @@ -1 +1,38 @@ -(()=>{var __webpack_modules__={530(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,"")}with(obj)__p+='
\n \n '+(null==(__t=label)?"":__t)+"\n \n
\n";return __p}},30(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__e=_.escape;with(obj)__p+='
\n
\n '+__e(elementsHtml)+"\n
\n
";return __p}},510(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,"")}with(obj)__p+='
\n ',label&&(__p+='\n \n "),__p+='\n
\n '+(null==(__t=e.label)?"":__t)+"\n \n
\n "}),__p+="\n
\n";return __p}},300(module){module.exports=function(obj){obj||(obj={});var __t,__p="";with(obj)__p+='
\n \n
\n \n
\n
';return __p}},37(module){module.exports=function(obj){obj||(obj={});var __t,__p="",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,"")}with(obj)__p+='
\n \n
\n \n
\n
";return __p}},712(module){module.exports=function(obj){obj||(obj={});var __t,__p="";with(obj)__p+='
\n \n
\n \n
\n
';return __p}},774(e){var t=window.iframely=window.iframely||{};t.config=t.config||{},e.exports=t},410(e,t,n){var _=n(960),l=n(774),o={checkbox:{getValue:function(e){return e[0].checked}},text:{getValue:function(e){var t=e[0],n=t.value;return"number"===t.type&&(n=parseInt(n),isNaN(n)&&(n="")),n},customEvents:function(e,t){var n=e[0];l.addEventListener(n,"click",function(){n.select()}),l.addEventListener(n,"blur",t),l.addEventListener(n,"keyup",function(e){13===e.keyCode&&t()})}},radio:{getValue:function(e){var t;return e.forEach(function(e){e.checked&&(t=e)}),t.value}}},r={};e.exports=function(e){var t=e.options,n=e.formContainer;if(n)if(t){var a=_(t,e.translator),i=e.id,u=e.renderer,c=r[i]=r[i]||{};Object.keys(t).forEach(function(e){t.query&&-1!==t.query.indexOf(e)||(c[e]=t[e].value)});var p=function(e){var t="";return e.forEach(function(e){e.context&&e.context.elements&&(e.context.elementsHtml=p(e.context.elements)),t+=u(e.type,e.context||{})}),t};n.innerHTML=p(a);var s=function(e){e.forEach(function(e){if(e.context&&e.context.elements)s(e.context.elements);else{var t=o[e.type];e.context&&(e.inputs=n.querySelectorAll('[name="'+e.context.key+'"]'),e.inputs.length>0?t&&t.customEvents?t.customEvents(e.inputs,f):e.inputs.forEach(function(e){l.addEventListener(e,"change",f)}):console.warn("No inputs found for option",e.key))}})};s(a)}else n.innerHTML="";else console.warn("No formContainer in form-builder options",e);function f(){var e=function(){var e={},t=function(n){n.forEach(function(n){if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){var _,l=o[n.type];_=l&&l.getValue?l.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(_))}})};return t(a),e}();Object.keys(c).forEach(function(t){c[t]!==e[t]&&void 0!==e[t]||delete e[t]}),l.trigger("options-changed",i,n,e)}}},960(e){var t=/^_./,n=function(e,t){return t&&"function"==typeof t&&t(e)||e};e.exports=function(e,_){if(!e)return[];delete(e=Object.assign({},e)).query;var l=[],o=Object.keys(e),r=0;if(o.forEach(function(o){var a,i,u={},c=e[o];c.key=o;var p,s,f=c.values&&Object.keys(c.values);if(f&&1===f.length&&(i=!0,p=f[0],s=c.values[p]),u.label=n(s||c.label,_),u.key=c.key,i||"boolean"==typeof c.value)u.checked=i?p===c.value||!p&&!c.value:c.value,r++,l.push({type:"checkbox",context:u,order:t.test(o)?0:1,getQuery:function(e){var t;t=i?e?p:"":e;var n={};return i?""===t||(n[c.key]=t):n[c.key]=e,n}});else if("number"!=typeof c.value&&"string"!=typeof c.value||c.values){if(c.values)if(u.value=c.value+"",a=function(e){var t={};return""===e||(t[c.key]=e),t},Object.keys(c.values).length<=3){c.label?u.label=n(c.label,_):u.label=!1;for(var v=0,d=!1,y=Object.values(c.values);v8,v++;u.inline=!d,u.items=[],Object.keys(c.values).forEach(function(e,t){u.items.push({id:u.key+"-"+t,value:e,label:n(c.values[e],_),checked:u.value===e})}),l.push({type:"radio",context:u,order:d?-3:/theme/.test(o)?-1:-2,getQuery:a})}else u.items=[],Object.keys(c.values).forEach(function(e){u.items.push({value:e,label:n(c.values[e],_),checked:u.value===e})}),l.push({type:"select",context:u,order:5,getQuery:a})}else{var m=c.range&&"number"==typeof c.range.min&&"number"==typeof c.range.max,b="number"==typeof c.value;u.value=c.value,a=function(e){var t={};return""===e||(t[c.key]=e),t},m?(u.min=c.range.min,u.max=c.range.max,l.push({type:"range",context:u,order:9,getQuery:a})):(u.placeholder=n(c.placeholder||"",_),u.inputType=b?"number":"text",l.push({type:"text",context:u,order:/start/i.test(o)?7:8,getQuery:a}))}}),l.sort(function(e,t){return e.order-t.order}),l.forEach(function(e){delete e.order}),r>0){var a,i=[];return l.forEach(function(e,n){if("checkbox"===e.type){var _=r>2&&n>0&&!t.test(e.context.key)&&"checkbox"===l[n-1].type&&t.test(l[n-1].context.key);a&&!_||(a=[],i.push({type:"group",context:{elements:a}})),a.push(e)}else i.push(e)}),i}return l}},505(e,t,n){var _={checkbox:n(530),range:n(300),text:n(712),radio:n(510),select:n(37),group:n(30)};e.exports=function(e,t){return(0,_[e])(t)}}},__webpack_module_cache__={};function __webpack_require__(e){var t=__webpack_module_cache__[e];if(void 0!==t)return t.exports;var n=__webpack_module_cache__[e]={exports:{}};return __webpack_modules__[e](n,n.exports,__webpack_require__),n.exports}var __webpack_exports__={},iframely,formBuilder,renderer;iframely=__webpack_require__(774),formBuilder=__webpack_require__(410),renderer=__webpack_require__(505),iframely.buildOptionsForm=function(e,t,n,_){formBuilder({id:e,formContainer:t,options:n,renderer,translator:_})}})(); \ No newline at end of file +(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{};var t=/^_./,n=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function r(e,r){if(!e)return[];e=Object.assign({},e),delete e.query;let i=[],a=Object.keys(e),o=0;if(a.forEach(a=>{let s={},c,l=e[a];l.key=a;let u=!1,d=l.values?Object.keys(l.values):void 0,f,p;if(d&&d.length===1&&(u=!0,f=d[0],p=l.values[f]),s.label=n(p||l.label,r),s.key=l.key,u||typeof l.value==`boolean`)u?s.checked=f===l.value||!f&&!l.value:s.checked=l.value,o++,i.push({type:`checkbox`,context:s,order:+!t.test(a),getQuery:e=>{let t;t=u?e?f:``:e;let n={};return u?t===``||(n[l.key]=t):n[l.key]=e,n}});else if((typeof l.value==`number`||typeof l.value==`string`)&&!l.values){let e=l.range&&typeof l.range.min==`number`&&typeof l.range.max==`number`,t=typeof l.value==`number`;s.value=l.value,c=e=>{let t={};return e===``||(t[l.key]=e),t},e?(s.min=l.range.min,s.max=l.range.max,i.push({type:`range`,context:s,order:9,getQuery:c})):(s.placeholder=n(l.placeholder||``,r),s.inputType=t?`number`:`text`,i.push({type:`text`,context:s,order:/start/i.test(a)?7:8,getQuery:c}))}else if(l.values)if(s.value=l.value+``,c=e=>{let t={};return e===``||(t[l.key]=e),t},Object.keys(l.values).length<=3){l.label?s.label=n(l.label,r):s.label=!1;let e=0,t=!1,o=Object.values(l.values);for(;e8,e++;s.inline=!t,s.items=[],Object.keys(l.values).forEach((e,t)=>{s.items.push({id:s.key+`-`+t,value:e,label:n(l.values[e],r),checked:s.value===e})}),i.push({type:`radio`,context:s,order:t?-3:/theme/.test(a)?-1:-2,getQuery:c})}else s.items=[],Object.keys(l.values).forEach(e=>{s.items.push({value:e,label:n(l.values[e],r),checked:s.value===e})}),i.push({type:`select`,context:s,order:5,getQuery:c})}),i.sort((e,t)=>e.order-t.order),i.forEach(e=>{delete e.order}),o>0){let e=[],n;return i.forEach((r,a)=>{if(r.type===`checkbox`){let s=o>2&&a>0&&!t.test(r.context.key)&&i[a-1].type===`checkbox`&&t.test(i[a-1].context.key);(!n||s)&&(n=[],e.push({type:`group`,context:{elements:n}})),n.push(r)}else e.push(r)}),e}else return i}var i={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(t,n)=>{let r=t[0];e.addEventListener(r,`click`,()=>{r.select()}),e.addEventListener(r,`blur`,n),e.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},a={};function o(t){let n=t.options,o=t.formContainer;if(!o){console.warn(`No formContainer in form-builder options`,t);return}if(!n){o.innerHTML=``;return}let s=r(n,t.translator),c=t.id,l=t.renderer,u=a[c]=a[c]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(u[e]=n[e].value)});function d(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=i[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(s),e}function f(){let t=d();Object.keys(u).forEach(e=>{(u[e]===t[e]||t[e]===void 0)&&delete t[e]}),e.trigger(`options-changed`,c,o,t)}let p=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=p(e.context.elements)),t+=l(e.type,e.context||{})}),t};o.innerHTML=p(s);let m=t=>{t.forEach(t=>{if(t.context&&t.context.elements)m(t.context.elements);else{let n=i[t.type];if(t.context){let r=o.querySelectorAll(`[name="`+t.context.key+`"]`);t.inputs=r,r.length>0?n&&n.customEvents?n.customEvents(r,f):r.forEach(t=>{e.addEventListener(t,`change`,f)}):console.warn(`No inputs found for option`,t.context.key)}}})};m(s)}var s={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},c=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>s[e]),l={checkbox:e=>` +
+ + +
`,group:e=>` +
+
${e.elementsHtml??``}
+
`,radio:e=>` +
+ ${e.label?``:``} +
+ ${(e.items||[]).map(t=>` +
+ + +
`).join(``)} +
+
`,range:e=>` +
+ +
+ +
+
`,select:e=>` +
+ +
+ +
+
`,text:e=>` +
+ +
+ +
+
`},u=(e,t)=>l[e](t);function d(){e.buildOptionsForm=(e,t,n,r)=>{o({id:e,formContainer:t,options:n,renderer:u,translator:r})}}d()})(); \ No newline at end of file diff --git a/dist/types/ahref.d.ts b/dist/types/ahref.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/ahref.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/const.d.ts b/dist/types/const.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/const.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/deprecated.d.ts b/dist/types/deprecated.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/deprecated.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/dom-ready.d.ts b/dist/types/dom-ready.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/types/dom-ready.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/types/events.d.ts b/dist/types/events.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/events.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/iframely.d.ts b/dist/types/iframely.d.ts new file mode 100644 index 0000000..eae984e --- /dev/null +++ b/dist/types/iframely.d.ts @@ -0,0 +1,3 @@ +import type { Iframely } from './types'; +declare const iframely: Iframely; +export default iframely; diff --git a/dist/types/import.d.ts b/dist/types/import.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/import.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/index-options.d.ts b/dist/types/index-options.d.ts new file mode 100644 index 0000000..efc471c --- /dev/null +++ b/dist/types/index-options.d.ts @@ -0,0 +1 @@ +import './dom-ready'; diff --git a/dist/types/index.d.ts b/dist/types/index.d.ts new file mode 100644 index 0000000..efc471c --- /dev/null +++ b/dist/types/index.d.ts @@ -0,0 +1 @@ +import './dom-ready'; diff --git a/dist/types/intersection.d.ts b/dist/types/intersection.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/intersection.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/lazy-iframe.d.ts b/dist/types/lazy-iframe.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/lazy-iframe.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/lazy-img-placeholder.d.ts b/dist/types/lazy-img-placeholder.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/lazy-img-placeholder.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/main-options.d.ts b/dist/types/main-options.d.ts new file mode 100644 index 0000000..1ad0e6c --- /dev/null +++ b/dist/types/main-options.d.ts @@ -0,0 +1,3 @@ +import './index-options'; +export { default as iframely } from './iframely'; +export type * from './types'; diff --git a/dist/types/main.d.ts b/dist/types/main.d.ts new file mode 100644 index 0000000..4edfefd --- /dev/null +++ b/dist/types/main.d.ts @@ -0,0 +1,3 @@ +import './index'; +export { default as iframely } from './iframely'; +export type * from './types'; diff --git a/dist/types/messaging.d.ts b/dist/types/messaging.d.ts new file mode 100644 index 0000000..776572e --- /dev/null +++ b/dist/types/messaging.d.ts @@ -0,0 +1,3 @@ +import type { IframelyMessage } from './types'; +export declare function boot(): void; +export declare function postMessage(message: IframelyMessage | string, target_url?: string, target?: Window | null): void; diff --git a/dist/types/options/entry.d.ts b/dist/types/options/entry.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/types/options/entry.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/types/options/form-builder.d.ts b/dist/types/options/form-builder.d.ts new file mode 100644 index 0000000..de0157c --- /dev/null +++ b/dist/types/options/form-builder.d.ts @@ -0,0 +1,10 @@ +import type { Renderer } from './renderer'; +import type { TranslatorFn, WidgetOptions } from '../types'; +export interface FormBuilderParams { + id: string; + formContainer: HTMLElement; + options?: WidgetOptions; + renderer: Renderer; + translator?: TranslatorFn | null; +} +export default function formBuilder(params: FormBuilderParams): void; diff --git a/dist/types/options/form-generator.d.ts b/dist/types/options/form-generator.d.ts new file mode 100644 index 0000000..23e9d9d --- /dev/null +++ b/dist/types/options/form-generator.d.ts @@ -0,0 +1,2 @@ +import type { FormElement, TranslatorFn, WidgetOptions } from '../types'; +export default function getFormElements(options: WidgetOptions | undefined, translator?: TranslatorFn | null): FormElement[]; diff --git a/dist/types/options/index.d.ts b/dist/types/options/index.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/options/index.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/options/lang/labels.de.d.ts b/dist/types/options/lang/labels.de.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/types/options/lang/labels.de.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/types/options/lang/labels.fr.d.ts b/dist/types/options/lang/labels.fr.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/dist/types/options/lang/labels.fr.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/dist/types/options/renderer.d.ts b/dist/types/options/renderer.d.ts new file mode 100644 index 0000000..0b880d3 --- /dev/null +++ b/dist/types/options/renderer.d.ts @@ -0,0 +1,4 @@ +import type { ElementContext, FormElementType } from '../types'; +export type Renderer = (type: FormElementType, context: ElementContext) => string; +declare const render: Renderer; +export default render; diff --git a/dist/types/options/translator.d.ts b/dist/types/options/translator.d.ts new file mode 100644 index 0000000..143770b --- /dev/null +++ b/dist/types/options/translator.d.ts @@ -0,0 +1 @@ +export declare function registerLabels(lang: string, labels: Record): void; diff --git a/dist/types/theme.d.ts b/dist/types/theme.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/theme.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/types.d.ts b/dist/types/types.d.ts new file mode 100644 index 0000000..2605366 --- /dev/null +++ b/dist/types/types.d.ts @@ -0,0 +1,123 @@ +export type ConfigValue = string | number | boolean; +export interface IframelyConfig { + autorun?: boolean; + theme?: string; + nonce?: string; + cdn?: string; + shadow?: string; + lazy?: ConfigValue; + key?: string; + api_key?: string; + [key: string]: ConfigValue | undefined; +} +export interface IframelyWidget { + iframe: Element; + aspectWrapper: HTMLElement; + maxWidthWrapper: HTMLElement; + url?: string; +} +export interface IframelyMessage { + method?: string; + type?: string; + context?: string; + src?: string; + url?: string; + height?: number; + domains?: string | string[]; + [key: string]: any; +} +export interface FindIframeOptions { + contentWindow: MessageEventSource | Window | null; + src?: string; + domains?: string[] | false; +} +export type TranslatorFn = (label: string) => string; +export type FormElementType = 'checkbox' | 'range' | 'text' | 'radio' | 'select' | 'group'; +export interface RadioItem { + id?: string; + value: string | number | boolean; + label: string; + checked?: boolean; +} +export interface ElementContext { + key?: string; + label?: string | false; + checked?: boolean; + value?: string | number | boolean; + min?: number; + max?: number; + placeholder?: string; + inputType?: string; + inline?: boolean; + items?: RadioItem[]; + elements?: FormElement[]; + elementsHtml?: string; + [key: string]: any; +} +export interface FormElement { + type: FormElementType; + context: ElementContext; + order?: number; + getQuery?: (inputValue: any) => Record; + inputs?: ArrayLike; + [key: string]: any; +} +export interface WidgetOption { + label?: string; + value?: ConfigValue; + values?: Record; + placeholder?: string; + range?: { + min: number; + max: number; + }; + [key: string]: any; +} +export type WidgetOptions = Record; +export interface Iframely { + config: IframelyConfig; + _loaded?: boolean; + on(event: string, cb: (...args: any[]) => void): void; + trigger(event: string, ...args: any[]): void; + triggerAsync(event: string, ...args: any[]): void; + load(...args: any[]): void; + extendOptions(options: Record | undefined): void; + getElementComputedStyle(el: Element, style: string): string | undefined; + findIframe(options: FindIframeOptions): HTMLIFrameElement | undefined; + setTheme(theme?: string): void; + addEventListener(elem: EventTarget, type: string, handler: (e: any) => void): void; + isTouch(): boolean; + buildOptionsForm?(id: string, formContainer: HTMLElement, options: WidgetOptions, translator?: TranslatorFn | null): void; + optionsTranslator?(lang: string): TranslatorFn | undefined; + VERSION: number; + ASPECT_WRAPPER_CLASS: string; + MAXWIDTH_WRAPPER_CLASS: string; + LOADER_CLASS: string; + DOMAINS: string[]; + CDN: string; + BASE_RE: RegExp; + ID_RE: RegExp; + SCRIPT_RE: RegExp; + CDN_RE: RegExp; + SUPPORTED_QUERY_STRING: (string | RegExp)[]; + SUPPORTED_THEMES: string[]; + LAZY_IFRAME_SHOW_TIMEOUT: number; + LAZY_IFRAME_FADE_TIMEOUT: number; + CLEAR_WRAPPER_STYLES_TIMEOUT: number; + RECOVER_HREFS_ON_CANCEL: boolean; + SHADOW: string; + SUPPORT_IFRAME_LOADING_ATTR: boolean; + widgets: { + load?: Iframely['load']; + }; + events: { + on?: Iframely['on']; + trigger?: Iframely['trigger']; + }; + [key: string]: any; +} +declare global { + interface Window { + iframely?: Iframely; + } +} diff --git a/dist/types/utils.d.ts b/dist/types/utils.d.ts new file mode 100644 index 0000000..aa54937 --- /dev/null +++ b/dist/types/utils.d.ts @@ -0,0 +1,17 @@ +import type { IframelyWidget } from './types'; +export declare function boot(): void; +export declare function getIframeWrapper(iframe: Element, checkClass?: boolean): { + aspectWrapper: HTMLElement; + maxWidthWrapper: HTMLElement; +} | undefined; +export declare function addDefaultWrappers(el: Element): { + aspectWrapper: HTMLElement; + maxWidthWrapper: HTMLElement; +}; +export declare function getWidget(iframe: Element): IframelyWidget | undefined; +export declare function setStyles(el: HTMLElement | undefined | null, styles: Record): void; +export declare function applyNonce(element: HTMLElement): void; +export declare function addQueryString(href: string, options: Record): string; +export declare function getEndpoint(src: string, options?: Record, config_params?: (string | RegExp)[]): string; +export declare function parseQueryString(url: string, allowed_query_string?: (string | RegExp)[]): Record; +export declare function createScript(): HTMLScriptElement; diff --git a/dist/types/widget-cancel.d.ts b/dist/types/widget-cancel.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/widget-cancel.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/widget-click.d.ts b/dist/types/widget-click.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/widget-click.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/widget-options.d.ts b/dist/types/widget-options.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/widget-options.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/dist/types/widget-resize.d.ts b/dist/types/widget-resize.d.ts new file mode 100644 index 0000000..46db090 --- /dev/null +++ b/dist/types/widget-resize.d.ts @@ -0,0 +1 @@ +export declare function boot(): void; diff --git a/eslint.config.js b/eslint.config.js index 99a278c..07d70ce 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,27 +1,18 @@ -module.exports = [ +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import globals from 'globals'; + +export default tseslint.config( + { ignores: ['dist/**', 'demo/**'] }, + js.configs.recommended, + ...tseslint.configs.recommended, { + files: ['src/**/*.ts', 'scripts/**/*.js'], languageOptions: { - ecmaVersion: 2018, + ecmaVersion: 'latest', sourceType: 'module', globals: { - ActiveXObject: 'readonly', - console: 'readonly', - window: 'readonly', - document: 'readonly', - navigator: 'readonly', - setTimeout: 'readonly', - clearTimeout: 'readonly', - setInterval: 'readonly', - clearInterval: 'readonly', - requestAnimationFrame: 'readonly', - cancelAnimationFrame: 'readonly', - IntersectionObserver: 'readonly', - MutationObserver: 'readonly', - XMLHttpRequest: 'readonly', - location: 'readonly', - module: 'readonly', - require: 'readonly', - exports: 'readonly' + ...globals.browser } }, rules: { @@ -58,7 +49,8 @@ module.exports = [ { 'allowEmptyCatch': true } - ] + ], + '@typescript-eslint/no-explicit-any': 'off' } } -]; +); diff --git a/package.json b/package.json index d44de9f..c690850 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@iframely/embed.js", - "version": "1.11.0", + "version": "2.0.0", "description": "Iframely embeds cloud JavaScript library, helps with rich media embed codes rendering for Iframely hosted iFrames. Library functions include unfurling URLs, lazy-loading, and rich-media events handling.", "keywords": [ "iframely", @@ -18,22 +18,45 @@ "bugs": { "url": "https://github.com/itteco/embedjs/issues" }, - "main": "src/index.js", + "type": "module", + "main": "./dist/esm/main.js", + "types": "./dist/types/main.d.ts", + "exports": { + ".": { + "types": "./dist/types/main.d.ts", + "import": "./dist/esm/main.js" + }, + "./options": { + "types": "./dist/types/main-options.d.ts", + "import": "./dist/esm/main-options.js" + }, + "./i18n/de": { + "types": "./dist/types/options/lang/labels.de.d.ts", + "import": "./dist/esm/i18n.de.js" + }, + "./i18n/fr": { + "types": "./dist/types/options/lang/labels.fr.d.ts", + "import": "./dist/esm/i18n.fr.js" + } + }, + "files": [ + "dist", + "src" + ], "scripts": { - "start": "webpack --env development --progress --watch", - "prebuild": "eslint ./src/**.js", - "build": "webpack --env production --progress", - "all": "webpack --env production && webpack --env development", - "lint": "eslint ./src/**.js" + "dev": "vite", + "typecheck": "tsc -p tsconfig.json", + "lint": "eslint .", + "prebuild": "pnpm typecheck && pnpm lint", + "build": "node scripts/build.js && tsc -p tsconfig.build.json" }, "devDependencies": { - "ejs-loader": "^0.5.0", + "@eslint/js": "^10.0.1", "eslint": "^10.0.0", - "eslint-webpack-plugin": "^5.0.1", - "webpack": "^5.90.0", - "webpack-cli": "^5.1.4", - "webpack-merge": "^6.0.1", - "ejs": "^5.0.1" + "globals": "^17.7.0", + "typescript": "~5.9.3", + "typescript-eslint": "^8.63.0", + "vite": "^8.1.4" }, "license": "MIT", "dependencies": {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 62d73f6..90f9c8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,33 +8,35 @@ importers: .: devDependencies: - ejs: - specifier: ^5.0.1 - version: 5.0.1 - ejs-loader: - specifier: ^0.5.0 - version: 0.5.0 + '@eslint/js': + specifier: ^10.0.1 + version: 10.0.1(eslint@10.0.3) eslint: specifier: ^10.0.0 version: 10.0.3 - eslint-webpack-plugin: - specifier: ^5.0.1 - version: 5.0.3(eslint@10.0.3)(webpack@5.105.4) - webpack: - specifier: ^5.90.0 - version: 5.105.4(webpack-cli@5.1.4) - webpack-cli: - specifier: ^5.1.4 - version: 5.1.4(webpack@5.105.4) - webpack-merge: - specifier: ^6.0.1 - version: 6.0.1 + globals: + specifier: ^17.7.0 + version: 17.7.0 + typescript: + specifier: ~5.9.3 + version: 5.9.3 + typescript-eslint: + specifier: ^8.63.0 + version: 8.63.0(eslint@10.0.3)(typescript@5.9.3) + vite: + specifier: ^8.1.4 + version: 8.1.4(@types/node@25.5.0)(terser@5.46.0) packages: - '@discoveryjs/json-ext@0.5.7': - resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} - engines: {node: '>=10.0.0'} + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} '@eslint-community/eslint-utils@4.9.1': resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} @@ -58,6 +60,15 @@ packages: resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + '@eslint/object-schema@3.0.3': resolution: {integrity: sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -82,14 +93,6 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jest/types@29.6.3': - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -106,14 +109,115 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@sinclair/typebox@0.27.10': - resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} - - '@types/eslint-scope@3.7.7': - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - - '@types/eslint@9.6.1': - resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.139.0': + resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + + '@rolldown/binding-android-arm64@1.1.5': + resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.1.5': + resolution: {integrity: sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.1.5': + resolution: {integrity: sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.1.5': + resolution: {integrity: sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + resolution: {integrity: sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.1.5': + resolution: {integrity: sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.1.5': + resolution: {integrity: sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + resolution: {integrity: sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.1.5': + resolution: {integrity: sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.1.5': + resolution: {integrity: sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.1.5': + resolution: {integrity: sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.1.5': + resolution: {integrity: sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.1.5': + resolution: {integrity: sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.1.5': + resolution: {integrity: sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.1.5': + resolution: {integrity: sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} @@ -121,108 +225,70 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/istanbul-lib-coverage@2.0.6': - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - - '@types/istanbul-lib-report@3.0.3': - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - - '@types/istanbul-reports@3.0.4': - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} '@types/node@25.5.0': resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} - '@types/yargs-parser@21.0.3': - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - - '@types/yargs@17.0.35': - resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - - '@webassemblyjs/ast@1.14.1': - resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - - '@webassemblyjs/floating-point-hex-parser@1.13.2': - resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - - '@webassemblyjs/helper-api-error@1.13.2': - resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - - '@webassemblyjs/helper-buffer@1.14.1': - resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - - '@webassemblyjs/helper-numbers@1.13.2': - resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': - resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - - '@webassemblyjs/helper-wasm-section@1.14.1': - resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - - '@webassemblyjs/ieee754@1.13.2': - resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - - '@webassemblyjs/leb128@1.13.2': - resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - - '@webassemblyjs/utf8@1.13.2': - resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - - '@webassemblyjs/wasm-edit@1.14.1': - resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - - '@webassemblyjs/wasm-gen@1.14.1': - resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - - '@webassemblyjs/wasm-opt@1.14.1': - resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - - '@webassemblyjs/wasm-parser@1.14.1': - resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + '@typescript-eslint/eslint-plugin@8.63.0': + resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.63.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@webassemblyjs/wast-printer@1.14.1': - resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@typescript-eslint/parser@8.63.0': + resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@webpack-cli/configtest@2.1.1': - resolution: {integrity: sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==} - engines: {node: '>=14.15.0'} + '@typescript-eslint/project-service@8.63.0': + resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - webpack: 5.x.x - webpack-cli: 5.x.x + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@8.63.0': + resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@webpack-cli/info@2.0.2': - resolution: {integrity: sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==} - engines: {node: '>=14.15.0'} + '@typescript-eslint/tsconfig-utils@8.63.0': + resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - webpack: 5.x.x - webpack-cli: 5.x.x + typescript: '>=4.8.4 <6.1.0' - '@webpack-cli/serve@2.0.5': - resolution: {integrity: sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==} - engines: {node: '>=14.15.0'} + '@typescript-eslint/type-utils@8.63.0': + resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - webpack: 5.x.x - webpack-cli: 5.x.x - webpack-dev-server: '*' - peerDependenciesMeta: - webpack-dev-server: - optional: true + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@xtuc/ieee754@1.2.0': - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + '@typescript-eslint/types@8.63.0': + resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@xtuc/long@4.2.2': - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + '@typescript-eslint/typescript-estree@8.63.0': + resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - acorn-import-phases@1.0.4: - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} + '@typescript-eslint/utils@8.63.0': + resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - acorn: ^8.14.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@8.63.0': + resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -234,90 +300,20 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - - ajv-keywords@5.1.0: - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 - ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} - baseline-browser-mapping@2.10.7: - resolution: {integrity: sha512-1ghYO3HnxGec0TCGBXiDLVns4eCSx4zJpxnHrlqFQajmhfKMQBzUGDdkMK7fUW7PTHTeLf+j87aTuKuuwWzMGw==} - engines: {node: '>=6.0.0'} - hasBin: true - - big.js@5.2.2: - resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - brace-expansion@5.0.4: resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} engines: {node: 18 || 20 || >=22} - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - caniuse-lite@1.0.30001778: - resolution: {integrity: sha512-PN7uxFL+ExFJO61aVmP1aIEG4i9whQd4eoSCebav62UwDyp5OHh06zN4jqKSMePVgxHifCw1QJxdRkA1Pisekg==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - clone-deep@4.0.1: - resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} - engines: {node: '>=6'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - - commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -337,45 +333,14 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - ejs-loader@0.5.0: - resolution: {integrity: sha512-iirFqlP3tiFoedNZ7dQcjvechunl054VbW6Ki38T/pabgXMAncduSE0ZXLeVGn1NbmcUJF9Z5TC0EvQ4RIpP9Q==} - - ejs@5.0.1: - resolution: {integrity: sha512-COqBPFMxuPTPspXl2DkVYaDS3HtrD1GpzOGkNTJ1IYkifq/r9h8SVEFrjA3D9/VJGOEoMQcrlhpntcSUrM8k6A==} - engines: {node: '>=0.12.18'} - hasBin: true - - electron-to-chromium@1.5.313: - resolution: {integrity: sha512-QBMrTWEf00GXZmJyx2lbYD45jpI3TUFnNIzJ5BBc8piGUDwMPa1GV6HJWTZVvY/eiN3fSopl7NRbgGp9sZ9LTA==} - - emojis-list@3.0.0: - resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} - engines: {node: '>= 4'} - - enhanced-resolve@5.20.0: - resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} - engines: {node: '>=10.13.0'} - - envinfo@7.21.0: - resolution: {integrity: sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==} - engines: {node: '>=4'} - hasBin: true - - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - eslint-scope@9.1.2: resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -388,13 +353,6 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint-webpack-plugin@5.0.3: - resolution: {integrity: sha512-P2Id4RMSMQMwMEuw3W9x3n2qDbKPeD+tehWMY3ENFsoSPKNZ9i3WTZEsFE7NeQIpNebhNEGw8qorvpLVq1rK1g==} - engines: {node: '>= 18.12.0'} - peerDependencies: - eslint: ^8.0.0 || ^9.0.0 - webpack: ^5.0.0 - eslint@10.0.3: resolution: {integrity: sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -417,10 +375,6 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -429,10 +383,6 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -442,25 +392,19 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - - fastest-levenshtein@1.0.16: - resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} - engines: {node: '>= 4.9.1'} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -469,55 +413,34 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - flatted@3.4.1: resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + globals@17.7.0: + resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} + engines: {node: '>=18'} ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - import-local@3.2.0: - resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} - engines: {node: '>=8'} - hasBin: true + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - interpret@3.1.1: - resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} - engines: {node: '>=10.13.0'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -526,98 +449,103 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} - isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} - - jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - - jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - loader-runner@4.3.1: - resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} - engines: {node: '>=6.11.5'} - - loader-utils@2.0.4: - resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} - engines: {node: '>=8.9.0'} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash@4.17.23: - resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - minimatch@10.2.4: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} @@ -625,43 +553,26 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -670,19 +581,16 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} - pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} + postcss@8.5.16: + resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} + engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -692,34 +600,15 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - rechoir@0.8.0: - resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} - engines: {node: '>= 10.13.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} - - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} + rolldown@1.1.5: + resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} - - shallow-clone@3.0.1: - resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} - engines: {node: '>=8'} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -729,6 +618,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} @@ -736,104 +629,87 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - - terser-webpack-plugin@5.4.0: - resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - terser@5.46.0: resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} engines: {node: '>=10'} hasBin: true - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + typescript-eslint@8.63.0: + resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - watchpack@2.5.1: - resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} - engines: {node: '>=10.13.0'} - - webpack-cli@5.1.4: - resolution: {integrity: sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==} - engines: {node: '>=14.15.0'} + vite@8.1.4: + resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: - '@webpack-cli/generators': '*' - webpack: 5.x.x - webpack-bundle-analyzer: '*' - webpack-dev-server: '*' + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: - '@webpack-cli/generators': + '@types/node': optional: true - webpack-bundle-analyzer: + '@vitejs/devtools': optional: true - webpack-dev-server: + esbuild: optional: true - - webpack-merge@5.10.0: - resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} - engines: {node: '>=10.0.0'} - - webpack-merge@6.0.1: - resolution: {integrity: sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==} - engines: {node: '>=18.0.0'} - - webpack-sources@3.3.4: - resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} - engines: {node: '>=10.13.0'} - - webpack@5.105.4: - resolution: {integrity: sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: optional: true which@2.0.2: @@ -841,9 +717,6 @@ packages: engines: {node: '>= 8'} hasBin: true - wildcard@2.0.1: - resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} - word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} @@ -854,7 +727,21 @@ packages: snapshots: - '@discoveryjs/json-ext@0.5.7': {} + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true '@eslint-community/eslint-utils@4.9.1(eslint@10.0.3)': dependencies: @@ -879,6 +766,10 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@eslint/js@10.0.1(eslint@10.0.3)': + optionalDependencies: + eslint: 10.0.3 + '@eslint/object-schema@3.0.3': {} '@eslint/plugin-kit@0.6.1': @@ -897,174 +788,196 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.10 - - '@jest/types@29.6.3': - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 25.5.0 - '@types/yargs': 17.0.35 - chalk: 4.1.2 - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 + optional: true - '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/resolve-uri@3.1.2': + optional: true '@jridgewell/source-map@0.3.11': dependencies: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 + optional: true - '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.5.5': + optional: true '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + optional: true - '@sinclair/typebox@0.27.10': {} - - '@types/eslint-scope@3.7.7': + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': dependencies: - '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true - '@types/eslint@9.6.1': - dependencies: - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 + '@oxc-project/types@0.139.0': {} - '@types/esrecurse@4.3.1': {} + '@rolldown/binding-android-arm64@1.1.5': + optional: true - '@types/estree@1.0.8': {} + '@rolldown/binding-darwin-arm64@1.1.5': + optional: true - '@types/istanbul-lib-coverage@2.0.6': {} + '@rolldown/binding-darwin-x64@1.1.5': + optional: true - '@types/istanbul-lib-report@3.0.3': - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 + '@rolldown/binding-freebsd-x64@1.1.5': + optional: true - '@types/istanbul-reports@3.0.4': - dependencies: - '@types/istanbul-lib-report': 3.0.3 + '@rolldown/binding-linux-arm-gnueabihf@1.1.5': + optional: true - '@types/json-schema@7.0.15': {} + '@rolldown/binding-linux-arm64-gnu@1.1.5': + optional: true - '@types/node@25.5.0': - dependencies: - undici-types: 7.18.2 + '@rolldown/binding-linux-arm64-musl@1.1.5': + optional: true - '@types/yargs-parser@21.0.3': {} + '@rolldown/binding-linux-ppc64-gnu@1.1.5': + optional: true - '@types/yargs@17.0.35': - dependencies: - '@types/yargs-parser': 21.0.3 + '@rolldown/binding-linux-s390x-gnu@1.1.5': + optional: true - '@webassemblyjs/ast@1.14.1': - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + '@rolldown/binding-linux-x64-gnu@1.1.5': + optional: true - '@webassemblyjs/helper-api-error@1.13.2': {} + '@rolldown/binding-linux-x64-musl@1.1.5': + optional: true - '@webassemblyjs/helper-buffer@1.14.1': {} + '@rolldown/binding-openharmony-arm64@1.1.5': + optional: true - '@webassemblyjs/helper-numbers@1.13.2': + '@rolldown/binding-wasm32-wasi@1.1.5': dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true - '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + '@rolldown/binding-win32-arm64-msvc@1.1.5': + optional: true - '@webassemblyjs/helper-wasm-section@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 + '@rolldown/binding-win32-x64-msvc@1.1.5': + optional: true - '@webassemblyjs/ieee754@1.13.2': - dependencies: - '@xtuc/ieee754': 1.2.0 + '@rolldown/pluginutils@1.0.1': {} - '@webassemblyjs/leb128@1.13.2': + '@tybys/wasm-util@0.10.3': dependencies: - '@xtuc/long': 4.2.2 + tslib: 2.8.1 + optional: true - '@webassemblyjs/utf8@1.13.2': {} + '@types/esrecurse@4.3.1': {} - '@webassemblyjs/wasm-edit@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - - '@webassemblyjs/wasm-gen@1.14.1': + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/node@25.5.0': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 + undici-types: 7.18.2 + optional: true - '@webassemblyjs/wasm-opt@1.14.1': + '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3)': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.63.0(eslint@10.0.3)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/type-utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.63.0 + eslint: 10.0.3 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color - '@webassemblyjs/wasm-parser@1.14.1': + '@typescript-eslint/parser@8.63.0(eslint@10.0.3)(typescript@5.9.3)': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wast-printer@1.14.1': + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.63.0 + debug: 4.4.3 + eslint: 10.0.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.63.0(typescript@5.9.3)': dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) + '@typescript-eslint/types': 8.63.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.105.4)': + '@typescript-eslint/scope-manager@8.63.0': dependencies: - webpack: 5.105.4(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.105.4) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.105.4)': + '@typescript-eslint/tsconfig-utils@8.63.0(typescript@5.9.3)': dependencies: - webpack: 5.105.4(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.105.4) + typescript: 5.9.3 - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.105.4)': + '@typescript-eslint/type-utils@8.63.0(eslint@10.0.3)(typescript@5.9.3)': dependencies: - webpack: 5.105.4(webpack-cli@5.1.4) - webpack-cli: 5.1.4(webpack@5.105.4) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) + debug: 4.4.3 + eslint: 10.0.3 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color - '@xtuc/ieee754@1.2.0': {} + '@typescript-eslint/types@8.63.0': {} - '@xtuc/long@4.2.2': {} + '@typescript-eslint/typescript-estree@8.63.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.63.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/visitor-keys': 8.63.0 + debug: 4.4.3 + minimatch: 10.2.4 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color - acorn-import-phases@1.0.4(acorn@8.16.0): + '@typescript-eslint/utils@8.63.0(eslint@10.0.3)(typescript@5.9.3)': dependencies: - acorn: 8.16.0 + '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) + '@typescript-eslint/scope-manager': 8.63.0 + '@typescript-eslint/types': 8.63.0 + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + eslint: 10.0.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.63.0': + dependencies: + '@typescript-eslint/types': 8.63.0 + eslint-visitor-keys: 5.0.1 acorn-jsx@5.3.2(acorn@8.16.0): dependencies: @@ -1072,15 +985,6 @@ snapshots: acorn@8.16.0: {} - ajv-formats@2.1.1(ajv@8.18.0): - optionalDependencies: - ajv: 8.18.0 - - ajv-keywords@5.1.0(ajv@8.18.0): - dependencies: - ajv: 8.18.0 - fast-deep-equal: 3.1.3 - ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -1088,69 +992,17 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.7: {} - - big.js@5.2.2: {} - brace-expansion@5.0.4: dependencies: balanced-match: 4.0.4 - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.10.7 - caniuse-lite: 1.0.30001778 - electron-to-chromium: 1.5.313 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - buffer-from@1.1.2: {} - - caniuse-lite@1.0.30001778: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chrome-trace-event@1.0.4: {} - - ci-info@3.9.0: {} - - clone-deep@4.0.1: - dependencies: - is-plain-object: 2.0.4 - kind-of: 6.0.3 - shallow-clone: 3.0.1 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - colorette@2.0.20: {} - - commander@10.0.1: {} + buffer-from@1.1.2: + optional: true - commander@2.20.3: {} + commander@2.20.3: + optional: true cross-spawn@7.0.6: dependencies: @@ -1164,35 +1016,10 @@ snapshots: deep-is@0.1.4: {} - ejs-loader@0.5.0: - dependencies: - loader-utils: 2.0.4 - lodash: 4.17.23 - - ejs@5.0.1: {} - - electron-to-chromium@1.5.313: {} - - emojis-list@3.0.0: {} - - enhanced-resolve@5.20.0: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - - envinfo@7.21.0: {} - - es-module-lexer@2.0.0: {} - - escalade@3.2.0: {} + detect-libc@2.1.2: {} escape-string-regexp@4.0.0: {} - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - eslint-scope@9.1.2: dependencies: '@types/esrecurse': 4.3.1 @@ -1204,17 +1031,6 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint-webpack-plugin@5.0.3(eslint@10.0.3)(webpack@5.105.4): - dependencies: - '@types/eslint': 9.6.1 - eslint: 10.0.3 - flatted: 3.4.1 - jest-worker: 29.7.0 - micromatch: 4.0.8 - normalize-path: 3.0.0 - schema-utils: 4.3.3 - webpack: 5.105.4(webpack-cli@5.1.4) - eslint@10.0.3: dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) @@ -1264,37 +1080,24 @@ snapshots: dependencies: estraverse: 5.3.0 - estraverse@4.3.0: {} - estraverse@5.3.0: {} esutils@2.0.3: {} - events@3.3.0: {} - fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} - fast-uri@3.1.0: {} - - fastest-levenshtein@1.0.16: {} + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -1305,132 +1108,98 @@ snapshots: flatted: 3.4.1 keyv: 4.5.4 - flat@5.0.2: {} - flatted@3.4.1: {} - function-bind@1.1.2: {} + fsevents@2.3.3: + optional: true glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - - graceful-fs@4.2.11: {} - - has-flag@4.0.0: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 + globals@17.7.0: {} ignore@5.3.2: {} - import-local@3.2.0: - dependencies: - pkg-dir: 4.2.0 - resolve-cwd: 3.0.0 + ignore@7.0.5: {} imurmurhash@0.1.4: {} - interpret@3.1.1: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - is-extglob@2.1.1: {} is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - is-number@7.0.0: {} - - is-plain-object@2.0.4: - dependencies: - isobject: 3.0.1 - isexe@2.0.0: {} - isobject@3.0.1: {} - - jest-util@29.7.0: - dependencies: - '@jest/types': 29.6.3 - '@types/node': 25.5.0 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - - jest-worker@27.5.1: - dependencies: - '@types/node': 25.5.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - - jest-worker@29.7.0: - dependencies: - '@types/node': 25.5.0 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - json-buffer@3.0.1: {} - json-parse-even-better-errors@2.3.1: {} - json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - json-stable-stringify-without-jsonify@1.0.1: {} - json5@2.2.3: {} - keyv@4.5.4: dependencies: json-buffer: 3.0.1 - kind-of@6.0.3: {} - levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - loader-runner@4.3.1: {} + lightningcss-android-arm64@1.32.0: + optional: true - loader-utils@2.0.4: - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 + lightningcss-darwin-arm64@1.32.0: + optional: true - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 + lightningcss-darwin-x64@1.32.0: + optional: true - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 + lightningcss-freebsd-x64@1.32.0: + optional: true - lodash@4.17.23: {} + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true - merge-stream@2.0.0: {} + lightningcss-linux-arm64-gnu@1.32.0: + optional: true - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true - mime-db@1.52.0: {} + lightningcss-win32-arm64-msvc@1.32.0: + optional: true - mime-types@2.1.35: + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: dependencies: - mime-db: 1.52.0 + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 minimatch@10.2.4: dependencies: @@ -1438,13 +1207,9 @@ snapshots: ms@2.1.3: {} - natural-compare@1.4.0: {} + nanoid@3.3.15: {} - neo-async@2.6.2: {} - - node-releases@2.0.36: {} - - normalize-path@3.0.0: {} + natural-compare@1.4.0: {} optionator@0.9.4: dependencies: @@ -1455,70 +1220,54 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 - p-try@2.2.0: {} - path-exists@4.0.0: {} path-key@3.1.1: {} - path-parse@1.0.7: {} - picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@4.0.5: {} - pkg-dir@4.2.0: + postcss@8.5.16: dependencies: - find-up: 4.1.0 + nanoid: 3.3.15 + picocolors: 1.1.1 + source-map-js: 1.2.1 prelude-ls@1.2.1: {} punycode@2.3.1: {} - rechoir@0.8.0: - dependencies: - resolve: 1.22.11 - - require-from-string@2.0.2: {} - - resolve-cwd@3.0.0: + rolldown@1.1.5: dependencies: - resolve-from: 5.0.0 - - resolve-from@5.0.0: {} - - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - schema-utils@4.3.3: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.18.0 - ajv-formats: 2.1.1(ajv@8.18.0) - ajv-keywords: 5.1.0(ajv@8.18.0) - - shallow-clone@3.0.1: - dependencies: - kind-of: 6.0.3 + '@oxc-project/types': 0.139.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.1.5 + '@rolldown/binding-darwin-arm64': 1.1.5 + '@rolldown/binding-darwin-x64': 1.1.5 + '@rolldown/binding-freebsd-x64': 1.1.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.5 + '@rolldown/binding-linux-arm64-gnu': 1.1.5 + '@rolldown/binding-linux-arm64-musl': 1.1.5 + '@rolldown/binding-linux-ppc64-gnu': 1.1.5 + '@rolldown/binding-linux-s390x-gnu': 1.1.5 + '@rolldown/binding-linux-x64-gnu': 1.1.5 + '@rolldown/binding-linux-x64-musl': 1.1.5 + '@rolldown/binding-openharmony-arm64': 1.1.5 + '@rolldown/binding-wasm32-wasi': 1.1.5 + '@rolldown/binding-win32-arm64-msvc': 1.1.5 + '@rolldown/binding-win32-x64-msvc': 1.1.5 + + semver@7.8.5: {} shebang-command@2.0.0: dependencies: @@ -1526,32 +1275,16 @@ snapshots: shebang-regex@3.0.0: {} + source-map-js@1.2.1: {} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + optional: true - source-map@0.6.1: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - tapable@2.3.0: {} - - terser-webpack-plugin@5.4.0(webpack@5.105.4): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - terser: 5.46.0 - webpack: 5.105.4(webpack-cli@5.1.4) + source-map@0.6.1: + optional: true terser@5.46.0: dependencies: @@ -1559,103 +1292,60 @@ snapshots: acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 + optional: true - to-regex-range@5.0.1: + tinyglobby@0.2.17: dependencies: - is-number: 7.0.0 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 - type-check@0.4.0: + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: - prelude-ls: 1.2.1 + typescript: 5.9.3 - undici-types@7.18.2: {} + tslib@2.8.1: + optional: true - update-browserslist-db@1.2.3(browserslist@4.28.1): + type-check@0.4.0: dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 + prelude-ls: 1.2.1 - uri-js@4.4.1: + typescript-eslint@8.63.0(eslint@10.0.3)(typescript@5.9.3): dependencies: - punycode: 2.3.1 + '@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3) + '@typescript-eslint/parser': 8.63.0(eslint@10.0.3)(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) + eslint: 10.0.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color - watchpack@2.5.1: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 + typescript@5.9.3: {} - webpack-cli@5.1.4(webpack@5.105.4): - dependencies: - '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.105.4) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.105.4) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.105.4) - colorette: 2.0.20 - commander: 10.0.1 - cross-spawn: 7.0.6 - envinfo: 7.21.0 - fastest-levenshtein: 1.0.16 - import-local: 3.2.0 - interpret: 3.1.1 - rechoir: 0.8.0 - webpack: 5.105.4(webpack-cli@5.1.4) - webpack-merge: 5.10.0 - - webpack-merge@5.10.0: - dependencies: - clone-deep: 4.0.1 - flat: 5.0.2 - wildcard: 2.0.1 + undici-types@7.18.2: + optional: true - webpack-merge@6.0.1: + uri-js@4.4.1: dependencies: - clone-deep: 4.0.1 - flat: 5.0.2 - wildcard: 2.0.1 - - webpack-sources@3.3.4: {} + punycode: 2.3.1 - webpack@5.105.4(webpack-cli@5.1.4): + vite@8.1.4(@types/node@25.5.0)(terser@5.46.0): dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.16.0 - acorn-import-phases: 1.0.4(acorn@8.16.0) - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.20.0 - es-module-lexer: 2.0.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.4.0(webpack@5.105.4) - watchpack: 2.5.1 - webpack-sources: 3.3.4 + lightningcss: 1.32.0 + picomatch: 4.0.5 + postcss: 8.5.16 + rolldown: 1.1.5 + tinyglobby: 0.2.17 optionalDependencies: - webpack-cli: 5.1.4(webpack@5.105.4) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js + '@types/node': 25.5.0 + fsevents: 2.3.3 + terser: 5.46.0 which@2.0.2: dependencies: isexe: 2.0.0 - wildcard@2.0.1: {} - word-wrap@1.2.5: {} yocto-queue@0.1.0: {} diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..652080b --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,65 @@ +import { rm } from 'node:fs/promises'; +import { build } from 'vite'; + +// Each IIFE bundle must be a single self-contained file with a fixed name: +// the library locates its own + + + diff --git a/demo/old.html b/demo/old.html deleted file mode 100644 index 10e26cd..0000000 --- a/demo/old.html +++ /dev/null @@ -1,7 +0,0 @@ - - -old embed.js surface - - - - diff --git a/eslint.config.js b/eslint.config.js index 07d70ce..89a4285 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,11 +3,11 @@ import tseslint from 'typescript-eslint'; import globals from 'globals'; export default tseslint.config( - { ignores: ['dist/**', 'demo/**'] }, + { ignores: ['dist/**', 'demo/**', 'test-results/**', 'playwright-report/**'] }, js.configs.recommended, ...tseslint.configs.recommended, { - files: ['src/**/*.ts', 'scripts/**/*.js'], + files: ['src/**/*.ts', 'scripts/**/*.{js,mjs}', 'tests/**/*.ts', '*.config.ts'], languageOptions: { ecmaVersion: 'latest', sourceType: 'module', @@ -52,5 +52,13 @@ export default tseslint.config( ], '@typescript-eslint/no-explicit-any': 'off' } + }, + { + files: ['scripts/**/*.{js,mjs}'], + languageOptions: { + globals: { + ...globals.node + } + } } ); diff --git a/package.json b/package.json index c690850..0b05cf9 100644 --- a/package.json +++ b/package.json @@ -45,19 +45,25 @@ ], "scripts": { "dev": "vite", + "serve": "node scripts/serve.mjs", "typecheck": "tsc -p tsconfig.json", "lint": "eslint .", + "test": "vitest run", + "test:watch": "vitest", + "test:e2e": "node scripts/build.js && playwright test", "prebuild": "pnpm typecheck && pnpm lint", "build": "node scripts/build.js && tsc -p tsconfig.build.json" }, "devDependencies": { "@eslint/js": "^10.0.1", + "@playwright/test": "^1.61.1", "eslint": "^10.0.0", "globals": "^17.7.0", + "jsdom": "^29.1.1", "typescript": "~5.9.3", "typescript-eslint": "^8.63.0", - "vite": "^8.1.4" + "vite": "^8.1.4", + "vitest": "^4.1.10" }, - "license": "MIT", - "dependencies": {} + "license": "MIT" } diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..d3d050e --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,26 @@ +import { defineConfig, devices } from '@playwright/test'; + +// Fixture pages in demo/ reference http://localhost:8917 with absolute URLs +// because the library's SCRIPT_RE self-configuration only matches absolute +// script src values. Keep the port in sync with scripts/serve.mjs. +const BASE_URL = 'http://localhost:8917'; + +export default defineConfig({ + testDir: 'tests/e2e', + fullyParallel: true, + reporter: [['list']], + use: { + baseURL: BASE_URL + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] } + } + ], + webServer: { + command: 'node scripts/serve.mjs', + url: BASE_URL + '/demo/index.html', + reuseExistingServer: true + } +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 90f9c8f..2fe9891 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,12 +11,18 @@ importers: '@eslint/js': specifier: ^10.0.1 version: 10.0.1(eslint@10.0.3) + '@playwright/test': + specifier: ^1.61.1 + version: 1.61.1 eslint: specifier: ^10.0.0 version: 10.0.3 globals: specifier: ^17.7.0 version: 17.7.0 + jsdom: + specifier: ^29.1.1 + version: 29.1.1 typescript: specifier: ~5.9.3 version: 5.9.3 @@ -26,9 +32,67 @@ importers: vite: specifier: ^8.1.4 version: 8.1.4(@types/node@25.5.0)(terser@5.46.0) + vitest: + specifier: ^4.1.10 + version: 4.1.10(@types/node@25.5.0)(jsdom@29.1.1)(vite@8.1.4(@types/node@25.5.0)(terser@5.46.0)) packages: + '@asamuzakjp/css-color@5.1.11': + resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/dom-selector@7.1.1': + resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/generational-cache@1.0.1': + resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + + '@csstools/color-helpers@6.1.0': + resolution: {integrity: sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.2.1': + resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.1.9': + resolution: {integrity: sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.6': + resolution: {integrity: sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + '@emnapi/core@1.11.1': resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} @@ -77,6 +141,15 @@ packages: resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -118,6 +191,11 @@ packages: '@oxc-project/types@0.139.0': resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + '@playwright/test@1.61.1': + resolution: {integrity: sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==} + engines: {node: '>=18'} + hasBin: true + '@rolldown/binding-android-arm64@1.1.5': resolution: {integrity: sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -216,9 +294,18 @@ packages: '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} @@ -290,6 +377,35 @@ packages: resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vitest/expect@4.1.10': + resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} + + '@vitest/mocker@4.1.10': + resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.10': + resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + + '@vitest/runner@4.1.10': + resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + + '@vitest/snapshot@4.1.10': + resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + + '@vitest/spy@4.1.10': + resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + + '@vitest/utils@4.1.10': + resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -303,10 +419,17 @@ packages: ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + brace-expansion@5.0.4: resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} engines: {node: 18 || 20 || >=22} @@ -314,13 +437,28 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -330,6 +468,9 @@ packages: supports-color: optional: true + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -337,6 +478,13 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + + es-module-lexer@2.3.0: + resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} @@ -379,10 +527,17 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -416,6 +571,11 @@ packages: flatted@3.4.1: resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -429,6 +589,10 @@ packages: resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} engines: {node: '>=18'} + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -449,9 +613,21 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jsdom@29.1.1: + resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -546,6 +722,16 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + minimatch@10.2.4: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} @@ -561,6 +747,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + obug@2.1.3: + resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} + engines: {node: '>=12.20.0'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -573,6 +763,9 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -581,6 +774,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -588,6 +784,16 @@ packages: resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} engines: {node: '>=12'} + playwright-core@1.61.1: + resolution: {integrity: sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.61.1: + resolution: {integrity: sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==} + engines: {node: '>=18'} + hasBin: true + postcss@8.5.16: resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} engines: {node: ^10 || ^12 || >=14} @@ -600,11 +806,19 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + rolldown@1.1.5: resolution: {integrity: sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} @@ -618,6 +832,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -629,15 +846,50 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + terser@5.46.0: resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} engines: {node: '>=10'} hasBin: true + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.17: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + tldts-core@7.4.7: + resolution: {integrity: sha512-rNlAI8fKn/JckBMUSbNL/ES2kmDiurWaE49l+ikwEc9A6lFR7gMx9AhgQMQKBK4H5w4pKLH64JzZfB99uRsGNQ==} + + tldts@7.4.7: + resolution: {integrity: sha512-56L0/9HELHSsG1bFCzay8UoLxzRL7kpFf7Wl5q/kSYwiSJGACvro61xnKzPNM+SadxllzdtXsKDSXE7HPeqIAw==} + hasBin: true + + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} + engines: {node: '>=16'} + + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -666,6 +918,10 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici@7.28.0: + resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} + engines: {node: '>=20.18.1'} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -712,21 +968,138 @@ packages: yaml: optional: true + vitest@4.1.10: + resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.10 + '@vitest/browser-preview': 4.1.10 + '@vitest/browser-webdriverio': 4.1.10 + '@vitest/coverage-istanbul': 4.1.10 + '@vitest/coverage-v8': 4.1.10 + '@vitest/ui': 4.1.10 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} snapshots: + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@asamuzakjp/dom-selector@7.1.1': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + + '@asamuzakjp/generational-cache@1.0.1': {} + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + + '@csstools/color-helpers@6.1.0': {} + + '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.1.9(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.1.0 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.6(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} + '@emnapi/core@1.11.1': dependencies: '@emnapi/wasi-threads': 1.2.2 @@ -777,6 +1150,8 @@ snapshots: '@eslint/core': 1.1.1 levn: 0.4.1 + '@exodus/bytes@1.15.1': {} + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -803,8 +1178,7 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 optional: true - '@jridgewell/sourcemap-codec@1.5.5': - optional: true + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': dependencies: @@ -821,6 +1195,10 @@ snapshots: '@oxc-project/types@0.139.0': {} + '@playwright/test@1.61.1': + dependencies: + playwright: 1.61.1 + '@rolldown/binding-android-arm64@1.1.5': optional: true @@ -872,11 +1250,20 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} + '@standard-schema/spec@1.1.0': {} + '@tybys/wasm-util@0.10.3': dependencies: tslib: 2.8.1 optional: true + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + '@types/esrecurse@4.3.1': {} '@types/estree@1.0.8': {} @@ -979,6 +1366,47 @@ snapshots: '@typescript-eslint/types': 8.63.0 eslint-visitor-keys: 5.0.1 + '@vitest/expect@4.1.10': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.10(vite@8.1.4(@types/node@25.5.0)(terser@5.46.0))': + dependencies: + '@vitest/spy': 4.1.10 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.1.4(@types/node@25.5.0)(terser@5.46.0) + + '@vitest/pretty-format@4.1.10': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.10': + dependencies: + '@vitest/utils': 4.1.10 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.10': + dependencies: + '@vitest/pretty-format': 4.1.10 + '@vitest/utils': 4.1.10 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.10': {} + + '@vitest/utils@4.1.10': + dependencies: + '@vitest/pretty-format': 4.1.10 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -992,8 +1420,14 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + assertion-error@2.0.1: {} + balanced-match@4.0.4: {} + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + brace-expansion@5.0.4: dependencies: balanced-match: 4.0.4 @@ -1001,23 +1435,45 @@ snapshots: buffer-from@1.1.2: optional: true + chai@6.2.2: {} + commander@2.20.3: optional: true + convert-source-map@2.0.0: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + data-urls@7.0.0: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + transitivePeerDependencies: + - '@noble/hashes' + debug@4.4.3: dependencies: ms: 2.1.3 + decimal.js@10.6.0: {} + deep-is@0.1.4: {} detect-libc@2.1.2: {} + entities@8.0.0: {} + + es-module-lexer@2.3.0: {} + escape-string-regexp@4.0.0: {} eslint-scope@9.1.2: @@ -1082,8 +1538,14 @@ snapshots: estraverse@5.3.0: {} + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + esutils@2.0.3: {} + expect-type@1.4.0: {} + fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} @@ -1110,6 +1572,9 @@ snapshots: flatted@3.4.1: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -1119,6 +1584,12 @@ snapshots: globals@17.7.0: {} + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + ignore@5.3.2: {} ignore@7.0.5: {} @@ -1131,8 +1602,36 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-potential-custom-element-name@1.0.1: {} + isexe@2.0.0: {} + jsdom@29.1.1: + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.6(css-tree@3.2.1) + '@exodus/bytes': 1.15.1 + css-tree: 3.2.1 + data-urls: 7.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.2 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.2 + undici: 7.28.0 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + json-buffer@3.0.1: {} json-schema-traverse@0.4.1: {} @@ -1201,6 +1700,14 @@ snapshots: dependencies: p-locate: 5.0.0 + lru-cache@11.5.2: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + mdn-data@2.27.1: {} + minimatch@10.2.4: dependencies: brace-expansion: 5.0.4 @@ -1211,6 +1718,8 @@ snapshots: natural-compare@1.4.0: {} + obug@2.1.3: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -1228,14 +1737,28 @@ snapshots: dependencies: p-limit: 3.1.0 + parse5@8.0.1: + dependencies: + entities: 8.0.0 + path-exists@4.0.0: {} path-key@3.1.1: {} + pathe@2.0.3: {} + picocolors@1.1.1: {} picomatch@4.0.5: {} + playwright-core@1.61.1: {} + + playwright@1.61.1: + dependencies: + playwright-core: 1.61.1 + optionalDependencies: + fsevents: 2.3.2 + postcss@8.5.16: dependencies: nanoid: 3.3.15 @@ -1246,6 +1769,8 @@ snapshots: punycode@2.3.1: {} + require-from-string@2.0.2: {} + rolldown@1.1.5: dependencies: '@oxc-project/types': 0.139.0 @@ -1267,6 +1792,10 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.1.5 '@rolldown/binding-win32-x64-msvc': 1.1.5 + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + semver@7.8.5: {} shebang-command@2.0.0: @@ -1275,6 +1804,8 @@ snapshots: shebang-regex@3.0.0: {} + siginfo@2.0.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -1286,6 +1817,12 @@ snapshots: source-map@0.6.1: optional: true + stackback@0.0.2: {} + + std-env@4.2.0: {} + + symbol-tree@3.2.4: {} + terser@5.46.0: dependencies: '@jridgewell/source-map': 0.3.11 @@ -1294,11 +1831,31 @@ snapshots: source-map-support: 0.5.21 optional: true + tinybench@2.9.0: {} + + tinyexec@1.2.4: {} + tinyglobby@0.2.17: dependencies: fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 + tinyrainbow@3.1.0: {} + + tldts-core@7.4.7: {} + + tldts@7.4.7: + dependencies: + tldts-core: 7.4.7 + + tough-cookie@6.0.2: + dependencies: + tldts: 7.4.7 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + ts-api-utils@2.5.0(typescript@5.9.3): dependencies: typescript: 5.9.3 @@ -1326,6 +1883,8 @@ snapshots: undici-types@7.18.2: optional: true + undici@7.28.0: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -1342,10 +1901,63 @@ snapshots: fsevents: 2.3.3 terser: 5.46.0 + vitest@4.1.10(@types/node@25.5.0)(jsdom@29.1.1)(vite@8.1.4(@types/node@25.5.0)(terser@5.46.0)): + dependencies: + '@vitest/expect': 4.1.10 + '@vitest/mocker': 4.1.10(vite@8.1.4(@types/node@25.5.0)(terser@5.46.0)) + '@vitest/pretty-format': 4.1.10 + '@vitest/runner': 4.1.10 + '@vitest/snapshot': 4.1.10 + '@vitest/spy': 4.1.10 + '@vitest/utils': 4.1.10 + es-module-lexer: 2.3.0 + expect-type: 1.4.0 + magic-string: 0.30.21 + obug: 2.1.3 + pathe: 2.0.3 + picomatch: 4.0.5 + std-env: 4.2.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.1.4(@types/node@25.5.0)(terser@5.46.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.5.0 + jsdom: 29.1.1 + transitivePeerDependencies: + - msw + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@8.0.1: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@16.0.1: + dependencies: + '@exodus/bytes': 1.15.1 + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + which@2.0.2: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + word-wrap@1.2.5: {} + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + yocto-queue@0.1.0: {} diff --git a/scripts/serve.mjs b/scripts/serve.mjs new file mode 100644 index 0000000..45208fa --- /dev/null +++ b/scripts/serve.mjs @@ -0,0 +1,37 @@ +// Tiny static server for the demo pages and Playwright e2e tests. +// Serves the repo root so /dist and /demo resolve as they do in production. +import { createServer } from 'node:http'; +import { readFile } from 'node:fs/promises'; +import { join, extname, normalize, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const root = normalize(join(dirname(fileURLToPath(import.meta.url)), '..')); +const port = Number(process.env.PORT) || 8917; + +const mime = { + '.html': 'text/html; charset=utf-8', + '.js': 'text/javascript; charset=utf-8', + '.mjs': 'text/javascript; charset=utf-8', + '.css': 'text/css', + '.json': 'application/json', + '.map': 'application/json' +}; + +createServer(async (req, res) => { + try { + const urlPath = decodeURIComponent(new URL(req.url, 'http://x').pathname); + let filePath = normalize(join(root, urlPath)); + if (!filePath.startsWith(root)) { + res.writeHead(403).end(); + return; + } + if (urlPath === '/') { + filePath = join(root, 'demo/index.html'); + } + const data = await readFile(filePath); + res.writeHead(200, { 'content-type': mime[extname(filePath)] || 'application/octet-stream' }); + res.end(data); + } catch { + res.writeHead(404).end('not found'); + } +}).listen(port, () => console.warn(`serving ${root} on http://localhost:${port}`)); diff --git a/src/types.ts b/src/types.ts index 18d6c84..a0c9a67 100644 --- a/src/types.ts +++ b/src/types.ts @@ -103,7 +103,7 @@ export interface Iframely { findIframe(options: FindIframeOptions): HTMLIFrameElement | undefined; // theme.ts - setTheme(theme?: string): void; + setTheme(theme?: string, container?: Element): void; // import.ts addEventListener(elem: EventTarget, type: string, handler: (e: any) => void): void; diff --git a/tests/e2e/double-load.spec.ts b/tests/e2e/double-load.spec.ts new file mode 100644 index 0000000..b31f278 --- /dev/null +++ b/tests/e2e/double-load.spec.ts @@ -0,0 +1,14 @@ +import { test, expect } from '@playwright/test'; + +test('loading embed.js and embed-options.js together boots exactly once', async ({ page }) => { + await page.goto('/demo/double.html'); + await page.waitForFunction(() => (window as any).iframely && (window as any).iframely._loaded); + + const state = await page.evaluate(() => ({ + initCount: (window as any).__initCount(), + hasOn: typeof (window as any).iframely.on === 'function' + })); + + expect(state.initCount).toBe(1); + expect(state.hasOn).toBe(true); +}); diff --git a/tests/e2e/embed.spec.ts b/tests/e2e/embed.spec.ts new file mode 100644 index 0000000..6f35a64 --- /dev/null +++ b/tests/e2e/embed.spec.ts @@ -0,0 +1,82 @@ +import { test, expect, type Page } from '@playwright/test'; + +// Serve a stub widget instead of the real Iframely CDN so tests are +// deterministic. The stub can post messages back to the parent page, +// exercising the full messaging -> findIframe -> handler chain. +async function stubWidget(page: Page, bodyScript = ''): Promise { + await page.route('**/api/iframe*', route => route.fulfill({ + contentType: 'text/html', + body: `` + })); +} + +test('parses config from its own script src query string', async ({ page }) => { + await stubWidget(page); + await page.goto('/demo/index.html'); + + await page.waitForFunction(() => (window as any).iframely && (window as any).iframely._loaded); + + const state = await page.evaluate(() => { + const iframely = (window as any).iframely; + return { + api_key: iframely.config.api_key, + theme: iframely.config.theme, + intersection: iframely.config.intersection, + cdn: iframely.CDN, + stylesInjected: !!document.getElementById('iframely-styles') + }; + }); + + expect(state).toEqual({ + api_key: 'TEST', + theme: 'dark', + intersection: true, + cdn: 'cdn.iframe.ly', + stylesInjected: true + }); +}); + +test('unfurls an anchor into an iframe pointing at the API endpoint', async ({ page }) => { + await stubWidget(page); + await page.goto('/demo/index.html'); + + const iframe = page.locator('.iframely-responsive iframe'); + await expect(iframe).toHaveCount(1); + await expect(page.locator('a[data-iframely-url]')).toHaveCount(0); + + const src = await iframe.getAttribute('src'); + expect(src).toContain('cdn.iframe.ly/api/iframe'); + expect(src).toContain('url=' + encodeURIComponent('https://www.youtube.com/watch?v=dQw4w9WgXcQ')); + expect(src).toContain('v=1'); + expect(src).toContain('app=1'); + expect(src).toContain('theme=dark'); + expect(src).toContain('api_key=TEST'); +}); + +test('handles a resize message from the widget iframe', async ({ page }) => { + await stubWidget(page, "parent.postMessage(JSON.stringify({ method: 'resize', height: 400 }), '*');"); + await page.goto('/demo/index.html'); + + const aspectWrapper = page.locator('.iframely-responsive'); + await expect(aspectWrapper).toHaveCSS('height', '400px'); + await expect(aspectWrapper).toHaveCSS('padding-bottom', '0px'); +}); + +test('handles a cancelWidget message by removing the widget', async ({ page }) => { + await stubWidget(page, "parent.postMessage(JSON.stringify({ method: 'cancelWidget' }), '*');"); + await page.goto('/demo/index.html'); + + await expect(page.locator('.iframely-embed')).toHaveCount(0); + await expect(page.locator('iframe')).toHaveCount(0); +}); + +test('recreates a link on cancel when the anchor had text', async ({ page }) => { + await stubWidget(page, "parent.postMessage(JSON.stringify({ method: 'cancelWidget' }), '*');"); + await page.goto('/demo/cancel-recover.html'); + + const link = page.locator('a[href="https://www.youtube.com/watch?v=dQw4w9WgXcQ"]'); + await expect(link).toHaveText('Watch the video'); + await expect(link).toHaveAttribute('target', '_blank'); + await expect(link).toHaveAttribute('rel', 'noopener'); + await expect(page.locator('.iframely-embed')).toHaveCount(0); +}); diff --git a/tests/e2e/esm.spec.ts b/tests/e2e/esm.spec.ts new file mode 100644 index 0000000..eefd0ef --- /dev/null +++ b/tests/e2e/esm.spec.ts @@ -0,0 +1,13 @@ +import { test, expect } from '@playwright/test'; + +test('the ESM build exports the same singleton that is attached to window', async ({ page }) => { + await page.goto('/demo/esm.html'); + await page.waitForFunction(() => !!(window as any).__esm); + + const state = await page.evaluate(() => (window as any).__esm); + expect(state).toEqual({ + sameSingleton: true, + version: 1, + hasOn: true + }); +}); diff --git a/tests/e2e/options.spec.ts b/tests/e2e/options.spec.ts new file mode 100644 index 0000000..1534c96 --- /dev/null +++ b/tests/e2e/options.spec.ts @@ -0,0 +1,43 @@ +import { test, expect } from '@playwright/test'; + +test.beforeEach(async ({ page }) => { + await page.goto('/demo/options.html'); + await page.waitForFunction(() => !!document.querySelector('#form input')); +}); + +test('renders all option element types, grouped', async ({ page }) => { + const form = page.locator('#form'); + await expect(form.locator('input[type="checkbox"]')).toHaveCount(2); + await expect(form.locator('input[type="radio"]')).toHaveCount(3); + await expect(form.locator('select')).toHaveCount(1); + await expect(form.locator('input[type="range"]')).toHaveCount(1); + // Checkboxes are wrapped in a group container. + await expect(form.locator('.iframely-option__group .iframely-option-checkbox')).toHaveCount(2); +}); + +test('applies German labels from the separately loaded i18n bundle', async ({ page }) => { + const labels = await page.locator('#form label').allTextContents(); + const text = labels.join('|'); + expect(text).toContain('Theme Farbe'); + expect(text).toContain('Artwork ausblenden'); + expect(text).toContain('Wiedergabeliste anzeigen'); + expect(text).toContain('Höhe einstellen'); + // Select options are translated too. + const optionTexts = await page.locator('#form select option').allTextContents(); + expect(optionTexts).toContain('Klassisch'); + expect(optionTexts).toContain('Bild'); +}); + +test('fires options-changed with the non-default query on user input', async ({ page }) => { + await page.locator('#form input[name="_hide"]').check(); + + const changes = await page.evaluate(() => (window as any).__optionsChanged); + expect(changes).toHaveLength(1); + expect(changes[0].id).toBe('test-form'); + expect(changes[0].query._hide).toBe(true); + + await page.locator('#form select[name="style"]').selectOption('mini'); + const changes2 = await page.evaluate(() => (window as any).__optionsChanged); + expect(changes2).toHaveLength(2); + expect(changes2[1].query.style).toBe('mini'); +}); diff --git a/tests/e2e/surface.spec.ts b/tests/e2e/surface.spec.ts new file mode 100644 index 0000000..a07cfa6 --- /dev/null +++ b/tests/e2e/surface.spec.ts @@ -0,0 +1,48 @@ +import { test, expect } from '@playwright/test'; + +// The public window.iframely surface as shipped by the last webpack build +// (v1.11). The migration must not add or remove keys. +const EXPECTED_KEYS = [ + 'ASPECT_WRAPPER_CLASS', 'BASE_RE', 'CDN', 'CDN_RE', 'CLEAR_WRAPPER_STYLES_TIMEOUT', + 'DOMAINS', 'ID_RE', 'LAZY_IFRAME_FADE_TIMEOUT', 'LAZY_IFRAME_SHOW_TIMEOUT', + 'LOADER_CLASS', 'MAXWIDTH_WRAPPER_CLASS', 'RECOVER_HREFS_ON_CANCEL', 'SCRIPT_RE', + 'SHADOW', 'SUPPORTED_QUERY_STRING', 'SUPPORTED_THEMES', 'SUPPORT_IFRAME_LOADING_ATTR', + 'VERSION', '_loaded', 'addEventListener', 'buildImportWidgets', 'cancelWidget', + 'config', 'events', 'extendOptions', 'findIframe', 'getElementComputedStyle', + 'isTouch', 'load', 'on', 'openHref', 'setTheme', 'trigger', 'triggerAsync', 'widgets' +]; + +test('embed.js exposes the exact pre-migration API surface', async ({ page }) => { + await page.goto('/demo/new.html'); + await page.waitForFunction(() => (window as any).iframely && (window as any).iframely._loaded); + + const keys = await page.evaluate(() => Object.keys((window as any).iframely).sort()); + expect(keys).toEqual(EXPECTED_KEYS); + + const constants = await page.evaluate(() => { + const iframely = (window as any).iframely; + return { + version: iframely.VERSION, + supportsLoadingAttr: iframely.SUPPORT_IFRAME_LOADING_ATTR, + domains: iframely.DOMAINS + }; + }); + // VERSION is sent to the API as the v= param; it must stay 1. + expect(constants.version).toBe(1); + expect(constants.supportsLoadingAttr).toBe(true); + expect(constants.domains).toEqual(['cdn.iframe.ly', 'iframe.ly', 'if-cdn.com', 'iframely.net']); +}); + +test('embed-options.js additionally exposes buildOptionsForm', async ({ page }) => { + await page.goto('/demo/options.html'); + await page.waitForFunction(() => (window as any).iframely && (window as any).iframely._loaded); + + const extras = await page.evaluate(() => { + const iframely = (window as any).iframely; + return { + buildOptionsForm: typeof iframely.buildOptionsForm, + optionsTranslator: typeof iframely.optionsTranslator + }; + }); + expect(extras).toEqual({ buildOptionsForm: 'function', optionsTranslator: 'function' }); +}); diff --git a/tests/unit/events.test.ts b/tests/unit/events.test.ts new file mode 100644 index 0000000..8ea4a87 --- /dev/null +++ b/tests/unit/events.test.ts @@ -0,0 +1,59 @@ +import { beforeAll, describe, expect, it, vi } from 'vitest'; +import iframely from '../../src/iframely'; +import { boot as bootEvents } from '../../src/events'; + +beforeAll(() => { + bootEvents(); +}); + +describe('events', () => { + + it('calls handlers synchronously with trigger, in registration order', () => { + const calls: string[] = []; + iframely.on('sync-test', () => calls.push('first')); + iframely.on('sync-test', () => calls.push('second')); + + iframely.trigger('sync-test'); + expect(calls).toEqual(['first', 'second']); + }); + + it('passes trigger arguments and binds this to the singleton', () => { + let seenArgs: any[] = []; + let seenThis: any; + iframely.on('args-test', function(this: any, ...args: any[]) { + seenArgs = args; + // eslint-disable-next-line @typescript-eslint/no-this-alias + seenThis = this; + }); + + iframely.trigger('args-test', 1, 'two', { three: 3 }); + expect(seenArgs).toEqual([1, 'two', { three: 3 }]); + expect(seenThis).toBe(iframely); + }); + + it('does not call handlers of other events', () => { + const cb = vi.fn(); + iframely.on('event-a', cb); + iframely.trigger('event-b'); + expect(cb).not.toHaveBeenCalled(); + }); + + it('triggerAsync defers handlers to the next animation frame', async () => { + const cb = vi.fn(); + iframely.on('async-test', cb); + + iframely.triggerAsync('async-test', 42); + expect(cb).not.toHaveBeenCalled(); + + await vi.waitFor(() => expect(cb).toHaveBeenCalledWith(42)); + }); + + it('clears init handlers after the first init', () => { + const cb = vi.fn(); + iframely.on('init', cb); + + iframely.trigger('init'); + iframely.trigger('init'); + expect(cb).toHaveBeenCalledTimes(1); + }); +}); diff --git a/tests/unit/form-builder.test.ts b/tests/unit/form-builder.test.ts new file mode 100644 index 0000000..003606c --- /dev/null +++ b/tests/unit/form-builder.test.ts @@ -0,0 +1,112 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import iframely from '../../src/iframely'; +import { boot as bootConst } from '../../src/const'; +import { boot as bootEvents } from '../../src/events'; +import formBuilder from '../../src/options/form-builder'; +import renderer from '../../src/options/renderer'; + +beforeAll(() => { + bootConst(); + bootEvents(); + // Provided by import.ts in the embed bundle; stubbed here to unit-test + // the options subsystem in isolation. + iframely.addEventListener = (elem, type, handler) => elem.addEventListener(type, handler); +}); + +let container: HTMLElement; +let changes: { id: string, query: Record }[]; + +beforeEach(() => { + document.body.innerHTML = '
'; + container = document.getElementById('form')!; + changes = []; +}); + +function buildForm(id = 'test-' + Math.random()): string { + formBuilder({ + id: id, + formContainer: container, + renderer: renderer, + options: { + theme: { label: 'Theme color', value: 'light', values: { light: 'Light', dark: 'Dark', auto: 'Auto' } }, + _hide: { label: 'Hide artwork', value: false }, + _playlist: { label: 'Include playlist', value: true }, + maxheight: { label: 'Adjust height', value: '' } + } + }); + return id; +} + +describe('form-builder', () => { + + beforeAll(() => { + iframely.on('options-changed', (id: string, formContainer: HTMLElement, query: Record) => { + changes.push({ id, query }); + }); + }); + + it('renders all element types into the container', () => { + buildForm(); + expect(container.querySelectorAll('input[type="radio"]')).toHaveLength(3); + expect(container.querySelectorAll('input[type="checkbox"]')).toHaveLength(2); + expect(container.querySelectorAll('input[type="text"]')).toHaveLength(1); + expect(container.querySelectorAll('.iframely-option__group').length).toBeGreaterThan(0); + }); + + it('fires options-changed with only non-default values', () => { + const id = buildForm(); + + const hide = container.querySelector('input[name="_hide"]')!; + hide.checked = true; + hide.dispatchEvent(new Event('change', { bubbles: true })); + + expect(changes).toHaveLength(1); + expect(changes[0].id).toBe(id); + expect(changes[0].query).toEqual({ _hide: true }); + }); + + it('omits values that return to their defaults', () => { + buildForm(); + + const dark = container.querySelector('input[name="theme"][value="dark"]')!; + dark.checked = true; + dark.dispatchEvent(new Event('change', { bubbles: true })); + expect(changes[0].query).toEqual({ theme: 'dark' }); + + const light = container.querySelector('input[name="theme"][value="light"]')!; + light.checked = true; + dark.checked = false; + light.dispatchEvent(new Event('change', { bubbles: true })); + expect(changes[1].query).toEqual({}); + }); + + it('submits text inputs on Enter', () => { + buildForm(); + + const text = container.querySelector('input[name="maxheight"]')!; + text.value = '300'; + const enter = new KeyboardEvent('keyup'); + Object.defineProperty(enter, 'keyCode', { value: 13 }); + text.dispatchEvent(enter); + + expect(changes).toHaveLength(1); + expect(changes[0].query).toEqual({ maxheight: '300' }); + + text.value = '400'; + text.dispatchEvent(new FocusEvent('blur')); + expect(changes[1].query).toEqual({ maxheight: '400' }); + }); + + it('clears the container when options are missing', () => { + container.innerHTML = 'old'; + formBuilder({ id: 'x', formContainer: container, renderer: renderer }); + expect(container.innerHTML).toBe(''); + }); + + it('warns without a form container', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + formBuilder({ id: 'x', formContainer: null as unknown as HTMLElement, renderer: renderer }); + expect(warn).toHaveBeenCalled(); + warn.mockRestore(); + }); +}); diff --git a/tests/unit/form-generator.test.ts b/tests/unit/form-generator.test.ts new file mode 100644 index 0000000..d0ae8bc --- /dev/null +++ b/tests/unit/form-generator.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, it } from 'vitest'; +import getFormElements from '../../src/options/form-generator'; +import type { FormElement } from '../../src/types'; + +function flatten(elements: FormElement[]): FormElement[] { + return elements.flatMap(el => el.type === 'group' ? flatten(el.context.elements!) : [el]); +} + +describe('form-generator', () => { + + it('returns an empty list without options', () => { + expect(getFormElements(undefined)).toEqual([]); + }); + + it('drops the reserved query key', () => { + const elements = getFormElements({ query: ['a'] }); + expect(elements).toEqual([]); + }); + + it('maps a boolean option to a checkbox with a boolean query', () => { + const [group] = getFormElements({ _hide: { label: 'Hide artwork', value: true } }); + expect(group.type).toBe('group'); + const [checkbox] = group.context.elements!; + expect(checkbox.type).toBe('checkbox'); + expect(checkbox.context.checked).toBe(true); + expect(checkbox.getQuery!(false)).toEqual({ _hide: false }); + }); + + it('forces a checkbox for a single key-value option and maps checked to the key', () => { + const [group] = getFormElements({ + card: { label: 'ignored', value: '', values: { small: 'Make it a small card' } } + }); + const [checkbox] = group.context.elements!; + expect(checkbox.type).toBe('checkbox'); + expect(checkbox.context.label).toBe('Make it a small card'); + expect(checkbox.context.checked).toBe(false); // value '' does not match the single key + expect(checkbox.getQuery!(true)).toEqual({ card: 'small' }); + expect(checkbox.getQuery!(false)).toEqual({}); + + const [checkedGroup] = getFormElements({ + card: { value: 'small', values: { small: 'Make it a small card' } } + }); + expect(checkedGroup.context.elements![0].context.checked).toBe(true); + }); + + it('maps a string option to a text input and a number option to a number input', () => { + const elements = getFormElements({ + start: { label: 'Start from', value: '11', placeholder: 'ex.: 11' }, + maxheight: { label: 'Adjust height', value: 200 } + }); + const text = elements.find(el => el.context.key === 'start')!; + const number = elements.find(el => el.context.key === 'maxheight')!; + expect(text.type).toBe('text'); + expect(text.context.inputType).toBe('text'); + expect(text.context.placeholder).toBe('ex.: 11'); + expect(number.context.inputType).toBe('number'); + expect(number.getQuery!('')).toEqual({}); + expect(number.getQuery!(300)).toEqual({ maxheight: 300 }); + }); + + it('maps a ranged numeric option to a range slider ordered last', () => { + const elements = getFormElements({ + height: { label: 'Height', value: 200, range: { min: 100, max: 600 } }, + name: { label: 'Name', value: 'x' } + }); + expect(elements[elements.length - 1].type).toBe('range'); + expect(elements[elements.length - 1].context).toMatchObject({ min: 100, max: 600, value: 200 }); + }); + + it('maps up to 3 values to radios and more than 3 to a select', () => { + const [radio] = getFormElements({ + theme: { label: 'Theme color', value: 'dark', values: { light: 'Light', dark: 'Dark', auto: 'Auto' } } + }); + expect(radio.type).toBe('radio'); + expect(radio.context.inline).toBe(true); // all labels are short + expect(radio.context.items).toHaveLength(3); + expect(radio.context.items![1]).toMatchObject({ id: 'theme-1', value: 'dark', checked: true }); + + const [select] = getFormElements({ + style: { label: 'Style', value: 'mini', values: { mini: 'Mini', classic: 'Classic', picture: 'Picture', big: 'Big' } } + }); + expect(select.type).toBe('select'); + expect(select.context.items).toHaveLength(4); + }); + + it('disables inline radios and label for long or missing labels', () => { + const [radio] = getFormElements({ + layout: { value: 'a', values: { a: 'A very long label indeed', b: 'B' } } + }); + expect(radio.type).toBe('radio'); + expect(radio.context.inline).toBe(false); + expect(radio.context.label).toBe(false); + }); + + it('groups checkboxes and starts a new group at the _-prefix boundary', () => { + const elements = getFormElements({ + _a: { label: 'A', value: true }, + _b: { label: 'B', value: false }, + c: { label: 'C', value: true } + }); + const groups = elements.filter(el => el.type === 'group'); + expect(groups).toHaveLength(2); + expect(groups[0].context.elements!.map(el => el.context.key)).toEqual(['_a', '_b']); + expect(groups[1].context.elements!.map(el => el.context.key)).toEqual(['c']); + expect(flatten(elements)).toHaveLength(3); + }); + + it('applies the translator, falling back to the original label', () => { + const translator = (label: string) => (label === 'Light' ? 'Hell' : ''); + const [radio] = getFormElements({ + theme: { label: 'Theme color', value: 'light', values: { light: 'Light', dark: 'Dark' } } + }, translator); + expect(radio.context.items![0].label).toBe('Hell'); + expect(radio.context.items![1].label).toBe('Dark'); // empty translation falls back + }); +}); diff --git a/tests/unit/messaging.test.ts b/tests/unit/messaging.test.ts new file mode 100644 index 0000000..0f7ae2e --- /dev/null +++ b/tests/unit/messaging.test.ts @@ -0,0 +1,135 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import iframely from '../../src/iframely'; +import { boot as bootConst } from '../../src/const'; +import { boot as bootEvents } from '../../src/events'; +import { boot as bootUtils } from '../../src/utils'; +import { boot as bootMessaging } from '../../src/messaging'; +import * as messaging from '../../src/messaging'; + +beforeAll(() => { + bootConst(); + bootEvents(); + bootUtils(); + bootMessaging(); +}); + +beforeEach(() => { + iframely.config = {}; + document.body.innerHTML = ''; +}); + +function buildWidgetIframe(src = 'https://cdn.iframe.ly/api/iframe?url=https%3A%2F%2Fx.com'): HTMLIFrameElement { + document.body.innerHTML = + '
' + + '' + + '
'; + return document.querySelector('iframe')!; +} + +describe('postMessage', () => { + + it('stringifies the message, adds the page context and trims the target origin', () => { + const iframe = buildWidgetIframe(); + const target = iframe.contentWindow!; + const spy = vi.spyOn(target, 'postMessage'); + + messaging.postMessage({ method: 'getSize' }, 'https://cdn.iframe.ly/some/deep/path?x=1', target); + + expect(spy).toHaveBeenCalledTimes(1); + const [data, origin] = spy.mock.calls[0]; + expect(JSON.parse(data as string)).toEqual({ method: 'getSize', context: document.location.href }); + expect(origin).toBe('https://cdn.iframe.ly'); + }); + + it('defaults the target origin to *', () => { + const iframe = buildWidgetIframe(); + const target = iframe.contentWindow!; + const spy = vi.spyOn(target, 'postMessage'); + + messaging.postMessage({ method: 'getSize' }, undefined, target); + expect(spy.mock.calls[0][1]).toBe('*'); + }); +}); + +describe('findIframe', () => { + + it('finds an iframe by contentWindow among domain-matched iframes', () => { + const iframe = buildWidgetIframe(); + const found = iframely.findIframe({ + contentWindow: iframe.contentWindow, + domains: iframely.DOMAINS + }); + expect(found).toBe(iframe); + }); + + it('finds an iframe by src match', () => { + const iframe = buildWidgetIframe(); + const found = iframely.findIframe({ + contentWindow: iframe.contentWindow, + src: 'https://cdn.iframe.ly/api/iframe', + domains: false + }); + expect(found).toBe(iframe); + }); + + it('returns undefined for an unknown contentWindow', () => { + buildWidgetIframe(); + expect(iframely.findIframe({ contentWindow: window, domains: iframely.DOMAINS })).toBeUndefined(); + }); + + it('finds iframes inside shadow roots', () => { + document.body.innerHTML = '
'; + const host = document.querySelector('.iframely-shadow')!; + const shadowRoot = host.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ''; + const iframe = shadowRoot.querySelector('iframe')!; + + const found = iframely.findIframe({ + contentWindow: iframe.contentWindow, + domains: iframely.DOMAINS + }); + expect(found).toBe(iframe); + }); +}); + +describe('message listener', () => { + + function dispatchMessage(data: unknown, source: MessageEventSource | null): void { + window.dispatchEvent(new MessageEvent('message', { data, source })); + } + + it('resolves the widget and triggers the iframely message event for JSON messages', () => { + const iframe = buildWidgetIframe(); + const seen: any[] = []; + iframely.on('message', (widget: any, message: any) => seen.push({ widget, message })); + + dispatchMessage(JSON.stringify({ method: 'test-method', domains: 'all' }), iframe.contentWindow); + + expect(seen).toHaveLength(1); + expect(seen[0].message.method).toBe('test-method'); + expect(seen[0].widget.iframe).toBe(iframe); + expect(seen[0].widget.url).toBe('https://x.com'); + }); + + it('supports the pym height fallback format', () => { + const iframe = buildWidgetIframe(); + const seen: any[] = []; + iframely.on('message', (widget: any, message: any) => seen.push(message)); + + dispatchMessage('heightxPYMx120', iframe.contentWindow); + + expect(seen).toHaveLength(1); + expect(seen[0]).toEqual({ method: 'resize', height: 121, domains: 'all' }); + }); + + it('ignores unrelated messages', () => { + buildWidgetIframe(); + const cb = vi.fn(); + iframely.on('message', cb); + + dispatchMessage('unparseable garbage', null); + dispatchMessage(JSON.stringify({ noMethod: true }), null); + + expect(cb).not.toHaveBeenCalled(); + }); +}); diff --git a/tests/unit/renderer.test.ts b/tests/unit/renderer.test.ts new file mode 100644 index 0000000..03addb9 --- /dev/null +++ b/tests/unit/renderer.test.ts @@ -0,0 +1,99 @@ +import { describe, expect, it } from 'vitest'; +import render from '../../src/options/renderer'; + +describe('renderer', () => { + + it('renders a checkbox with id/name/label and the checked attribute', () => { + const html = render('checkbox', { key: '_hide', label: 'Hide artwork', checked: true }); + expect(html).toContain('type="checkbox"'); + expect(html).toContain('id="_hide"'); + expect(html).toContain('name="_hide"'); + expect(html).toContain('checked="checked"'); + expect(html).toContain('Hide artwork'); + + const unchecked = render('checkbox', { key: '_hide', label: 'Hide artwork', checked: false }); + expect(unchecked).not.toContain('checked'); + }); + + it('HTML-escapes scalar interpolations', () => { + const html = render('checkbox', { key: 'k', label: '"quoted" & \'raw\'' }); + expect(html).not.toContain(''); + expect(html).toContain('<b>"quoted" & 'raw'</b>'); + }); + + it('renders nullish values as empty strings', () => { + const html = render('text', { key: 'k', label: 'L' }); + expect(html).toContain('placeholder=""'); + expect(html).toContain('value=""'); + expect(html).not.toContain('undefined'); + }); + + it('injects group elementsHtml raw', () => { + const child = render('checkbox', { key: 'c', label: 'C' }); + const html = render('group', { elementsHtml: child }); + expect(html).toContain('iframely-option__group'); + expect(html).toContain('type="checkbox"'); // not escaped + expect(html).not.toContain('<input'); + }); + + it('renders radio items with per-item ids, values and checked state', () => { + const html = render('radio', { + key: 'theme', + label: 'Theme color', + inline: true, + items: [ + { id: 'theme-0', value: 'light', label: 'Light', checked: true }, + { id: 'theme-1', value: 'dark', label: 'Dark', checked: false } + ] + }); + expect(html).toContain('iframely-option__group-inline'); + expect(html).toContain('Theme color:'); + expect(html).toContain('id="theme-0"'); + expect(html).toContain('value="light" checked="checked"'); + expect(html).toContain('value="dark"'); + expect(html).not.toContain('value="dark" checked'); + expect((html.match(/name="theme"/g) || []).length).toBe(2); + }); + + it('omits the radio group label when label is false', () => { + const html = render('radio', { + key: 'k', + label: false, + items: [{ id: 'k-0', value: 'a', label: 'A', checked: false }] + }); + expect(html).not.toContain('iframely-option__label'); + expect(html).not.toContain('iframely-option__group-inline'); + }); + + it('renders select options with the selected attribute', () => { + const html = render('select', { + key: 'style', + label: 'Widget style', + items: [ + { value: 'mini', label: 'Mini', checked: false }, + { value: 'classic', label: 'Classic', checked: true } + ] + }); + expect(html).toContain('Classic'); + expect(html).toContain(''); + }); + + it('renders a range input with min/max/step and CSS custom properties', () => { + const html = render('range', { key: 'h', label: 'Height', min: 100, max: 600, value: 200 }); + expect(html).toContain('type="range"'); + expect(html).toContain('min="100"'); + expect(html).toContain('max="600"'); + expect(html).toContain('step="1"'); + expect(html).toContain('value="200"'); + expect(html).toContain('style="--min: 100; --max: 600; --val: 200;"'); + }); + + it('renders a text input with the requested inputType and placeholder', () => { + const html = render('text', { key: 'start', label: 'Start from', inputType: 'number', placeholder: 'ex.: 11', value: 5 }); + expect(html).toContain('type="number"'); + expect(html).toContain('placeholder="ex.: 11"'); + expect(html).toContain('value="5"'); + }); +}); diff --git a/tests/unit/theme.test.ts b/tests/unit/theme.test.ts new file mode 100644 index 0000000..1b568cb --- /dev/null +++ b/tests/unit/theme.test.ts @@ -0,0 +1,61 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import iframely from '../../src/iframely'; +import { boot as bootConst } from '../../src/const'; +import { boot as bootEvents } from '../../src/events'; +import { boot as bootUtils } from '../../src/utils'; +import { boot as bootTheme } from '../../src/theme'; + +beforeAll(() => { + bootConst(); + bootEvents(); + bootUtils(); + bootTheme(); +}); + +beforeEach(() => { + iframely.config = {}; + document.body.innerHTML = ''; +}); + +describe('setTheme', () => { + + it('stores a supported theme, notifies iframes and triggers set-theme', () => { + document.body.innerHTML = ''; + const iframe = document.querySelector('iframe')!; + const spy = vi.spyOn(iframe.contentWindow!, 'postMessage'); + const setThemeCb = vi.fn(); + iframely.on('set-theme', setThemeCb); + + iframely.setTheme('dark'); + + expect(iframely.config.theme).toBe('dark'); + expect(setThemeCb).toHaveBeenCalledWith('dark'); + expect(JSON.parse(spy.mock.calls[0][0] as string)).toMatchObject({ method: 'setTheme', data: 'dark' }); + }); + + it('scopes to a container element when provided, without touching config', () => { + document.body.innerHTML = + '
' + + ''; + const inside = document.querySelector('#scope iframe')!; + const outside = document.querySelector('#outside')!; + const insideSpy = vi.spyOn(inside.contentWindow!, 'postMessage'); + const outsideSpy = vi.spyOn(outside.contentWindow!, 'postMessage'); + + iframely.setTheme('light', document.getElementById('scope')!); + + expect(insideSpy).toHaveBeenCalled(); + expect(outsideSpy).not.toHaveBeenCalled(); + expect(iframely.config.theme).toBeUndefined(); + }); + + it('warns and does nothing for an unsupported theme', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + + iframely.setTheme('neon'); + + expect(warn).toHaveBeenCalled(); + expect(iframely.config.theme).toBeUndefined(); + warn.mockRestore(); + }); +}); diff --git a/tests/unit/translator.test.ts b/tests/unit/translator.test.ts new file mode 100644 index 0000000..fef2898 --- /dev/null +++ b/tests/unit/translator.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from 'vitest'; +import iframely from '../../src/iframely'; +import * as translator from '../../src/options/translator'; + +describe('translator', () => { + + it('assigns iframely.optionsTranslator at import time', () => { + expect(typeof iframely.optionsTranslator).toBe('function'); + }); + + it('translates registered labels', () => { + translator.registerLabels('de', { 'Light': 'Hell', 'Dark': 'Dunkel' }); + const t = iframely.optionsTranslator!('de')!; + expect(t('Light')).toBe('Hell'); + expect(t('Dark')).toBe('Dunkel'); + }); + + it('falls back to the original label for unknown or empty translations', () => { + translator.registerLabels('de', { 'Auto': '' }); + const t = iframely.optionsTranslator!('de')!; + expect(t('Auto')).toBe('Auto'); + expect(t('Unknown label')).toBe('Unknown label'); + }); + + it('returns identity for an unregistered language', () => { + const t = iframely.optionsTranslator!('xx')!; + expect(t('Light')).toBe('Light'); + }); + + it('merges labels registered in multiple calls', () => { + translator.registerLabels('fr', { 'Light': 'Lumière' }); + translator.registerLabels('fr', { 'Dark': 'Sombre' }); + const t = iframely.optionsTranslator!('fr')!; + expect(t('Light')).toBe('Lumière'); + expect(t('Dark')).toBe('Sombre'); + }); +}); diff --git a/tests/unit/utils.test.ts b/tests/unit/utils.test.ts new file mode 100644 index 0000000..bd33643 --- /dev/null +++ b/tests/unit/utils.test.ts @@ -0,0 +1,186 @@ +import { beforeAll, beforeEach, describe, expect, it } from 'vitest'; +import iframely from '../../src/iframely'; +import { boot as bootConst } from '../../src/const'; +import { boot as bootEvents } from '../../src/events'; +import { boot as bootUtils } from '../../src/utils'; +import * as utils from '../../src/utils'; + +beforeAll(() => { + bootConst(); + bootEvents(); + bootUtils(); +}); + +beforeEach(() => { + iframely.config = {}; + document.body.innerHTML = ''; +}); + +describe('addQueryString', () => { + + it('appends params with ? for a bare href and & for an existing query', () => { + expect(utils.addQueryString('//host/path', { a: 'b' })).toBe('//host/path?a=b'); + expect(utils.addQueryString('//host/path?x=1', { a: 'b' })).toBe('//host/path?x=1&a=b'); + }); + + it('url-encodes values', () => { + expect(utils.addQueryString('//host/p', { url: 'https://a.com/?x=1&y=2' })) + .toBe('//host/p?url=' + encodeURIComponent('https://a.com/?x=1&y=2')); + }); + + it('converts booleans to 1/0 except for _-prefixed keys', () => { + expect(utils.addQueryString('//host/p', { lazy: true, autoplay: false })).toBe('//host/p?lazy=1&autoplay=0'); + expect(utils.addQueryString('//host/p', { _opt: true })).toBe('//host/p?_opt=true'); + }); + + it('expands arrays into repeated params', () => { + expect(utils.addQueryString('//host/p', { uri: ['a', 'b'] })).toBe('//host/p?uri=a&uri=b'); + }); + + it('skips undefined values and keys already present in the href', () => { + expect(utils.addQueryString('//host/p?a=1', { a: '2', b: undefined, c: '3' })).toBe('//host/p?a=1&c=3'); + }); +}); + +describe('parseQueryString', () => { + + it('parses all params without an allowlist', () => { + expect(utils.parseQueryString('//host/p?a=1&b=x%20y')).toEqual({ a: '1', b: 'x y' }); + }); + + it('returns an empty object without a query string', () => { + expect(utils.parseQueryString('//host/p')).toEqual({}); + }); + + it('filters by allowlist of strings and regexps', () => { + const parsed = utils.parseQueryString('//h/p?api_key=k&_opt=1&evil=x', ['api_key', /^_.+/]); + expect(parsed).toEqual({ api_key: 'k', _opt: '1' }); + }); +}); + +describe('getEndpoint', () => { + + it('prefixes relative paths with the CDN and protocol slashes', () => { + expect(utils.getEndpoint('/api/iframe', { url: 'https://x.com' })) + .toBe('//cdn.iframe.ly/api/iframe?url=' + encodeURIComponent('https://x.com')); + }); + + it('prefers an explicit CDN option and removes it from the query', () => { + const endpoint = utils.getEndpoint('/api/iframe', { CDN: '//other.cdn', url: 'u' }); + expect(endpoint).toBe('//other.cdn/api/iframe?url=u'); + }); + + it('keeps absolute urls untouched apart from the query string', () => { + expect(utils.getEndpoint('https://cdn.iframe.ly/abc', { v: 1 })).toBe('https://cdn.iframe.ly/abc?v=1'); + }); + + it('adds matching iframely.config values for config_params, including regex matches', () => { + iframely.extendOptions({ api_key: 'KEY', _theme_opt: 'x', unrelated: 'nope' }); + const endpoint = utils.getEndpoint('/api/iframe', { url: 'u' }, iframely.SUPPORTED_QUERY_STRING); + expect(endpoint).toContain('api_key=KEY'); + expect(endpoint).toContain('_theme_opt=x'); + expect(endpoint).not.toContain('unrelated'); + }); +}); + +describe('extendOptions', () => { + + it('normalizes falsy/truthy string and number values to booleans', () => { + iframely.extendOptions({ a: '0', b: 'false', c: 0, d: false, e: '1', f: 'true', g: 1, h: true, i: 'text' }); + expect(iframely.config).toEqual({ + a: false, b: false, c: false, d: false, + e: true, f: true, g: true, h: true, + i: 'text' + }); + }); + + it('does not override values previously disabled with false', () => { + iframely.extendOptions({ lazy: false }); + iframely.extendOptions({ lazy: true }); + expect(iframely.config.lazy).toBe(false); + }); + + it('ignores undefined options', () => { + expect(() => iframely.extendOptions(undefined)).not.toThrow(); + }); +}); + +describe('widget wrappers', () => { + + function buildWidgetDom(inner = '') { + document.body.innerHTML = + '
' + inner + '
'; + return document.querySelector('.iframely-responsive')!.firstElementChild!; + } + + it('getIframeWrapper finds both wrappers for a well-formed widget', () => { + const iframe = buildWidgetDom(); + const wrapper = utils.getIframeWrapper(iframe, true)!; + expect(wrapper.aspectWrapper.className).toBe('iframely-responsive'); + expect(wrapper.maxWidthWrapper.className).toBe('iframely-embed'); + }); + + it('getIframeWrapper returns undefined without the wrapper structure', () => { + document.body.innerHTML = '
'; + expect(utils.getIframeWrapper(document.querySelector('iframe')!, true)).toBeUndefined(); + }); + + it('getWidget extracts the url from an iframe src url= param', () => { + const iframe = buildWidgetDom(); + const widget = utils.getWidget(iframe)!; + expect(widget.iframe).toBe(iframe); + expect(widget.url).toBe('https://x.com'); + }); + + it('getWidget extracts the url from an anchor href', () => { + const a = buildWidgetDom(''); + const widget = utils.getWidget(a)!; + expect(widget.url).toBe('https://y.com/page'); + }); + + it('addDefaultWrappers inserts the two-wrapper structure before the element', () => { + document.body.innerHTML = '

x

'; + const a = document.getElementById('link')!; + const wrapper = utils.addDefaultWrappers(a); + expect(wrapper.maxWidthWrapper.className).toBe('iframely-embed'); + expect(wrapper.aspectWrapper.parentNode).toBe(wrapper.maxWidthWrapper); + expect(wrapper.maxWidthWrapper.nextSibling).toBe(a); + }); +}); + +describe('setStyles', () => { + + it('converts numeric values to px', () => { + const el = document.createElement('div'); + utils.setStyles(el, { height: 400, width: '250' }); + expect(el.style.height).toBe('400px'); + expect(el.style.width).toBe('250px'); + }); + + it('keeps non-numeric string values as-is and skips max-width "keep"', () => { + const el = document.createElement('div'); + el.style.maxWidth = '100px'; + utils.setStyles(el, { position: 'absolute', 'max-width': 'keep' }); + expect(el.style.position).toBe('absolute'); + expect(el.style.maxWidth).toBe('100px'); + }); + + it('tolerates a missing element', () => { + expect(() => utils.setStyles(null, { height: 1 })).not.toThrow(); + }); +}); + +describe('createScript / applyNonce', () => { + + it('creates a script and applies the configured nonce', () => { + iframely.config.nonce = 'abc123'; + const script = utils.createScript(); + expect(script.tagName).toBe('SCRIPT'); + expect(script.nonce).toBe('abc123'); + }); + + it('leaves nonce empty when not configured', () => { + const script = utils.createScript(); + expect(script.nonce).toBeFalsy(); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 8b4fa83..f12cf29 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,5 +16,5 @@ "skipLibCheck": true, "noEmit": true }, - "include": ["src"] + "include": ["src", "tests", "vitest.config.ts", "playwright.config.ts"] } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..2dc54bd --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + environment: 'jsdom', + include: ['tests/unit/**/*.test.ts'] + } +}); From 273366d6d8efe8437256fabfe373bcf4ff9d33bb Mon Sep 17 00:00:00 2001 From: Alexander Matveyenko Date: Fri, 10 Jul 2026 21:29:34 +0200 Subject: [PATCH 3/7] Support a real Iframely API key for demo pages via .env - Demo pages use an {{IFRAMELY_API_KEY}} placeholder in script srcs; scripts/serve.mjs substitutes it at request time from the environment or a git-ignored .env at the repo root, falling back to the inert TEST placeholder. The key is only injected into locally served responses and never written to committed files. - Add .env.example; git-ignore .env. - Pin the Playwright web server to IFRAMELY_API_KEY=TEST and disable reuseExistingServer so tests never assert against a dev server that is running with a real key. - Document the workflow in the README. Co-Authored-By: Claude Fable 5 --- .env.example | 4 ++++ .gitignore | 1 + README.md | 4 +++- demo/cancel-recover.html | 2 +- demo/index.html | 2 +- demo/new.html | 2 +- playwright.config.ts | 5 ++++- scripts/serve.mjs | 29 +++++++++++++++++++++++++++-- 8 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..6897dcc --- /dev/null +++ b/.env.example @@ -0,0 +1,4 @@ +# Copy to .env (git-ignored) to use a real Iframely API key with the demo +# pages served by `pnpm serve`. scripts/serve.mjs substitutes it into the +# demo HTML at request time; without it the pages use the TEST placeholder. +IFRAMELY_API_KEY= diff --git a/.gitignore b/.gitignore index aa55ba1..80c5ca2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ package-lock.json .npmrc test-results/ playwright-report/ +.env diff --git a/README.md b/README.md index ec62a0d..a4e4169 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,9 @@ The classic script bundles keep their historical names and stay plain IIFE scrip ### Tests -Unit tests run with [Vitest](https://vitest.dev) (jsdom) over the modules in `src/`; browser tests run with [Playwright](https://playwright.dev) against the built bundles served from `dist/`, using the pages in `demo/` as fixtures (the Iframely API endpoint is stubbed via request interception, so no network access or API key is needed). The same pages double as a manual playground: `pnpm serve` and open [http://localhost:8917](http://localhost:8917). +Unit tests run with [Vitest](https://vitest.dev) (jsdom) over the modules in `src/`; browser tests run with [Playwright](https://playwright.dev) against the built bundles served from `dist/`, using the pages in `demo/` as fixtures (the Iframely API endpoint is stubbed via request interception, so no network access or API key is needed). + +The same pages double as a manual playground: `pnpm serve` and open [http://localhost:8917](http://localhost:8917). To exercise the real Iframely API there, copy `.env.example` to `.env` (git-ignored) and set `IFRAMELY_API_KEY` — the dev server substitutes it into the demo pages at request time, so the key never appears in committed files. Note: stop the dev server before `pnpm test:e2e`; the tests start their own instance pinned to the `TEST` placeholder. ```bash pnpm test # unit tests (Vitest) diff --git a/demo/cancel-recover.html b/demo/cancel-recover.html index ae1909d..69127c0 100644 --- a/demo/cancel-recover.html +++ b/demo/cancel-recover.html @@ -2,7 +2,7 @@ cancel-recover test - + diff --git a/demo/index.html b/demo/index.html index a025ce8..1e8e3f2 100644 --- a/demo/index.html +++ b/demo/index.html @@ -3,7 +3,7 @@ embed.js demo

embed.js smoke test

- +
diff --git a/demo/new.html b/demo/new.html index 0111f07..4b97a90 100644 --- a/demo/new.html +++ b/demo/new.html @@ -2,6 +2,6 @@ new embed.js surface - + diff --git a/playwright.config.ts b/playwright.config.ts index d3d050e..ed1e819 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -21,6 +21,9 @@ export default defineConfig({ webServer: { command: 'node scripts/serve.mjs', url: BASE_URL + '/demo/index.html', - reuseExistingServer: true + // Tests assert against the TEST placeholder key, so never reuse a + // dev server that may be running with a real key from .env. + reuseExistingServer: false, + env: { IFRAMELY_API_KEY: 'TEST' } } }); diff --git a/scripts/serve.mjs b/scripts/serve.mjs index 45208fa..693d5fb 100644 --- a/scripts/serve.mjs +++ b/scripts/serve.mjs @@ -1,5 +1,10 @@ // Tiny static server for the demo pages and Playwright e2e tests. // Serves the repo root so /dist and /demo resolve as they do in production. +// +// Demo pages use {{IFRAMELY_API_KEY}} placeholders in their script srcs; +// the server substitutes them from the environment or a git-ignored .env +// file at the repo root, falling back to 'TEST'. The key is injected only +// into locally served HTML and never written to disk. import { createServer } from 'node:http'; import { readFile } from 'node:fs/promises'; import { join, extname, normalize, dirname } from 'node:path'; @@ -8,6 +13,23 @@ import { fileURLToPath } from 'node:url'; const root = normalize(join(dirname(fileURLToPath(import.meta.url)), '..')); const port = Number(process.env.PORT) || 8917; +async function loadDotEnv() { + try { + const raw = await readFile(join(root, '.env'), 'utf8'); + for (const line of raw.split(/\r?\n/)) { + const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/); + if (m && !(m[1] in process.env)) { // real environment wins over .env + process.env[m[1]] = m[2].replace(/^(["'])(.*)\1$/, '$2'); + } + } + } catch { + // no .env — fall back to defaults + } +} + +await loadDotEnv(); +const apiKey = process.env.IFRAMELY_API_KEY || 'TEST'; + const mime = { '.html': 'text/html; charset=utf-8', '.js': 'text/javascript; charset=utf-8', @@ -28,10 +50,13 @@ createServer(async (req, res) => { if (urlPath === '/') { filePath = join(root, 'demo/index.html'); } - const data = await readFile(filePath); + let data = await readFile(filePath); + if (extname(filePath) === '.html') { + data = data.toString().replaceAll('{{IFRAMELY_API_KEY}}', apiKey); + } res.writeHead(200, { 'content-type': mime[extname(filePath)] || 'application/octet-stream' }); res.end(data); } catch { res.writeHead(404).end('not found'); } -}).listen(port, () => console.warn(`serving ${root} on http://localhost:${port}`)); +}).listen(port, () => console.warn(`serving ${root} on http://localhost:${port} (api_key: ${apiKey === 'TEST' ? 'TEST placeholder' : 'from environment'})`)); From a8cc108067f445fd7ec566daefa2b4a2450257b5 Mon Sep 17 00:00:00 2001 From: Alexander Matveyenko Date: Sat, 11 Jul 2026 10:18:35 +0200 Subject: [PATCH 4/7] Migrate toolchain to TypeScript 7, oxlint and oxfmt - TypeScript 5.9 -> 7.0 (native compiler) for typecheck and declaration emit; tsgo requires an explicit rootDir in tsconfig.build.json for the dist/types layout. The typescript-eslint dependency was what pinned TS to 5.x. - Replace ESLint (+ @eslint/js, globals, typescript-eslint) with oxlint: correctness category as errors plus the carried-over no-console/no-empty rules, configured in oxlint.config.ts. - Add oxfmt for formatting, configured in oxfmt.config.ts: tabs (width 4), single quotes, no trailing commas; dist/, demo/ and markdown excluded. One-time reformat of the codebase to tabs. - Scripts: lint -> oxlint, new format/format:check; prebuild now runs typecheck + lint + format:check. - Pin Node 24.18 via .node-version: the *.config.ts files rely on Node native type stripping, which the previous default Node 22.16 lacks. No engines field so npm consumers are unaffected. - Rewrite the events test this-binding assertion via vi.fn mock contexts (oxlint no-this-alias). Co-Authored-By: Claude Fable 5 --- .node-version | 1 + README.md | 2 +- dist/embed-options.js | 8 +- dist/embed.js | 8 +- dist/esm/chunks/deprecated.js | 8 +- dist/esm/i18n.de.js | 36 +- dist/esm/i18n.fr.js | 36 +- dist/options.i18n.de.js | 36 +- dist/options.i18n.fr.js | 36 +- dist/types/types.d.ts | 2 +- eslint.config.js | 64 -- oxfmt.config.ts | 10 + oxlint.config.ts | 22 + package.json | 134 +-- playwright.config.ts | 40 +- pnpm-lock.yaml | 1347 +++++++++++------------- scripts/build.js | 94 +- scripts/serve.mjs | 81 +- src/ahref.ts | 222 ++-- src/const.ts | 82 +- src/deprecated.ts | 55 +- src/dom-ready.ts | 19 +- src/events.ts | 59 +- src/iframely.ts | 2 +- src/import.ts | 697 ++++++------ src/index-options.ts | 37 +- src/index.ts | 39 +- src/intersection.ts | 113 +- src/lazy-iframe.ts | 115 +- src/lazy-img-placeholder.ts | 475 +++++---- src/messaging.ts | 233 ++-- src/options/form-builder.ts | 319 +++--- src/options/form-generator.ts | 466 ++++---- src/options/index.ts | 19 +- src/options/lang/labels.LAN.example.ts | 204 ++-- src/options/lang/labels.de.ts | 206 ++-- src/options/lang/labels.fr.ts | 185 ++-- src/options/renderer.ts | 37 +- src/options/translator.ts | 12 +- src/theme.ts | 66 +- src/types.ts | 227 ++-- src/utils.ts | 671 ++++++------ src/widget-cancel.ts | 98 +- src/widget-click.ts | 43 +- src/widget-options.ts | 11 +- src/widget-resize.ts | 245 ++--- tests/e2e/double-load.spec.ts | 16 +- tests/e2e/embed.spec.ts | 111 +- tests/e2e/esm.spec.ts | 16 +- tests/e2e/options.spec.ts | 56 +- tests/e2e/surface.spec.ts | 94 +- tests/unit/events.test.ts | 94 +- tests/unit/form-builder.test.ts | 194 ++-- tests/unit/form-generator.test.ts | 214 ++-- tests/unit/messaging.test.ts | 235 +++-- tests/unit/renderer.test.ts | 179 ++-- tests/unit/theme.test.ts | 94 +- tests/unit/translator.test.ts | 53 +- tests/unit/utils.test.ts | 331 +++--- tsconfig.build.json | 21 +- tsconfig.json | 39 +- vitest.config.ts | 8 +- 62 files changed, 4411 insertions(+), 4266 deletions(-) create mode 100644 .node-version delete mode 100644 eslint.config.js create mode 100644 oxfmt.config.ts create mode 100644 oxlint.config.ts diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..ca5c350 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +24.18.0 diff --git a/README.md b/README.md index a4e4169..79c3c5f 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ To add more languages with form label translations, see [labels.LAN.example.ts]( ### Build embed.js -The build uses [Vite](https://vite.dev) and TypeScript; sources are ES modules in `src/`. Requires Node 20.19+ (or 22.12+) and [pnpm](https://pnpm.io). +The build uses [Vite](https://vite.dev) and TypeScript 7 (the native compiler); linting is [oxlint](https://oxc.rs/docs/guide/usage/linter) and formatting is [oxfmt](https://oxc.rs/docs/guide/usage/formatter) (`pnpm lint` / `pnpm format`), both configured via `oxlint.config.ts` / `oxfmt.config.ts`. Sources are ES modules in `src/`. Requires Node 24 (pinned in `.node-version`; the TypeScript config files rely on Node's native type stripping) and [pnpm](https://pnpm.io). Install required modules first: diff --git a/dist/embed-options.js b/dist/embed-options.js index 99cd7b0..9bf60ee 100644 --- a/dist/embed-options.js +++ b/dist/embed-options.js @@ -920,16 +920,16 @@ //#endregion //#region src/widget-resize.ts var resetWrapperBorderStyles = { - "border": "", + border: "", "border-radius": "", "box-shadow": "", - "overflow": "" + overflow: "" }; var resetIframeBorderStyles = { - "border": "0", + border: "0", "border-radius": "", "box-shadow": "", - "overflow": "" + overflow: "" }; function boot$4() { iframely.on("message", (widget, message) => { diff --git a/dist/embed.js b/dist/embed.js index f80ce39..1dde1e1 100644 --- a/dist/embed.js +++ b/dist/embed.js @@ -920,16 +920,16 @@ //#endregion //#region src/widget-resize.ts var resetWrapperBorderStyles = { - "border": "", + border: "", "border-radius": "", "box-shadow": "", - "overflow": "" + overflow: "" }; var resetIframeBorderStyles = { - "border": "0", + border: "0", "border-radius": "", "box-shadow": "", - "overflow": "" + overflow: "" }; function boot$3() { iframely.on("message", (widget, message) => { diff --git a/dist/esm/chunks/deprecated.js b/dist/esm/chunks/deprecated.js index aa2f874..b74491e 100644 --- a/dist/esm/chunks/deprecated.js +++ b/dist/esm/chunks/deprecated.js @@ -901,16 +901,16 @@ function boot$4() { //#endregion //#region src/widget-resize.ts var resetWrapperBorderStyles = { - "border": "", + border: "", "border-radius": "", "box-shadow": "", - "overflow": "" + overflow: "" }; var resetIframeBorderStyles = { - "border": "0", + border: "0", "border-radius": "", "box-shadow": "", - "overflow": "" + overflow: "" }; function boot$3() { iframely.on("message", (widget, message) => { diff --git a/dist/esm/i18n.de.js b/dist/esm/i18n.de.js index e4aafb8..8e58bf6 100644 --- a/dist/esm/i18n.de.js +++ b/dist/esm/i18n.de.js @@ -5,10 +5,10 @@ registerLabels("de", { "Include playlist": "Wiedergabeliste anzeigen", "Hide artwork": "Artwork ausblenden", "Theme color": "Theme Farbe", - "Light": "Hell", - "Dark": "Dunkel", - "Auto": "Automatisch", - "Default": "Standard", + Light: "Hell", + Dark: "Dunkel", + Auto: "Automatisch", + Default: "Standard", "Adjust height": "Höhe einstellen", "Active page": "Aktive Seite", "Use click-to-load": "Verwende click-to-load", @@ -27,14 +27,14 @@ registerLabels("de", { "Adjust width": "Breite anpassen", "Hide description": "Beschreibung verbergen", "Widget style": "Widget-Style", - "Mini": "Mini", - "Classic": "Klassisch", - "Picture": "Bild", - "Zoom": "Zoom", + Mini: "Mini", + Classic: "Klassisch", + Picture: "Bild", + Zoom: "Zoom", "Map orientation": "Karten-Ausrichtung", - "Album": "Album", - "Portrait": "Portrait", - "Square": "Quadratisch", + Album: "Album", + Portrait: "Portrait", + Square: "Quadratisch", "Show context slideshow": "Als Slideshow anzeigen", "Show description footer": "Fußzeile anzeigen", "Show user header": "Kopfbereich anzeigen", @@ -44,14 +44,14 @@ registerLabels("de", { "Show recent posts": "Neueste Beiträge anzeigen", "Show profile photos when friends like this": "Profilfotos anzeigen, wenn Freunde dies mögen", "Use the small header instead": "Kleine Kopfzeile stattdessen verwenden", - "Artwork": "Artwork", - "Small": "klein", - "Big": "groß", - "None": "Keines", - "Layout": "Layout", - "Slim": "Schlank", + Artwork: "Artwork", + Small: "klein", + Big: "groß", + None: "Keines", + Layout: "Layout", + Slim: "Schlank", "Artwork-only": "Nur Artwork", - "Standard": "Standard", + Standard: "Standard", "Size & style": "Größe & Stil", "Wide image": "Breite Darstellung", "Wide simple": "Breite Darstellung (Einfach)", diff --git a/dist/esm/i18n.fr.js b/dist/esm/i18n.fr.js index 6cc1d74..8778df6 100644 --- a/dist/esm/i18n.fr.js +++ b/dist/esm/i18n.fr.js @@ -5,10 +5,10 @@ registerLabels("fr", { "Include playlist": "Inclure la playlist", "Hide artwork": "Masquer la illustration", "Theme color": "Couleur du thème", - "Light": "Lumière", - "Dark": "Sombre", - "Auto": "", - "Default": "Défaut", + Light: "Lumière", + Dark: "Sombre", + Auto: "", + Default: "Défaut", "Adjust height": "Height", "Active page": "Page active", "Use click-to-load": "Utilisez click-to-load", @@ -24,14 +24,14 @@ registerLabels("fr", { "Hide previous Tweet in conversation thread": "Masquer le tweet parent", "Hide description": "Masquer la description", "Widget style": "Style de widget", - "Mini": "", - "Classic": "Classique", - "Picture": "Image", - "Zoom": "", + Mini: "", + Classic: "Classique", + Picture: "Image", + Zoom: "", "Map orientation": "Orientation de la carte", - "Album": "", - "Portrait": "", - "Square": "Carré", + Album: "", + Portrait: "", + Square: "Carré", "Show context slideshow": "Afficher le diaporama contextuel", "Show description footer": "Afficher la description pied de page", "Show user header": "Afficher l'en-tête de l'utilisateur", @@ -41,14 +41,14 @@ registerLabels("fr", { "Show recent posts": "Afficher les messages récents", "Show profile photos when friends like this": "", "Use the small header instead": "Utilisez plutôt le petit en-tête", - "Artwork": "Ouvrages d'art", - "Small": "Petite", - "Big": "Grosse", - "None": "Aucune", - "Layout": "Disposition", - "Slim": "Svelte", + Artwork: "Ouvrages d'art", + Small: "Petite", + Big: "Grosse", + None: "Aucune", + Layout: "Disposition", + Slim: "Svelte", "Artwork-only": "Oeuvre seule", - "Standard": "Standard", + Standard: "Standard", "Size & style": "Style", "Wide image": "Image large", "Wide simple": "Large simple", diff --git a/dist/options.i18n.de.js b/dist/options.i18n.de.js index c2b5457..53d700e 100644 --- a/dist/options.i18n.de.js +++ b/dist/options.i18n.de.js @@ -25,10 +25,10 @@ "Include playlist": "Wiedergabeliste anzeigen", "Hide artwork": "Artwork ausblenden", "Theme color": "Theme Farbe", - "Light": "Hell", - "Dark": "Dunkel", - "Auto": "Automatisch", - "Default": "Standard", + Light: "Hell", + Dark: "Dunkel", + Auto: "Automatisch", + Default: "Standard", "Adjust height": "Höhe einstellen", "Active page": "Aktive Seite", "Use click-to-load": "Verwende click-to-load", @@ -47,14 +47,14 @@ "Adjust width": "Breite anpassen", "Hide description": "Beschreibung verbergen", "Widget style": "Widget-Style", - "Mini": "Mini", - "Classic": "Klassisch", - "Picture": "Bild", - "Zoom": "Zoom", + Mini: "Mini", + Classic: "Klassisch", + Picture: "Bild", + Zoom: "Zoom", "Map orientation": "Karten-Ausrichtung", - "Album": "Album", - "Portrait": "Portrait", - "Square": "Quadratisch", + Album: "Album", + Portrait: "Portrait", + Square: "Quadratisch", "Show context slideshow": "Als Slideshow anzeigen", "Show description footer": "Fußzeile anzeigen", "Show user header": "Kopfbereich anzeigen", @@ -64,14 +64,14 @@ "Show recent posts": "Neueste Beiträge anzeigen", "Show profile photos when friends like this": "Profilfotos anzeigen, wenn Freunde dies mögen", "Use the small header instead": "Kleine Kopfzeile stattdessen verwenden", - "Artwork": "Artwork", - "Small": "klein", - "Big": "groß", - "None": "Keines", - "Layout": "Layout", - "Slim": "Schlank", + Artwork: "Artwork", + Small: "klein", + Big: "groß", + None: "Keines", + Layout: "Layout", + Slim: "Schlank", "Artwork-only": "Nur Artwork", - "Standard": "Standard", + Standard: "Standard", "Size & style": "Größe & Stil", "Wide image": "Breite Darstellung", "Wide simple": "Breite Darstellung (Einfach)", diff --git a/dist/options.i18n.fr.js b/dist/options.i18n.fr.js index b03a164..b62d1c8 100644 --- a/dist/options.i18n.fr.js +++ b/dist/options.i18n.fr.js @@ -25,10 +25,10 @@ "Include playlist": "Inclure la playlist", "Hide artwork": "Masquer la illustration", "Theme color": "Couleur du thème", - "Light": "Lumière", - "Dark": "Sombre", - "Auto": "", - "Default": "Défaut", + Light: "Lumière", + Dark: "Sombre", + Auto: "", + Default: "Défaut", "Adjust height": "Height", "Active page": "Page active", "Use click-to-load": "Utilisez click-to-load", @@ -44,14 +44,14 @@ "Hide previous Tweet in conversation thread": "Masquer le tweet parent", "Hide description": "Masquer la description", "Widget style": "Style de widget", - "Mini": "", - "Classic": "Classique", - "Picture": "Image", - "Zoom": "", + Mini: "", + Classic: "Classique", + Picture: "Image", + Zoom: "", "Map orientation": "Orientation de la carte", - "Album": "", - "Portrait": "", - "Square": "Carré", + Album: "", + Portrait: "", + Square: "Carré", "Show context slideshow": "Afficher le diaporama contextuel", "Show description footer": "Afficher la description pied de page", "Show user header": "Afficher l'en-tête de l'utilisateur", @@ -61,14 +61,14 @@ "Show recent posts": "Afficher les messages récents", "Show profile photos when friends like this": "", "Use the small header instead": "Utilisez plutôt le petit en-tête", - "Artwork": "Ouvrages d'art", - "Small": "Petite", - "Big": "Grosse", - "None": "Aucune", - "Layout": "Disposition", - "Slim": "Svelte", + Artwork: "Ouvrages d'art", + Small: "Petite", + Big: "Grosse", + None: "Aucune", + Layout: "Disposition", + Slim: "Svelte", "Artwork-only": "Oeuvre seule", - "Standard": "Standard", + Standard: "Standard", "Size & style": "Style", "Wide image": "Image large", "Wide simple": "Large simple", diff --git a/dist/types/types.d.ts b/dist/types/types.d.ts index 2605366..81292ca 100644 --- a/dist/types/types.d.ts +++ b/dist/types/types.d.ts @@ -84,7 +84,7 @@ export interface Iframely { extendOptions(options: Record | undefined): void; getElementComputedStyle(el: Element, style: string): string | undefined; findIframe(options: FindIframeOptions): HTMLIFrameElement | undefined; - setTheme(theme?: string): void; + setTheme(theme?: string, container?: Element): void; addEventListener(elem: EventTarget, type: string, handler: (e: any) => void): void; isTouch(): boolean; buildOptionsForm?(id: string, formContainer: HTMLElement, options: WidgetOptions, translator?: TranslatorFn | null): void; diff --git a/eslint.config.js b/eslint.config.js deleted file mode 100644 index 89a4285..0000000 --- a/eslint.config.js +++ /dev/null @@ -1,64 +0,0 @@ -import js from '@eslint/js'; -import tseslint from 'typescript-eslint'; -import globals from 'globals'; - -export default tseslint.config( - { ignores: ['dist/**', 'demo/**', 'test-results/**', 'playwright-report/**'] }, - js.configs.recommended, - ...tseslint.configs.recommended, - { - files: ['src/**/*.ts', 'scripts/**/*.{js,mjs}', 'tests/**/*.ts', '*.config.ts'], - languageOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - globals: { - ...globals.browser - } - }, - rules: { - 'indent': [ - 'error', - 4, - { - 'ignoreComments': true - } - ], - 'linebreak-style': [ - 'error', - 'unix' - ], - 'quotes': [ - 'error', - 'single', - { - 'avoidEscape': true - } - ], - 'semi': [ - 'error', - 'always' - ], - 'no-console': [ - 'warn', - { - 'allow': ['warn', 'error'] - } - ], - 'no-empty': [ - 'error', - { - 'allowEmptyCatch': true - } - ], - '@typescript-eslint/no-explicit-any': 'off' - } - }, - { - files: ['scripts/**/*.{js,mjs}'], - languageOptions: { - globals: { - ...globals.node - } - } - } -); diff --git a/oxfmt.config.ts b/oxfmt.config.ts new file mode 100644 index 0000000..ea7dff0 --- /dev/null +++ b/oxfmt.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'oxfmt'; + +export default defineConfig({ + useTabs: true, + tabWidth: 4, + singleQuote: true, + trailingComma: 'none', + sortPackageJson: false, + ignorePatterns: ['dist/**', 'demo/**', '**/*.md'] +}); diff --git a/oxlint.config.ts b/oxlint.config.ts new file mode 100644 index 0000000..876b97e --- /dev/null +++ b/oxlint.config.ts @@ -0,0 +1,22 @@ +import { defineConfig } from 'oxlint'; + +export default defineConfig({ + env: { + browser: true + }, + categories: { + correctness: 'error' + }, + rules: { + 'no-console': ['warn', { allow: ['warn', 'error'] }], + 'no-empty': ['error', { allowEmptyCatch: true }], + 'typescript/no-explicit-any': 'off' + }, + ignorePatterns: ['dist', 'demo', 'test-results', 'playwright-report'], + overrides: [ + { + files: ['scripts/**'], + env: { node: true, browser: false } + } + ] +}); diff --git a/package.json b/package.json index 0b05cf9..94e9987 100644 --- a/package.json +++ b/package.json @@ -1,69 +1,69 @@ { - "name": "@iframely/embed.js", - "version": "2.0.0", - "description": "Iframely embeds cloud JavaScript library, helps with rich media embed codes rendering for Iframely hosted iFrames. Library functions include unfurling URLs, lazy-loading, and rich-media events handling.", - "keywords": [ - "iframely", - "embed", - "embedjs", - "embed.js", - "iframe", - "oembed" - ], - "homepage": "http://iframely.com", - "repository": { - "type": "git", - "url": "https://github.com/itteco/embedjs.git" - }, - "bugs": { - "url": "https://github.com/itteco/embedjs/issues" - }, - "type": "module", - "main": "./dist/esm/main.js", - "types": "./dist/types/main.d.ts", - "exports": { - ".": { - "types": "./dist/types/main.d.ts", - "import": "./dist/esm/main.js" - }, - "./options": { - "types": "./dist/types/main-options.d.ts", - "import": "./dist/esm/main-options.js" - }, - "./i18n/de": { - "types": "./dist/types/options/lang/labels.de.d.ts", - "import": "./dist/esm/i18n.de.js" - }, - "./i18n/fr": { - "types": "./dist/types/options/lang/labels.fr.d.ts", - "import": "./dist/esm/i18n.fr.js" - } - }, - "files": [ - "dist", - "src" - ], - "scripts": { - "dev": "vite", - "serve": "node scripts/serve.mjs", - "typecheck": "tsc -p tsconfig.json", - "lint": "eslint .", - "test": "vitest run", - "test:watch": "vitest", - "test:e2e": "node scripts/build.js && playwright test", - "prebuild": "pnpm typecheck && pnpm lint", - "build": "node scripts/build.js && tsc -p tsconfig.build.json" - }, - "devDependencies": { - "@eslint/js": "^10.0.1", - "@playwright/test": "^1.61.1", - "eslint": "^10.0.0", - "globals": "^17.7.0", - "jsdom": "^29.1.1", - "typescript": "~5.9.3", - "typescript-eslint": "^8.63.0", - "vite": "^8.1.4", - "vitest": "^4.1.10" - }, - "license": "MIT" + "name": "@iframely/embed.js", + "version": "2.0.0", + "description": "Iframely embeds cloud JavaScript library, helps with rich media embed codes rendering for Iframely hosted iFrames. Library functions include unfurling URLs, lazy-loading, and rich-media events handling.", + "keywords": [ + "iframely", + "embed", + "embedjs", + "embed.js", + "iframe", + "oembed" + ], + "homepage": "http://iframely.com", + "repository": { + "type": "git", + "url": "https://github.com/itteco/embedjs.git" + }, + "bugs": { + "url": "https://github.com/itteco/embedjs/issues" + }, + "type": "module", + "main": "./dist/esm/main.js", + "types": "./dist/types/main.d.ts", + "exports": { + ".": { + "types": "./dist/types/main.d.ts", + "import": "./dist/esm/main.js" + }, + "./options": { + "types": "./dist/types/main-options.d.ts", + "import": "./dist/esm/main-options.js" + }, + "./i18n/de": { + "types": "./dist/types/options/lang/labels.de.d.ts", + "import": "./dist/esm/i18n.de.js" + }, + "./i18n/fr": { + "types": "./dist/types/options/lang/labels.fr.d.ts", + "import": "./dist/esm/i18n.fr.js" + } + }, + "files": [ + "dist", + "src" + ], + "scripts": { + "dev": "vite", + "serve": "node scripts/serve.mjs", + "typecheck": "tsc -p tsconfig.json", + "lint": "oxlint", + "format": "oxfmt", + "format:check": "oxfmt --check", + "test": "vitest run", + "test:watch": "vitest", + "test:e2e": "node scripts/build.js && playwright test", + "prebuild": "pnpm typecheck && pnpm lint && pnpm format:check", + "build": "node scripts/build.js && tsc -p tsconfig.build.json" + }, + "devDependencies": { + "@playwright/test": "^1.61.1", + "jsdom": "^29.1.1", + "oxfmt": "^0.58.0", + "oxlint": "^1.73.0", + "typescript": "~7.0.2", + "vite": "^8.1.4", + "vitest": "^4.1.10" + }, + "license": "MIT" } diff --git a/playwright.config.ts b/playwright.config.ts index ed1e819..c5f5602 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -6,24 +6,24 @@ import { defineConfig, devices } from '@playwright/test'; const BASE_URL = 'http://localhost:8917'; export default defineConfig({ - testDir: 'tests/e2e', - fullyParallel: true, - reporter: [['list']], - use: { - baseURL: BASE_URL - }, - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] } - } - ], - webServer: { - command: 'node scripts/serve.mjs', - url: BASE_URL + '/demo/index.html', - // Tests assert against the TEST placeholder key, so never reuse a - // dev server that may be running with a real key from .env. - reuseExistingServer: false, - env: { IFRAMELY_API_KEY: 'TEST' } - } + testDir: 'tests/e2e', + fullyParallel: true, + reporter: [['list']], + use: { + baseURL: BASE_URL + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] } + } + ], + webServer: { + command: 'node scripts/serve.mjs', + url: BASE_URL + '/demo/index.html', + // Tests assert against the TEST placeholder key, so never reuse a + // dev server that may be running with a real key from .env. + reuseExistingServer: false, + env: { IFRAMELY_API_KEY: 'TEST' } + } }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2fe9891..65875b1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,27 +8,21 @@ importers: .: devDependencies: - '@eslint/js': - specifier: ^10.0.1 - version: 10.0.1(eslint@10.0.3) '@playwright/test': specifier: ^1.61.1 version: 1.61.1 - eslint: - specifier: ^10.0.0 - version: 10.0.3 - globals: - specifier: ^17.7.0 - version: 17.7.0 jsdom: specifier: ^29.1.1 version: 29.1.1 + oxfmt: + specifier: ^0.58.0 + version: 0.58.0 + oxlint: + specifier: ^1.73.0 + version: 1.73.0 typescript: - specifier: ~5.9.3 - version: 5.9.3 - typescript-eslint: - specifier: ^8.63.0 - version: 8.63.0(eslint@10.0.3)(typescript@5.9.3) + specifier: ~7.0.2 + version: 7.0.2 vite: specifier: ^8.1.4 version: 8.1.4(@types/node@25.5.0)(terser@5.46.0) @@ -102,45 +96,6 @@ packages: '@emnapi/wasi-threads@1.2.2': resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.23.3': - resolution: {integrity: sha512-j+eEWmB6YYLwcNOdlwQ6L2OsptI/LO6lNBuLIqe5R7RetD658HLoF+Mn7LzYmAWWNNzdC6cqP+L6r8ujeYXWLw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/config-helpers@0.5.3': - resolution: {integrity: sha512-lzGN0onllOZCGroKJmRwY6QcEHxbjBw1gwB8SgRSqK8YbbtEXMvKynsXc3553ckIEBxsbMBU7oOZXKIPGZNeZw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/core@1.1.1': - resolution: {integrity: sha512-QUPblTtE51/7/Zhfv8BDwO0qkkzQL7P/aWWbqcf4xWLEYn1oKjdO0gglQBB4GAsu7u6wjijbCmzsUTy6mnk6oQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/js@10.0.1': - resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - peerDependencies: - eslint: ^10.0.0 - peerDependenciesMeta: - eslint: - optional: true - - '@eslint/object-schema@3.0.3': - resolution: {integrity: sha512-iM869Pugn9Nsxbh/YHRqYiqd23AmIbxJOcpUMOuWCVNdoQJ5ZtwL6h3t0bcZzJUlC3Dq9jCFCESBZnX0GTv7iQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - '@eslint/plugin-kit@0.6.1': - resolution: {integrity: sha512-iH1B076HoAshH1mLpHMgwdGeTs0CYwL0SPMkGuSebZrwBp16v415e9NZXg2jtrqPVQjf6IANe2Vtlr5KswtcZQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@exodus/bytes@1.15.1': resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -150,22 +105,6 @@ packages: '@noble/hashes': optional: true - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -191,6 +130,250 @@ packages: '@oxc-project/types@0.139.0': resolution: {integrity: sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==} + '@oxfmt/binding-android-arm-eabi@0.58.0': + resolution: {integrity: sha512-Uz62sHduGGPftXtILGyxdSW4PX82rUg+rfdNqhsgxe881g4rIoXlIqmZQ6HVKcF4f+F8qMhdD03Bx5u7gmeTdg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxfmt/binding-android-arm64@0.58.0': + resolution: {integrity: sha512-rD0lRaJp1b+9vw6X4A2dJWKukd6X8yxiicN4JxXcXayolmUypRZxk+lKR+fVOu5q/iYc0fh5fR4bgmfOfVlbaA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxfmt/binding-darwin-arm64@0.58.0': + resolution: {integrity: sha512-uzbPPk7O6M+w2K65vcQ1woga3wgP8zghjL1KOG5b6qJ8dvYHZJ1VShaslg2KOK6yQIwCQtcMCXqLBM6sqXUNTg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxfmt/binding-darwin-x64@0.58.0': + resolution: {integrity: sha512-L0nKYDxU32oxeQqJj21W9SlIMnf81VZEhyah6iDvFhf5q0oynq498Fopth7blErUJVBpVtxQ98RMCfMPqpJX6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxfmt/binding-freebsd-x64@0.58.0': + resolution: {integrity: sha512-woNwfD58dC5PGS9LSLSD5JYfo/EFK5iG9vhDWkcCg3q78ag7KC8bpDqgvPHrMoXpx83OLXxoSOhu6z8FsVTHlg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxfmt/binding-linux-arm-gnueabihf@0.58.0': + resolution: {integrity: sha512-Sqs8nMLxuQpY21NKJ1u4stPDmO5hskBCNNh2E3AdCfI1QqWtf4m+Qn4mGEIUO4KGmuq3SWc/SZ80uy5IiwTCDw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm-musleabihf@0.58.0': + resolution: {integrity: sha512-Vd4exzBI5B5hB9m22JiTQzIL23WvHo/Pe+sNXPNeBLXSP9swCBPKCEBRwKpmpQzYhlgYaCgfPcGXPKAJBRIiZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxfmt/binding-linux-arm64-gnu@0.58.0': + resolution: {integrity: sha512-bUWi5mHV+4Vi56RLHE1h6q/HHfwAIT3XoB9vJAVeRzfu5NriXM8y6eeJu0vlKa0C9kq2rq1sOWRClhdLHPocrg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-arm64-musl@0.58.0': + resolution: {integrity: sha512-2ZHxemzgHcjtktAuVUwSoyXmGo/t+aF5tS1ciPpPei4rhSyrz3JOqDosXXrmhN/yLUSzJjtuW7ToTWqfQpCj2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-ppc64-gnu@0.58.0': + resolution: {integrity: sha512-AwKkVwjVmFQ3bcO7j0McGYAqCKH2a326fswfofng/E8VewCT/raeeGQr4huVhY704deK8AWASSTlxzMj0eZc6Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-gnu@0.58.0': + resolution: {integrity: sha512-xsRpTxfUnJF8D3AUKko/qyWdjw4GZVHlCVFuGlzSCTeewLmykKINW8em1+wx+axsDVtJJcMtvsiaXggXxrlHgw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-riscv64-musl@0.58.0': + resolution: {integrity: sha512-Z4AYOTcy7nYEIiXwD62PlerimyYRcfJOgUbQAEBjXz098kxKuERBlRntofGy69HHhe9E0TLVNMl1yspVNu+efw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-linux-s390x-gnu@0.58.0': + resolution: {integrity: sha512-A3nhhtZPC/TKVWOPj9q/H3p2znJDCcHWYlJBhWL8hGq/bFmBaNBHC8Np6E581yVq1w9Mi3rMDNzDalWvtUfJtQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-gnu@0.58.0': + resolution: {integrity: sha512-2g+tVkgwqphw8R4hgo+kF4oz8+P5RwVOtr9+irsC7uwEp0e9j7Crw8kDGKL20uYlLPD7g02DqA61mC/UNYx98A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxfmt/binding-linux-x64-musl@0.58.0': + resolution: {integrity: sha512-rc15P6AbyyB7426aN8AakLd02Trb3a6ML/mmfAQeVHJEfVofWLcWIrBdy6zDEY+DIaL/s8E4GGPboVw+oP3+EA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxfmt/binding-openharmony-arm64@0.58.0': + resolution: {integrity: sha512-ZWoTM27/HYPOh9iq86DAbhPu9nXb8qKvvGU/h8OfliyVUFAMMNTLDkGsWDKKnDqIkqvZ9+dXlgUOsH1LYO3O7g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxfmt/binding-win32-arm64-msvc@0.58.0': + resolution: {integrity: sha512-LHZnqFXe2dEfkRI4XdZS/57nEOT/I4UCRX5IyM9v4GYW9XwQCjGe1IUK59SuKw3POwvcgWQ4pme2cYXmNqTNPg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxfmt/binding-win32-ia32-msvc@0.58.0': + resolution: {integrity: sha512-mZKpg20TpheCJym1rarcZCUJeW1sSruw8zAAaCYWvuVfwIUDN1CXdrPU/JgCWReXTCTrEfCB8Wyo3hh9jSZ2EA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxfmt/binding-win32-x64-msvc@0.58.0': + resolution: {integrity: sha512-N/wUU4N5PZ2orBtI+Ko7MnMfYLfE7K91UrGMY/c/pYyHR3lA9kwst1XugkZx+92YcRh/Eo+iv2eTESSWXfiZPA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxlint/binding-android-arm-eabi@1.73.0': + resolution: {integrity: sha512-HZQRN/UMBu+Ut+/9MiAChkbP4qZqrNOWBcNI45vOT40GVhbGR0JgHB87L48D4iAqFQIdVmeQYtV9RF89AjTKkg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxlint/binding-android-arm64@1.73.0': + resolution: {integrity: sha512-Gp+KJRylv2aW7thRpG5p1KTxZq4ZJFbWowrKzufNq9d3ssl3r3JviYV45/+p+7CN1Nv0zDd1e8Ex0b/HUDq4TQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxlint/binding-darwin-arm64@1.73.0': + resolution: {integrity: sha512-3de96NdtXhxERMjIz7wsp2HYMY6pMQycGxFWac2mFecAx6VeARF/IqFb1QIaqiCRIdfzBwzTed+pCTCoiS+CYA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxlint/binding-darwin-x64@1.73.0': + resolution: {integrity: sha512-5zx/uPW32TiaOeVY1dQ/H5iOf0K1HOdFKOJhLqGl4o63+i1fpzoqqu/mKtd7OFgFjNCdhlyTGgjVkQTZm1ELcg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxlint/binding-freebsd-x64@1.73.0': + resolution: {integrity: sha512-qNe4gKHaGnLuZJ8toUg90JAa0S2vTVvDw+0bRi3q1avXZXDT4u5mMeECf3nD4HYrbdn1O7dXqWut4onY/yx/Xg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxlint/binding-linux-arm-gnueabihf@1.73.0': + resolution: {integrity: sha512-cCehYh5hTbfShm/fxTD6wwrGUWIpvX+N5OxmAMhFhDeTGXvw+BeNj889tpxsFQ9ZLatQ6wImuY8tsKLZ+FMz7w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm-musleabihf@1.73.0': + resolution: {integrity: sha512-d5j5GDU/2dMgjVhw7TQT9ITrsIr1Y02KEXKyVGIXUkD+KiaxE9TP65FS2ZdgTBemQvoRL+gSBdbrIm3cQIeacg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxlint/binding-linux-arm64-gnu@1.73.0': + resolution: {integrity: sha512-Eyf1SrP3+yR1DI3OJgOY2Pvrr9dWP9TK37xPaDYycwTtlGlI45erJAVIfH5/m/xosDt6BupJYEFi47bvbTuuyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-arm64-musl@1.73.0': + resolution: {integrity: sha512-IlT/OJApEDKaMmCooHuncgJZbbCe7T5QIWmTZBEtYscWvzPQuuEinVcid6kwQRVQOUdb7PUCz4jQHnaYXdfJXw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-ppc64-gnu@1.73.0': + resolution: {integrity: sha512-L+JYcb/vdg5fmcH08V6o0YYLU28cTH1SPNulwJdvK9NK49aXSkYy6oNpKBmddArVOXYqNepriDGiZ04G54kh1Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-gnu@1.73.0': + resolution: {integrity: sha512-Qtk0g3bKV6OwWjIm7R8kQN1uOZRKQt/MODK2a8QfkwhTpXBD53ozx5XLVWLGDQAVyp2otLW4D2wB98XfAfMPGA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-riscv64-musl@1.73.0': + resolution: {integrity: sha512-wX0NQKZVxltkAOVmzFcpOaMpdaUvsq1Eqpx9tkAfl71UdkTlSo1R4AdAnGccR1Fm2+TzFgZ22CyyGuZ41RDr/A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@oxlint/binding-linux-s390x-gnu@1.73.0': + resolution: {integrity: sha512-vPe7UGBMWyiLTtnqS4xxgMQFSFGmtQwhwCxuiw6lXygaO6bVt0D8dFVg8Xv05eaiN3ybC0HXXHUAohFMFvqoCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-gnu@1.73.0': + resolution: {integrity: sha512-2CwIWr9cemFC/CbRBWZvuk5mffz6ObmfFkfcC/9rTQ7f+icNhYr2kOjf9Rt8lLvugvkdGDOmkoVoFFHh6ClCTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@oxlint/binding-linux-x64-musl@1.73.0': + resolution: {integrity: sha512-nDadfJgg7NBBxG0N560wOe7LLX5QiYp6qBaI7viuk5EUORFBktU/NfV0MbTqU3gTqQDCh4VyxKdo5VADxk9w8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@oxlint/binding-openharmony-arm64@1.73.0': + resolution: {integrity: sha512-wGjJC+NLH9xP+IKGn9RDW94ojJR/wPbg5WCnQjj/oReaOtCQthr8ws1zICe77JFmo4ouUdeTHHZL/ESGiF6Pmw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxlint/binding-win32-arm64-msvc@1.73.0': + resolution: {integrity: sha512-I7X47GPGljw225YUQ5SbC/rb1Kkdrd0yQf0x+hYxeKS6DpfjMbo9ccQPQ6LNY6BoJQ1sHhgDUGuMn5Vg5gHT6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxlint/binding-win32-ia32-msvc@1.73.0': + resolution: {integrity: sha512-5lWj+3h+74Fm1jYOO9qkJA4xkAlZA099DkXppuXsk7UpnpZLttsefrZU469vChGaG6hcSqrkKXQOvMTZtbjeNg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxlint/binding-win32-x64-msvc@1.73.0': + resolution: {integrity: sha512-WaNRvh4f6zY9CvUQk2YoA1O90ieWrIklI84+HXFr9Isjz9CSESrdqo/RtIYt4Dll/cAchqGDMehfaZd0vqEFZw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@playwright/test@1.61.1': resolution: {integrity: sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==} engines: {node: '>=18'} @@ -306,76 +489,131 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/esrecurse@4.3.1': - resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@25.5.0': resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} - '@typescript-eslint/eslint-plugin@8.63.0': - resolution: {integrity: sha512-rvwSgqT+DHpWdzfSzPatRLm02a0GlESt++9iy3hLCDY4BgkaLcl8LBi9Yh7XGFBpwcBE/K3024QuXWTpbz4FfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.63.0 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] - '@typescript-eslint/parser@8.63.0': - resolution: {integrity: sha512-gwh4gvvlaVDKKxyfxMG+Gnu1u9X0OQBwyGLkbwB65dIzBKnxeRiJlNFqlI3zwVhNXJIs6qV7mlFCn/BIajlVig==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] - '@typescript-eslint/project-service@8.63.0': - resolution: {integrity: sha512-e5dh0/UI0ok53AlZ5wRkXCB32z/f2jUZqPR/ygAw5WYaSw8j9EoJWlS7wQjr/dmOaqWjnPIn2m+HhVPCMWGZVQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] - '@typescript-eslint/scope-manager@8.63.0': - resolution: {integrity: sha512-uUyfMWCnDSN8bCpcrY8nGP2BLkQ9Xn0GsipcONcpIDWhwhO4ZSyHvyS14U3X75mzxWxL3I2UZIrenTzdzcJO8A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] - '@typescript-eslint/tsconfig-utils@8.63.0': - resolution: {integrity: sha512-sUAbkulqBAsncKnbRP3+7CtQFRKicexnj7ZwNC6ddCR7EmrXvjvdCYMJbUIqMd6lwoEriZjwLo08aS5tSjVMHg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] - '@typescript-eslint/type-utils@8.63.0': - resolution: {integrity: sha512-Nzzh/OGxVCOjObjaj1CQF2RUasyYy2Jfuh+zZ3PjLzG2fYRriAiZLib9UKtO+CpQAS3YHiAS+ckZDclwqI1TPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] - '@typescript-eslint/types@8.63.0': - resolution: {integrity: sha512-xyLtl9DUBBFrcJS4x2pIqGLH68/tC2uOa4Z7pUteW09D3bXnnXUom4dyPikzWgB7llmIc1zoeI3aoUdC4rPK/Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] - '@typescript-eslint/typescript-estree@8.63.0': - resolution: {integrity: sha512-ygBkU+B7ex5UI/gKhaqexWev79uISfIv7XQCRNYO/jmD8rGLPyWLAb3KMRT6nd8Gt9bmUBi9+iX6tBdYfOY81Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.1.0' + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] - '@typescript-eslint/utils@8.63.0': - resolution: {integrity: sha512-fUKaeAvrTuQg/Tgt3nliAUSZHJM6DlCcfyEmxCvlX8kieWSStBX+5O5Fnidtc3i2JrH+9c/GL4RY2iasd/GPTA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] - '@typescript-eslint/visitor-keys@8.63.0': - resolution: {integrity: sha512-UexrHGnGTpbuQHct2ExOc2ZcFbGUS9FOesCxxqdBGcpI1BxYu/LZ6U8Aq6/72XtF/qRBk9nhuGHFJIXXMhPMdw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] '@vitest/expect@4.1.10': resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} @@ -406,34 +644,18 @@ packages: '@vitest/utils@4.1.10': resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} - engines: {node: 18 || 20 || >=22} - buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -447,10 +669,6 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - css-tree@3.2.1: resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} @@ -459,21 +677,9 @@ packages: resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -485,68 +691,13 @@ packages: es-module-lexer@2.3.0: resolution: {integrity: sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==} - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-scope@9.1.2: - resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@10.0.3: - resolution: {integrity: sha512-COV33RzXZkqhG9P2rZCFl9ZmJ7WL+gQSCRzE7RhkbclbQPtLAWReL7ysA0Sh4c8Im2U9ynybdR56PV0XcKvqaQ==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - espree@11.2.0: - resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - expect-type@1.4.0: resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -556,21 +707,6 @@ packages: picomatch: optional: true - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.1: - resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} - fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -581,44 +717,13 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - globals@17.7.0: - resolution: {integrity: sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==} - engines: {node: '>=18'} - html-encoding-sniffer@6.0.0: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - jsdom@29.1.1: resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} @@ -628,22 +733,6 @@ packages: canvas: optional: true - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} @@ -718,10 +807,6 @@ packages: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - lru-cache@11.5.2: resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} @@ -732,48 +817,44 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} - engines: {node: 18 || 20 || >=22} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.15: resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - obug@2.1.3: resolution: {integrity: sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==} engines: {node: '>=12.20.0'} - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + oxfmt@0.58.0: + resolution: {integrity: sha512-8feG/7NVEHDVwc1OUpP6Pks+TnaDFUw2jLLFIMi5bcmmwxAX2wBQvjSzj62RRTYBf2Op1Wt8xbkmagmPTR5ETg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + svelte: ^5.0.0 + vite-plus: '*' + peerDependenciesMeta: + svelte: + optional: true + vite-plus: + optional: true - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + oxlint@1.73.0: + resolution: {integrity: sha512-u91G9TJzU6yqKWNZUYprQB07W7YvntZXaRxQ6CkoytepYhLWUXWsr1M8zUJ34VatNPuUAr3Z8GH+O2A331CluQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + oxlint-tsgolint: '>=0.24.0' + vite-plus: '*' + peerDependenciesMeta: + oxlint-tsgolint: + optional: true + vite-plus: + optional: true parse5@8.0.1: resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -798,10 +879,6 @@ packages: resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} engines: {node: ^10 || ^12 || >=14} - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -815,22 +892,9 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - - semver@7.8.5: - resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} - engines: {node: '>=10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -871,6 +935,10 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} + tinypool@2.1.0: + resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==} + engines: {node: ^20.0.0 || >=22.0.0} + tinyrainbow@3.1.0: resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} @@ -890,29 +958,12 @@ packages: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - typescript-eslint@8.63.0: - resolution: {integrity: sha512-xgwXyzG4sK9ALkBxbyGkTMMOS+imnW65iPhxCQMK83KhxyoDNW7l+IDqEf9vMdoUidHpOoS967RCq4eMiTexwQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.1.0' - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} hasBin: true undici-types@7.18.2: @@ -922,9 +973,6 @@ packages: resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==} engines: {node: '>=20.18.1'} - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vite@8.1.4: resolution: {integrity: sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1025,20 +1073,11 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} @@ -1046,10 +1085,6 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - snapshots: '@asamuzakjp/css-color@5.1.11': @@ -1116,53 +1151,8 @@ snapshots: tslib: 2.8.1 optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.0.3)': - dependencies: - eslint: 10.0.3 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/config-array@0.23.3': - dependencies: - '@eslint/object-schema': 3.0.3 - debug: 4.4.3 - minimatch: 10.2.4 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.5.3': - dependencies: - '@eslint/core': 1.1.1 - - '@eslint/core@1.1.1': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/js@10.0.1(eslint@10.0.3)': - optionalDependencies: - eslint: 10.0.3 - - '@eslint/object-schema@3.0.3': {} - - '@eslint/plugin-kit@0.6.1': - dependencies: - '@eslint/core': 1.1.1 - levn: 0.4.1 - '@exodus/bytes@1.15.1': {} - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1195,6 +1185,120 @@ snapshots: '@oxc-project/types@0.139.0': {} + '@oxfmt/binding-android-arm-eabi@0.58.0': + optional: true + + '@oxfmt/binding-android-arm64@0.58.0': + optional: true + + '@oxfmt/binding-darwin-arm64@0.58.0': + optional: true + + '@oxfmt/binding-darwin-x64@0.58.0': + optional: true + + '@oxfmt/binding-freebsd-x64@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm-gnueabihf@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm-musleabihf@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-arm64-musl@0.58.0': + optional: true + + '@oxfmt/binding-linux-ppc64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-riscv64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-riscv64-musl@0.58.0': + optional: true + + '@oxfmt/binding-linux-s390x-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-x64-gnu@0.58.0': + optional: true + + '@oxfmt/binding-linux-x64-musl@0.58.0': + optional: true + + '@oxfmt/binding-openharmony-arm64@0.58.0': + optional: true + + '@oxfmt/binding-win32-arm64-msvc@0.58.0': + optional: true + + '@oxfmt/binding-win32-ia32-msvc@0.58.0': + optional: true + + '@oxfmt/binding-win32-x64-msvc@0.58.0': + optional: true + + '@oxlint/binding-android-arm-eabi@1.73.0': + optional: true + + '@oxlint/binding-android-arm64@1.73.0': + optional: true + + '@oxlint/binding-darwin-arm64@1.73.0': + optional: true + + '@oxlint/binding-darwin-x64@1.73.0': + optional: true + + '@oxlint/binding-freebsd-x64@1.73.0': + optional: true + + '@oxlint/binding-linux-arm-gnueabihf@1.73.0': + optional: true + + '@oxlint/binding-linux-arm-musleabihf@1.73.0': + optional: true + + '@oxlint/binding-linux-arm64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-arm64-musl@1.73.0': + optional: true + + '@oxlint/binding-linux-ppc64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-riscv64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-riscv64-musl@1.73.0': + optional: true + + '@oxlint/binding-linux-s390x-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-x64-gnu@1.73.0': + optional: true + + '@oxlint/binding-linux-x64-musl@1.73.0': + optional: true + + '@oxlint/binding-openharmony-arm64@1.73.0': + optional: true + + '@oxlint/binding-win32-arm64-msvc@1.73.0': + optional: true + + '@oxlint/binding-win32-ia32-msvc@1.73.0': + optional: true + + '@oxlint/binding-win32-x64-msvc@1.73.0': + optional: true + '@playwright/test@1.61.1': dependencies: playwright: 1.61.1 @@ -1264,107 +1368,72 @@ snapshots: '@types/deep-eql@4.0.2': {} - '@types/esrecurse@4.3.1': {} - '@types/estree@1.0.8': {} - '@types/json-schema@7.0.15': {} - '@types/node@25.5.0': dependencies: undici-types: 7.18.2 optional: true - '@typescript-eslint/eslint-plugin@8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.63.0(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.63.0 - '@typescript-eslint/type-utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.63.0 - eslint: 10.0.3 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true - '@typescript-eslint/parser@8.63.0(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.63.0 - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.63.0 - debug: 4.4.3 - eslint: 10.0.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true - '@typescript-eslint/project-service@8.63.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) - '@typescript-eslint/types': 8.63.0 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@typescript/typescript-darwin-x64@7.0.2': + optional: true - '@typescript-eslint/scope-manager@8.63.0': - dependencies: - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/visitor-keys': 8.63.0 + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true - '@typescript-eslint/tsconfig-utils@8.63.0(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true - '@typescript-eslint/type-utils@8.63.0(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) - debug: 4.4.3 - eslint: 10.0.3 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@typescript/typescript-linux-arm64@7.0.2': + optional: true - '@typescript-eslint/types@8.63.0': {} + '@typescript/typescript-linux-arm@7.0.2': + optional: true - '@typescript-eslint/typescript-estree@8.63.0(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.63.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.63.0(typescript@5.9.3) - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/visitor-keys': 8.63.0 - debug: 4.4.3 - minimatch: 10.2.4 - semver: 7.8.5 - tinyglobby: 0.2.17 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@typescript/typescript-linux-loong64@7.0.2': + optional: true - '@typescript-eslint/utils@8.63.0(eslint@10.0.3)(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) - '@typescript-eslint/scope-manager': 8.63.0 - '@typescript-eslint/types': 8.63.0 - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - eslint: 10.0.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true - '@typescript-eslint/visitor-keys@8.63.0': - dependencies: - '@typescript-eslint/types': 8.63.0 - eslint-visitor-keys: 5.0.1 + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true '@vitest/expect@4.1.10': dependencies: @@ -1407,31 +1476,15 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - ajv@6.14.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 + acorn@8.16.0: + optional: true assertion-error@2.0.1: {} - balanced-match@4.0.4: {} - bidi-js@1.0.3: dependencies: require-from-string: 2.0.2 - brace-expansion@5.0.4: - dependencies: - balanced-match: 4.0.4 - buffer-from@1.1.2: optional: true @@ -1442,12 +1495,6 @@ snapshots: convert-source-map@2.0.0: {} - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - css-tree@3.2.1: dependencies: mdn-data: 2.27.1 @@ -1460,152 +1507,38 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - debug@4.4.3: - dependencies: - ms: 2.1.3 - decimal.js@10.6.0: {} - deep-is@0.1.4: {} - detect-libc@2.1.2: {} entities@8.0.0: {} es-module-lexer@2.3.0: {} - escape-string-regexp@4.0.0: {} - - eslint-scope@9.1.2: - dependencies: - '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@5.0.1: {} - - eslint@10.0.3: - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.0.3) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.23.3 - '@eslint/config-helpers': 0.5.3 - '@eslint/core': 1.1.1 - '@eslint/plugin-kit': 0.6.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 9.1.2 - eslint-visitor-keys: 5.0.1 - espree: 11.2.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - minimatch: 10.2.4 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - - espree@11.2.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 5.0.1 - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 - esutils@2.0.3: {} - expect-type@1.4.0: {} - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - fdir@6.5.0(picomatch@4.0.5): optionalDependencies: picomatch: 4.0.5 - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.1 - keyv: 4.5.4 - - flatted@3.4.1: {} - fsevents@2.3.2: optional: true fsevents@2.3.3: optional: true - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - globals@17.7.0: {} - html-encoding-sniffer@6.0.0: dependencies: '@exodus/bytes': 1.15.1 transitivePeerDependencies: - '@noble/hashes' - ignore@5.3.2: {} - - ignore@7.0.5: {} - - imurmurhash@0.1.4: {} - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - is-potential-custom-element-name@1.0.1: {} - isexe@2.0.0: {} - jsdom@29.1.1: dependencies: '@asamuzakjp/css-color': 5.1.11 @@ -1632,21 +1565,6 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - lightningcss-android-arm64@1.32.0: optional: true @@ -1696,10 +1614,6 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - lru-cache@11.5.2: {} magic-string@0.30.21: @@ -1708,43 +1622,60 @@ snapshots: mdn-data@2.27.1: {} - minimatch@10.2.4: - dependencies: - brace-expansion: 5.0.4 - - ms@2.1.3: {} - nanoid@3.3.15: {} - natural-compare@1.4.0: {} - obug@2.1.3: {} - optionator@0.9.4: + oxfmt@0.58.0: dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 + tinypool: 2.1.0 + optionalDependencies: + '@oxfmt/binding-android-arm-eabi': 0.58.0 + '@oxfmt/binding-android-arm64': 0.58.0 + '@oxfmt/binding-darwin-arm64': 0.58.0 + '@oxfmt/binding-darwin-x64': 0.58.0 + '@oxfmt/binding-freebsd-x64': 0.58.0 + '@oxfmt/binding-linux-arm-gnueabihf': 0.58.0 + '@oxfmt/binding-linux-arm-musleabihf': 0.58.0 + '@oxfmt/binding-linux-arm64-gnu': 0.58.0 + '@oxfmt/binding-linux-arm64-musl': 0.58.0 + '@oxfmt/binding-linux-ppc64-gnu': 0.58.0 + '@oxfmt/binding-linux-riscv64-gnu': 0.58.0 + '@oxfmt/binding-linux-riscv64-musl': 0.58.0 + '@oxfmt/binding-linux-s390x-gnu': 0.58.0 + '@oxfmt/binding-linux-x64-gnu': 0.58.0 + '@oxfmt/binding-linux-x64-musl': 0.58.0 + '@oxfmt/binding-openharmony-arm64': 0.58.0 + '@oxfmt/binding-win32-arm64-msvc': 0.58.0 + '@oxfmt/binding-win32-ia32-msvc': 0.58.0 + '@oxfmt/binding-win32-x64-msvc': 0.58.0 + + oxlint@1.73.0: + optionalDependencies: + '@oxlint/binding-android-arm-eabi': 1.73.0 + '@oxlint/binding-android-arm64': 1.73.0 + '@oxlint/binding-darwin-arm64': 1.73.0 + '@oxlint/binding-darwin-x64': 1.73.0 + '@oxlint/binding-freebsd-x64': 1.73.0 + '@oxlint/binding-linux-arm-gnueabihf': 1.73.0 + '@oxlint/binding-linux-arm-musleabihf': 1.73.0 + '@oxlint/binding-linux-arm64-gnu': 1.73.0 + '@oxlint/binding-linux-arm64-musl': 1.73.0 + '@oxlint/binding-linux-ppc64-gnu': 1.73.0 + '@oxlint/binding-linux-riscv64-gnu': 1.73.0 + '@oxlint/binding-linux-riscv64-musl': 1.73.0 + '@oxlint/binding-linux-s390x-gnu': 1.73.0 + '@oxlint/binding-linux-x64-gnu': 1.73.0 + '@oxlint/binding-linux-x64-musl': 1.73.0 + '@oxlint/binding-openharmony-arm64': 1.73.0 + '@oxlint/binding-win32-arm64-msvc': 1.73.0 + '@oxlint/binding-win32-ia32-msvc': 1.73.0 + '@oxlint/binding-win32-x64-msvc': 1.73.0 parse5@8.0.1: dependencies: entities: 8.0.0 - path-exists@4.0.0: {} - - path-key@3.1.1: {} - pathe@2.0.3: {} picocolors@1.1.1: {} @@ -1765,8 +1696,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - prelude-ls@1.2.1: {} - punycode@2.3.1: {} require-from-string@2.0.2: {} @@ -1796,14 +1725,6 @@ snapshots: dependencies: xmlchars: 2.2.0 - semver@7.8.5: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - siginfo@2.0.0: {} source-map-js@1.2.1: {} @@ -1840,6 +1761,8 @@ snapshots: fdir: 6.5.0(picomatch@4.0.5) picomatch: 4.0.5 + tinypool@2.1.0: {} + tinyrainbow@3.1.0: {} tldts-core@7.4.7: {} @@ -1856,39 +1779,37 @@ snapshots: dependencies: punycode: 2.3.1 - ts-api-utils@2.5.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - tslib@2.8.1: optional: true - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - typescript-eslint@8.63.0(eslint@10.0.3)(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.63.0(@typescript-eslint/parser@8.63.0(eslint@10.0.3)(typescript@5.9.3))(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/parser': 8.63.0(eslint@10.0.3)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.63.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.63.0(eslint@10.0.3)(typescript@5.9.3) - eslint: 10.0.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 undici-types@7.18.2: optional: true undici@7.28.0: {} - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - vite@8.1.4(@types/node@25.5.0)(terser@5.46.0): dependencies: lightningcss: 1.32.0 @@ -1945,19 +1866,11 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - which@2.0.2: - dependencies: - isexe: 2.0.0 - why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - word-wrap@1.2.5: {} - xml-name-validator@5.0.0: {} xmlchars@2.2.0: {} - - yocto-queue@0.1.0: {} diff --git a/scripts/build.js b/scripts/build.js index 652080b..fe1bfdb 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -6,60 +6,60 @@ import { build } from 'vite'; // "embed.js"/"iframely.js") and parses config from its query string. // IIFE output does not support multiple entries, hence one build per entry. const iifeEntries = [ - ['src/index.ts', 'embed'], - ['src/index-options.ts', 'embed-options'], - ['src/options/entry.ts', 'options'], - ['src/options/lang/labels.de.ts', 'options.i18n.de'], - ['src/options/lang/labels.fr.ts', 'options.i18n.fr'], + ['src/index.ts', 'embed'], + ['src/index-options.ts', 'embed-options'], + ['src/options/entry.ts', 'options'], + ['src/options/lang/labels.de.ts', 'options.i18n.de'], + ['src/options/lang/labels.fr.ts', 'options.i18n.fr'] ]; for (const [entry, name] of iifeEntries) { - await build({ - configFile: false, - logLevel: 'info', - build: { - outDir: 'dist', - emptyOutDir: false, - minify: false, - modulePreload: false, - copyPublicDir: false, - rolldownOptions: { - input: entry, - output: [ - { format: 'iife', entryFileNames: `${name}.js`, minify: false }, - { format: 'iife', entryFileNames: `${name}.min.js`, minify: true }, - ], - }, - }, - }); + await build({ + configFile: false, + logLevel: 'info', + build: { + outDir: 'dist', + emptyOutDir: false, + minify: false, + modulePreload: false, + copyPublicDir: false, + rolldownOptions: { + input: entry, + output: [ + { format: 'iife', entryFileNames: `${name}.js`, minify: false }, + { format: 'iife', entryFileNames: `${name}.min.js`, minify: true } + ] + } + } + }); } // ESM build for npm/bundler consumers. dist is committed, so chunk names // must be stable (no hashes) to avoid diff noise. await rm('dist/esm', { recursive: true, force: true }); await build({ - configFile: false, - logLevel: 'info', - build: { - outDir: 'dist/esm', - emptyOutDir: false, - minify: false, - modulePreload: false, - copyPublicDir: false, - rolldownOptions: { - // Keep the entries' `export` statements (Vite's app build drops them). - preserveEntrySignatures: 'strict', - input: { - 'main': 'src/main.ts', - 'main-options': 'src/main-options.ts', - 'i18n.de': 'src/options/lang/labels.de.ts', - 'i18n.fr': 'src/options/lang/labels.fr.ts', - }, - output: { - format: 'es', - entryFileNames: '[name].js', - chunkFileNames: 'chunks/[name].js', - }, - }, - }, + configFile: false, + logLevel: 'info', + build: { + outDir: 'dist/esm', + emptyOutDir: false, + minify: false, + modulePreload: false, + copyPublicDir: false, + rolldownOptions: { + // Keep the entries' `export` statements (Vite's app build drops them). + preserveEntrySignatures: 'strict', + input: { + main: 'src/main.ts', + 'main-options': 'src/main-options.ts', + 'i18n.de': 'src/options/lang/labels.de.ts', + 'i18n.fr': 'src/options/lang/labels.fr.ts' + }, + output: { + format: 'es', + entryFileNames: '[name].js', + chunkFileNames: 'chunks/[name].js' + } + } + } }); diff --git a/scripts/serve.mjs b/scripts/serve.mjs index 693d5fb..0e59b78 100644 --- a/scripts/serve.mjs +++ b/scripts/serve.mjs @@ -14,49 +14,56 @@ const root = normalize(join(dirname(fileURLToPath(import.meta.url)), '..')); const port = Number(process.env.PORT) || 8917; async function loadDotEnv() { - try { - const raw = await readFile(join(root, '.env'), 'utf8'); - for (const line of raw.split(/\r?\n/)) { - const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/); - if (m && !(m[1] in process.env)) { // real environment wins over .env - process.env[m[1]] = m[2].replace(/^(["'])(.*)\1$/, '$2'); - } - } - } catch { - // no .env — fall back to defaults - } + try { + const raw = await readFile(join(root, '.env'), 'utf8'); + for (const line of raw.split(/\r?\n/)) { + const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/); + if (m && !(m[1] in process.env)) { + // real environment wins over .env + process.env[m[1]] = m[2].replace(/^(["'])(.*)\1$/, '$2'); + } + } + } catch { + // no .env — fall back to defaults + } } await loadDotEnv(); const apiKey = process.env.IFRAMELY_API_KEY || 'TEST'; const mime = { - '.html': 'text/html; charset=utf-8', - '.js': 'text/javascript; charset=utf-8', - '.mjs': 'text/javascript; charset=utf-8', - '.css': 'text/css', - '.json': 'application/json', - '.map': 'application/json' + '.html': 'text/html; charset=utf-8', + '.js': 'text/javascript; charset=utf-8', + '.mjs': 'text/javascript; charset=utf-8', + '.css': 'text/css', + '.json': 'application/json', + '.map': 'application/json' }; createServer(async (req, res) => { - try { - const urlPath = decodeURIComponent(new URL(req.url, 'http://x').pathname); - let filePath = normalize(join(root, urlPath)); - if (!filePath.startsWith(root)) { - res.writeHead(403).end(); - return; - } - if (urlPath === '/') { - filePath = join(root, 'demo/index.html'); - } - let data = await readFile(filePath); - if (extname(filePath) === '.html') { - data = data.toString().replaceAll('{{IFRAMELY_API_KEY}}', apiKey); - } - res.writeHead(200, { 'content-type': mime[extname(filePath)] || 'application/octet-stream' }); - res.end(data); - } catch { - res.writeHead(404).end('not found'); - } -}).listen(port, () => console.warn(`serving ${root} on http://localhost:${port} (api_key: ${apiKey === 'TEST' ? 'TEST placeholder' : 'from environment'})`)); + try { + const urlPath = decodeURIComponent(new URL(req.url, 'http://x').pathname); + let filePath = normalize(join(root, urlPath)); + if (!filePath.startsWith(root)) { + res.writeHead(403).end(); + return; + } + if (urlPath === '/') { + filePath = join(root, 'demo/index.html'); + } + let data = await readFile(filePath); + if (extname(filePath) === '.html') { + data = data.toString().replaceAll('{{IFRAMELY_API_KEY}}', apiKey); + } + res.writeHead(200, { + 'content-type': mime[extname(filePath)] || 'application/octet-stream' + }); + res.end(data); + } catch { + res.writeHead(404).end('not found'); + } +}).listen(port, () => + console.warn( + `serving ${root} on http://localhost:${port} (api_key: ${apiKey === 'TEST' ? 'TEST placeholder' : 'from environment'})` + ) +); diff --git a/src/ahref.ts b/src/ahref.ts index 143d8df..9606a40 100644 --- a/src/ahref.ts +++ b/src/ahref.ts @@ -2,116 +2,120 @@ import iframely from './iframely'; import * as utils from './utils'; export function boot(): void { - - iframely.on('load', (container?: Element, href?: string) => { - if (container && container.nodeName && typeof href === 'string') { - const a = document.createElement('a'); - a.setAttribute('href', href); - container.appendChild(a); - iframely.trigger('load', a); - } - }); - - iframely.on('load', (el?: Element) => { - - if (!el && !iframely.import) { - - const elements = document.querySelectorAll('a[data-iframely-url]:not([data-import-uri])'); - for (let i = 0; i < elements.length; i++) { - iframely.trigger('load', elements[i]); - } - } - - }); - - iframely.on('load', (el?: Element) => { - - if (el && el.nodeName === 'A' && (el.getAttribute('data-iframely-url') || el.getAttribute('href')) && !el.hasAttribute('data-import-uri')) { - unfurl(el as HTMLAnchorElement); - } - - }); + iframely.on('load', (container?: Element, href?: string) => { + if (container && container.nodeName && typeof href === 'string') { + const a = document.createElement('a'); + a.setAttribute('href', href); + container.appendChild(a); + iframely.trigger('load', a); + } + }); + + iframely.on('load', (el?: Element) => { + if (!el && !iframely.import) { + const elements = document.querySelectorAll( + 'a[data-iframely-url]:not([data-import-uri])' + ); + for (let i = 0; i < elements.length; i++) { + iframely.trigger('load', elements[i]); + } + } + }); + + iframely.on('load', (el?: Element) => { + if ( + el && + el.nodeName === 'A' && + (el.getAttribute('data-iframely-url') || el.getAttribute('href')) && + !el.hasAttribute('data-import-uri') + ) { + unfurl(el as HTMLAnchorElement); + } + }); } function unfurl(el: HTMLAnchorElement): void { - if (!el.getAttribute('data-iframely-url') && !el.getAttribute('href')) { - return; // isn't valid - } - let src; - - const dataIframelyUrl = el.getAttribute('data-iframely-url'); - if (dataIframelyUrl && /^((?:https?:)?\/\/[^/]+)\/\w+/i.test(dataIframelyUrl)) { - src = utils.getEndpoint(dataIframelyUrl, { - v: iframely.VERSION, - app: 1, - theme: iframely.config.theme - }); - } else if ((iframely.config.api_key || iframely.config.key) && iframely.CDN) { - - if (!el.getAttribute('href')) { - console.warn('Iframely cannot build embeds: "href" attribute missing in', el); - return; - } - - src = utils.getEndpoint('/api/iframe', { - url: el.getAttribute('href'), - v: iframely.VERSION, - app: 1, - theme: iframely.config.theme - }, iframely.SUPPORTED_QUERY_STRING); - } else { - console.warn('Iframely cannot build embeds: api key is required as query-string of embed.js'); - } - - if (!src) { - el.removeAttribute('data-iframely-url'); - } else { - - const iframe = document.createElement('iframe'); - - iframe.setAttribute('allowfullscreen', ''); - iframe.setAttribute('allow', 'autoplay *; encrypted-media *; ch-prefers-color-scheme *'); - - if (el.hasAttribute('data-img')) { - iframe.setAttribute('data-img', el.getAttribute('data-img')!); - } - - const isLazy = el.hasAttribute('data-lazy') || el.hasAttribute('data-img') || /&lazy=1/.test(src) || iframely.config.lazy; - - // support restoring failed links by its text - const text = el.textContent; - - if (text && text !== '') { - iframe.textContent = text; - } - - let wrapper = utils.getIframeWrapper(el, true); - - if (wrapper) { - - // Delete all in aspect wrapper. - while (wrapper.aspectWrapper.lastChild) { - wrapper.aspectWrapper.removeChild(wrapper.aspectWrapper.lastChild); - } - - } else { - wrapper = utils.addDefaultWrappers(el); - - el.parentNode!.removeChild(el); - } - - wrapper.aspectWrapper.appendChild(iframe); - - if (isLazy) { - - // send to lazy iframe flow - iframe.setAttribute('data-iframely-url', src); - iframely.trigger('load', iframe); - - } else { - - iframe.setAttribute('src', src); - iframely.trigger('iframe-ready', iframe); - } - } + if (!el.getAttribute('data-iframely-url') && !el.getAttribute('href')) { + return; // isn't valid + } + let src; + + const dataIframelyUrl = el.getAttribute('data-iframely-url'); + if (dataIframelyUrl && /^((?:https?:)?\/\/[^/]+)\/\w+/i.test(dataIframelyUrl)) { + src = utils.getEndpoint(dataIframelyUrl, { + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }); + } else if ((iframely.config.api_key || iframely.config.key) && iframely.CDN) { + if (!el.getAttribute('href')) { + console.warn('Iframely cannot build embeds: "href" attribute missing in', el); + return; + } + + src = utils.getEndpoint( + '/api/iframe', + { + url: el.getAttribute('href'), + v: iframely.VERSION, + app: 1, + theme: iframely.config.theme + }, + iframely.SUPPORTED_QUERY_STRING + ); + } else { + console.warn( + 'Iframely cannot build embeds: api key is required as query-string of embed.js' + ); + } + + if (!src) { + el.removeAttribute('data-iframely-url'); + } else { + const iframe = document.createElement('iframe'); + + iframe.setAttribute('allowfullscreen', ''); + iframe.setAttribute('allow', 'autoplay *; encrypted-media *; ch-prefers-color-scheme *'); + + if (el.hasAttribute('data-img')) { + iframe.setAttribute('data-img', el.getAttribute('data-img')!); + } + + const isLazy = + el.hasAttribute('data-lazy') || + el.hasAttribute('data-img') || + /&lazy=1/.test(src) || + iframely.config.lazy; + + // support restoring failed links by its text + const text = el.textContent; + + if (text && text !== '') { + iframe.textContent = text; + } + + let wrapper = utils.getIframeWrapper(el, true); + + if (wrapper) { + // Delete all in aspect wrapper. + while (wrapper.aspectWrapper.lastChild) { + wrapper.aspectWrapper.removeChild(wrapper.aspectWrapper.lastChild); + } + } else { + wrapper = utils.addDefaultWrappers(el); + + el.parentNode!.removeChild(el); + } + + wrapper.aspectWrapper.appendChild(iframe); + + if (isLazy) { + // send to lazy iframe flow + iframe.setAttribute('data-iframely-url', src); + iframely.trigger('load', iframe); + } else { + iframe.setAttribute('src', src); + iframely.trigger('iframe-ready', iframe); + } + } } diff --git a/src/const.ts b/src/const.ts index 180efe3..3a4045b 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,34 +1,56 @@ import iframely from './iframely'; export function boot(): void { - - iframely.VERSION = 1; - - iframely.ASPECT_WRAPPER_CLASS = 'iframely-responsive'; - iframely.MAXWIDTH_WRAPPER_CLASS = 'iframely-embed'; - iframely.LOADER_CLASS = 'iframely-loader'; - - iframely.DOMAINS = ['cdn.iframe.ly', 'iframe.ly', 'if-cdn.com', 'iframely.net']; - iframely.CDN = iframely.CDN || iframely.DOMAINS[0]; // default domain, user or script src can change CDN - - iframely.BASE_RE = /^(?:https?:)?\/\/[^/]+/i; - iframely.ID_RE = /^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/; - iframely.SCRIPT_RE = /^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i; - iframely.CDN_RE = /^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i; - - iframely.SUPPORTED_QUERY_STRING = ['api_key', 'key', 'iframe', 'html5', 'playerjs', 'align', 'language', 'media', 'maxwidth', 'maxheight', 'lazy', 'import', 'parent', 'shadow', 'click_to_play', 'autoplay', 'mute', 'card', 'consent', 'theme', /^_.+/]; - - iframely.SUPPORTED_THEMES = ['auto', 'light', 'dark']; - - iframely.LAZY_IFRAME_SHOW_TIMEOUT = 3000; - iframely.LAZY_IFRAME_FADE_TIMEOUT = 200; - iframely.CLEAR_WRAPPER_STYLES_TIMEOUT = 3000; - - iframely.RECOVER_HREFS_ON_CANCEL = false; - - iframely.SHADOW = 'iframely-shadow'; - - // All baseline browsers support ' - + ''; - return document.querySelector('iframe')!; +function buildWidgetIframe( + src = 'https://cdn.iframe.ly/api/iframe?url=https%3A%2F%2Fx.com' +): HTMLIFrameElement { + document.body.innerHTML = + '
' + + '' + + '
'; + return document.querySelector('iframe')!; } describe('postMessage', () => { - - it('stringifies the message, adds the page context and trims the target origin', () => { - const iframe = buildWidgetIframe(); - const target = iframe.contentWindow!; - const spy = vi.spyOn(target, 'postMessage'); - - messaging.postMessage({ method: 'getSize' }, 'https://cdn.iframe.ly/some/deep/path?x=1', target); - - expect(spy).toHaveBeenCalledTimes(1); - const [data, origin] = spy.mock.calls[0]; - expect(JSON.parse(data as string)).toEqual({ method: 'getSize', context: document.location.href }); - expect(origin).toBe('https://cdn.iframe.ly'); - }); - - it('defaults the target origin to *', () => { - const iframe = buildWidgetIframe(); - const target = iframe.contentWindow!; - const spy = vi.spyOn(target, 'postMessage'); - - messaging.postMessage({ method: 'getSize' }, undefined, target); - expect(spy.mock.calls[0][1]).toBe('*'); - }); + it('stringifies the message, adds the page context and trims the target origin', () => { + const iframe = buildWidgetIframe(); + const target = iframe.contentWindow!; + const spy = vi.spyOn(target, 'postMessage'); + + messaging.postMessage( + { method: 'getSize' }, + 'https://cdn.iframe.ly/some/deep/path?x=1', + target + ); + + expect(spy).toHaveBeenCalledTimes(1); + const [data, origin] = spy.mock.calls[0]; + expect(JSON.parse(data as string)).toEqual({ + method: 'getSize', + context: document.location.href + }); + expect(origin).toBe('https://cdn.iframe.ly'); + }); + + it('defaults the target origin to *', () => { + const iframe = buildWidgetIframe(); + const target = iframe.contentWindow!; + const spy = vi.spyOn(target, 'postMessage'); + + messaging.postMessage({ method: 'getSize' }, undefined, target); + expect(spy.mock.calls[0][1]).toBe('*'); + }); }); describe('findIframe', () => { - - it('finds an iframe by contentWindow among domain-matched iframes', () => { - const iframe = buildWidgetIframe(); - const found = iframely.findIframe({ - contentWindow: iframe.contentWindow, - domains: iframely.DOMAINS - }); - expect(found).toBe(iframe); - }); - - it('finds an iframe by src match', () => { - const iframe = buildWidgetIframe(); - const found = iframely.findIframe({ - contentWindow: iframe.contentWindow, - src: 'https://cdn.iframe.ly/api/iframe', - domains: false - }); - expect(found).toBe(iframe); - }); - - it('returns undefined for an unknown contentWindow', () => { - buildWidgetIframe(); - expect(iframely.findIframe({ contentWindow: window, domains: iframely.DOMAINS })).toBeUndefined(); - }); - - it('finds iframes inside shadow roots', () => { - document.body.innerHTML = '
'; - const host = document.querySelector('.iframely-shadow')!; - const shadowRoot = host.attachShadow({ mode: 'open' }); - shadowRoot.innerHTML = ''; - const iframe = shadowRoot.querySelector('iframe')!; - - const found = iframely.findIframe({ - contentWindow: iframe.contentWindow, - domains: iframely.DOMAINS - }); - expect(found).toBe(iframe); - }); + it('finds an iframe by contentWindow among domain-matched iframes', () => { + const iframe = buildWidgetIframe(); + const found = iframely.findIframe({ + contentWindow: iframe.contentWindow, + domains: iframely.DOMAINS + }); + expect(found).toBe(iframe); + }); + + it('finds an iframe by src match', () => { + const iframe = buildWidgetIframe(); + const found = iframely.findIframe({ + contentWindow: iframe.contentWindow, + src: 'https://cdn.iframe.ly/api/iframe', + domains: false + }); + expect(found).toBe(iframe); + }); + + it('returns undefined for an unknown contentWindow', () => { + buildWidgetIframe(); + expect( + iframely.findIframe({ contentWindow: window, domains: iframely.DOMAINS }) + ).toBeUndefined(); + }); + + it('finds iframes inside shadow roots', () => { + document.body.innerHTML = '
'; + const host = document.querySelector('.iframely-shadow')!; + const shadowRoot = host.attachShadow({ mode: 'open' }); + shadowRoot.innerHTML = ''; + const iframe = shadowRoot.querySelector('iframe')!; + + const found = iframely.findIframe({ + contentWindow: iframe.contentWindow, + domains: iframely.DOMAINS + }); + expect(found).toBe(iframe); + }); }); describe('message listener', () => { - - function dispatchMessage(data: unknown, source: MessageEventSource | null): void { - window.dispatchEvent(new MessageEvent('message', { data, source })); - } - - it('resolves the widget and triggers the iframely message event for JSON messages', () => { - const iframe = buildWidgetIframe(); - const seen: any[] = []; - iframely.on('message', (widget: any, message: any) => seen.push({ widget, message })); - - dispatchMessage(JSON.stringify({ method: 'test-method', domains: 'all' }), iframe.contentWindow); - - expect(seen).toHaveLength(1); - expect(seen[0].message.method).toBe('test-method'); - expect(seen[0].widget.iframe).toBe(iframe); - expect(seen[0].widget.url).toBe('https://x.com'); - }); - - it('supports the pym height fallback format', () => { - const iframe = buildWidgetIframe(); - const seen: any[] = []; - iframely.on('message', (widget: any, message: any) => seen.push(message)); - - dispatchMessage('heightxPYMx120', iframe.contentWindow); - - expect(seen).toHaveLength(1); - expect(seen[0]).toEqual({ method: 'resize', height: 121, domains: 'all' }); - }); - - it('ignores unrelated messages', () => { - buildWidgetIframe(); - const cb = vi.fn(); - iframely.on('message', cb); - - dispatchMessage('unparseable garbage', null); - dispatchMessage(JSON.stringify({ noMethod: true }), null); - - expect(cb).not.toHaveBeenCalled(); - }); + function dispatchMessage(data: unknown, source: MessageEventSource | null): void { + window.dispatchEvent(new MessageEvent('message', { data, source })); + } + + it('resolves the widget and triggers the iframely message event for JSON messages', () => { + const iframe = buildWidgetIframe(); + const seen: any[] = []; + iframely.on('message', (widget: any, message: any) => seen.push({ widget, message })); + + dispatchMessage( + JSON.stringify({ method: 'test-method', domains: 'all' }), + iframe.contentWindow + ); + + expect(seen).toHaveLength(1); + expect(seen[0].message.method).toBe('test-method'); + expect(seen[0].widget.iframe).toBe(iframe); + expect(seen[0].widget.url).toBe('https://x.com'); + }); + + it('supports the pym height fallback format', () => { + const iframe = buildWidgetIframe(); + const seen: any[] = []; + iframely.on('message', (widget: any, message: any) => seen.push(message)); + + dispatchMessage('heightxPYMx120', iframe.contentWindow); + + expect(seen).toHaveLength(1); + expect(seen[0]).toEqual({ method: 'resize', height: 121, domains: 'all' }); + }); + + it('ignores unrelated messages', () => { + buildWidgetIframe(); + const cb = vi.fn(); + iframely.on('message', cb); + + dispatchMessage('unparseable garbage', null); + dispatchMessage(JSON.stringify({ noMethod: true }), null); + + expect(cb).not.toHaveBeenCalled(); + }); }); diff --git a/tests/unit/renderer.test.ts b/tests/unit/renderer.test.ts index 03addb9..bb3ba6c 100644 --- a/tests/unit/renderer.test.ts +++ b/tests/unit/renderer.test.ts @@ -2,98 +2,107 @@ import { describe, expect, it } from 'vitest'; import render from '../../src/options/renderer'; describe('renderer', () => { + it('renders a checkbox with id/name/label and the checked attribute', () => { + const html = render('checkbox', { key: '_hide', label: 'Hide artwork', checked: true }); + expect(html).toContain('type="checkbox"'); + expect(html).toContain('id="_hide"'); + expect(html).toContain('name="_hide"'); + expect(html).toContain('checked="checked"'); + expect(html).toContain('Hide artwork'); - it('renders a checkbox with id/name/label and the checked attribute', () => { - const html = render('checkbox', { key: '_hide', label: 'Hide artwork', checked: true }); - expect(html).toContain('type="checkbox"'); - expect(html).toContain('id="_hide"'); - expect(html).toContain('name="_hide"'); - expect(html).toContain('checked="checked"'); - expect(html).toContain('Hide artwork'); + const unchecked = render('checkbox', { + key: '_hide', + label: 'Hide artwork', + checked: false + }); + expect(unchecked).not.toContain('checked'); + }); - const unchecked = render('checkbox', { key: '_hide', label: 'Hide artwork', checked: false }); - expect(unchecked).not.toContain('checked'); - }); + it('HTML-escapes scalar interpolations', () => { + const html = render('checkbox', { key: 'k', label: '"quoted" & \'raw\'' }); + expect(html).not.toContain(''); + expect(html).toContain('<b>"quoted" & 'raw'</b>'); + }); - it('HTML-escapes scalar interpolations', () => { - const html = render('checkbox', { key: 'k', label: '"quoted" & \'raw\'' }); - expect(html).not.toContain(''); - expect(html).toContain('<b>"quoted" & 'raw'</b>'); - }); + it('renders nullish values as empty strings', () => { + const html = render('text', { key: 'k', label: 'L' }); + expect(html).toContain('placeholder=""'); + expect(html).toContain('value=""'); + expect(html).not.toContain('undefined'); + }); - it('renders nullish values as empty strings', () => { - const html = render('text', { key: 'k', label: 'L' }); - expect(html).toContain('placeholder=""'); - expect(html).toContain('value=""'); - expect(html).not.toContain('undefined'); - }); + it('injects group elementsHtml raw', () => { + const child = render('checkbox', { key: 'c', label: 'C' }); + const html = render('group', { elementsHtml: child }); + expect(html).toContain('iframely-option__group'); + expect(html).toContain('type="checkbox"'); // not escaped + expect(html).not.toContain('<input'); + }); - it('injects group elementsHtml raw', () => { - const child = render('checkbox', { key: 'c', label: 'C' }); - const html = render('group', { elementsHtml: child }); - expect(html).toContain('iframely-option__group'); - expect(html).toContain('type="checkbox"'); // not escaped - expect(html).not.toContain('<input'); - }); + it('renders radio items with per-item ids, values and checked state', () => { + const html = render('radio', { + key: 'theme', + label: 'Theme color', + inline: true, + items: [ + { id: 'theme-0', value: 'light', label: 'Light', checked: true }, + { id: 'theme-1', value: 'dark', label: 'Dark', checked: false } + ] + }); + expect(html).toContain('iframely-option__group-inline'); + expect(html).toContain('Theme color:'); + expect(html).toContain('id="theme-0"'); + expect(html).toContain('value="light" checked="checked"'); + expect(html).toContain('value="dark"'); + expect(html).not.toContain('value="dark" checked'); + expect((html.match(/name="theme"/g) || []).length).toBe(2); + }); - it('renders radio items with per-item ids, values and checked state', () => { - const html = render('radio', { - key: 'theme', - label: 'Theme color', - inline: true, - items: [ - { id: 'theme-0', value: 'light', label: 'Light', checked: true }, - { id: 'theme-1', value: 'dark', label: 'Dark', checked: false } - ] - }); - expect(html).toContain('iframely-option__group-inline'); - expect(html).toContain('Theme color:'); - expect(html).toContain('id="theme-0"'); - expect(html).toContain('value="light" checked="checked"'); - expect(html).toContain('value="dark"'); - expect(html).not.toContain('value="dark" checked'); - expect((html.match(/name="theme"/g) || []).length).toBe(2); - }); + it('omits the radio group label when label is false', () => { + const html = render('radio', { + key: 'k', + label: false, + items: [{ id: 'k-0', value: 'a', label: 'A', checked: false }] + }); + expect(html).not.toContain('iframely-option__label'); + expect(html).not.toContain('iframely-option__group-inline'); + }); - it('omits the radio group label when label is false', () => { - const html = render('radio', { - key: 'k', - label: false, - items: [{ id: 'k-0', value: 'a', label: 'A', checked: false }] - }); - expect(html).not.toContain('iframely-option__label'); - expect(html).not.toContain('iframely-option__group-inline'); - }); + it('renders select options with the selected attribute', () => { + const html = render('select', { + key: 'style', + label: 'Widget style', + items: [ + { value: 'mini', label: 'Mini', checked: false }, + { value: 'classic', label: 'Classic', checked: true } + ] + }); + expect(html).toContain('Classic'); + expect(html).toContain(''); + }); - it('renders select options with the selected attribute', () => { - const html = render('select', { - key: 'style', - label: 'Widget style', - items: [ - { value: 'mini', label: 'Mini', checked: false }, - { value: 'classic', label: 'Classic', checked: true } - ] - }); - expect(html).toContain('Classic'); - expect(html).toContain(''); - }); + it('renders a range input with min/max/step and CSS custom properties', () => { + const html = render('range', { key: 'h', label: 'Height', min: 100, max: 600, value: 200 }); + expect(html).toContain('type="range"'); + expect(html).toContain('min="100"'); + expect(html).toContain('max="600"'); + expect(html).toContain('step="1"'); + expect(html).toContain('value="200"'); + expect(html).toContain('style="--min: 100; --max: 600; --val: 200;"'); + }); - it('renders a range input with min/max/step and CSS custom properties', () => { - const html = render('range', { key: 'h', label: 'Height', min: 100, max: 600, value: 200 }); - expect(html).toContain('type="range"'); - expect(html).toContain('min="100"'); - expect(html).toContain('max="600"'); - expect(html).toContain('step="1"'); - expect(html).toContain('value="200"'); - expect(html).toContain('style="--min: 100; --max: 600; --val: 200;"'); - }); - - it('renders a text input with the requested inputType and placeholder', () => { - const html = render('text', { key: 'start', label: 'Start from', inputType: 'number', placeholder: 'ex.: 11', value: 5 }); - expect(html).toContain('type="number"'); - expect(html).toContain('placeholder="ex.: 11"'); - expect(html).toContain('value="5"'); - }); + it('renders a text input with the requested inputType and placeholder', () => { + const html = render('text', { + key: 'start', + label: 'Start from', + inputType: 'number', + placeholder: 'ex.: 11', + value: 5 + }); + expect(html).toContain('type="number"'); + expect(html).toContain('placeholder="ex.: 11"'); + expect(html).toContain('value="5"'); + }); }); diff --git a/tests/unit/theme.test.ts b/tests/unit/theme.test.ts index 1b568cb..e695b37 100644 --- a/tests/unit/theme.test.ts +++ b/tests/unit/theme.test.ts @@ -6,56 +6,58 @@ import { boot as bootUtils } from '../../src/utils'; import { boot as bootTheme } from '../../src/theme'; beforeAll(() => { - bootConst(); - bootEvents(); - bootUtils(); - bootTheme(); + bootConst(); + bootEvents(); + bootUtils(); + bootTheme(); }); beforeEach(() => { - iframely.config = {}; - document.body.innerHTML = ''; + iframely.config = {}; + document.body.innerHTML = ''; }); describe('setTheme', () => { - - it('stores a supported theme, notifies iframes and triggers set-theme', () => { - document.body.innerHTML = ''; - const iframe = document.querySelector('iframe')!; - const spy = vi.spyOn(iframe.contentWindow!, 'postMessage'); - const setThemeCb = vi.fn(); - iframely.on('set-theme', setThemeCb); - - iframely.setTheme('dark'); - - expect(iframely.config.theme).toBe('dark'); - expect(setThemeCb).toHaveBeenCalledWith('dark'); - expect(JSON.parse(spy.mock.calls[0][0] as string)).toMatchObject({ method: 'setTheme', data: 'dark' }); - }); - - it('scopes to a container element when provided, without touching config', () => { - document.body.innerHTML = - '
' - + ''; - const inside = document.querySelector('#scope iframe')!; - const outside = document.querySelector('#outside')!; - const insideSpy = vi.spyOn(inside.contentWindow!, 'postMessage'); - const outsideSpy = vi.spyOn(outside.contentWindow!, 'postMessage'); - - iframely.setTheme('light', document.getElementById('scope')!); - - expect(insideSpy).toHaveBeenCalled(); - expect(outsideSpy).not.toHaveBeenCalled(); - expect(iframely.config.theme).toBeUndefined(); - }); - - it('warns and does nothing for an unsupported theme', () => { - const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); - - iframely.setTheme('neon'); - - expect(warn).toHaveBeenCalled(); - expect(iframely.config.theme).toBeUndefined(); - warn.mockRestore(); - }); + it('stores a supported theme, notifies iframes and triggers set-theme', () => { + document.body.innerHTML = ''; + const iframe = document.querySelector('iframe')!; + const spy = vi.spyOn(iframe.contentWindow!, 'postMessage'); + const setThemeCb = vi.fn(); + iframely.on('set-theme', setThemeCb); + + iframely.setTheme('dark'); + + expect(iframely.config.theme).toBe('dark'); + expect(setThemeCb).toHaveBeenCalledWith('dark'); + expect(JSON.parse(spy.mock.calls[0][0] as string)).toMatchObject({ + method: 'setTheme', + data: 'dark' + }); + }); + + it('scopes to a container element when provided, without touching config', () => { + document.body.innerHTML = + '
' + + ''; + const inside = document.querySelector('#scope iframe')!; + const outside = document.querySelector('#outside')!; + const insideSpy = vi.spyOn(inside.contentWindow!, 'postMessage'); + const outsideSpy = vi.spyOn(outside.contentWindow!, 'postMessage'); + + iframely.setTheme('light', document.getElementById('scope')!); + + expect(insideSpy).toHaveBeenCalled(); + expect(outsideSpy).not.toHaveBeenCalled(); + expect(iframely.config.theme).toBeUndefined(); + }); + + it('warns and does nothing for an unsupported theme', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + + iframely.setTheme('neon'); + + expect(warn).toHaveBeenCalled(); + expect(iframely.config.theme).toBeUndefined(); + warn.mockRestore(); + }); }); diff --git a/tests/unit/translator.test.ts b/tests/unit/translator.test.ts index fef2898..7f380aa 100644 --- a/tests/unit/translator.test.ts +++ b/tests/unit/translator.test.ts @@ -3,35 +3,34 @@ import iframely from '../../src/iframely'; import * as translator from '../../src/options/translator'; describe('translator', () => { + it('assigns iframely.optionsTranslator at import time', () => { + expect(typeof iframely.optionsTranslator).toBe('function'); + }); - it('assigns iframely.optionsTranslator at import time', () => { - expect(typeof iframely.optionsTranslator).toBe('function'); - }); + it('translates registered labels', () => { + translator.registerLabels('de', { Light: 'Hell', Dark: 'Dunkel' }); + const t = iframely.optionsTranslator!('de')!; + expect(t('Light')).toBe('Hell'); + expect(t('Dark')).toBe('Dunkel'); + }); - it('translates registered labels', () => { - translator.registerLabels('de', { 'Light': 'Hell', 'Dark': 'Dunkel' }); - const t = iframely.optionsTranslator!('de')!; - expect(t('Light')).toBe('Hell'); - expect(t('Dark')).toBe('Dunkel'); - }); + it('falls back to the original label for unknown or empty translations', () => { + translator.registerLabels('de', { Auto: '' }); + const t = iframely.optionsTranslator!('de')!; + expect(t('Auto')).toBe('Auto'); + expect(t('Unknown label')).toBe('Unknown label'); + }); - it('falls back to the original label for unknown or empty translations', () => { - translator.registerLabels('de', { 'Auto': '' }); - const t = iframely.optionsTranslator!('de')!; - expect(t('Auto')).toBe('Auto'); - expect(t('Unknown label')).toBe('Unknown label'); - }); + it('returns identity for an unregistered language', () => { + const t = iframely.optionsTranslator!('xx')!; + expect(t('Light')).toBe('Light'); + }); - it('returns identity for an unregistered language', () => { - const t = iframely.optionsTranslator!('xx')!; - expect(t('Light')).toBe('Light'); - }); - - it('merges labels registered in multiple calls', () => { - translator.registerLabels('fr', { 'Light': 'Lumière' }); - translator.registerLabels('fr', { 'Dark': 'Sombre' }); - const t = iframely.optionsTranslator!('fr')!; - expect(t('Light')).toBe('Lumière'); - expect(t('Dark')).toBe('Sombre'); - }); + it('merges labels registered in multiple calls', () => { + translator.registerLabels('fr', { Light: 'Lumière' }); + translator.registerLabels('fr', { Dark: 'Sombre' }); + const t = iframely.optionsTranslator!('fr')!; + expect(t('Light')).toBe('Lumière'); + expect(t('Dark')).toBe('Sombre'); + }); }); diff --git a/tests/unit/utils.test.ts b/tests/unit/utils.test.ts index bd33643..cc9aa08 100644 --- a/tests/unit/utils.test.ts +++ b/tests/unit/utils.test.ts @@ -6,181 +6,206 @@ import { boot as bootUtils } from '../../src/utils'; import * as utils from '../../src/utils'; beforeAll(() => { - bootConst(); - bootEvents(); - bootUtils(); + bootConst(); + bootEvents(); + bootUtils(); }); beforeEach(() => { - iframely.config = {}; - document.body.innerHTML = ''; + iframely.config = {}; + document.body.innerHTML = ''; }); describe('addQueryString', () => { - - it('appends params with ? for a bare href and & for an existing query', () => { - expect(utils.addQueryString('//host/path', { a: 'b' })).toBe('//host/path?a=b'); - expect(utils.addQueryString('//host/path?x=1', { a: 'b' })).toBe('//host/path?x=1&a=b'); - }); - - it('url-encodes values', () => { - expect(utils.addQueryString('//host/p', { url: 'https://a.com/?x=1&y=2' })) - .toBe('//host/p?url=' + encodeURIComponent('https://a.com/?x=1&y=2')); - }); - - it('converts booleans to 1/0 except for _-prefixed keys', () => { - expect(utils.addQueryString('//host/p', { lazy: true, autoplay: false })).toBe('//host/p?lazy=1&autoplay=0'); - expect(utils.addQueryString('//host/p', { _opt: true })).toBe('//host/p?_opt=true'); - }); - - it('expands arrays into repeated params', () => { - expect(utils.addQueryString('//host/p', { uri: ['a', 'b'] })).toBe('//host/p?uri=a&uri=b'); - }); - - it('skips undefined values and keys already present in the href', () => { - expect(utils.addQueryString('//host/p?a=1', { a: '2', b: undefined, c: '3' })).toBe('//host/p?a=1&c=3'); - }); + it('appends params with ? for a bare href and & for an existing query', () => { + expect(utils.addQueryString('//host/path', { a: 'b' })).toBe('//host/path?a=b'); + expect(utils.addQueryString('//host/path?x=1', { a: 'b' })).toBe('//host/path?x=1&a=b'); + }); + + it('url-encodes values', () => { + expect(utils.addQueryString('//host/p', { url: 'https://a.com/?x=1&y=2' })).toBe( + '//host/p?url=' + encodeURIComponent('https://a.com/?x=1&y=2') + ); + }); + + it('converts booleans to 1/0 except for _-prefixed keys', () => { + expect(utils.addQueryString('//host/p', { lazy: true, autoplay: false })).toBe( + '//host/p?lazy=1&autoplay=0' + ); + expect(utils.addQueryString('//host/p', { _opt: true })).toBe('//host/p?_opt=true'); + }); + + it('expands arrays into repeated params', () => { + expect(utils.addQueryString('//host/p', { uri: ['a', 'b'] })).toBe('//host/p?uri=a&uri=b'); + }); + + it('skips undefined values and keys already present in the href', () => { + expect(utils.addQueryString('//host/p?a=1', { a: '2', b: undefined, c: '3' })).toBe( + '//host/p?a=1&c=3' + ); + }); }); describe('parseQueryString', () => { - - it('parses all params without an allowlist', () => { - expect(utils.parseQueryString('//host/p?a=1&b=x%20y')).toEqual({ a: '1', b: 'x y' }); - }); - - it('returns an empty object without a query string', () => { - expect(utils.parseQueryString('//host/p')).toEqual({}); - }); - - it('filters by allowlist of strings and regexps', () => { - const parsed = utils.parseQueryString('//h/p?api_key=k&_opt=1&evil=x', ['api_key', /^_.+/]); - expect(parsed).toEqual({ api_key: 'k', _opt: '1' }); - }); + it('parses all params without an allowlist', () => { + expect(utils.parseQueryString('//host/p?a=1&b=x%20y')).toEqual({ a: '1', b: 'x y' }); + }); + + it('returns an empty object without a query string', () => { + expect(utils.parseQueryString('//host/p')).toEqual({}); + }); + + it('filters by allowlist of strings and regexps', () => { + const parsed = utils.parseQueryString('//h/p?api_key=k&_opt=1&evil=x', ['api_key', /^_.+/]); + expect(parsed).toEqual({ api_key: 'k', _opt: '1' }); + }); }); describe('getEndpoint', () => { - - it('prefixes relative paths with the CDN and protocol slashes', () => { - expect(utils.getEndpoint('/api/iframe', { url: 'https://x.com' })) - .toBe('//cdn.iframe.ly/api/iframe?url=' + encodeURIComponent('https://x.com')); - }); - - it('prefers an explicit CDN option and removes it from the query', () => { - const endpoint = utils.getEndpoint('/api/iframe', { CDN: '//other.cdn', url: 'u' }); - expect(endpoint).toBe('//other.cdn/api/iframe?url=u'); - }); - - it('keeps absolute urls untouched apart from the query string', () => { - expect(utils.getEndpoint('https://cdn.iframe.ly/abc', { v: 1 })).toBe('https://cdn.iframe.ly/abc?v=1'); - }); - - it('adds matching iframely.config values for config_params, including regex matches', () => { - iframely.extendOptions({ api_key: 'KEY', _theme_opt: 'x', unrelated: 'nope' }); - const endpoint = utils.getEndpoint('/api/iframe', { url: 'u' }, iframely.SUPPORTED_QUERY_STRING); - expect(endpoint).toContain('api_key=KEY'); - expect(endpoint).toContain('_theme_opt=x'); - expect(endpoint).not.toContain('unrelated'); - }); + it('prefixes relative paths with the CDN and protocol slashes', () => { + expect(utils.getEndpoint('/api/iframe', { url: 'https://x.com' })).toBe( + '//cdn.iframe.ly/api/iframe?url=' + encodeURIComponent('https://x.com') + ); + }); + + it('prefers an explicit CDN option and removes it from the query', () => { + const endpoint = utils.getEndpoint('/api/iframe', { CDN: '//other.cdn', url: 'u' }); + expect(endpoint).toBe('//other.cdn/api/iframe?url=u'); + }); + + it('keeps absolute urls untouched apart from the query string', () => { + expect(utils.getEndpoint('https://cdn.iframe.ly/abc', { v: 1 })).toBe( + 'https://cdn.iframe.ly/abc?v=1' + ); + }); + + it('adds matching iframely.config values for config_params, including regex matches', () => { + iframely.extendOptions({ api_key: 'KEY', _theme_opt: 'x', unrelated: 'nope' }); + const endpoint = utils.getEndpoint( + '/api/iframe', + { url: 'u' }, + iframely.SUPPORTED_QUERY_STRING + ); + expect(endpoint).toContain('api_key=KEY'); + expect(endpoint).toContain('_theme_opt=x'); + expect(endpoint).not.toContain('unrelated'); + }); }); describe('extendOptions', () => { - - it('normalizes falsy/truthy string and number values to booleans', () => { - iframely.extendOptions({ a: '0', b: 'false', c: 0, d: false, e: '1', f: 'true', g: 1, h: true, i: 'text' }); - expect(iframely.config).toEqual({ - a: false, b: false, c: false, d: false, - e: true, f: true, g: true, h: true, - i: 'text' - }); - }); - - it('does not override values previously disabled with false', () => { - iframely.extendOptions({ lazy: false }); - iframely.extendOptions({ lazy: true }); - expect(iframely.config.lazy).toBe(false); - }); - - it('ignores undefined options', () => { - expect(() => iframely.extendOptions(undefined)).not.toThrow(); - }); + it('normalizes falsy/truthy string and number values to booleans', () => { + iframely.extendOptions({ + a: '0', + b: 'false', + c: 0, + d: false, + e: '1', + f: 'true', + g: 1, + h: true, + i: 'text' + }); + expect(iframely.config).toEqual({ + a: false, + b: false, + c: false, + d: false, + e: true, + f: true, + g: true, + h: true, + i: 'text' + }); + }); + + it('does not override values previously disabled with false', () => { + iframely.extendOptions({ lazy: false }); + iframely.extendOptions({ lazy: true }); + expect(iframely.config.lazy).toBe(false); + }); + + it('ignores undefined options', () => { + expect(() => iframely.extendOptions(undefined)).not.toThrow(); + }); }); describe('widget wrappers', () => { - - function buildWidgetDom(inner = '') { - document.body.innerHTML = - '
' + inner + '
'; - return document.querySelector('.iframely-responsive')!.firstElementChild!; - } - - it('getIframeWrapper finds both wrappers for a well-formed widget', () => { - const iframe = buildWidgetDom(); - const wrapper = utils.getIframeWrapper(iframe, true)!; - expect(wrapper.aspectWrapper.className).toBe('iframely-responsive'); - expect(wrapper.maxWidthWrapper.className).toBe('iframely-embed'); - }); - - it('getIframeWrapper returns undefined without the wrapper structure', () => { - document.body.innerHTML = '
'; - expect(utils.getIframeWrapper(document.querySelector('iframe')!, true)).toBeUndefined(); - }); - - it('getWidget extracts the url from an iframe src url= param', () => { - const iframe = buildWidgetDom(); - const widget = utils.getWidget(iframe)!; - expect(widget.iframe).toBe(iframe); - expect(widget.url).toBe('https://x.com'); - }); - - it('getWidget extracts the url from an anchor href', () => { - const a = buildWidgetDom(''); - const widget = utils.getWidget(a)!; - expect(widget.url).toBe('https://y.com/page'); - }); - - it('addDefaultWrappers inserts the two-wrapper structure before the element', () => { - document.body.innerHTML = '

x

'; - const a = document.getElementById('link')!; - const wrapper = utils.addDefaultWrappers(a); - expect(wrapper.maxWidthWrapper.className).toBe('iframely-embed'); - expect(wrapper.aspectWrapper.parentNode).toBe(wrapper.maxWidthWrapper); - expect(wrapper.maxWidthWrapper.nextSibling).toBe(a); - }); + function buildWidgetDom( + inner = '' + ) { + document.body.innerHTML = + '
' + + inner + + '
'; + return document.querySelector('.iframely-responsive')!.firstElementChild!; + } + + it('getIframeWrapper finds both wrappers for a well-formed widget', () => { + const iframe = buildWidgetDom(); + const wrapper = utils.getIframeWrapper(iframe, true)!; + expect(wrapper.aspectWrapper.className).toBe('iframely-responsive'); + expect(wrapper.maxWidthWrapper.className).toBe('iframely-embed'); + }); + + it('getIframeWrapper returns undefined without the wrapper structure', () => { + document.body.innerHTML = '
'; + expect(utils.getIframeWrapper(document.querySelector('iframe')!, true)).toBeUndefined(); + }); + + it('getWidget extracts the url from an iframe src url= param', () => { + const iframe = buildWidgetDom(); + const widget = utils.getWidget(iframe)!; + expect(widget.iframe).toBe(iframe); + expect(widget.url).toBe('https://x.com'); + }); + + it('getWidget extracts the url from an anchor href', () => { + const a = buildWidgetDom(''); + const widget = utils.getWidget(a)!; + expect(widget.url).toBe('https://y.com/page'); + }); + + it('addDefaultWrappers inserts the two-wrapper structure before the element', () => { + document.body.innerHTML = '

x

'; + const a = document.getElementById('link')!; + const wrapper = utils.addDefaultWrappers(a); + expect(wrapper.maxWidthWrapper.className).toBe('iframely-embed'); + expect(wrapper.aspectWrapper.parentNode).toBe(wrapper.maxWidthWrapper); + expect(wrapper.maxWidthWrapper.nextSibling).toBe(a); + }); }); describe('setStyles', () => { - - it('converts numeric values to px', () => { - const el = document.createElement('div'); - utils.setStyles(el, { height: 400, width: '250' }); - expect(el.style.height).toBe('400px'); - expect(el.style.width).toBe('250px'); - }); - - it('keeps non-numeric string values as-is and skips max-width "keep"', () => { - const el = document.createElement('div'); - el.style.maxWidth = '100px'; - utils.setStyles(el, { position: 'absolute', 'max-width': 'keep' }); - expect(el.style.position).toBe('absolute'); - expect(el.style.maxWidth).toBe('100px'); - }); - - it('tolerates a missing element', () => { - expect(() => utils.setStyles(null, { height: 1 })).not.toThrow(); - }); + it('converts numeric values to px', () => { + const el = document.createElement('div'); + utils.setStyles(el, { height: 400, width: '250' }); + expect(el.style.height).toBe('400px'); + expect(el.style.width).toBe('250px'); + }); + + it('keeps non-numeric string values as-is and skips max-width "keep"', () => { + const el = document.createElement('div'); + el.style.maxWidth = '100px'; + utils.setStyles(el, { position: 'absolute', 'max-width': 'keep' }); + expect(el.style.position).toBe('absolute'); + expect(el.style.maxWidth).toBe('100px'); + }); + + it('tolerates a missing element', () => { + expect(() => utils.setStyles(null, { height: 1 })).not.toThrow(); + }); }); describe('createScript / applyNonce', () => { - - it('creates a script and applies the configured nonce', () => { - iframely.config.nonce = 'abc123'; - const script = utils.createScript(); - expect(script.tagName).toBe('SCRIPT'); - expect(script.nonce).toBe('abc123'); - }); - - it('leaves nonce empty when not configured', () => { - const script = utils.createScript(); - expect(script.nonce).toBeFalsy(); - }); + it('creates a script and applies the configured nonce', () => { + iframely.config.nonce = 'abc123'; + const script = utils.createScript(); + expect(script.tagName).toBe('SCRIPT'); + expect(script.nonce).toBe('abc123'); + }); + + it('leaves nonce empty when not configured', () => { + const script = utils.createScript(); + expect(script.nonce).toBeFalsy(); + }); }); diff --git a/tsconfig.build.json b/tsconfig.build.json index ffc4cab..678fb95 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,12 +1,13 @@ { - "extends": "./tsconfig.json", - "compilerOptions": { - "noEmit": false, - "emitDeclarationOnly": true, - "declaration": true, - "declarationMap": false, - "outDir": "dist/types" - }, - "include": ["src"], - "exclude": ["src/options/lang/labels.LAN.example.ts"] + "extends": "./tsconfig.json", + "compilerOptions": { + "noEmit": false, + "emitDeclarationOnly": true, + "declaration": true, + "declarationMap": false, + "rootDir": "src", + "outDir": "dist/types" + }, + "include": ["src"], + "exclude": ["src/options/lang/labels.LAN.example.ts"] } diff --git a/tsconfig.json b/tsconfig.json index f12cf29..9039213 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,20 +1,27 @@ { - "compilerOptions": { - "target": "ES2022", - "lib": ["ES2022", "DOM", "DOM.Iterable"], - "module": "ESNext", - "moduleResolution": "bundler", - "types": [], + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "types": [], - "strict": true, - "noImplicitOverride": true, - "noFallthroughCasesInSwitch": true, + "strict": true, + "noImplicitOverride": true, + "noFallthroughCasesInSwitch": true, - "isolatedModules": true, - "verbatimModuleSyntax": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "noEmit": true - }, - "include": ["src", "tests", "vitest.config.ts", "playwright.config.ts"] + "isolatedModules": true, + "verbatimModuleSyntax": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "noEmit": true + }, + "include": [ + "src", + "tests", + "vitest.config.ts", + "playwright.config.ts", + "oxlint.config.ts", + "oxfmt.config.ts" + ] } diff --git a/vitest.config.ts b/vitest.config.ts index 2dc54bd..fea63e2 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,8 +1,8 @@ import { defineConfig } from 'vitest/config'; export default defineConfig({ - test: { - environment: 'jsdom', - include: ['tests/unit/**/*.test.ts'] - } + test: { + environment: 'jsdom', + include: ['tests/unit/**/*.test.ts'] + } }); From 1f11c4417c8f17e336feeb2221b3963310c84cfc Mon Sep 17 00:00:00 2001 From: Alexander Matveyenko Date: Sat, 11 Jul 2026 12:39:01 +0200 Subject: [PATCH 5/7] Make the ESM build manual-activation, SSR-safe; add iframely.configure - ESM entries (main.ts, main-options.ts) no longer auto-run on DOMContentLoaded: config.autorun defaults to false, and consumers activate embeds explicitly with iframely.load(). Pre-set window.iframely = { config: { autorun: true } } before importing to restore the script-tag behavior. IIFE script bundles are unchanged. - Importing is now safe in isomorphic environments (SvelteKit, etc.): on the server iframely.ts exports a detached, stateless no-op stub; dom-ready and the entry bootstraps skip without browser globals, so a server pass neither throws nor runs side effects. - Rename extendOptions to iframely.configure; extendOptions stays as a deprecated alias registered in deprecated.ts and marked @deprecated in the types. Internal callers switched. - Tests: new node-environment SSR suite (imports every public entry, asserts inert no-op behavior), new e2e spec proving no auto-run on import and activation via load(), surface snapshot gains the `configure` key, alias identity pinned in unit tests. - Document the ESM/isomorphic usage flow in the README. Co-Authored-By: Claude Fable 5 --- README.md | 116 +++++++++++++++++++++++----------- demo/esm.html | 9 ++- dist/embed-options.js | 35 ++++++++-- dist/embed-options.min.js | 4 +- dist/embed.js | 35 ++++++++-- dist/embed.min.js | 2 +- dist/esm/chunks/deprecated.js | 11 ++-- dist/esm/chunks/iframely.js | 22 ++++++- dist/esm/main-options.js | 5 +- dist/esm/main.js | 5 +- dist/options.i18n.de.js | 22 ++++++- dist/options.i18n.de.min.js | 2 +- dist/options.i18n.fr.js | 22 ++++++- dist/options.i18n.fr.min.js | 2 +- dist/options.js | 22 ++++++- dist/options.min.js | 28 ++++---- dist/types/main-options.d.ts | 3 +- dist/types/main.d.ts | 3 +- dist/types/types.d.ts | 2 + src/deprecated.ts | 3 + src/dom-ready.ts | 15 +++-- src/iframely.ts | 37 +++++++++-- src/index-options.ts | 5 +- src/index.ts | 5 +- src/intersection.ts | 2 +- src/main-options.ts | 12 +++- src/main.ts | 15 ++++- src/theme.ts | 2 +- src/types.ts | 2 + src/utils.ts | 6 +- tests/e2e/esm.spec.ts | 27 +++++++- tests/e2e/surface.spec.ts | 4 +- tests/unit/ssr.test.ts | 41 ++++++++++++ tests/unit/utils.test.ts | 18 ++++-- 34 files changed, 428 insertions(+), 116 deletions(-) create mode 100644 tests/unit/ssr.test.ts diff --git a/README.md b/README.md index 79c3c5f..30a39fb 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,95 @@ # Iframely.com Embed.js -Embed.js script is a part of [Iframely](https://iframely.com) cloud service for rich media embeds and works *only* with Iframely-hosted [iFrame helpers](https://iframely.com/docs/iframes). The script is normally hosted on Iframely's CDN and is included when required into HTML codes that our API returns. If you wish to self-host the script rather than rely on our CDN, we make the script available here on GitHub and on NPM. - -The script's main function is to adjust height of rich media with variable sizes (say, Twitter, Facebook or Iframely summary cards) and to handle other messages received from Iframely iFrames. The script also enables lazy-loading through intersection observer (including video placeholders), unfurls URLs if you use Iframely without making API requests first, and uses web component imports to speed-up bulk inserts of rich media. - -Read more about the script itself at [iframely.com/docs/embedjs](https://iframely.com/docs/embedjs). The description below focuses solely on self-hosting of the script. - +Embed.js script is a part of [Iframely](https://iframely.com) cloud service for rich media embeds and works *only* with +Iframely-hosted [iFrame helpers](https://iframely.com/docs/iframes). The script is normally hosted on Iframely's CDN and +is included when required in HTML codes that our API returns. If you wish to self-host the script rather than rely on +our CDN, we make the script available here on GitHub and on NPM. + +The script's main function is to adjust the height of rich media with variable sizes (say, Twitter, Facebook, or +Iframely summary cards) and to handle other messages received from Iframely iFrames. The script also enables +lazy-loading through intersection observer (including video placeholders), unfurls URLs if you use Iframely without +making API requests first, and uses web component imports to speed up bulk inserts of rich media. Read more about the +script itself at [iframely.com/docs/embedjs](https://iframely.com/docs/embedjs). The description below focuses solely on +self-hosting of the script. ## Host embed.js on your servers -To serve embed.js script from your network, your reverse proxy needs to be configured to point `embed.js` file to its location on the local disc. +To serve embed.js script from your network, your reverse proxy needs to be configured to point `embed.js` file to its +location on the local disc. * `dist/embed.js` - not minified development version * `dist/embed.min.js` - minified production version -You can either clone repo from GitHub, or pull library from NPM as `@iframely/embed.js`. We recommend creating a symlink to a file first for a simpler reverse proxy config. +You can either clone repo from GitHub or pull the library from NPM as `@iframely/embed.js`. We recommend creating a +symlink to a file first for a simpler reverse proxy config. + +Alternatively, you may include the contents of embed.js in your other JavaScript distributions. The package ships an ES +module build: `import { iframely } from '@iframely/embed.js'` (embed only) or `'@iframely/embed.js/options'` (embed + +options form). TypeScript declarations are included. Unlike the script tag, the ES module does **not** auto-run on +DOMContentLoaded — activate it when your page is ready: -Alternatively, you may include the contents of embed.js into your other JavaScript distributions. The package ships an ES module build: `import '@iframely/embed.js'` (embed only) or `import '@iframely/embed.js/options'` (embed + options form) in your own build to pull all dependencies. TypeScript declarations are included. + import { iframely } from '@iframely/embed.js'; + iframely.configure({ api_key: '...' }); + iframely.load(); + +The module is safe to import in isomorphic setups (SvelteKit, Next.js, etc.): on the server it exports an inert +no-op stub and performs no side effects, so you can import it at the top level and call `iframely.load()` from +client-only code (e.g. Svelte's `onMount`). ## Omit cloud embed.js from API responses -The HTML embed codes you get from Iframely APIs will include the cloud copy of embed.js by default (as ` diff --git a/dist/embed-options.js b/dist/embed-options.js index 9bf60ee..b3c945a 100644 --- a/dist/embed-options.js +++ b/dist/embed-options.js @@ -2,7 +2,27 @@ //#region src/iframely.ts - var iframely = window.iframely = window.iframely || {}; + function createServerStub() { + const noop = () => {}; + return { + config: {}, + on: noop, + trigger: noop, + triggerAsync: noop, + load: noop, + configure: noop, + extendOptions: noop, + setTheme: noop, + cancelWidget: noop, + openHref: noop, + addEventListener: noop, + isTouch: () => false, + findIframe: () => void 0, + getElementComputedStyle: () => void 0, + buildOptionsForm: noop + }; + } + var iframely = typeof window === "undefined" ? createServerStub() : window.iframely = window.iframely || {}; iframely.config = iframely.config || {}; //#endregion @@ -11,7 +31,7 @@ if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(f, 0); document.addEventListener("DOMContentLoaded", f); }; - DOMReady(() => { + if (typeof document !== "undefined") DOMReady(() => { if (typeof iframely.config.autorun === "undefined" || iframely.config.autorun !== false) iframely.trigger("load"); }); @@ -183,7 +203,7 @@ //#region src/utils.ts function boot$12() { iframely.on("init", () => { - iframely.extendOptions(parseQueryStringFromScriptSrc()); + iframely.configure(parseQueryStringFromScriptSrc()); defineDefaultStyles(); if (iframely.config.theme) iframely.setTheme(iframely.config.theme); requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, ""))); @@ -194,7 +214,7 @@ iframely.getElementComputedStyle = (el, style) => { return window.getComputedStyle(el).getPropertyValue(style); }; - iframely.extendOptions = (options) => { + iframely.configure = (options) => { if (!options) return; Object.keys(options).forEach((key) => { const new_value = options[key] === 0 || options[key] === "0" || options[key] === false || options[key] === "false" ? false : options[key] === 1 || options[key] === "1" || options[key] === true || options[key] === "true" ? true : options[key]; @@ -390,7 +410,7 @@ } function boot$11() { iframely.on("init", () => { - iframely.extendOptions({ intersection: 1 }); + iframely.configure({ intersection: 1 }); }); iframely.on("message", (widget, message) => { if (message.method === "send-intersections" && widget.iframe) { @@ -418,7 +438,7 @@ if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) if (container) if (container.tagName === "IFRAME") setThemeInIframe(container, theme); else setThemeInAllIframes(container, theme); else { - iframely.extendOptions({ theme }); + iframely.configure({ theme }); setThemeInAllIframes(document, theme); iframely.trigger("set-theme", theme); } @@ -1024,6 +1044,7 @@ function boot$1() { iframely.widgets = iframely.widgets || {}; iframely.widgets.load = iframely.load; + iframely.extendOptions = iframely.configure; if (!iframely.events) { iframely.events = {}; iframely.events.on = iframely.on; @@ -1372,7 +1393,7 @@ //#endregion //#region src/index-options.ts - if (!iframely._loaded) { + if (typeof window !== "undefined" && !iframely._loaded) { iframely._loaded = true; boot$15(); boot$14(); diff --git a/dist/embed-options.min.js b/dist/embed-options.min.js index 8bedec2..6baf06e 100644 --- a/dist/embed-options.min.js +++ b/dist/embed-options.min.js @@ -1,4 +1,4 @@ -(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{},(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(e.config.autorun===void 0||e.config.autorun!==!1)&&e.trigger(`load`)});function t(){e.VERSION=1,e.ASPECT_WRAPPER_CLASS=`iframely-responsive`,e.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,e.LOADER_CLASS=`iframely-loader`,e.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],e.CDN=e.CDN||e.DOMAINS[0],e.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,e.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,e.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],e.SUPPORTED_THEMES=[`auto`,`light`,`dark`],e.LAZY_IFRAME_SHOW_TIMEOUT=3e3,e.LAZY_IFRAME_FADE_TIMEOUT=200,e.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,e.RECOVER_HREFS_ON_CANCEL=!1,e.SHADOW=`iframely-shadow`,e.SUPPORT_IFRAME_LOADING_ATTR=!0}var n=e=>{window.requestAnimationFrame(e)},r={};function i(t,i,a){(r[t]||[]).forEach(t=>{i?n(()=>{t.apply(e,a)}):t.apply(e,a)}),t===`init`&&(r[t]=[])}function a(){e.on=(e,t)=>{(r[e]=r[e]||[]).push(t)},e.trigger=(e,...t)=>{i(e,!1,t)},e.triggerAsync=(e,...t)=>{i(e,!0,t)}}function o(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function s(e,t){let n;for(let r=0;r{let t=c(document,e);return t||=l(document,e),t},o((t,n)=>{if(n&&(n.method||n.type||n.context)){let r=e.findIframe({contentWindow:t.source,src:n.src||n.context,domains:n.domains!==`all`&&e.DOMAINS.concat(e.CDN)});if(r){let t=m(r);t&&n.url&&(t.url=n.url),e.trigger(`message`,t,n)}}})}function d(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){e.on(`init`,()=>{e.extendOptions(y()),te(),e.config.theme&&e.setTheme(e.config.theme),ne(e.DOMAINS.concat(e.CDN.replace(/^https?:\/\//,``)))}),e.load=function(...t){e.trigger(`load`,...t)},e.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),e.extendOptions=t=>{t&&Object.keys(t).forEach(n=>{let r=t[n]===0||t[n]===`0`||t[n]===!1||t[n]===`false`?!1:t[n]===1||t[n]===`1`||t[n]===!0||t[n]===`true`||t[n];e.config[n]!==!1&&(e.config[n]=r)})}}function f(t,n){let r=t.parentNode;if(!r||r.nodeName!==`DIV`||b(r)>2||n&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||b(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function p(t){let n=t.parentNode,r=document.createElement(`div`);r.className=e.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=e.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,t),{aspectWrapper:i,maxWidthWrapper:r}}function m(e){let t=f(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=S(r);e.url&&(n.url=e.url)}return n}function h(t,n){t&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=t.style,o=a[r];e.getElementComputedStyle(t,r)!=i&&!(t.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function g(t){e.config.nonce&&(t.nonce=e.config.nonce)}function te(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,g(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function _(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function v(t,n,r){let i=t;if(/^(https?:)?\/\//i.test(t)||(i=(n&&n.CDN||e.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=_(i,n)),r&&r.length){let t={},n=Object.keys(e.config);for(let i=0;i0)return t}}return{}}function ne(t){let n=document.querySelectorAll(`iframe[src*="`+(t||e.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{d({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},E(e)),w[t]=n),n}function E(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function re(){e.on(`init`,()=>{e.extendOptions({intersection:1})}),e.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},T(n).observe(e.iframe)}})}function D(e,t){d({method:`setTheme`,data:t},`*`,e.contentWindow)}function O(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{t&&e.SUPPORTED_THEMES.indexOf(t)>-1?n?n.tagName===`IFRAME`?D(n,t):O(n,t):(e.extendOptions({theme:t}),O(document,t),e.trigger(`set-theme`,t)):console.warn(`Using iframely.setTheme with not supported theme: "`+t+`". Supported themes are: `+e.SUPPORTED_THEMES.join(`, `))}}var A={};function ie(){e.on(`load`,t=>{if(!t&&e.config.import!==!1&&se()&&!e.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&ae(e)}}),e.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=A[e.uri];if(n)for(let r=0;r{e.trigger(`import-loaded`,t),t.widgets.forEach(n=>{e.trigger(`load`,n,t)}),j()},e.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,e.on(`import-widget-ready`,M),e.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function ae(t){let n=C(),r=[],i=[],a=null;function o(e,t){A[e]||(A[e]=[]),A[e].push(t)}function s(t){let n=t.getAttribute(`data-iframely-url`),s=n.match(e.ID_RE),c=s&&s[1],l=S(n,e.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let t=n.match(e.BASE_RE);l.CDN=t&&t[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?e.trigger(`load`,t):c?(t.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,t)):(u||=t.getAttribute(`href`),(a.key||a.api_key||e.config.api_key||e.config.key)&&u?(t.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,t)):e.trigger(`load`,t))}for(let e=0;e0||i.length>0?(a||={},a.touch=e.isTouch(),a.flash=!1,a.app=1,e.config.theme&&(a.theme=e.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=e.VERSION,n.src=v(`/api/import/v2`,a,e.SUPPORTED_QUERY_STRING),n.onerror=()=>{j()},document.head.appendChild(n),e.import=n):(j(),e.trigger(`load`))}function oe(t,n,r){let i=t.cancel,a=t.shadow,o=t.renderEvent,s=f(n,!0);if(i)e.cancelWidget(m(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=t.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:t.context,stylesIds:t.stylesIds,stylesDict:r.commonShadowStyles};e.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),e.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),N(i);c.removeChild(l),o&&setTimeout(()=>{M(c)},e.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function j(){delete e.import;let t=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function N(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=C();r.type=`text/javascript`;for(let e=0;e{if(t&&t.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),t.appendChild(r),e.trigger(`load`,r)}}),e.on(`load`,t=>{if(!t&&!e.import){let t=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&F(e)})}function F(t){if(!t.getAttribute(`data-iframely-url`)&&!t.getAttribute(`href`))return;let n,r=t.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=v(r,{v:e.VERSION,app:1,theme:e.config.theme});else if((e.config.api_key||e.config.key)&&e.CDN){if(!t.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,t);return}n=v(`/api/iframe`,{url:t.getAttribute(`href`),v:e.VERSION,app:1,theme:e.config.theme},e.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)t.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),t.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,t.getAttribute(`data-img`));let i=t.hasAttribute(`data-lazy`)||t.hasAttribute(`data-img`)||/&lazy=1/.test(n)||e.config.lazy,a=t.textContent;a&&a!==``&&(r.textContent=a);let o=f(t,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=p(t),t.parentNode.removeChild(t);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),e.trigger(`load`,r)):(r.setAttribute(`src`,n),e.trigger(`iframe-ready`,r))}}function I(){e.on(`load`,t=>{if(t&&t.nodeName===`IFRAME`&&t.hasAttribute(`data-iframely-url`)&&t.hasAttribute(`data-img`)&&!t.getAttribute(`src`)){let n=t.getAttribute(`data-img`);t.removeAttribute(`data-img`),t.setAttribute(`data-img-created`,``);let r=m(t),i=t.getAttribute(`data-iframely-url`);r&&(L(r,i,n),i=_(i,{img:1}),t.setAttribute(`data-iframely-url`,i),new G(r)),e.trigger(`load`,t)}}),e.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(B(e),n=U(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=U(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=U(e),n?.registerLoadingTimeout())})}function L(t,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let t=S(n),r={};for(let e in t)e.indexOf(`_`)===0&&(r[e]=t[e]);if(t.media&&(r.media=t.media),n.match(/\/api\/iframe/))i=v(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:t.url,api_key:t.api_key,key:t.key},r));else if(n.match(e.ID_RE))i=v(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);h(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,e.LOADER_CLASS),a.appendChild(o);let s=e.getElementComputedStyle(t.aspectWrapper,`padding-top`),c=e.getElementComputedStyle(t.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let e=document.createElement(`div`);h(e,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),e.appendChild(a),t.aspectWrapper.appendChild(e)}else t.aspectWrapper.appendChild(a)}function R(e,t){let n=0;for(let r=0;r1&&R(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var V=[];function H(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),V.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{B(this.widget)},e.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),W(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},e.LAZY_IFRAME_SHOW_TIMEOUT)}};function K(){e.on(`load`,t=>{if(!t){let t=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&q(e)})}function q(t){let n=m(t),r=t.getAttribute(`data-iframely-url`),i=t.hasAttribute(`data-img-created`)||t.hasAttribute(`data-img`),a=!i&&e.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let t={v:e.VERSION,app:1,theme:e.config.theme};!a&&e.config.intersection&&(t.lazy=1),r=v(r,t)}a&&t.setAttribute(`loading`,`lazy`),i&&e.SUPPORT_IFRAME_LOADING_ATTR&&t.setAttribute(`loading`,`edge`),t.setAttribute(`src`,r||``),t.removeAttribute(`data-iframely-url`),e.trigger(`iframe-ready`,t)}function ce(){e.on(`message`,(t,n)=>{n.method===`cancelWidget`&&e.cancelWidget(t)}),e.cancelWidget=t=>{if(!t){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=t.maxWidthWrapper&&t.maxWidthWrapper.parentNode,i=t.maxWidthWrapper;if(e.config&&e.config.parent){let a=n(t.maxWidthWrapper,String(e.config.parent));a&&(r=a.parentNode,i=a)}if(t.url){let n=t.iframe&&t.iframe.textContent;e.triggerAsync(`cancel`,t.url,r,n,i.nextSibling)}r.removeChild(i)}}var le={border:``,"border-radius":``,"box-shadow":``,overflow:``},ue={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function de(){e.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),J(e,n)):t.method===`setIframelyEmbedData`&&J(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),pe(e,r)}})}function J(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,h(e.aspectWrapper,t)):h(e.iframe,t):!t&&e&&e.iframe&&(h(e.aspectWrapper,le),h(e.iframe,ue))}function fe(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function pe(t,n){if(n&&Object.keys(n).length>0&&t){let r=fe(t),i=window.getComputedStyle(t.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),h(t.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&t.iframe&&t.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&h(t.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(t.iframe).getPropertyValue(`height`);i&&i!==s&&e.triggerAsync(`heightChanged`,t.iframe,i,s)}}function me(){e.on(`message`,(t,n)=>{(n.method===`open-href`||n.method===`click`)&&e.trigger(n.method,n.href)}),e.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},e.on(`open-href`,t=>{e.triggerAsync(`click`,t),e.openHref(t)})}function he(){e.on(`message`,(t,n)=>{n.method===`setIframelyEmbedOptions`&&e.trigger(`options`,t,n.data)})}function ge(){e.widgets=e.widgets||{},e.widgets.load=e.load,e.events||(e.events={},e.events.on=e.on,e.events.trigger=e.trigger),e.on(`cancel`,(t,n,r,i)=>{if(e.RECOVER_HREFS_ON_CANCEL&&!r&&(r=t),t&&n&&r&&r!==``){let e=document.createElement(`a`);e.setAttribute(`href`,t),e.setAttribute(`target`,`_blank`),e.setAttribute(`rel`,`noopener`),e.textContent=r,i?n.insertBefore(e,i):n.appendChild(e)}})}var Y=/^_./,X=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function _e(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let n=[],r=Object.keys(e),i=0;if(r.forEach(r=>{let a={},o,s=e[r];s.key=r;let c=!1,l=s.values?Object.keys(s.values):void 0,u,d;if(l&&l.length===1&&(c=!0,u=l[0],d=s.values[u]),a.label=X(d||s.label,t),a.key=s.key,c||typeof s.value==`boolean`)c?a.checked=u===s.value||!u&&!s.value:a.checked=s.value,i++,n.push({type:`checkbox`,context:a,order:+!Y.test(r),getQuery:e=>{let t;t=c?e?u:``:e;let n={};return c?t===``||(n[s.key]=t):n[s.key]=e,n}});else if((typeof s.value==`number`||typeof s.value==`string`)&&!s.values){let e=s.range&&typeof s.range.min==`number`&&typeof s.range.max==`number`,i=typeof s.value==`number`;a.value=s.value,o=e=>{let t={};return e===``||(t[s.key]=e),t},e?(a.min=s.range.min,a.max=s.range.max,n.push({type:`range`,context:a,order:9,getQuery:o})):(a.placeholder=X(s.placeholder||``,t),a.inputType=i?`number`:`text`,n.push({type:`text`,context:a,order:/start/i.test(r)?7:8,getQuery:o}))}else if(s.values)if(a.value=s.value+``,o=e=>{let t={};return e===``||(t[s.key]=e),t},Object.keys(s.values).length<=3){s.label?a.label=X(s.label,t):a.label=!1;let e=0,i=!1,c=Object.values(s.values);for(;e8,e++;a.inline=!i,a.items=[],Object.keys(s.values).forEach((e,n)=>{a.items.push({id:a.key+`-`+n,value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`radio`,context:a,order:i?-3:/theme/.test(r)?-1:-2,getQuery:o})}else a.items=[],Object.keys(s.values).forEach(e=>{a.items.push({value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`select`,context:a,order:5,getQuery:o})}),n.sort((e,t)=>e.order-t.order),n.forEach(e=>{delete e.order}),i>0){let e=[],t;return n.forEach((r,a)=>{if(r.type===`checkbox`){let o=i>2&&a>0&&!Y.test(r.context.key)&&n[a-1].type===`checkbox`&&Y.test(n[a-1].context.key);(!t||o)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return n}var Z={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(t,n)=>{let r=t[0];e.addEventListener(r,`click`,()=>{r.select()}),e.addEventListener(r,`blur`,n),e.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},Q={};function ve(t){let n=t.options,r=t.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,t);return}if(!n){r.innerHTML=``;return}let i=_e(n,t.translator),a=t.id,o=t.renderer,s=Q[a]=Q[a]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(s[e]=n[e].value)});function c(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=Z[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(i),e}function l(){let t=c();Object.keys(s).forEach(e=>{(s[e]===t[e]||t[e]===void 0)&&delete t[e]}),e.trigger(`options-changed`,a,r,t)}let u=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=u(e.context.elements)),t+=o(e.type,e.context||{})}),t};r.innerHTML=u(i);let d=t=>{t.forEach(t=>{if(t.context&&t.context.elements)d(t.context.elements);else{let n=Z[t.type];if(t.context){let i=r.querySelectorAll(`[name="`+t.context.key+`"]`);t.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,l):i.forEach(t=>{e.addEventListener(t,`change`,l)}):console.warn(`No inputs found for option`,t.context.key)}}})};d(i)}var ye={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},$=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>ye[e]),be={checkbox:e=>` +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{},typeof document<`u`&&(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(t.config.autorun===void 0||t.config.autorun!==!1)&&t.trigger(`load`)});function n(){t.VERSION=1,t.ASPECT_WRAPPER_CLASS=`iframely-responsive`,t.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,t.LOADER_CLASS=`iframely-loader`,t.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],t.CDN=t.CDN||t.DOMAINS[0],t.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,t.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,t.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],t.SUPPORTED_THEMES=[`auto`,`light`,`dark`],t.LAZY_IFRAME_SHOW_TIMEOUT=3e3,t.LAZY_IFRAME_FADE_TIMEOUT=200,t.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,t.RECOVER_HREFS_ON_CANCEL=!1,t.SHADOW=`iframely-shadow`,t.SUPPORT_IFRAME_LOADING_ATTR=!0}var r=e=>{window.requestAnimationFrame(e)},i={};function a(e,n,a){(i[e]||[]).forEach(e=>{n?r(()=>{e.apply(t,a)}):e.apply(t,a)}),e===`init`&&(i[e]=[])}function o(){t.on=(e,t)=>{(i[e]=i[e]||[]).push(t)},t.trigger=(e,...t)=>{a(e,!1,t)},t.triggerAsync=(e,...t)=>{a(e,!0,t)}}function s(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function c(e,t){let n;for(let r=0;r{let t=l(document,e);return t||=u(document,e),t},s((e,n)=>{if(n&&(n.method||n.type||n.context)){let r=t.findIframe({contentWindow:e.source,src:n.src||n.context,domains:n.domains!==`all`&&t.DOMAINS.concat(t.CDN)});if(r){let e=h(r);e&&n.url&&(e.url=n.url),t.trigger(`message`,e,n)}}})}function f(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){t.on(`init`,()=>{t.configure(b()),te(),t.config.theme&&t.setTheme(t.config.theme),ne(t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)))}),t.load=function(...e){t.trigger(`load`,...e)},t.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),t.configure=e=>{e&&Object.keys(e).forEach(n=>{let r=e[n]===0||e[n]===`0`||e[n]===!1||e[n]===`false`?!1:e[n]===1||e[n]===`1`||e[n]===!0||e[n]===`true`||e[n];t.config[n]!==!1&&(t.config[n]=r)})}}function p(e,n){let r=e.parentNode;if(!r||r.nodeName!==`DIV`||x(r)>2||n&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||x(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function m(e){let n=e.parentNode,r=document.createElement(`div`);r.className=t.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=t.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,e),{aspectWrapper:i,maxWidthWrapper:r}}function h(e){let t=p(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=C(r);e.url&&(n.url=e.url)}return n}function g(e,n){e&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=e.style,o=a[r];t.getElementComputedStyle(e,r)!=i&&!(e.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function _(e){t.config.nonce&&(e.nonce=t.config.nonce)}function te(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,_(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function v(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function y(e,n,r){let i=e;if(/^(https?:)?\/\//i.test(e)||(i=(n&&n.CDN||t.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=v(i,n)),r&&r.length){let e={},n=Object.keys(t.config);for(let i=0;i0)return e}}return{}}function ne(e){let n=document.querySelectorAll(`iframe[src*="`+(e||t.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{f({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},D(e)),T[t]=n),n}function D(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function re(){t.on(`init`,()=>{t.configure({intersection:1})}),t.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},E(n).observe(e.iframe)}})}function O(e,t){f({method:`setTheme`,data:t},`*`,e.contentWindow)}function k(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{e&&t.SUPPORTED_THEMES.indexOf(e)>-1?n?n.tagName===`IFRAME`?O(n,e):k(n,e):(t.configure({theme:e}),k(document,e),t.trigger(`set-theme`,e)):console.warn(`Using iframely.setTheme with not supported theme: "`+e+`". Supported themes are: `+t.SUPPORTED_THEMES.join(`, `))}}var j={};function ie(){t.on(`load`,e=>{if(!e&&t.config.import!==!1&&se()&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&ae(e)}}),t.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=j[e.uri];if(n)for(let r=0;r{t.trigger(`import-loaded`,e),e.widgets.forEach(n=>{t.trigger(`load`,n,e)}),M()},t.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,t.on(`import-widget-ready`,N),t.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function ae(e){let n=w(),r=[],i=[],a=null;function o(e,t){j[e]||(j[e]=[]),j[e].push(t)}function s(e){let n=e.getAttribute(`data-iframely-url`),s=n.match(t.ID_RE),c=s&&s[1],l=C(n,t.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let e=n.match(t.BASE_RE);l.CDN=e&&e[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?t.trigger(`load`,e):c?(e.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,e)):(u||=e.getAttribute(`href`),(a.key||a.api_key||t.config.api_key||t.config.key)&&u?(e.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,e)):t.trigger(`load`,e))}for(let t=0;t0||i.length>0?(a||={},a.touch=t.isTouch(),a.flash=!1,a.app=1,t.config.theme&&(a.theme=t.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=t.VERSION,n.src=y(`/api/import/v2`,a,t.SUPPORTED_QUERY_STRING),n.onerror=()=>{M()},document.head.appendChild(n),t.import=n):(M(),t.trigger(`load`))}function oe(e,n,r){let i=e.cancel,a=e.shadow,o=e.renderEvent,s=p(n,!0);if(i)t.cancelWidget(h(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=e.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:e.context,stylesIds:e.stylesIds,stylesDict:r.commonShadowStyles};t.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),t.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),P(i);c.removeChild(l),o&&setTimeout(()=>{N(c)},t.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function M(){delete t.import;let e=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function P(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=w();r.type=`text/javascript`;for(let e=0;e{if(e&&e.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),e.appendChild(r),t.trigger(`load`,r)}}),t.on(`load`,e=>{if(!e&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&I(e)})}function I(e){if(!e.getAttribute(`data-iframely-url`)&&!e.getAttribute(`href`))return;let n,r=e.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=y(r,{v:t.VERSION,app:1,theme:t.config.theme});else if((t.config.api_key||t.config.key)&&t.CDN){if(!e.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,e);return}n=y(`/api/iframe`,{url:e.getAttribute(`href`),v:t.VERSION,app:1,theme:t.config.theme},t.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)e.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),e.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,e.getAttribute(`data-img`));let i=e.hasAttribute(`data-lazy`)||e.hasAttribute(`data-img`)||/&lazy=1/.test(n)||t.config.lazy,a=e.textContent;a&&a!==``&&(r.textContent=a);let o=p(e,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=m(e),e.parentNode.removeChild(e);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),t.trigger(`load`,r)):(r.setAttribute(`src`,n),t.trigger(`iframe-ready`,r))}}function L(){t.on(`load`,e=>{if(e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)){let n=e.getAttribute(`data-img`);e.removeAttribute(`data-img`),e.setAttribute(`data-img-created`,``);let r=h(e),i=e.getAttribute(`data-iframely-url`);r&&(R(r,i,n),i=v(i,{img:1}),e.setAttribute(`data-iframely-url`,i),new K(r)),t.trigger(`load`,e)}}),t.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(V(e),n=W(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=W(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=W(e),n?.registerLoadingTimeout())})}function R(e,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let e=C(n),r={};for(let t in e)t.indexOf(`_`)===0&&(r[t]=e[t]);if(e.media&&(r.media=e.media),n.match(/\/api\/iframe/))i=y(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:e.url,api_key:e.api_key,key:e.key},r));else if(n.match(t.ID_RE))i=y(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);g(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,t.LOADER_CLASS),a.appendChild(o);let s=t.getElementComputedStyle(e.aspectWrapper,`padding-top`),c=t.getElementComputedStyle(e.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let t=document.createElement(`div`);g(t,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),t.appendChild(a),e.aspectWrapper.appendChild(t)}else e.aspectWrapper.appendChild(a)}function z(e,t){let n=0;for(let r=0;r1&&z(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var H=[];function U(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),H.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{V(this.widget)},t.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),G(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},t.LAZY_IFRAME_SHOW_TIMEOUT)}};function ce(){t.on(`load`,e=>{if(!e){let e=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&q(e)})}function q(e){let n=h(e),r=e.getAttribute(`data-iframely-url`),i=e.hasAttribute(`data-img-created`)||e.hasAttribute(`data-img`),a=!i&&t.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let e={v:t.VERSION,app:1,theme:t.config.theme};!a&&t.config.intersection&&(e.lazy=1),r=y(r,e)}a&&e.setAttribute(`loading`,`lazy`),i&&t.SUPPORT_IFRAME_LOADING_ATTR&&e.setAttribute(`loading`,`edge`),e.setAttribute(`src`,r||``),e.removeAttribute(`data-iframely-url`),t.trigger(`iframe-ready`,e)}function le(){t.on(`message`,(e,n)=>{n.method===`cancelWidget`&&t.cancelWidget(e)}),t.cancelWidget=e=>{if(!e){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=e.maxWidthWrapper&&e.maxWidthWrapper.parentNode,i=e.maxWidthWrapper;if(t.config&&t.config.parent){let a=n(e.maxWidthWrapper,String(t.config.parent));a&&(r=a.parentNode,i=a)}if(e.url){let n=e.iframe&&e.iframe.textContent;t.triggerAsync(`cancel`,e.url,r,n,i.nextSibling)}r.removeChild(i)}}var ue={border:``,"border-radius":``,"box-shadow":``,overflow:``},de={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function fe(){t.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),J(e,n)):t.method===`setIframelyEmbedData`&&J(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),me(e,r)}})}function J(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,g(e.aspectWrapper,t)):g(e.iframe,t):!t&&e&&e.iframe&&(g(e.aspectWrapper,ue),g(e.iframe,de))}function pe(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function me(e,n){if(n&&Object.keys(n).length>0&&e){let r=pe(e),i=window.getComputedStyle(e.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),g(e.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&e.iframe&&e.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&g(e.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(e.iframe).getPropertyValue(`height`);i&&i!==s&&t.triggerAsync(`heightChanged`,e.iframe,i,s)}}function he(){t.on(`message`,(e,n)=>{(n.method===`open-href`||n.method===`click`)&&t.trigger(n.method,n.href)}),t.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},t.on(`open-href`,e=>{t.triggerAsync(`click`,e),t.openHref(e)})}function ge(){t.on(`message`,(e,n)=>{n.method===`setIframelyEmbedOptions`&&t.trigger(`options`,e,n.data)})}function _e(){t.widgets=t.widgets||{},t.widgets.load=t.load,t.extendOptions=t.configure,t.events||(t.events={},t.events.on=t.on,t.events.trigger=t.trigger),t.on(`cancel`,(e,n,r,i)=>{if(t.RECOVER_HREFS_ON_CANCEL&&!r&&(r=e),e&&n&&r&&r!==``){let t=document.createElement(`a`);t.setAttribute(`href`,e),t.setAttribute(`target`,`_blank`),t.setAttribute(`rel`,`noopener`),t.textContent=r,i?n.insertBefore(t,i):n.appendChild(t)}})}var Y=/^_./,X=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function ve(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let n=[],r=Object.keys(e),i=0;if(r.forEach(r=>{let a={},o,s=e[r];s.key=r;let c=!1,l=s.values?Object.keys(s.values):void 0,u,d;if(l&&l.length===1&&(c=!0,u=l[0],d=s.values[u]),a.label=X(d||s.label,t),a.key=s.key,c||typeof s.value==`boolean`)c?a.checked=u===s.value||!u&&!s.value:a.checked=s.value,i++,n.push({type:`checkbox`,context:a,order:+!Y.test(r),getQuery:e=>{let t;t=c?e?u:``:e;let n={};return c?t===``||(n[s.key]=t):n[s.key]=e,n}});else if((typeof s.value==`number`||typeof s.value==`string`)&&!s.values){let e=s.range&&typeof s.range.min==`number`&&typeof s.range.max==`number`,i=typeof s.value==`number`;a.value=s.value,o=e=>{let t={};return e===``||(t[s.key]=e),t},e?(a.min=s.range.min,a.max=s.range.max,n.push({type:`range`,context:a,order:9,getQuery:o})):(a.placeholder=X(s.placeholder||``,t),a.inputType=i?`number`:`text`,n.push({type:`text`,context:a,order:/start/i.test(r)?7:8,getQuery:o}))}else if(s.values)if(a.value=s.value+``,o=e=>{let t={};return e===``||(t[s.key]=e),t},Object.keys(s.values).length<=3){s.label?a.label=X(s.label,t):a.label=!1;let e=0,i=!1,c=Object.values(s.values);for(;e8,e++;a.inline=!i,a.items=[],Object.keys(s.values).forEach((e,n)=>{a.items.push({id:a.key+`-`+n,value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`radio`,context:a,order:i?-3:/theme/.test(r)?-1:-2,getQuery:o})}else a.items=[],Object.keys(s.values).forEach(e=>{a.items.push({value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`select`,context:a,order:5,getQuery:o})}),n.sort((e,t)=>e.order-t.order),n.forEach(e=>{delete e.order}),i>0){let e=[],t;return n.forEach((r,a)=>{if(r.type===`checkbox`){let o=i>2&&a>0&&!Y.test(r.context.key)&&n[a-1].type===`checkbox`&&Y.test(n[a-1].context.key);(!t||o)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return n}var Z={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(e,n)=>{let r=e[0];t.addEventListener(r,`click`,()=>{r.select()}),t.addEventListener(r,`blur`,n),t.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},Q={};function ye(e){let n=e.options,r=e.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,e);return}if(!n){r.innerHTML=``;return}let i=ve(n,e.translator),a=e.id,o=e.renderer,s=Q[a]=Q[a]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(s[e]=n[e].value)});function c(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=Z[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(i),e}function l(){let e=c();Object.keys(s).forEach(t=>{(s[t]===e[t]||e[t]===void 0)&&delete e[t]}),t.trigger(`options-changed`,a,r,e)}let u=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=u(e.context.elements)),t+=o(e.type,e.context||{})}),t};r.innerHTML=u(i);let d=e=>{e.forEach(e=>{if(e.context&&e.context.elements)d(e.context.elements);else{let n=Z[e.type];if(e.context){let i=r.querySelectorAll(`[name="`+e.context.key+`"]`);e.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,l):i.forEach(e=>{t.addEventListener(e,`change`,l)}):console.warn(`No inputs found for option`,e.context.key)}}})};d(i)}var be={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},$=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>be[e]),xe={checkbox:e=>`
@@ -35,4 +35,4 @@
-
`},xe=(e,t)=>be[e](t);function Se(){e.buildOptionsForm=(e,t,n,r)=>{ve({id:e,formContainer:t,options:n,renderer:xe,translator:r})}}e._loaded||(e._loaded=!0,t(),a(),ee(),u(),re(),k(),ie(),P(),I(),K(),ce(),de(),me(),he(),ge(),Se(),e.trigger(`init`))})(); \ No newline at end of file + `},Se=(e,t)=>xe[e](t);function Ce(){t.buildOptionsForm=(e,t,n,r)=>{ye({id:e,formContainer:t,options:n,renderer:Se,translator:r})}}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),ee(),d(),re(),A(),ie(),F(),L(),ce(),le(),fe(),he(),ge(),_e(),Ce(),t.trigger(`init`))})(); \ No newline at end of file diff --git a/dist/embed.js b/dist/embed.js index 1dde1e1..f445c44 100644 --- a/dist/embed.js +++ b/dist/embed.js @@ -2,7 +2,27 @@ //#region src/iframely.ts - var iframely = window.iframely = window.iframely || {}; + function createServerStub() { + const noop = () => {}; + return { + config: {}, + on: noop, + trigger: noop, + triggerAsync: noop, + load: noop, + configure: noop, + extendOptions: noop, + setTheme: noop, + cancelWidget: noop, + openHref: noop, + addEventListener: noop, + isTouch: () => false, + findIframe: () => void 0, + getElementComputedStyle: () => void 0, + buildOptionsForm: noop + }; + } + var iframely = typeof window === "undefined" ? createServerStub() : window.iframely = window.iframely || {}; iframely.config = iframely.config || {}; //#endregion @@ -11,7 +31,7 @@ if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(f, 0); document.addEventListener("DOMContentLoaded", f); }; - DOMReady(() => { + if (typeof document !== "undefined") DOMReady(() => { if (typeof iframely.config.autorun === "undefined" || iframely.config.autorun !== false) iframely.trigger("load"); }); @@ -183,7 +203,7 @@ //#region src/utils.ts function boot$11() { iframely.on("init", () => { - iframely.extendOptions(parseQueryStringFromScriptSrc()); + iframely.configure(parseQueryStringFromScriptSrc()); defineDefaultStyles(); if (iframely.config.theme) iframely.setTheme(iframely.config.theme); requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, ""))); @@ -194,7 +214,7 @@ iframely.getElementComputedStyle = (el, style) => { return window.getComputedStyle(el).getPropertyValue(style); }; - iframely.extendOptions = (options) => { + iframely.configure = (options) => { if (!options) return; Object.keys(options).forEach((key) => { const new_value = options[key] === 0 || options[key] === "0" || options[key] === false || options[key] === "false" ? false : options[key] === 1 || options[key] === "1" || options[key] === true || options[key] === "true" ? true : options[key]; @@ -390,7 +410,7 @@ } function boot$10() { iframely.on("init", () => { - iframely.extendOptions({ intersection: 1 }); + iframely.configure({ intersection: 1 }); }); iframely.on("message", (widget, message) => { if (message.method === "send-intersections" && widget.iframe) { @@ -418,7 +438,7 @@ if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) if (container) if (container.tagName === "IFRAME") setThemeInIframe(container, theme); else setThemeInAllIframes(container, theme); else { - iframely.extendOptions({ theme }); + iframely.configure({ theme }); setThemeInAllIframes(document, theme); iframely.trigger("set-theme", theme); } @@ -1024,6 +1044,7 @@ function boot() { iframely.widgets = iframely.widgets || {}; iframely.widgets.load = iframely.load; + iframely.extendOptions = iframely.configure; if (!iframely.events) { iframely.events = {}; iframely.events.on = iframely.on; @@ -1045,7 +1066,7 @@ //#endregion //#region src/index.ts - if (!iframely._loaded) { + if (typeof window !== "undefined" && !iframely._loaded) { iframely._loaded = true; boot$14(); boot$13(); diff --git a/dist/embed.min.js b/dist/embed.min.js index c809725..801b741 100644 --- a/dist/embed.min.js +++ b/dist/embed.min.js @@ -1 +1 @@ -(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{},(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(e.config.autorun===void 0||e.config.autorun!==!1)&&e.trigger(`load`)});function t(){e.VERSION=1,e.ASPECT_WRAPPER_CLASS=`iframely-responsive`,e.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,e.LOADER_CLASS=`iframely-loader`,e.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],e.CDN=e.CDN||e.DOMAINS[0],e.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,e.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,e.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,e.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],e.SUPPORTED_THEMES=[`auto`,`light`,`dark`],e.LAZY_IFRAME_SHOW_TIMEOUT=3e3,e.LAZY_IFRAME_FADE_TIMEOUT=200,e.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,e.RECOVER_HREFS_ON_CANCEL=!1,e.SHADOW=`iframely-shadow`,e.SUPPORT_IFRAME_LOADING_ATTR=!0}var n=e=>{window.requestAnimationFrame(e)},r={};function i(t,i,a){(r[t]||[]).forEach(t=>{i?n(()=>{t.apply(e,a)}):t.apply(e,a)}),t===`init`&&(r[t]=[])}function a(){e.on=(e,t)=>{(r[e]=r[e]||[]).push(t)},e.trigger=(e,...t)=>{i(e,!1,t)},e.triggerAsync=(e,...t)=>{i(e,!0,t)}}function o(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function s(e,t){let n;for(let r=0;r{let t=c(document,e);return t||=l(document,e),t},o((t,n)=>{if(n&&(n.method||n.type||n.context)){let r=e.findIframe({contentWindow:t.source,src:n.src||n.context,domains:n.domains!==`all`&&e.DOMAINS.concat(e.CDN)});if(r){let t=m(r);t&&n.url&&(t.url=n.url),e.trigger(`message`,t,n)}}})}function d(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){e.on(`init`,()=>{e.extendOptions(b()),_(),e.config.theme&&e.setTheme(e.config.theme),x(e.DOMAINS.concat(e.CDN.replace(/^https?:\/\//,``)))}),e.load=function(...t){e.trigger(`load`,...t)},e.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),e.extendOptions=t=>{t&&Object.keys(t).forEach(n=>{let r=t[n]===0||t[n]===`0`||t[n]===!1||t[n]===`false`?!1:t[n]===1||t[n]===`1`||t[n]===!0||t[n]===`true`||t[n];e.config[n]!==!1&&(e.config[n]=r)})}}function f(t,n){let r=t.parentNode;if(!r||r.nodeName!==`DIV`||S(r)>2||n&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==e.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||S(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function p(t){let n=t.parentNode,r=document.createElement(`div`);r.className=e.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=e.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,t),{aspectWrapper:i,maxWidthWrapper:r}}function m(e){let t=f(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=w(r);e.url&&(n.url=e.url)}return n}function h(t,n){t&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=t.style,o=a[r];e.getElementComputedStyle(t,r)!=i&&!(t.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function g(t){e.config.nonce&&(t.nonce=e.config.nonce)}function _(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,g(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function v(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function y(t,n,r){let i=t;if(/^(https?:)?\/\//i.test(t)||(i=(n&&n.CDN||e.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=v(i,n)),r&&r.length){let t={},n=Object.keys(e.config);for(let i=0;i0)return t}}return{}}function x(t){let n=document.querySelectorAll(`iframe[src*="`+(t||e.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{d({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},O(e)),E[t]=n),n}function O(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function k(){e.on(`init`,()=>{e.extendOptions({intersection:1})}),e.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},D(n).observe(e.iframe)}})}function A(e,t){d({method:`setTheme`,data:t},`*`,e.contentWindow)}function j(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{t&&e.SUPPORTED_THEMES.indexOf(t)>-1?n?n.tagName===`IFRAME`?A(n,t):j(n,t):(e.extendOptions({theme:t}),j(document,t),e.trigger(`set-theme`,t)):console.warn(`Using iframely.setTheme with not supported theme: "`+t+`". Supported themes are: `+e.SUPPORTED_THEMES.join(`, `))}}var M={};function N(){e.on(`load`,t=>{if(!t&&e.config.import!==!1&&L()&&!e.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&P(e)}}),e.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=M[e.uri];if(n)for(let r=0;r{e.trigger(`import-loaded`,t),t.widgets.forEach(n=>{e.trigger(`load`,n,t)}),I()},e.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,e.on(`import-widget-ready`,R),e.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function P(t){let n=T(),r=[],i=[],a=null;function o(e,t){M[e]||(M[e]=[]),M[e].push(t)}function s(t){let n=t.getAttribute(`data-iframely-url`),s=n.match(e.ID_RE),c=s&&s[1],l=w(n,e.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let t=n.match(e.BASE_RE);l.CDN=t&&t[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?e.trigger(`load`,t):c?(t.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,t)):(u||=t.getAttribute(`href`),(a.key||a.api_key||e.config.api_key||e.config.key)&&u?(t.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,t)):e.trigger(`load`,t))}for(let e=0;e0||i.length>0?(a||={},a.touch=e.isTouch(),a.flash=!1,a.app=1,e.config.theme&&(a.theme=e.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=e.VERSION,n.src=y(`/api/import/v2`,a,e.SUPPORTED_QUERY_STRING),n.onerror=()=>{I()},document.head.appendChild(n),e.import=n):(I(),e.trigger(`load`))}function F(t,n,r){let i=t.cancel,a=t.shadow,o=t.renderEvent,s=f(n,!0);if(i)e.cancelWidget(m(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=t.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:t.context,stylesIds:t.stylesIds,stylesDict:r.commonShadowStyles};e.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),e.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),z(i);c.removeChild(l),o&&setTimeout(()=>{R(c)},e.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function I(){delete e.import;let t=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(e.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function z(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=T();r.type=`text/javascript`;for(let e=0;e{if(t&&t.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),t.appendChild(r),e.trigger(`load`,r)}}),e.on(`load`,t=>{if(!t&&!e.import){let t=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&V(e)})}function V(t){if(!t.getAttribute(`data-iframely-url`)&&!t.getAttribute(`href`))return;let n,r=t.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=y(r,{v:e.VERSION,app:1,theme:e.config.theme});else if((e.config.api_key||e.config.key)&&e.CDN){if(!t.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,t);return}n=y(`/api/iframe`,{url:t.getAttribute(`href`),v:e.VERSION,app:1,theme:e.config.theme},e.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)t.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),t.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,t.getAttribute(`data-img`));let i=t.hasAttribute(`data-lazy`)||t.hasAttribute(`data-img`)||/&lazy=1/.test(n)||e.config.lazy,a=t.textContent;a&&a!==``&&(r.textContent=a);let o=f(t,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=p(t),t.parentNode.removeChild(t);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),e.trigger(`load`,r)):(r.setAttribute(`src`,n),e.trigger(`iframe-ready`,r))}}function H(){e.on(`load`,t=>{if(t&&t.nodeName===`IFRAME`&&t.hasAttribute(`data-iframely-url`)&&t.hasAttribute(`data-img`)&&!t.getAttribute(`src`)){let n=t.getAttribute(`data-img`);t.removeAttribute(`data-img`),t.setAttribute(`data-img-created`,``);let r=m(t),i=t.getAttribute(`data-iframely-url`);r&&(U(r,i,n),i=v(i,{img:1}),t.setAttribute(`data-iframely-url`,i),new Z(r)),e.trigger(`load`,t)}}),e.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(K(e),n=Y(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=Y(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=Y(e),n?.registerLoadingTimeout())})}function U(t,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let t=w(n),r={};for(let e in t)e.indexOf(`_`)===0&&(r[e]=t[e]);if(t.media&&(r.media=t.media),n.match(/\/api\/iframe/))i=y(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:t.url,api_key:t.api_key,key:t.key},r));else if(n.match(e.ID_RE))i=y(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);h(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,e.LOADER_CLASS),a.appendChild(o);let s=e.getElementComputedStyle(t.aspectWrapper,`padding-top`),c=e.getElementComputedStyle(t.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let e=document.createElement(`div`);h(e,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),e.appendChild(a),t.aspectWrapper.appendChild(e)}else t.aspectWrapper.appendChild(a)}function W(e,t){let n=0;for(let r=0;r1&&W(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var q=[];function J(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),q.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{K(this.widget)},e.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),X(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},e.LAZY_IFRAME_SHOW_TIMEOUT)}};function ne(){e.on(`load`,t=>{if(!t){let t=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&re(e)})}function re(t){let n=m(t),r=t.getAttribute(`data-iframely-url`),i=t.hasAttribute(`data-img-created`)||t.hasAttribute(`data-img`),a=!i&&e.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let t={v:e.VERSION,app:1,theme:e.config.theme};!a&&e.config.intersection&&(t.lazy=1),r=y(r,t)}a&&t.setAttribute(`loading`,`lazy`),i&&e.SUPPORT_IFRAME_LOADING_ATTR&&t.setAttribute(`loading`,`edge`),t.setAttribute(`src`,r||``),t.removeAttribute(`data-iframely-url`),e.trigger(`iframe-ready`,t)}function ie(){e.on(`message`,(t,n)=>{n.method===`cancelWidget`&&e.cancelWidget(t)}),e.cancelWidget=t=>{if(!t){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=t.maxWidthWrapper&&t.maxWidthWrapper.parentNode,i=t.maxWidthWrapper;if(e.config&&e.config.parent){let a=n(t.maxWidthWrapper,String(e.config.parent));a&&(r=a.parentNode,i=a)}if(t.url){let n=t.iframe&&t.iframe.textContent;e.triggerAsync(`cancel`,t.url,r,n,i.nextSibling)}r.removeChild(i)}}var ae={border:``,"border-radius":``,"box-shadow":``,overflow:``},oe={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function se(){e.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),Q(e,n)):t.method===`setIframelyEmbedData`&&Q(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),le(e,r)}})}function Q(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,h(e.aspectWrapper,t)):h(e.iframe,t):!t&&e&&e.iframe&&(h(e.aspectWrapper,ae),h(e.iframe,oe))}function ce(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function le(t,n){if(n&&Object.keys(n).length>0&&t){let r=ce(t),i=window.getComputedStyle(t.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),h(t.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&t.iframe&&t.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&h(t.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(t.iframe).getPropertyValue(`height`);i&&i!==s&&e.triggerAsync(`heightChanged`,t.iframe,i,s)}}function $(){e.on(`message`,(t,n)=>{(n.method===`open-href`||n.method===`click`)&&e.trigger(n.method,n.href)}),e.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},e.on(`open-href`,t=>{e.triggerAsync(`click`,t),e.openHref(t)})}function ue(){e.on(`message`,(t,n)=>{n.method===`setIframelyEmbedOptions`&&e.trigger(`options`,t,n.data)})}function de(){e.widgets=e.widgets||{},e.widgets.load=e.load,e.events||(e.events={},e.events.on=e.on,e.events.trigger=e.trigger),e.on(`cancel`,(t,n,r,i)=>{if(e.RECOVER_HREFS_ON_CANCEL&&!r&&(r=t),t&&n&&r&&r!==``){let e=document.createElement(`a`);e.setAttribute(`href`,t),e.setAttribute(`target`,`_blank`),e.setAttribute(`rel`,`noopener`),e.textContent=r,i?n.insertBefore(e,i):n.appendChild(e)}})}e._loaded||(e._loaded=!0,t(),a(),ee(),u(),k(),te(),N(),B(),H(),ne(),ie(),se(),$(),ue(),de(),e.trigger(`init`))})(); \ No newline at end of file +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{},typeof document<`u`&&(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(t.config.autorun===void 0||t.config.autorun!==!1)&&t.trigger(`load`)});function n(){t.VERSION=1,t.ASPECT_WRAPPER_CLASS=`iframely-responsive`,t.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,t.LOADER_CLASS=`iframely-loader`,t.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],t.CDN=t.CDN||t.DOMAINS[0],t.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,t.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,t.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],t.SUPPORTED_THEMES=[`auto`,`light`,`dark`],t.LAZY_IFRAME_SHOW_TIMEOUT=3e3,t.LAZY_IFRAME_FADE_TIMEOUT=200,t.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,t.RECOVER_HREFS_ON_CANCEL=!1,t.SHADOW=`iframely-shadow`,t.SUPPORT_IFRAME_LOADING_ATTR=!0}var r=e=>{window.requestAnimationFrame(e)},i={};function a(e,n,a){(i[e]||[]).forEach(e=>{n?r(()=>{e.apply(t,a)}):e.apply(t,a)}),e===`init`&&(i[e]=[])}function o(){t.on=(e,t)=>{(i[e]=i[e]||[]).push(t)},t.trigger=(e,...t)=>{a(e,!1,t)},t.triggerAsync=(e,...t)=>{a(e,!0,t)}}function s(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function c(e,t){let n;for(let r=0;r{let t=l(document,e);return t||=u(document,e),t},s((e,n)=>{if(n&&(n.method||n.type||n.context)){let r=t.findIframe({contentWindow:e.source,src:n.src||n.context,domains:n.domains!==`all`&&t.DOMAINS.concat(t.CDN)});if(r){let e=h(r);e&&n.url&&(e.url=n.url),t.trigger(`message`,e,n)}}})}function f(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){t.on(`init`,()=>{t.configure(x()),v(),t.config.theme&&t.setTheme(t.config.theme),S(t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)))}),t.load=function(...e){t.trigger(`load`,...e)},t.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),t.configure=e=>{e&&Object.keys(e).forEach(n=>{let r=e[n]===0||e[n]===`0`||e[n]===!1||e[n]===`false`?!1:e[n]===1||e[n]===`1`||e[n]===!0||e[n]===`true`||e[n];t.config[n]!==!1&&(t.config[n]=r)})}}function p(e,n){let r=e.parentNode;if(!r||r.nodeName!==`DIV`||C(r)>2||n&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||C(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function m(e){let n=e.parentNode,r=document.createElement(`div`);r.className=t.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=t.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,e),{aspectWrapper:i,maxWidthWrapper:r}}function h(e){let t=p(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=T(r);e.url&&(n.url=e.url)}return n}function g(e,n){e&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=e.style,o=a[r];t.getElementComputedStyle(e,r)!=i&&!(e.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function _(e){t.config.nonce&&(e.nonce=t.config.nonce)}function v(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,_(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function y(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function b(e,n,r){let i=e;if(/^(https?:)?\/\//i.test(e)||(i=(n&&n.CDN||t.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=y(i,n)),r&&r.length){let e={},n=Object.keys(t.config);for(let i=0;i0)return e}}return{}}function S(e){let n=document.querySelectorAll(`iframe[src*="`+(e||t.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{f({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},k(e)),D[t]=n),n}function k(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function A(){t.on(`init`,()=>{t.configure({intersection:1})}),t.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},O(n).observe(e.iframe)}})}function j(e,t){f({method:`setTheme`,data:t},`*`,e.contentWindow)}function M(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{e&&t.SUPPORTED_THEMES.indexOf(e)>-1?n?n.tagName===`IFRAME`?j(n,e):M(n,e):(t.configure({theme:e}),M(document,e),t.trigger(`set-theme`,e)):console.warn(`Using iframely.setTheme with not supported theme: "`+e+`". Supported themes are: `+t.SUPPORTED_THEMES.join(`, `))}}var N={};function P(){t.on(`load`,e=>{if(!e&&t.config.import!==!1&&R()&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&F(e)}}),t.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=N[e.uri];if(n)for(let r=0;r{t.trigger(`import-loaded`,e),e.widgets.forEach(n=>{t.trigger(`load`,n,e)}),L()},t.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,t.on(`import-widget-ready`,z),t.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function F(e){let n=E(),r=[],i=[],a=null;function o(e,t){N[e]||(N[e]=[]),N[e].push(t)}function s(e){let n=e.getAttribute(`data-iframely-url`),s=n.match(t.ID_RE),c=s&&s[1],l=T(n,t.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let e=n.match(t.BASE_RE);l.CDN=e&&e[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?t.trigger(`load`,e):c?(e.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,e)):(u||=e.getAttribute(`href`),(a.key||a.api_key||t.config.api_key||t.config.key)&&u?(e.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,e)):t.trigger(`load`,e))}for(let t=0;t0||i.length>0?(a||={},a.touch=t.isTouch(),a.flash=!1,a.app=1,t.config.theme&&(a.theme=t.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=t.VERSION,n.src=b(`/api/import/v2`,a,t.SUPPORTED_QUERY_STRING),n.onerror=()=>{L()},document.head.appendChild(n),t.import=n):(L(),t.trigger(`load`))}function I(e,n,r){let i=e.cancel,a=e.shadow,o=e.renderEvent,s=p(n,!0);if(i)t.cancelWidget(h(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=e.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:e.context,stylesIds:e.stylesIds,stylesDict:r.commonShadowStyles};t.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),t.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),B(i);c.removeChild(l),o&&setTimeout(()=>{z(c)},t.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function L(){delete t.import;let e=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function B(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=E();r.type=`text/javascript`;for(let e=0;e{if(e&&e.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),e.appendChild(r),t.trigger(`load`,r)}}),t.on(`load`,e=>{if(!e&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&H(e)})}function H(e){if(!e.getAttribute(`data-iframely-url`)&&!e.getAttribute(`href`))return;let n,r=e.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=b(r,{v:t.VERSION,app:1,theme:t.config.theme});else if((t.config.api_key||t.config.key)&&t.CDN){if(!e.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,e);return}n=b(`/api/iframe`,{url:e.getAttribute(`href`),v:t.VERSION,app:1,theme:t.config.theme},t.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)e.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),e.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,e.getAttribute(`data-img`));let i=e.hasAttribute(`data-lazy`)||e.hasAttribute(`data-img`)||/&lazy=1/.test(n)||t.config.lazy,a=e.textContent;a&&a!==``&&(r.textContent=a);let o=p(e,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=m(e),e.parentNode.removeChild(e);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),t.trigger(`load`,r)):(r.setAttribute(`src`,n),t.trigger(`iframe-ready`,r))}}function U(){t.on(`load`,e=>{if(e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)){let n=e.getAttribute(`data-img`);e.removeAttribute(`data-img`),e.setAttribute(`data-img-created`,``);let r=h(e),i=e.getAttribute(`data-iframely-url`);r&&(W(r,i,n),i=y(i,{img:1}),e.setAttribute(`data-iframely-url`,i),new ne(r)),t.trigger(`load`,e)}}),t.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(q(e),n=X(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=X(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=X(e),n?.registerLoadingTimeout())})}function W(e,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let e=T(n),r={};for(let t in e)t.indexOf(`_`)===0&&(r[t]=e[t]);if(e.media&&(r.media=e.media),n.match(/\/api\/iframe/))i=b(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:e.url,api_key:e.api_key,key:e.key},r));else if(n.match(t.ID_RE))i=b(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);g(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,t.LOADER_CLASS),a.appendChild(o);let s=t.getElementComputedStyle(e.aspectWrapper,`padding-top`),c=t.getElementComputedStyle(e.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let t=document.createElement(`div`);g(t,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),t.appendChild(a),e.aspectWrapper.appendChild(t)}else e.aspectWrapper.appendChild(a)}function G(e,t){let n=0;for(let r=0;r1&&G(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var J=[];function Y(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),J.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{q(this.widget)},t.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),Z(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},t.LAZY_IFRAME_SHOW_TIMEOUT)}};function re(){t.on(`load`,e=>{if(!e){let e=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&ie(e)})}function ie(e){let n=h(e),r=e.getAttribute(`data-iframely-url`),i=e.hasAttribute(`data-img-created`)||e.hasAttribute(`data-img`),a=!i&&t.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let e={v:t.VERSION,app:1,theme:t.config.theme};!a&&t.config.intersection&&(e.lazy=1),r=b(r,e)}a&&e.setAttribute(`loading`,`lazy`),i&&t.SUPPORT_IFRAME_LOADING_ATTR&&e.setAttribute(`loading`,`edge`),e.setAttribute(`src`,r||``),e.removeAttribute(`data-iframely-url`),t.trigger(`iframe-ready`,e)}function ae(){t.on(`message`,(e,n)=>{n.method===`cancelWidget`&&t.cancelWidget(e)}),t.cancelWidget=e=>{if(!e){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=e.maxWidthWrapper&&e.maxWidthWrapper.parentNode,i=e.maxWidthWrapper;if(t.config&&t.config.parent){let a=n(e.maxWidthWrapper,String(t.config.parent));a&&(r=a.parentNode,i=a)}if(e.url){let n=e.iframe&&e.iframe.textContent;t.triggerAsync(`cancel`,e.url,r,n,i.nextSibling)}r.removeChild(i)}}var oe={border:``,"border-radius":``,"box-shadow":``,overflow:``},Q={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function se(){t.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),$(e,n)):t.method===`setIframelyEmbedData`&&$(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),le(e,r)}})}function $(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,g(e.aspectWrapper,t)):g(e.iframe,t):!t&&e&&e.iframe&&(g(e.aspectWrapper,oe),g(e.iframe,Q))}function ce(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function le(e,n){if(n&&Object.keys(n).length>0&&e){let r=ce(e),i=window.getComputedStyle(e.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),g(e.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&e.iframe&&e.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&g(e.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(e.iframe).getPropertyValue(`height`);i&&i!==s&&t.triggerAsync(`heightChanged`,e.iframe,i,s)}}function ue(){t.on(`message`,(e,n)=>{(n.method===`open-href`||n.method===`click`)&&t.trigger(n.method,n.href)}),t.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},t.on(`open-href`,e=>{t.triggerAsync(`click`,e),t.openHref(e)})}function de(){t.on(`message`,(e,n)=>{n.method===`setIframelyEmbedOptions`&&t.trigger(`options`,e,n.data)})}function fe(){t.widgets=t.widgets||{},t.widgets.load=t.load,t.extendOptions=t.configure,t.events||(t.events={},t.events.on=t.on,t.events.trigger=t.trigger),t.on(`cancel`,(e,n,r,i)=>{if(t.RECOVER_HREFS_ON_CANCEL&&!r&&(r=e),e&&n&&r&&r!==``){let t=document.createElement(`a`);t.setAttribute(`href`,e),t.setAttribute(`target`,`_blank`),t.setAttribute(`rel`,`noopener`),t.textContent=r,i?n.insertBefore(t,i):n.appendChild(t)}})}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),ee(),d(),A(),te(),P(),V(),U(),re(),ae(),se(),ue(),de(),fe(),t.trigger(`init`))})(); \ No newline at end of file diff --git a/dist/esm/chunks/deprecated.js b/dist/esm/chunks/deprecated.js index b74491e..3d5fb74 100644 --- a/dist/esm/chunks/deprecated.js +++ b/dist/esm/chunks/deprecated.js @@ -4,7 +4,7 @@ var DOMReady = (f) => { if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(f, 0); document.addEventListener("DOMContentLoaded", f); }; -DOMReady(() => { +if (typeof document !== "undefined") DOMReady(() => { if (typeof iframely.config.autorun === "undefined" || iframely.config.autorun !== false) iframely.trigger("load"); }); //#endregion @@ -172,7 +172,7 @@ function postMessage(message, target_url, target) { //#region src/utils.ts function boot$11() { iframely.on("init", () => { - iframely.extendOptions(parseQueryStringFromScriptSrc()); + iframely.configure(parseQueryStringFromScriptSrc()); defineDefaultStyles(); if (iframely.config.theme) iframely.setTheme(iframely.config.theme); requestSizeOfExistingIframes(iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, ""))); @@ -183,7 +183,7 @@ function boot$11() { iframely.getElementComputedStyle = (el, style) => { return window.getComputedStyle(el).getPropertyValue(style); }; - iframely.extendOptions = (options) => { + iframely.configure = (options) => { if (!options) return; Object.keys(options).forEach((key) => { const new_value = options[key] === 0 || options[key] === "0" || options[key] === false || options[key] === "false" ? false : options[key] === 1 || options[key] === "1" || options[key] === true || options[key] === "true" ? true : options[key]; @@ -378,7 +378,7 @@ function getObserverOptions(options) { } function boot$10() { iframely.on("init", () => { - iframely.extendOptions({ intersection: 1 }); + iframely.configure({ intersection: 1 }); }); iframely.on("message", (widget, message) => { if (message.method === "send-intersections" && widget.iframe) { @@ -405,7 +405,7 @@ function boot$9() { if (theme && iframely.SUPPORTED_THEMES.indexOf(theme) > -1) if (container) if (container.tagName === "IFRAME") setThemeInIframe(container, theme); else setThemeInAllIframes(container, theme); else { - iframely.extendOptions({ theme }); + iframely.configure({ theme }); setThemeInAllIframes(document, theme); iframely.trigger("set-theme", theme); } @@ -1002,6 +1002,7 @@ function boot$1() { function boot() { iframely.widgets = iframely.widgets || {}; iframely.widgets.load = iframely.load; + iframely.extendOptions = iframely.configure; if (!iframely.events) { iframely.events = {}; iframely.events.on = iframely.on; diff --git a/dist/esm/chunks/iframely.js b/dist/esm/chunks/iframely.js index 503ee66..d9a15ee 100644 --- a/dist/esm/chunks/iframely.js +++ b/dist/esm/chunks/iframely.js @@ -1,5 +1,25 @@ //#region src/iframely.ts -var iframely = window.iframely = window.iframely || {}; +function createServerStub() { + const noop = () => {}; + return { + config: {}, + on: noop, + trigger: noop, + triggerAsync: noop, + load: noop, + configure: noop, + extendOptions: noop, + setTheme: noop, + cancelWidget: noop, + openHref: noop, + addEventListener: noop, + isTouch: () => false, + findIframe: () => void 0, + getElementComputedStyle: () => void 0, + buildOptionsForm: noop + }; +} +var iframely = typeof window === "undefined" ? createServerStub() : window.iframely = window.iframely || {}; iframely.config = iframely.config || {}; //#endregion export { iframely as t }; diff --git a/dist/esm/main-options.js b/dist/esm/main-options.js index ed6e808..e30cf94 100644 --- a/dist/esm/main-options.js +++ b/dist/esm/main-options.js @@ -324,7 +324,7 @@ function boot() { } //#endregion //#region src/index-options.ts -if (!iframely._loaded) { +if (typeof window !== "undefined" && !iframely._loaded) { iframely._loaded = true; boot$1(); boot$2(); @@ -345,4 +345,7 @@ if (!iframely._loaded) { iframely.trigger("init"); } //#endregion +//#region src/main-options.ts +if (typeof window !== "undefined") iframely.config.autorun = iframely.config.autorun ?? false; +//#endregion export { iframely }; diff --git a/dist/esm/main.js b/dist/esm/main.js index aa91eb0..6ff1e9f 100644 --- a/dist/esm/main.js +++ b/dist/esm/main.js @@ -1,7 +1,7 @@ import { t as iframely } from "./chunks/iframely.js"; import { a as boot$10, c as boot$7, d as boot$4, f as boot$2, h as boot, i as boot$11, l as boot$6, m as boot$1, n as boot$13, o as boot$9, p as boot$3, r as boot$12, s as boot$8, t as boot$14, u as boot$5 } from "./chunks/deprecated.js"; //#region src/index.ts -if (!iframely._loaded) { +if (typeof window !== "undefined" && !iframely._loaded) { iframely._loaded = true; boot(); boot$1(); @@ -21,4 +21,7 @@ if (!iframely._loaded) { iframely.trigger("init"); } //#endregion +//#region src/main.ts +if (typeof window !== "undefined") iframely.config.autorun = iframely.config.autorun ?? false; +//#endregion export { iframely }; diff --git a/dist/options.i18n.de.js b/dist/options.i18n.de.js index 53d700e..e05343b 100644 --- a/dist/options.i18n.de.js +++ b/dist/options.i18n.de.js @@ -2,7 +2,27 @@ //#region src/iframely.ts - var iframely = window.iframely = window.iframely || {}; + function createServerStub() { + const noop = () => {}; + return { + config: {}, + on: noop, + trigger: noop, + triggerAsync: noop, + load: noop, + configure: noop, + extendOptions: noop, + setTheme: noop, + cancelWidget: noop, + openHref: noop, + addEventListener: noop, + isTouch: () => false, + findIframe: () => void 0, + getElementComputedStyle: () => void 0, + buildOptionsForm: noop + }; + } + var iframely = typeof window === "undefined" ? createServerStub() : window.iframely = window.iframely || {}; iframely.config = iframely.config || {}; //#endregion diff --git a/dist/options.i18n.de.min.js b/dist/options.i18n.de.min.js index a2abb68..05f073b 100644 --- a/dist/options.i18n.de.min.js +++ b/dist/options.i18n.de.min.js @@ -1 +1 @@ -(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{};var t={};function n(e,n){let r=t[e]=t[e]||{};Object.assign(r,n)}e.optionsTranslator=e=>n=>t[e]&&t[e][n]&&t[e][n]!==``?t[e][n]:n,n(`de`,{"Slimmer horizontal player":`Schlanker horizontaler Player`,"Include playlist":`Wiedergabeliste anzeigen`,"Hide artwork":`Artwork ausblenden`,"Theme color":`Theme Farbe`,Light:`Hell`,Dark:`Dunkel`,Auto:`Automatisch`,Default:`Standard`,"Adjust height":`Höhe einstellen`,"Active page":`Aktive Seite`,"Use click-to-load":`Verwende click-to-load`,"ex.: 600, in px":`Z.B. 600, in px`,"Hide timed comments":`Kommentare ausblenden`,"Let Iframely optimize player for the artwork":`Optimierung des Players durch IFramely`,"Show as slideshow":`Als Slideshow zeigen`,"Start from":`Start ab`,"ex.: 11, 1m10s":`z.B. 11, 1m10s`,"End on":`Ende an`,"Closed captions":`Untertitel`,"Include up to 20 tweets":`Bis zu 20 Tweets anzeigen`,"Hide photos, videos, and cards":`Verberge Fotos, Videos und Cards`,"Hide previous Tweet in conversation thread":`Verberge den vorigen Tweet in der Konversation`,"Use dark theme":`Verwende dunkles Farbschema`,"Adjust width":`Breite anpassen`,"Hide description":`Beschreibung verbergen`,"Widget style":`Widget-Style`,Mini:`Mini`,Classic:`Klassisch`,Picture:`Bild`,Zoom:`Zoom`,"Map orientation":`Karten-Ausrichtung`,Album:`Album`,Portrait:`Portrait`,Square:`Quadratisch`,"Show context slideshow":`Als Slideshow anzeigen`,"Show description footer":`Fußzeile anzeigen`,"Show user header":`Kopfbereich anzeigen`,"Show author's text caption":`Beschriftung des Autors anzeigen`,"Hide author's text caption":`Beschriftung des Autors verbergen`,"Include parent comment (if url is a reply)":`Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)`,"Show recent posts":`Neueste Beiträge anzeigen`,"Show profile photos when friends like this":`Profilfotos anzeigen, wenn Freunde dies mögen`,"Use the small header instead":`Kleine Kopfzeile stattdessen verwenden`,Artwork:`Artwork`,Small:`klein`,Big:`groß`,None:`Keines`,Layout:`Layout`,Slim:`Schlank`,"Artwork-only":`Nur Artwork`,Standard:`Standard`,"Size & style":`Größe & Stil`,"Wide image":`Breite Darstellung`,"Wide simple":`Breite Darstellung (Einfach)`,"Text language (ignored if no captions)":`Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)`,"Two letters: en, fr, es, de...":`Zwei Buchstaben: en, fr, es, de...`,"Don't include attached player":`Player nicht integrieren`,"Attached player only, no card":`Nur Player, keine Card`,"Hold load & play until clicked":`Klicken zum Abspielen`,"Make it a small card":`Kleine Card verwenden`,"Keep using full media card":`Verwende weiterhin vollständige Media-Cards`,"Don't include player":`Player nicht hinzufügen`,"Player only, no card":`Nur Player, keine Card`,"Just the player":`Nur Player`,"Just the image":`Nur Bild`})})(); \ No newline at end of file +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n={};function r(e,t){let r=n[e]=n[e]||{};Object.assign(r,t)}t.optionsTranslator=e=>t=>n[e]&&n[e][t]&&n[e][t]!==``?n[e][t]:t,r(`de`,{"Slimmer horizontal player":`Schlanker horizontaler Player`,"Include playlist":`Wiedergabeliste anzeigen`,"Hide artwork":`Artwork ausblenden`,"Theme color":`Theme Farbe`,Light:`Hell`,Dark:`Dunkel`,Auto:`Automatisch`,Default:`Standard`,"Adjust height":`Höhe einstellen`,"Active page":`Aktive Seite`,"Use click-to-load":`Verwende click-to-load`,"ex.: 600, in px":`Z.B. 600, in px`,"Hide timed comments":`Kommentare ausblenden`,"Let Iframely optimize player for the artwork":`Optimierung des Players durch IFramely`,"Show as slideshow":`Als Slideshow zeigen`,"Start from":`Start ab`,"ex.: 11, 1m10s":`z.B. 11, 1m10s`,"End on":`Ende an`,"Closed captions":`Untertitel`,"Include up to 20 tweets":`Bis zu 20 Tweets anzeigen`,"Hide photos, videos, and cards":`Verberge Fotos, Videos und Cards`,"Hide previous Tweet in conversation thread":`Verberge den vorigen Tweet in der Konversation`,"Use dark theme":`Verwende dunkles Farbschema`,"Adjust width":`Breite anpassen`,"Hide description":`Beschreibung verbergen`,"Widget style":`Widget-Style`,Mini:`Mini`,Classic:`Klassisch`,Picture:`Bild`,Zoom:`Zoom`,"Map orientation":`Karten-Ausrichtung`,Album:`Album`,Portrait:`Portrait`,Square:`Quadratisch`,"Show context slideshow":`Als Slideshow anzeigen`,"Show description footer":`Fußzeile anzeigen`,"Show user header":`Kopfbereich anzeigen`,"Show author's text caption":`Beschriftung des Autors anzeigen`,"Hide author's text caption":`Beschriftung des Autors verbergen`,"Include parent comment (if url is a reply)":`Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)`,"Show recent posts":`Neueste Beiträge anzeigen`,"Show profile photos when friends like this":`Profilfotos anzeigen, wenn Freunde dies mögen`,"Use the small header instead":`Kleine Kopfzeile stattdessen verwenden`,Artwork:`Artwork`,Small:`klein`,Big:`groß`,None:`Keines`,Layout:`Layout`,Slim:`Schlank`,"Artwork-only":`Nur Artwork`,Standard:`Standard`,"Size & style":`Größe & Stil`,"Wide image":`Breite Darstellung`,"Wide simple":`Breite Darstellung (Einfach)`,"Text language (ignored if no captions)":`Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)`,"Two letters: en, fr, es, de...":`Zwei Buchstaben: en, fr, es, de...`,"Don't include attached player":`Player nicht integrieren`,"Attached player only, no card":`Nur Player, keine Card`,"Hold load & play until clicked":`Klicken zum Abspielen`,"Make it a small card":`Kleine Card verwenden`,"Keep using full media card":`Verwende weiterhin vollständige Media-Cards`,"Don't include player":`Player nicht hinzufügen`,"Player only, no card":`Nur Player, keine Card`,"Just the player":`Nur Player`,"Just the image":`Nur Bild`})})(); \ No newline at end of file diff --git a/dist/options.i18n.fr.js b/dist/options.i18n.fr.js index b62d1c8..0b02a2a 100644 --- a/dist/options.i18n.fr.js +++ b/dist/options.i18n.fr.js @@ -2,7 +2,27 @@ //#region src/iframely.ts - var iframely = window.iframely = window.iframely || {}; + function createServerStub() { + const noop = () => {}; + return { + config: {}, + on: noop, + trigger: noop, + triggerAsync: noop, + load: noop, + configure: noop, + extendOptions: noop, + setTheme: noop, + cancelWidget: noop, + openHref: noop, + addEventListener: noop, + isTouch: () => false, + findIframe: () => void 0, + getElementComputedStyle: () => void 0, + buildOptionsForm: noop + }; + } + var iframely = typeof window === "undefined" ? createServerStub() : window.iframely = window.iframely || {}; iframely.config = iframely.config || {}; //#endregion diff --git a/dist/options.i18n.fr.min.js b/dist/options.i18n.fr.min.js index 0215dd3..4f69d88 100644 --- a/dist/options.i18n.fr.min.js +++ b/dist/options.i18n.fr.min.js @@ -1 +1 @@ -(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{};var t={};function n(e,n){let r=t[e]=t[e]||{};Object.assign(r,n)}e.optionsTranslator=e=>n=>t[e]&&t[e][n]&&t[e][n]!==``?t[e][n]:n,n(`fr`,{"Slimmer horizontal player":`Joueur de audio classique`,"Include playlist":`Inclure la playlist`,"Hide artwork":`Masquer la illustration`,"Theme color":`Couleur du thème`,Light:`Lumière`,Dark:`Sombre`,Auto:``,Default:`Défaut`,"Adjust height":`Height`,"Active page":`Page active`,"Use click-to-load":`Utilisez click-to-load`,"ex.: 600, in px":``,"Hide timed comments":`Masquer les commentaires`,"Let Iframely optimize player for the artwork":`Optimiser le lecteur pour l'illustration`,"Show as slideshow":`Montrer en diaporama`,"Start from":`Commencer`,"ex.: 11, 1m10s":``,"End on":`Fin sur`,"Include up to 20 tweets":`Incluez jusqu'à 20 tweets`,"Hide photos, videos, and cards":`Masquer les photos, les vidéos et les cartes`,"Hide previous Tweet in conversation thread":`Masquer le tweet parent`,"Hide description":`Masquer la description`,"Widget style":`Style de widget`,Mini:``,Classic:`Classique`,Picture:`Image`,Zoom:``,"Map orientation":`Orientation de la carte`,Album:``,Portrait:``,Square:`Carré`,"Show context slideshow":`Afficher le diaporama contextuel`,"Show description footer":`Afficher la description pied de page`,"Show user header":`Afficher l'en-tête de l'utilisateur`,"Show author's text caption":`Afficher la description de l'auteur`,"Hide author's text caption":`Masquer la description de l'auteur`,"Include parent comment (if url is a reply)":``,"Show recent posts":`Afficher les messages récents`,"Show profile photos when friends like this":``,"Use the small header instead":`Utilisez plutôt le petit en-tête`,Artwork:`Ouvrages d'art`,Small:`Petite`,Big:`Grosse`,None:`Aucune`,Layout:`Disposition`,Slim:`Svelte`,"Artwork-only":`Oeuvre seule`,Standard:`Standard`,"Size & style":`Style`,"Wide image":`Image large`,"Wide simple":`Large simple`,"Hold load & play until clicked":`Click-to-play`,"Make it a small card":`Carte compacte`,"Keep using full media card":`Continuez à utiliser la carte média complète`,"Don't include player":`Ne pas inclure la vidéo`,"Player only, no card":`La vidéo seulement, pas de carte`,"Just the player":`Seulement la vidéo`,"Just the image":`Seulement l'image`})})(); \ No newline at end of file +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n={};function r(e,t){let r=n[e]=n[e]||{};Object.assign(r,t)}t.optionsTranslator=e=>t=>n[e]&&n[e][t]&&n[e][t]!==``?n[e][t]:t,r(`fr`,{"Slimmer horizontal player":`Joueur de audio classique`,"Include playlist":`Inclure la playlist`,"Hide artwork":`Masquer la illustration`,"Theme color":`Couleur du thème`,Light:`Lumière`,Dark:`Sombre`,Auto:``,Default:`Défaut`,"Adjust height":`Height`,"Active page":`Page active`,"Use click-to-load":`Utilisez click-to-load`,"ex.: 600, in px":``,"Hide timed comments":`Masquer les commentaires`,"Let Iframely optimize player for the artwork":`Optimiser le lecteur pour l'illustration`,"Show as slideshow":`Montrer en diaporama`,"Start from":`Commencer`,"ex.: 11, 1m10s":``,"End on":`Fin sur`,"Include up to 20 tweets":`Incluez jusqu'à 20 tweets`,"Hide photos, videos, and cards":`Masquer les photos, les vidéos et les cartes`,"Hide previous Tweet in conversation thread":`Masquer le tweet parent`,"Hide description":`Masquer la description`,"Widget style":`Style de widget`,Mini:``,Classic:`Classique`,Picture:`Image`,Zoom:``,"Map orientation":`Orientation de la carte`,Album:``,Portrait:``,Square:`Carré`,"Show context slideshow":`Afficher le diaporama contextuel`,"Show description footer":`Afficher la description pied de page`,"Show user header":`Afficher l'en-tête de l'utilisateur`,"Show author's text caption":`Afficher la description de l'auteur`,"Hide author's text caption":`Masquer la description de l'auteur`,"Include parent comment (if url is a reply)":``,"Show recent posts":`Afficher les messages récents`,"Show profile photos when friends like this":``,"Use the small header instead":`Utilisez plutôt le petit en-tête`,Artwork:`Ouvrages d'art`,Small:`Petite`,Big:`Grosse`,None:`Aucune`,Layout:`Disposition`,Slim:`Svelte`,"Artwork-only":`Oeuvre seule`,Standard:`Standard`,"Size & style":`Style`,"Wide image":`Image large`,"Wide simple":`Large simple`,"Hold load & play until clicked":`Click-to-play`,"Make it a small card":`Carte compacte`,"Keep using full media card":`Continuez à utiliser la carte média complète`,"Don't include player":`Ne pas inclure la vidéo`,"Player only, no card":`La vidéo seulement, pas de carte`,"Just the player":`Seulement la vidéo`,"Just the image":`Seulement l'image`})})(); \ No newline at end of file diff --git a/dist/options.js b/dist/options.js index f8ac59c..37b7975 100644 --- a/dist/options.js +++ b/dist/options.js @@ -2,7 +2,27 @@ //#region src/iframely.ts - var iframely = window.iframely = window.iframely || {}; + function createServerStub() { + const noop = () => {}; + return { + config: {}, + on: noop, + trigger: noop, + triggerAsync: noop, + load: noop, + configure: noop, + extendOptions: noop, + setTheme: noop, + cancelWidget: noop, + openHref: noop, + addEventListener: noop, + isTouch: () => false, + findIframe: () => void 0, + getElementComputedStyle: () => void 0, + buildOptionsForm: noop + }; + } + var iframely = typeof window === "undefined" ? createServerStub() : window.iframely = window.iframely || {}; iframely.config = iframely.config || {}; //#endregion diff --git a/dist/options.min.js b/dist/options.min.js index 33a640b..a03ebff 100644 --- a/dist/options.min.js +++ b/dist/options.min.js @@ -1,38 +1,38 @@ -(function(){var e=window.iframely=window.iframely||{};e.config=e.config||{};var t=/^_./,n=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function r(e,r){if(!e)return[];e=Object.assign({},e),delete e.query;let i=[],a=Object.keys(e),o=0;if(a.forEach(a=>{let s={},c,l=e[a];l.key=a;let u=!1,d=l.values?Object.keys(l.values):void 0,f,p;if(d&&d.length===1&&(u=!0,f=d[0],p=l.values[f]),s.label=n(p||l.label,r),s.key=l.key,u||typeof l.value==`boolean`)u?s.checked=f===l.value||!f&&!l.value:s.checked=l.value,o++,i.push({type:`checkbox`,context:s,order:+!t.test(a),getQuery:e=>{let t;t=u?e?f:``:e;let n={};return u?t===``||(n[l.key]=t):n[l.key]=e,n}});else if((typeof l.value==`number`||typeof l.value==`string`)&&!l.values){let e=l.range&&typeof l.range.min==`number`&&typeof l.range.max==`number`,t=typeof l.value==`number`;s.value=l.value,c=e=>{let t={};return e===``||(t[l.key]=e),t},e?(s.min=l.range.min,s.max=l.range.max,i.push({type:`range`,context:s,order:9,getQuery:c})):(s.placeholder=n(l.placeholder||``,r),s.inputType=t?`number`:`text`,i.push({type:`text`,context:s,order:/start/i.test(a)?7:8,getQuery:c}))}else if(l.values)if(s.value=l.value+``,c=e=>{let t={};return e===``||(t[l.key]=e),t},Object.keys(l.values).length<=3){l.label?s.label=n(l.label,r):s.label=!1;let e=0,t=!1,o=Object.values(l.values);for(;e8,e++;s.inline=!t,s.items=[],Object.keys(l.values).forEach((e,t)=>{s.items.push({id:s.key+`-`+t,value:e,label:n(l.values[e],r),checked:s.value===e})}),i.push({type:`radio`,context:s,order:t?-3:/theme/.test(a)?-1:-2,getQuery:c})}else s.items=[],Object.keys(l.values).forEach(e=>{s.items.push({value:e,label:n(l.values[e],r),checked:s.value===e})}),i.push({type:`select`,context:s,order:5,getQuery:c})}),i.sort((e,t)=>e.order-t.order),i.forEach(e=>{delete e.order}),o>0){let e=[],n;return i.forEach((r,a)=>{if(r.type===`checkbox`){let s=o>2&&a>0&&!t.test(r.context.key)&&i[a-1].type===`checkbox`&&t.test(i[a-1].context.key);(!n||s)&&(n=[],e.push({type:`group`,context:{elements:n}})),n.push(r)}else e.push(r)}),e}else return i}var i={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(t,n)=>{let r=t[0];e.addEventListener(r,`click`,()=>{r.select()}),e.addEventListener(r,`blur`,n),e.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},a={};function o(t){let n=t.options,o=t.formContainer;if(!o){console.warn(`No formContainer in form-builder options`,t);return}if(!n){o.innerHTML=``;return}let s=r(n,t.translator),c=t.id,l=t.renderer,u=a[c]=a[c]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(u[e]=n[e].value)});function d(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=i[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(s),e}function f(){let t=d();Object.keys(u).forEach(e=>{(u[e]===t[e]||t[e]===void 0)&&delete t[e]}),e.trigger(`options-changed`,c,o,t)}let p=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=p(e.context.elements)),t+=l(e.type,e.context||{})}),t};o.innerHTML=p(s);let m=t=>{t.forEach(t=>{if(t.context&&t.context.elements)m(t.context.elements);else{let n=i[t.type];if(t.context){let r=o.querySelectorAll(`[name="`+t.context.key+`"]`);t.inputs=r,r.length>0?n&&n.customEvents?n.customEvents(r,f):r.forEach(t=>{e.addEventListener(t,`change`,f)}):console.warn(`No inputs found for option`,t.context.key)}}})};m(s)}var s={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},c=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>s[e]),l={checkbox:e=>` +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n=/^_./,r=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function i(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let i=[],a=Object.keys(e),o=0;if(a.forEach(a=>{let s={},c,l=e[a];l.key=a;let u=!1,d=l.values?Object.keys(l.values):void 0,f,p;if(d&&d.length===1&&(u=!0,f=d[0],p=l.values[f]),s.label=r(p||l.label,t),s.key=l.key,u||typeof l.value==`boolean`)u?s.checked=f===l.value||!f&&!l.value:s.checked=l.value,o++,i.push({type:`checkbox`,context:s,order:+!n.test(a),getQuery:e=>{let t;t=u?e?f:``:e;let n={};return u?t===``||(n[l.key]=t):n[l.key]=e,n}});else if((typeof l.value==`number`||typeof l.value==`string`)&&!l.values){let e=l.range&&typeof l.range.min==`number`&&typeof l.range.max==`number`,n=typeof l.value==`number`;s.value=l.value,c=e=>{let t={};return e===``||(t[l.key]=e),t},e?(s.min=l.range.min,s.max=l.range.max,i.push({type:`range`,context:s,order:9,getQuery:c})):(s.placeholder=r(l.placeholder||``,t),s.inputType=n?`number`:`text`,i.push({type:`text`,context:s,order:/start/i.test(a)?7:8,getQuery:c}))}else if(l.values)if(s.value=l.value+``,c=e=>{let t={};return e===``||(t[l.key]=e),t},Object.keys(l.values).length<=3){l.label?s.label=r(l.label,t):s.label=!1;let e=0,n=!1,o=Object.values(l.values);for(;e8,e++;s.inline=!n,s.items=[],Object.keys(l.values).forEach((e,n)=>{s.items.push({id:s.key+`-`+n,value:e,label:r(l.values[e],t),checked:s.value===e})}),i.push({type:`radio`,context:s,order:n?-3:/theme/.test(a)?-1:-2,getQuery:c})}else s.items=[],Object.keys(l.values).forEach(e=>{s.items.push({value:e,label:r(l.values[e],t),checked:s.value===e})}),i.push({type:`select`,context:s,order:5,getQuery:c})}),i.sort((e,t)=>e.order-t.order),i.forEach(e=>{delete e.order}),o>0){let e=[],t;return i.forEach((r,a)=>{if(r.type===`checkbox`){let s=o>2&&a>0&&!n.test(r.context.key)&&i[a-1].type===`checkbox`&&n.test(i[a-1].context.key);(!t||s)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return i}var a={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(e,n)=>{let r=e[0];t.addEventListener(r,`click`,()=>{r.select()}),t.addEventListener(r,`blur`,n),t.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},o={};function s(e){let n=e.options,r=e.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,e);return}if(!n){r.innerHTML=``;return}let s=i(n,e.translator),c=e.id,l=e.renderer,u=o[c]=o[c]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(u[e]=n[e].value)});function d(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=a[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(s),e}function f(){let e=d();Object.keys(u).forEach(t=>{(u[t]===e[t]||e[t]===void 0)&&delete e[t]}),t.trigger(`options-changed`,c,r,e)}let p=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=p(e.context.elements)),t+=l(e.type,e.context||{})}),t};r.innerHTML=p(s);let m=e=>{e.forEach(e=>{if(e.context&&e.context.elements)m(e.context.elements);else{let n=a[e.type];if(e.context){let i=r.querySelectorAll(`[name="`+e.context.key+`"]`);e.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,f):i.forEach(e=>{t.addEventListener(e,`change`,f)}):console.warn(`No inputs found for option`,e.context.key)}}})};m(s)}var c={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},l=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>c[e]),u={checkbox:e=>`
- - + +
`,group:e=>`
${e.elementsHtml??``}
`,radio:e=>`
- ${e.label?``:``} + ${e.label?``:``}
${(e.items||[]).map(t=>`
- - + +
`).join(``)}
`,range:e=>`
- +
- +
`,select:e=>`
- +
- + ${(e.items||[]).map(e=>``).join(``)}
`,text:e=>`
- +
- +
-
`},u=(e,t)=>l[e](t);function d(){e.buildOptionsForm=(e,t,n,r)=>{o({id:e,formContainer:t,options:n,renderer:u,translator:r})}}d()})(); \ No newline at end of file + `},d=(e,t)=>u[e](t);function f(){t.buildOptionsForm=(e,t,n,r)=>{s({id:e,formContainer:t,options:n,renderer:d,translator:r})}}f()})(); \ No newline at end of file diff --git a/dist/types/main-options.d.ts b/dist/types/main-options.d.ts index 1ad0e6c..1f7b990 100644 --- a/dist/types/main-options.d.ts +++ b/dist/types/main-options.d.ts @@ -1,3 +1,4 @@ import './index-options'; -export { default as iframely } from './iframely'; +import iframely from './iframely'; +export { iframely }; export type * from './types'; diff --git a/dist/types/main.d.ts b/dist/types/main.d.ts index 4edfefd..a0a47c2 100644 --- a/dist/types/main.d.ts +++ b/dist/types/main.d.ts @@ -1,3 +1,4 @@ import './index'; -export { default as iframely } from './iframely'; +import iframely from './iframely'; +export { iframely }; export type * from './types'; diff --git a/dist/types/types.d.ts b/dist/types/types.d.ts index 81292ca..1d098e3 100644 --- a/dist/types/types.d.ts +++ b/dist/types/types.d.ts @@ -81,6 +81,8 @@ export interface Iframely { trigger(event: string, ...args: any[]): void; triggerAsync(event: string, ...args: any[]): void; load(...args: any[]): void; + configure(options: Record | undefined): void; + /** @deprecated Pre-2.0 name of {@link Iframely.configure}. */ extendOptions(options: Record | undefined): void; getElementComputedStyle(el: Element, style: string): string | undefined; findIframe(options: FindIframeOptions): HTMLIFrameElement | undefined; diff --git a/src/deprecated.ts b/src/deprecated.ts index cda54e6..cef9c79 100644 --- a/src/deprecated.ts +++ b/src/deprecated.ts @@ -5,6 +5,9 @@ export function boot(): void { iframely.widgets = iframely.widgets || {}; iframely.widgets.load = iframely.load; + // Pre-2.0 name of iframely.configure. + iframely.extendOptions = iframely.configure; + if (!iframely.events) { iframely.events = {}; iframely.events.on = iframely.on; diff --git a/src/dom-ready.ts b/src/dom-ready.ts index e523705..11b5199 100644 --- a/src/dom-ready.ts +++ b/src/dom-ready.ts @@ -10,9 +10,12 @@ const DOMReady = (f: () => void): void => { // Runs at import time, outside the entries' `_loaded` guard — each loaded // bundle announces itself, exactly like the old per-bundle require did. -DOMReady(() => { - // Called each time on script load - if (typeof iframely.config.autorun === 'undefined' || iframely.config.autorun !== false) { - iframely.trigger('load'); - } -}); +// Skipped on the server, where there is no document (SSR-safe import). +if (typeof document !== 'undefined') { + DOMReady(() => { + // Called each time on script load + if (typeof iframely.config.autorun === 'undefined' || iframely.config.autorun !== false) { + iframely.trigger('load'); + } + }); +} diff --git a/src/iframely.ts b/src/iframely.ts index b7b427a..2d9f93d 100644 --- a/src/iframely.ts +++ b/src/iframely.ts @@ -1,9 +1,38 @@ import type { Iframely } from './types'; -// The window.iframely singleton is the library's only global exposure and the -// only state shared between separately loaded bundles (embed, options, i18n). -// Another bundle may have created it already — never overwrite. -const iframely: Iframely = (window.iframely = window.iframely || ({} as Iframely)); +// In server (SSR) environments the singleton is a detached, inert stub so +// that importing the package is error- and side-effect-free; every API call +// is a no-op until the code runs in a browser. Nothing may store state here: +// on the server one module instance is shared across requests. +function createServerStub(): Iframely { + const noop = (): void => {}; + return { + config: {}, + on: noop, + trigger: noop, + triggerAsync: noop, + load: noop, + configure: noop, + extendOptions: noop, + setTheme: noop, + cancelWidget: noop, + openHref: noop, + addEventListener: noop, + isTouch: () => false, + findIframe: () => undefined, + getElementComputedStyle: () => undefined, + buildOptionsForm: noop + } as unknown as Iframely; +} + +// In the browser, the window.iframely singleton is the library's only global +// exposure and the only state shared between separately loaded bundles +// (embed, options, i18n). Another bundle may have created it already — never +// overwrite. +const iframely: Iframely = + typeof window === 'undefined' + ? createServerStub() + : (window.iframely = window.iframely || ({} as Iframely)); iframely.config = iframely.config || {}; export default iframely; diff --git a/src/index-options.ts b/src/index-options.ts index be045ed..6e06b4a 100644 --- a/src/index-options.ts +++ b/src/index-options.ts @@ -18,8 +18,9 @@ import { boot as bootDeprecated } from './deprecated'; import { boot as bootOptions } from './options/index'; // Same bootstrap as index.ts plus the options form builder. -// See index.ts for why boot() functions replace CJS side-effect requires. -if (!iframely._loaded) { +// See index.ts for why boot() functions replace CJS side-effect requires +// and why nothing boots on the server. +if (typeof window !== 'undefined' && !iframely._loaded) { iframely._loaded = true; bootConst(); diff --git a/src/index.ts b/src/index.ts index 2f785e7..5136577 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,8 +20,9 @@ import { boot as bootDeprecated } from './deprecated'; // module evaluation. Modules therefore defer all singleton mutations and // listener registrations to their boot() functions, and the guard skips // those: when several bundles share a page (e.g. embed.js + options.js), -// only the first one boots and triggers 'init'. -if (!iframely._loaded) { +// only the first one boots and triggers 'init'. On the server nothing boots +// at all — the singleton stays an inert stub (SSR-safe import). +if (typeof window !== 'undefined' && !iframely._loaded) { iframely._loaded = true; bootConst(); diff --git a/src/intersection.ts b/src/intersection.ts index 81d7b3f..ba30f49 100644 --- a/src/intersection.ts +++ b/src/intersection.ts @@ -54,7 +54,7 @@ function getObserverOptions(options: IntersectionOptions): IntersectionObserverI export function boot(): void { iframely.on('init', () => { - iframely.extendOptions({ + iframely.configure({ intersection: 1 }); }); diff --git a/src/main-options.ts b/src/main-options.ts index ab88b3c..c01cb3b 100644 --- a/src/main-options.ts +++ b/src/main-options.ts @@ -1,6 +1,14 @@ // Public ESM entry for npm/bundler consumers: embed + options form builder. -// Loading it has the same side effects as the embed-options.js script tag. +// Unlike the embed-options.js script tag, it does NOT auto-run on +// DOMContentLoaded: call iframely.load() to scan the DOM and build embeds. +// To restore the script-tag behavior, pre-set +// `window.iframely = { config: { autorun: true } }` before importing. import './index-options'; +import iframely from './iframely'; -export { default as iframely } from './iframely'; +if (typeof window !== 'undefined') { + iframely.config.autorun = iframely.config.autorun ?? false; +} + +export { iframely }; export type * from './types'; diff --git a/src/main.ts b/src/main.ts index 910a1bb..7ce4136 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,17 @@ // Public ESM entry for npm/bundler consumers of the embed library. -// Loading it has the same side effects as the embed.js script tag. +// Unlike the embed.js script tag, it does NOT auto-run on DOMContentLoaded: +// call iframely.load() to scan the DOM and build embeds. To restore the +// script-tag behavior, pre-set `window.iframely = { config: { autorun: true } }` +// before importing. import './index'; +import iframely from './iframely'; -export { default as iframely } from './iframely'; +// dom-ready checks autorun when DOMContentLoaded fires (or on the macrotask +// after import for already-loaded documents), so setting it here is in time. +// On the server the singleton is an inert stub — leave it untouched. +if (typeof window !== 'undefined') { + iframely.config.autorun = iframely.config.autorun ?? false; +} + +export { iframely }; export type * from './types'; diff --git a/src/theme.ts b/src/theme.ts index 2924e3e..ada70e3 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -30,7 +30,7 @@ export function boot(): void { } } else { // Send get param to next iframes. - iframely.extendOptions({ + iframely.configure({ theme: theme }); setThemeInAllIframes(document, theme); diff --git a/src/types.ts b/src/types.ts index 60e56f9..2ed4d5b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -96,6 +96,8 @@ export interface Iframely { // utils.ts load(...args: any[]): void; + configure(options: Record | undefined): void; + /** @deprecated Pre-2.0 name of {@link Iframely.configure}. */ extendOptions(options: Record | undefined): void; getElementComputedStyle(el: Element, style: string): string | undefined; diff --git a/src/utils.ts b/src/utils.ts index 622802f..9e2c99a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -7,7 +7,7 @@ import type { IframelyWidget } from './types'; export function boot(): void { iframely.on('init', () => { - iframely.extendOptions(parseQueryStringFromScriptSrc()); + iframely.configure(parseQueryStringFromScriptSrc()); // if it's hosted from elsewhere - we don't support customizing via query-string. // iframely.CDN will be default one unless changed by user (?cdn= or iframely.CDN= ) @@ -31,8 +31,8 @@ export function boot(): void { return window.getComputedStyle(el).getPropertyValue(style); }; - // helper method to init more options through js code - iframely.extendOptions = (options) => { + // helper method to init more config options through js code + iframely.configure = (options) => { if (!options) { return; } diff --git a/tests/e2e/esm.spec.ts b/tests/e2e/esm.spec.ts index f27d39f..ba69bda 100644 --- a/tests/e2e/esm.spec.ts +++ b/tests/e2e/esm.spec.ts @@ -1,13 +1,36 @@ import { test, expect } from '@playwright/test'; -test('the ESM build exports the same singleton that is attached to window', async ({ page }) => { +test.beforeEach(async ({ page }) => { + await page.route('**/api/iframe*', (route) => + route.fulfill({ + contentType: 'text/html', + body: 'widget' + }) + ); await page.goto('/demo/esm.html'); await page.waitForFunction(() => !!(window as any).__esm); +}); +test('the ESM build exports the same singleton that is attached to window', async ({ page }) => { const state = await page.evaluate(() => (window as any).__esm); expect(state).toEqual({ sameSingleton: true, version: 1, - hasOn: true + hasOn: true, + autorun: false }); }); + +test('does not auto-run on import; iframely.load() activates it', async ({ page }) => { + // Give the dom-ready autorun path time to fire if it (wrongly) were active. + await page.waitForTimeout(250); + await expect(page.locator('a[data-iframely-url]')).toHaveCount(1); + await expect(page.locator('iframe')).toHaveCount(0); + + await page.evaluate(() => (window as any).__load()); + + const iframe = page.locator('.iframely-responsive iframe'); + await expect(iframe).toHaveCount(1); + await expect(page.locator('a[data-iframely-url]')).toHaveCount(0); + expect(await iframe.getAttribute('src')).toContain('cdn.iframe.ly/api/iframe'); +}); diff --git a/tests/e2e/surface.spec.ts b/tests/e2e/surface.spec.ts index dadf649..00a42b6 100644 --- a/tests/e2e/surface.spec.ts +++ b/tests/e2e/surface.spec.ts @@ -1,7 +1,8 @@ import { test, expect } from '@playwright/test'; // The public window.iframely surface as shipped by the last webpack build -// (v1.11). The migration must not add or remove keys. +// (v1.11), plus `configure` (new in 2.0; `extendOptions` remains as its +// deprecated alias). Nothing else may be added or removed. const EXPECTED_KEYS = [ 'ASPECT_WRAPPER_CLASS', 'BASE_RE', @@ -26,6 +27,7 @@ const EXPECTED_KEYS = [ 'buildImportWidgets', 'cancelWidget', 'config', + 'configure', 'events', 'extendOptions', 'findIframe', diff --git a/tests/unit/ssr.test.ts b/tests/unit/ssr.test.ts new file mode 100644 index 0000000..1188f6c --- /dev/null +++ b/tests/unit/ssr.test.ts @@ -0,0 +1,41 @@ +// @vitest-environment node +// +// Simulates an isomorphic (e.g. SvelteKit) server pass: no window, no +// document. Importing any public entry must neither throw nor run browser +// side effects, and the exported singleton must be an inert no-op stub. +import { describe, expect, it } from 'vitest'; + +describe('SSR import (node environment)', () => { + it('runs without browser globals', () => { + expect(typeof window).toBe('undefined'); + expect(typeof document).toBe('undefined'); + }); + + it('imports the main entry without errors or side effects', async () => { + const { iframely } = await import('../../src/main'); + expect(iframely).toBeDefined(); + // Nothing booted: the browser-only bootstrap was skipped. + expect(iframely._loaded).toBeUndefined(); + }); + + it('tolerates API calls on the server as no-ops', async () => { + const { iframely } = await import('../../src/main'); + expect(() => { + iframely.on('load', () => {}); + iframely.trigger('anything'); + iframely.load(); + iframely.configure({ api_key: 'x' }); + iframely.setTheme('dark'); + iframely.cancelWidget(); + }).not.toThrow(); + // The stub must stay stateless: one server module instance is shared + // across requests. + expect(iframely.config).toEqual({}); + }); + + it('imports the options and i18n entries without errors', async () => { + await expect(import('../../src/main-options')).resolves.toBeDefined(); + await expect(import('../../src/options/lang/labels.de')).resolves.toBeDefined(); + await expect(import('../../src/options/lang/labels.fr')).resolves.toBeDefined(); + }); +}); diff --git a/tests/unit/utils.test.ts b/tests/unit/utils.test.ts index cc9aa08..430a9c9 100644 --- a/tests/unit/utils.test.ts +++ b/tests/unit/utils.test.ts @@ -3,6 +3,7 @@ import iframely from '../../src/iframely'; import { boot as bootConst } from '../../src/const'; import { boot as bootEvents } from '../../src/events'; import { boot as bootUtils } from '../../src/utils'; +import { boot as bootDeprecated } from '../../src/deprecated'; import * as utils from '../../src/utils'; beforeAll(() => { @@ -80,7 +81,7 @@ describe('getEndpoint', () => { }); it('adds matching iframely.config values for config_params, including regex matches', () => { - iframely.extendOptions({ api_key: 'KEY', _theme_opt: 'x', unrelated: 'nope' }); + iframely.configure({ api_key: 'KEY', _theme_opt: 'x', unrelated: 'nope' }); const endpoint = utils.getEndpoint( '/api/iframe', { url: 'u' }, @@ -92,9 +93,9 @@ describe('getEndpoint', () => { }); }); -describe('extendOptions', () => { +describe('configure', () => { it('normalizes falsy/truthy string and number values to booleans', () => { - iframely.extendOptions({ + iframely.configure({ a: '0', b: 'false', c: 0, @@ -119,13 +120,18 @@ describe('extendOptions', () => { }); it('does not override values previously disabled with false', () => { - iframely.extendOptions({ lazy: false }); - iframely.extendOptions({ lazy: true }); + iframely.configure({ lazy: false }); + iframely.configure({ lazy: true }); expect(iframely.config.lazy).toBe(false); }); it('ignores undefined options', () => { - expect(() => iframely.extendOptions(undefined)).not.toThrow(); + expect(() => iframely.configure(undefined)).not.toThrow(); + }); + + it('keeps extendOptions as a deprecated alias', () => { + bootDeprecated(); + expect(iframely.extendOptions).toBe(iframely.configure); }); }); From 71961033b2bd2f144cf08e685a2367bb37b99f50 Mon Sep 17 00:00:00 2001 From: Alexander Matveyenko Date: Sat, 11 Jul 2026 13:01:35 +0200 Subject: [PATCH 6/7] Add iframely.unload() as the inverse of load() - unload(container?) removes the widgets the library built (domain- matched iframes and pending data-iframely-url lazy iframes with the proper wrapper structure; foreign iframes untouched), firing unload-widget per widget and a final unload event. - Modules release their state through those events: intersection unobserves removed iframes and drops all observers on a full unload (observers held strong refs - the actual leak in long-lived SPAs), lazy-img-placeholder clears pending waiting-widget timers, import resets transient import state. - Not covered by design: restoring consumed anchors and import/shadow widgets; documented in types and README. SSR stub gains a no-op. - Tests: unload unit suite, e2e load->unload round trip, surface snapshot + SSR no-op coverage. Co-Authored-By: Claude Fable 5 --- README.md | 5 ++ dist/embed-options.js | 35 +++++++++++++ dist/embed-options.min.js | 4 +- dist/embed.js | 35 +++++++++++++ dist/embed.min.js | 2 +- dist/esm/chunks/deprecated.js | 34 ++++++++++++ dist/esm/chunks/iframely.js | 1 + dist/options.i18n.de.js | 1 + dist/options.i18n.de.min.js | 2 +- dist/options.i18n.fr.js | 1 + dist/options.i18n.fr.min.js | 2 +- dist/options.js | 1 + dist/options.min.js | 2 +- dist/types/types.d.ts | 6 +++ src/iframely.ts | 1 + src/import.ts | 11 ++++ src/intersection.ts | 16 ++++++ src/lazy-img-placeholder.ts | 5 ++ src/types.ts | 6 +++ src/utils.ts | 21 ++++++++ tests/e2e/esm.spec.ts | 10 ++++ tests/e2e/surface.spec.ts | 2 + tests/unit/ssr.test.ts | 1 + tests/unit/unload.test.ts | 99 +++++++++++++++++++++++++++++++++++ 24 files changed, 297 insertions(+), 6 deletions(-) create mode 100644 tests/unit/unload.test.ts diff --git a/README.md b/README.md index 30a39fb..92a5eb6 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,11 @@ The module is safe to import in isomorphic setups (SvelteKit, Next.js, etc.): on no-op stub and performs no side effects, so you can import it at the top level and call `iframely.load()` from client-only code (e.g. Svelte's `onMount`). +To deactivate, `iframely.unload()` (or `iframely.unload(container)`) removes the widgets that `load()` built and +releases their intersection observers and pending timers — pair it with `load()` across route changes or in unmount +hooks. It does not restore the original `` markup (re-render it yourself to re-embed), and it +does not cover import/shadow-DOM widgets. + ## Omit cloud embed.js from API responses The HTML embed codes you get from Iframely APIs will include the cloud copy of embed.js by default (as diff --git a/dist/embed-options.js b/dist/embed-options.js index b3c945a..3a29051 100644 --- a/dist/embed-options.js +++ b/dist/embed-options.js @@ -10,6 +10,7 @@ trigger: noop, triggerAsync: noop, load: noop, + unload: noop, configure: noop, extendOptions: noop, setTheme: noop, @@ -211,6 +212,20 @@ iframely.load = function(...args) { iframely.trigger("load", ...args); }; + iframely.unload = (el) => { + const domains = iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, "")); + const root = el || document; + const selector = "iframe[src*=\"" + domains.join("\"], iframe[src*=\"") + "\"], iframe[data-iframely-url]"; + const iframes = root.querySelectorAll(selector); + for (let i = 0; i < iframes.length; i++) { + const widget = getWidget(iframes[i]); + if (widget) { + iframely.trigger("unload-widget", widget); + widget.maxWidthWrapper.remove(); + } + } + iframely.trigger("unload", el); + }; iframely.getElementComputedStyle = (el, style) => { return window.getComputedStyle(el).getPropertyValue(style); }; @@ -419,6 +434,15 @@ getObserver(options).observe(widget.iframe); } }); + iframely.on("unload-widget", (widget) => { + Object.values(observers).forEach((observer) => observer.unobserve(widget.iframe)); + }); + iframely.on("unload", (el) => { + if (!el) Object.keys(observers).forEach((key) => { + observers[key].disconnect(); + delete observers[key]; + }); + }); } //#endregion @@ -474,6 +498,14 @@ return "ontouchstart" in window || navigator.maxTouchPoints > 0; }; iframely.on("import-widget-ready", clearWrapperStylesAndClass); + iframely.on("unload", (el) => { + if (!el) { + delete iframely.import; + Object.keys(widgetsCache).forEach((key) => { + delete widgetsCache[key]; + }); + } + }); if (!iframely.addEventListener) iframely.addEventListener = (elem, type, eventHandle) => { if (!elem) return; elem.addEventListener(type, eventHandle, false); @@ -748,6 +780,9 @@ waitingWidget?.registerLoadingTimeout(); } }); + iframely.on("unload-widget", (widget) => { + findWaitingWidget(widget)?.deactivate(); + }); } function addPlaceholderThumbnail(widget, href, imageUrl) { let thumbHref; diff --git a/dist/embed-options.min.js b/dist/embed-options.min.js index 6baf06e..dcfe497 100644 --- a/dist/embed-options.min.js +++ b/dist/embed-options.min.js @@ -1,4 +1,4 @@ -(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{},typeof document<`u`&&(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(t.config.autorun===void 0||t.config.autorun!==!1)&&t.trigger(`load`)});function n(){t.VERSION=1,t.ASPECT_WRAPPER_CLASS=`iframely-responsive`,t.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,t.LOADER_CLASS=`iframely-loader`,t.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],t.CDN=t.CDN||t.DOMAINS[0],t.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,t.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,t.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],t.SUPPORTED_THEMES=[`auto`,`light`,`dark`],t.LAZY_IFRAME_SHOW_TIMEOUT=3e3,t.LAZY_IFRAME_FADE_TIMEOUT=200,t.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,t.RECOVER_HREFS_ON_CANCEL=!1,t.SHADOW=`iframely-shadow`,t.SUPPORT_IFRAME_LOADING_ATTR=!0}var r=e=>{window.requestAnimationFrame(e)},i={};function a(e,n,a){(i[e]||[]).forEach(e=>{n?r(()=>{e.apply(t,a)}):e.apply(t,a)}),e===`init`&&(i[e]=[])}function o(){t.on=(e,t)=>{(i[e]=i[e]||[]).push(t)},t.trigger=(e,...t)=>{a(e,!1,t)},t.triggerAsync=(e,...t)=>{a(e,!0,t)}}function s(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function c(e,t){let n;for(let r=0;r{let t=l(document,e);return t||=u(document,e),t},s((e,n)=>{if(n&&(n.method||n.type||n.context)){let r=t.findIframe({contentWindow:e.source,src:n.src||n.context,domains:n.domains!==`all`&&t.DOMAINS.concat(t.CDN)});if(r){let e=h(r);e&&n.url&&(e.url=n.url),t.trigger(`message`,e,n)}}})}function f(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){t.on(`init`,()=>{t.configure(b()),te(),t.config.theme&&t.setTheme(t.config.theme),ne(t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)))}),t.load=function(...e){t.trigger(`load`,...e)},t.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),t.configure=e=>{e&&Object.keys(e).forEach(n=>{let r=e[n]===0||e[n]===`0`||e[n]===!1||e[n]===`false`?!1:e[n]===1||e[n]===`1`||e[n]===!0||e[n]===`true`||e[n];t.config[n]!==!1&&(t.config[n]=r)})}}function p(e,n){let r=e.parentNode;if(!r||r.nodeName!==`DIV`||x(r)>2||n&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||x(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function m(e){let n=e.parentNode,r=document.createElement(`div`);r.className=t.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=t.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,e),{aspectWrapper:i,maxWidthWrapper:r}}function h(e){let t=p(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=C(r);e.url&&(n.url=e.url)}return n}function g(e,n){e&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=e.style,o=a[r];t.getElementComputedStyle(e,r)!=i&&!(e.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function _(e){t.config.nonce&&(e.nonce=t.config.nonce)}function te(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,_(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function v(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function y(e,n,r){let i=e;if(/^(https?:)?\/\//i.test(e)||(i=(n&&n.CDN||t.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=v(i,n)),r&&r.length){let e={},n=Object.keys(t.config);for(let i=0;i0)return e}}return{}}function ne(e){let n=document.querySelectorAll(`iframe[src*="`+(e||t.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{f({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},D(e)),T[t]=n),n}function D(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function re(){t.on(`init`,()=>{t.configure({intersection:1})}),t.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},E(n).observe(e.iframe)}})}function O(e,t){f({method:`setTheme`,data:t},`*`,e.contentWindow)}function k(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{e&&t.SUPPORTED_THEMES.indexOf(e)>-1?n?n.tagName===`IFRAME`?O(n,e):k(n,e):(t.configure({theme:e}),k(document,e),t.trigger(`set-theme`,e)):console.warn(`Using iframely.setTheme with not supported theme: "`+e+`". Supported themes are: `+t.SUPPORTED_THEMES.join(`, `))}}var j={};function ie(){t.on(`load`,e=>{if(!e&&t.config.import!==!1&&se()&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&ae(e)}}),t.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=j[e.uri];if(n)for(let r=0;r{t.trigger(`import-loaded`,e),e.widgets.forEach(n=>{t.trigger(`load`,n,e)}),M()},t.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,t.on(`import-widget-ready`,N),t.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function ae(e){let n=w(),r=[],i=[],a=null;function o(e,t){j[e]||(j[e]=[]),j[e].push(t)}function s(e){let n=e.getAttribute(`data-iframely-url`),s=n.match(t.ID_RE),c=s&&s[1],l=C(n,t.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let e=n.match(t.BASE_RE);l.CDN=e&&e[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?t.trigger(`load`,e):c?(e.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,e)):(u||=e.getAttribute(`href`),(a.key||a.api_key||t.config.api_key||t.config.key)&&u?(e.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,e)):t.trigger(`load`,e))}for(let t=0;t0||i.length>0?(a||={},a.touch=t.isTouch(),a.flash=!1,a.app=1,t.config.theme&&(a.theme=t.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=t.VERSION,n.src=y(`/api/import/v2`,a,t.SUPPORTED_QUERY_STRING),n.onerror=()=>{M()},document.head.appendChild(n),t.import=n):(M(),t.trigger(`load`))}function oe(e,n,r){let i=e.cancel,a=e.shadow,o=e.renderEvent,s=p(n,!0);if(i)t.cancelWidget(h(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=e.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:e.context,stylesIds:e.stylesIds,stylesDict:r.commonShadowStyles};t.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),t.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),P(i);c.removeChild(l),o&&setTimeout(()=>{N(c)},t.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function M(){delete t.import;let e=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function P(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=w();r.type=`text/javascript`;for(let e=0;e{if(e&&e.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),e.appendChild(r),t.trigger(`load`,r)}}),t.on(`load`,e=>{if(!e&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&I(e)})}function I(e){if(!e.getAttribute(`data-iframely-url`)&&!e.getAttribute(`href`))return;let n,r=e.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=y(r,{v:t.VERSION,app:1,theme:t.config.theme});else if((t.config.api_key||t.config.key)&&t.CDN){if(!e.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,e);return}n=y(`/api/iframe`,{url:e.getAttribute(`href`),v:t.VERSION,app:1,theme:t.config.theme},t.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)e.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),e.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,e.getAttribute(`data-img`));let i=e.hasAttribute(`data-lazy`)||e.hasAttribute(`data-img`)||/&lazy=1/.test(n)||t.config.lazy,a=e.textContent;a&&a!==``&&(r.textContent=a);let o=p(e,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=m(e),e.parentNode.removeChild(e);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),t.trigger(`load`,r)):(r.setAttribute(`src`,n),t.trigger(`iframe-ready`,r))}}function L(){t.on(`load`,e=>{if(e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)){let n=e.getAttribute(`data-img`);e.removeAttribute(`data-img`),e.setAttribute(`data-img-created`,``);let r=h(e),i=e.getAttribute(`data-iframely-url`);r&&(R(r,i,n),i=v(i,{img:1}),e.setAttribute(`data-iframely-url`,i),new K(r)),t.trigger(`load`,e)}}),t.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(V(e),n=W(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=W(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=W(e),n?.registerLoadingTimeout())})}function R(e,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let e=C(n),r={};for(let t in e)t.indexOf(`_`)===0&&(r[t]=e[t]);if(e.media&&(r.media=e.media),n.match(/\/api\/iframe/))i=y(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:e.url,api_key:e.api_key,key:e.key},r));else if(n.match(t.ID_RE))i=y(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);g(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,t.LOADER_CLASS),a.appendChild(o);let s=t.getElementComputedStyle(e.aspectWrapper,`padding-top`),c=t.getElementComputedStyle(e.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let t=document.createElement(`div`);g(t,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),t.appendChild(a),e.aspectWrapper.appendChild(t)}else e.aspectWrapper.appendChild(a)}function z(e,t){let n=0;for(let r=0;r1&&z(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var H=[];function U(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),H.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{V(this.widget)},t.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),G(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},t.LAZY_IFRAME_SHOW_TIMEOUT)}};function ce(){t.on(`load`,e=>{if(!e){let e=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&q(e)})}function q(e){let n=h(e),r=e.getAttribute(`data-iframely-url`),i=e.hasAttribute(`data-img-created`)||e.hasAttribute(`data-img`),a=!i&&t.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let e={v:t.VERSION,app:1,theme:t.config.theme};!a&&t.config.intersection&&(e.lazy=1),r=y(r,e)}a&&e.setAttribute(`loading`,`lazy`),i&&t.SUPPORT_IFRAME_LOADING_ATTR&&e.setAttribute(`loading`,`edge`),e.setAttribute(`src`,r||``),e.removeAttribute(`data-iframely-url`),t.trigger(`iframe-ready`,e)}function le(){t.on(`message`,(e,n)=>{n.method===`cancelWidget`&&t.cancelWidget(e)}),t.cancelWidget=e=>{if(!e){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=e.maxWidthWrapper&&e.maxWidthWrapper.parentNode,i=e.maxWidthWrapper;if(t.config&&t.config.parent){let a=n(e.maxWidthWrapper,String(t.config.parent));a&&(r=a.parentNode,i=a)}if(e.url){let n=e.iframe&&e.iframe.textContent;t.triggerAsync(`cancel`,e.url,r,n,i.nextSibling)}r.removeChild(i)}}var ue={border:``,"border-radius":``,"box-shadow":``,overflow:``},de={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function fe(){t.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),J(e,n)):t.method===`setIframelyEmbedData`&&J(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),me(e,r)}})}function J(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,g(e.aspectWrapper,t)):g(e.iframe,t):!t&&e&&e.iframe&&(g(e.aspectWrapper,ue),g(e.iframe,de))}function pe(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function me(e,n){if(n&&Object.keys(n).length>0&&e){let r=pe(e),i=window.getComputedStyle(e.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),g(e.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&e.iframe&&e.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&g(e.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(e.iframe).getPropertyValue(`height`);i&&i!==s&&t.triggerAsync(`heightChanged`,e.iframe,i,s)}}function he(){t.on(`message`,(e,n)=>{(n.method===`open-href`||n.method===`click`)&&t.trigger(n.method,n.href)}),t.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},t.on(`open-href`,e=>{t.triggerAsync(`click`,e),t.openHref(e)})}function ge(){t.on(`message`,(e,n)=>{n.method===`setIframelyEmbedOptions`&&t.trigger(`options`,e,n.data)})}function _e(){t.widgets=t.widgets||{},t.widgets.load=t.load,t.extendOptions=t.configure,t.events||(t.events={},t.events.on=t.on,t.events.trigger=t.trigger),t.on(`cancel`,(e,n,r,i)=>{if(t.RECOVER_HREFS_ON_CANCEL&&!r&&(r=e),e&&n&&r&&r!==``){let t=document.createElement(`a`);t.setAttribute(`href`,e),t.setAttribute(`target`,`_blank`),t.setAttribute(`rel`,`noopener`),t.textContent=r,i?n.insertBefore(t,i):n.appendChild(t)}})}var Y=/^_./,X=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function ve(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let n=[],r=Object.keys(e),i=0;if(r.forEach(r=>{let a={},o,s=e[r];s.key=r;let c=!1,l=s.values?Object.keys(s.values):void 0,u,d;if(l&&l.length===1&&(c=!0,u=l[0],d=s.values[u]),a.label=X(d||s.label,t),a.key=s.key,c||typeof s.value==`boolean`)c?a.checked=u===s.value||!u&&!s.value:a.checked=s.value,i++,n.push({type:`checkbox`,context:a,order:+!Y.test(r),getQuery:e=>{let t;t=c?e?u:``:e;let n={};return c?t===``||(n[s.key]=t):n[s.key]=e,n}});else if((typeof s.value==`number`||typeof s.value==`string`)&&!s.values){let e=s.range&&typeof s.range.min==`number`&&typeof s.range.max==`number`,i=typeof s.value==`number`;a.value=s.value,o=e=>{let t={};return e===``||(t[s.key]=e),t},e?(a.min=s.range.min,a.max=s.range.max,n.push({type:`range`,context:a,order:9,getQuery:o})):(a.placeholder=X(s.placeholder||``,t),a.inputType=i?`number`:`text`,n.push({type:`text`,context:a,order:/start/i.test(r)?7:8,getQuery:o}))}else if(s.values)if(a.value=s.value+``,o=e=>{let t={};return e===``||(t[s.key]=e),t},Object.keys(s.values).length<=3){s.label?a.label=X(s.label,t):a.label=!1;let e=0,i=!1,c=Object.values(s.values);for(;e8,e++;a.inline=!i,a.items=[],Object.keys(s.values).forEach((e,n)=>{a.items.push({id:a.key+`-`+n,value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`radio`,context:a,order:i?-3:/theme/.test(r)?-1:-2,getQuery:o})}else a.items=[],Object.keys(s.values).forEach(e=>{a.items.push({value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`select`,context:a,order:5,getQuery:o})}),n.sort((e,t)=>e.order-t.order),n.forEach(e=>{delete e.order}),i>0){let e=[],t;return n.forEach((r,a)=>{if(r.type===`checkbox`){let o=i>2&&a>0&&!Y.test(r.context.key)&&n[a-1].type===`checkbox`&&Y.test(n[a-1].context.key);(!t||o)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return n}var Z={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(e,n)=>{let r=e[0];t.addEventListener(r,`click`,()=>{r.select()}),t.addEventListener(r,`blur`,n),t.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},Q={};function ye(e){let n=e.options,r=e.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,e);return}if(!n){r.innerHTML=``;return}let i=ve(n,e.translator),a=e.id,o=e.renderer,s=Q[a]=Q[a]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(s[e]=n[e].value)});function c(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=Z[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(i),e}function l(){let e=c();Object.keys(s).forEach(t=>{(s[t]===e[t]||e[t]===void 0)&&delete e[t]}),t.trigger(`options-changed`,a,r,e)}let u=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=u(e.context.elements)),t+=o(e.type,e.context||{})}),t};r.innerHTML=u(i);let d=e=>{e.forEach(e=>{if(e.context&&e.context.elements)d(e.context.elements);else{let n=Z[e.type];if(e.context){let i=r.querySelectorAll(`[name="`+e.context.key+`"]`);e.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,l):i.forEach(e=>{t.addEventListener(e,`change`,l)}):console.warn(`No inputs found for option`,e.context.key)}}})};d(i)}var be={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},$=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>be[e]),xe={checkbox:e=>` +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,unload:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{},typeof document<`u`&&(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(t.config.autorun===void 0||t.config.autorun!==!1)&&t.trigger(`load`)});function n(){t.VERSION=1,t.ASPECT_WRAPPER_CLASS=`iframely-responsive`,t.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,t.LOADER_CLASS=`iframely-loader`,t.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],t.CDN=t.CDN||t.DOMAINS[0],t.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,t.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,t.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],t.SUPPORTED_THEMES=[`auto`,`light`,`dark`],t.LAZY_IFRAME_SHOW_TIMEOUT=3e3,t.LAZY_IFRAME_FADE_TIMEOUT=200,t.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,t.RECOVER_HREFS_ON_CANCEL=!1,t.SHADOW=`iframely-shadow`,t.SUPPORT_IFRAME_LOADING_ATTR=!0}var r=e=>{window.requestAnimationFrame(e)},i={};function a(e,n,a){(i[e]||[]).forEach(e=>{n?r(()=>{e.apply(t,a)}):e.apply(t,a)}),e===`init`&&(i[e]=[])}function o(){t.on=(e,t)=>{(i[e]=i[e]||[]).push(t)},t.trigger=(e,...t)=>{a(e,!1,t)},t.triggerAsync=(e,...t)=>{a(e,!0,t)}}function s(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function c(e,t){let n;for(let r=0;r{let t=l(document,e);return t||=u(document,e),t},s((e,n)=>{if(n&&(n.method||n.type||n.context)){let r=t.findIframe({contentWindow:e.source,src:n.src||n.context,domains:n.domains!==`all`&&t.DOMAINS.concat(t.CDN)});if(r){let e=h(r);e&&n.url&&(e.url=n.url),t.trigger(`message`,e,n)}}})}function f(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function p(){t.on(`init`,()=>{t.configure(x()),v(),t.config.theme&&t.setTheme(t.config.theme),S(t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)))}),t.load=function(...e){t.trigger(`load`,...e)},t.unload=e=>{let n=t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)),r=e||document,i=`iframe[src*="`+n.join(`"], iframe[src*="`)+`"], iframe[data-iframely-url]`,a=r.querySelectorAll(i);for(let e=0;ewindow.getComputedStyle(e).getPropertyValue(t),t.configure=e=>{e&&Object.keys(e).forEach(n=>{let r=e[n]===0||e[n]===`0`||e[n]===!1||e[n]===`false`?!1:e[n]===1||e[n]===`1`||e[n]===!0||e[n]===`true`||e[n];t.config[n]!==!1&&(t.config[n]=r)})}}function m(e,n){let r=e.parentNode;if(!r||r.nodeName!==`DIV`||C(r)>2||n&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||C(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function ee(e){let n=e.parentNode,r=document.createElement(`div`);r.className=t.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=t.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,e),{aspectWrapper:i,maxWidthWrapper:r}}function h(e){let t=m(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=T(r);e.url&&(n.url=e.url)}return n}function g(e,n){e&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=e.style,o=a[r];t.getElementComputedStyle(e,r)!=i&&!(e.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function _(e){t.config.nonce&&(e.nonce=t.config.nonce)}function v(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,_(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function y(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function b(e,n,r){let i=e;if(/^(https?:)?\/\//i.test(e)||(i=(n&&n.CDN||t.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=y(i,n)),r&&r.length){let e={},n=Object.keys(t.config);for(let i=0;i0)return e}}return{}}function S(e){let n=document.querySelectorAll(`iframe[src*="`+(e||t.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{f({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},ne(e)),D[t]=n),n}function ne(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function O(){t.on(`init`,()=>{t.configure({intersection:1})}),t.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},te(n).observe(e.iframe)}}),t.on(`unload-widget`,e=>{Object.values(D).forEach(t=>t.unobserve(e.iframe))}),t.on(`unload`,e=>{e||Object.keys(D).forEach(e=>{D[e].disconnect(),delete D[e]})})}function k(e,t){f({method:`setTheme`,data:t},`*`,e.contentWindow)}function A(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{e&&t.SUPPORTED_THEMES.indexOf(e)>-1?n?n.tagName===`IFRAME`?k(n,e):A(n,e):(t.configure({theme:e}),A(document,e),t.trigger(`set-theme`,e)):console.warn(`Using iframely.setTheme with not supported theme: "`+e+`". Supported themes are: `+t.SUPPORTED_THEMES.join(`, `))}}var M={};function re(){t.on(`load`,e=>{if(!e&&t.config.import!==!1&&oe()&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&ie(e)}}),t.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=M[e.uri];if(n)for(let r=0;r{t.trigger(`import-loaded`,e),e.widgets.forEach(n=>{t.trigger(`load`,n,e)}),N()},t.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,t.on(`import-widget-ready`,P),t.on(`unload`,e=>{e||(delete t.import,Object.keys(M).forEach(e=>{delete M[e]}))}),t.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function ie(e){let n=E(),r=[],i=[],a=null;function o(e,t){M[e]||(M[e]=[]),M[e].push(t)}function s(e){let n=e.getAttribute(`data-iframely-url`),s=n.match(t.ID_RE),c=s&&s[1],l=T(n,t.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let e=n.match(t.BASE_RE);l.CDN=e&&e[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?t.trigger(`load`,e):c?(e.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,e)):(u||=e.getAttribute(`href`),(a.key||a.api_key||t.config.api_key||t.config.key)&&u?(e.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,e)):t.trigger(`load`,e))}for(let t=0;t0||i.length>0?(a||={},a.touch=t.isTouch(),a.flash=!1,a.app=1,t.config.theme&&(a.theme=t.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=t.VERSION,n.src=b(`/api/import/v2`,a,t.SUPPORTED_QUERY_STRING),n.onerror=()=>{N()},document.head.appendChild(n),t.import=n):(N(),t.trigger(`load`))}function ae(e,n,r){let i=e.cancel,a=e.shadow,o=e.renderEvent,s=m(n,!0);if(i)t.cancelWidget(h(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=e.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:e.context,stylesIds:e.stylesIds,stylesDict:r.commonShadowStyles};t.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),t.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),F(i);c.removeChild(l),o&&setTimeout(()=>{P(c)},t.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function N(){delete t.import;let e=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function F(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=E();r.type=`text/javascript`;for(let e=0;e{if(e&&e.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),e.appendChild(r),t.trigger(`load`,r)}}),t.on(`load`,e=>{if(!e&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&L(e)})}function L(e){if(!e.getAttribute(`data-iframely-url`)&&!e.getAttribute(`href`))return;let n,r=e.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=b(r,{v:t.VERSION,app:1,theme:t.config.theme});else if((t.config.api_key||t.config.key)&&t.CDN){if(!e.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,e);return}n=b(`/api/iframe`,{url:e.getAttribute(`href`),v:t.VERSION,app:1,theme:t.config.theme},t.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)e.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),e.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,e.getAttribute(`data-img`));let i=e.hasAttribute(`data-lazy`)||e.hasAttribute(`data-img`)||/&lazy=1/.test(n)||t.config.lazy,a=e.textContent;a&&a!==``&&(r.textContent=a);let o=m(e,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=ee(e),e.parentNode.removeChild(e);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),t.trigger(`load`,r)):(r.setAttribute(`src`,n),t.trigger(`iframe-ready`,r))}}function R(){t.on(`load`,e=>{if(e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)){let n=e.getAttribute(`data-img`);e.removeAttribute(`data-img`),e.setAttribute(`data-img-created`,``);let r=h(e),i=e.getAttribute(`data-iframely-url`);r&&(z(r,i,n),i=y(i,{img:1}),e.setAttribute(`data-iframely-url`,i),new q(r)),t.trigger(`load`,e)}}),t.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(H(e),n=G(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=G(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=G(e),n?.registerLoadingTimeout())}),t.on(`unload-widget`,e=>{G(e)?.deactivate()})}function z(e,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let e=T(n),r={};for(let t in e)t.indexOf(`_`)===0&&(r[t]=e[t]);if(e.media&&(r.media=e.media),n.match(/\/api\/iframe/))i=b(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:e.url,api_key:e.api_key,key:e.key},r));else if(n.match(t.ID_RE))i=b(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);g(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,t.LOADER_CLASS),a.appendChild(o);let s=t.getElementComputedStyle(e.aspectWrapper,`padding-top`),c=t.getElementComputedStyle(e.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let t=document.createElement(`div`);g(t,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),t.appendChild(a),e.aspectWrapper.appendChild(t)}else e.aspectWrapper.appendChild(a)}function B(e,t){let n=0;for(let r=0;r1&&B(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var U=[];function W(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),U.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{H(this.widget)},t.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),K(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},t.LAZY_IFRAME_SHOW_TIMEOUT)}};function se(){t.on(`load`,e=>{if(!e){let e=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&ce(e)})}function ce(e){let n=h(e),r=e.getAttribute(`data-iframely-url`),i=e.hasAttribute(`data-img-created`)||e.hasAttribute(`data-img`),a=!i&&t.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let e={v:t.VERSION,app:1,theme:t.config.theme};!a&&t.config.intersection&&(e.lazy=1),r=b(r,e)}a&&e.setAttribute(`loading`,`lazy`),i&&t.SUPPORT_IFRAME_LOADING_ATTR&&e.setAttribute(`loading`,`edge`),e.setAttribute(`src`,r||``),e.removeAttribute(`data-iframely-url`),t.trigger(`iframe-ready`,e)}function le(){t.on(`message`,(e,n)=>{n.method===`cancelWidget`&&t.cancelWidget(e)}),t.cancelWidget=e=>{if(!e){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=e.maxWidthWrapper&&e.maxWidthWrapper.parentNode,i=e.maxWidthWrapper;if(t.config&&t.config.parent){let a=n(e.maxWidthWrapper,String(t.config.parent));a&&(r=a.parentNode,i=a)}if(e.url){let n=e.iframe&&e.iframe.textContent;t.triggerAsync(`cancel`,e.url,r,n,i.nextSibling)}r.removeChild(i)}}var ue={border:``,"border-radius":``,"box-shadow":``,overflow:``},de={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function fe(){t.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),J(e,n)):t.method===`setIframelyEmbedData`&&J(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),me(e,r)}})}function J(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,g(e.aspectWrapper,t)):g(e.iframe,t):!t&&e&&e.iframe&&(g(e.aspectWrapper,ue),g(e.iframe,de))}function pe(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function me(e,n){if(n&&Object.keys(n).length>0&&e){let r=pe(e),i=window.getComputedStyle(e.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),g(e.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&e.iframe&&e.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&g(e.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(e.iframe).getPropertyValue(`height`);i&&i!==s&&t.triggerAsync(`heightChanged`,e.iframe,i,s)}}function he(){t.on(`message`,(e,n)=>{(n.method===`open-href`||n.method===`click`)&&t.trigger(n.method,n.href)}),t.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},t.on(`open-href`,e=>{t.triggerAsync(`click`,e),t.openHref(e)})}function ge(){t.on(`message`,(e,n)=>{n.method===`setIframelyEmbedOptions`&&t.trigger(`options`,e,n.data)})}function _e(){t.widgets=t.widgets||{},t.widgets.load=t.load,t.extendOptions=t.configure,t.events||(t.events={},t.events.on=t.on,t.events.trigger=t.trigger),t.on(`cancel`,(e,n,r,i)=>{if(t.RECOVER_HREFS_ON_CANCEL&&!r&&(r=e),e&&n&&r&&r!==``){let t=document.createElement(`a`);t.setAttribute(`href`,e),t.setAttribute(`target`,`_blank`),t.setAttribute(`rel`,`noopener`),t.textContent=r,i?n.insertBefore(t,i):n.appendChild(t)}})}var Y=/^_./,X=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function ve(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let n=[],r=Object.keys(e),i=0;if(r.forEach(r=>{let a={},o,s=e[r];s.key=r;let c=!1,l=s.values?Object.keys(s.values):void 0,u,d;if(l&&l.length===1&&(c=!0,u=l[0],d=s.values[u]),a.label=X(d||s.label,t),a.key=s.key,c||typeof s.value==`boolean`)c?a.checked=u===s.value||!u&&!s.value:a.checked=s.value,i++,n.push({type:`checkbox`,context:a,order:+!Y.test(r),getQuery:e=>{let t;t=c?e?u:``:e;let n={};return c?t===``||(n[s.key]=t):n[s.key]=e,n}});else if((typeof s.value==`number`||typeof s.value==`string`)&&!s.values){let e=s.range&&typeof s.range.min==`number`&&typeof s.range.max==`number`,i=typeof s.value==`number`;a.value=s.value,o=e=>{let t={};return e===``||(t[s.key]=e),t},e?(a.min=s.range.min,a.max=s.range.max,n.push({type:`range`,context:a,order:9,getQuery:o})):(a.placeholder=X(s.placeholder||``,t),a.inputType=i?`number`:`text`,n.push({type:`text`,context:a,order:/start/i.test(r)?7:8,getQuery:o}))}else if(s.values)if(a.value=s.value+``,o=e=>{let t={};return e===``||(t[s.key]=e),t},Object.keys(s.values).length<=3){s.label?a.label=X(s.label,t):a.label=!1;let e=0,i=!1,c=Object.values(s.values);for(;e8,e++;a.inline=!i,a.items=[],Object.keys(s.values).forEach((e,n)=>{a.items.push({id:a.key+`-`+n,value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`radio`,context:a,order:i?-3:/theme/.test(r)?-1:-2,getQuery:o})}else a.items=[],Object.keys(s.values).forEach(e=>{a.items.push({value:e,label:X(s.values[e],t),checked:a.value===e})}),n.push({type:`select`,context:a,order:5,getQuery:o})}),n.sort((e,t)=>e.order-t.order),n.forEach(e=>{delete e.order}),i>0){let e=[],t;return n.forEach((r,a)=>{if(r.type===`checkbox`){let o=i>2&&a>0&&!Y.test(r.context.key)&&n[a-1].type===`checkbox`&&Y.test(n[a-1].context.key);(!t||o)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return n}var Z={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(e,n)=>{let r=e[0];t.addEventListener(r,`click`,()=>{r.select()}),t.addEventListener(r,`blur`,n),t.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},Q={};function ye(e){let n=e.options,r=e.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,e);return}if(!n){r.innerHTML=``;return}let i=ve(n,e.translator),a=e.id,o=e.renderer,s=Q[a]=Q[a]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(s[e]=n[e].value)});function c(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=Z[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(i),e}function l(){let e=c();Object.keys(s).forEach(t=>{(s[t]===e[t]||e[t]===void 0)&&delete e[t]}),t.trigger(`options-changed`,a,r,e)}let u=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=u(e.context.elements)),t+=o(e.type,e.context||{})}),t};r.innerHTML=u(i);let d=e=>{e.forEach(e=>{if(e.context&&e.context.elements)d(e.context.elements);else{let n=Z[e.type];if(e.context){let i=r.querySelectorAll(`[name="`+e.context.key+`"]`);e.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,l):i.forEach(e=>{t.addEventListener(e,`change`,l)}):console.warn(`No inputs found for option`,e.context.key)}}})};d(i)}var be={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},$=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>be[e]),xe={checkbox:e=>`
@@ -35,4 +35,4 @@
-
`},Se=(e,t)=>xe[e](t);function Ce(){t.buildOptionsForm=(e,t,n,r)=>{ye({id:e,formContainer:t,options:n,renderer:Se,translator:r})}}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),ee(),d(),re(),A(),ie(),F(),L(),ce(),le(),fe(),he(),ge(),_e(),Ce(),t.trigger(`init`))})(); \ No newline at end of file + `},Se=(e,t)=>xe[e](t);function Ce(){t.buildOptionsForm=(e,t,n,r)=>{ye({id:e,formContainer:t,options:n,renderer:Se,translator:r})}}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),p(),d(),O(),j(),re(),I(),R(),se(),le(),fe(),he(),ge(),_e(),Ce(),t.trigger(`init`))})(); \ No newline at end of file diff --git a/dist/embed.js b/dist/embed.js index f445c44..6a32172 100644 --- a/dist/embed.js +++ b/dist/embed.js @@ -10,6 +10,7 @@ trigger: noop, triggerAsync: noop, load: noop, + unload: noop, configure: noop, extendOptions: noop, setTheme: noop, @@ -211,6 +212,20 @@ iframely.load = function(...args) { iframely.trigger("load", ...args); }; + iframely.unload = (el) => { + const domains = iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, "")); + const root = el || document; + const selector = "iframe[src*=\"" + domains.join("\"], iframe[src*=\"") + "\"], iframe[data-iframely-url]"; + const iframes = root.querySelectorAll(selector); + for (let i = 0; i < iframes.length; i++) { + const widget = getWidget(iframes[i]); + if (widget) { + iframely.trigger("unload-widget", widget); + widget.maxWidthWrapper.remove(); + } + } + iframely.trigger("unload", el); + }; iframely.getElementComputedStyle = (el, style) => { return window.getComputedStyle(el).getPropertyValue(style); }; @@ -419,6 +434,15 @@ getObserver(options).observe(widget.iframe); } }); + iframely.on("unload-widget", (widget) => { + Object.values(observers).forEach((observer) => observer.unobserve(widget.iframe)); + }); + iframely.on("unload", (el) => { + if (!el) Object.keys(observers).forEach((key) => { + observers[key].disconnect(); + delete observers[key]; + }); + }); } //#endregion @@ -474,6 +498,14 @@ return "ontouchstart" in window || navigator.maxTouchPoints > 0; }; iframely.on("import-widget-ready", clearWrapperStylesAndClass); + iframely.on("unload", (el) => { + if (!el) { + delete iframely.import; + Object.keys(widgetsCache).forEach((key) => { + delete widgetsCache[key]; + }); + } + }); if (!iframely.addEventListener) iframely.addEventListener = (elem, type, eventHandle) => { if (!elem) return; elem.addEventListener(type, eventHandle, false); @@ -748,6 +780,9 @@ waitingWidget?.registerLoadingTimeout(); } }); + iframely.on("unload-widget", (widget) => { + findWaitingWidget(widget)?.deactivate(); + }); } function addPlaceholderThumbnail(widget, href, imageUrl) { let thumbHref; diff --git a/dist/embed.min.js b/dist/embed.min.js index 801b741..e7c4932 100644 --- a/dist/embed.min.js +++ b/dist/embed.min.js @@ -1 +1 @@ -(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{},typeof document<`u`&&(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(t.config.autorun===void 0||t.config.autorun!==!1)&&t.trigger(`load`)});function n(){t.VERSION=1,t.ASPECT_WRAPPER_CLASS=`iframely-responsive`,t.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,t.LOADER_CLASS=`iframely-loader`,t.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],t.CDN=t.CDN||t.DOMAINS[0],t.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,t.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,t.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],t.SUPPORTED_THEMES=[`auto`,`light`,`dark`],t.LAZY_IFRAME_SHOW_TIMEOUT=3e3,t.LAZY_IFRAME_FADE_TIMEOUT=200,t.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,t.RECOVER_HREFS_ON_CANCEL=!1,t.SHADOW=`iframely-shadow`,t.SUPPORT_IFRAME_LOADING_ATTR=!0}var r=e=>{window.requestAnimationFrame(e)},i={};function a(e,n,a){(i[e]||[]).forEach(e=>{n?r(()=>{e.apply(t,a)}):e.apply(t,a)}),e===`init`&&(i[e]=[])}function o(){t.on=(e,t)=>{(i[e]=i[e]||[]).push(t)},t.trigger=(e,...t)=>{a(e,!1,t)},t.triggerAsync=(e,...t)=>{a(e,!0,t)}}function s(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function c(e,t){let n;for(let r=0;r{let t=l(document,e);return t||=u(document,e),t},s((e,n)=>{if(n&&(n.method||n.type||n.context)){let r=t.findIframe({contentWindow:e.source,src:n.src||n.context,domains:n.domains!==`all`&&t.DOMAINS.concat(t.CDN)});if(r){let e=h(r);e&&n.url&&(e.url=n.url),t.trigger(`message`,e,n)}}})}function f(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function ee(){t.on(`init`,()=>{t.configure(x()),v(),t.config.theme&&t.setTheme(t.config.theme),S(t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)))}),t.load=function(...e){t.trigger(`load`,...e)},t.getElementComputedStyle=(e,t)=>window.getComputedStyle(e).getPropertyValue(t),t.configure=e=>{e&&Object.keys(e).forEach(n=>{let r=e[n]===0||e[n]===`0`||e[n]===!1||e[n]===`false`?!1:e[n]===1||e[n]===`1`||e[n]===!0||e[n]===`true`||e[n];t.config[n]!==!1&&(t.config[n]=r)})}}function p(e,n){let r=e.parentNode;if(!r||r.nodeName!==`DIV`||C(r)>2||n&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||C(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function m(e){let n=e.parentNode,r=document.createElement(`div`);r.className=t.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=t.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,e),{aspectWrapper:i,maxWidthWrapper:r}}function h(e){let t=p(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=T(r);e.url&&(n.url=e.url)}return n}function g(e,n){e&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=e.style,o=a[r];t.getElementComputedStyle(e,r)!=i&&!(e.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function _(e){t.config.nonce&&(e.nonce=t.config.nonce)}function v(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,_(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function y(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function b(e,n,r){let i=e;if(/^(https?:)?\/\//i.test(e)||(i=(n&&n.CDN||t.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=y(i,n)),r&&r.length){let e={},n=Object.keys(t.config);for(let i=0;i0)return e}}return{}}function S(e){let n=document.querySelectorAll(`iframe[src*="`+(e||t.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{f({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},k(e)),D[t]=n),n}function k(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function A(){t.on(`init`,()=>{t.configure({intersection:1})}),t.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},O(n).observe(e.iframe)}})}function j(e,t){f({method:`setTheme`,data:t},`*`,e.contentWindow)}function M(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{e&&t.SUPPORTED_THEMES.indexOf(e)>-1?n?n.tagName===`IFRAME`?j(n,e):M(n,e):(t.configure({theme:e}),M(document,e),t.trigger(`set-theme`,e)):console.warn(`Using iframely.setTheme with not supported theme: "`+e+`". Supported themes are: `+t.SUPPORTED_THEMES.join(`, `))}}var N={};function P(){t.on(`load`,e=>{if(!e&&t.config.import!==!1&&R()&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&F(e)}}),t.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=N[e.uri];if(n)for(let r=0;r{t.trigger(`import-loaded`,e),e.widgets.forEach(n=>{t.trigger(`load`,n,e)}),L()},t.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,t.on(`import-widget-ready`,z),t.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function F(e){let n=E(),r=[],i=[],a=null;function o(e,t){N[e]||(N[e]=[]),N[e].push(t)}function s(e){let n=e.getAttribute(`data-iframely-url`),s=n.match(t.ID_RE),c=s&&s[1],l=T(n,t.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let e=n.match(t.BASE_RE);l.CDN=e&&e[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?t.trigger(`load`,e):c?(e.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,e)):(u||=e.getAttribute(`href`),(a.key||a.api_key||t.config.api_key||t.config.key)&&u?(e.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,e)):t.trigger(`load`,e))}for(let t=0;t0||i.length>0?(a||={},a.touch=t.isTouch(),a.flash=!1,a.app=1,t.config.theme&&(a.theme=t.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=t.VERSION,n.src=b(`/api/import/v2`,a,t.SUPPORTED_QUERY_STRING),n.onerror=()=>{L()},document.head.appendChild(n),t.import=n):(L(),t.trigger(`load`))}function I(e,n,r){let i=e.cancel,a=e.shadow,o=e.renderEvent,s=p(n,!0);if(i)t.cancelWidget(h(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=e.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:e.context,stylesIds:e.stylesIds,stylesDict:r.commonShadowStyles};t.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),t.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),B(i);c.removeChild(l),o&&setTimeout(()=>{z(c)},t.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function L(){delete t.import;let e=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function B(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=E();r.type=`text/javascript`;for(let e=0;e{if(e&&e.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),e.appendChild(r),t.trigger(`load`,r)}}),t.on(`load`,e=>{if(!e&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&H(e)})}function H(e){if(!e.getAttribute(`data-iframely-url`)&&!e.getAttribute(`href`))return;let n,r=e.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=b(r,{v:t.VERSION,app:1,theme:t.config.theme});else if((t.config.api_key||t.config.key)&&t.CDN){if(!e.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,e);return}n=b(`/api/iframe`,{url:e.getAttribute(`href`),v:t.VERSION,app:1,theme:t.config.theme},t.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)e.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),e.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,e.getAttribute(`data-img`));let i=e.hasAttribute(`data-lazy`)||e.hasAttribute(`data-img`)||/&lazy=1/.test(n)||t.config.lazy,a=e.textContent;a&&a!==``&&(r.textContent=a);let o=p(e,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=m(e),e.parentNode.removeChild(e);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),t.trigger(`load`,r)):(r.setAttribute(`src`,n),t.trigger(`iframe-ready`,r))}}function U(){t.on(`load`,e=>{if(e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)){let n=e.getAttribute(`data-img`);e.removeAttribute(`data-img`),e.setAttribute(`data-img-created`,``);let r=h(e),i=e.getAttribute(`data-iframely-url`);r&&(W(r,i,n),i=y(i,{img:1}),e.setAttribute(`data-iframely-url`,i),new ne(r)),t.trigger(`load`,e)}}),t.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(q(e),n=X(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=X(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=X(e),n?.registerLoadingTimeout())})}function W(e,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let e=T(n),r={};for(let t in e)t.indexOf(`_`)===0&&(r[t]=e[t]);if(e.media&&(r.media=e.media),n.match(/\/api\/iframe/))i=b(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:e.url,api_key:e.api_key,key:e.key},r));else if(n.match(t.ID_RE))i=b(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);g(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,t.LOADER_CLASS),a.appendChild(o);let s=t.getElementComputedStyle(e.aspectWrapper,`padding-top`),c=t.getElementComputedStyle(e.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let t=document.createElement(`div`);g(t,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),t.appendChild(a),e.aspectWrapper.appendChild(t)}else e.aspectWrapper.appendChild(a)}function G(e,t){let n=0;for(let r=0;r1&&G(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var J=[];function Y(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),J.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{q(this.widget)},t.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),Z(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},t.LAZY_IFRAME_SHOW_TIMEOUT)}};function re(){t.on(`load`,e=>{if(!e){let e=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&ie(e)})}function ie(e){let n=h(e),r=e.getAttribute(`data-iframely-url`),i=e.hasAttribute(`data-img-created`)||e.hasAttribute(`data-img`),a=!i&&t.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let e={v:t.VERSION,app:1,theme:t.config.theme};!a&&t.config.intersection&&(e.lazy=1),r=b(r,e)}a&&e.setAttribute(`loading`,`lazy`),i&&t.SUPPORT_IFRAME_LOADING_ATTR&&e.setAttribute(`loading`,`edge`),e.setAttribute(`src`,r||``),e.removeAttribute(`data-iframely-url`),t.trigger(`iframe-ready`,e)}function ae(){t.on(`message`,(e,n)=>{n.method===`cancelWidget`&&t.cancelWidget(e)}),t.cancelWidget=e=>{if(!e){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=e.maxWidthWrapper&&e.maxWidthWrapper.parentNode,i=e.maxWidthWrapper;if(t.config&&t.config.parent){let a=n(e.maxWidthWrapper,String(t.config.parent));a&&(r=a.parentNode,i=a)}if(e.url){let n=e.iframe&&e.iframe.textContent;t.triggerAsync(`cancel`,e.url,r,n,i.nextSibling)}r.removeChild(i)}}var oe={border:``,"border-radius":``,"box-shadow":``,overflow:``},Q={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function se(){t.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),$(e,n)):t.method===`setIframelyEmbedData`&&$(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),le(e,r)}})}function $(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,g(e.aspectWrapper,t)):g(e.iframe,t):!t&&e&&e.iframe&&(g(e.aspectWrapper,oe),g(e.iframe,Q))}function ce(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function le(e,n){if(n&&Object.keys(n).length>0&&e){let r=ce(e),i=window.getComputedStyle(e.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),g(e.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&e.iframe&&e.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&g(e.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(e.iframe).getPropertyValue(`height`);i&&i!==s&&t.triggerAsync(`heightChanged`,e.iframe,i,s)}}function ue(){t.on(`message`,(e,n)=>{(n.method===`open-href`||n.method===`click`)&&t.trigger(n.method,n.href)}),t.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},t.on(`open-href`,e=>{t.triggerAsync(`click`,e),t.openHref(e)})}function de(){t.on(`message`,(e,n)=>{n.method===`setIframelyEmbedOptions`&&t.trigger(`options`,e,n.data)})}function fe(){t.widgets=t.widgets||{},t.widgets.load=t.load,t.extendOptions=t.configure,t.events||(t.events={},t.events.on=t.on,t.events.trigger=t.trigger),t.on(`cancel`,(e,n,r,i)=>{if(t.RECOVER_HREFS_ON_CANCEL&&!r&&(r=e),e&&n&&r&&r!==``){let t=document.createElement(`a`);t.setAttribute(`href`,e),t.setAttribute(`target`,`_blank`),t.setAttribute(`rel`,`noopener`),t.textContent=r,i?n.insertBefore(t,i):n.appendChild(t)}})}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),ee(),d(),A(),te(),P(),V(),U(),re(),ae(),se(),ue(),de(),fe(),t.trigger(`init`))})(); \ No newline at end of file +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,unload:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{},typeof document<`u`&&(e=>{(document.readyState===`complete`||document.readyState===`interactive`)&&setTimeout(e,0),document.addEventListener(`DOMContentLoaded`,e)})(()=>{(t.config.autorun===void 0||t.config.autorun!==!1)&&t.trigger(`load`)});function n(){t.VERSION=1,t.ASPECT_WRAPPER_CLASS=`iframely-responsive`,t.MAXWIDTH_WRAPPER_CLASS=`iframely-embed`,t.LOADER_CLASS=`iframely-loader`,t.DOMAINS=[`cdn.iframe.ly`,`iframe.ly`,`if-cdn.com`,`iframely.net`],t.CDN=t.CDN||t.DOMAINS[0],t.BASE_RE=/^(?:https?:)?\/\/[^/]+/i,t.ID_RE=/^(?:https?:)?\/\/[^/]+\/(\w+-?\w+)(?:\?.*)?$/,t.SCRIPT_RE=/^(?:https?:|file:\/)?\/\/[^/]+(?:.+)?\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.CDN_RE=/^(?:https?:)?\/\/([^/]+)\/(?:embed|iframely)\.js(?:[^/]+)?$/i,t.SUPPORTED_QUERY_STRING=[`api_key`,`key`,`iframe`,`html5`,`playerjs`,`align`,`language`,`media`,`maxwidth`,`maxheight`,`lazy`,`import`,`parent`,`shadow`,`click_to_play`,`autoplay`,`mute`,`card`,`consent`,`theme`,/^_.+/],t.SUPPORTED_THEMES=[`auto`,`light`,`dark`],t.LAZY_IFRAME_SHOW_TIMEOUT=3e3,t.LAZY_IFRAME_FADE_TIMEOUT=200,t.CLEAR_WRAPPER_STYLES_TIMEOUT=3e3,t.RECOVER_HREFS_ON_CANCEL=!1,t.SHADOW=`iframely-shadow`,t.SUPPORT_IFRAME_LOADING_ATTR=!0}var r=e=>{window.requestAnimationFrame(e)},i={};function a(e,n,a){(i[e]||[]).forEach(e=>{n?r(()=>{e.apply(t,a)}):e.apply(t,a)}),e===`init`&&(i[e]=[])}function o(){t.on=(e,t)=>{(i[e]=i[e]||[]).push(t)},t.trigger=(e,...t)=>{a(e,!1,t)},t.triggerAsync=(e,...t)=>{a(e,!0,t)}}function s(e){window.addEventListener(`message`,t=>{let n;try{typeof t.data==`string`?n=JSON.parse(t.data):typeof t.data==`object`&&(n=t.data)}catch{if(typeof t.data==`string`){let e=t.data.match(/heightxPYMx(\d+)/);e&&(n={method:`resize`,height:parseInt(e[1])+1,domains:`all`})}}e(t,n)},!1)}function c(e,t){let n;for(let r=0;r{let t=l(document,e);return t||=u(document,e),t},s((e,n)=>{if(n&&(n.method||n.type||n.context)){let r=t.findIframe({contentWindow:e.source,src:n.src||n.context,domains:n.domains!==`all`&&t.DOMAINS.concat(t.CDN)});if(r){let e=h(r);e&&n.url&&(e.url=n.url),t.trigger(`message`,e,n)}}})}function f(e,t,n){typeof e==`object`&&(e.context=document.location.href);let r=JSON.stringify(e);t||=`*`,n||=window.parent,n.postMessage(r,t.replace(/([^:]+:\/\/[^/]+).*/,`$1`))}function p(){t.on(`init`,()=>{t.configure(x()),v(),t.config.theme&&t.setTheme(t.config.theme),S(t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)))}),t.load=function(...e){t.trigger(`load`,...e)},t.unload=e=>{let n=t.DOMAINS.concat(t.CDN.replace(/^https?:\/\//,``)),r=e||document,i=`iframe[src*="`+n.join(`"], iframe[src*="`)+`"], iframe[data-iframely-url]`,a=r.querySelectorAll(i);for(let e=0;ewindow.getComputedStyle(e).getPropertyValue(t),t.configure=e=>{e&&Object.keys(e).forEach(n=>{let r=e[n]===0||e[n]===`0`||e[n]===!1||e[n]===`false`?!1:e[n]===1||e[n]===`1`||e[n]===!0||e[n]===`true`||e[n];t.config[n]!==!1&&(t.config[n]=r)})}}function m(e,n){let r=e.parentNode;if(!r||r.nodeName!==`DIV`||C(r)>2||n&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS||!n&&r.style.position!==`relative`&&r.getAttribute(`class`)!==t.ASPECT_WRAPPER_CLASS)return;let i=r.parentNode;if(!(!i||i.nodeName!==`DIV`||C(i)>1||n&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)===-1||!n&&i.getAttribute(`class`)&&!i.getAttribute(`class`).match(/iframely/i)))return{aspectWrapper:r,maxWidthWrapper:i}}function ee(e){let n=e.parentNode,r=document.createElement(`div`);r.className=t.MAXWIDTH_WRAPPER_CLASS;let i=document.createElement(`div`);return i.className=t.ASPECT_WRAPPER_CLASS,r.appendChild(i),n.insertBefore(r,e),{aspectWrapper:i,maxWidthWrapper:r}}function h(e){let t=m(e);if(!t)return;let n={iframe:e,aspectWrapper:t.aspectWrapper,maxWidthWrapper:t.maxWidthWrapper},r=e.getAttribute(`src`);if(e.nodeName===`A`&&e.hasAttribute(`href`))n.url=e.getAttribute(`href`);else if(r&&/url=/.test(r)){let e=T(r);e.url&&(n.url=e.url)}return n}function g(e,n){e&&Object.keys(n).forEach(r=>{let i=n[r];(typeof i==`number`||typeof i==`string`&&/^(\d+)?\.?(\d+)$/.test(i))&&(i+=`px`);let a=e.style,o=a[r];t.getElementComputedStyle(e,r)!=i&&!(e.className==`iframely-responsive`&&r===`paddingBottom`&&!o&&/^56\.2\d+%$/.test(i))&&!(r===`max-width`&&i===`keep`)&&(a[r]=i||``)})}function _(e){t.config.nonce&&(e.nonce=t.config.nonce)}function v(){let e=`iframely-styles`,t=document.getElementById(e);t||(t=document.createElement(`style`),t.id=e,_(t),t.innerHTML=`.iframely-responsive{top:0;left:0;width:100%;height:0;position:relative;padding-bottom:56.25%;box-sizing:border-box;}.iframely-responsive>*{top:0;left:0;width:100%;height:100%;position:absolute;border:0;box-sizing:border-box;}`,document.getElementsByTagName(`head`)[0].appendChild(t))}function y(e,t){let n=``;return Object.keys(t).forEach(r=>{let i=t[r];if(Array.isArray(i)){let e=i.map(e=>r+`=`+encodeURIComponent(e));n+=`&`+e.join(`&`)}else i!==void 0&&e.indexOf(r+`=`)===-1&&(typeof i==`boolean`&&r.charAt(0)!==`_`&&(i=+!!i),n+=`&`+r+`=`+encodeURIComponent(i))}),e+(n===``?``:(e.indexOf(`?`)>-1?`&`:`?`)+n.replace(/^&/,``))}function b(e,n,r){let i=e;if(/^(https?:)?\/\//i.test(e)||(i=(n&&n.CDN||t.CDN)+i,n&&delete n.CDN),/^(?:https?:)?\/\//i.test(i)||(i=`//`+i),n&&(i=y(i,n)),r&&r.length){let e={},n=Object.keys(t.config);for(let i=0;i0)return e}}return{}}function S(e){let n=document.querySelectorAll(`iframe[src*="`+(e||t.DOMAINS).join(`"], iframe[src*="`)+`"]`);for(let e=0;e{t.forEach(t=>{f({method:`intersection`,entry:{isIntersecting:t.isIntersecting},options:e},`*`,t.target.contentWindow)})},k(e)),D[t]=n),n}function k(e){let t={};return e&&e.threshold&&(t.threshold=e.threshold),e&&e.margin&&(t.rootMargin=e.margin+`px `+e.margin+`px `+e.margin+`px `+e.margin+`px`),t}function A(){t.on(`init`,()=>{t.configure({intersection:1})}),t.on(`message`,(e,t)=>{if(t.method===`send-intersections`&&e.iframe){let n=t.options;n||={margin:1e3},O(n).observe(e.iframe)}}),t.on(`unload-widget`,e=>{Object.values(D).forEach(t=>t.unobserve(e.iframe))}),t.on(`unload`,e=>{e||Object.keys(D).forEach(e=>{D[e].disconnect(),delete D[e]})})}function j(e,t){f({method:`setTheme`,data:t},`*`,e.contentWindow)}function M(e,t){let n=e.getElementsByTagName(`iframe`);for(let e=0;e{e&&t.SUPPORTED_THEMES.indexOf(e)>-1?n?n.tagName===`IFRAME`?j(n,e):M(n,e):(t.configure({theme:e}),M(document,e),t.trigger(`set-theme`,e)):console.warn(`Using iframely.setTheme with not supported theme: "`+e+`". Supported themes are: `+t.SUPPORTED_THEMES.join(`, `))}}var N={};function P(){t.on(`load`,e=>{if(!e&&t.config.import!==!1&&R()&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);e.length>1&&F(e)}}),t.on(`load`,(e,t)=>{if(e&&!(e instanceof Element)&&e.uri&&(e.html||e.cancel)){let n=N[e.uri];if(n)for(let r=0;r{t.trigger(`import-loaded`,e),e.widgets.forEach(n=>{t.trigger(`load`,n,e)}),L()},t.isTouch=()=>`ontouchstart`in window||navigator.maxTouchPoints>0,t.on(`import-widget-ready`,z),t.on(`unload`,e=>{e||(delete t.import,Object.keys(N).forEach(e=>{delete N[e]}))}),t.addEventListener||=(e,t,n)=>{e&&e.addEventListener(t,n,!1)}}function F(e){let n=E(),r=[],i=[],a=null;function o(e,t){N[e]||(N[e]=[]),N[e].push(t)}function s(e){let n=e.getAttribute(`data-iframely-url`),s=n.match(t.ID_RE),c=s&&s[1],l=T(n,t.SUPPORTED_QUERY_STRING.concat(`url`)),u=l.url;delete l.url;let d=l.import===`0`||l.import===`false`||l.playerjs===`1`||l.playerjs===`true`;if(!d){let e=n.match(t.BASE_RE);l.CDN=e&&e[0],a?JSON.stringify(l,Object.keys(l).sort())!==JSON.stringify(a,Object.keys(a).sort())&&(d=!0):a=l}d?t.trigger(`load`,e):c?(e.setAttribute(`data-import-uri`,c),i.indexOf(c)===-1&&i.push(c),o(c,e)):(u||=e.getAttribute(`href`),(a.key||a.api_key||t.config.api_key||t.config.key)&&u?(e.setAttribute(`data-import-uri`,u),r.indexOf(u)===-1&&r.push(u),o(u,e)):t.trigger(`load`,e))}for(let t=0;t0||i.length>0?(a||={},a.touch=t.isTouch(),a.flash=!1,a.app=1,t.config.theme&&(a.theme=t.config.theme),r.length>0&&(a.uri=r),i.length>0&&(a.ids=i.join(`&`)),a.v=t.VERSION,n.src=b(`/api/import/v2`,a,t.SUPPORTED_QUERY_STRING),n.onerror=()=>{L()},document.head.appendChild(n),t.import=n):(L(),t.trigger(`load`))}function I(e,n,r){let i=e.cancel,a=e.shadow,o=e.renderEvent,s=m(n,!0);if(i)t.cancelWidget(h(n)||{maxWidthWrapper:n,iframe:n,url:n.getAttribute(`href`)});else{let i=document.createElement(`div`);i.innerHTML=e.html;let c,l;if(s&&!o?(c=s.aspectWrapper.parentNode,l=s.aspectWrapper,s.maxWidthWrapper.removeAttribute(`style`)):(c=n.parentNode,l=n),a){let n=document.createElement(`div`),a=n.attachShadow({mode:`open`});a.appendChild(i);let o={shadowRoot:a,shadowContainer:n,container:c,context:e.context,stylesIds:e.stylesIds,stylesDict:r.commonShadowStyles};t.trigger(`import-shadow-widget-before-render`,o),c.insertBefore(n,l),t.trigger(`import-shadow-widget-after-render`,o)}else c.insertBefore(i,l),B(i);c.removeChild(l),o&&setTimeout(()=>{z(c)},t.CLEAR_WRAPPER_STYLES_TIMEOUT)}}function L(){delete t.import;let e=document.querySelectorAll(`a[data-iframely-url][data-import-uri]`);for(let n=0;n4&&(n=null);let i=n&&n.parentNode;i&&i.getAttribute(`class`)&&i.getAttribute(`class`).split(` `).indexOf(t.MAXWIDTH_WRAPPER_CLASS)>-1&&(n.removeAttribute(`style`),n.removeAttribute(`class`),i.removeAttribute(`style`))}function B(e){function t(e,t){return!!e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()}function n(t){let n=t.text||t.textContent||t.innerHTML||``,r=E();r.type=`text/javascript`;for(let e=0;e{if(e&&e.nodeName&&typeof n==`string`){let r=document.createElement(`a`);r.setAttribute(`href`,n),e.appendChild(r),t.trigger(`load`,r)}}),t.on(`load`,e=>{if(!e&&!t.import){let e=document.querySelectorAll(`a[data-iframely-url]:not([data-import-uri])`);for(let n=0;n{e&&e.nodeName===`A`&&(e.getAttribute(`data-iframely-url`)||e.getAttribute(`href`))&&!e.hasAttribute(`data-import-uri`)&&H(e)})}function H(e){if(!e.getAttribute(`data-iframely-url`)&&!e.getAttribute(`href`))return;let n,r=e.getAttribute(`data-iframely-url`);if(r&&/^((?:https?:)?\/\/[^/]+)\/\w+/i.test(r))n=b(r,{v:t.VERSION,app:1,theme:t.config.theme});else if((t.config.api_key||t.config.key)&&t.CDN){if(!e.getAttribute(`href`)){console.warn(`Iframely cannot build embeds: "href" attribute missing in`,e);return}n=b(`/api/iframe`,{url:e.getAttribute(`href`),v:t.VERSION,app:1,theme:t.config.theme},t.SUPPORTED_QUERY_STRING)}else console.warn(`Iframely cannot build embeds: api key is required as query-string of embed.js`);if(!n)e.removeAttribute(`data-iframely-url`);else{let r=document.createElement(`iframe`);r.setAttribute(`allowfullscreen`,``),r.setAttribute(`allow`,`autoplay *; encrypted-media *; ch-prefers-color-scheme *`),e.hasAttribute(`data-img`)&&r.setAttribute(`data-img`,e.getAttribute(`data-img`));let i=e.hasAttribute(`data-lazy`)||e.hasAttribute(`data-img`)||/&lazy=1/.test(n)||t.config.lazy,a=e.textContent;a&&a!==``&&(r.textContent=a);let o=m(e,!0);if(o)for(;o.aspectWrapper.lastChild;)o.aspectWrapper.removeChild(o.aspectWrapper.lastChild);else o=ee(e),e.parentNode.removeChild(e);o.aspectWrapper.appendChild(r),i?(r.setAttribute(`data-iframely-url`,n),t.trigger(`load`,r)):(r.setAttribute(`src`,n),t.trigger(`iframe-ready`,r))}}function U(){t.on(`load`,e=>{if(e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)){let n=e.getAttribute(`data-img`);e.removeAttribute(`data-img`),e.setAttribute(`data-img-created`,``);let r=h(e),i=e.getAttribute(`data-iframely-url`);r&&(W(r,i,n),i=y(i,{img:1}),e.setAttribute(`data-iframely-url`,i),new ne(r)),t.trigger(`load`,e)}}),t.on(`message`,(e,t)=>{if(!e)return;let n;t.method===`widgetRendered`&&(q(e),n=X(e),n?.deactivate()),t.method===`begin-waiting-widget-render`&&(n=X(e),n?.clearLoadingTimeout()),t.method===`end-waiting-widget-render`&&(n=X(e),n?.registerLoadingTimeout())}),t.on(`unload-widget`,e=>{X(e)?.deactivate()})}function W(e,n,r){let i;if(r&&/^(https?:)?\/\//.test(r))i=r;else{let e=T(n),r={};for(let t in e)t.indexOf(`_`)===0&&(r[t]=e[t]);if(e.media&&(r.media=e.media),n.match(/\/api\/iframe/))i=b(n.match(/^(.+)\/api\/iframe/i)[1]+`/api/thumbnail`,Object.assign({url:e.url,api_key:e.api_key,key:e.key},r));else if(n.match(t.ID_RE))i=b(n.replace(/^((?:https?:)?\/\/[^/]+\/(\w+-?\w+))(?:\?.*)?$/,`$1/thumbnail`),r);else return}let a=document.createElement(`div`);g(a,{position:`absolute`,width:`100%`,height:`100%`,backgroundImage:`url('`+i+`')`,backgroundSize:`cover`,backgroundPosition:`center`});let o=document.createElement(`div`);o.setAttribute(`class`,t.LOADER_CLASS),a.appendChild(o);let s=t.getElementComputedStyle(e.aspectWrapper,`padding-top`),c=t.getElementComputedStyle(e.aspectWrapper,`padding-bottom`),l=s&&s.match(/^(\d+)px$/);if(l&&parseInt(l[1])&&c){let t=document.createElement(`div`);g(t,{top:`-`+s,width:`100%`,height:0,position:`relative`,paddingBottom:c}),t.appendChild(a),e.aspectWrapper.appendChild(t)}else e.aspectWrapper.appendChild(a)}function G(e,t){let n=0;for(let r=0;r1&&G(1,e.aspectWrapper);t&&t.nodeName===`DIV`&&e.aspectWrapper.removeChild(t)}var J=[];function Y(e){let t=0;for(;t{this.iframeOnLoad()}),this.registerLoadingTimeout(),J.push(this)}iframeOnLoad(){this.loadCount++,this.loadCount===2&&(this.deactivate(),setTimeout(()=>{q(this.widget)},t.LAZY_IFRAME_FADE_TIMEOUT))}deactivate(){this.clearLoadingTimeout(),Z(this.widget)}clearLoadingTimeout(){this.timeoutId&&clearTimeout(this.timeoutId),this.timeoutId=null}registerLoadingTimeout(){this.timeoutId||=setTimeout(()=>{this.iframeOnLoad()},t.LAZY_IFRAME_SHOW_TIMEOUT)}};function re(){t.on(`load`,e=>{if(!e){let e=document.querySelectorAll(`iframe[data-iframely-url]`);for(let n=0;n{e&&e.nodeName===`IFRAME`&&e.hasAttribute(`data-iframely-url`)&&!e.hasAttribute(`data-img`)&&!e.getAttribute(`src`)&&ie(e)})}function ie(e){let n=h(e),r=e.getAttribute(`data-iframely-url`),i=e.hasAttribute(`data-img-created`)||e.hasAttribute(`data-img`),a=!i&&t.SUPPORT_IFRAME_LOADING_ATTR;if(n&&r){let e={v:t.VERSION,app:1,theme:t.config.theme};!a&&t.config.intersection&&(e.lazy=1),r=b(r,e)}a&&e.setAttribute(`loading`,`lazy`),i&&t.SUPPORT_IFRAME_LOADING_ATTR&&e.setAttribute(`loading`,`edge`),e.setAttribute(`src`,r||``),e.removeAttribute(`data-iframely-url`),t.trigger(`iframe-ready`,e)}function ae(){t.on(`message`,(e,n)=>{n.method===`cancelWidget`&&t.cancelWidget(e)}),t.cancelWidget=e=>{if(!e){console.warn(`iframely.cancelWidget called without widget param`);return}function n(e,t){let n=!1;for(;!n&&e.parentNode;)e=e.parentNode,n=!!e.className&&typeof e.className==`string`&&e.className.split(` `).indexOf(t)>=0;return n&&e}let r=e.maxWidthWrapper&&e.maxWidthWrapper.parentNode,i=e.maxWidthWrapper;if(t.config&&t.config.parent){let a=n(e.maxWidthWrapper,String(t.config.parent));a&&(r=a.parentNode,i=a)}if(e.url){let n=e.iframe&&e.iframe.textContent;t.triggerAsync(`cancel`,e.url,r,n,i.nextSibling)}r.removeChild(i)}}var oe={border:``,"border-radius":``,"box-shadow":``,overflow:``},se={border:`0`,"border-radius":``,"box-shadow":``,overflow:``};function Q(){t.on(`message`,(e,t)=>{if(t.method===`setIframelyWidgetSize`||t.method===`resize`||t.method===`setIframelyEmbedData`||t.type===`embed-size`||t.context===`iframe.resize`){let n=null;t.data&&t.data.media&&t.data.media.frame_style?(t.data.media.frame_style.split(`;`).forEach(e=>{if(e.trim()!==``&&e.indexOf(`:`)>-1){let t=e.split(`:`);t.length===2&&(n||={},n[t[0].trim()]=t[1].trim())}}),$(e,n)):t.method===`setIframelyEmbedData`&&$(e,null);let r=t.data&&t.data.media;!r&&t.height&&(r={height:t.height,"max-width":`keep`}),le(e,r)}})}function $(e,t){t&&e&&e.iframe?t[`border-radius`]?(t.overflow=`hidden`,g(e.aspectWrapper,t)):g(e.iframe,t):!t&&e&&e.iframe&&(g(e.aspectWrapper,oe),g(e.iframe,se))}function ce(e){let t=e.iframe&&e.iframe.style.border||e.aspectWrapper&&e.aspectWrapper.style.border,n=t&&t.match(/(\d+)px/);return n?parseInt(n[1])*2:0}function le(e,n){if(n&&Object.keys(n).length>0&&e){let r=ce(e),i=window.getComputedStyle(e.iframe).getPropertyValue(`height`),a=n[`max-width`];typeof a==`number`&&(a+=r),g(e.maxWidthWrapper,{"max-width":a,"min-width":n[`min-width`]&&n[`min-width`]+r,width:n.width&&n.width+r}),n.scrolling&&e.iframe&&e.iframe.setAttribute(`scrolling`,n.scrolling);let o=n[`aspect-ratio`];(o||n.height)&&g(e.aspectWrapper,{paddingBottom:o?Math.round(1e3*100/o)/1e3+`%`:0,paddingTop:o&&n[`padding-bottom`],height:o?0:n.height&&n.height+r});let s=window.getComputedStyle(e.iframe).getPropertyValue(`height`);i&&i!==s&&t.triggerAsync(`heightChanged`,e.iframe,i,s)}}function ue(){t.on(`message`,(e,n)=>{(n.method===`open-href`||n.method===`click`)&&t.trigger(n.method,n.href)}),t.openHref||=e=>{e.indexOf(window.location.origin)===0?window.location.href=e:window.open(e,`_blank`,`noopener`)},t.on(`open-href`,e=>{t.triggerAsync(`click`,e),t.openHref(e)})}function de(){t.on(`message`,(e,n)=>{n.method===`setIframelyEmbedOptions`&&t.trigger(`options`,e,n.data)})}function fe(){t.widgets=t.widgets||{},t.widgets.load=t.load,t.extendOptions=t.configure,t.events||(t.events={},t.events.on=t.on,t.events.trigger=t.trigger),t.on(`cancel`,(e,n,r,i)=>{if(t.RECOVER_HREFS_ON_CANCEL&&!r&&(r=e),e&&n&&r&&r!==``){let t=document.createElement(`a`);t.setAttribute(`href`,e),t.setAttribute(`target`,`_blank`),t.setAttribute(`rel`,`noopener`),t.textContent=r,i?n.insertBefore(t,i):n.appendChild(t)}})}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),p(),d(),A(),te(),P(),V(),U(),re(),ae(),Q(),ue(),de(),fe(),t.trigger(`init`))})(); \ No newline at end of file diff --git a/dist/esm/chunks/deprecated.js b/dist/esm/chunks/deprecated.js index 3d5fb74..c0ecb1b 100644 --- a/dist/esm/chunks/deprecated.js +++ b/dist/esm/chunks/deprecated.js @@ -180,6 +180,20 @@ function boot$11() { iframely.load = function(...args) { iframely.trigger("load", ...args); }; + iframely.unload = (el) => { + const domains = iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, "")); + const root = el || document; + const selector = "iframe[src*=\"" + domains.join("\"], iframe[src*=\"") + "\"], iframe[data-iframely-url]"; + const iframes = root.querySelectorAll(selector); + for (let i = 0; i < iframes.length; i++) { + const widget = getWidget(iframes[i]); + if (widget) { + iframely.trigger("unload-widget", widget); + widget.maxWidthWrapper.remove(); + } + } + iframely.trigger("unload", el); + }; iframely.getElementComputedStyle = (el, style) => { return window.getComputedStyle(el).getPropertyValue(style); }; @@ -387,6 +401,15 @@ function boot$10() { getObserver(options).observe(widget.iframe); } }); + iframely.on("unload-widget", (widget) => { + Object.values(observers).forEach((observer) => observer.unobserve(widget.iframe)); + }); + iframely.on("unload", (el) => { + if (!el) Object.keys(observers).forEach((key) => { + observers[key].disconnect(); + delete observers[key]; + }); + }); } //#endregion //#region src/theme.ts @@ -440,6 +463,14 @@ function boot$8() { return "ontouchstart" in window || navigator.maxTouchPoints > 0; }; iframely.on("import-widget-ready", clearWrapperStylesAndClass); + iframely.on("unload", (el) => { + if (!el) { + delete iframely.import; + Object.keys(widgetsCache).forEach((key) => { + delete widgetsCache[key]; + }); + } + }); if (!iframely.addEventListener) iframely.addEventListener = (elem, type, eventHandle) => { if (!elem) return; elem.addEventListener(type, eventHandle, false); @@ -712,6 +743,9 @@ function boot$6() { waitingWidget?.registerLoadingTimeout(); } }); + iframely.on("unload-widget", (widget) => { + findWaitingWidget(widget)?.deactivate(); + }); } function addPlaceholderThumbnail(widget, href, imageUrl) { let thumbHref; diff --git a/dist/esm/chunks/iframely.js b/dist/esm/chunks/iframely.js index d9a15ee..cb72551 100644 --- a/dist/esm/chunks/iframely.js +++ b/dist/esm/chunks/iframely.js @@ -7,6 +7,7 @@ function createServerStub() { trigger: noop, triggerAsync: noop, load: noop, + unload: noop, configure: noop, extendOptions: noop, setTheme: noop, diff --git a/dist/options.i18n.de.js b/dist/options.i18n.de.js index e05343b..c22f029 100644 --- a/dist/options.i18n.de.js +++ b/dist/options.i18n.de.js @@ -10,6 +10,7 @@ trigger: noop, triggerAsync: noop, load: noop, + unload: noop, configure: noop, extendOptions: noop, setTheme: noop, diff --git a/dist/options.i18n.de.min.js b/dist/options.i18n.de.min.js index 05f073b..d194d02 100644 --- a/dist/options.i18n.de.min.js +++ b/dist/options.i18n.de.min.js @@ -1 +1 @@ -(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n={};function r(e,t){let r=n[e]=n[e]||{};Object.assign(r,t)}t.optionsTranslator=e=>t=>n[e]&&n[e][t]&&n[e][t]!==``?n[e][t]:t,r(`de`,{"Slimmer horizontal player":`Schlanker horizontaler Player`,"Include playlist":`Wiedergabeliste anzeigen`,"Hide artwork":`Artwork ausblenden`,"Theme color":`Theme Farbe`,Light:`Hell`,Dark:`Dunkel`,Auto:`Automatisch`,Default:`Standard`,"Adjust height":`Höhe einstellen`,"Active page":`Aktive Seite`,"Use click-to-load":`Verwende click-to-load`,"ex.: 600, in px":`Z.B. 600, in px`,"Hide timed comments":`Kommentare ausblenden`,"Let Iframely optimize player for the artwork":`Optimierung des Players durch IFramely`,"Show as slideshow":`Als Slideshow zeigen`,"Start from":`Start ab`,"ex.: 11, 1m10s":`z.B. 11, 1m10s`,"End on":`Ende an`,"Closed captions":`Untertitel`,"Include up to 20 tweets":`Bis zu 20 Tweets anzeigen`,"Hide photos, videos, and cards":`Verberge Fotos, Videos und Cards`,"Hide previous Tweet in conversation thread":`Verberge den vorigen Tweet in der Konversation`,"Use dark theme":`Verwende dunkles Farbschema`,"Adjust width":`Breite anpassen`,"Hide description":`Beschreibung verbergen`,"Widget style":`Widget-Style`,Mini:`Mini`,Classic:`Klassisch`,Picture:`Bild`,Zoom:`Zoom`,"Map orientation":`Karten-Ausrichtung`,Album:`Album`,Portrait:`Portrait`,Square:`Quadratisch`,"Show context slideshow":`Als Slideshow anzeigen`,"Show description footer":`Fußzeile anzeigen`,"Show user header":`Kopfbereich anzeigen`,"Show author's text caption":`Beschriftung des Autors anzeigen`,"Hide author's text caption":`Beschriftung des Autors verbergen`,"Include parent comment (if url is a reply)":`Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)`,"Show recent posts":`Neueste Beiträge anzeigen`,"Show profile photos when friends like this":`Profilfotos anzeigen, wenn Freunde dies mögen`,"Use the small header instead":`Kleine Kopfzeile stattdessen verwenden`,Artwork:`Artwork`,Small:`klein`,Big:`groß`,None:`Keines`,Layout:`Layout`,Slim:`Schlank`,"Artwork-only":`Nur Artwork`,Standard:`Standard`,"Size & style":`Größe & Stil`,"Wide image":`Breite Darstellung`,"Wide simple":`Breite Darstellung (Einfach)`,"Text language (ignored if no captions)":`Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)`,"Two letters: en, fr, es, de...":`Zwei Buchstaben: en, fr, es, de...`,"Don't include attached player":`Player nicht integrieren`,"Attached player only, no card":`Nur Player, keine Card`,"Hold load & play until clicked":`Klicken zum Abspielen`,"Make it a small card":`Kleine Card verwenden`,"Keep using full media card":`Verwende weiterhin vollständige Media-Cards`,"Don't include player":`Player nicht hinzufügen`,"Player only, no card":`Nur Player, keine Card`,"Just the player":`Nur Player`,"Just the image":`Nur Bild`})})(); \ No newline at end of file +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,unload:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n={};function r(e,t){let r=n[e]=n[e]||{};Object.assign(r,t)}t.optionsTranslator=e=>t=>n[e]&&n[e][t]&&n[e][t]!==``?n[e][t]:t,r(`de`,{"Slimmer horizontal player":`Schlanker horizontaler Player`,"Include playlist":`Wiedergabeliste anzeigen`,"Hide artwork":`Artwork ausblenden`,"Theme color":`Theme Farbe`,Light:`Hell`,Dark:`Dunkel`,Auto:`Automatisch`,Default:`Standard`,"Adjust height":`Höhe einstellen`,"Active page":`Aktive Seite`,"Use click-to-load":`Verwende click-to-load`,"ex.: 600, in px":`Z.B. 600, in px`,"Hide timed comments":`Kommentare ausblenden`,"Let Iframely optimize player for the artwork":`Optimierung des Players durch IFramely`,"Show as slideshow":`Als Slideshow zeigen`,"Start from":`Start ab`,"ex.: 11, 1m10s":`z.B. 11, 1m10s`,"End on":`Ende an`,"Closed captions":`Untertitel`,"Include up to 20 tweets":`Bis zu 20 Tweets anzeigen`,"Hide photos, videos, and cards":`Verberge Fotos, Videos und Cards`,"Hide previous Tweet in conversation thread":`Verberge den vorigen Tweet in der Konversation`,"Use dark theme":`Verwende dunkles Farbschema`,"Adjust width":`Breite anpassen`,"Hide description":`Beschreibung verbergen`,"Widget style":`Widget-Style`,Mini:`Mini`,Classic:`Klassisch`,Picture:`Bild`,Zoom:`Zoom`,"Map orientation":`Karten-Ausrichtung`,Album:`Album`,Portrait:`Portrait`,Square:`Quadratisch`,"Show context slideshow":`Als Slideshow anzeigen`,"Show description footer":`Fußzeile anzeigen`,"Show user header":`Kopfbereich anzeigen`,"Show author's text caption":`Beschriftung des Autors anzeigen`,"Hide author's text caption":`Beschriftung des Autors verbergen`,"Include parent comment (if url is a reply)":`Ursprünglichen Kommentar einschließen (wenn die Url eine Antwort ist)`,"Show recent posts":`Neueste Beiträge anzeigen`,"Show profile photos when friends like this":`Profilfotos anzeigen, wenn Freunde dies mögen`,"Use the small header instead":`Kleine Kopfzeile stattdessen verwenden`,Artwork:`Artwork`,Small:`klein`,Big:`groß`,None:`Keines`,Layout:`Layout`,Slim:`Schlank`,"Artwork-only":`Nur Artwork`,Standard:`Standard`,"Size & style":`Größe & Stil`,"Wide image":`Breite Darstellung`,"Wide simple":`Breite Darstellung (Einfach)`,"Text language (ignored if no captions)":`Sprache der Untertitel (wird ignoriert, wenn keine Untertitel vorhanden)`,"Two letters: en, fr, es, de...":`Zwei Buchstaben: en, fr, es, de...`,"Don't include attached player":`Player nicht integrieren`,"Attached player only, no card":`Nur Player, keine Card`,"Hold load & play until clicked":`Klicken zum Abspielen`,"Make it a small card":`Kleine Card verwenden`,"Keep using full media card":`Verwende weiterhin vollständige Media-Cards`,"Don't include player":`Player nicht hinzufügen`,"Player only, no card":`Nur Player, keine Card`,"Just the player":`Nur Player`,"Just the image":`Nur Bild`})})(); \ No newline at end of file diff --git a/dist/options.i18n.fr.js b/dist/options.i18n.fr.js index 0b02a2a..4265414 100644 --- a/dist/options.i18n.fr.js +++ b/dist/options.i18n.fr.js @@ -10,6 +10,7 @@ trigger: noop, triggerAsync: noop, load: noop, + unload: noop, configure: noop, extendOptions: noop, setTheme: noop, diff --git a/dist/options.i18n.fr.min.js b/dist/options.i18n.fr.min.js index 4f69d88..5c20eca 100644 --- a/dist/options.i18n.fr.min.js +++ b/dist/options.i18n.fr.min.js @@ -1 +1 @@ -(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n={};function r(e,t){let r=n[e]=n[e]||{};Object.assign(r,t)}t.optionsTranslator=e=>t=>n[e]&&n[e][t]&&n[e][t]!==``?n[e][t]:t,r(`fr`,{"Slimmer horizontal player":`Joueur de audio classique`,"Include playlist":`Inclure la playlist`,"Hide artwork":`Masquer la illustration`,"Theme color":`Couleur du thème`,Light:`Lumière`,Dark:`Sombre`,Auto:``,Default:`Défaut`,"Adjust height":`Height`,"Active page":`Page active`,"Use click-to-load":`Utilisez click-to-load`,"ex.: 600, in px":``,"Hide timed comments":`Masquer les commentaires`,"Let Iframely optimize player for the artwork":`Optimiser le lecteur pour l'illustration`,"Show as slideshow":`Montrer en diaporama`,"Start from":`Commencer`,"ex.: 11, 1m10s":``,"End on":`Fin sur`,"Include up to 20 tweets":`Incluez jusqu'à 20 tweets`,"Hide photos, videos, and cards":`Masquer les photos, les vidéos et les cartes`,"Hide previous Tweet in conversation thread":`Masquer le tweet parent`,"Hide description":`Masquer la description`,"Widget style":`Style de widget`,Mini:``,Classic:`Classique`,Picture:`Image`,Zoom:``,"Map orientation":`Orientation de la carte`,Album:``,Portrait:``,Square:`Carré`,"Show context slideshow":`Afficher le diaporama contextuel`,"Show description footer":`Afficher la description pied de page`,"Show user header":`Afficher l'en-tête de l'utilisateur`,"Show author's text caption":`Afficher la description de l'auteur`,"Hide author's text caption":`Masquer la description de l'auteur`,"Include parent comment (if url is a reply)":``,"Show recent posts":`Afficher les messages récents`,"Show profile photos when friends like this":``,"Use the small header instead":`Utilisez plutôt le petit en-tête`,Artwork:`Ouvrages d'art`,Small:`Petite`,Big:`Grosse`,None:`Aucune`,Layout:`Disposition`,Slim:`Svelte`,"Artwork-only":`Oeuvre seule`,Standard:`Standard`,"Size & style":`Style`,"Wide image":`Image large`,"Wide simple":`Large simple`,"Hold load & play until clicked":`Click-to-play`,"Make it a small card":`Carte compacte`,"Keep using full media card":`Continuez à utiliser la carte média complète`,"Don't include player":`Ne pas inclure la vidéo`,"Player only, no card":`La vidéo seulement, pas de carte`,"Just the player":`Seulement la vidéo`,"Just the image":`Seulement l'image`})})(); \ No newline at end of file +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,unload:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n={};function r(e,t){let r=n[e]=n[e]||{};Object.assign(r,t)}t.optionsTranslator=e=>t=>n[e]&&n[e][t]&&n[e][t]!==``?n[e][t]:t,r(`fr`,{"Slimmer horizontal player":`Joueur de audio classique`,"Include playlist":`Inclure la playlist`,"Hide artwork":`Masquer la illustration`,"Theme color":`Couleur du thème`,Light:`Lumière`,Dark:`Sombre`,Auto:``,Default:`Défaut`,"Adjust height":`Height`,"Active page":`Page active`,"Use click-to-load":`Utilisez click-to-load`,"ex.: 600, in px":``,"Hide timed comments":`Masquer les commentaires`,"Let Iframely optimize player for the artwork":`Optimiser le lecteur pour l'illustration`,"Show as slideshow":`Montrer en diaporama`,"Start from":`Commencer`,"ex.: 11, 1m10s":``,"End on":`Fin sur`,"Include up to 20 tweets":`Incluez jusqu'à 20 tweets`,"Hide photos, videos, and cards":`Masquer les photos, les vidéos et les cartes`,"Hide previous Tweet in conversation thread":`Masquer le tweet parent`,"Hide description":`Masquer la description`,"Widget style":`Style de widget`,Mini:``,Classic:`Classique`,Picture:`Image`,Zoom:``,"Map orientation":`Orientation de la carte`,Album:``,Portrait:``,Square:`Carré`,"Show context slideshow":`Afficher le diaporama contextuel`,"Show description footer":`Afficher la description pied de page`,"Show user header":`Afficher l'en-tête de l'utilisateur`,"Show author's text caption":`Afficher la description de l'auteur`,"Hide author's text caption":`Masquer la description de l'auteur`,"Include parent comment (if url is a reply)":``,"Show recent posts":`Afficher les messages récents`,"Show profile photos when friends like this":``,"Use the small header instead":`Utilisez plutôt le petit en-tête`,Artwork:`Ouvrages d'art`,Small:`Petite`,Big:`Grosse`,None:`Aucune`,Layout:`Disposition`,Slim:`Svelte`,"Artwork-only":`Oeuvre seule`,Standard:`Standard`,"Size & style":`Style`,"Wide image":`Image large`,"Wide simple":`Large simple`,"Hold load & play until clicked":`Click-to-play`,"Make it a small card":`Carte compacte`,"Keep using full media card":`Continuez à utiliser la carte média complète`,"Don't include player":`Ne pas inclure la vidéo`,"Player only, no card":`La vidéo seulement, pas de carte`,"Just the player":`Seulement la vidéo`,"Just the image":`Seulement l'image`})})(); \ No newline at end of file diff --git a/dist/options.js b/dist/options.js index 37b7975..d2536e0 100644 --- a/dist/options.js +++ b/dist/options.js @@ -10,6 +10,7 @@ trigger: noop, triggerAsync: noop, load: noop, + unload: noop, configure: noop, extendOptions: noop, setTheme: noop, diff --git a/dist/options.min.js b/dist/options.min.js index a03ebff..1cd6969 100644 --- a/dist/options.min.js +++ b/dist/options.min.js @@ -1,4 +1,4 @@ -(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n=/^_./,r=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function i(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let i=[],a=Object.keys(e),o=0;if(a.forEach(a=>{let s={},c,l=e[a];l.key=a;let u=!1,d=l.values?Object.keys(l.values):void 0,f,p;if(d&&d.length===1&&(u=!0,f=d[0],p=l.values[f]),s.label=r(p||l.label,t),s.key=l.key,u||typeof l.value==`boolean`)u?s.checked=f===l.value||!f&&!l.value:s.checked=l.value,o++,i.push({type:`checkbox`,context:s,order:+!n.test(a),getQuery:e=>{let t;t=u?e?f:``:e;let n={};return u?t===``||(n[l.key]=t):n[l.key]=e,n}});else if((typeof l.value==`number`||typeof l.value==`string`)&&!l.values){let e=l.range&&typeof l.range.min==`number`&&typeof l.range.max==`number`,n=typeof l.value==`number`;s.value=l.value,c=e=>{let t={};return e===``||(t[l.key]=e),t},e?(s.min=l.range.min,s.max=l.range.max,i.push({type:`range`,context:s,order:9,getQuery:c})):(s.placeholder=r(l.placeholder||``,t),s.inputType=n?`number`:`text`,i.push({type:`text`,context:s,order:/start/i.test(a)?7:8,getQuery:c}))}else if(l.values)if(s.value=l.value+``,c=e=>{let t={};return e===``||(t[l.key]=e),t},Object.keys(l.values).length<=3){l.label?s.label=r(l.label,t):s.label=!1;let e=0,n=!1,o=Object.values(l.values);for(;e8,e++;s.inline=!n,s.items=[],Object.keys(l.values).forEach((e,n)=>{s.items.push({id:s.key+`-`+n,value:e,label:r(l.values[e],t),checked:s.value===e})}),i.push({type:`radio`,context:s,order:n?-3:/theme/.test(a)?-1:-2,getQuery:c})}else s.items=[],Object.keys(l.values).forEach(e=>{s.items.push({value:e,label:r(l.values[e],t),checked:s.value===e})}),i.push({type:`select`,context:s,order:5,getQuery:c})}),i.sort((e,t)=>e.order-t.order),i.forEach(e=>{delete e.order}),o>0){let e=[],t;return i.forEach((r,a)=>{if(r.type===`checkbox`){let s=o>2&&a>0&&!n.test(r.context.key)&&i[a-1].type===`checkbox`&&n.test(i[a-1].context.key);(!t||s)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return i}var a={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(e,n)=>{let r=e[0];t.addEventListener(r,`click`,()=>{r.select()}),t.addEventListener(r,`blur`,n),t.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},o={};function s(e){let n=e.options,r=e.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,e);return}if(!n){r.innerHTML=``;return}let s=i(n,e.translator),c=e.id,l=e.renderer,u=o[c]=o[c]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(u[e]=n[e].value)});function d(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=a[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(s),e}function f(){let e=d();Object.keys(u).forEach(t=>{(u[t]===e[t]||e[t]===void 0)&&delete e[t]}),t.trigger(`options-changed`,c,r,e)}let p=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=p(e.context.elements)),t+=l(e.type,e.context||{})}),t};r.innerHTML=p(s);let m=e=>{e.forEach(e=>{if(e.context&&e.context.elements)m(e.context.elements);else{let n=a[e.type];if(e.context){let i=r.querySelectorAll(`[name="`+e.context.key+`"]`);e.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,f):i.forEach(e=>{t.addEventListener(e,`change`,f)}):console.warn(`No inputs found for option`,e.context.key)}}})};m(s)}var c={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},l=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>c[e]),u={checkbox:e=>` +(function(){function e(){let e=()=>{};return{config:{},on:e,trigger:e,triggerAsync:e,load:e,unload:e,configure:e,extendOptions:e,setTheme:e,cancelWidget:e,openHref:e,addEventListener:e,isTouch:()=>!1,findIframe:()=>void 0,getElementComputedStyle:()=>void 0,buildOptionsForm:e}}var t=typeof window>`u`?e():window.iframely=window.iframely||{};t.config=t.config||{};var n=/^_./,r=(e,t)=>t&&typeof t==`function`&&e&&t(e)||e;function i(e,t){if(!e)return[];e=Object.assign({},e),delete e.query;let i=[],a=Object.keys(e),o=0;if(a.forEach(a=>{let s={},c,l=e[a];l.key=a;let u=!1,d=l.values?Object.keys(l.values):void 0,f,p;if(d&&d.length===1&&(u=!0,f=d[0],p=l.values[f]),s.label=r(p||l.label,t),s.key=l.key,u||typeof l.value==`boolean`)u?s.checked=f===l.value||!f&&!l.value:s.checked=l.value,o++,i.push({type:`checkbox`,context:s,order:+!n.test(a),getQuery:e=>{let t;t=u?e?f:``:e;let n={};return u?t===``||(n[l.key]=t):n[l.key]=e,n}});else if((typeof l.value==`number`||typeof l.value==`string`)&&!l.values){let e=l.range&&typeof l.range.min==`number`&&typeof l.range.max==`number`,n=typeof l.value==`number`;s.value=l.value,c=e=>{let t={};return e===``||(t[l.key]=e),t},e?(s.min=l.range.min,s.max=l.range.max,i.push({type:`range`,context:s,order:9,getQuery:c})):(s.placeholder=r(l.placeholder||``,t),s.inputType=n?`number`:`text`,i.push({type:`text`,context:s,order:/start/i.test(a)?7:8,getQuery:c}))}else if(l.values)if(s.value=l.value+``,c=e=>{let t={};return e===``||(t[l.key]=e),t},Object.keys(l.values).length<=3){l.label?s.label=r(l.label,t):s.label=!1;let e=0,n=!1,o=Object.values(l.values);for(;e8,e++;s.inline=!n,s.items=[],Object.keys(l.values).forEach((e,n)=>{s.items.push({id:s.key+`-`+n,value:e,label:r(l.values[e],t),checked:s.value===e})}),i.push({type:`radio`,context:s,order:n?-3:/theme/.test(a)?-1:-2,getQuery:c})}else s.items=[],Object.keys(l.values).forEach(e=>{s.items.push({value:e,label:r(l.values[e],t),checked:s.value===e})}),i.push({type:`select`,context:s,order:5,getQuery:c})}),i.sort((e,t)=>e.order-t.order),i.forEach(e=>{delete e.order}),o>0){let e=[],t;return i.forEach((r,a)=>{if(r.type===`checkbox`){let s=o>2&&a>0&&!n.test(r.context.key)&&i[a-1].type===`checkbox`&&n.test(i[a-1].context.key);(!t||s)&&(t=[],e.push({type:`group`,context:{elements:t}})),t.push(r)}else e.push(r)}),e}else return i}var a={checkbox:{getValue:e=>e[0].checked},text:{getValue:e=>{let t=e[0],n=t.value;return t.type===`number`&&(n=parseInt(n),isNaN(n)&&(n=``)),n},customEvents:(e,n)=>{let r=e[0];t.addEventListener(r,`click`,()=>{r.select()}),t.addEventListener(r,`blur`,n),t.addEventListener(r,`keyup`,e=>{e.keyCode===13&&n()})}},radio:{getValue:e=>{let t;return Array.prototype.forEach.call(e,e=>{e.checked&&(t=e)}),t.value}}},o={};function s(e){let n=e.options,r=e.formContainer;if(!r){console.warn(`No formContainer in form-builder options`,e);return}if(!n){r.innerHTML=``;return}let s=i(n,e.translator),c=e.id,l=e.renderer,u=o[c]=o[c]||{};Object.keys(n).forEach(e=>{(!n.query||n.query.indexOf(e)===-1)&&(u[e]=n[e].value)});function d(){let e={},t=n=>{n.forEach(n=>{if(n.context&&n.context.elements)t(n.context.elements);else if(n.inputs){let t=a[n.type],r;r=t&&t.getValue?t.getValue(n.inputs):n.inputs[0].value,Object.assign(e,n.getQuery(r))}})};return t(s),e}function f(){let e=d();Object.keys(u).forEach(t=>{(u[t]===e[t]||e[t]===void 0)&&delete e[t]}),t.trigger(`options-changed`,c,r,e)}let p=e=>{let t=``;return e.forEach(e=>{e.context&&e.context.elements&&(e.context.elementsHtml=p(e.context.elements)),t+=l(e.type,e.context||{})}),t};r.innerHTML=p(s);let m=e=>{e.forEach(e=>{if(e.context&&e.context.elements)m(e.context.elements);else{let n=a[e.type];if(e.context){let i=r.querySelectorAll(`[name="`+e.context.key+`"]`);e.inputs=i,i.length>0?n&&n.customEvents?n.customEvents(i,f):i.forEach(e=>{t.addEventListener(e,`change`,f)}):console.warn(`No inputs found for option`,e.context.key)}}})};m(s)}var c={"&":`&`,"<":`<`,">":`>`,'"':`"`,"'":`'`},l=e=>e==null?``:String(e).replace(/[&<>"']/g,e=>c[e]),u={checkbox:e=>`
diff --git a/dist/types/types.d.ts b/dist/types/types.d.ts index 1d098e3..8c4d7ed 100644 --- a/dist/types/types.d.ts +++ b/dist/types/types.d.ts @@ -81,6 +81,12 @@ export interface Iframely { trigger(event: string, ...args: any[]): void; triggerAsync(event: string, ...args: any[]): void; load(...args: any[]): void; + /** + * Inverse of load(): removes built widgets from the document (or a + * container), releases their intersection observers and pending timers. + * Import/shadow widgets are not covered; consumed anchors are not restored. + */ + unload(el?: Element): void; configure(options: Record | undefined): void; /** @deprecated Pre-2.0 name of {@link Iframely.configure}. */ extendOptions(options: Record | undefined): void; diff --git a/src/iframely.ts b/src/iframely.ts index 2d9f93d..4b895db 100644 --- a/src/iframely.ts +++ b/src/iframely.ts @@ -12,6 +12,7 @@ function createServerStub(): Iframely { trigger: noop, triggerAsync: noop, load: noop, + unload: noop, configure: noop, extendOptions: noop, setTheme: noop, diff --git a/src/import.ts b/src/import.ts index e6c0b97..9d05dd9 100644 --- a/src/import.ts +++ b/src/import.ts @@ -56,6 +56,17 @@ export function boot(): void { iframely.on('import-widget-ready', clearWrapperStylesAndClass); + // A full unload resets transient import state so a later load() starts + // a fresh import cycle. + iframely.on('unload', (el?: Element) => { + if (!el) { + delete iframely.import; + Object.keys(widgetsCache).forEach((key) => { + delete widgetsCache[key]; + }); + } + }); + // used in server templates if (!iframely.addEventListener) { iframely.addEventListener = (elem, type, eventHandle) => { diff --git a/src/intersection.ts b/src/intersection.ts index ba30f49..3bb9db0 100644 --- a/src/intersection.ts +++ b/src/intersection.ts @@ -1,5 +1,6 @@ import iframely from './iframely'; import * as messaging from './messaging'; +import type { IframelyWidget } from './types'; interface IntersectionOptions { threshold?: number | number[]; @@ -72,4 +73,19 @@ export function boot(): void { getObserver(options).observe(widget.iframe); } }); + + // Observers hold strong references to their targets: release a widget's + // iframe when it is unloaded, and drop all observers on a full unload. + iframely.on('unload-widget', (widget: IframelyWidget) => { + Object.values(observers).forEach((observer) => observer.unobserve(widget.iframe)); + }); + + iframely.on('unload', (el?: Element) => { + if (!el) { + Object.keys(observers).forEach((key) => { + observers[key].disconnect(); + delete observers[key]; + }); + } + }); } diff --git a/src/lazy-img-placeholder.ts b/src/lazy-img-placeholder.ts index 4523b66..2bea01a 100644 --- a/src/lazy-img-placeholder.ts +++ b/src/lazy-img-placeholder.ts @@ -56,6 +56,11 @@ export function boot(): void { waitingWidget?.registerLoadingTimeout(); } }); + + // Release the pending timeout and tracking entry of an unloaded widget. + iframely.on('unload-widget', (widget: IframelyWidget) => { + findWaitingWidget(widget)?.deactivate(); + }); } function addPlaceholderThumbnail( diff --git a/src/types.ts b/src/types.ts index 2ed4d5b..0e24590 100644 --- a/src/types.ts +++ b/src/types.ts @@ -96,6 +96,12 @@ export interface Iframely { // utils.ts load(...args: any[]): void; + /** + * Inverse of load(): removes built widgets from the document (or a + * container), releases their intersection observers and pending timers. + * Import/shadow widgets are not covered; consumed anchors are not restored. + */ + unload(el?: Element): void; configure(options: Record | undefined): void; /** @deprecated Pre-2.0 name of {@link Iframely.configure}. */ extendOptions(options: Record | undefined): void; diff --git a/src/utils.ts b/src/utils.ts index 9e2c99a..b9aa27a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -27,6 +27,27 @@ export function boot(): void { iframely.trigger('load', ...args); }; + // Inverse of load(): removes the widgets this library built from the + // document (or from a container). Import/shadow widgets are not covered, + // and consumed anchors are not restored — + // re-rendering the original markup is the host page's job. + iframely.unload = (el?: Element) => { + const domains = iframely.DOMAINS.concat(iframely.CDN.replace(/^https?:\/\//, '')); + const root = el || document; + const selector = + 'iframe[src*="' + domains.join('"], iframe[src*="') + '"], iframe[data-iframely-url]'; + const iframes = root.querySelectorAll(selector); + for (let i = 0; i < iframes.length; i++) { + const widget = getWidget(iframes[i]); + if (widget) { + // Lets modules release per-widget state (observers, timeouts). + iframely.trigger('unload-widget', widget); + widget.maxWidthWrapper.remove(); + } + } + iframely.trigger('unload', el); + }; + iframely.getElementComputedStyle = (el, style) => { return window.getComputedStyle(el).getPropertyValue(style); }; diff --git a/tests/e2e/esm.spec.ts b/tests/e2e/esm.spec.ts index ba69bda..53e887f 100644 --- a/tests/e2e/esm.spec.ts +++ b/tests/e2e/esm.spec.ts @@ -34,3 +34,13 @@ test('does not auto-run on import; iframely.load() activates it', async ({ page await expect(page.locator('a[data-iframely-url]')).toHaveCount(0); expect(await iframe.getAttribute('src')).toContain('cdn.iframe.ly/api/iframe'); }); + +test('iframely.unload() removes the widgets load() built', async ({ page }) => { + await page.evaluate(() => (window as any).__load()); + await expect(page.locator('.iframely-responsive iframe')).toHaveCount(1); + + await page.evaluate(() => (window as any).iframely.unload()); + + await expect(page.locator('iframe')).toHaveCount(0); + await expect(page.locator('.iframely-embed')).toHaveCount(0); +}); diff --git a/tests/e2e/surface.spec.ts b/tests/e2e/surface.spec.ts index 00a42b6..9f904af 100644 --- a/tests/e2e/surface.spec.ts +++ b/tests/e2e/surface.spec.ts @@ -39,6 +39,8 @@ const EXPECTED_KEYS = [ 'setTheme', 'trigger', 'triggerAsync', + // unload is new in 2.0. + 'unload', 'widgets' ]; diff --git a/tests/unit/ssr.test.ts b/tests/unit/ssr.test.ts index 1188f6c..435c57c 100644 --- a/tests/unit/ssr.test.ts +++ b/tests/unit/ssr.test.ts @@ -24,6 +24,7 @@ describe('SSR import (node environment)', () => { iframely.on('load', () => {}); iframely.trigger('anything'); iframely.load(); + iframely.unload(); iframely.configure({ api_key: 'x' }); iframely.setTheme('dark'); iframely.cancelWidget(); diff --git a/tests/unit/unload.test.ts b/tests/unit/unload.test.ts new file mode 100644 index 0000000..fdbd4d2 --- /dev/null +++ b/tests/unit/unload.test.ts @@ -0,0 +1,99 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import iframely from '../../src/iframely'; +import { boot as bootConst } from '../../src/const'; +import { boot as bootEvents } from '../../src/events'; +import { boot as bootUtils } from '../../src/utils'; +import { boot as bootImport } from '../../src/import'; + +beforeAll(() => { + bootConst(); + bootEvents(); + bootUtils(); + bootImport(); +}); + +beforeEach(() => { + iframely.config = {}; + document.body.innerHTML = ''; +}); + +function widgetHtml(src: string): string { + return ( + '
' + + '' + + '
' + ); +} + +describe('unload', () => { + it('removes all built widgets from the document', () => { + document.body.innerHTML = + widgetHtml('https://cdn.iframe.ly/api/iframe?url=https%3A%2F%2Fx.com') + + widgetHtml('https://iframely.net/abc123') + + ''; + + iframely.unload(); + + expect(document.querySelectorAll('.iframely-embed')).toHaveLength(0); + // Non-Iframely iframes are left alone. + expect(document.getElementById('foreign')).not.toBeNull(); + }); + + it('removes lazy widgets that have not loaded yet (data-iframely-url)', () => { + document.body.innerHTML = + '
' + + '' + + '
'; + + iframely.unload(); + + expect(document.querySelectorAll('.iframely-embed')).toHaveLength(0); + }); + + it('scopes removal to a container when one is given', () => { + document.body.innerHTML = + '
' + + widgetHtml('https://cdn.iframe.ly/one') + + '
' + + '
' + + widgetHtml('https://cdn.iframe.ly/two') + + '
'; + + iframely.unload(document.getElementById('a')!); + + expect(document.querySelectorAll('#a .iframely-embed')).toHaveLength(0); + expect(document.querySelectorAll('#b .iframely-embed')).toHaveLength(1); + }); + + it('leaves widgets without the library wrapper structure alone', () => { + document.body.innerHTML = '
'; + + iframely.unload(); + + expect(document.querySelectorAll('iframe')).toHaveLength(1); + }); + + it('triggers unload-widget per widget and a final unload event', () => { + document.body.innerHTML = widgetHtml('https://cdn.iframe.ly/one'); + const perWidget = vi.fn(); + const done = vi.fn(); + iframely.on('unload-widget', perWidget); + iframely.on('unload', done); + + iframely.unload(); + + expect(perWidget).toHaveBeenCalledTimes(1); + expect(perWidget.mock.calls[0][0].iframe).toBeInstanceOf(HTMLIFrameElement); + expect(done).toHaveBeenCalledWith(undefined); + }); + + it('resets transient import state on a full unload', () => { + iframely.import = document.createElement('script'); + + iframely.unload(); + + expect(iframely.import).toBeUndefined(); + }); +}); From d5430b96b2bb55451001f1f9090cc1d880724987 Mon Sep 17 00:00:00 2001 From: Alexander Matveyenko Date: Sat, 11 Jul 2026 16:38:23 +0200 Subject: [PATCH 7/7] Fail silently when options.js is used without embed.js buildOptionsForm now checks at call time that the embed bundle has provided iframely.trigger and iframely.addEventListener; without them it logs a console.warn and returns instead of throwing from form-builder. Checked per call, not at boot, so loading options.js before embed.js keeps working. Covered by a unit test booting only the options module and an e2e spec with an options.js-only fixture page asserting zero page errors, an empty container, and the warning. Co-Authored-By: Claude Fable 5 --- demo/options-standalone.html | 21 +++++++++++++++++++++ dist/embed-options.js | 4 ++++ dist/embed-options.min.js | 2 +- dist/esm/main-options.js | 4 ++++ dist/options.js | 4 ++++ dist/options.min.js | 2 +- src/options/index.ts | 14 ++++++++++++++ tests/e2e/options-standalone.spec.ts | 22 ++++++++++++++++++++++ tests/unit/options-standalone.test.ts | 27 +++++++++++++++++++++++++++ 9 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 demo/options-standalone.html create mode 100644 tests/e2e/options-standalone.spec.ts create mode 100644 tests/unit/options-standalone.test.ts diff --git a/demo/options-standalone.html b/demo/options-standalone.html new file mode 100644 index 0000000..6bc2c4d --- /dev/null +++ b/demo/options-standalone.html @@ -0,0 +1,21 @@ + + +standalone options.js test + +

options.js without embed.js

+
+ + + + diff --git a/dist/embed-options.js b/dist/embed-options.js index 3a29051..98bf1fc 100644 --- a/dist/embed-options.js +++ b/dist/embed-options.js @@ -1416,6 +1416,10 @@ //#region src/options/index.ts function boot() { iframely.buildOptionsForm = (id, formContainer, options, translator) => { + if (typeof iframely.trigger !== "function" || typeof iframely.addEventListener !== "function") { + console.warn("iframely.buildOptionsForm requires embed.js (or embed-options.js) to be loaded"); + return; + } formBuilder({ id, formContainer, diff --git a/dist/embed-options.min.js b/dist/embed-options.min.js index dcfe497..8b4eeb9 100644 --- a/dist/embed-options.min.js +++ b/dist/embed-options.min.js @@ -35,4 +35,4 @@
-
`},Se=(e,t)=>xe[e](t);function Ce(){t.buildOptionsForm=(e,t,n,r)=>{ye({id:e,formContainer:t,options:n,renderer:Se,translator:r})}}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),p(),d(),O(),j(),re(),I(),R(),se(),le(),fe(),he(),ge(),_e(),Ce(),t.trigger(`init`))})(); \ No newline at end of file + `},Se=(e,t)=>xe[e](t);function Ce(){t.buildOptionsForm=(e,n,r,i)=>{if(typeof t.trigger!=`function`||typeof t.addEventListener!=`function`){console.warn(`iframely.buildOptionsForm requires embed.js (or embed-options.js) to be loaded`);return}ye({id:e,formContainer:n,options:r,renderer:Se,translator:i})}}typeof window<`u`&&!t._loaded&&(t._loaded=!0,n(),o(),p(),d(),O(),j(),re(),I(),R(),se(),le(),fe(),he(),ge(),_e(),Ce(),t.trigger(`init`))})(); \ No newline at end of file diff --git a/dist/esm/main-options.js b/dist/esm/main-options.js index e30cf94..d830792 100644 --- a/dist/esm/main-options.js +++ b/dist/esm/main-options.js @@ -313,6 +313,10 @@ var render = (type, context) => templates[type](context); //#region src/options/index.ts function boot() { iframely.buildOptionsForm = (id, formContainer, options, translator) => { + if (typeof iframely.trigger !== "function" || typeof iframely.addEventListener !== "function") { + console.warn("iframely.buildOptionsForm requires embed.js (or embed-options.js) to be loaded"); + return; + } formBuilder({ id, formContainer, diff --git a/dist/options.js b/dist/options.js index d2536e0..f993dc7 100644 --- a/dist/options.js +++ b/dist/options.js @@ -343,6 +343,10 @@ //#region src/options/index.ts function boot() { iframely.buildOptionsForm = (id, formContainer, options, translator) => { + if (typeof iframely.trigger !== "function" || typeof iframely.addEventListener !== "function") { + console.warn("iframely.buildOptionsForm requires embed.js (or embed-options.js) to be loaded"); + return; + } formBuilder({ id, formContainer, diff --git a/dist/options.min.js b/dist/options.min.js index 1cd6969..d60e9d4 100644 --- a/dist/options.min.js +++ b/dist/options.min.js @@ -35,4 +35,4 @@
- `},d=(e,t)=>u[e](t);function f(){t.buildOptionsForm=(e,t,n,r)=>{s({id:e,formContainer:t,options:n,renderer:d,translator:r})}}f()})(); \ No newline at end of file + `},d=(e,t)=>u[e](t);function f(){t.buildOptionsForm=(e,n,r,i)=>{if(typeof t.trigger!=`function`||typeof t.addEventListener!=`function`){console.warn(`iframely.buildOptionsForm requires embed.js (or embed-options.js) to be loaded`);return}s({id:e,formContainer:n,options:r,renderer:d,translator:i})}}f()})(); \ No newline at end of file diff --git a/src/options/index.ts b/src/options/index.ts index 70de859..483e127 100644 --- a/src/options/index.ts +++ b/src/options/index.ts @@ -4,6 +4,20 @@ import renderer from './renderer'; export function boot(): void { iframely.buildOptionsForm = (id, formContainer, options, translator) => { + // The standalone options.js bundle relies on an embed bundle for the + // event bus and addEventListener. Checked per call (not at boot) + // because loading options.js before embed.js is a supported order. + // Without embed.js the form fails silently instead of throwing. + if ( + typeof iframely.trigger !== 'function' || + typeof iframely.addEventListener !== 'function' + ) { + console.warn( + 'iframely.buildOptionsForm requires embed.js (or embed-options.js) to be loaded' + ); + return; + } + formBuilder({ id: id, formContainer: formContainer, diff --git a/tests/e2e/options-standalone.spec.ts b/tests/e2e/options-standalone.spec.ts new file mode 100644 index 0000000..d78b4c7 --- /dev/null +++ b/tests/e2e/options-standalone.spec.ts @@ -0,0 +1,22 @@ +import { test, expect } from '@playwright/test'; + +test('options.js without embed.js fails silently on buildOptionsForm', async ({ page }) => { + const pageErrors: string[] = []; + const warnings: string[] = []; + page.on('pageerror', (error) => pageErrors.push(error.message)); + page.on('console', (message) => { + if (message.type() === 'warning') { + warnings.push(message.text()); + } + }); + + await page.goto('/demo/options-standalone.html'); + await page.waitForFunction(() => (window as any).__done); + + // The inline script ran to completion: nothing threw. + expect(pageErrors).toEqual([]); + expect(await page.evaluate(() => (window as any).__errors)).toEqual([]); + // The form was not rendered, and a warning points at the missing embed.js. + await expect(page.locator('#form *')).toHaveCount(0); + expect(warnings.join('|')).toContain('requires embed.js'); +}); diff --git a/tests/unit/options-standalone.test.ts b/tests/unit/options-standalone.test.ts new file mode 100644 index 0000000..231b9c2 --- /dev/null +++ b/tests/unit/options-standalone.test.ts @@ -0,0 +1,27 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import iframely from '../../src/iframely'; +import { boot as bootOptions } from '../../src/options/index'; + +// Deliberately boots ONLY the options module — no events, no import — +// mirroring a page that loads the standalone options.js without embed.js. +describe('standalone options bundle without embed', () => { + beforeEach(() => { + document.body.innerHTML = '
'; + bootOptions(); + }); + + it('buildOptionsForm fails silently with a warning instead of throwing', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const container = document.getElementById('form')!; + + expect(() => { + iframely.buildOptionsForm!('id', container, { + _hide: { label: 'Hide artwork', value: false } + }); + }).not.toThrow(); + + expect(container.innerHTML).toBe(''); + expect(warn).toHaveBeenCalledWith(expect.stringContaining('requires embed.js')); + warn.mockRestore(); + }); +});