mobiwek61menu
Version:
Mobile Friendly cascading menu with zoom/pan image view. AI composition tested ok.
2 lines • 4.2 MB
JavaScript
/*! For license information please see bundle.js.LICENSE.txt */
(()=>{var __webpack_modules__={"../src/PackageTreeEntry.tsx":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ MediaPictureWithInfo: () => (/* reexport safe */ _mobiwekView_MediaPictureWithInfo_tsx__WEBPACK_IMPORTED_MODULE_2__.MediaPictureWithInfo),\n/* harmony export */ MobiWekMenuFrame: () => (/* reexport safe */ _mobiwekMenu_mobiwekMenuFrameHelper__WEBPACK_IMPORTED_MODULE_3__.MobiWekMenuFrame),\n/* harmony export */ MobiWekPageWrapper: () => (/* reexport safe */ _mobiwekView_MobiWekPageWrapper__WEBPACK_IMPORTED_MODULE_4__.MobiWekPageWrapper),\n/* harmony export */ Popup_descrip_qr_scrollTips: () => (/* reexport safe */ _util_Popup_descrip_qr_scrollTips__WEBPACK_IMPORTED_MODULE_0__.Popup_descrip_qr_scrollTips),\n/* harmony export */ favoriteCheese: () => (/* reexport safe */ _mobiwekView_MediaPictureWithInfo_tsx__WEBPACK_IMPORTED_MODULE_2__.favoriteCheese),\n/* harmony export */ findJsonObjectByFullPath: () => (/* reexport safe */ _mobiwekMenu_mobiwekUtils__WEBPACK_IMPORTED_MODULE_1__.findJsonObjectByFullPath),\n/* harmony export */ findJsonObjectByKeyNameAndValue: () => (/* reexport safe */ _mobiwekMenu_mobiwekUtils__WEBPACK_IMPORTED_MODULE_1__.findJsonObjectByKeyNameAndValue),\n/* harmony export */ sayHi: () => (/* binding */ sayHi),\n/* harmony export */ validateMwMenu: () => (/* reexport safe */ _mobiwekMenu_mobiwekUtils__WEBPACK_IMPORTED_MODULE_1__.validateMwMenu)\n/* harmony export */ });\n/* harmony import */ var _util_Popup_descrip_qr_scrollTips__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util/Popup_descrip_qr_scrollTips */ "../src/util/Popup_descrip_qr_scrollTips.js");\n/* harmony import */ var _mobiwekMenu_mobiwekUtils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mobiwekMenu/mobiwekUtils */ "../src/mobiwekMenu/mobiwekUtils.js");\n/* harmony import */ var _mobiwekView_MediaPictureWithInfo_tsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mobiwekView/MediaPictureWithInfo.tsx */ "../src/mobiwekView/MediaPictureWithInfo.tsx");\n/* harmony import */ var _mobiwekMenu_mobiwekMenuFrameHelper__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./mobiwekMenu/mobiwekMenuFrameHelper */ "../src/mobiwekMenu/mobiwekMenuFrameHelper.js");\n/* harmony import */ var _mobiwekView_MobiWekPageWrapper__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./mobiwekView/MobiWekPageWrapper */ "../src/mobiwekView/MobiWekPageWrapper.js");\n/*\r\n This is the javascript file which goes into file webpack.config.js:\r\n entry: \'../src/PackageTreeEntry.tsx\',\r\n\r\n Entry means 2 things:\r\n 1. "start dependency graph at this file" to build bundle.js\r\n 2. when index.html has this: <script src="/bundle_localdev.js" type="text/javascript"><\/script>\r\n the bundle\'s exports get available via the DOM window object (see example index.html in webpack projects)\r\n 2a. when script is called, every non-function javascript code in any file in the bundle gets run.\r\n Typically there is code to start React.js ie: ReactDOM.createRoot( ...\r\n\r\n Typescript:\r\n This file began as javascript. Later I used a typescript file for\r\n something and needed to export a typescript "interface". In order to\r\n get this file to pass through the export, it had to be converted\r\n to typescript also. See exports section. \r\n*/\n\n\n\n// NOTE THAT TYPESCRIPT IMPORT MUST END WITH TS OR TSX. ANY TYPESCRIPT HAVING\n// JSX IN IT MUST HAVE A TSX SUFFIX\n\n\n\n\n// ReactDOM.createRoot( ... can go here to startup react for development.\n// Instead, I put it in a dev-only js file which gets put into the dev bundle. That way you see what\'s going on.\nconsole.log(\'running code at PackageTreeEntry.js Oct 2 to npmjs\');\n\n// this code would be automatically run if a client imported the bundle.\n// Clients typically run this code themselves, so they can specify their own menus and callbacks.\n// so that\'s why its commented out.\n// function CreateReactRootFromDivAndRunMobiWekDemo() {\n// // console.log("running bundle code from file PackageTreeEntry.js. Now loading div \\"" + rootDivName + "\\" with React stuff")\n// const root = ReactDOM.createRoot(document.getElementById(rootDivName));\n// // console.log(\'root \' + root)\n// root.render(\n// <div>\n// <MobiWekDemo />\n// </div>\n// );\n// }\n\n// NOTE: it only wants to return values as JSON, not a simple string when used as an export\nfunction sayHi() {\n return {\n msg: \'...sayHi() from PackageTreeEntry.js in the bundle\'\n };\n}\n\n// export { sayHi, MobiWekDemo, PopupDebugShowsQRandCmdLine, findJsonObjectByFullPath, findJsonObjectByKeyNameAndValue, \n// validateMwMenu, MediaPictureWithInfo, MobiWekMenuFrame, MobiWekPageWrapper }\n\n// TODO: webpack.config_build.js gives warning:\n// export \'PopupProps\' (reexported as \'PopupProps\') was not found in \'./mobiwekView/MediaPictureWithInfo.tsx\' (possible exports: MediaPictureWithInfo, favoriteCheese)\n\n\n// this is a typescript thing. It specifies a set of parameters passed\n// to a function by the mobiwek framework.\n\n//# sourceURL=webpack:///../src/PackageTreeEntry.tsx?')},"../src/mobiwekMenu/Html5AnimationHelper.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ DoHtml5AnimateSlide: () => (/* binding */ DoHtml5AnimateSlide)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n\n\n//var fontAwsomeSizeThing = \"2x\"; // see options at end of this file\n//var theIcon = FaBars //<FontAwesomeIcon icon={faBars} size={fontAwsomeSizeThing} />\n\nconst animEndDontAddMeTwice = (htmlElem, hideMe) => {\n // console.log('animEndDontAddMeTwice'); \n if (hideMe) htmlElem.style.display = 'none';\n};\nconst x_hidden = -250;\n\n/* animation done by html5, not react.js code \r\n https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations \r\n JavaScript can access the @keyframes at-rule with the CSS object model interface CSSKeyframesRule.\r\n About forwardRef: its used here to expose function SlideToOpen to code outside DoHtml5AnimateSlide \r\n Something about creating a ref to it in the client code... */\nconst DoHtml5AnimateSlide = /*#__PURE__*/(0,react__WEBPACK_IMPORTED_MODULE_0__.forwardRef)((propsSlide, ref) => {\n /* useImperativeHandle somehow exposes it to outside this functional component\r\n This does a dom CSS javascript animation.\r\n Using useState() as a param to this component causes a refresh, which gums\r\n up the css animation of it sliding left and right.\r\n Only ONE function is possible as far as I can tell */\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useImperativeHandle)(ref, overrideIfNotNull => ({\n ToggleMenuSlideInOut(override) {\n if (document.querySelector('#divSlidesInToShowMenu').classList.contains('animateSlideFromLeft')) {\n override = false; // menu IS OPEN so close it\n }\n if (override == null) {\n SlideToOpen();\n } else if (override === true) {\n SlideToOpen();\n } else {\n SlideToClose();\n }\n }\n }));\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n id: \"divSlidesInToShowMenu\",\n style: {\n left: {\n x_hidden\n },\n display: 'none',\n position: 'relative',\n zIndex: '10'\n }\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(propsSlide.sideSlidePayload, {\n menuCallBackPtr: propsSlide.menuCallBackPtr /* runs callback in client code */,\n CloseSliderFn: SlideToClose\n }));\n function SlideToOpen() {\n // also ok const SlideToOpen = () => {\n const divSlidesInToShowMenu = document.querySelector('#divSlidesInToShowMenu');\n // dont do this way because they get added each time..... elemA.addEventListener(\"animationend\", animEndDontAddMeTwice(elemA, false)); \n divSlidesInToShowMenu.onanimationend = event => {\n animEndDontAddMeTwice(divSlidesInToShowMenu, false);\n /* below tells menu to scroll itself into position. Necessary for\r\n the FIRST time only; subsequent calls its already fully setup. \r\n See tag for this control to see what the actual function is */\n //// fails when something is chosen... if (firstCalled.current) \n propsSlide.onPayloadVisible();\n ////firstCalled.current = false;\n };\n divSlidesInToShowMenu.style.display = 'block'; // make VISIBLE!\n divSlidesInToShowMenu.classList.remove('animateSlideNhide');\n divSlidesInToShowMenu.classList.add('animateSlideFromLeft');\n /* onPayloadVisible gets called when page is directed to a url bookmark\r\n and menu slides-in and needs to be scrolled to\r\n accommodate the current url which may be several levels down ie:\r\n http://localhost:3000/pictures/tableware/cups */\n\n /* 0=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=0\r\n SAVE DONT DELETE!!!!! SHOWS HOW TO ANIMATE IN CODE, NOT USING CSS FILE.\r\n IT LETS YOU USE VARIABLES TO DETERMINE ANIMATION PARAMETERS WHICH CANNOT\r\n BE DONE USING CSS FILE. NOT USED HERE SO SOURCE CODE NOT NEEDED TO TUNE ANIMATION.\r\n const slideNbounce_keyframes = [{ transform: 'translateX(' + x_hidden + 'px)' }, \r\n { transform: 'translateX(' + x_visible + 'px)' }];\r\n divSlidesInToShowMenu.animate(slideNbounce_keyframes, \r\n { duration: 250, \r\n // TO GET BEZIER VISIT https://cubic-bezier.com/#.17,.67,.87,.26\r\n easing: 'cubic-bezier(0,.96,1,1.11)', // goes past and bounces back bc > 1.0\r\n fill:'forwards', direction:'normal' } // fill means keep new postion. direction:theDirection javascript--bezierCurveTo() \r\n );\r\n 0=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=0 */\n }\n function SlideToClose(zz) {\n const elemB = document.querySelector('#divSlidesInToShowMenu');\n // htmlElem.style.display = 'block'; // make VISIBLE!\n elemB.classList.remove('animateSlideFromLeft');\n elemB.classList.add('animateSlideNhide');\n // hide it when animation has completed, not before\n elemB.onanimationend = event => {\n animEndDontAddMeTwice(elemB, true);\n };\n /* 0=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=0\r\n SAVE DONT DELETE!!!!! SHOWS HOW TO ANIMATE IN CODE, NOT USING CSS FILE.\r\n IT LETS YOU USE VARIABLES TO DETERMINE ANIMATION PARAMETERS WHICH CANNOT\r\n BE DONE USING CSS FILE. NOT USED HERE SO SOURCE CODE NOT NEEDED TO TUNE ANIMATION. \r\n var anim = htmlElem.animate([{ transform: 'translateX(' + x_hidden + 'px)' }], \r\n { duration: 500, // BELOW TO GET BEZIER VISIT https://cubic-bezier.com/#.17,.67,.87,.26\r\n easing: 'cubic-bezier(.22,0,.91,1.27)', // goes past and bounces back bc > 1.0\r\n fill:'forwards', direction:'normal' } // fill means keep new postion. direction:theDirection javascript--bezierCurveTo() \r\n );\r\n // https://developer.mozilla.org/en-US/docs/Web/API/Animation/finished\r\n anim.finished.then( () => { \r\n // console.log('amin done') // finished is a \"promise\"\r\n htmlElem.style.display = 'none';\r\n });\r\n 0=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=00=0=0=0=0=0=0=0 */\n }\n}); // forwardRef\n\n/* SAVE as simple example\r\nconst TestCSSanimation = () => {\r\n var showYesHideNo = false;\r\n const doAnimate = (event) => {\r\n var slideX = 200;\r\n const htmlElem = document.getElementById('divDoingTheSliding'); // not portable.. event.target;\r\n htmlElem.style.background = '#ffff00'\r\n showYesHideNo = !showYesHideNo;\r\n const hideIt_keyframes = [{ transform: 'translateX(' + slideX + 'px)' },\r\n { transform: 'translateX(0px)' }];\r\n const slideNbounce_keyframes = [{ transform: 'translateX(0px)' }, \r\n { transform: 'translateX(' + slideX + 'px)' }]; //,\r\n //{ transform: 'translateX(' + (slideX - 10) + 'px)' }];\r\n var keyFrameSet = hideIt_keyframes; // gets changed...\r\n if (showYesHideNo) {\r\n htmlElem.style.background = '#00ffff'\r\n keyFrameSet = slideNbounce_keyframes;\r\n }\r\n // most googles give css file @keyframes method. I like this better\r\n // https://developer.mozilla.org/en-US/docs/Web/API/Element/animate\r\n // https://developer.mozilla.org/en-US/docs/Web/API/KeyframeEffect/KeyframeEffect#parameters\r\n event.target.animate(keyFrameSet, \r\n { duration: 500, // BELOW TO GET BEZIER VISIT https://cubic-bezier.com/#.17,.67,.87,.26\r\n easing: 'cubic-bezier(.22,0,.91,1.27)', // goes past and bounces back bc > 1.0\r\n fill:'forwards', direction:'normal' }\r\n // fill means keep new postion. direction:theDirection javascript--bezierCurveTo() \r\n );\r\n }\r\n return (<div id='divDoingTheSliding' style={{height:'140px',width:'100px', \r\n background:'#2da73f', border:'3px solid #000', borderRadius:'5px'}} \r\n onClick={(event)=>doAnimate(event)} ></div>)\r\n} */\n\n\n\n//# sourceURL=webpack:///../src/mobiwekMenu/Html5AnimationHelper.js?")},"../src/mobiwekMenu/mobiWekGlobals.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ok_mwmtype_Values: () => (/* binding */ ok_mwmtype_Values)\n/* harmony export */ });\nconst ok_mwmtype_Values = {\n handwriting: 1,\n image: 1,\n text: 1,\n mwtypNull: 1,\n reactRoute: 1\n};\n\n\n//# sourceURL=webpack:///../src/mobiwekMenu/mobiWekGlobals.js?")},"../src/mobiwekMenu/mobiwekMenuBuilder.jsx":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ MobiWekAutoXYScrollMenuComponent: () => (/* binding */ MobiWekAutoXYScrollMenuComponent),\n/* harmony export */ sayHi: () => (/* binding */ sayHi)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _mobiwekMenuBuilderHelper__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./mobiwekMenuBuilderHelper */ \"../src/mobiwekMenu/mobiwekMenuBuilderHelper.js\");\n/* harmony import */ var _mobiWekGlobals__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./mobiWekGlobals */ \"../src/mobiwekMenu/mobiWekGlobals.js\");\n/* harmony import */ var react_icons_fa__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! react-icons/fa */ \"../node_modules/react-icons/fa/index.mjs\");\n/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react/jsx-runtime */ \"../node_modules/react/jsx-runtime.js\");\nfunction _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }\n\n// import { useNavigate } from \"react-router-dom\";\n\n\n// import { FaRedoAlt as MenuHomeIcon } from \"react-icons/fa\";\n\n\nvar jsonPath = __webpack_require__(/*! jsonpath */ \"../node_modules/jsonpath/jsonpath.js\");\n// import { FaRegPlusSquare } from \"react-icons/fa\";\n// import { FaRegMinusSquare } from \"react-icons/fa\";\nvar reactNeedsThisUniqueKey = 0; // need key otherwise error\nvar allmwmKeys = [];\n\n/* places a MobiwekBuildMenu inside a scrollable div.\r\n This div serves as a viewport through which the menu shows; the menu may be\r\n several times the screen width, and this div scrolls to show the desired section */\nfunction MobiWekAutoXYScrollMenuComponent(props) {\n var ref_unHighLightMeNextClick = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)();\n var mobiWekMenuTreeScrollingRoot = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)();\n var ref_menuElementWasClicked = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(false);\n var quittingError = false;\n var errMsg;\n /* !!! useEffect() !!! huh ?\r\n In the React world \"useEffect\" is a conponent lifecycle function. Controlled by argument 2 as follows:\r\n missing: run always; [] empty: run only once when component mounts; [foo] run when useState foo changes */\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n if (quittingError) return;\n mobiWekMenuTreeScrollingRoot.current.addEventListener('click', event => {\n // event.stopPropagation(); // preventDefault()\n // console.log('click')\n scrollingDivClick(event.target, event, props.CloseSliderFn, ref_menuElementWasClicked.current);\n }, false); // this third argument \"useCapture\" seems to determine event bubbling order \n }, []); // [] present: only on load .. \n\n var fsize = new URLSearchParams(props.windowDotLocation.search).get('mwmfont');\n // SAVE as example console.log('picUrl ' + new URLSearchParams(props.windowDotLocation.search).get('picUrl'))\n // console.log('picUrl2 ' + new URLSearchParams(props.windowDotLocation.search).get('picUrl2'))\n var regexMatch;\n if (fsize) regexMatch = fsize.match(/(^\\d*\\.?\\d*px$)/);\n if (fsize && !regexMatch) {\n quittingError = true;\n console.log('ERROR -QUITTING: mwmfont of ' + fsize + ' not allowed. Must be like \"6px\"');\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null, \"ERROR -QUITTING: mwmfont of \", fsize, \" not allowed. Must be like \\\"6px\\\"\");\n }\n if (fsize) document.body.style.setProperty('--mwmMenuFontSize', fsize);\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n id: \"resetNscroll\",\n style: {\n // border:'4px solid red',\n // position:'absolute'\n }\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(DoFontUpAndDownAndHomeButtons, props), \" \", /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n ref: mobiWekMenuTreeScrollingRoot\n /* this div acts as a window into the menu div which gets scrolled. As the menu grows\r\n too wide to fit in this div, this window scrolls, so the right edge of the\r\n menu is always visible. Done using complicated javascript. */,\n id: \"mobiWekMenuTreeScrollingRoot\",\n style: {\n marginLeft: '2vw',\n height: '80vh',\n //border:'11px dotted yellow',\n // peanuts width:'90vw', overflowY:'scroll', overflowX:'overlay' }} \n width: '90vw',\n overflowY: 'scroll',\n overflowX: 'scroll'\n }\n /* in CSS file: #mobiWekMenuTreeScrollingRoot::-webkit-scrollbar{ display: none; } \r\n prevents a wierd 1px wide scrollbar from appearing */\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(MobiwekBuildMenuRecursiveReactCompon, _extends({}, props, {\n isRoot: \"yes\"\n }))));\n function DoFontUpAndDownAndHomeButtons(propsFUD) {\n // SAVE shows how to get css in code... \n // useEffect(() => { console.log( // wont work without useEffect bc menuTitle does not yet exist...\n // document.querySelector(\"#menuTitle\").style.getPropertyValue('margin-left'))}, []); \n var screenScaler = getComputedStyle(document.body).getPropertyValue('--mwmMenuScrnScaler');\n var leftMargin = (0,_mobiwekMenuBuilderHelper__WEBPACK_IMPORTED_MODULE_1__.isDesktop)(document) ? '40vw' : '15vw';\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n id: \"menuHomeDiv\",\n style: {\n display: 'inline',\n width: '100%',\n zIndex: '30'\n }\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n id: \"menuTitle\",\n style: {\n float: 'left',\n marginLeft: leftMargin,\n marginTop: '2vmin',\n fontSize: screenScaler * 0.06 + 'px'\n }\n }, propsFUD.appTitle), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(react_icons_fa__WEBPACK_IMPORTED_MODULE_4__.FaHome, {\n id: \"reset_menu\",\n className: \"fontPlusMinusButtonsA\",\n style: {\n float: 'right',\n color: 'black',\n fontSize: screenScaler * 0.10 + 'px',\n marginRight: '2px'\n },\n onClick: () => {\n /* User wants to collapse menus and scroll to 0.\r\n Get all elements matching and do a forEach on the list to set CSS class to hide.\r\n Then do similar to scroll viewport back to 0 */\n document.querySelectorAll('[mobiwekrole=\"BRANCH_SUBMENU\"]').forEach(submenu => {\n submenu.classList.remove('dispBlockClass');\n document.querySelector('#mobiWekMenuTreeScrollingRoot').scroll({\n left: 0,\n behavior: 'smooth'\n });\n });\n }\n }), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"span\", {\n style: {\n float: 'right',\n fontSize: screenScaler * 0.07 + 'px'\n }\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"span\", {\n className: \"fontPlusMinusButtonsA\",\n onClick: () => {\n (0,_mobiwekMenuBuilderHelper__WEBPACK_IMPORTED_MODULE_1__.changeFontSize)(false);\n }\n }, \"A-\"), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"span\", {\n style: {\n paddingLeft: '1.2vmin',\n fontSize: screenScaler * 0.09 + 'px'\n },\n className: \"fontPlusMinusButtonsA\",\n onClick: () => {\n (0,_mobiwekMenuBuilderHelper__WEBPACK_IMPORTED_MODULE_1__.changeFontSize)(true);\n }\n }, \"A+\"))));\n }\n function MobiwekBuildMenuRecursiveReactCompon(props) {\n (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {\n if (props.isRoot === 'yes') {\n // do ONLY for ROOT element, not ALL element\n if (errMsg !== undefined) {\n var foo = document.querySelectorAll('[mobiwekrole=\"headOfMenuTreeWithTableRowDisplay\"]');\n foo[0].innerHTML = '<div style=\"width:80vmin; font-size:22px; color:yellow; background:black;\">' + 'error(s) in menu specification<br/>' + errMsg + '</div>';\n console.log(foo[0].innerHTML);\n }\n allmwmKeys = []; // reset for next load sometime\n componentOnRender(props);\n }\n // var movingMenuDiv = document.querySelector('[mobiwekrole=\"pushWidthOut\"]')\n // movingMenuDiv.addEventListener('mousedown', () => { mouseDown = true; })\n // movingMenuDiv.addEventListener('mouseup', () => { mouseDown = false; })\n // movingMenuDiv.addEventListener('mousemove', (evt) => { \n // if (mouseDown) {\n // console.log('menu drag ' + evt.target.attributes.mobiwekrole.value)\n // }\n // })\n }); // [] missing: run after every render. (no dependencies)\n\n var mouseDown = false;\n const uniqueKey = props.prefix + '/' + props.nextLoc.mwmkey;\n if (allmwmKeys.indexOf(uniqueKey) != -1) {\n errMsg = 'duplicate keys in menu spec. mwmkey: \\\"' + uniqueKey + '\\\"';\n }\n allmwmKeys.push(uniqueKey);\n function componentOnRender(props) {\n /* occurs ONCE in recursions because its ROOT */\n /* NOTE: use ref_ things so that below function shares with THIS function */\n (0,_mobiwekMenuBuilderHelper__WEBPACK_IMPORTED_MODULE_1__.mobiwekSetMenuButtonEvents)(ref_unHighLightMeNextClick, ref_menuElementWasClicked, props.CloseSliderFn, props.menuCallBackPtr);\n // 65 msec for big menu.. console.log('menu setup time: ' + (Date.now() - startt) + ' ms');\n (0,_mobiwekMenuBuilderHelper__WEBPACK_IMPORTED_MODULE_1__.setMenuToWindowLocation)(props.windowDotLocation);\n if (!fsize) {\n /* The url does not specify a font size. So calculate a starting size. \r\n TAGS so I can find this later: default mwmfont \r\n here is where the default fontsize is setup when not specified. */\n var minWidOrHeightFactor = getComputedStyle(document.body).getPropertyValue('--mwmMenuScrnScaler');\n /* now save it as a css variable aka custom property\r\n divide by 15 gives 24px size on a phone... */\n var sizeSpec = (minWidOrHeightFactor / 15).toFixed(1) + 'px';\n document.body.style.setProperty('--mwmMenuFontSize', sizeSpec);\n }\n }\n if (props.nextLoc.DD_MENU_HEAD) {\n // console.log('menu spec revision: \\\"' + props.nextLoc.REV + '\\\"');\n return (\n /*#__PURE__*/\n /* from docs: \"table-row These elements behave like <tr> HTML elements\"\r\n This forces all elements inside div to have same width, so appearance and pushbuttons line up ok */\n react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n mobiwekrole: \"pushWidthOut\",\n style: {\n width: '600vw'\n }\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n mobiwekrole: \"headOfMenuTreeWithTableRowDisplay\",\n style: {\n display: 'table-row',\n border: '3px solid red'\n }\n }, props.nextLoc.DD_MENU_HEAD.map(childElem => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(MobiwekBuildMenuRecursiveReactCompon, _extends({}, props, {\n isRoot: \"no\",\n key: reactNeedsThisUniqueKey++,\n nextLoc: childElem,\n prefix: ''\n })))))\n );\n }\n if (props.nextLoc.BRANCH) {\n var _props$nextLoc$BRANCH;\n var ppx = props.prefix ? props.prefix + '/' : '';\n var pathA = ppx + props.nextLoc.mwmkey; // console.log('Menu prefix: ' + pathA)\n /* BUG: branch label may be a react.fragment generated by a JSX expression. \r\n It may contain divs and img tags, which can EAT A MOUSE CLICK and not pass it to the BRANCH.\r\n a branch label may be a string or a JSX expression (react.fragment)\r\n FIX: find them and set pointerEvents:'none' */\n /* what's \"type?\" .. if type is null evaluates to false instead of crashing.\r\n This is a nice typescript feature since I changed to .tsx from .js */\n if (((_props$nextLoc$BRANCH = props.nextLoc.BRANCH.type) === null || _props$nextLoc$BRANCH === void 0 ? void 0 : _props$nextLoc$BRANCH.toString()) === 'Symbol(react.fragment)') {\n var elementsToModify = findDivAndImgInFragment(props.nextLoc.BRANCH);\n elementsToModify.forEach(jsxTag => {\n try {\n jsxTag.props.style.pointerEvents = 'none';\n } catch (ex) {}\n });\n }\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n mobiwekrole: \"BRANCH\"\n }, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n mobiwekrole: \"BRANCH_BUTTON\"\n }, props.nextLoc.BRANCH), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n mobiwekrole: \"BRANCH_SUBMENU\"\n }, props.nextLoc.items.map(childElem => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(MobiwekBuildMenuRecursiveReactCompon, _extends({}, props, {\n isRoot: \"no\",\n key: reactNeedsThisUniqueKey++,\n nextLoc: childElem,\n prefix: pathA\n })))));\n }\n if (props.nextLoc.LEAF) {\n var mwmkeyVal = props.prefix === '' ? props.nextLoc.mwmkey : props.prefix + '/' + props.nextLoc.mwmkey;\n // no longer needed. now using recursive path search. \n // props.nextLoc.fullPath = mwmkeyVal; \n // add path to json object, apart from DOM. For searching later.\n // console.log(\"Item mwmkey: \" + mwmkeyVal)\n return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0___default().createElement(\"div\", {\n mobiwekrole: \"LEAF\",\n style: {\n borderRight: '1px solid #001bce'\n },\n mwmkey: mwmkeyVal\n }, props.nextLoc.LEAF);\n }\n }\n\n /* called when div containing menu is clicked; called AFTER button is clicked, thanks to\r\n \"useCapture\" argument to addEventListener(). If no button pressed, it hides the menu.\r\n If button pressed, re-scrolls the menu to useful position */\n function scrollingDivClick(thisElement, evt, CloseSliderFn) {\n // console.log('scrollingDivClick ' + thisElement.id);\n if (!ref_menuElementWasClicked.current) {\n // if user clicked outside element they want it closed.\n // console.log('no menu clicked')\n CloseSliderFn();\n }\n ref_menuElementWasClicked.current = false; // reset for next click\n }\n} // MobiWekAutoXYScrollMenuComponent\n\n/** uses jsonpath to find and img or div tags in a react fragment */\nfunction findDivAndImgInFragment(fragmentToSearch) {\n var jsonPathQueryString = \"$..*[?(@.type=='div'||@.type=='img')]\";\n /* jsonPathQuery = \"$..*[?(@.mwmkey=='winslowHomerFogWarning')]\"\r\n ^ $ is root of tree\r\n ^^ 2 dots is \"Recursive descent\" drill-down operator\r\n ^ wildcard \"anything within the tree having next thing\"\r\n they call this \"filter\" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */\n var matchA = jsonPath.query(fragmentToSearch, jsonPathQueryString);\n return matchA;\n}\n\n// const Memo_MobiWekAutoXYScrollMenuComponent = memo(MobiWekAutoXYScrollMenuComponent)\nconst sayHi = () => {\n console.log('this is hi from MobiwekMenuBuilder.js in the package');\n};\n\n\n// not used approach to set pointerevents='none'\n// Replaced by jsonpath approach to find those tags.\n// if (props.nextLoc.BRANCH.type && props.nextLoc.BRANCH.type.toString() === 'Symbol(react.fragment)') {\n// // console.log('JSX labelled branch')\n// props.nextLoc.BRANCH.props.children.forEach(jsxTag => {\n// if (jsxTag.type && new Set([\"div\", \"img\"]).has(jsxTag.type.toString())) {\n// //jsxTag.props.style.setProperty('pointerEvents', 'none')\n// try { jsxTag.props.style.pointerEvents='none' } catch (ex) {}\n// // console.log('div or img!')\n// }\n// // console.log('zz' + jsxTag)\n// // if (jsxTag.type) console.log(' yy ' + jsxTag.type.toString() )\n// }) \n// }\n\n//# sourceURL=webpack:///../src/mobiwekMenu/mobiwekMenuBuilder.jsx?")},"../src/mobiwekMenu/mobiwekMenuBuilderHelper.js":(__unused_webpack_module,__webpack_exports__,__webpack_require__)=>{"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ changeFontSize: () => (/* binding */ changeFontSize),\n/* harmony export */ isDesktop: () => (/* binding */ isDesktop),\n/* harmony export */ mobiwekSetMenuButtonEvents: () => (/* binding */ mobiwekSetMenuButtonEvents),\n/* harmony export */ scrollVandHToShowChosenSubmenu: () => (/* binding */ scrollVandHToShowChosenSubmenu),\n/* harmony export */ setMenuToWindowLocation: () => (/* binding */ setMenuToWindowLocation)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"react\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n\n/**\r\n * Helper functions for menu builder.\r\n * Some variables used by these functions are React useRef() things so that their:\r\n * 1) values get preserved across function calls\r\n * 2) values get shared with caller who is a react function component\r\n */\n\n/* preset menu selection to props.currPath ie \"pictures/tableware/forks\"\r\n To do this find the BRANCH_SUBMENU with mwmkey matching above. Then make it its siblings\r\n and its parent elements visible, similar to the onclick action way of doing it. \r\n */\nfunction setMenuToWindowLocation(windowDotLocation) {\n /* inspect window.location and setup menu state and scroll position to match */\n // pathname strips out -> ?mwmfont=8\n var targetKey = '[mwmkey=\\'' + windowDotLocation.pathname.slice(1) + '\\']'; // slice leading '/'\n // typically -> [mwmkey='pictures/artists/andywarhol/soupcan']\n // or, document.querySelectorAll([mwmkey='pictures/artists/andywarhol/soupcan']);\n // \"get me list of elements where mwmkey attribute is 'pictures/artists/andywarhol/soupcan' \"\n // console.log('targetKey ' + targetKey)\n var nodeListA = document.querySelectorAll(targetKey);\n // nodeListA.forEach (nodeWithKey => { console.log('i found: ' + nodeWithKey.textContent) });\n if (nodeListA.length > 1) console.log('WARNING: DUPLICATE MWMKEY IN TREE');\n var nodeMatchingWindowLocation = nodeListA.item(0);\n // above is a node. outerHTML is: <div mobiwekrole=\"LEAF\" mwmkey=\"workshopTools/hand/pliers\">pliers</div>\n if (!nodeMatchingWindowLocation) return;\n nodeMatchingWindowLocation.setAttribute('mwmCurrent', \"mwmchosen\");\n nodeMatchingWindowLocation.classList.add('chosenMenuLeaf');\n // nodeMatchingWindowLocation.style.setProperty('border', 'solid 3px #ffcccc')\n // \"get me list of elements with mobiwekrole attribute == 'BRANCH_SUBMENU' \"\n document.querySelectorAll('[mobiwekrole=\"BRANCH_SUBMENU\"]').forEach(submenu => {\n if (submenu === nodeMatchingWindowLocation || submenu.contains(nodeMatchingWindowLocation) || nodeMatchingWindowLocation.contains(submenu)) {\n submenu.classList.add('dispBlockClass');\n // previousSibling of a BRANCH_SUBMENU gets its corresponding BRANCH_BUTTON which has a solid or hollow arrow\n // now set the arrow after its title to solid to indicate in selected path\n submenu.previousSibling.style.setProperty('--mwmBtnAfterShape', 'var(--unicodeSolidRightTri)');\n }\n });\n if (nodeMatchingWindowLocation.attributes.mobiwekrole.textContent === 'LEAF') {\n /* add marker class so auto-scroll wont cut off the leaf */\n nodeMatchingWindowLocation.classList.add('leafDummyClass');\n }\n}\n\n/* obsolete. I found out that using a JSX expression in menu spec makes this unnecessary \r\n/ * to incorporate <br/> into label. Must be restrictive to prevent injection. \r\n avoids use of dangerouslySetInnerHTML * /\r\nfunction doHtmlBreakTag(zz) {\r\n // SPLIT USING A REGULAR EXPRESSION WITH TWO DELIMITERS (ONE IS <br/> other is <br />).\r\n var parts = zz.split(/<br\\/\\>|<br \\/\\>/i) // HEY! DONT PUT REGEX IN QUOTATION MARKS!!!\r\n // ^ the i means IGNORE CASE\r\n if (parts.length === 1) return zz;\r\n / * now build a jsx thing. String wont work because html markup like <br/> gets rendered\r\n literally, as a safety measure. \r\n Why is Fragment with key used? because if not, render works ok but the console\r\n gives a warning from React that each fragment must have a unique key. It\r\n really seems to demand this. * /\r\n const breaktag = <br/>; \r\n const space4 = <> </>;\r\n var newJSX = parts.map((pt, idx) => { \r\n if (idx == parts.length - 1) {\r\n return (<Fragment key={idx}>{ pt }</Fragment>)\r\n } else {\r\n return (<Fragment key={idx}>{ pt }{ breaktag }{ space4 }</Fragment>)\r\n }})\r\n // return (<span key={idx++}>{ pt }{ breaktag }{ space4 }</span>)})\r\n return(newJSX)\r\n }\r\n */\n/* other method but has problems\r\nconst jsxArrayThing = [];\r\nvar idx = 0;\r\nparts.forEach(pt => {\r\n jsxArrayThing.push(<Fragment key={idx++}>{ parts[idx++] }</Fragment>)\r\n jsxArrayThing.push(<Fragment key={idx++}>{ breaktag }{ space4 }</Fragment>)\r\n})\r\njsxArrayThing.pop(); // remove last <br/> and spaces\r\nreturn(jsxArrayThing)\r\n*/\n/* note: map produces another array not a string! */\n/* another way of doing it using map */\n// SAVE console.log(parts.map((pt, i) => { return('pt is: ' + pt)}))\n\n/* another way using foreach instead of map\r\nfunction doHtmlBreakTag(zz) {\r\n // SPLIT USING A REGULAR EXPRESSION WITH TWO DELIMITERS (ONE IS <br/> other is <br />).\r\n var parts = zz.split(/<br\\/\\>|<br \\/\\>/i) // HEY! DONT PUT REGEX IN QUOTATION MARKS!!!\r\n // ^ the i means IGNORE CASE\r\n if (parts.length === 1) return zz;\r\n console.log('breaktag ' + zz)\r\n const breaktag = <br/>; \r\n const space4 = <> </>;\r\n const jsxArrayThing = [];\r\n var idx = 0;\r\n parts.forEach(pt => {\r\n jsxArrayThing.push(<>{ parts[idx++] }</>)\r\n jsxArrayThing.push(<>{ breaktag }{ space4 }</>)\r\n })\r\n jsxArrayThing.pop(); // remove last <br/> and spaces\r\n return(<>{jsxArrayThing}</>)\r\n //var parts = zz.split(/(<br\\/>)|(\\ ){2,}/); // var parts = zz.split(/(\\ ){2,}/);\r\n // parts.forEach(bb => { // });\r\n}\r\n*/\n\nfunction hideOpenMenusExceptClickedSuccession(ancestors, clickedBranch) {\n // HIDE ALL menus EXCEPT those which are ancestors or descendants\n ancestors.forEach(submenu => {\n if (!(submenu === clickedBranch) && !submenu.contains(clickedBranch) && !clickedBranch.contains(submenu)) {\n submenu.classList.remove('dispBlockClass');\n }\n });\n}\n\n/** scrolls screen so chosenDomNode is in a nice place on the screen. Does it by recursing up the tree\r\n * and summing widths and heights of nodes along the way */\nfunction scrollVandHToShowChosenSubmenu(chosenDomNode, extraWidth) {\n if (chosenDomNode === null) return;\n var runner = chosenDomNode;\n var XscrollTotal = runner.clientWidth + extraWidth; // include the leaf node width to start with\n var YscrollTotal = 0; // if not initialized get NaN like the tv show\n\n const menuHeadNode = document.querySelector('[mobiwekrole=\"headOfMenuTreeWithTableRowDisplay\"]');\n\n // CALCULATE X OFFSET FOR SCROLLING \n do {\n // if (runner.attributes.mobiwekrole && runner.attributes.mobiwekrole.textContent === 'BRANCH') // only BRANCH pushes node to the right\n if (runner.attributes.mobiwekrole.textContent === 'BRANCH')\n // only BRANCH pushes node to the right\n XscrollTotal += runner.clientWidth;\n runner = runner.parentElement;\n } while (runner !== menuHeadNode);\n var scrollingFrameOfMenu = document.querySelector('#mobiWekMenuTreeScrollingRoot');\n // if scroll amount is narrow than window, do nothing\n if (XscrollTotal - scrollingFrameOfMenu.clientWidth > 0) {\n XscrollTotal = XscrollTotal - scrollingFrameOfMenu.clientWidth;\n } else {\n XscrollTotal = 0;\n }\n\n // SHIFT Y OFFSET SO ITEM IS NOT SCRUNCHED AGAINST BOTTOM EDGE\n YscrollTotal = addHeightsRecurse(chosenDomNode, 0, menuHeadNode);\n if (YscrollTotal - scrollingFrameOfMenu.clientHeight * .75 > 0) {\n // this puts chosen menu item at bottom edge\n YscrollTotal = YscrollTotal - scrollingFrameOfMenu.clientHeight;\n // not lift it up so it's fully visible. Mobile landscape node needs more offset....\n YscrollTotal += scrollingFrameOfMenu.clientHeight * .55;\n } else {\n YscrollTotal = 0;\n }\n scrollingFrameOfMenu.scroll({\n left: XscrollTotal,\n top: YscrollTotal,\n behavior: 'smooth'\n });\n}\n\n// BRANCH\n// / \\\n// BRANCH_BUTTON BRANCH_SUBMENU \n\n/** recurses upward in the DOM tree from 'runner', summing heights in order to obtain\r\n * the y offset of the chosen node, so the screen may be scrolled so its in a nice place \r\n * Leave console.log's in place, control flow hard to follow! */\nfunction addHeightsRecurse(runner, Ysum, menuHeadNode) {\n // console.log(runner.getAttribute('mobiwekrole'), runner.clientHeight, runner.textContent)\n if (runner === menuHeadNode) return Ysum;\n // if (runner.getAttribute('mobiwekrole') === 'BRANCH')\n // console.log(runner.firstChild.textContent)\n if (!runner.previousSibling) {\n // we are at top leaf in a submenu or menu. \n var parentSubMenu = runner.parentNode;\n if (parentSubMenu === menuHeadNode) return Ysum; // at very top, break out now.\n // console.log('BRANCH_BUTTON text: ' + parentSubMenu.previousSibling.textContent)\n // recurse up to parent menu\n return addHeightsRecurse(parentSubMenu.parentNode, Ysum + runner.clientHeight, menuHeadNode);\n }\n // add height of previous sibling to total, then recurse with previous sibling\n return addHeightsRecurse(runner.previousSibling, Ysum + runner.clientHeight, menuHeadNode);\n}\nfunction ancestorsToSolidArrow(clickedBranch) {\n // Nope... var labelist = document.querySelectorAll('[--mwmBtnAfterShape=\"var(--unicodeHollowRightTri)\"]');\n // \"get me all elements with mobiwekrole == 'BRANCH' \"\n var ancestors = document.querySelectorAll('[mobiwekrole=\"BRANCH\"]');\n ancestors.forEach(theBranch => {\n // see \"buoy88\" to see why below works\n var labelForTheBranch = theBranch.firstElementChild;\n if (!(theBranch === clickedBranch) && theBranch.contains(clickedBranch) && !clickedBranch.contains(theBranch)) {\n // console.log('labelForTheBranch ' + labelForTheBranch.textContent)\n labelForTheBranch.style.setProperty('--mwmBtnAfterShape', 'var(--unicodeSolidRightTri)');\n // it works!.. labelForTheBranch.style.setProperty('--mwmBtnAfterColor', 'red');\n } else {\n labelForTheBranch.style.setProperty('--mwmBtnAfterShape', 'var(--unicodeHollowRightTri)');\n }\n });\n}\nfunction mobiwekSetMenuButtonEvents(ref_unHighLightMeNextClick, ref_menuElementWasClicked, CloseSliderFn, menuCallBackPtr) {\n /* below obtains a \"NodeList\" of all buttons and adds click listener to each.\r\n It uses forEach to iterate through; oneBranch is the current pointer */\n document.querySelectorAll('[mobiwekrole=\"BRANCH_BUTTON\"]').forEach(oneBranch => {\n oneBranch.addEventListener('click', function (branchButtonEvent) {\n // console.log('click evt oneBranch: ' + oneBranch.innerHTML)\n ref_menuElementWasClicked.current = true; // reset element-clicked flag\n /* get the corresponding BRANCH_SUBMENU. see \"Buoy88\" comment to see why nextSibling is used */\n var targetSubmenu = branchButtonEvent.target.nextSibling;\n /* should be BRANCH_SUBMENU... console.log('targetSubmenu.attributes.mobiwekrole ' + targetSubmenu.attributes.mobiwekrole.textContent) */\n hideOpenMenusExceptClickedSuccession(document.querySelectorAll('[mobiwekrole=\"BRANCH_SUBMENU\"]'), targetSubmenu);\n var DOMTokenList_A = targetSubmenu.classList;\n /* NOTE: \"toggle() adds the class if not present OR removes it\r\n if present, and returns the final state:\r\n Returns TRUE if it is now a 'dispBlockClass' */\n var I_am_visible_now = DOMTokenList_A.toggle('dispBlockClass');\n /* LOOK! this is how to set variable in css file! ie \"var(--variableNameInCSS_file\" */\n /* LOOK! this is how to set variable in css file! ie \"var(--variableNameInCSS_file\"*/\n var submenuOfThisButton = branchButtonEvent.target.nextSibling;\n if (I_am_visible_now) {\n // branch was just opened\n targetSubmenu.setAttribute('latestClickedSubMenu', \"thatsMe\");\n ref_unHighLightMeNextClick.current = targetSubmenu;\n // alert: to fix vertical scroll when branch below bottom clicked\n /* see Commit (which broke it) 1533c45 on Oct 31, 2024 */\n scrollVandHToShowChosenSubmenu(targetSubmenu.parentNode, 0);\n // below without .parentNode BREAKS when branch below bottom clicked\n // scrollVandHToShowChosenSubmenu(targetSubmenu, 0)\n } else {\n // branch was just closed\n // whoops! this removes the node ... targetSubmenu.remove('latestClickedSubMenu', \"pizza\")\n // does nothing.. delete targetSubmenu.latestClickedSubMenu;\n targetSubmenu.setAttribute('latestClickedSubMenu', \"NOT_ME\");\n /* hide its sub-menus if it just got hidden. Refer to \"Buoy88\" for hierarchy */\n var mySubMenus_NodeList = branchButtonEvent.target.parentNode.querySelectorAll('[mobiwekrole=\"BRANCH_SUBMENU\"]');\n mySubMenus_NodeList.forEach(subElem => {\n // console.log('hide role ' + subElem.attributes.mobiwekrole.textContent);\n // below used for menu scrolling calculation\n subElem.classList.remove('dispBlockClass');\n subElem.classList.remove('leafDummyClass');\n });\n // scrollVandHToShowChosenSubmenu(branchButtonEvent.target.parentNode, -branchButtonEvent.target.clientWidth)\n // alert: removing parentNode may introduce a bug?? Removed to simplify code..\n scrollVandHToShowChosenSubmenu(branchButtonEvent.target, -branchButtonEvent.target.clientWidth);\n }\n ancestorsToSolidArrow(oneBranch);\n });\n });\n document.querySelectorAll('[mobiwekrole=\"LEAF\"]').forEach(theleaf => {\n // iterate allLeafs; theleaf is the current object in loop\n // console.log('theleaf ' + theleaf.innerHTML)\n theleaf.addEventListener('click', function (event) {\n // event.target.style.border = '5px dotted red'\n event.target.style.setProperty('background', 'red');\n //console.log('todo when press get rid of current hilite')\n setTimeout(() => {\n // delay a bit so user sees choice light up\n // console.log('todo pause to show highlilghted choice')\n ref_menuElementWasClicked.current = true;\n // event.target.classList.toggle('dispBlockClass')\n // console.log('click leaf: ' + event.target.innerText)\n // + ' mwmkey: ' + event.target.attributes.mwmkey.textContent) //parentElement\n CloseSliderFn();\n /* call the menu callback specified as param */\n var fontSearchUrlParam = document.body.style.getPropertyValue('--mwmMenuFontSize');\n // console.log('--mwmMenuFontSize property ' + fontSearchUrlParam);\n fontSearchUrlParam = '?mwmfont=' + fontSearchUrlParam;\n /* typically function menuCallback in MobiWekDemo.js It calls Navigate() */\n /* whoops, sometimes an image is clicked inside a button. If so, use its parent. */\n if (event.target.nodeName === 'IMG') menuCallBackPtr(event.target.parentNode.attributes.mwmkey.textContent, event.target.innerText, fontSearchUrlParam); // innerHTML outerText outerHTML\n else menuCallBackPtr(event.target.attributes.mwmkey.textContent, event.target.innerText, fontSearchUrlParam); // innerHTML outerText outerHTML\n }, 333);\n });\n });\n} // mobiwekSetMenuButtonEvents\n\nfunction changeFontSize(makeBigger) {\n /* about css variables: the two-dash thing is a variable declared in the css file (by html5, not react)\r\n its used like this in the css >> font-size: var(--mwmMenuFontSize);\r\n Below you see how javascript can change the value of this variable dynamically \r\n because css variable is used, need to COMPUTE the value....getComputedStyle */\n // var fontSz = getComputedStyle(document.querySelector(':root')).getPropertyValue('--mwmMenuFontSize');\n var fontSz = getComputedStyle(document.body).getPropertyValue('--mwmMenuFontSize');\n fontSz = parseFloat(fontSz.slice(0, -2)); // remove 'vmin' 'vw' or 'px'\n var upDn = getComputedStyle(document.body).getPropertyValue('--mwmMenuScrnScaler');\n upDn /= 222;\n if (makeBigger) {\n fontSz = fontSz + upDn;\n } else {\n fontSz = fontSz - upDn;\n }\n /* change property of menu root div so it cascades down.. */\n document.body.style.setProperty('--mwmMenuFontSize', fontSz.toFixed(1) + 'px');\n /* now rescroll window so chosen dom node appears in visible portion */\n var chosenDomNode = document.querySelector('[mwmCurrent=\"mwmchosen\"]');\n if (document.querySelector('[latestClickedSubMenu=\"thatsMe\"]') !== null) {\n chosenDomNode = document.querySelector('[latestClickedSubMenu=\"thatsMe\"]');\n console.log('latestClickedSubMenu');\n }\n scrollVandHToShowChosenSubmenu(chosenDomNode, 0); // chosenDomNode.clientWidth)\n}\nfunction isDesktop(document) {\n var ret = getComputedStyle(document.body).getPropertyValue('--mwmVMINcutoff') < window.screen.width ? true : false;\n return ret;\n}\n\n/* \"Buoy88\" Use as a guide for choosing nextSibling, getParent etc in code...\r\n O==O==O==O==O below is copy/paste from browser inspect->edit html O==O==O==O==O\r\n O==O==O==O==O snapshot taken while the \"tools->power is open and tools->hand is closed\" O==O==O==O==O\r\n ........ as of 7-31-2023 .....\r\n<div mobiwekrole=\"BRANCH_SUBMENU\" class=\"dispBlockClass\">\r\n <div mobiwekrole=\"BRANCH\">\r\n <div mobiwekrole=\"BRANCH_BUTTON\" style=\"--mwmBtnAfterShape: var(--unicodeSolidRightTri);\">power</div>\r\n <div mobiwekrole=\"BRANCH_SUBMENU\" class=\"dispBlockClass\">\r\n <div mobiwekrole=\"LEAF\" mwmkey=\"workshopTools/power/drillPress\">drillPress</div>\r\n <div mobiwekrole=\"LEAF\" mwmkey=\"workshopTools/power/saw\">saw</div>\r\n </div>\r\n </div>\r\n <div m