class ClassListModule { static SearchQuery = ''; static ModeCookieName = 'doczilla-js-docs-class-list-mode'; static OpenedFoldersCookieName = 'doczilla-js-docs-class-list-opened-folders'; static Mode = { Structurized: 'structurized', Unstructurized: 'unstructurized' }; static _Mode = ClassListModule.Mode.Structurized; static setQuery(query, reload) { ClassListModule.SearchQuery = query.toLowerCase(); if(reload) ClassListModule.reload(); } static load() { ClassListModule.classListElement = ClassListModule.classListElement ? ClassListModule.classListElement : DOM.get('.class-list'); DOM.get('.class-list-mode-button.structurized').switchClass('selected', ClassListModule._Mode === ClassListModule.Mode.Structurized); DOM.get('.class-list-mode-button.unstructurized').switchClass('selected', ClassListModule._Mode === ClassListModule.Mode.Unstructurized); ClassListModule.loadClasses(ClassListModule._Mode); } static loadClasses(mode) { let classList = {}; if(mode === ClassListModule.Mode.Structurized) { for(const root of RepoNames) { classList[root] = { type: 'dir', contents: {} }; Object.keys(ClassList).filter((key) => { return ClassList[key].filePath.indexOf(root) === 0 && (ClassListModule.SearchQuery.length == 0 || key.toLowerCase().includes(ClassListModule.SearchQuery) || (ClassList[key].shortName || '').toLowerCase().includes(ClassListModule.SearchQuery)); }).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())).map((key) => { classList[root].contents[key] = { type: 'cls', class: ClassList[key] }; }); } classList = ClassListModule.transformStructure(classList); Object.keys(classList).forEach((key) => { if(Object.keys(classList[key].contents).length > 0) ClassListModule.renderDir(key, key, classList[key].contents, ClassListModule.classListElement); }); } else { Object.keys(ClassList).sort((a, b) => { return a.toLowerCase().localeCompare(b.toLowerCase()); }).filter((key) => { return ClassListModule.SearchQuery.length == 0 || key.toLowerCase().includes(ClassListModule.SearchQuery) || (ClassList[key].shortName || '').toLowerCase().includes(ClassListModule.SearchQuery); }).map((key) => { classList[key] = ClassList[key]; }); for(const className of Object.keys(classList)) { const icon = DOM.create({ tag: 'div', cls: 'class-icon' }); const name = DOM.create({ tag: 'div', cls: 'class-name', innerHTML: className }); DOM.create({ tag: 'div', cls: `class-item ${ Class ? (Class.name === className ? 'selected' : '') : '' }`, cn: [icon, name], attr: { 'data-class-name': className, 'data-class-shortname': classList[className].shortName, 'title': className } }, ClassListModule.classListElement).on('click', ClassListModule.onListItemClick); } } } static renderDir(dirName, dirPath, dirContents, parentContainer) { if(ClassListModule.SearchQuery.length > 0 && Object.keys(dirContents).length === 0) return; const dirCollapsedIconEl = DOM.create({ tag: 'div', cls: 'dir-collapsed-icon' }); const dirIconEl = DOM.create({ tag: 'div', cls: 'dir-icon' }); const dirNameEl = DOM.create({ tag: 'div', cls: 'dir-name', cn: [dirCollapsedIconEl, dirIconEl], innerHTML: dirName }).on('click', ClassListModule.onListItemClick); const dirContentEl = DOM.create({ tag: 'div', cls: 'dir-content' }); const dirItem = DOM.create({ tag: 'div', cls: 'dir-item', cn: [dirNameEl, dirContentEl], attr: { 'data-dir-path': dirPath } }, parentContainer); const opened = (DOM.getCookieProperty(App.CookieName, ClassListModule.OpenedFoldersCookieName) || []).indexOf(dirPath) > -1; if(CDUtils.isEmpty(ClassListModule.SearchQuery) && !opened) dirItem.addClass('collapsed'); Object.keys(dirContents).sort((a, b) => { return -dirContents[a].type.localeCompare(dirContents[b].type); // 'dir' > 'cls' }).forEach((key) => { const item = dirContents[key]; if(item.type === 'cls') { ClassListModule.renderClass(item.class, dirContentEl); } else { ClassListModule.renderDir(key, `${dirPath}/${key}`, item.contents, dirContentEl); } }); } static renderClass(cls, container) { const className = cls.name; const classShortName = cls.shortName; const icon = DOM.create({ tag: 'div', cls: 'class-icon' }); const name = DOM.create({ tag: 'div', cls: 'class-name', innerHTML: className }); DOM.create({ tag: 'div', cls: `class-item ${ Class ? (Class.name === className ? 'selected' : '') : '' }`, cn: [icon, name], attr: { 'data-class-name': className, 'data-class-shortname': classShortName, 'title': className } }, container).on('click', ClassListModule.onListItemClick); } static transformStructure(obj) { const newObj = {}; function recursiveTransform(parent, path, type, cls) { const [currentKey, ...rest] = path.split('.'); if (!currentKey) return; if (!parent[currentKey]) { parent[currentKey] = {}; parent[currentKey].type = rest.length === 0 ? type : 'dir'; parent[currentKey].contents = {}; } if (rest.length === 0) { parent[currentKey].type = type; parent[currentKey].class = cls; } else { recursiveTransform(parent[currentKey].contents, rest.join('.'), type, cls); } } function sortContents(contents) { const sortedKeys = Object.keys(contents).sort((a, b) => { const typeA = contents[a].type === 'dir' ? 0 : 1; const typeB = contents[b].type === 'dir' ? 0 : 1; if (typeA !== typeB) return typeA - typeB; return a.localeCompare(b); }); const sortedContents = {}; sortedKeys.forEach(key => { sortedContents[key] = contents[key]; }); return sortedContents; } for (const rootKey in obj) { if (obj.hasOwnProperty(rootKey)) { const { type, contents } = obj[rootKey]; newObj[rootKey] = { type: 'dir', contents: sortContents({}) }; for (const classKey in contents) { if (contents.hasOwnProperty(classKey)) { const { type, class: cls } = contents[classKey]; recursiveTransform(newObj[rootKey].contents, classKey, type, cls); } } } } return newObj; } static onListItemClick(e) { let target = CDElement.get(e.target); while(!target.hasClass('class-item') && !target.hasClass('dir-name')) target = target.getParent(); if(target.hasClass('class-item')) { Url.goTo(`/class/${target.getAttribute('data-class-name')}`); } else if(target.hasClass('dir-name')) { const parent = target.getParent(); const dataDirPath = parent.getAttribute('data-dir-path'); parent.switchClass('collapsed'); if(!CDUtils.isEmpty(ClassListModule.SearchQuery)) return; let openedFoldersCookieValue = DOM.getCookieProperty(App.CookieName, ClassListModule.OpenedFoldersCookieName) || []; if(parent.hasClass('collapsed')) { openedFoldersCookieValue.splice(openedFoldersCookieValue.indexOf(dataDirPath), 1); } else { openedFoldersCookieValue.push(dataDirPath); } DOM.setCookieProperty(App.CookieName, ClassListModule.OpenedFoldersCookieName, openedFoldersCookieValue, 24); } } static onModeButtonClick(e) { const target = CDElement.get(e.target); const mode = target.getAttribute('data-mode'); ClassListModule._Mode = mode; DOM.setCookieProperty(App.CookieName, ClassListModule.ModeCookieName, mode); ClassListModule.reload(); } static clear() { DOM.get('.class-list').getChildrenRecursive().forEach((item) => { if(item.hasClass('class-item') || item.hasClass('dir-name')) item.un('click', ClassListModule.onListItemClick); item.remove(); }); } static reload() { ClassListModule.clear(); ClassListModule.load(); } static updateSources() { fetch('/updateSources', { method: 'POST' }); } static init() { DOM.get('.class-list-mode-button.structurized').on(DOM.Events.Click, ClassListModule.onModeButtonClick); DOM.get('.class-list-mode-button.unstructurized').on(DOM.Events.Click, ClassListModule.onModeButtonClick); DOM.get('.faq-button').on(DOM.Events.Click, (e) => { Url.goTo('/faq'); }); const refreshButton = DOM.get('.refresh-button'); if(refreshButton) { refreshButton.on(DOM.Events.Click, (e) => { if(confirm('Are you sure you want to update sources? It will take approximately 3-5 minutes. The system will not be available until the process finished.')) { ClassListModule.updateSources(); Url.goTo('/'); } }); } const statisticsButton = DOM.get('.statistics-button'); if(statisticsButton) { statisticsButton.on(DOM.Events.Click, (e) => { Url.goTo('/statistics'); }); } const modeCookieValue = DOM.getCookieProperty(App.CookieName, ClassListModule.ModeCookieName); ClassListModule._Mode = modeCookieValue || ClassListModule.Mode.Structurized; if(!modeCookieValue) DOM.setCookieProperty(App.CookieName, ClassListModule.ModeCookieName, ClassListModule.Mode.Structurized); ClassListModule.load(); ClassListModule.classListElement.scrollTo('.class-item.selected'); } } window_.on('load', (e) => { ClassListModule.init(); });