\r\n );\r\n};\r\n\r\nconst pageListStyles = makeStyles((theme) => ({\r\n main: {\r\n flexGrow: 1\r\n },\r\n list: {\r\n \r\n },\r\n sort: { \r\n color: \"var(--darkBlue)\",\r\n textTransform: \"uppercase\",\r\n '& > .MuiInputBase-input': {\r\n fontWeight: 700,\r\n fontSize: \".9rem\",\r\n padding: '5px 24px 5px 5px'\r\n },\r\n textDecoration: \"none\",\r\n marginLeft: \"1em\", \r\n [theme.breakpoints.down('sm')]: {\r\n flex: '0 0 100%',\r\n marginLeft: 0,\r\n marginBottom: '10px'\r\n },\r\n\r\n fontFamily: \"var(--secondaryText)\",\r\n border: 'none',\r\n content: 'none',\r\n transition: 'none',\r\n transform: 'none',\r\n borderBottom: '2px solid var(--red)', \r\n //marginTop: 0,\r\n '&::before': {\r\n content: 'none',\r\n border: 'none',\r\n transition: 'none',\r\n transform: 'none'\r\n },\r\n '&::after': {\r\n content: 'none',\r\n border: 'none',\r\n transition: 'none',\r\n transform: 'none'\r\n },\r\n '&::hover': {\r\n content: 'none',\r\n border: 'none',\r\n transition: 'none',\r\n transform: 'none'\r\n },\r\n \r\n \r\n },\r\n sortItem: { \r\n fontFamily: \"var(--secondaryText)\",\r\n color: \"var(--darkBlue)\", \r\n textTransform: \"uppercase\",\r\n fontWeight: 700,\r\n fontSize: \".9rem\",\r\n },\r\n sectionDesktop: {\r\n display: 'none',\r\n [theme.breakpoints.up('md')]: {\r\n display: 'block',\r\n },\r\n },\r\n sectionMobile: {\r\n display: 'unset',\r\n [theme.breakpoints.up('md')]: {\r\n display: 'none',\r\n },\r\n '& > .MuiPaper-root': {\r\n padding: '1em',\r\n maxWidth: '75%',\r\n width: 'auto'\r\n }\r\n },\r\n filterWrapper: {\r\n flexBasis: '0%',\r\n flexShrink: '0',\r\n [theme.breakpoints.up('md')]: {\r\n flexBasis: (!!window.MSInputMethodContext && !!document.documentMode)?'auto':'25%',\r\n }\r\n }\r\n}));\r\nconst PageList = (props) => {\r\n let location = useLocation();\r\n let history = useHistory();\r\n let match = useRouteMatch();\r\n let settings = useSettings();\r\n const analytics = useAnalytics();\r\n\r\n var query = new URLSearchParams(location.search);\r\n const classes = pageListStyles();\r\n const auth = useAuth();\r\n const { area } = props;\r\n const [canContribute, setCanContribute] = useState(false);\r\n const [canApprove, setCanApprove] = useState(false);\r\n const [canContributeCollection, setCanContributeCollection] = useState(false);\r\n const [canApproveCollection, setCanApproveCollection] = useState(false);\r\n const [tags, setTags] = useState(TagService.cachedList[area.url]);\r\n const [pages, setPages] = useState([]);\r\n const [filter, setFilter] = useState(props?.filter ?? query.get('filter') ?? '');//can set initial search on URL args or props\r\n const [sort, setSort] = useState(props?.sort ?? query.get('sort') ?? 'popularity');//can set initial search on URL args or props\r\n const [canLoadMore, setCanLoadMore] = useState(false);//for infinite loading\r\n const [initialised, setInitialised] = useState(false);//make sure tags are loaded before initial pages load to prevent double load\r\n const [pageSize, setPageSize] = useState(parseInt(settings.get(\"Pages fetch size\")) || 10);\r\n const [mobileOpen, setMobileOpen] = React.useState(false);\r\n const [queryLoaded, setQueryLoaded] = useState(query.get(\"loaded\"));\r\n const [loading, setLoading] = useState(true);\r\n\r\n const [override, setOverride] = useState(null);\r\n\r\n useEffect(() => {\r\n if (area.url == \"article\" || area.url == \"showcase\" || area.url == \"page\" || area.url == \"unlisted\") {\r\n setCanContribute(auth.user.id && auth.user?.roles && auth.user.roles.indexOf(area.url + \".contributor\") !== -1);\r\n setCanApprove(auth.user.id && auth.user?.roles && auth.user.roles.indexOf(area.url + \".approver\") !== -1);\r\n if (area.url == \"article\") {\r\n setCanContributeCollection(auth.user.id && auth.user?.roles && auth.user.roles.indexOf(\"collection.contributor\") !== -1);\r\n setCanApproveCollection(auth.user.id && auth.user?.roles && auth.user.roles.indexOf(\"collection.approver\") !== -1);\r\n }\r\n } else if (area.url != \"search\" && auth.user.id && auth.user?.roles && auth.user.roles.indexOf(\"admin\") !== -1) {\r\n setCanContribute(true);\r\n setCanApprove(true);\r\n } else {\r\n setCanContribute(false);\r\n setCanApprove(false);\r\n setCanContributeCollection(false);\r\n setCanApproveCollection(false);\r\n }\r\n }, [area,auth]);\r\n\r\n useEffect(() => {\r\n query = new URLSearchParams(location.search);\r\n var f = query.get('filter') ?? filter ?? '';\r\n if(f != filter){}\r\n setFilter(f);\r\n var changedTags = applyEnabled(tags);\r\n if (changedTags) {\r\n findOverride(changedTags);\r\n setTags(changedTags);\r\n }\r\n },[location]);\r\n\r\n var applyEnabled = function (tgs) {\r\n var oldSelectedTags = [], response = [...tgs];\r\n\r\n var changed = false;\r\n var queryTags = query.getAll('options');\r\n if (queryTags.length > 0) {\r\n oldSelectedTags = queryTags.map((t) => parseInt(t));\r\n }\r\n for (var i = 0; i < response.length; i++) {\r\n for (var j = 0; j < response[i].options.length; j++) {\r\n var newE = (oldSelectedTags.indexOf(response[i].options[j].id) !== -1);\r\n if (newE != response[i].options[j].enabled) {\r\n changed = true;\r\n }\r\n response[i].options[j].enabled = newE;\r\n }\r\n }\r\n if (changed)\r\n return response;\r\n else\r\n return null;\r\n };\r\n const [lastTagFetch, setLastTagFetch] = useState(0);\r\n var fetchTags = function () {\r\n var time = settings.get(\"Tags last updated\");\r\n if (lastTagFetch !== time) {\r\n setLastTagFetch(time);\r\n setPageSize(parseInt(settings.get(\"Pages fetch size\")) || 10);\r\n TagService.getList({ area: area.url }, time)\r\n .then((response) => {\r\n var changed = applyEnabled(response);\r\n setTags(changed ? changed : response);\r\n setInitialised(true);\r\n setLoading(true);\r\n findOverride(changed ? changed : response);\r\n })\r\n .catch(function (e) {\r\n setTags([]);\r\n });\r\n }\r\n };\r\n useEffect(fetchTags, [settings]);\r\n\r\n const findOverride = (tgs) => {\r\n if (!tgs) tgs = tags;\r\n //determine override tag if enabled\r\n var cat = null, tgs = [...tgs];\r\n for (var i = 0; i < tgs.length; i++) {\r\n if (tgs[i].isCategory) {\r\n for (var j = 0; j < tgs[i].options.length; j++) {\r\n if (tgs[i].options[j].enabled) {\r\n cat = tgs[i].options[j];\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n setOverride(cat);\r\n };\r\n\r\n const fetchPages = (showMore = false) => {\r\n\r\n if (!initialised) return false;\r\n\r\n var tagRequest = [];\r\n for (var i = 0; i < tags.length; i++) {\r\n for (var j = 0; j < tags[i].options.length; j++) {\r\n if (tags[i].options[j].enabled) {\r\n tagRequest.push(tags[i].options[j].id);\r\n }\r\n }\r\n }\r\n\r\n if (pageSize) {\r\n var newPages = (showMore ? [...pages] : []);\r\n var req = { filter: filter, page: Math.floor(newPages.length / pageSize), pageSize: pageSize, options: tagRequest, area: area.url, sort: sort };\r\n console.log(req)\r\n //initial query load\r\n if (queryLoaded && queryLoaded > pageSize) {\r\n req.page = 0;\r\n req.pageSize = queryLoaded;\r\n setQueryLoaded(0);\r\n }\r\n\r\n setLoading(true);\r\n PageService.getList(req)\r\n .then((response) => {\r\n if ('data' in response && 'data' in response.data) {\r\n var l = newPages.length;\r\n for (var i = 0; i < response.data.data.length; i++) {\r\n var found = false;\r\n for (var j = 0; j < l; j++) {\r\n if (newPages[j].id == response.data.data[i].id) {\r\n found = true;\r\n break;\r\n }\r\n }\r\n if (!found) {\r\n newPages.push(response.data.data[i]);\r\n }\r\n }\r\n\r\n setPages(newPages);\r\n console.log(\"fetched\", newPages.length, \"of\", response.data.total, \"pages\");\r\n setCanLoadMore(response.data.total != newPages.length);\r\n analytics.tag('event', 'view_search_results', {\r\n search_term: filter,\r\n items: newPages.map((p) => { return { item_id: p.id, item_name: p.title }; })\r\n });\r\n\r\n const params = new URLSearchParams();\r\n if (filter) params.append('filter', filter); else params.delete('filter');\r\n if (sort) params.append('sort', sort); else params.delete('sort');\r\n params.delete('options');\r\n if (tagRequest.length > 0) {\r\n for (var i = 0; i < tagRequest.length; i++)\r\n params.append('options', tagRequest[i]);\r\n }\r\n params.append('loaded', newPages.length);\r\n history.replace(match.path + \"?\" + params.toString());\r\n\r\n setLoading(false);\r\n }\r\n })\r\n .catch(function (e) {\r\n\r\n });\r\n }\r\n };\r\n useEffect(fetchPages, [filter, sort, tags, initialised]);\r\n\r\n const UpdateTags = () => {\r\n return function (tagId, optionId) {\r\n var oldTags = [...tags];\r\n var needUpdate = false;\r\n //for each in the tag db\r\n for (var t = 0; t < oldTags.length; t++) {\r\n if (oldTags[t].id == tagId) {\r\n var enabled = false;\r\n for (var o = 0; o < oldTags[t].options.length; o++) {\r\n if (oldTags[t].options[o].id == optionId) {\r\n oldTags[t].options[o].enabled = !oldTags[t].options[o].enabled;\r\n enabled = oldTags[t].options[o].enabled;\r\n needUpdate = true;\r\n break;\r\n }\r\n }\r\n\r\n //turn off other group members if needed\r\n if (oldTags[t].type == \"single\" && enabled) {\r\n for (var o = 0; o < oldTags[t].options.length; o++) {\r\n if (oldTags[t].options[o].id != optionId) {\r\n oldTags[t].options[o].enabled = false;\r\n }\r\n }\r\n }\r\n break;\r\n }\r\n }\r\n\r\n\r\n if (needUpdate) {\r\n setTags(oldTags);\r\n findOverride(oldTags);\r\n var selectedOptions = [];\r\n for (var t = 0; t < oldTags.length; t++) {\r\n for (var o = 0; o < oldTags[t].options.length; o++) {\r\n if (oldTags[t].options[o].enabled) {\r\n selectedOptions.push(oldTags[t].options[o].id);\r\n }\r\n }\r\n }\r\n //localStorage.setItem(\"lthub_selected_tags\", JSON.stringify(selectedOptions));\r\n }\r\n }\r\n };\r\n\r\n const applyFilter = (v) => {\r\n if ((sort != \"\" && v == \"\") || v != \"\") {\r\n setSort(\"score\");\r\n analytics.tag('event', 'search', { search_term: v });\r\n }\r\n setFilter(v);\r\n };\r\n const applySort = (e) => {\r\n setSort(e.target.value);\r\n };\r\n const handleShowMore = () => {\r\n setCanLoadMore(false);\r\n fetchPages(true);\r\n };\r\n\r\n const generateTitle = () => {\r\n if (override == null) {\r\n return area.plural;\r\n } else {\r\n return override.name;\r\n }\r\n };\r\n const generateIntro = () => {\r\n if (override == null) {\r\n switch (area.url) {\r\n case \"showcase\":\r\n case \"article\":\r\n case \"search\":\r\n return ();\r\n case \"template\":\r\n return (
Templates are a special page type which does not show up in search results,\r\n they are intended to be used as a starting point for other page types.\r\n For example, if you make a template page setting out the basic headings and structure\r\n for an Article and then assign it as the article template in the Site Settings area,\r\n any new Articles created will start with the content of the template.
);\r\n break;\r\n case \"page\":\r\n return (
Loose pages are normal pages in the system but are not articles or showcase pages. Unlike Unlisted pages, they can be found using the sitewide search.
);\r\n break;\r\n case \"unlisted\":\r\n return (
Unlisted pages are normal pages in the system but are not articles or showcase pages. Unlike Loose pages, they cannot be found using the sitewide search.
);\r\n break;\r\n case \"collection\":\r\n return (
Collections are a curated, commentated list of other articles and resources in the hub.
);\r\n break;\r\n\r\n }\r\n } else {\r\n return (
{override.description}
);\r\n }\r\n };\r\n\r\n const [pickedTags, setPickedTags] = React.useState(0);\r\n const calcPickedTags = () => {\r\n var count = 0;\r\n for (var i = 0; i < tags.length; i++) {\r\n if (tags[i].hidden == false) {\r\n for (var j = 0; j < tags[i].options.length; j++) {\r\n if (tags[i].options[j].enabled)\r\n count++;\r\n }\r\n }\r\n }\r\n setPickedTags(count);\r\n };\r\n useEffect(calcPickedTags, [tags]);\r\n\r\n const toggleMobile = (o) => {\r\n setMobileOpen(o);\r\n }\r\n\r\n return (\r\n
\r\n ))\r\n }\r\n \r\n \r\n );\r\n}\r\n\r\nexport default Glossary;","import { red } from '@material-ui/core/colors';\r\nimport { createMuiTheme } from '@material-ui/core/styles';\r\n\r\nconst darkBlue = getComputedStyle(document.documentElement).getPropertyValue('--darkBlue');\r\n// A custom theme for this app\r\nconst theme = createMuiTheme({\r\n breakpoints: {\r\n values: {\r\n xs: 0,\r\n sm: 600,\r\n md: 960,\r\n lg: 1180,\r\n xl: 1920,\r\n },\r\n },\r\n palette: {\r\n primary: {\r\n main: '#001641',\r\n },\r\n secondary: {\r\n main: '#001641',\r\n },\r\n danger: {\r\n main: \"#ED0A00\",\r\n },\r\n error: {\r\n main: \"#ED0A00\",\r\n },\r\n background: {\r\n default: 'var(--white)',\r\n }, \r\n },\r\n});\r\n\r\n\r\nexport default theme;","import Home from './components/Home.js';\r\nimport NavMenu from './components/NavMenu.js';\r\nimport Footer from './components/Footer.js';\r\nimport Consent from './components/support/Consent.js';\r\nimport NotFound from './components/support/NotFound.js';\r\n\r\nimport Areas from './components/support/Areas.js';\r\nimport ScrollToTop from './components/support/ScrollToTop.js';\r\nimport useAuth from './components/auth/useAuth.js';\r\nimport { ProvideAuth } from './components/auth/useAuth.js';\r\nimport PrivateRoute from './components/auth/PrivateRoute.js';\r\nimport { ProvideSettings } from './components/settings/useSettings.js';\r\nimport { ProvideAnalytics } from './components/support/Analytics.js';\r\n\r\nimport Pages from './components/pages/Pages.js';\r\nimport Glossary from './components/glossary/Glossary.js';\r\n\r\nimport theme from './components/theme';\r\nimport jss from './components/jss';\r\nimport { getClassGen } from './components/jss';\r\n\r\nimport React, { useState, useRef, lazy, Suspense, useEffect } from 'react';\r\nimport axios from 'axios';\r\nimport { Route, Switch, useLocation, Redirect } from 'react-router';\r\nimport { Link } from 'react-router-dom';\r\nimport { ThemeProvider } from '@material-ui/core/styles';\r\nimport CssBaseline from '@material-ui/core/CssBaseline';\r\nimport Container from '@material-ui/core/Container';\r\nimport { StylesProvider } from '@material-ui/core/styles';\r\nimport CircularProgress from '@material-ui/core/CircularProgress';\r\nimport { DarkModeProvider } from './components/support/DarkModeContext';\r\n\r\n import './custom.css';\r\n\r\nconst Login = lazy(() => import('./components/auth/Login.js'));\r\nconst Users = lazy(() => import('./components/users/Users.js'));\r\nconst Tags = lazy(() => import('./components/tags/Tags.js'));\r\nconst Settings = lazy(() => import('./components/settings/Settings.js'));\r\nconst FileManager = lazy(() => import('./components/files/FileManager.js'));\r\nconst Logs = lazy(() => import('./components/logs/Logs.js'));\r\nconst NavItems = lazy(() => import('./components/navitems/NavItems.js'));\r\nconst Trash = lazy(() => import('./components/pages/Trash.js'));\r\n\r\nconst App = (props) => {\r\n let auth = useAuth();\r\n const mainRef = useRef();\r\n\r\n const [login, setLogin] = useState(false);\r\n\r\n const [ax, setAx] = React.useState(false);\r\n if (!ax) {\r\n axios.interceptors.response.use(function (response) {\r\n return response;\r\n }, function (error) {\r\n var err = error;\r\n if ('response' in err) {\r\n err = error.response;\r\n }\r\n if (err) {\r\n if (err.status === 401) {\r\n setLogin(true);\r\n auth.signout(true);\r\n } else if (err.status === 403) {\r\n console.log(\"invalid permissions\", err.message);\r\n }\r\n } else if (error.request) {\r\n console.log(error.request);\r\n } else {\r\n console.log('Error', error.message);\r\n }\r\n return Promise.reject(error);\r\n });\r\n setAx(true);\r\n }\r\n\r\n const onLogin = (success) => {\r\n if (success) {\r\n\r\n } else {\r\n\r\n }\r\n setLogin(false);\r\n };\r\n\r\n const unauthDev = () => {\r\n if (process.env.REACT_APP_ENV !== \"Development\")\r\n return false;\r\n if (auth?.user?.id)\r\n return false;\r\n if (window.localStorage.getItem(\"lthub_has_loggedin\") === \"1\")\r\n return false;\r\n return true;\r\n };\r\n return (\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n mainRef.current.scrollIntoView({ behavior: 'smooth' })}>Skip to Content\r\n \r\n \r\n \r\n {typeof window != \"undefined\" ? : null}\r\n {!unauthDev() ? \r\n \r\n\r\n {Areas.map((value, index) => {\r\n return ();\r\n })}\r\n \r\n\r\n }>\r\n }>\r\n }>\r\n }>\r\n }>\r\n }>\r\n }>\r\n }>\r\n \r\n : null}\r\n \r\n \r\n \r\n \r\n }>\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n );\r\n};\r\n\r\nfunction NoMatch() {\r\n let location = useLocation();\r\n console.log(window.location.pathname);\r\n if (window.location.pathname.indexOf('.css') >= 0) {\r\n return ; // must return at least an empty div\r\n } else {\r\n return (\r\n \r\n //
\r\n //
\r\n // No match for {location.pathname}\r\n //
\r\n //
\r\n );\r\n }\r\n}\r\n\r\nexport default App;\r\n","// In production, we register a service worker to serve assets from local cache.\r\n\r\n// This lets the app load faster on subsequent visits in production, and gives\r\n// it offline capabilities. However, it also means that developers (and users)\r\n// will only see deployed updates on the \"N+1\" visit to a page, since previously\r\n// cached resources are updated in the background.\r\n\r\n// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.\r\n// This link also includes instructions on opting out of this behavior.\r\n\r\nconst isLocalhost = Boolean(\r\n window.location.hostname === 'localhost' ||\r\n // [::1] is the IPv6 localhost address.\r\n window.location.hostname === '[::1]' ||\r\n // 127.0.0.1/8 is considered localhost for IPv4.\r\n window.location.hostname.match(\r\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\r\n )\r\n);\r\n\r\nexport default function register (onUpdate) {\r\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\r\n // The URL constructor is available in all browsers that support SW.\r\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location);\r\n if (publicUrl.origin !== window.location.origin) {\r\n // Our service worker won't work if PUBLIC_URL is on a different origin\r\n // from what our page is served on. This might happen if a CDN is used to\r\n // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374\r\n return;\r\n }\r\n\r\n window.addEventListener('load', () => {\r\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\r\n\r\n if (isLocalhost) {\r\n // This is running on localhost. Lets check if a service worker still exists or not.\r\n checkValidServiceWorker(swUrl, onUpdate);\r\n } else {\r\n // Is not local host. Just register service worker\r\n registerValidSW(swUrl, onUpdate);\r\n }\r\n });\r\n }\r\n}\r\n\r\nfunction registerValidSW (swUrl, onUpdate) {\r\n navigator.serviceWorker\r\n .register(swUrl)\r\n .then(registration => {\r\n registration.onupdatefound = () => {\r\n const installingWorker = registration.installing;\r\n installingWorker.onstatechange = () => {\r\n if (installingWorker.state === 'installed') {\r\n if (navigator.serviceWorker.controller) {\r\n // At this point, the old content will have been purged and\r\n // the fresh content will have been added to the cache.\r\n // It's the perfect time to display a \"New content is\r\n // available; please refresh.\" message in your web app.\r\n console.log('New content is available; please refresh.');\r\n registration.waiting.postMessage({ type: 'SKIP_WAITING' });\r\n if (onUpdate) onUpdate();\r\n } else {\r\n // At this point, everything has been precached.\r\n // It's the perfect time to display a\r\n // \"Content is cached for offline use.\" message.\r\n console.log('Content is cached for offline use.');\r\n }\r\n }\r\n };\r\n };\r\n })\r\n .catch(error => {\r\n console.error('Error during service worker registration:', error);\r\n });\r\n}\r\n\r\nfunction checkValidServiceWorker (swUrl, onUpdate) {\r\n // Check if the service worker can be found. If it can't reload the page.\r\n fetch(swUrl)\r\n .then(response => {\r\n // Ensure service worker exists, and that we really are getting a JS file.\r\n if (\r\n response.status === 404 ||\r\n response.headers.get('content-type').indexOf('javascript') === -1\r\n ) {\r\n // No service worker found. Probably a different app. Reload the page.\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister().then(() => {\r\n window.location.reload();\r\n });\r\n });\r\n } else {\r\n // Service worker found. Proceed as normal.\r\n registerValidSW(swUrl, onUpdate);\r\n }\r\n })\r\n .catch(() => {\r\n console.log(\r\n 'No internet connection found. App is running in offline mode.'\r\n );\r\n });\r\n}\r\n\r\nexport function unregister () {\r\n if ('serviceWorker' in navigator) {\r\n navigator.serviceWorker.ready.then(registration => {\r\n registration.unregister();\r\n });\r\n }\r\n}\r\n","import 'react-app-polyfill/ie11';\r\nimport 'react-app-polyfill/stable';\r\nimport React, { Component, hydrate } from 'react';\r\nimport ReactDOM from 'react-dom';\r\nimport { BrowserRouter } from 'react-router-dom';\r\nimport App from './App';\r\nimport registerServiceWorker from './registerServiceWorker';\r\nimport Snackbar from '@material-ui/core/Snackbar';\r\nimport IconButton from '@material-ui/core/IconButton';\r\nimport CloseIcon from '@material-ui/icons/Close';\r\n\r\nif (!('remove' in Element.prototype)) {\r\n Element.prototype.remove = function () {\r\n if (this.parentNode) {\r\n this.parentNode.removeChild(this);\r\n }\r\n };\r\n}\r\nif (!String.prototype.replaceAll) {\r\n String.prototype.replaceAll = function (str, newStr) {\r\n\r\n // If a regex pattern\r\n if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {\r\n return this.replace(str, newStr);\r\n }\r\n\r\n // If a string\r\n return this.replace(new RegExp(str, 'g'), newStr);\r\n\r\n };\r\n}\r\n\r\nconst baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');\r\n\r\n//on Page type pages, the root element is predefined, delete it as we are populating with JS\r\nvar rootElement = document.getElementById('root');\r\nvar prerendered = document.getElementById('prerendered');\r\nif (prerendered) {\r\n prerendered.parentNode.removeChild(prerendered);\r\n}\r\nclass NewVersionAlert extends Component {\r\n static displayName = App.name;\r\n constructor(props) {\r\n super(props);\r\n this.state = {\r\n open: true\r\n };\r\n }\r\n render() {\r\n return (\r\n this.setState({ open: false })}\r\n message=\"A new version of the app is available, please refresh your browser.\"\r\n action={\r\n \r\n this.setState({ open: false })}>\r\n \r\n \r\n \r\n }\r\n />\r\n );\r\n }\r\n}\r\nconst onUpdate = () => {\r\n // show alert\r\n const d = document.createElement(\"div\")\r\n d.id = \"newversion-alert\";\r\n rootElement.appendChild(d);\r\n ReactDOM.render(, document.getElementById(\"newversion-alert\"));\r\n}\r\n\r\nvar jsss = document.querySelectorAll(\"style[data-jss]:not([data-meta='makeStyles'])\");\r\nfor (var i = 0; i < jsss.length; i++)\r\n jsss[i].parentNode.removeChild(jsss[i]);\r\n\r\nif (rootElement.hasChildNodes()) {\r\n console.log(\"hydrating...\");\r\n ReactDOM.hydrate(, rootElement);\r\n registerServiceWorker(onUpdate);\r\n} else {\r\n console.log(\"rendering...\");\r\n ReactDOM.render(, rootElement);\r\n}\r\n","const AppTitle = function (text) {\r\n return text + (text ? \" - \" : \"\") + \"L&T Hub\";\r\n};\r\n\r\nexport default AppTitle;","import React, { useState } from 'react';\r\nimport Tooltip from '@material-ui/core/Tooltip';\r\nimport { StylesProvider } from '@material-ui/core/styles';\r\n\r\nconst GlossaryLink = (props) => {\r\n const { entry, innerText } = props;\r\n const [tip, setTip] = useState(false);\r\n\r\n\r\n\r\n const clickHandler = () => {\r\n setTip(false);\r\n };\r\n return (\r\n \r\n setTip(true)} onClose={() => setTip(false)}>\r\n {innerText}\r\n \r\n \r\n );\r\n};\r\n\r\nexport default GlossaryLink;\r\n","import { NoRouterHijack } from \"../support/Hijack.js\";\r\nimport jss from '../jss';\r\nimport { getClassGen } from '../jss';\r\n\r\nimport React, { useState, useEffect, useRef } from 'react';\r\nimport Dialog from '@material-ui/core/Dialog';\r\nimport DialogTitle from '@material-ui/core/DialogTitle';\r\nimport DialogContent from '@material-ui/core/DialogContent';\r\nimport DialogActions from '@material-ui/core/DialogActions';\r\nimport Button from '@material-ui/core/Button';\r\nimport Box from '@material-ui/core/Box';\r\nimport { StylesProvider } from '@material-ui/core/styles';\r\nimport { makeStyles } from '@material-ui/core/styles';\r\nimport LaunchIcon from '@material-ui/icons/Launch';\r\nimport PlayCircleOutlineIcon from '@material-ui/icons/PlayCircleOutline';\r\nimport Tooltip from '@material-ui/core/Tooltip';\r\n\r\nconst popupStyles = makeStyles((theme) => ({\r\n \r\n popupLink: {\r\n color: 'var(--red)',\r\n cursor: 'pointer',\r\n display: \"flex\",\r\n alignItems: \"flex-end\",\r\n \"&:hover\": {\r\n color: \"var(--black)\"\r\n },\r\n paddingBottom: \"5px\"\r\n },\r\n popupButton: { \r\n color: \"var(--darkBlue)\"\r\n\r\n },\r\n icon: {\r\n marginLeft: \"8px\",\r\n marginRight: \"4px\"\r\n },\r\n contentContainer: { \r\n \"& img\": {\r\n width: '100%',\r\n height: 'auto'\r\n },\r\n },\r\n image: {\r\n maxWidth: '100%'\r\n },\r\n imageBox: {\r\n cursor: 'zoom-in'\r\n }\r\n\r\n\r\n}));\r\nconst Popup = (props) => {\r\n const [open, setOpen] = useState(false)\r\n const classes = popupStyles();\r\n const htmlRef = useRef(null);\r\n return (\r\n \r\n
\r\n \r\n \r\n\r\n );\r\n};\r\nconst EnlargeImage = (props) => {\r\n const [open, setOpen] = useState(false)\r\n const classes = popupStyles();\r\n const [tip, setTip] = useState(false);\r\n return (\r\n \r\n setTip(true)} onClose={() => setTip(false)}>\r\n setOpen(true)} color=\"primary\">\r\n \r\n\r\n \r\n \r\n\r\n );\r\n};\r\n\r\nexport default Popup;\r\nexport { EnlargeImage };","import GlossaryLink from '../glossary/GlossaryLink.js';\r\nimport GlossaryService from '../glossary/GlossaryService.js';\r\nimport React, { useEffect, Component } from 'react';\r\nimport { withRouter } from 'react-router-dom';\r\nimport PropTypes from 'prop-types';\r\nimport ReactDOM from 'react-dom';\r\nimport TranscriptButton from './TranscriptButton.js';\r\nimport Popup, { EnlargeImage } from './Popup.js';\r\n\r\nfunction ApplyInjections(target) {\r\n //console.log(\"apply injections\");\r\n var base = document.getElementsByTagName('base')[0].getAttribute('href');\r\n //activateAbsoluteURLs\r\n var as = target.getElementsByTagName(\"a\");\r\n for (var i = 0; i < as.length; i++) {\r\n var href = as[i].getAttribute(\"href\");\r\n if (href) {\r\n if (base != \"/\")\r\n href = href.replaceAll(base, \"\");\r\n if (href[0] == \"/\") {\r\n as[i].setAttribute(\"href\", base + href.substr(1, href.length))\r\n }\r\n }\r\n }\r\n\r\n //activateGlossary\r\n if (GlossaryService.cachedList) {\r\n const glossary = GlossaryService.cachedList;\r\n var glossaryLinks = target.getElementsByClassName(\"glossary-link\");\r\n for (var i = 0; i < glossaryLinks.length; i++) {\r\n var id = glossaryLinks[i].getAttribute(\"data-entry\");\r\n if (id) {\r\n for (var j = 0; j < glossary.length; j++) {\r\n if (id.toLowerCase() == glossary[j].name.toLowerCase()) {\r\n ReactDOM.render(, glossaryLinks[i]);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n //activateTranscript\r\n var buttons = target.getElementsByClassName(\"transcript-button\");\r\n var contents = target.getElementsByClassName(\"transcript-content\");\r\n for (var i = 0; i < buttons.length; i++) {\r\n var label = buttons[i].getAttribute(\"data-label\") || \"transcript\";\r\n var big = buttons[i].hasAttribute(\"data-big\");\r\n var paste = buttons[i].hasAttribute(\"data-paste\");\r\n var hashName = buttons[i].parentNode.getAttribute(\"id\") || \"\";\r\n var hidden = !buttons[i].hasAttribute(\"data-open\");\r\n ReactDOM.render(, buttons[i]);\r\n }\r\n\r\n //activatePopup\r\n var buttons = target.getElementsByClassName(\"popup-button\");\r\n var titles = target.getElementsByClassName(\"popup-title\");\r\n var contents = target.getElementsByClassName(\"popup-content\");\r\n for (var i = 0; i < buttons.length; i++) {\r\n let isVideo = titles[i].classList.contains(\"popup-video\");\r\n if(i < titles.length && i < contents.length)\r\n ReactDOM.render(, buttons[i]);\r\n }\r\n //activateEnlargeImage\r\n var gridItems = target.getElementsByClassName(\"grid-item-image\"); \r\n for (var i = 0; i < gridItems.length; i++) { \r\n ReactDOM.render(, gridItems[i].parentNode);\r\n }\r\n\r\n //automatically wrap iframes in responsive div if needed\r\n //activateIFrames\r\n var iframes = target.getElementsByTagName(\"iframe\");\r\n for (var i = 0; i < iframes.length; i++) {\r\n if (!iframes[i].parentNode.classList.contains(\"embed-container\")) {\r\n var par = document.createElement(\"div\");\r\n par.classList.add(\"embed-container\");\r\n var h = iframes[i].getAttribute(\"height\"), w = iframes[i].getAttribute(\"width\");\r\n if (h && w)\r\n par.style.paddingBottom = (100 * (parseFloat(\"\" + h) / parseFloat(\"\" + w))) + \"%\";\r\n iframes[i].parentNode.insertBefore(par, iframes[i]);\r\n par.appendChild(iframes[i]);\r\n }\r\n }\r\n}\r\n\r\nconst NoRouterHijack = (props) => {\r\n useEffect(() => {\r\n ApplyInjections(props.children.ref.current);\r\n });\r\n\r\n return (\r\n
{props.children}
\r\n );\r\n};\r\n\r\nconst getRoute = function(url) {\r\n var getLocation = function (href) {\r\n // eslint-disable-next-line no-useless-escape\r\n const re = /^(https?\\:)?\\/\\/(([^:\\/?#]*)(?:\\:([0-9]+))?)([\\/]{0,1}[^?#]*)(\\?[^#]*|)(#.*|)$/\r\n const match = href.match(re)\r\n const location = match && {\r\n href: href,\r\n protocol: match[1],\r\n host: match[2],\r\n hostname: match[3],\r\n port: match[4],\r\n pathname: match[5],\r\n search: match[6],\r\n hash: match[7]\r\n }\r\n return match && location\r\n };\r\n\r\n // if it is an explicit non-http protocol, we want the browser to handle it natively\r\n // using history.push will do bad things\r\n const protocols = Hijack.defaultProps.protocols;\r\n const hostnames = Hijack.defaultProps.hostnames;\r\n const nonHttpProtocol = protocols.some(protocol => url.startsWith(`${protocol}:`))\r\n if (nonHttpProtocol) { return false; }\r\n\r\n let destination = url;\r\n\r\n var base = document.getElementsByTagName('base')[0].getAttribute('href');\r\n const isApi = destination.indexOf(\"/api/\") !== -1;\r\n if (isApi) return false;\r\n\r\n // if it's http or protocol-relative, we need to check further\r\n // we want to use react router if it's sending us to the same domain\r\n const re = new RegExp('^(https?:)?//')\r\n const isHTTP = re.test(url)\r\n if (isHTTP) {\r\n const { hostname, pathname, search, hash } = getLocation(url)\r\n const sameSite = (hostname === window.location.hostname && pathname.indexOf(base) === 0) || hostnames.indexOf(hostname) !== -1\r\n if (sameSite) {\r\n destination = pathname\r\n if (search) { destination += search }\r\n if (hash) { destination += hash }\r\n } else {\r\n // if it's an external http url, we let the browser handle it natively\r\n return false;\r\n }\r\n }\r\n\r\n if (base != \"/\" && destination.indexOf(base) === 0) {\r\n destination = destination.replace(base, \"/\");\r\n }\r\n\r\n return destination;\r\n}\r\n\r\nexport class Hijack extends Component {\r\n \r\n shouldRouterHandle(url, event) {\r\n var destination = getRoute(url);\r\n if (destination !== false) {\r\n // in all other cases (query string, hash fragment, relative URL)\r\n // we directly push the url and React Router will handle it correctly\r\n //console.log(\"using hijack to go to \" + destination + \" From \" + window.location.pathname.substr(1));\r\n if (destination[0] === \"#\") {\r\n window.location.hash = destination;\r\n var el = document.getElementById(destination.substring(1));\r\n if(el)\r\n el.scrollIntoView({ behavior: 'smooth' });\r\n } else {\r\n if (destination.startsWith(window.location.pathname.substr(0)) == true || destination.startsWith(window.location.pathname.substr(1)) == true) {\r\n //console.log('same page' + destination.startsWith(window.location.pathname.substr(0)));\r\n this.props.history.push(destination);\r\n window.location.reload();\r\n } else {\r\n this.props.history.push(destination);\r\n }\r\n }\r\n event.preventDefault();\r\n }\r\n }\r\n\r\n onClick = event => {\r\n // if the user is trying to right click or open the link in a new tab or window\r\n // we do not want to interfere\r\n const { ctrlKey, shiftKey, metaKey } = event\r\n if (ctrlKey || shiftKey || metaKey) {\r\n return\r\n }\r\n\r\n // when Hijack is clicked, we look at the target and each of the target's parents\r\n // if an tag was clicked, we process it further\r\n const self = event.currentTarget\r\n for (let el = event.target; el !== self; el = el.parentElement) {\r\n if (el.nodeName === 'A') {\r\n const target = el.getAttribute('target')\r\n if (target && target !== '_self' && target !== window.name) { return }\r\n const href = el.getAttribute('href')\r\n href && this.shouldRouterHandle(href, event)\r\n break\r\n }\r\n }\r\n }\r\n componentDidMount() { ApplyInjections(this.props.children.ref.current); }\r\n componentDidUpdate() { ApplyInjections(this.props.children.ref.current); }\r\n\r\n \r\n render() {\r\n return