@jsenv/core 25.4.2 → 25.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1821,7 +1821,7 @@ html[data-toolbar-visible] #toolbar-trigger {
1821
1821
  <div class="category-subtitle">
1822
1822
  Send system notification when execution fails or is fixed.
1823
1823
  <div class="notification-text">
1824
- <a data-when="notif_permission:no" class="request_notification_permission" href="javascript:void(0);">Enable notification</a>
1824
+ <a data-when="notif_granted:no" class="request_notification_permission" href="javascript:void(0);">Enable notification</a>
1825
1825
  </div>
1826
1826
  </div>
1827
1827
  </div>
@@ -2426,6 +2426,19 @@ html[data-toolbar-visible] #toolbar-trigger {
2426
2426
  document.documentElement.setAttribute("data-last-interaction", "keyboard");
2427
2427
  });
2428
2428
 
2429
+ var setLinkHrefForParentWindow = function setLinkHrefForParentWindow(a, href) {
2430
+ a.href = href;
2431
+
2432
+ a.onclick = function (e) {
2433
+ if (e.ctrlKey || e.metaKey) {
2434
+ return;
2435
+ }
2436
+
2437
+ e.preventDefault();
2438
+ window.parent.location.href = href;
2439
+ };
2440
+ };
2441
+
2429
2442
  var createPreference = function createPreference(name) {
2430
2443
  return {
2431
2444
  has: function has() {
@@ -2671,56 +2684,88 @@ html[data-toolbar-visible] #toolbar-trigger {
2671
2684
  var arrayOfOpenedNotifications = [];
2672
2685
 
2673
2686
  var renderToolbarNotification = function renderToolbarNotification() {
2674
- var notifCheckbox = document.querySelector("#toggle-notifs");
2675
-
2676
2687
  if (!notificationAvailable) {
2677
- var notifSetting = document.querySelector(".settings-notification");
2678
- notifSetting.setAttribute("data-disabled", "true");
2679
- notifSetting.setAttribute("title", "Notification not available in the browser");
2680
- notifCheckbox.disabled = true;
2688
+ applyNotificationNotAvailableEffects();
2681
2689
  return;
2682
2690
  }
2683
2691
 
2684
- var updatePermission = function updatePermission() {
2685
- if (Notification.permission === "denied") {
2686
- var _notifSetting = document.querySelector(".settings-notification");
2692
+ updatePermission();
2693
+ };
2687
2694
 
2688
- _notifSetting.setAttribute("data-disabled", "true");
2695
+ var updatePermission = function updatePermission() {
2696
+ var notifPermission = Notification.permission;
2689
2697
 
2690
- _notifSetting.setAttribute("title", "Notification denied");
2698
+ if (notifPermission === "default") {
2699
+ applyNotificationDefaultEffects();
2700
+ return;
2701
+ }
2691
2702
 
2692
- notifCheckbox.disabled = true;
2693
- return;
2694
- }
2703
+ if (notifPermission === "denied") {
2704
+ applyNotificationDeniedEffects();
2705
+ return;
2706
+ }
2695
2707
 
2696
- notifCheckbox.checked = getNotificationPreference();
2708
+ if (notifPermission === "granted") {
2709
+ applyNotificationGrantedEffects();
2710
+ return;
2711
+ }
2712
+ };
2697
2713
 
2698
- notifCheckbox.onchange = function () {
2699
- setNotificationPreference(notifCheckbox.checked);
2714
+ var notifCheckbox = document.querySelector("#toggle-notifs");
2700
2715
 
2701
- if (!notifCheckbox.checked) {
2702
- // slice because arrayOfOpenedNotifications can be mutated while looping
2703
- arrayOfOpenedNotifications.slice().forEach(function (notification) {
2704
- notification.close();
2705
- });
2706
- }
2707
- };
2716
+ var applyNotificationNotAvailableEffects = function applyNotificationNotAvailableEffects() {
2717
+ var notifSetting = document.querySelector(".settings-notification");
2718
+ notifSetting.setAttribute("data-disabled", "true");
2719
+ notifSetting.setAttribute("title", "Notification not available in the browser");
2720
+ notifCheckbox.disabled = true;
2721
+ };
2708
2722
 
2709
- var notifPermission = Notification.permission;
2710
- enableVariant(document.querySelector(".notification-text"), {
2711
- notif_permission: notifPermission === "granted" ? "yes" : "no"
2712
- });
2723
+ var applyNotificationDefaultEffects = function applyNotificationDefaultEffects() {
2724
+ applyNotificationNOTGrantedEffects();
2725
+ var notifSetting = document.querySelector(".settings-notification");
2726
+ notifSetting.removeAttribute("data-disabled");
2727
+ notifSetting.removeAttribute("title");
2728
+ };
2713
2729
 
2714
- if (notifPermission === "default") {
2715
- document.querySelector("a.request_notification_permission").onclick = function () {
2716
- requestPermission().then(function () {
2717
- updatePermission();
2718
- });
2719
- };
2730
+ var applyNotificationDeniedEffects = function applyNotificationDeniedEffects() {
2731
+ applyNotificationNOTGrantedEffects();
2732
+ var notifSetting = document.querySelector(".settings-notification");
2733
+ notifSetting.setAttribute("data-disabled", "true");
2734
+ notifSetting.setAttribute("title", "Notification denied");
2735
+ };
2736
+
2737
+ var applyNotificationGrantedEffects = function applyNotificationGrantedEffects() {
2738
+ enableVariant(document.querySelector(".notification-text"), {
2739
+ notif_granted: "yes"
2740
+ });
2741
+ notifCheckbox.disabled = false;
2742
+ notifCheckbox.checked = getNotificationPreference();
2743
+
2744
+ notifCheckbox.onchange = function () {
2745
+ setNotificationPreference(notifCheckbox.checked);
2746
+
2747
+ if (!notifCheckbox.checked) {
2748
+ // slice because arrayOfOpenedNotifications can be mutated while looping
2749
+ arrayOfOpenedNotifications.slice().forEach(function (notification) {
2750
+ notification.close();
2751
+ });
2720
2752
  }
2721
2753
  };
2754
+ };
2722
2755
 
2723
- updatePermission();
2756
+ var applyNotificationNOTGrantedEffects = function applyNotificationNOTGrantedEffects() {
2757
+ enableVariant(document.querySelector(".notification-text"), {
2758
+ notif_granted: "no"
2759
+ });
2760
+ notifCheckbox.disabled = true;
2761
+ notifCheckbox.checked = false;
2762
+
2763
+ document.querySelector("a.request_notification_permission").onclick = function () {
2764
+ requestPermission().then(function () {
2765
+ setNotificationPreference(true);
2766
+ updatePermission();
2767
+ });
2768
+ };
2724
2769
  };
2725
2770
 
2726
2771
  var notifyExecutionResult = function notifyExecutionResult(executedFileRelativeUrl, execution, previousExecution) {
@@ -4426,21 +4471,10 @@ html[data-toolbar-visible] #toolbar-trigger {
4426
4471
  document.querySelector(".files_compilation_text").innerHTML = "Files shown are compiled for ".concat(runtimeReport.name, "@").concat(runtimeReport.version);
4427
4472
  }
4428
4473
 
4429
- filesCompilationRootNode.querySelector("a.link_to_source_files").onclick = function () {
4430
- window.parent.location.href = "/".concat(compileGroup.fileRelativeUrl);
4431
- };
4432
-
4433
- filesCompilationRootNode.querySelector("a.link_to_compiled_files").onclick = function () {
4434
- window.parent.location.href = "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl);
4435
- };
4436
-
4437
- filesCompilationRootNode.querySelector("a.link_to_compilation_forced_files").onclick = function () {
4438
- window.parent.location.href = "/".concat(jsenvDirectoryRelativeUrl, "force/").concat(compileGroup.fileRelativeUrl);
4439
- };
4440
-
4441
- filesCompilationRootNode.querySelector("a.link_to_appropriate_files").onclick = function () {
4442
- window.parent.location.href = "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl);
4443
- };
4474
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_source_files"), "/".concat(compileGroup.fileRelativeUrl));
4475
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_compiled_files"), "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl));
4476
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_compilation_forced_files"), "/".concat(jsenvDirectoryRelativeUrl, "force/").concat(compileGroup.fileRelativeUrl));
4477
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_appropriate_files"), "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl));
4444
4478
 
4445
4479
  if (hasWarning) {
4446
4480
  enableWarningStyle();
@@ -4739,10 +4773,7 @@ html[data-toolbar-visible] #toolbar-trigger {
4739
4773
  });
4740
4774
  }
4741
4775
 
4742
- document.querySelector(".toolbar-icon-wrapper").onclick = function () {
4743
- window.parent.location.href = "/";
4744
- };
4745
-
4776
+ setLinkHrefForParentWindow(document.querySelector(".toolbar-icon-wrapper"), "/");
4746
4777
  renderToolbarNotification();
4747
4778
  makeToolbarResponsive();
4748
4779
  renderToolbarSettings();
@@ -4935,7 +4966,7 @@ html[data-toolbar-visible] #toolbar-trigger {
4935
4966
  };
4936
4967
  });
4937
4968
 
4938
- //# sourceMappingURL=toolbar.main_279b3a68.js.map</script>
4969
+ //# sourceMappingURL=toolbar.main_2c56a4e0.js.map</script>
4939
4970
 
4940
4971
 
4941
4972
  </body></html>
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "assets/jsenv-logo.svg": "assets/jsenv-logo_188b9ca6.svg",
3
- "toolbar_injector.js": "toolbar_injector_34f6ad8e.js",
4
- "toolbar_injector.js.map": "toolbar_injector_34f6ad8e.js.map"
3
+ "toolbar_injector.js": "toolbar_injector_0f93509c.js",
4
+ "toolbar_injector.js.map": "toolbar_injector_0f93509c.js.map"
5
5
  }
@@ -746,7 +746,7 @@
746
746
  return then ? value.then(then) : value;
747
747
  }
748
748
 
749
- var TOOLBAR_BUILD_RELATIVE_URL = "dist/toolbar/toolbar_0a91ca3b.html";
749
+ var TOOLBAR_BUILD_RELATIVE_URL = "dist/toolbar/toolbar_17abd09a.html";
750
750
 
751
751
  function _call(body, then, direct) {
752
752
  if (direct) {
@@ -973,4 +973,4 @@
973
973
 
974
974
  })();
975
975
 
976
- //# sourceMappingURL=toolbar_injector_34f6ad8e.js.map
976
+ //# sourceMappingURL=toolbar_injector_0f93509c.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
- "file": "toolbar_injector_34f6ad8e.js",
3
+ "file": "toolbar_injector_0f93509c.js",
4
4
  "sources": [
5
5
  "../../helpers/babel/typeof/typeof.js",
6
6
  "../../helpers/babel/defineProperty/defineProperty.js",
@@ -25,7 +25,7 @@
25
25
  "import { fetchUrl } from \"./fetch_browser.js\"\n\nexport const fetchJson = async (url, options = {}) => {\n const response = await fetchUrl(url, options)\n const object = await response.json()\n return object\n}\n",
26
26
  "import { fetchJson } from \"../../browser_utils/fetchJson.js\"\n\nexport const fetchExploringJson = async ({ signal } = {}) => {\n try {\n const exploringInfo = await fetchJson(\"/.jsenv/exploring.json\", {\n signal,\n })\n return exploringInfo\n } catch (e) {\n if (signal && signal.aborted && e.name === \"AbortError\") {\n throw e\n }\n throw new Error(\n `Cannot communicate with exploring server due to a network error\n--- error stack ---\n${e.stack}`,\n )\n }\n}\n",
27
27
  "export const updateIframeOverflowOnParentWindow = () => {\n if (!window.parent) {\n // can happen while parent iframe reloads\n return\n }\n\n const aTooltipIsOpened =\n document.querySelector(\"[data-tooltip-visible]\") ||\n document.querySelector(\"[data-tooltip-auto-visible]\")\n const settingsAreOpened = document.querySelector(\"#settings[data-active]\")\n\n if (aTooltipIsOpened || settingsAreOpened) {\n enableIframeOverflowOnParentWindow()\n } else {\n disableIframeOverflowOnParentWindow()\n }\n}\n\nlet iframeOverflowEnabled = false\nconst enableIframeOverflowOnParentWindow = () => {\n if (iframeOverflowEnabled) return\n iframeOverflowEnabled = true\n\n const iframe = getToolbarIframe()\n const transitionDuration = iframe.style.transitionDuration\n setStyles(iframe, { \"height\": \"100%\", \"transition-duration\": \"0ms\" })\n if (transitionDuration) {\n setTimeout(() => {\n setStyles(iframe, { \"transition-duration\": transitionDuration })\n })\n }\n}\n\nconst disableIframeOverflowOnParentWindow = () => {\n if (!iframeOverflowEnabled) return\n iframeOverflowEnabled = false\n\n const iframe = getToolbarIframe()\n const transitionDuration = iframe.style.transitionDuration\n setStyles(iframe, { \"height\": \"40px\", \"transition-duration\": \"0ms\" })\n if (transitionDuration) {\n setTimeout(() => {\n setStyles(iframe, { \"transition-duration\": transitionDuration })\n })\n }\n}\n\nexport const getToolbarIframe = () => {\n const iframes = Array.from(window.parent.document.querySelectorAll(\"iframe\"))\n return iframes.find((iframe) => iframe.contentWindow === window)\n}\n\nexport const forceHideElement = (element) => {\n element.setAttribute(\"data-force-hide\", \"\")\n}\n\nexport const removeForceHideElement = (element) => {\n element.removeAttribute(\"data-force-hide\")\n}\n\nexport const setStyles = (element, styles) => {\n const elementStyle = element.style\n const restoreStyles = Object.keys(styles).map((styleName) => {\n let restore\n if (styleName in elementStyle) {\n const currentStyle = elementStyle[styleName]\n restore = () => {\n elementStyle[styleName] = currentStyle\n }\n } else {\n restore = () => {\n delete elementStyle[styleName]\n }\n }\n\n elementStyle[styleName] = styles[styleName]\n\n return restore\n })\n return () => {\n restoreStyles.forEach((restore) => restore())\n }\n}\n\nexport const setAttributes = (element, attributes) => {\n Object.keys(attributes).forEach((name) => {\n element.setAttribute(name, attributes[name])\n })\n}\n\nexport const getDocumentScroll = () => {\n return {\n x: document.documentElement.scrollLeft,\n y: document.documentElement.scrollTop,\n }\n}\n\nexport const toolbarSectionIsActive = (element) => {\n return element.hasAttribute(\"data-active\")\n}\n\nexport const activateToolbarSection = (element) => {\n element.setAttribute(\"data-active\", \"\")\n}\n\nexport const deactivateToolbarSection = (element) => {\n element.removeAttribute(\"data-active\")\n}\n",
28
- "import { fetchExploringJson } from \"@jsenv/core/src/internal/dev_server/exploring/fetchExploringJson.js\"\nimport { setAttributes, setStyles } from \"./util/dom.js\"\n\n// eslint-disable-next-line no-undef\nconst TOOLBAR_BUILD_RELATIVE_URL = \"dist/toolbar/toolbar_0a91ca3b.html\"\nconst jsenvLogoSvgUrl = new URL(\"./jsenv-logo.svg\", import.meta.url)\n\nconst injectToolbar = async () => {\n await new Promise((resolve) => {\n if (window.requestIdleCallback) {\n window.requestIdleCallback(resolve, { timeout: 400 })\n } else {\n window.requestAnimationFrame(resolve)\n }\n })\n const exploringJSON = await fetchExploringJson()\n const placeholder = getToolbarPlaceholder()\n\n const iframe = document.createElement(\"iframe\")\n setAttributes(iframe, {\n tabindex: -1,\n // sandbox: \"allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation\",\n // allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr\",\n allowtransparency: true,\n })\n setStyles(iframe, {\n \"position\": \"fixed\",\n \"zIndex\": 1000,\n \"bottom\": 0,\n \"left\": 0,\n \"width\": \"100%\",\n \"height\": 0,\n /* ensure toolbar children are not focusable when hidden */\n \"visibility\": \"hidden\",\n \"transition-duration\": \"300ms\",\n \"transition-property\": \"height, visibility\",\n \"border\": \"none\",\n })\n const iframeLoadedPromise = iframeToLoadedPromise(iframe)\n const jsenvCoreDirectoryServerUrl = new URL(\n exploringJSON.jsenvCoreDirectoryRelativeUrl,\n document.location.origin,\n ).href\n const jsenvToolbarHtmlServerUrl = new URL(\n TOOLBAR_BUILD_RELATIVE_URL,\n jsenvCoreDirectoryServerUrl,\n )\n // set iframe src BEFORE putting it into the DOM (prevent firefox adding an history entry)\n iframe.setAttribute(\"src\", jsenvToolbarHtmlServerUrl)\n placeholder.parentNode.replaceChild(iframe, placeholder)\n\n addToolbarEventCallback(iframe, \"toolbar_ready\", () => {\n sendCommandToToolbar(iframe, \"renderToolbar\", { exploringJSON })\n })\n\n await iframeLoadedPromise\n iframe.removeAttribute(\"tabindex\")\n\n const div = document.createElement(\"div\")\n div.innerHTML = `\n<div id=\"jsenv-toolbar-trigger\">\n <svg id=\"jsenv-toolbar-trigger-icon\">\n <use xlink:href=\"${jsenvLogoSvgUrl}#jsenv-logo\"></use>\n </svg>\n <style>\n #jsenv-toolbar-trigger {\n display: block;\n overflow: hidden;\n position: fixed;\n z-index: 1000;\n bottom: -32px;\n right: 20px;\n height: 40px;\n width: 40px;\n padding: 0;\n margin: 0;\n border-radius: 5px 5px 0 0;\n border: 1px solid rgba(0, 0, 0, 0.33);\n border-bottom: none;\n box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.46);\n background: transparent;\n text-align: center;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger:hover {\n cursor: pointer;\n }\n\n #jsenv-toolbar-trigger[data-expanded] {\n bottom: 0;\n }\n\n #jsenv-toolbar-trigger-icon {\n width: 35px;\n height: 35px;\n opacity: 0;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger[data-expanded] #jsenv-toolbar-trigger-icon {\n opacity: 1;\n }\n </style>\n</div>`\n const toolbarTrigger = div.firstElementChild\n iframe.parentNode.appendChild(toolbarTrigger)\n\n let timer\n toolbarTrigger.onmouseenter = () => {\n toolbarTrigger.setAttribute(\"data-animate\", \"\")\n timer = setTimeout(expandToolbarTrigger, 500)\n }\n toolbarTrigger.onmouseleave = () => {\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onfocus = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n expandToolbarTrigger()\n }\n toolbarTrigger.onblur = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onclick = () => {\n sendCommandToToolbar(iframe, \"showToolbar\")\n }\n\n const showToolbarTrigger = () => {\n toolbarTrigger.style.display = \"block\"\n }\n\n const hideToolbarTrigger = () => {\n toolbarTrigger.style.display = \"none\"\n }\n\n const expandToolbarTrigger = () => {\n toolbarTrigger.setAttribute(\"data-expanded\", \"\")\n }\n\n const collapseToolbarTrigger = () => {\n toolbarTrigger.removeAttribute(\"data-expanded\", \"\")\n }\n\n hideToolbarTrigger()\n addToolbarEventCallback(iframe, \"toolbar-visibility-change\", (visible) => {\n if (visible) {\n hideToolbarTrigger()\n } else {\n showToolbarTrigger()\n }\n })\n\n return iframe\n}\n\nconst addToolbarEventCallback = (iframe, eventName, callback) => {\n const messageEventCallback = (messageEvent) => {\n const { data } = messageEvent\n if (typeof data !== \"object\") {\n return\n }\n const { __jsenv__ } = data\n if (!__jsenv__) {\n return\n }\n if (__jsenv__.event !== eventName) {\n return\n }\n callback(__jsenv__.data)\n }\n\n window.addEventListener(\"message\", messageEventCallback, false)\n return () => {\n window.removeEventListener(\"message\", messageEventCallback, false)\n }\n}\n\nconst sendCommandToToolbar = (iframe, command, ...args) => {\n iframe.contentWindow.postMessage(\n {\n __jsenv__: {\n command,\n args,\n },\n },\n window.origin,\n )\n}\n\nconst getToolbarPlaceholder = () => {\n const placeholder = queryPlaceholder()\n if (placeholder) {\n if (document.body.contains(placeholder)) {\n return placeholder\n }\n // otherwise iframe would not be visible because in <head>\n console.warn(\n \"element with [data-jsenv-toolbar-placeholder] must be inside document.body\",\n )\n return createTooolbarPlaceholder()\n }\n return createTooolbarPlaceholder()\n}\n\nconst queryPlaceholder = () => {\n return document.querySelector(\"[data-jsenv-toolbar-placeholder]\")\n}\n\nconst createTooolbarPlaceholder = () => {\n const placeholder = document.createElement(\"span\")\n document.body.appendChild(placeholder)\n return placeholder\n}\n\nconst iframeToLoadedPromise = (iframe) => {\n return new Promise((resolve) => {\n const onload = () => {\n iframe.removeEventListener(\"load\", onload, true)\n resolve()\n }\n iframe.addEventListener(\"load\", onload, true)\n })\n}\n\nif (document.readyState === \"complete\") {\n injectToolbar()\n} else {\n window.addEventListener(\"load\", injectToolbar)\n // document.addEventListener(\"readystatechange\", () => {\n // if (document.readyState === \"complete\") {\n // injectToolbar()\n // }\n // })\n}\n"
28
+ "import { fetchExploringJson } from \"@jsenv/core/src/internal/dev_server/exploring/fetchExploringJson.js\"\nimport { setAttributes, setStyles } from \"./util/dom.js\"\n\n// eslint-disable-next-line no-undef\nconst TOOLBAR_BUILD_RELATIVE_URL = \"dist/toolbar/toolbar_17abd09a.html\"\nconst jsenvLogoSvgUrl = new URL(\"./jsenv-logo.svg\", import.meta.url)\n\nconst injectToolbar = async () => {\n await new Promise((resolve) => {\n if (window.requestIdleCallback) {\n window.requestIdleCallback(resolve, { timeout: 400 })\n } else {\n window.requestAnimationFrame(resolve)\n }\n })\n const exploringJSON = await fetchExploringJson()\n const placeholder = getToolbarPlaceholder()\n\n const iframe = document.createElement(\"iframe\")\n setAttributes(iframe, {\n tabindex: -1,\n // sandbox: \"allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation\",\n // allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr\",\n allowtransparency: true,\n })\n setStyles(iframe, {\n \"position\": \"fixed\",\n \"zIndex\": 1000,\n \"bottom\": 0,\n \"left\": 0,\n \"width\": \"100%\",\n \"height\": 0,\n /* ensure toolbar children are not focusable when hidden */\n \"visibility\": \"hidden\",\n \"transition-duration\": \"300ms\",\n \"transition-property\": \"height, visibility\",\n \"border\": \"none\",\n })\n const iframeLoadedPromise = iframeToLoadedPromise(iframe)\n const jsenvCoreDirectoryServerUrl = new URL(\n exploringJSON.jsenvCoreDirectoryRelativeUrl,\n document.location.origin,\n ).href\n const jsenvToolbarHtmlServerUrl = new URL(\n TOOLBAR_BUILD_RELATIVE_URL,\n jsenvCoreDirectoryServerUrl,\n )\n // set iframe src BEFORE putting it into the DOM (prevent firefox adding an history entry)\n iframe.setAttribute(\"src\", jsenvToolbarHtmlServerUrl)\n placeholder.parentNode.replaceChild(iframe, placeholder)\n\n addToolbarEventCallback(iframe, \"toolbar_ready\", () => {\n sendCommandToToolbar(iframe, \"renderToolbar\", { exploringJSON })\n })\n\n await iframeLoadedPromise\n iframe.removeAttribute(\"tabindex\")\n\n const div = document.createElement(\"div\")\n div.innerHTML = `\n<div id=\"jsenv-toolbar-trigger\">\n <svg id=\"jsenv-toolbar-trigger-icon\">\n <use xlink:href=\"${jsenvLogoSvgUrl}#jsenv-logo\"></use>\n </svg>\n <style>\n #jsenv-toolbar-trigger {\n display: block;\n overflow: hidden;\n position: fixed;\n z-index: 1000;\n bottom: -32px;\n right: 20px;\n height: 40px;\n width: 40px;\n padding: 0;\n margin: 0;\n border-radius: 5px 5px 0 0;\n border: 1px solid rgba(0, 0, 0, 0.33);\n border-bottom: none;\n box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.46);\n background: transparent;\n text-align: center;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger:hover {\n cursor: pointer;\n }\n\n #jsenv-toolbar-trigger[data-expanded] {\n bottom: 0;\n }\n\n #jsenv-toolbar-trigger-icon {\n width: 35px;\n height: 35px;\n opacity: 0;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger[data-expanded] #jsenv-toolbar-trigger-icon {\n opacity: 1;\n }\n </style>\n</div>`\n const toolbarTrigger = div.firstElementChild\n iframe.parentNode.appendChild(toolbarTrigger)\n\n let timer\n toolbarTrigger.onmouseenter = () => {\n toolbarTrigger.setAttribute(\"data-animate\", \"\")\n timer = setTimeout(expandToolbarTrigger, 500)\n }\n toolbarTrigger.onmouseleave = () => {\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onfocus = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n expandToolbarTrigger()\n }\n toolbarTrigger.onblur = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onclick = () => {\n sendCommandToToolbar(iframe, \"showToolbar\")\n }\n\n const showToolbarTrigger = () => {\n toolbarTrigger.style.display = \"block\"\n }\n\n const hideToolbarTrigger = () => {\n toolbarTrigger.style.display = \"none\"\n }\n\n const expandToolbarTrigger = () => {\n toolbarTrigger.setAttribute(\"data-expanded\", \"\")\n }\n\n const collapseToolbarTrigger = () => {\n toolbarTrigger.removeAttribute(\"data-expanded\", \"\")\n }\n\n hideToolbarTrigger()\n addToolbarEventCallback(iframe, \"toolbar-visibility-change\", (visible) => {\n if (visible) {\n hideToolbarTrigger()\n } else {\n showToolbarTrigger()\n }\n })\n\n return iframe\n}\n\nconst addToolbarEventCallback = (iframe, eventName, callback) => {\n const messageEventCallback = (messageEvent) => {\n const { data } = messageEvent\n if (typeof data !== \"object\") {\n return\n }\n const { __jsenv__ } = data\n if (!__jsenv__) {\n return\n }\n if (__jsenv__.event !== eventName) {\n return\n }\n callback(__jsenv__.data)\n }\n\n window.addEventListener(\"message\", messageEventCallback, false)\n return () => {\n window.removeEventListener(\"message\", messageEventCallback, false)\n }\n}\n\nconst sendCommandToToolbar = (iframe, command, ...args) => {\n iframe.contentWindow.postMessage(\n {\n __jsenv__: {\n command,\n args,\n },\n },\n window.origin,\n )\n}\n\nconst getToolbarPlaceholder = () => {\n const placeholder = queryPlaceholder()\n if (placeholder) {\n if (document.body.contains(placeholder)) {\n return placeholder\n }\n // otherwise iframe would not be visible because in <head>\n console.warn(\n \"element with [data-jsenv-toolbar-placeholder] must be inside document.body\",\n )\n return createTooolbarPlaceholder()\n }\n return createTooolbarPlaceholder()\n}\n\nconst queryPlaceholder = () => {\n return document.querySelector(\"[data-jsenv-toolbar-placeholder]\")\n}\n\nconst createTooolbarPlaceholder = () => {\n const placeholder = document.createElement(\"span\")\n document.body.appendChild(placeholder)\n return placeholder\n}\n\nconst iframeToLoadedPromise = (iframe) => {\n return new Promise((resolve) => {\n const onload = () => {\n iframe.removeEventListener(\"load\", onload, true)\n resolve()\n }\n iframe.addEventListener(\"load\", onload, true)\n })\n}\n\nif (document.readyState === \"complete\") {\n injectToolbar()\n} else {\n window.addEventListener(\"load\", injectToolbar)\n // document.addEventListener(\"readystatechange\", () => {\n // if (document.readyState === \"complete\") {\n // injectToolbar()\n // }\n // })\n}\n"
29
29
  ],
30
30
  "names": [
31
31
  "nativeTypeOf",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "25.4.2",
3
+ "version": "25.4.7",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,7 +11,8 @@
11
11
  "node": ">=16.13.0"
12
12
  },
13
13
  "publishConfig": {
14
- "access": "public"
14
+ "access": "public",
15
+ "registry": "https://registry.npmjs.org"
15
16
  },
16
17
  "type": "module",
17
18
  "exports": {
@@ -141,4 +142,4 @@
141
142
  "redux": "4.1.2",
142
143
  "rollup-plugin-import-assert": "1.1.1"
143
144
  }
144
- }
145
+ }
@@ -139,7 +139,7 @@ export const compileHtml = async ({
139
139
  addHtmlMutation,
140
140
  })
141
141
  }
142
- await visitImportmapScript({
142
+ await visitImportmapScripts({
143
143
  logger,
144
144
  url,
145
145
  compiledUrl,
@@ -245,7 +245,7 @@ const visitRessourceHints = async ({ ressourceHints, addHtmlMutation }) => {
245
245
  )
246
246
  }
247
247
 
248
- const visitImportmapScript = async ({
248
+ const visitImportmapScripts = async ({
249
249
  logger,
250
250
  url,
251
251
  compiledUrl,
@@ -265,14 +265,15 @@ const visitImportmapScript = async ({
265
265
  const type = typeAttribute ? typeAttribute.value : "application/javascript"
266
266
  return type === "importmap"
267
267
  })
268
+ const jsenvImportmap = getDefaultImportmap(compiledUrl, {
269
+ projectDirectoryUrl,
270
+ compileDirectoryUrl,
271
+ })
272
+
268
273
  // in case there is no importmap, force the presence
269
274
  // so that '@jsenv/core/' are still remapped
270
275
  if (importmapScripts.length === 0) {
271
- const defaultImportMap = getDefaultImportmap(compiledUrl, {
272
- projectDirectoryUrl,
273
- compileDirectoryUrl,
274
- })
275
- const defaultImportMapAsText = JSON.stringify(defaultImportMap, null, " ")
276
+ const defaultImportMapAsText = JSON.stringify(jsenvImportmap, null, " ")
276
277
  onHtmlImportmapInfo({
277
278
  url: compiledUrl,
278
279
  text: defaultImportMapAsText,
@@ -324,6 +325,7 @@ const visitImportmapScript = async ({
324
325
  )
325
326
  importmap = {}
326
327
  }
328
+ importmap = composeTwoImportMaps(jsenvImportmap, importmap)
327
329
  const importmapAsText = JSON.stringify(importmap, null, " ")
328
330
  onHtmlImportmapInfo({
329
331
  url: importmapUrl,
@@ -343,10 +345,6 @@ const visitImportmapScript = async ({
343
345
  return
344
346
  }
345
347
 
346
- const jsenvImportmap = getDefaultImportmap(compiledUrl, {
347
- projectDirectoryUrl,
348
- compileDirectoryUrl,
349
- })
350
348
  const htmlImportmap = JSON.parse(
351
349
  getHtmlNodeTextNode(firstImportmapScript).value,
352
350
  )
@@ -20,5 +20,8 @@ export const sameValueInTwoObjects = (object, secondObject) => {
20
20
  }
21
21
 
22
22
  export const sameValuesInTwoArrays = (array, secondArray) => {
23
- return array.every((value) => secondArray.includes(value))
23
+ return (
24
+ array.length === secondArray.length &&
25
+ array.every((value) => secondArray.includes(value))
26
+ )
24
27
  }
@@ -61,8 +61,9 @@ const readJsenvCoreVersionFromPackageFile = async () => {
61
61
  "./package.json",
62
62
  jsenvCoreDirectoryUrl,
63
63
  )
64
- const jsenvCoreVersion = await readFile(jsenvCorePackageFileUrl, {
64
+ const jsenvCorePackage = await readFile(jsenvCorePackageFileUrl, {
65
65
  as: "json",
66
- }).version
67
- return jsenvCoreVersion
66
+ })
67
+ const version = jsenvCorePackage.version
68
+ return version
68
69
  }
@@ -84,7 +84,7 @@ export const setupJsenvDirectory = async ({
84
84
  const { runtimes } = compileDirectory
85
85
  if (!runtimes.includes(runtime)) {
86
86
  runtimes.push(runtime)
87
- await writeMetaFile()
87
+ writeMetaFile()
88
88
  }
89
89
  return existingCompileId
90
90
  }
@@ -1,4 +1,5 @@
1
1
  import { scanBrowserRuntimeFeatures } from "../../../features/browser_feature_detection/browser_feature_detection.js"
2
+ import { setLinkHrefForParentWindow } from "../util/iframe_to_parent_href.js"
2
3
  import { removeForceHideElement } from "../util/dom.js"
3
4
  import { enableVariant } from "../variant/variant.js"
4
5
  import {
@@ -101,25 +102,24 @@ export const renderCompilationInToolbar = ({ compileGroup }) => {
101
102
  ".files_compilation_text",
102
103
  ).innerHTML = `Files shown are compiled for ${runtimeReport.name}@${runtimeReport.version}`
103
104
  }
104
- filesCompilationRootNode.querySelector("a.link_to_source_files").onclick =
105
- () => {
106
- window.parent.location.href = `/${compileGroup.fileRelativeUrl}`
107
- }
108
- filesCompilationRootNode.querySelector(
109
- "a.link_to_compiled_files",
110
- ).onclick = () => {
111
- window.parent.location.href = `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`
112
- }
113
- filesCompilationRootNode.querySelector(
114
- "a.link_to_compilation_forced_files",
115
- ).onclick = () => {
116
- window.parent.location.href = `/${jsenvDirectoryRelativeUrl}force/${compileGroup.fileRelativeUrl}`
117
- }
118
- filesCompilationRootNode.querySelector(
119
- "a.link_to_appropriate_files",
120
- ).onclick = () => {
121
- window.parent.location.href = `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`
122
- }
105
+ setLinkHrefForParentWindow(
106
+ filesCompilationRootNode.querySelector("a.link_to_source_files"),
107
+ `/${compileGroup.fileRelativeUrl}`,
108
+ )
109
+ setLinkHrefForParentWindow(
110
+ filesCompilationRootNode.querySelector("a.link_to_compiled_files"),
111
+ `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`,
112
+ )
113
+ setLinkHrefForParentWindow(
114
+ filesCompilationRootNode.querySelector(
115
+ "a.link_to_compilation_forced_files",
116
+ ),
117
+ `/${jsenvDirectoryRelativeUrl}force/${compileGroup.fileRelativeUrl}`,
118
+ )
119
+ setLinkHrefForParentWindow(
120
+ filesCompilationRootNode.querySelector("a.link_to_appropriate_files"),
121
+ `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`,
122
+ )
123
123
 
124
124
  if (hasWarning) {
125
125
  enableWarningStyle()
@@ -6,51 +6,80 @@ const notificationPreference = createPreference("notification")
6
6
 
7
7
  const arrayOfOpenedNotifications = []
8
8
  export const renderToolbarNotification = () => {
9
- const notifCheckbox = document.querySelector("#toggle-notifs")
10
9
  if (!notificationAvailable) {
11
- const notifSetting = document.querySelector(".settings-notification")
12
- notifSetting.setAttribute("data-disabled", "true")
13
- notifSetting.setAttribute(
14
- "title",
15
- `Notification not available in the browser`,
16
- )
17
- notifCheckbox.disabled = true
10
+ applyNotificationNotAvailableEffects()
18
11
  return
19
12
  }
13
+ updatePermission()
14
+ }
20
15
 
21
- const updatePermission = () => {
22
- if (Notification.permission === "denied") {
23
- const notifSetting = document.querySelector(".settings-notification")
24
- notifSetting.setAttribute("data-disabled", "true")
25
- notifSetting.setAttribute("title", `Notification denied`)
26
- notifCheckbox.disabled = true
27
- return
28
- }
16
+ const updatePermission = () => {
17
+ const notifPermission = Notification.permission
18
+ if (notifPermission === "default") {
19
+ applyNotificationDefaultEffects()
20
+ return
21
+ }
22
+ if (notifPermission === "denied") {
23
+ applyNotificationDeniedEffects()
24
+ return
25
+ }
26
+ if (notifPermission === "granted") {
27
+ applyNotificationGrantedEffects()
28
+ return
29
+ }
30
+ }
29
31
 
30
- notifCheckbox.checked = getNotificationPreference()
31
- notifCheckbox.onchange = () => {
32
- setNotificationPreference(notifCheckbox.checked)
33
- if (!notifCheckbox.checked) {
34
- // slice because arrayOfOpenedNotifications can be mutated while looping
35
- arrayOfOpenedNotifications.slice().forEach((notification) => {
36
- notification.close()
37
- })
38
- }
32
+ const notifCheckbox = document.querySelector("#toggle-notifs")
33
+
34
+ const applyNotificationNotAvailableEffects = () => {
35
+ const notifSetting = document.querySelector(".settings-notification")
36
+ notifSetting.setAttribute("data-disabled", "true")
37
+ notifSetting.setAttribute(
38
+ "title",
39
+ `Notification not available in the browser`,
40
+ )
41
+ notifCheckbox.disabled = true
42
+ }
43
+ const applyNotificationDefaultEffects = () => {
44
+ applyNotificationNOTGrantedEffects()
45
+ const notifSetting = document.querySelector(".settings-notification")
46
+ notifSetting.removeAttribute("data-disabled")
47
+ notifSetting.removeAttribute("title")
48
+ }
49
+ const applyNotificationDeniedEffects = () => {
50
+ applyNotificationNOTGrantedEffects()
51
+ const notifSetting = document.querySelector(".settings-notification")
52
+ notifSetting.setAttribute("data-disabled", "true")
53
+ notifSetting.setAttribute("title", `Notification denied`)
54
+ }
55
+ const applyNotificationGrantedEffects = () => {
56
+ enableVariant(document.querySelector(".notification-text"), {
57
+ notif_granted: "yes",
58
+ })
59
+ notifCheckbox.disabled = false
60
+ notifCheckbox.checked = getNotificationPreference()
61
+ notifCheckbox.onchange = () => {
62
+ setNotificationPreference(notifCheckbox.checked)
63
+ if (!notifCheckbox.checked) {
64
+ // slice because arrayOfOpenedNotifications can be mutated while looping
65
+ arrayOfOpenedNotifications.slice().forEach((notification) => {
66
+ notification.close()
67
+ })
39
68
  }
40
- const notifPermission = Notification.permission
41
- enableVariant(document.querySelector(".notification-text"), {
42
- notif_permission: notifPermission === "granted" ? "yes" : "no",
69
+ }
70
+ }
71
+ const applyNotificationNOTGrantedEffects = () => {
72
+ enableVariant(document.querySelector(".notification-text"), {
73
+ notif_granted: "no",
74
+ })
75
+ notifCheckbox.disabled = true
76
+ notifCheckbox.checked = false
77
+ document.querySelector("a.request_notification_permission").onclick = () => {
78
+ requestPermission().then(() => {
79
+ setNotificationPreference(true)
80
+ updatePermission()
43
81
  })
44
- if (notifPermission === "default") {
45
- document.querySelector("a.request_notification_permission").onclick =
46
- () => {
47
- requestPermission().then(() => {
48
- updatePermission()
49
- })
50
- }
51
- }
52
82
  }
53
- updatePermission()
54
83
  }
55
84
 
56
85
  export const notifyExecutionResult = (
@@ -281,7 +281,7 @@
281
281
  Send system notification when execution fails or is fixed.
282
282
  <div class="notification-text">
283
283
  <a
284
- data-when="notif_permission:no"
284
+ data-when="notif_granted:no"
285
285
  class="request_notification_permission"
286
286
  href="javascript:void(0);"
287
287
  >Enable notification</a
@@ -3,6 +3,7 @@ import { urlToRelativeUrl } from "@jsenv/filesystem/src/urlToRelativeUrl.js"
3
3
 
4
4
  import { startJavaScriptAnimation } from "../toolbar/util/animation.js"
5
5
  import "./focus/toolbar.focus.js"
6
+ import { setLinkHrefForParentWindow } from "./util/iframe_to_parent_href.js"
6
7
  import {
7
8
  getToolbarIframe,
8
9
  deactivateToolbarSection,
@@ -52,9 +53,10 @@ const renderToolbar = async ({ exploringJSON }) => {
52
53
  hideToolbar({ animate: false })
53
54
  }
54
55
 
55
- document.querySelector(".toolbar-icon-wrapper").onclick = () => {
56
- window.parent.location.href = "/"
57
- }
56
+ setLinkHrefForParentWindow(
57
+ document.querySelector(".toolbar-icon-wrapper"),
58
+ "/",
59
+ )
58
60
 
59
61
  renderToolbarNotification()
60
62
  makeToolbarResponsive()
@@ -0,0 +1,10 @@
1
+ export const setLinkHrefForParentWindow = (a, href) => {
2
+ a.href = href
3
+ a.onclick = (e) => {
4
+ if (e.ctrlKey || e.metaKey) {
5
+ return
6
+ }
7
+ e.preventDefault()
8
+ window.parent.location.href = href
9
+ }
10
+ }
@@ -18,7 +18,6 @@ export const getDefaultImportmap = (
18
18
  jsenvCoreDirectoryUrl,
19
19
  projectDirectoryUrl,
20
20
  )
21
-
22
21
  let jsenvCoreUrl
23
22
  if (compileDirectoryUrl && urlIsInsideOf(url, compileDirectoryUrl)) {
24
23
  jsenvCoreUrl = resolveUrl(
@@ -28,25 +27,11 @@ export const getDefaultImportmap = (
28
27
  } else {
29
28
  jsenvCoreUrl = jsenvCoreDirectoryUrl
30
29
  }
31
-
30
+ const jsenvCoreRelativeUrl = urlToRelativeUrl(jsenvCoreUrl, url)
32
31
  const importmap = {
33
32
  imports: {
34
- "@jsenv/core/": makeRelativeMapping(jsenvCoreUrl, url),
33
+ "@jsenv/core/": `./${jsenvCoreRelativeUrl}`,
35
34
  },
36
35
  }
37
36
  return importmap
38
37
  }
39
-
40
- // this function just here to ensure relative urls starts with './'
41
- // so that importmap do not consider them as bare specifiers
42
- const makeRelativeMapping = (url, baseUrl) => {
43
- const relativeUrl = urlToRelativeUrl(url, baseUrl)
44
-
45
- if (urlIsInsideOf(url, baseUrl)) {
46
- if (relativeUrl.startsWith("../")) return relativeUrl
47
- if (relativeUrl.startsWith("./")) return relativeUrl
48
- return `./${relativeUrl}`
49
- }
50
-
51
- return relativeUrl
52
- }