| /******************************************************************************* |
| * Copyright (c) 2020 Holger Voormann and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| ******************************************************************************/ |
| (function(window, document) { |
| |
| var SMALL_SCREEN_WIDTH = 768; |
| var LOGO_ICON_WIDTH = 36; |
| var LOGO_FULL_WIDTH = 146; |
| var MENU_FONT_SIZING = 0; |
| var MENU_HELP = 0 // 0 or e.g. 'topic/org.eclipse.help.base/doc/help_home.html' |
| var MENU_HELP_LABEL = 'Help'; |
| var MENU_HELP_DESCRIPTION = 'Using the help system' |
| var MENU_ABOUT = 0; |
| var TOC_SIDEBAR_DEFAULT_WIDTH = 380; |
| var TOC_SIDEBAR_MINIMUM_WIDTH = 76; |
| var TOC_SIDEBAR_WIDTH_COOKIE_NAME = 'toc_width'; |
| var TOC_ICON_DESCRIPTION = 'Toggle table of content'; |
| var TOC_ICON = '<svg width="20" height="20" viewBox="0 0 20 20"><path fill="currentColor" d="M19 5H1V3h18v2zm0 10H1v2h18v-2zm-4-6H1v2h14V9z"/></svg>'; |
| var HISTORY_BACK_DESCRIPTION = 'Go back one page'; |
| var HISTORY_BACK_ICON = '<svg width="20" height="20" viewBox="0 0 20 20"><path fill="currentColor" d="m 8.27224,17.95644 c 0.39048,0.390343 1.023592,0.390211 1.413938,0 0.390613,-0.390612 0.390613,-1.023597 -1.33e-4,-1.41421 L 4.144057,11.000499 18.27041,10.999748 c 0.55219,-1.31e-4 0.999731,-0.447671 0.999731,-1.0001299 -1.34e-4,-0.552189 -0.447674,-0.999595 -0.999864,-0.999595 l -14.126755,9.99e-4 5.542723,-5.543204 c 0.390479,-0.390479 0.390479,-1.023727 0,-1.414074 -0.195307,-0.195173 -0.451138,-0.292892 -0.707102,-0.292892 -0.255832,0 -0.511664,0.09772 -0.70697,0.292759 l -7.249421,7.250043 c -0.187575,0.18744 -0.292893,0.441666 -0.292893,0.7069649 1.33e-4,0.2653 0.105451,0.519396 0.293025,0.707237 z"/></svg>'; |
| var HISTORY_FORWARD_DESCRIPTION = 'Go back one page'; |
| var HISTORY_FORWARD_ICON = '<svg width="20" height="20" viewBox="0 0 20 20"><path fill="currentColor" d="m 11.72776,17.95644 c -0.39048,0.390343 -1.023592,0.390211 -1.413938,0 -0.390613,-0.390612 -0.390613,-1.023597 1.33e-4,-1.41421 L 15.855943,11.000499 1.72959,10.999748 C 1.1774,10.999617 0.729859,10.552077 0.729859,9.9996181 0.729993,9.4474291 1.177533,9.0000231 1.729723,9.0000231 l 14.126755,9.99e-4 -5.542723,-5.543204 c -0.390479,-0.390479 -0.390479,-1.023727 0,-1.414074 0.195307,-0.195173 0.451138,-0.292892 0.707102,-0.292892 0.255832,0 0.511664,0.09772 0.70697,0.292759 l 7.249421,7.250043 c 0.187575,0.18744 0.292893,0.441666 0.292893,0.7069649 -1.33e-4,0.2653 -0.105451,0.519396 -0.293025,0.707237 z"/></svg>'; |
| var BOOKMARKS_ICON = '<svg width="20" height="20" viewBox="0 0 20 20"><path fill="currentColor" d="M 10.019531 0.5 A 1.000065 1.000065 0 0 0 9.1035156 1.0566406 L 6.5742188 6.1816406 L 0.91796875 7.0039062 A 1.000065 1.000065 0 0 0 0.36523438 8.7089844 L 4.4570312 12.699219 L 3.4902344 18.332031 A 1.000065 1.000065 0 0 0 4.9414062 19.384766 L 10 16.726562 L 15.058594 19.384766 A 1.000065 1.000065 0 0 0 16.509766 18.332031 L 15.542969 12.699219 L 19.634766 8.7089844 A 1.000065 1.000065 0 0 0 19.082031 7.0039062 L 13.425781 6.1816406 L 10.896484 1.0566406 A 1.000065 1.000065 0 0 0 10.019531 0.5 z M 10 3.7597656 L 11.865234 7.5390625 A 1.000065 1.000065 0 0 0 12.617188 8.0859375 L 16.789062 8.6914062 L 13.771484 11.632812 A 1.000065 1.000065 0 0 0 13.482422 12.517578 L 14.195312 16.673828 L 10.464844 14.710938 A 1.000065 1.000065 0 0 0 9.5351562 14.710938 L 5.8046875 16.673828 L 6.5175781 12.517578 A 1.000065 1.000065 0 0 0 6.2285156 11.632812 L 3.2109375 8.6914062 L 7.3828125 8.0859375 A 1.000065 1.000065 0 0 0 8.1347656 7.5390625 L 10 3.7597656 z"/></svg>'; |
| var BOOKMARKS_DESCRIPTION = 'Bookmarks'; |
| var BOOKMARKS_CLOSE_DESCRIPTION = 'Close bookmarks'; |
| var BOOKMARKS_ADD_PAGE_DESCRIPTION = 'Bookmark current page'; |
| var BOOKMARKS_ADD_SEARCH_DESCRIPTION = 'Bookmark current search'; |
| var BOOKMARKS_DELETE = 'Delete'; |
| var BOOKMARKS_DELETE_DESCRIPTION = 'Delete this bookmarks (cannot be undone)'; |
| var BOOKMARKS_DELETE_ALL = 'Delete all bookmarks'; |
| var BOOKMARKS_DELETE_ALL_DESCRIPTION = 'Delete all bookmarks (cannot be undone)'; |
| var BOOKMARKS_PATTERN = new RegExp('<tr[^<]*<td[^<]*<a\\s+(?:(?!href)[\\w\\-]+\\s*=\\s*(?:(?:\'[^\']*\')|(?:"[^"]*"))\\s+)*href\\s*=\\s*\'([^\']*)\'[^<]*<img[^>]*>\\s*([^<]*)</a>', 'gi'); |
| var MENU_ICON = '<svg width="20" height="20" viewBox="0 0 20 20"><path fill="currentColor" d="M 10 1.5 A 2 2 0 0 0 8 3.5 A 2 2 0 0 0 10 5.5 A 2 2 0 0 0 12 3.5 A 2 2 0 0 0 10 1.5 z M 10 8 A 2 2 0 0 0 8 10 A 2 2 0 0 0 10 12 A 2 2 0 0 0 12 10 A 2 2 0 0 0 10 8 z M 10 14.5 A 2 2 0 0 0 8 16.5 A 2 2 0 0 0 10 18.5 A 2 2 0 0 0 12 16.5 A 2 2 0 0 0 10 14.5 z"/></svg>'; |
| var MENU_ICON_DESCRIPTION = 'Show menu'; |
| var MENU_CLOSE_ICON = '<svg width="20" height="20" viewBox="0 0 20 20"><path fill="currentColor" d="M 4.34375 2.9296875 L 2.9296875 4.34375 L 8.5859375 10 L 2.9296875 15.65625 L 4.34375 17.070312 L 10 11.414062 L 15.65625 17.070312 L 17.070312 15.65625 L 11.414062 10 L 17.070312 4.34375 L 15.65625 2.9296875 L 10 8.5859375 L 4.34375 2.9296875 z"/></svg>'; |
| var MENU_CLOSE_ICON_DESCRIPTION = 'Hide menu'; |
| var TREE_HANDLE = '<svg width="24" height="24" viewBox="0 0 24 24" focusable="false" role="presentation">-<path d="M10.294 9.698a.988.988 0 0 1 0-1.407 1.01 1.01 0 0 1 1.419 0l2.965 2.94a1.09 1.09 0 0 1 0 1.548l-2.955 2.93a1.01 1.01 0 0 1-1.42 0 .988.988 0 0 1 0-1.407l2.318-2.297-2.327-2.307z" fill="currentColor"/></svg>'; |
| var BOOK_NAME_SHORTENER = function shortenBookName(bookName) { return bookName.replace(/\s+(Documentation\s*)?(\-\s+([0-9,\-]+\s+)?Preview(\s+[0-9,\-]+)?\s*)?$/i, ''); }; |
| var BOOK_SCOPE_BY_DEFAULT = 0; |
| var BOOK_SCOPE_COOKIE = 'book-scope'; |
| var SEARCH_SCOPE_CLOSE_DESCRIPTION = 'Close scopes'; |
| var SEARCH_ICON = '<svg width="20" height="20" viewBox="0 0 20 20"><g fill="#fff"><path fill="currentColor" d="M 7.5 0 C 3.3578644 0 0 3.3578644 0 7.5 C 0 11.642136 3.3578644 15 7.5 15 C 8.8853834 14.997 10.242857 14.610283 11.421875 13.882812 L 17.185547 19.662109 C 17.632478 20.113489 18.36112 20.112183 18.8125 19.660156 L 19.623047 18.845703 C 20.072507 18.398153 20.072507 17.665594 19.623047 17.214844 L 13.871094 11.447266 C 14.607206 10.26212 14.998156 8.8951443 15 7.5 C 15 3.3578644 11.642136 0 7.5 0 z M 7.5 2 A 5.5 5.5 0 0 1 13 7.5 A 5.5 5.5 0 0 1 7.5 13 A 5.5 5.5 0 0 1 2 7.5 A 5.5 5.5 0 0 1 7.5 2 z"/></g></svg>'; |
| var SEARCH_FIELD_DESCRIPTION = '* = any string\n? = any character\n"" = phrase\nAND, OR & NOT = boolean operators'; |
| var SEARCH_FIELD_PLACEHOLDER = 'Search'; |
| var BASE_URL; |
| var SEARCH_BASE_URL; |
| var SEARCH_HITS_MAX = 500; |
| var SEARCH_AS_YOU_TYPE_PROPOSAL_MAX = 7; |
| var SEARCH_RESULTS_INDEXING_PATTERN = new RegExp('[\'"]divProgress[\'"]\\s+STYLE\\s*=\\s*[\'"]\\s*width\\s*:\\s*([\\d]+)\\s*px', 'i'); |
| var SEARCH_RESULTS_PATTERN = new RegExp('<tr[^<]*<td[^<]*<img[^<]*</td[^<]*<td[^<]*<a\\s+(?:(?!href)(?!title)[\\w\\-]+\\s*=\\s*(?:(?:\'[^\']*\')|(?:"[^"]*"))\\s+)*(href|title)\\s*=\\s*"([^"]*)"\\s+(?:(?!href)(?!title)[\\w\\-]+\\s*=\\s*(?:(?:\'[^\']*\')|(?:"[^"]*"))\\s+)*(href|title)\\s*=\\s*"([^"]*)"[^>]*>([^<]*)</a>(?:(?:(?!<[/]?tr)[\\s\\S])*</tr\\s*>\\s*<tr(?:(?!</tr)(?!class="location">)[\\s\\S])*class="location">((?:(?!</div)[\\s\\S])*))?(?:(?:(?!</tr)(?!\\sclass=["\']description["\'])[\\s\\S])*</tr){1,2}(?:(?!</tr)(?!\\sclass=["\']description["\'])[\\s\\S])*\\sclass=["\']description["\'][^>]*>([^<]*)', 'gi'); |
| var SEARCH_RESULTS_BREADCRUMB_SNIPPET_PATTERN = new RegExp('<a\\s+href="([^"]+)">([^<]+)</a>', 'gi'); |
| var SEARCH_SCOPE_LABEL_NONE = 'All'; |
| var SEARCH_SCOPE_LABEL_BOOK = 'Book'; |
| var SEARCH_SCOPE_LABEL_CHAPTER = 'Chapter'; |
| // var SEARCH_SCOPE_LABEL_TOPIC = 'Find in page'; |
| var SEARCH_SCOPE_CURRENT_PATTERN = new RegExp('<div\\s+id\\s*=\\s*"scope"\\s*>([^<]*)<'); |
| var SEARCH_SCOPE_ALL_PATTERN = new RegExp('<a\\s+(?:(?!title)[\\w\\-]+\\s*=\\s*(?:(?:\'[^\']*\')|(?:"[^"]*"))\\s+)*title\\s*=\\s*"([^"]*)"', 'gi'); |
| var SEARCH_SCOPE_NAME_PATTERN = new RegExp('<input\\s+type\\s*=\\s*["\']text["\']\\s+(?:(?!value)[\\w\\-]+\\s*=\\s*(?:(?:\'[^\']*\')|(?:"[^"]*"))\\s+)*value\\s*=\\s*\'([^\']*)\'', 'i'); |
| var SEARCH_SCOPE_IS_NEW_PATTERN = new RegExp('oldName\\s*=\\s*\'\'', 'i'); |
| var SEARCH_SCOPE_HREFS_PATTERN = new RegExp('<input(?:\\s+(?!checked)[\\w\\-]+\\s*=\\s*(?:(?:\'[^\']*\')|(?:"[^"]*")))*(\\s+checked)?[^<]+<label\\s+for\\s*=\\s*"([^"]*)"[^>]*>([^<]*)</label>\\s*(</div)?', 'gi'); |
| var SEARCH_AS_YOU_TYPE_CACHE_SIZE = 7; |
| var SEARCH_FULL_SEARCH_CACHE_SIZE = 3; |
| var SEARCH_DELAY_IN_MILLISECOND = 99; |
| var SEARCH_CACHE = {fi: -1, f: [], ti: -1, t: [] }; |
| |
| // TODO integration: the browser should not have to calculate the following variables itself; |
| // only "init()" should be called instead |
| var embeddedMode = 1; |
| var title = 'Help'; |
| var bookmarksPage; |
| var scopesPage; |
| var searchPage; |
| var renderFullSearch; |
| var updateScopeByToc; |
| var setSearchScope; |
| var currentSearch = {}; |
| var searchScope = {l: 0, s: '', t: 0}; |
| |
| addEvent(window, 'load', function() { |
| |
| // (search) base URL |
| var a = createElement(0, 'a'); |
| a.href = window.location.pathname.indexOf('/index.jsp') >= 0 ? 'x' : '../../x'; |
| BASE_URL = a.href.substring(0, a.href.length - 1); |
| SEARCH_BASE_URL = BASE_URL + 'advanced/searchView.jsp?showSearchCategories=false&searchWord='; |
| |
| remoteRequest(BASE_URL + 'advanced/search.jsp', function(responseText) { |
| |
| // read user defined search scope |
| var match = SEARCH_SCOPE_CURRENT_PATTERN.exec(responseText); |
| searchScope.i = match ? match[1] : match; |
| |
| // make sure no scope is set (a scope might have been set via the legacy UI before) |
| remoteRequest(BASE_URL + 'scopeState.jsp?workingSet='); |
| |
| // title |
| remoteRequest(BASE_URL + 'index.jsp?legacy', function(responseText) { |
| var match = new RegExp('<title>([^<]*)</title>').exec(responseText); |
| if (!match) return; |
| title = decodeHtml(match[1]); |
| document.title = title; |
| }); |
| |
| // embedded or Infocenter mode? + read scopes |
| remoteRequest(BASE_URL + 'advanced/tabs.jsp', function(responseText) { |
| if (responseText.indexOf('e_bookmarks_view.') < 0) embeddedMode = 0; |
| |
| // read scopes |
| remoteRequest(BASE_URL + 'advanced/workingSetManager.jsp?t=' + Date.now(), function(responseText) { |
| var scopeIndex = 0; |
| SEARCH_SCOPE_ALL_PATTERN.lastIndex = 0; |
| for (var match; (match = SEARCH_SCOPE_ALL_PATTERN.exec(responseText)) != null;) { |
| var scopeName = decodeHtml(match[1]); |
| if (scopeName.substring(0, 1) == '\u200B') { |
| if (scopeName.length < 3) { |
| searchScope.l = scopeName.length; |
| break; |
| } else { |
| searchScope.l = 4; |
| searchScope.t = scopeName.length - 3; |
| continue; |
| } |
| } |
| if (searchScope.i && searchScope.i == scopeName) { |
| searchScope.l = 4; |
| searchScope.s = scopeName; |
| break; |
| } else if (searchScope.l == 4 && searchScope.t == scopeIndex) { |
| searchScope.s = scopeName; |
| } |
| scopeIndex++; |
| } |
| |
| init(); |
| |
| }); |
| }); |
| |
| }); |
| |
| }); |
| |
| function init() { |
| |
| // bookmarks page |
| bookmarksPage = createElement(getElementById('m'), 0, 'c'); |
| bookmarksPage.id = 'b'; |
| bookmarksPage.s = function(show) { |
| bookmarksPage.o = !!show; |
| if (show && scopesPage) scopesPage.s(); |
| bookmarksPage.style.display = show ? 'block' : 'none'; |
| getElementById('c').style.display = show || (searchPage && searchPage.o) ? 'none' : 'block'; |
| if (searchPage) searchPage.style.display = searchPage.o && !show ? 'block' : 'none'; |
| if (!show) return; |
| bookmarksPage.innerHTML = ''; |
| |
| // add bookmark |
| try { |
| var url = frames.c.location.href; |
| var title = searchPage.o ? searchPage.l : frames.c.document.title; |
| if (title == null || title == '') { |
| title = url; |
| } |
| createElement(bookmarksPage, 'span', 'g', 'Add:'); |
| var addArea = createElement(bookmarksPage, 'span', 'a'); |
| var input = createElement(addArea, 'input'); |
| input.type = 'text'; |
| input.autocomplete = 'off'; |
| input.value = title; |
| var addButtonTooltip = searchPage.o ? BOOKMARKS_ADD_SEARCH_DESCRIPTION : BOOKMARKS_ADD_PAGE_DESCRIPTION; |
| createButton(addArea, BOOKMARKS_ICON, addButtonTooltip, function() { |
| try { |
| var url = frames.c.location.href; |
| if (url.substring(0, BASE_URL.length + 6) == BASE_URL + 'topic/') { |
| url = url.substring(BASE_URL.length + 5); |
| |
| // workaround for a bug of the legacy UI: non-topic links (e.g. ".../nav/..." instead of |
| // ".../topic/...") are stored absolutely instead of relatively (which doesn't work, because by |
| // default a random port number is chosen when restarting Eclipse) |
| } else if (url.substring(0, BASE_URL.length) == BASE_URL) { |
| url = '/../' + url.substring(BASE_URL.length); |
| } |
| |
| var title = frames.c.document.title; |
| if (title == null || title == '') { |
| title = url; |
| } |
| remoteRequest( BASE_URL + 'advanced/bookmarksView.jsp?operation=add&' |
| + 'bookmark=' + encodeURIComponent(url) |
| + '&title=' + encodeURIComponent(input.value) |
| + '&t=' + Date.now()); |
| bookmarksPage.s(); |
| } catch (e) {} |
| }); |
| } catch (e) {} |
| |
| // "x" button |
| setClassName(createButton(bookmarksPage, MENU_CLOSE_ICON, BOOKMARKS_CLOSE_DESCRIPTION, function() { |
| bookmarksPage.s(); |
| }), 'b bc'); |
| |
| remoteRequest(BASE_URL + 'advanced/bookmarksView.jsp?t=' + Date.now(), function(responseText) { |
| var ol; |
| var element = createElement(); |
| var deleteButtons = []; |
| BOOKMARKS_PATTERN.lastIndex = 0; |
| for (var match; (match = BOOKMARKS_PATTERN.exec(responseText)) != null;) { |
| if (!ol) { |
| createElement(bookmarksPage, 0, 'g', 'Bookmarks:'); |
| ol = createElement(bookmarksPage, 'ol'); |
| } |
| var groups = []; |
| for (var i = 1; i < 4; i++) { |
| element.innerHTML = match[i]; |
| groups.push((element.textContent ? element.textContent : element.innerText).replace(/^\s+|\s+$/g,'').replace(/\s+/g,' ')); |
| } |
| var li = createElement(ol, 'li'); |
| var href = groups[0].substring(0, 3) == '../' ? BASE_URL + '/' + groups[0] : groups[0]; |
| var deleteButton = createButton(li, |
| BOOKMARKS_DELETE, |
| BOOKMARKS_DELETE_DESCRIPTION, |
| function(href, title, li) { |
| return function() { |
| remoteRequest( BASE_URL + 'advanced/bookmarksView.jsp?operation=remove&' |
| + 'bookmark=' + encodeURIComponent(href) |
| + '&title=' + encodeURIComponent(title) |
| + '&t=' + Date.now()); |
| li.style.display = 'none'; |
| } |
| }(groups[0].substring(0, 9) == '../topic/' ? groups[0].substring(8) : groups[0], groups[1], li)); |
| deleteButton.style.display = 'none'; |
| deleteButton.className = 'b br'; |
| deleteButtons.push(deleteButton); |
| var a = createElement(li, 'a'); |
| a.target = 'c'; |
| a.href = href; |
| createElement(a, 'span').innerHTML = BOOKMARKS_ICON; |
| createElement(a, 'span', 0, groups[1]); |
| } |
| if (deleteButtons.length) { |
| var editButton = createButton(bookmarksPage, 'Edit', 'Delete bookmarks', function() { |
| var editMode = editButton.innerHTML == 'Edit'; |
| editButton.innerHTML = editMode ? BOOKMARKS_DELETE_ALL : 'Edit'; |
| editButton.title = editMode ? BOOKMARKS_DELETE_ALL_DESCRIPTION : 'Delete bookmarks'; |
| setClassName(editButton, editMode ? 'b br' : 'b'); |
| for (var i = 0; i < deleteButtons.length; i++) { |
| deleteButtons[i].style.display = 'inline-block'; |
| } |
| if (!editMode) { |
| remoteRequest(BASE_URL + 'advanced/bookmarksView.jsp?operation=removeAll&t=' + Date.now()); |
| bookmarksPage.s(); |
| } |
| }); |
| } |
| createButton(bookmarksPage, 'Cancel', BOOKMARKS_CLOSE_DESCRIPTION, function() { bookmarksPage.s(); }); |
| |
| }); |
| } |
| bookmarksPage.s(); |
| |
| // scopes page |
| scopesPage = createElement(getElementById('m'), 0, 'c'); |
| scopesPage.id = 'o'; |
| scopesPage.s = function(show) { |
| scopesPage.o = !!show; |
| if (show && bookmarksPage) bookmarksPage.s(); |
| scopesPage.style.display = show ? 'block' : 'none'; |
| getElementById('c').style.display = show || (searchPage && searchPage.o) ? 'none' : 'block'; |
| if (searchPage) searchPage.style.display = searchPage.o && !show ? 'block' : 'none'; |
| if (!show) return; |
| function showScopesPage(query, scopeNr) { |
| scopesPage.innerHTML = ''; |
| |
| // "x" button |
| setClassName(createButton(scopesPage, MENU_CLOSE_ICON, SEARCH_SCOPE_CLOSE_DESCRIPTION, function() { |
| scopesPage.s(); |
| }), 'b bc'); |
| |
| // get and show content |
| remoteRequest( BASE_URL |
| + 'advanced/workingSet' |
| + (query ? '.jsp?' + query + '&' : 'Manager.jsp?') |
| + 't=' + Date.now(), |
| function(responseText) { |
| var match = SEARCH_SCOPE_NAME_PATTERN.exec(responseText); |
| if (match) { |
| createElement(scopesPage, 'span', 'g', 'Scope:'); |
| var scopeName = decodeHtml(match[1]); |
| var nameInput = createElement(createElement(scopesPage, 'span', 'a'), 'input'); |
| nameInput.type = 'text'; |
| nameInput.value = scopeName; |
| var tree = []; |
| var allNodes = []; |
| var parentNode; |
| SEARCH_SCOPE_HREFS_PATTERN.lastIndex = 0; |
| for (; (match = SEARCH_SCOPE_HREFS_PATTERN.exec(responseText)) != null;) { |
| var node = {n: {l: decodeHtml(match[3]), v: decodeHtml(match[2]), c: [], x: !!match[1]}, l: 1}; |
| allNodes.push(node.n); |
| if (match[4] && parentNode) { |
| parentNode.l = 0; |
| parentNode.n.c.push(node); |
| node.n.p = parentNode.n; |
| } else { |
| parentNode = node; |
| tree.push(node); |
| } |
| } |
| createTree(scopesPage, |
| |
| // content provider |
| function(node, processChildrenFn) { |
| processChildrenFn(node ? node.c : tree); |
| }, |
| |
| // label provider |
| function(li, node) { |
| var checkboxWithLabel = createElement(li); |
| var checkbox = createElement(checkboxWithLabel, 'input'); |
| checkbox.type = 'checkbox'; |
| checkbox.id = node.v; |
| if (node.x) { |
| checkbox.checked = 'checked'; |
| } |
| node.b = checkbox; |
| checkbox.n = node; |
| updateOrGetScopeCheckboxStates(node); |
| if (updateOrGetScopeCheckboxStates(node, 1)) { |
| setClassName(li, 'open'); |
| } |
| addEvent(checkbox, 'click', (function(node) { |
| return function() { |
| updateOrGetScopeCheckboxStates(node.p); |
| setSubtreeState(node, node.b.checked); |
| }; |
| })(node)); |
| var label = createElement(checkboxWithLabel, 'label', 0, node.l); |
| setAttribute(label, 'for', node.v); |
| return checkboxWithLabel; |
| } |
| |
| ); |
| function getHrefs() { |
| hrefs = ''; |
| for (var i = 0; i < allNodes.length; i++) { |
| var node = allNodes[i]; |
| if ( (node.b ? node.b.checked : node.x) |
| && (!node.p || !(node.p.b ? node.p.b.checked : node.p.x))) { |
| hrefs += '&hrefs=' + node.v; |
| } |
| } |
| return hrefs; |
| } |
| if (SEARCH_SCOPE_IS_NEW_PATTERN.exec(responseText)) { |
| createButton(scopesPage, 'Create', 'Add new scope', function() { |
| doScopesOperation( 'add&oldName=&workingSet=' |
| + encodeURIComponent(nameInput.value) |
| + getHrefs()); |
| }); |
| } else { |
| var deleteButton = createButton(scopesPage, 'Delete', 'Delete this scope', function() { |
| doScopesOperation('remove&workingSet=' + encodeURIComponent(scopeName)); |
| }); |
| deleteButton.className = 'b br'; |
| createButton(scopesPage, 'Apply', 'Update this scope', function() { |
| doScopesOperation( 'edit&oldName=' |
| + encodeURIComponent(scopeName) |
| + '&workingSet=' |
| + encodeURIComponent(nameInput.value) |
| + getHrefs()); |
| setSearchScope([4, scopeName, scopeNr]); |
| }); |
| } |
| createButton(scopesPage, 'Cancel', 'Go back to list of scopes',function() { showScopesPage(); }); |
| |
| } else { |
| createElement(scopesPage, 0, 'g', 'Scopes:'); |
| var ol = createElement(scopesPage, 'ol'); |
| SEARCH_SCOPE_ALL_PATTERN.lastIndex = 0; |
| for (var scopeIndex = 0; (match = SEARCH_SCOPE_ALL_PATTERN.exec(responseText)) != null;) { |
| var scopeName = decodeHtml(match[1]); |
| if (scopeName.substring(0, 1) == '\u200B') continue; |
| var li = createElement(ol, 'li'); |
| createButton(li, scopeName, 0, function(scopeName, scopeIndex) { |
| return function() { showScopesPage('operation=edit&workingSet=' + encodeURIComponent(scopeName), scopeIndex); }; |
| }(scopeName, scopeIndex), 'ba'); |
| scopeIndex++; |
| } |
| createButton(scopesPage, 'New', 'Add a new scope', function() { showScopesPage('operation=add'); }); |
| createButton(scopesPage, 'Cancel', SEARCH_SCOPE_CLOSE_DESCRIPTION, function() { scopesPage.s(); }); |
| } |
| }); |
| } |
| function doScopesOperation(query) { |
| remoteRequest( BASE_URL |
| + 'workingSetState.jsp?operation=' |
| + query |
| + '&t=' + Date.now(), |
| function() { showScopesPage(); }); |
| } |
| showScopesPage(); |
| } |
| function updateOrGetScopeCheckboxStates(node, computeState) { |
| for (var parent = node; parent; parent = parent.p) { |
| var allChecked = 1; |
| var allUnchecked = 1; |
| for (var i = 0; i < parent.c.length; i++) { |
| var childNode = parent.c[i].n; |
| if (childNode.b ? childNode.b.checked : childNode.x) { |
| allUnchecked = 0; |
| } else { |
| allChecked = 0; |
| } |
| } |
| if (computeState) { |
| return !allChecked && !allUnchecked; |
| } |
| if (!parent.c.length) continue; |
| parent.b.checked = !!allChecked; |
| parent.b.indeterminate = !allChecked && !allUnchecked; |
| } |
| } |
| function setSubtreeState(node, state) { |
| for (var i = 0; i < node.c.length; i++) { |
| var childNode = node.c[i].n; |
| if (childNode.b) { |
| childNode.b.checked = !!state; |
| } else { |
| childNode.x = state; |
| } |
| setSubtreeState(childNode, state); |
| } |
| } |
| scopesPage.s(); |
| |
| // search page |
| searchPage = createElement(getElementById('m'), 0, 'c', 'Loading...'); |
| searchPage.id = 'r'; |
| searchPage.s = function(show) { |
| searchPage.o = !!show; |
| searchPage.style.display = show ? 'block' : 'none'; |
| getElementById('c').style.display = show ? 'none' : 'block'; |
| if (bookmarksPage) bookmarksPage.s(); |
| if (scopesPage) scopesPage.s(); |
| if (show) { |
| document.title = searchPage.l + ' - ' + title; |
| } else { |
| try { |
| var topicTitle = contentFrame.contentDocument.title; |
| document.title = topicTitle ? (topicTitle + ' - ' + title) : title; |
| } catch(e) { |
| document.title = title; |
| } |
| } |
| } |
| searchPage.s(); |
| |
| // toolbar: TOC sidebar button and history Back/Forward buttons (in embedded help, but not in Infocenter mode) |
| var header = getElementById('h'); |
| var toolbarContainer = createElement(header); |
| var toolbar = createElement(toolbarContainer, 0, 'y'); |
| var tocSidebarToggleButton = createButton(toolbar, TOC_ICON, TOC_ICON_DESCRIPTION); |
| if (embeddedMode) { |
| createButton(toolbar, HISTORY_BACK_ICON, HISTORY_BACK_DESCRIPTION, function() { |
| window.history.back(); |
| }); |
| createButton(toolbar, HISTORY_FORWARD_ICON, HISTORY_FORWARD_DESCRIPTION, function() { |
| window.history.forward(); |
| }); |
| } |
| |
| // TOC slider (to change TOC sidebar width by moving the slider) |
| var smallScreenAutoCloseFn = createSlider(tocSidebarToggleButton, toolbarContainer, createElement(header, 0, 'i')); |
| |
| // fill TOC and create search field |
| var toc = getElementById('t'); |
| createTree(toc, |
| tocContentProvider, |
| function(li, node) { |
| if (node.toc) { |
| li.toc = node.toc; |
| } |
| li.n = node; |
| var a = createElement(li, 'a'); |
| a.href = node.h; |
| a.target = 'c'; |
| addEvent(a, 'click', smallScreenAutoCloseFn); |
| li.h = a.href; |
| li.a = a.hash; |
| li.b = a.protocol + '//' + a.host + a.pathname; |
| if (node.i) { |
| var iconImg = createElement(a, 'img'); |
| iconImg.setAttribute('src', BASE_URL |
| + 'advanced/images/' |
| + node.i |
| + '.svg'); |
| } |
| a.appendChild(document.createTextNode(node.t)); |
| return a; |
| }, |
| 1); |
| toc.c = 1; // scroll into view if needed: to upper third instead of scroll as less as possible |
| var contentFrame = getElementById('c'); |
| addEvent(contentFrame, 'load', function() { |
| |
| // full search? |
| var contentFrameHref = frames.c.location.href; |
| if (contentFrameHref.substring(0, SEARCH_BASE_URL.length) == SEARCH_BASE_URL) { |
| var data = frames.c.document.documentElement.innerHTML; |
| renderFullSearch(contentFrameHref.substring(SEARCH_BASE_URL.length), data); |
| searchPage.s(1); |
| return; |
| } |
| |
| // close maybe open bookmarks, scopes or search page |
| if (bookmarksPage) bookmarksPage.s(); |
| if (scopesPage) scopesPage.s(); |
| searchPage.s(); |
| updateDeepLink(); |
| |
| // font sizing |
| setFontSize(0, 1, 1); |
| |
| // update title and deep link |
| try { |
| var topicTitle = contentFrame.contentDocument.title; |
| document.title = topicTitle ? (topicTitle + ' - ' + title) : title; |
| } catch(e) { |
| document.title = title; |
| } |
| |
| // sync with TOC |
| try { |
| syncToc(); |
| addEvent(contentFrame.contentWindow, 'hashchange', function() { syncToc(); updateDeepLink(); }); |
| } catch(e) { |
| toc.x(0); |
| } |
| |
| }); |
| addEvent(window, 'hashchange', function() { |
| var newHash = window.location.hash; |
| if (isQueryHash(newHash)) { |
| searchFullByHash(newHash); |
| } else { |
| searchPage.s(); |
| } |
| }); |
| |
| } |
| function createButton(parent, innerHtml, description, clickFn, className, text) { |
| var button = createElement(parent, 'button', className ? className : 'b', text); |
| if (description) { |
| button.title = description; |
| } |
| if (innerHtml) { |
| setInnerHtml(button, innerHtml); |
| } |
| if (clickFn) { |
| addEvent(button, 'click', function(e) { preventDefault(e); clickFn(e); }); |
| } |
| return button; |
| } |
| |
| function initContentPage() { |
| |
| // set initial start/cover page... |
| // ...by hash |
| var hash = window.location.hash; |
| try { |
| if (hash && ( 'q=' == hash.substring(1, 3) |
| || 'nav/' == hash.substring(1, 5) |
| || 'topic/' == hash.substring(1, 7) |
| || 'rtopic/' == hash.substring(1, 8) |
| || 'ntopic/' == hash.substring(1, 8) |
| || 'nftopic/' == hash.substring(1, 9))) { |
| if ('q=' == hash.substring(1, 3)) { |
| searchFullByHash(hash); |
| } else { |
| getElementById('c').src = BASE_URL + hash.substring(1); |
| } |
| return; |
| } |
| } catch(e) {} |
| |
| // ...by legacy query parameters (topic/nav or search link) |
| var params = getParams(window.location.href.replace(/^[^#\?]*(?:\?([^#\?]*))?(#.*)?$/, '$1')); |
| var topicOrNav = params.topic || params.nav; |
| if (params.searchWord && params.tab == 'search') { |
| window.history.replaceState(null, '', window.location.pathname); |
| searchFullByHash('#q=' + encodeURIComponent(params.searchWord)); |
| return; |
| } |
| if (topicOrNav) { |
| getElementById('c').src = BASE_URL |
| + (params.nav ? 'nav' : 'topic') |
| + topicOrNav |
| + (params.anchor ? '#' + params.anchor : ''); |
| window.history.replaceState(null, '', window.location.pathname); |
| updateDeepLink(); |
| return; |
| } |
| |
| // ...default start/cover page |
| remoteRequest(BASE_URL + 'advanced/content.jsp', function(responseText) { |
| var start = responseText.indexOf('title="Topic View" src=\''); |
| if (start > 0) { |
| var end = responseText.indexOf("'", start + 24); |
| var element = createElement(null, 'p'); |
| element.innerHTML = responseText.substring(start + 24, end); |
| getElementById('c').src = BASE_URL |
| + 'topic/' |
| + (element.textContent ? element.textContent : element.innerText); |
| updateDeepLink(); |
| } |
| }); |
| |
| } |
| |
| function syncToc() { |
| var newLocation = getElementById('c').contentWindow.location; |
| var toc = getElementById('t'); |
| if (toc.s && toc.s.h == newLocation.href) return; |
| var newLocationHrefWithoutQueryAndHash = newLocation.protocol + '//' + newLocation.host + newLocation.pathname; |
| var newLocationHash = newLocation.hash; |
| var liMatch; |
| var liWhithoutHashMatch; |
| toc.v(function(li) { |
| if (newLocationHrefWithoutQueryAndHash != li.b) return 1; |
| if (!newLocationHash || newLocationHash == li.a) { |
| liMatch = li; |
| return 0; |
| } |
| if (!liWhithoutHashMatch) { |
| liWhithoutHashMatch = li; |
| } |
| return 1; |
| }); |
| if (liMatch) { |
| toc.x(liMatch, toc, 1); |
| } else if (liWhithoutHashMatch) { |
| toc.x(liWhithoutHashMatch, toc, 1); |
| } else { |
| toc.y(newLocation.href, toc, 1); |
| } |
| } |
| |
| function updateDeepLink(query) { |
| var hash; |
| if (query) { |
| hash = 'q=' + query; |
| } else { |
| try { |
| var src = getElementById('c').contentDocument.location.href; |
| if (BASE_URL != src.substring(0, BASE_URL.length)) return; |
| var current = src.substring(BASE_URL.length); |
| if ( 'nav/' == current.substring(0, 4) |
| || 'topic/' == current.substring(0, 6) |
| || 'rtopic/' == current.substring(0, 7) |
| || 'ntopic/' == current.substring(0, 7) |
| || 'nftopic/' == current.substring(0, 8)) { |
| hash = current; |
| } |
| } catch(e) {} |
| } |
| try { |
| var url = hash ? '#' + hash : window.location.href.replace(/^([^#\?]*(?:\?([^#\?]*))?)(#.*)?$/, '$1'); |
| window.history.replaceState(null, '', url); |
| } catch(e) {} |
| } |
| function isQueryHash(hash) { |
| return hash && ( (hash.length > 1 && hash.substring(0, 2) == 'q=') |
| || (hash.length > 2 && hash.substring(0, 3) == '#q=')); |
| } |
| |
| function createSlider(tocSidebarToggleButton, toolbar, headSpacerElement) { |
| |
| // create slider element |
| var slider = createElement(); |
| slider.id = 's'; |
| getElementById('m').insertBefore(slider, getElementById('c')); |
| var sliderWidth = slider.getBoundingClientRect().width; |
| var sliderHalfWidth = sliderWidth > 0 ? sliderWidth / 2 : 0; |
| |
| // create overlay required for smooth slider drag'n'drop |
| var overlay = createOverlay(); |
| |
| // TOC sidebar with its style and width |
| var tocWidth; |
| var tocSidebar = getElementById('t'); |
| var tocSidebarStyle = tocSidebar.style; |
| var headSpacerElementStyle = headSpacerElement.style; |
| var toolbarWidth = toolbar.getBoundingClientRect().width; |
| var tocSidebarMinimumWidth = TOC_SIDEBAR_MINIMUM_WIDTH > toolbarWidth ? TOC_SIDEBAR_MINIMUM_WIDTH : toolbarWidth; |
| |
| // slider movement |
| function move(e) { |
| tocWidth = (e.touches ? e.touches[0].clientX : e.pageX) - sliderHalfWidth; |
| if (tocWidth < 0) { |
| tocWidth = 0; |
| } |
| tocSidebarStyle.width = tocWidth + 'px'; |
| updateSpacerWidth(); |
| preventDefault(e); |
| } |
| function moveEnd(e) { |
| if (e.touches) { |
| addOrRemoveEventListener(0, 'touchmove', move, 1); |
| addOrRemoveEventListener(0, 'touchcancel', moveEnd); |
| addOrRemoveEventListener(0, 'touchend', moveEnd); |
| } else { |
| addOrRemoveEventListener(0, 'mousemove', move); |
| addOrRemoveEventListener(0, 'mouseup', moveEnd); |
| } |
| overlay.o(); |
| tocSidebarStyle.userSelect = ''; |
| if (tocWidth < tocSidebarMinimumWidth) { |
| var oldWidth = getCookie('toc-width'); |
| tocWidth = oldWidth ? oldWidth : TOC_SIDEBAR_DEFAULT_WIDTH; |
| toggleTocSidebar(); |
| } |
| setCookie(TOC_SIDEBAR_WIDTH_COOKIE_NAME, tocWidth); |
| preventDefault(e); |
| stopPropagation(e); |
| } |
| function moveStart(e) { |
| if (e.which && e.which != 1) return; |
| if (e.touches) { |
| addOrRemoveEventListener(1, 'touchend', moveEnd); |
| addOrRemoveEventListener(1, 'touchcancel', moveEnd); |
| addOrRemoveEventListener(1, 'touchmove', move, 1); |
| } else { |
| addOrRemoveEventListener(1, 'mouseup', moveEnd); |
| addOrRemoveEventListener(1, 'mousemove', move); |
| } |
| overlay.a(); |
| setClassName(tocSidebar, ''); |
| tocSidebarStyle.transition = ''; |
| headSpacerElementStyle.transition = ''; |
| preventDefault(e); |
| stopPropagation(e); |
| } |
| var documentElement = document.documentElement; |
| function addOrRemoveEventListener(add, event, fn, passive) { |
| if (add) { |
| documentElement.addEventListener(event, fn, passive ? { passive: false } : false); |
| } else { |
| documentElement.removeEventListener(event, fn, passive ? { passive: false } : false); |
| } |
| } |
| function updateSpacerWidth(hideToc, tocWidth, withTransition) { |
| if (withTransition) { |
| headSpacerElementStyle.transition = 'width .25s ease-in'; |
| } |
| var spacerWidth = (tocWidth || tocSidebar.getBoundingClientRect().right) |
| + sliderWidth |
| - toolbar.getBoundingClientRect().right; |
| var displayWidth = hideToc || spacerWidth < 0 ? 0 : spacerWidth; |
| headSpacerElementStyle.width = displayWidth + 'px'; |
| var widthPostfix = displayWidth >= LOGO_ICON_WIDTH ? (displayWidth >= LOGO_FULL_WIDTH ? 'f' : 1) : 0; |
| setClassName(headSpacerElement, 'k' + (embeddedMode ? 'e' : '') + widthPostfix); |
| } |
| |
| addEvent(slider, 'mousedown', moveStart); |
| addEvent(slider, 'touchstart', moveStart); |
| |
| // TOC sidebar toggling |
| function toggleTocSidebar(e, initialize, asSmallScreenAutoCloseFn) { |
| if (!asSmallScreenAutoCloseFn) { |
| preventDefault(e); |
| } |
| var isSmall = isSmallScreen(); |
| var currentClass = getClassName(tocSidebar); |
| if (asSmallScreenAutoCloseFn && (!isSmall || currentClass != 'show')) return; |
| var hideToc = isSmall ? currentClass == 'show' : tocWidth > 0; |
| if (initialize) { |
| tocWidth = -getCookie(TOC_SIDEBAR_WIDTH_COOKIE_NAME, TOC_SIDEBAR_DEFAULT_WIDTH); |
| hideToc = isSmall || tocWidth > 0; |
| } else { |
| tocSidebarStyle.transition = 'width .25s ease-in'; |
| headSpacerElementStyle.transition = 'margin-right .25s ease-in'; |
| } |
| setClassName(tocSidebar, isSmall ? (hideToc ? '' : 'show') : (hideToc ? 'hide' : '')); |
| if (initialize || !isSmall) { |
| tocWidth = -tocWidth; |
| if (!initialize) { |
| setCookie(TOC_SIDEBAR_WIDTH_COOKIE_NAME, tocWidth); |
| } |
| } |
| if (initialize || !isSmall) { |
| tocSidebarStyle.width = (hideToc ? 0 : tocWidth > tocSidebarMinimumWidth |
| ? tocWidth |
| : TOC_SIDEBAR_DEFAULT_WIDTH) |
| + 'px'; |
| } |
| tocSidebarStyle.userSelect = hideToc ? 'none' : ''; |
| if (!hideToc && tocSidebar.f) { |
| tocSidebar.f(); |
| } |
| if (!isSmall) { |
| updateSpacerWidth(hideToc, tocWidth, 1); |
| } |
| } |
| toggleTocSidebar(0, 1); |
| addEvent(slider, 'dblclick', toggleTocSidebar); |
| addEvent(tocSidebarToggleButton, 'click', toggleTocSidebar); |
| |
| // function to close TOC if screen is small |
| return function(e) { |
| toggleTocSidebar(e, 0, 1); |
| }; |
| |
| } |
| |
| function tocContentProvider(node, processChildrenFn) { |
| var callbackUrl = BASE_URL + 'advanced/tocfragment' |
| + (node |
| ? (node.toc ? '?toc=' + node.toc : '') |
| + (node.path ? '&path=' + node.path : '') |
| + (node.topic ? '?errorSuppress=true&topic=' + node.topic : '') |
| + (node.expand ? '?errorSuppress=true&expandPath=' + node.expand : '') |
| : ''); |
| remoteRequest(callbackUrl, function(responseText) { |
| var nodes = tocXmlNodes(parseXml(responseText), node ? node.toc : 0, node ? node.path : 0); |
| var children; |
| for (var i = 0; i < nodes.length; i++) { |
| var n = nodes[i]; |
| if (n.tagName == 'numeric_path') { |
| tocContentProvider({expand: getAttribute(n, 'path')}, processChildrenFn); |
| return; |
| } |
| if (n.tagName == 'node') { |
| children = tocToNodes(nodes, node ? node.toc : 0, node ? node.expand : 0); |
| break; |
| } |
| } |
| if (!node) { |
| createSearchField(); |
| initContentPage(); |
| setFontSize(0, 1); |
| } |
| processChildrenFn(children); |
| }); |
| } |
| function tocXmlNodes(xml, toc, path) { |
| var books = xml.documentElement.childNodes; |
| if (!toc) return books; |
| var book; |
| for (var i = 0; i < books.length; i++) { |
| book = books[i]; |
| if (book.tagName == 'node' && toc == book.getAttribute('id')) { |
| if (!path) return book.childNodes; |
| break; |
| } |
| } |
| var nodes = book.childNodes; |
| tocLevelLoop: while (1) { |
| for (var i = 0; i < nodes.length; i++) { |
| n = nodes[i]; |
| if (n.tagName != 'node') continue; |
| var id = n.getAttribute('id'); |
| if (path == id) return n.childNodes; |
| if ( id |
| && path.length > id.length |
| && path.substring(0, id.length + 1) == id + '_') { |
| nodes = n.childNodes; |
| continue tocLevelLoop; |
| } |
| } |
| break; |
| } |
| return []; |
| } |
| function tocToNodes(xmlChildren, toc, expandPath) { |
| var children = []; |
| for (var i = 0; i < xmlChildren.length; i++) { |
| var n = xmlChildren[i]; |
| if (n.tagName != 'node') continue; |
| var currentToc = toc ? toc : getAttribute(n, 'id'); |
| children.push({ |
| n/*node*/: { |
| toc: currentToc, |
| path: toc ? getAttribute(n, 'id') : 0, |
| t: getAttribute(n, 'title'), |
| h: BASE_URL + getAttribute(n, 'href').substring(3), |
| i: n.getAttribute('image'), |
| y: expandPath, |
| l/*is leaf*/: getAttribute(n, 'is_leaf') |
| }, |
| l/*is leaf*/: getAttribute(n, 'is_leaf'), |
| c/*children*/: tocToNodes(n.childNodes, currentToc) |
| }); |
| } |
| return children; |
| } |
| |
| function isSmallScreen() { |
| var clientWidth = document.documentElement.clientWidth || document.body.clientWidth; |
| return clientWidth <= SMALL_SCREEN_WIDTH; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // Search: search-as-you-type ('t') and full search ('f') |
| |
| function createSearchField() { |
| var currentTocLi; |
| |
| // create overlay required for closing proposals drop-down even when clicking into the content iframe |
| var overlay = createOverlay(); |
| addEvent(overlay, 'click', hideProposals); |
| |
| // area (containing scope drop-down, search field and button) |
| // "searchFieldAreaWrapper" as workaround for sub-pixel problem in Firefox (1px border might become 0.8px border |
| // to align real pixels on high-DPI to CSS px), otherwise proposals drop-down might not correctly aligned with |
| // search field area |
| var searchFieldAreaWrapper = createElement(getElementById('h'), 0, 'q0'); |
| var searchFieldArea = createElement(createElement(searchFieldAreaWrapper, 0, 'q1'), 'form', 'q'); |
| |
| if (embeddedMode) { |
| createButton(searchFieldAreaWrapper, BOOKMARKS_ICON, BOOKMARKS_DESCRIPTION, function() { |
| bookmarksPage.s(!bookmarksPage.o); |
| }); |
| } |
| |
| var searchFieldAreaHasFocus; |
| var searchFieldAreaContainsQuery; |
| var proposals; |
| function updateSearchFieldAreaClass() { |
| setClassName(searchFieldArea, |
| 'q' + (proposals.style.display == 'block' ? 'm' : (searchFieldAreaHasFocus ? 'f' : '')) |
| + (searchFieldAreaContainsQuery ? ' qa' : '') |
| ); |
| } |
| createMenu(); |
| |
| // scopes drop-down |
| var scopeButtonWrapper = createElement(searchFieldArea, 0, 's0'); |
| |
| var booksButton = createElement(scopeButtonWrapper, 'button', 's'); |
| setAttribute(booksButton, 'type', 'button'); |
| booksButtonText = createElement(booksButton, 'span'); |
| var dropDownHandle = createElement(booksButton, 'span', 'de'); |
| setInnerHtml(dropDownHandle, TREE_HANDLE); |
| var booksDropDown = createElement(scopeButtonWrapper, 0, 'u'); |
| booksDropDown.s = function(show) { |
| var isOpen = booksDropDown.style.display == 'block'; |
| if (!isOpen == !show) return; |
| booksDropDown.style.display = show ? 'block' : 'none'; |
| if (!show) return; |
| setInnerHtml(booksDropDown); |
| var booksDropDownUl = createElement(booksDropDown, 'ul', 'r'); |
| var menuItems = []; |
| var dataItems = []; |
| var currentBook; |
| var currentChapter; |
| for (var tocLi = currentTocLi; tocLi && tocLi.n; tocLi = tocLi.p) { |
| if (!tocLi.n.path) { |
| currentBook = tocLi.n.t; |
| if (!currentChapter) { |
| currentChapter = currentBook; |
| } |
| } else if (!currentChapter && !tocLi.n.l) { |
| currentChapter = tocLi.n.t; |
| } |
| } |
| menuItems.push(createElement(booksDropDownUl, 'li', searchScope.l == 0 ? 'x': 0, SEARCH_SCOPE_LABEL_NONE)); |
| dataItems.push([0]); |
| menuItems.push(createElement(booksDropDownUl, 'li', searchScope.l == 1 ? 'x': 0, SEARCH_SCOPE_LABEL_BOOK + (currentBook ? ': ' + currentBook : ''))); |
| dataItems.push([1]); |
| menuItems.push(createElement(booksDropDownUl, 'li', searchScope.l == 2 ? 'x': 0, SEARCH_SCOPE_LABEL_CHAPTER + (currentChapter ? ': ' + currentChapter : ''))); |
| dataItems.push([2]); |
| // menuItems.push(createElement(booksDropDownUl, 'li', searchScope.l == 3 ? 'x': 0, SEARCH_SCOPE_LABEL_TOPIC)); |
| // dataItems.push([3]); |
| remoteRequest(BASE_URL + 'advanced/workingSetManager.jsp?t=' + Date.now(), function(menuItems, dataItems) { |
| return function(responseText) { |
| var delimiter = 'l '; |
| var scopeIndex = 0; |
| SEARCH_SCOPE_ALL_PATTERN.lastIndex = 0; |
| for (var match; (match = SEARCH_SCOPE_ALL_PATTERN.exec(responseText)) != null;) { |
| var label = decodeHtml(match[1]); |
| if (label.substring(0, 1) == '\u200B') continue; |
| var className = delimiter + (searchScope.l == 4 && searchScope.s == label ? 'x' : ''); |
| menuItems.push(createElement(booksDropDownUl, 'li', className, label)); |
| delimiter = ''; |
| dataItems.push([4, label, scopeIndex]); |
| scopeIndex++; |
| } |
| menuItems.push(createElement(booksDropDownUl, 'li', 'l y', 'Scopes...')); |
| dataItems.push([5]); |
| toMenu(booksButton, menuItems, dataItems, setSearchScope); |
| } |
| }(menuItems, dataItems)); |
| } |
| booksDropDown.s(); |
| var scopeOverlay = createOverlay(4); |
| addEvent(scopeOverlay, 'click', function() { booksDropDown.s(); scopeOverlay.o(); }); |
| addEvent(booksButton, 'mousedown', function(e) { |
| var isOpen = booksDropDown.style.display == 'block'; |
| try { |
| booksButton.focus(); |
| } catch(e) {} |
| booksDropDown.s(!isOpen); |
| if (isOpen) { |
| scopeOverlay.o(); |
| } else { |
| scopeOverlay.a(); |
| } |
| preventDefault(e); |
| stopPropagation(e); |
| }); |
| addEvent(booksButton, 'click', function(e) {stopPropagation(e)}); |
| addEvent(booksButton, 'focus', function() { |
| booksDropDown.hasFocus = true; |
| booksDropDown.s(1); |
| scopeOverlay.a(); |
| }); |
| // addEvent(booksButton, 'blur', function() { |
| // booksDropDown.hasFocus = false; |
| // setTimeout(function() {if (!booksDropDown.hasFocus) booksDropDown.style.display = 'none'}, 200); |
| // }); |
| if (!embeddedMode && BOOK_SCOPE_BY_DEFAULT && searchScope.l == 0 && getCookie(BOOK_SCOPE_COOKIE) != 'init') { |
| setCookie(BOOK_SCOPE_COOKIE, 'init'); |
| setTimeout(function(){ if(setSearchScope) setSearchScope([1]); }, 420); |
| } else { |
| updateScopeButtonLabel(); |
| } |
| |
| setSearchScope = function(scopeData) { |
| booksDropDown.s(); |
| scopeOverlay.o(); |
| if (scopeData[0] == 5) { |
| scopesPage.s(1); |
| return; |
| } |
| if (searchScope.l != scopeData[0]) { |
| var scopeToRemove; |
| if (searchScope.l == 1 || searchScope.l == 2 || searchScope.l == 4) { |
| scopeToRemove = '%E2%80%8B' + (searchScope.l > 1 ? '%E2%80%8B' : ''); |
| for (var i = 0; searchScope.l == 4 && i <= searchScope.t; i++) { |
| scopeToRemove += '%E2%80%8B'; |
| } |
| } |
| var scopeToAdd; |
| if (scopeData[0] == 1 || scopeData[0] == 2 || scopeData[0] == 4) { |
| scopeToAdd = '%E2%80%8B' + (scopeData[0] > 1 ? '%E2%80%8B' : ''); |
| for (var i = 0; scopeData[0] == 4 && i <= scopeData[2]; i++) { |
| scopeToAdd += '%E2%80%8B'; |
| } |
| } |
| if (scopeToRemove || scopeToAdd) { |
| remoteRequest( BASE_URL |
| + 'workingSetState.jsp?operation=' |
| + (scopeToRemove && scopeToAdd ? 'edit' : (scopeToRemove ? 'remove' : 'add')) |
| + (scopeToRemove && scopeToAdd ? '&oldName=' + scopeToRemove : '') |
| + '&workingSet=' |
| + (!scopeToAdd ? scopeToRemove : scopeToAdd) |
| + '&t=' + Date.now()); |
| } |
| } |
| searchScope.l = scopeData[0]; |
| searchScope.s = searchScope.l == 4 ? scopeData[1] : 0; |
| searchScope.t = searchScope.l == 4 ? scopeData[2] : 0; |
| updateScopeButtonLabel(); |
| } |
| updateScopeByToc = function(li) { |
| currentTocLi = li; |
| updateScopeButtonLabel(); |
| } |
| function updateScopeButtonLabel() { |
| setInnerHtml(booksButtonText, ''); |
| if (searchScope.l == 0 || (searchScope.l < 3 && !currentTocLi)) return; |
| var newButtonlabel; |
| for (var tocLi = currentTocLi; searchScope.l < 3 && tocLi && tocLi.n; tocLi = tocLi.p) { |
| if (!tocLi.n.path || (searchScope.l == 2 && !tocLi.n.l)) { |
| newButtonlabel = tocLi.n.t; |
| break; |
| } |
| } |
| if (searchScope.l == 4) { |
| newButtonlabel = searchScope.s; |
| } |
| if (newButtonlabel) { |
| booksButtonText.appendChild(document.createTextNode(BOOK_NAME_SHORTENER(newButtonlabel))); |
| } |
| } |
| |
| // search field |
| var wrap = createElement(searchFieldArea, 0, 'q2'); |
| wrap.style.position = 'relative'; |
| var searchField = createElement(wrap, 'input'); |
| searchField.id = 'q'; |
| searchField.type = 'text'; |
| searchField.alt = SEARCH_FIELD_DESCRIPTION; |
| searchField.title = SEARCH_FIELD_DESCRIPTION; |
| searchField.autocomplete = 'off'; |
| searchField.placeholder = SEARCH_FIELD_PLACEHOLDER; |
| addEvent(searchField, 'input', search); // for IE 8 do also on 'propertychange' |
| addEvent(searchField, 'focus', search); |
| |
| var searchButton = createElement(searchFieldArea, 'button', 'b'); |
| setInnerHtml(searchButton, SEARCH_ICON); |
| addEvent(searchFieldArea, 'submit', function(e) {preventDefault(e); search(e, 1);}); |
| |
| // hint |
| var hintField = createElement(wrap, 'input', 'qh'); |
| if (searchField.nextSibling) { |
| searchField.parentNode.insertBefore(hintField, searchField.nextSibling); |
| } |
| searchField.style.position = 'relative'; |
| hintField.style.position = 'absolute'; |
| hintField.style.left = 0; |
| hintField.style.top = 0; |
| hintField.style.height = '100%'; |
| hintField.style.width = '100%'; |
| hintField.style.background = 'transparent'; |
| hintField.style.borderColor = 'transparent'; |
| hintField.setAttribute('disabled', 'disabled'); |
| wrap.appendChild(searchField); |
| searchField.style.background = 'url("data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw%3D%3D") repeat'; |
| |
| var searchFieldAreaElements = [booksButton, searchField, searchButton]; |
| for (var i = 0; i < searchFieldAreaElements.length; i++) { |
| addEvent(searchFieldAreaElements[i], 'focus', function() { |
| searchFieldAreaHasFocus = 1; |
| updateSearchFieldAreaClass(); |
| }); |
| addEvent(searchFieldAreaElements[i], 'blur', function() { |
| searchFieldAreaHasFocus = 0; |
| updateSearchFieldAreaClass(); |
| }); |
| } |
| |
| // proposals drop-down |
| proposals = createElement(searchFieldArea, 0, 'p'); |
| addEvent(proposals, 'click', function(e) {stopPropagation(e)}); |
| function showProposals() { |
| proposals.style.display = 'block'; |
| overlay.a(); |
| updateSearchFieldAreaClass(); |
| } |
| function hideProposals() { |
| proposals.style.display = 'none'; |
| overlay.o(); |
| updateSearchFieldAreaClass(); |
| } |
| hideProposals(); |
| |
| // focus search field |
| searchField.focus(); |
| |
| function search(e, fullSearch) { |
| var noPendingQueries = !currentSearch[getSearchTypeId(fullSearch)]; |
| |
| // get (trimmed) search word, query, URL and remember query to detect stale responses |
| var searchWord = searchField.value.replace(/(^\s+|\s+$)/ig, ''); |
| |
| // TODO if Eclipse bug 351077 (https://bugs.eclipse.org/351077), remove following line |
| if (!fullSearch || searchWord.indexOf('*') >= 0 || searchWord.indexOf('?') >= 0) { |
| searchWord = searchWord.replace(/\-([^\-\s]*$)/ig, ' $1'); |
| } |
| |
| var tocScope = currentTocLi ? currentTocLi.n : currentTocLi; |
| for (var tocLi = currentTocLi; searchScope.l < 3 && tocLi && tocLi.n; tocLi = tocLi.p) { |
| if (!tocLi.n.path || (searchScope.l == 2 && !tocLi.n.l)) { |
| tocScope = tocLi.n; |
| break; |
| } |
| } |
| var query = searchWord.length |
| ? ( encodeURIComponent(searchWord.toLowerCase()) |
| + ((searchScope.l == 1 || searchScope.l == 2) && tocScope && tocScope.toc ? '&toc=' + encodeURIComponent(tocScope.toc) : '') |
| + (searchScope.l == 2 && tocScope && tocScope.path ? '&path=' + tocScope.path : '') |
| + (searchScope.l == 4 && searchScope.s ? '&scope=' + encodeURIComponent(searchScope.s) : '')) |
| : ''; |
| var url = SEARCH_BASE_URL |
| + query.replace(/(\&|$)/, (fullSearch ? '' : '*') + '$1') |
| + '&maxHits=' |
| + (fullSearch ? SEARCH_HITS_MAX : SEARCH_AS_YOU_TYPE_PROPOSAL_MAX) |
| + (query.indexOf('&toc=') < 0 ? '' : '&quickSearch=true&quickSearchType=QuickSearchToc'); |
| currentSearch[getSearchTypeId(fullSearch)] = query; |
| if (fullSearch) { |
| currentSearch['t'] = 0; |
| hideProposals(); |
| if (bookmarksPage) bookmarksPage.s(); |
| if (scopesPage) scopesPage.s(); |
| updateDeepLink(query); |
| } else { |
| |
| // hide hint |
| hintField.value = ''; |
| |
| } |
| |
| // empty search? |
| searchFieldAreaContainsQuery = searchWord.length; |
| updateSearchFieldAreaClass(); |
| if (!searchWord.length) { |
| if (!fullSearch) { |
| hideProposals(); |
| } |
| return; |
| } |
| |
| // init UI |
| if (fullSearch) { |
| if (searchPage.o && query == searchPage.q) return; |
| searchPage.s(1); |
| if (query == searchPage.q) { |
| window.frames.c.location = url; |
| return; |
| } |
| setInnerHtml(searchPage, 'Searching...'); |
| searchPage.scrollTop = 0; |
| } else if (query == proposals.q) { |
| preventDefault(e); |
| showProposals(); |
| return; |
| } |
| |
| // cached? |
| var cache = SEARCH_CACHE[getSearchTypeId(fullSearch)]; |
| for (var i = 0; i < cache.length; i++) { |
| var r = cache[i]; |
| if (query == r.q) { |
| if (fullSearch) { |
| window.frames.c.location = url; |
| } |
| renderResults(fullSearch, r.r, r.b, query, searchWord, r.s); |
| return; |
| } |
| } |
| |
| // submit query to server |
| if (fullSearch) { |
| window.frames.c.location = url; |
| return; |
| } |
| var currentSearchScope = { |
| /* level */ l: searchScope.l, |
| /* (custom) scope name */ s: searchScope.s, |
| /* path */ p: 0 |
| }; |
| if (searchScope.l > 0 && searchScope.l < 3 && currentTocLi) { |
| currentSearchScope.p = [currentTocLi.n]; |
| for (var parentLi = currentTocLi.p; searchScope.l > 1 && parentLi && parentLi.n; parentLi = parentLi.p) { |
| currentSearchScope.p.unshift(parentLi.n); |
| } |
| } |
| var callbackFn = callbackFor(fullSearch, query, searchWord, currentSearchScope); |
| if (noPendingQueries) { |
| remoteRequest(url, callbackFn, getSearchTypeId(fullSearch)); |
| } else { |
| setTimeout(function() { |
| |
| // remote request if and only if not staled/outdated |
| if (query == currentSearch[getSearchTypeId(fullSearch)]) |
| remoteRequest(url, callbackFn, getSearchTypeId(fullSearch)); |
| |
| }, SEARCH_DELAY_IN_MILLISECOND); |
| } |
| } |
| |
| renderFullSearch = function(queryPart, data) { |
| var query = queryPart.substring(0, queryPart.indexOf('&maxHits=')); |
| updateDeepLink(query); |
| if (query == searchPage.q) return; |
| var valuePairs = queryPart.split('&'); |
| var searchWord; |
| var toc; |
| var path; |
| var scope; |
| for (var i = 0; i < valuePairs.length; i++) { |
| if (!searchWord && valuePairs[i].indexOf('=') < 0) { |
| searchWord = decodeURIComponent(valuePairs[i]); |
| } else if (valuePairs[i].substring(0, 4) == 'toc=') { |
| toc = decodeURIComponent(valuePairs[i].substring(4)); |
| } else if (valuePairs[i].substring(0, 5) == 'path=') { |
| path = decodeURIComponent(valuePairs[i].substring(5)); |
| } else if (valuePairs[i].substring(0, 6) == 'scope=') { |
| scope = decodeURIComponent(valuePairs[i].substring(6)); |
| } |
| } |
| var currentSearchScope = { |
| /* level */ l: scope ? 4 : (toc ? (path ? 2 : 1) : 0), |
| /* (custom) scope name */ s: scope, |
| /* path */ p: 0 |
| }; |
| var scopeFound = !toc; |
| if (toc && currentTocLi && currentTocLi.n) { |
| var nodes = [currentTocLi.n]; |
| for (var parentLi = currentTocLi.p; parentLi && parentLi.n; parentLi = parentLi.p) { |
| if (path) { |
| nodes.unshift(parentLi.n); |
| } else { |
| nodes = [parentLi.n]; |
| } |
| } |
| if (toc == nodes[0].toc && (!path || path == nodes[nodes.length - 1].path)) { |
| currentSearchScope.p = nodes; |
| scopeFound = 1; |
| } |
| } |
| if (!scopeFound) { |
| remoteRequest( BASE_URL + 'advanced/tocfragment?toc=' + encodeURIComponent(toc) |
| + (path ? '&path=' + path : ''), (function(toc, path, currentSearchScope, searchWord, query, data) { |
| return function(responseText) { |
| var nodePath = []; |
| var books = parseXml(responseText).documentElement.childNodes; |
| var book; |
| for (var i = 0; i < books.length; i++) { |
| book = books[i]; |
| if (book.tagName == 'node' && toc == book.getAttribute('id')) { |
| nodePath.push({t: book.getAttribute('title'), toc: toc}); |
| break; |
| } |
| } |
| var nodes = book.childNodes; |
| tocLevelLoop: while (path) { |
| for (var i = 0; i < nodes.length; i++) { |
| n = nodes[i]; |
| if (n.tagName != 'node') continue; |
| var id = n.getAttribute('id'); |
| if (path == id) { |
| nodePath.push({t: n.getAttribute('title'), toc: toc, path: id}); |
| break tocLevelLoop; |
| }; |
| if ( id |
| && path.length > id.length |
| && path.substring(0, id.length + 1) == id + '_') { |
| nodes = n.childNodes; |
| nodePath.push({t: n.getAttribute('title'), toc: toc, path: id}); |
| continue tocLevelLoop; |
| } |
| } |
| break; |
| } |
| currentSearchScope.p = nodePath; |
| (callbackFor(1, query, searchWord, currentSearchScope))(data); |
| };})(toc, path, currentSearchScope, searchWord, query, data)); |
| return; |
| } |
| (callbackFor(1, query, searchWord, currentSearchScope))(data); |
| } |
| |
| function callbackFor(fullSearch, query, searchWord, searchScope) { |
| return function(data) { |
| |
| // indexing in progress? |
| var match = SEARCH_RESULTS_INDEXING_PATTERN.exec(data); |
| if (match != null) { |
| if (fullSearch) { |
| setInnerHtml(searchPage, 'Indexing... ' + match[1] + '%'); |
| } |
| return; |
| } |
| |
| // parse HTML for results |
| var element = createElement(); |
| var hasBreadcrumbs = 0; |
| var results = []; |
| |
| SEARCH_RESULTS_PATTERN.lastIndex = 0; |
| for (var match; (match = SEARCH_RESULTS_PATTERN.exec(data)) != null;) { |
| var items = []; |
| for (var i = 2; i < 8; i++) { |
| element.innerHTML = match[i]; |
| items.push((element.textContent ? element.textContent : element.innerText).replace(/^\s+|\s+$/g,'').replace(/\s+/g,' ')); |
| } |
| var breadcrumb = []; |
| if (match[6]) { |
| SEARCH_RESULTS_BREADCRUMB_SNIPPET_PATTERN.lastIndex = 0; |
| for (var breadcrumbMatch; (breadcrumbMatch = SEARCH_RESULTS_BREADCRUMB_SNIPPET_PATTERN.exec(match[6])) != null;) { |
| for (var i = 1; i < 3; i++) { |
| element.innerHTML = breadcrumbMatch[i]; |
| breadcrumb.push((element.textContent ? element.textContent : element.innerText).replace(/^\s+|\s+$/g,'').replace(/\s+/g,' ')); |
| } |
| } |
| hasBreadcrumbs = 1; |
| } |
| var hrefFollowedByTitle = 'href' == match[1]; |
| results.push({ |
| /* title */ t: items[3], |
| /* description */ d: items[5], |
| /* href */ h: items[hrefFollowedByTitle ? 0 : 2].substring(8), |
| /* breadcrumb */ b: match[6] ? breadcrumb : [0, items[hrefFollowedByTitle ? 2 : 0]] |
| }); |
| } |
| |
| // cache parsed results |
| var queryResult = { |
| /* results */ r: results, |
| /* has breadcrumbs */ b: hasBreadcrumbs, |
| /* query */ q: query, |
| /* search scope */ s: searchScope |
| } |
| var cache = SEARCH_CACHE[getSearchTypeId(fullSearch)]; |
| var cacheIndexId = getSearchTypeId(fullSearch) + 'i'; |
| var cacheSize = fullSearch ? SEARCH_FULL_SEARCH_CACHE_SIZE : SEARCH_AS_YOU_TYPE_CACHE_SIZE; |
| SEARCH_CACHE[cacheIndexId] = (SEARCH_CACHE[cacheIndexId] + 1) % cacheSize; |
| if (cache.length < cacheSize) { |
| cache.push(queryResult); |
| } else { |
| cache[SEARCH_CACHE[cacheIndexId]] = queryResult; |
| } |
| |
| renderResults(fullSearch, results, hasBreadcrumbs, query, searchWord, searchScope); |
| } |
| |
| } |
| |
| function renderResults(fullSearch, results, hasBreadcrumbs, query, searchWord, searchScope) { |
| |
| // staled? |
| if (!fullSearch && query != currentSearch[getSearchTypeId(fullSearch)]) return; |
| |
| // show results |
| var items = []; |
| var data = []; |
| var filters = []; |
| var filterValues = []; |
| function applyFilters(e) { |
| var includeFilters = []; |
| var excludeFilters = []; |
| for (var i = 0; i < filters.length; i++) { |
| var f = filters[i]; |
| if (!f.checked && !f.indeterminate) excludeFilters.push(filterValues[i]); |
| if (f.checked && !f.indeterminate) includeFilters.push(filterValues[i]); |
| } |
| for (var i = 0; i < items.length; i++) { |
| items[i].style.display = arrayContainsPrefix(includeFilters, data[i]) |
| && !arrayContainsPrefix(excludeFilters, data[i]) |
| ? 'block' |
| : 'none'; |
| } |
| stopPropagation(e); |
| } |
| |
| var searchScopeLabel = searchScope.l > 3 ? searchScope.s : ''; |
| if (searchScope.p) { |
| for (var i = 0; i < searchScope.p.length; i++) { |
| if (i > 0) { |
| searchScopeLabel += ' > '; |
| } |
| searchScopeLabel += searchScope.p[i].t; |
| } |
| } |
| var parentElement = fullSearch ? searchPage : proposals; |
| setInnerHtml(parentElement, ''); |
| parentElement.q = query; |
| parentElement.l = 'Search' + (searchScope.l > 0 ? ' (' + searchScopeLabel+ ')': '') + ': ' + searchWord; |
| if (fullSearch) { |
| document.title = searchPage.l + ' - ' + title; |
| |
| // no results? |
| if (!results.length) { |
| var noResults = createElement(searchPage, 0, 'r0', 'No results found for '); |
| createElement(noResults, 'strong', 0, searchWord); |
| return; |
| } |
| |
| // filter tree |
| var filterTree = asTree(results, [], 9, true); |
| // TODO correction of tree for deeper scopes (below) might be done in "asTree" or "asTree" might be better simplified |
| if (searchScope.p && filterTree.length == 1 && filterTree[0].isNode) { |
| var afterCutOff = searchScope.p.length * 2 - filterTree[0].name.length; |
| if (afterCutOff < 0) { |
| filterTree[0].name = filterTree[0].name.slice(searchScope.p.length * 2); |
| } else if (afterCutOff >= 0) { |
| filterTree = filterTree[0].children; |
| if (afterCutOff > 0 && filterTree.length > 0 && filterTree[0].isNode) { |
| if (filterTree[0].name.length <= afterCutOff) { |
| filterTree = filterTree[0].children; |
| } else { |
| filterTree[0].name = filterTree[0].name.slice(afterCutOff); |
| } |
| } |
| } |
| } |
| createTree(searchPage, |
| |
| // content provider |
| function(node, processChildrenFn) { |
| if (!node) { |
| processChildrenFn([{ n/*ode*/: {children: filterTree}, l/*eaf*/: 0 }], 1); |
| return; |
| } |
| var children = []; |
| for (var i = 0; i < (node.isNode ? node.children.length : filterTree.length); i++) { |
| var childNode = node ? node.children[i] : filterTree[i]; |
| if (childNode.isNode) { |
| var isLeaf = 1; |
| for (var j = 0; j < childNode.children.length; j++) { |
| if (childNode.children[j].isNode) { |
| isLeaf = 0; |
| break; |
| } |
| } |
| children.push({ n/*ode*/: childNode, l/*eaf*/: isLeaf }); |
| childNode.p/*arent*/ = node; |
| } |
| } |
| processChildrenFn(children); |
| }, |
| |
| // label provider |
| function(li, node) { |
| var isRoot = !node.isNode; |
| |
| // checkbox |
| var checkboxWithLabel = createElement(li); |
| var checkbox = createElement(checkboxWithLabel, 'input'); |
| checkbox.type = 'checkbox'; |
| checkbox.checked = node.p ? node.p.x.checked : true; |
| node.x = checkbox; |
| if (node.p) { |
| checkbox.parentCheckbox = node.p.x; |
| } |
| checkbox.numberOfResults = isRoot ? results.length : node.count; |
| filters.push(checkbox); |
| filterValues.push(isRoot ? '' : toValue(node.l.concat(node.name))); |
| |
| // label |
| var labelText = ''; |
| if (isRoot) { |
| checkbox.style.display = 'none'; |
| labelText = 'Results ' + (searchScope && searchScope.l > 0 ? 'in ' : ''); |
| } else { |
| addEvent(checkbox, 'click', (function(liCheck, li) { |
| return function() { |
| selectSubtree(li, liCheck.checked); |
| updateParentsChecks(liCheck); |
| applyFilters(); |
| }; |
| })(checkbox, li)); |
| for (var i = 0; i < node.name.length; i+=2) { |
| labelText += (i == 0 ? '' : ' > ') + node.name[i+1]; |
| } |
| } |
| var label = createElement(checkboxWithLabel, 'span', node.isNode ? 0 : 't', labelText + ' '); |
| if (isRoot && searchScope && searchScope.l > 0 ) { |
| createElement(label, 'span', 'tl', searchScopeLabel + ' '); |
| } |
| createElement(label, 'span', 'count', checkbox.numberOfResults); |
| addEvent(label, 'click', (function(checkbox, li) { |
| return function() { |
| var root; |
| for (root = checkbox; root.parentCheckbox; root = root.parentCheckbox); |
| for (var i = 0; i < 5; i++) { |
| root = getParentElement(root); |
| if (root.tagName == 'UL') break; |
| } |
| selectSubtree(root, false); |
| selectSubtree(li, true); |
| updateParentsChecks(checkbox); |
| applyFilters(); |
| }; |
| })(checkbox, li)); |
| |
| return checkboxWithLabel; |
| }, |
| 0); |
| |
| } |
| var resultList = createElement(parentElement, 'ol', 'j'); |
| if (!fullSearch) { |
| |
| // no results? |
| if (!results.length) return; |
| |
| // hint |
| var wordBeginRegEx = queryToRegEx(query); |
| var newHints = {}; |
| for (var i = 0; i < results.length && searchWord.length < 36; i++) { |
| var match = wordBeginRegEx.exec(results[i].t/*title*/); |
| if (match) { |
| var pHint = match[0].toLowerCase(); |
| newHints[pHint] = (newHints[pHint] ? newHints[pHint] : 0) |
| + (1 + (results.length - i) / results.length) / results.length; |
| } |
| match = wordBeginRegEx.exec(results[i].d/*description*/); |
| if (match) { |
| var pHint = match[0].toLowerCase(); |
| newHints[pHint] = (newHints[pHint] ? newHints[pHint] : 0) |
| + (0.7 + (results.length - i) / results.length) / results.length; |
| } |
| } |
| var allHints = []; |
| for (var i in newHints) { |
| if (newHints[i] < 1.8 / results.length) continue; |
| allHints.push(newHints[i].toFixed(7) + i); |
| } |
| allHints.sort().reverse(); |
| hintField.value = allHints.length > 0 |
| ? searchField.value + wordBeginRegEx.exec(allHints[0].substring(9))[1] |
| : ''; |
| |
| // query proposals |
| for (var i = 0; i < allHints.length && i < 3; i++) { |
| var hintText = allHints[i].substring(9); |
| var li = createElement(resultList, 'li'); |
| var button = createElement(li, 'button'); |
| var spacerElementStyle = createElement(button, 'span').style; |
| spacerElementStyle.display = 'inline-block'; |
| spacerElementStyle.width = booksButton.offsetWidth + 'px'; |
| createElement(button, 'span', null, hintText.substring(0, searchWord.length)); |
| createElement(button, 'strong', null, hintText.substring(searchWord.length)); |
| items.push(li); |
| data.push([hintText]); |
| } |
| |
| } |
| |
| function toValue(path) { |
| var result = ''; |
| for (var i = 0; i < path.length; i++) result += (i > 0 ? '\n' : '') + path[i]; |
| return result; |
| } |
| |
| // list results |
| for (var i = 0; i < results.length; i++) { |
| var node = results[i]; |
| var li = createElement(resultList, 'li'); |
| var a = createElement(li, 'a'); |
| a.href = BASE_URL + 'topic' + node.h/*href*/; |
| a.target = 'c'; |
| var titleAndLocation = createElement(a, 0, 'm'); |
| |
| // title |
| addHighlightedText(createElement(titleAndLocation, 0, 'v'), node.t/*title*/, searchWord); |
| |
| // show book title only for no book/chapter scope |
| if (!fullSearch && !searchScope.p) { |
| createElement(titleAndLocation, 0, 'w', node.b/*breadcrumb*/[1]); |
| } |
| |
| // breadcrumb |
| if (fullSearch && hasBreadcrumbs && node.b/*breadcrumb*/) { |
| var location = createElement(titleAndLocation, 0, 'w'); |
| for (var j = searchScope && searchScope.p ? searchScope.p.length * 2 : 0; j < node.b/*breadcrumb*/.length; j+=2) { |
| createElement(location, 'span', 0, node.b/*breadcrumb*/[j+1]); |
| if (j < node.b/*breadcrumb*/.length-2) { |
| createElement(location, 'span', 0, ' > '); |
| } |
| } |
| } |
| |
| // description |
| addHighlightedText(createElement(a, 0, 'n'), node.d/*description*/, searchWord); |
| |
| // UI element and corresponding data |
| items.push(li); |
| if (fullSearch) { |
| var resultofStart = node.h/*href*/.indexOf('?resultof='); |
| var hrefNormed = '../topic' + (resultofStart < 0 ? node.h/*href*/ : node.h/*href*/.substring(0, resultofStart)); |
| data.push(toValue(node.b/*breadcrumb*/.slice().concat(hrefNormed).concat(node.t/*title*/))); |
| } else { |
| data.push([node.t/*title*/, node.h/*href*/]); |
| } |
| |
| } |
| |
| // add key support (and show proposals) |
| if (fullSearch) { |
| // toMenu(searchField, items, results, function(d) { |
| // getElementById('c').src = BASE_URL + 'topic' + d.h/*href*/; |
| // }, |
| // 0, |
| // 0, |
| // function(item, data, viaMouse) { |
| // if (!viaMouse) { |
| // scrollIntoViewIfNeeded(searchPage, item); |
| // } |
| // }, |
| // 1); |
| } else { |
| |
| // key support |
| toMenu(searchField, items, data, function(d) { |
| |
| // apply hint |
| if (d.length < 2) { |
| hintField.value = ''; |
| searchField.value = d; |
| search(); |
| return; |
| } |
| |
| // show search result |
| var searchWord = d[0]; |
| var toc; |
| var tocStart = searchWord.indexOf('&toc='); |
| if (tocStart > 0) { |
| toc = decodeURIComponent(searchWord.substring(tocStart + 5)); |
| searchWord = searchWord.substring(0, tocStart); |
| } |
| if (searchSearchWord(searchWord + '*', toc, d[1], false, true)) return; |
| getElementById('c').src = BASE_URL + 'topic' + d[1]; |
| hideProposals(); |
| |
| }, |
| function(d, key) { |
| |
| // empty search field? |
| if (!searchField.value) return false; |
| |
| // ignore RIGHT (key: 39) if cursor not at the end |
| if ( key == 39 |
| && searchField |
| && searchField.selectionStart |
| && searchField.value |
| && searchField.value.length != searchField.selectionStart) |
| return false; |
| |
| if (d && d.length > 0 && d[0].length < 2) { |
| searchField.value = d[0][0]; |
| search(); |
| return true; |
| } |
| return false; |
| }, |
| hideProposals, |
| function(a, b) { |
| if (b.length < 2 || a.armed) return; |
| a.armed = true; |
| var iFrame = createElement(a, 'iframe', 'f'); |
| iFrame.frameBorder = 0; |
| |
| // TODO handle absolute paths |
| iFrame.src = BASE_URL + 'topic' + b[1]; |
| }); |
| |
| // show proposals |
| showProposals(); |
| |
| } |
| |
| // done (no pending queries) |
| if (query == currentSearch[getSearchTypeId(fullSearch)]) { |
| currentSearch[getSearchTypeId(fullSearch)] = 0; |
| } |
| |
| } |
| |
| function getSearchTypeId(fullSearch) { |
| return fullSearch ? 'f' : 't'; |
| } |
| |
| function asTree(results, path, depth) { |
| if (depth < 1) return results; |
| var tree = []; |
| var grouped = {}; |
| for (var i = 0; i < results.length; i++) { |
| var r = results[i]; |
| r.p = i; |
| r.q = r.b/*breadcrumb*/.slice(); |
| var resultofStart = r.h/*href*/.indexOf('?resultof='); |
| r.q.push('../topic' + (resultofStart < 0 ? r.h/*href*/ : r.h/*href*/.substring(0, resultofStart))); |
| r.q.push(r.t/*title*/); |
| |
| // child? |
| if (!r.b/*breadcrumb*/ || r.b/*breadcrumb*/.length <= path.length) { |
| tree.push(r); |
| continue; |
| } |
| |
| // not child -> contained in a subtree |
| var key = r.b/*breadcrumb*/[path.length] + '\n' + r.b/*breadcrumb*/[path.length+1]; |
| if (!grouped[key]) { |
| var node = { |
| isNode: true, |
| name: [r.b/*breadcrumb*/[path.length], r.b/*breadcrumb*/[path.length+1]], |
| l/*ocation*/: path.slice(), |
| children: [r] |
| }; |
| grouped[key] = node; |
| tree.push(node); |
| } else { |
| grouped[key].children.push(r); |
| } |
| |
| } |
| |
| // calculate count and set the root (if it exists) |
| for (var i = 0; i < tree.length; i++) { |
| var r = tree[i]; |
| if (r.isNode) { |
| r.count = r.children.length + (r.root ? 1 : 0); |
| continue; |
| } |
| var rootOfGroup = grouped[r.q[r.q.length-2] + '\n' + r.t/*title*/]; |
| if (rootOfGroup) { |
| rootOfGroup.children.push(r); |
| rootOfGroup.count++; |
| tree.splice(i,1); |
| i--; |
| } |
| } |
| |
| // compact and recursion |
| for (var i = 0; i < tree.length; i++) { |
| var r = tree[i]; |
| if (!r.isNode) continue; |
| compact(path, r); |
| r.children = asTree(r.children, r.children[0].q.slice(0, path.length + r.name.length), depth - 1); |
| } |
| |
| return tree; |
| } |
| function compact(path, r) { |
| for (var i = path.length+2; r.children.length > 0 && !r.root; i+=2) { |
| if (r.children.length == 1 && r.children[0].b/*breadcrumb*/.length == i) return; |
| for (var j = 0; j < r.children.length; j++) { |
| var p0 = r.children[0].q; |
| var p = r.children[j].q; |
| if ( p.length < i+1 |
| || p[i] != p0[i] |
| || p[i+1] != p0[i+1]) return; |
| } |
| var p0 = r.children[0].q; |
| r.name.push(p0[i]); |
| r.name.push(p0[i+1]); |
| } |
| } |
| |
| function queryToRegEx(query) { |
| query = query.indexOf('&') < 0 |
| ? query |
| : query.substr(0, query.indexOf('&')); |
| query = decodeURIComponent(query.replace(/\+/g, '%20')); |
| query = query.replace(/([\.\?\*\+\-\(\)\[\]\{\}\\])/g, '\\$1'); |
| return new RegExp("\\b(?:" + query + ")((?:\\w+|\\W+\\w+))", "i"); |
| } |
| |
| function searchSearchWord(searchWord, toc, href, path, isSearchWordDecoded) { |
| try { |
| |
| // No SearchFrame or no NavFrame? -> exception handling |
| var root = parent.parent.parent; |
| var searchFrame = root.HelpToolbarFrame.SearchFrame; |
| var navFrame = root.HelpFrame.NavFrame; |
| |
| var scopeElement = searchFrame.document.getElementById('scope'); |
| var searchInput = searchFrame.document.getElementById('searchWord'); |
| if ( searchInput |
| && scopeElement |
| && scopeElement.firstChild.nodeValue == 'All topics') { |
| |
| // no scope -> update top left search input field only |
| searchInput.value = searchWord; |
| |
| } else { |
| |
| // disable scope and update top left search input field |
| searchFrame.location.replace( BASE_URL |
| + 'scopeState.jsp?workingSet=&searchWord=' |
| + encodeURIComponent(searchWord)); |
| |
| } |
| var newNavUrl = BASE_URL |
| + 'advanced/nav.jsp?e=h&tab=search&searchWord=' // 'e=h' for tracking (to distinguish normal queries from queries done with this script) |
| + (isSearchWordDecoded ? searchWord : encodeURIComponent(searchWord)); |
| if (toc) newNavUrl += '&quickSearch=true&quickSearchType=QuickSearchToc&toc=' + encodeURIComponent(toc); |
| if (path) newNavUrl += '&path=' + path; |
| navFrame.location.replace(newNavUrl); |
| |
| // topic (use 'setTimeout()' otherwise in Internet Explorer |
| // 'Go Back' does not work sometimes) |
| if (href) { |
| setTimeout(function(){window.location.href = BASE_URL + 'topic' + href}, 9); |
| } |
| |
| return true; |
| } catch(e) { |
| return false; |
| } |
| } |
| |
| // filter tree functions |
| function selectSubtree(element, checkStatus) { |
| for (var i = 0; i < element.children.length; i++) { |
| var n = element.children[i]; |
| if ('UL' == n.tagName || 'LI' == n.tagName || 'DIV' == n.tagName) { |
| selectSubtree(n, checkStatus); |
| } else if ('INPUT' == n.tagName) { |
| n.indeterminate = false; |
| n.checked = checkStatus; |
| n.notAllChecked = false; |
| } |
| } |
| } |
| function getChildrenChecks(checkbox) { |
| if (!checkbox || !checkbox.parentElement || !checkbox.parentElement.parentElement || 'LI' != checkbox.parentElement.parentElement.tagName) return []; |
| var li = checkbox.parentElement.parentElement; |
| var children = []; |
| for (var i = 0; i < li.children.length; i++) { |
| var n1 = li.children[i]; |
| if ('UL' != n1.tagName) continue; |
| for (var j = 0; j < n1.children.length; j++) { |
| var n2 = n1.children[j]; |
| if ('LI' != n2.tagName) continue; |
| for (var k = 0; k < n2.children.length; k++) { |
| var n3 = n2.children[k]; |
| for (var l = 0; l < n3.children.length; l++) { |
| var n4 = n3.children[l]; |
| if ('INPUT' == n4.tagName) children.push(n4); |
| } |
| } |
| } |
| } |
| return children; |
| } |
| function updateParentsChecks(checkbox) { |
| for (var parentCheckbox = checkbox.parentCheckbox; parentCheckbox; parentCheckbox = parentCheckbox.parentCheckbox) { |
| var checkedNumberOfResults = 0; |
| var uncheckedNumberOfResults = 0; |
| var uncheckedAll = true; |
| var notAllChecked = false; |
| var totalNumberOfResults = 0; |
| var indeterminateChildren = 0; |
| var children = getChildrenChecks(parentCheckbox); |
| for (var i = 0; i < children.length; i++) { |
| var n = children[i]; |
| if (n.notAllChecked) notAllChecked = true; |
| if (n.indeterminate) { |
| indeterminateChildren++; |
| uncheckedAll = false; |
| notAllChecked = true; |
| } else if (n.checked) { |
| checkedNumberOfResults += n.numberOfResults; |
| totalNumberOfResults += n.numberOfResults; |
| uncheckedAll = false; |
| } else { |
| uncheckedNumberOfResults += n.numberOfResults; |
| totalNumberOfResults += n.numberOfResults; |
| notAllChecked = true; |
| } |
| } |
| if (checkedNumberOfResults == parentCheckbox.numberOfResults && !notAllChecked) { |
| parentCheckbox.indeterminate = false; |
| parentCheckbox.checked = true; |
| parentCheckbox.notAllChecked = false; |
| } else if ( uncheckedNumberOfResults == parentCheckbox.numberOfResults |
| || (parentCheckbox.indeterminate && uncheckedAll)) { |
| parentCheckbox.indeterminate = false; |
| parentCheckbox.checked = false; |
| } else if ( totalNumberOfResults == parentCheckbox.numberOfResults |
| || ( !parentCheckbox.indeterminate |
| && !parentCheckbox.checked |
| && (indeterminateChildren || checkedNumberOfResults || notAllChecked))){ |
| parentCheckbox.indeterminate = true; |
| } else { |
| parentCheckbox.notAllChecked = notAllChecked; |
| } |
| } |
| } |
| |
| function toMenu(master, items, data, chooseFn, applyFn, cancelFn, armFn) { |
| //var isNotInputField = master.nodeName != 'INPUT'; |
| var cursorIndex = 0; |
| var isInit = 0; |
| master.onkeydown = function(e) { |
| e = e || window.event; |
| var key = e.keyCode || e.charCode; |
| |
| if ( cursorIndex > 0 |
| && getClassName(items[cursorIndex-1]) == items[cursorIndex-1].z) { |
| cursorIndex = 0; |
| } |
| |
| // RIGHT (key: 39) or TAB without SHIFT (key: 9) to apply |
| if (applyFn && (key == 39 || (key == 9 && !e.shiftKey))) { |
| if (applyFn(data, key)) preventDefault(e); |
| } |
| |
| // ESC to cancel |
| if (cancelFn && key == 27) { |
| cancelFn(); |
| preventDefault(e); |
| return; |
| } |
| |
| // ENTER to choose |
| if (key == 13 && cursorIndex > 0) { |
| preventDefault(e); |
| stopPropagation(e); |
| setClassName(items[cursorIndex-1], items[cursorIndex-1].z); |
| chooseFn(data[cursorIndex-1]); |
| cursorIndex = 0; |
| return; |
| } |
| |
| // select by UP and DOWN |
| if (key != 40 && key != 38) return; |
| preventDefault(e); |
| var isDown = key == 40; |
| if (cursorIndex > 0) { |
| setClassName(items[cursorIndex-1], items[cursorIndex-1].z); |
| } |
| cursorIndex = cursorIndex < 1 |
| ? (isDown ? 1 : items.length) |
| : (cursorIndex + (isDown ? 1 : -1)) % (items.length + 1); |
| if (cursorIndex > 0) { |
| var item = items[cursorIndex-1]; |
| setClassName(item, item.z + ' z'); |
| if (armFn) armFn(item, data[cursorIndex-1], 0); |
| } |
| } |
| for (var i = 0; i < items.length; i++) { |
| items[i].z = getClassName(items[i]); |
| items[i].onmousedown = function() {setTimeout(function() {if (master && !master.hasFocus) master.focus()}, 42)}; |
| items[i].onmouseup = items[i].ontouchend = function(a, b) {return function(e) {preventDefault(e); if (!a.canceled) {chooseFn(b); setClassName(a, a.z); cursorIndex = 0}}}(items[i], data[i]); |
| items[i].onmouseover = items[i].ontouchstart = function(a, b, c) {return function() {if (!isInit) return; if (cursorIndex > 0) setClassName(items[cursorIndex-1], items[cursorIndex-1].z); setClassName(a, a.z + ' z'); cursorIndex = b; a.canceled = ''; if (armFn && b > 0) armFn(a, c, 1)}}(items[i], i+1, data[i]); |
| items[i].onmouseout = function(a) {return function() {setClassName(a, a.z)}}(items[i]); |
| } |
| setTimeout(function() {isInit = 1; }, 142); |
| } |
| |
| function addHighlightedText(element, text, searchWord) { |
| var searchWordLowerCase = searchWord.toLowerCase(); |
| var textLowerCase = text.toLowerCase(); |
| var hIndex = textLowerCase.indexOf(searchWordLowerCase); |
| if (hIndex < 0) { |
| element.appendChild(document.createTextNode(text)); |
| return; |
| } |
| |
| var lastEnd = 0; |
| while (hIndex >=0) { |
| element.appendChild(document.createTextNode(text.substring(lastEnd, hIndex))); |
| lastEnd = hIndex + searchWord.length; |
| if ( hIndex == 0 |
| || text.substring(hIndex - 1, hIndex).replace(/\w/, "").length != 0) { |
| var strong = createElement(element, 'strong'); |
| strong.appendChild(document.createTextNode(text.substring(hIndex, lastEnd))); |
| } else { |
| element.appendChild(document.createTextNode(text.substring(hIndex, lastEnd))); |
| } |
| hIndex = textLowerCase.indexOf(searchWordLowerCase, lastEnd); |
| } |
| element.appendChild(document.createTextNode(text.substring(lastEnd))); |
| } |
| |
| } |
| |
| function searchFullByHash(hash) { |
| var url = SEARCH_BASE_URL + hash.substring(3) + '&maxHits=' + SEARCH_HITS_MAX |
| + (hash.indexOf('&toc=') < 0 ? '' : '&quickSearch=true&quickSearchType=QuickSearchToc'); |
| window.frames.c.location = url; |
| |
| // fill search field |
| var searchWord = getParams(hash)['#q']; |
| if (searchWord && searchWord != getElementById('q').value) { |
| getElementById('q').value = searchWord; |
| } |
| |
| // TODO set search socpe? |
| |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // Menu |
| |
| function createMenu() { |
| |
| // menu |
| var menu = createOverlay(9, 1); |
| var overlay = createOverlay(8); |
| menu.id = 'a'; |
| menuStyle = menu.style; |
| menu.a = function(e) { preventDefault(e); overlay.a(); menuStyle.width = '270px'; }; |
| menu.o = function(e) { preventDefault(e); overlay.o(); menuStyle.width = '0'; }; |
| menu.o(); |
| addEvent(overlay, 'click', menu.o); |
| function createMenuItem(label, description, fn, id, href, parent) { |
| var item = createElement(parent ? parent : menu, fn ? 'button' : 'a', 'b', label); |
| item.href = href ? (BASE_URL + href) : '#'; |
| item.target = 'c'; |
| item.title = description; |
| if (id) { |
| item.id = id; |
| } |
| addEvent(item, 'click', function(e) { |
| if (fn) { preventDefault(e); fn(e); } |
| if (href) { getElementById('c').contentDocument.location.href = BASE_URL + href; } |
| if (!parent) menu.o(); |
| }); |
| return item; |
| } |
| |
| // "x" button |
| var closeMenuButton = createElement(createElement(menu, 0, 'e'), 'a', 'b'); |
| closeMenuButton.href = '#'; |
| addEvent(closeMenuButton, 'click', menu.o); |
| closeMenuButton.alt = MENU_CLOSE_ICON_DESCRIPTION; |
| closeMenuButton.title = MENU_CLOSE_ICON_DESCRIPTION; |
| setInnerHtml(closeMenuButton, MENU_CLOSE_ICON); |
| |
| // "Highlight search terms" dummy |
| function HighlightConnector() {}; |
| HighlightConnector.prototype.setButtonState = function(/*name, state*/) { |
| // dummy for highlight() in org.eclipse.help.webapp/advanced/highlight.js |
| }; |
| window.ContentToolbarFrame = new HighlightConnector(); |
| var highlight = createMenuItem(0, 'Toggle search term highlighting', toggleHighlight, 'ah'); |
| createElement(highlight, 'span', 'hl', 'Highlight'); |
| createElement(highlight, 'span', 'hs', ' '); |
| createElement(highlight, 'span', 'ht', 'search term'); |
| toggleHighlight(0, 1); |
| |
| // "Font: - +" |
| if (MENU_FONT_SIZING) { |
| var fontSizer = createElement(menu); |
| fontSizer.id = 'af'; |
| createElement(fontSizer, 'span', 0, 'Font:'); |
| createMenuItem('\u2013', 'Decrease font size', function() { setFontSize(0); }, 'afm', 0, fontSizer); |
| createMenuItem('+', 'Increase font size', function() { setFontSize(1); }, 'afp', 0, fontSizer); |
| } |
| |
| // "Bookmarks..." |
| if (embeddedMode) { |
| createMenuItem('Bookmarks...', 'Bookmark current topic and manage existing bookmarks', function() { |
| bookmarksPage.s(1); |
| }); |
| } |
| |
| // "Search scopes..." |
| createMenuItem('Search scopes...', 'Manage search scopes', function() { |
| scopesPage.s(1); |
| }); |
| |
| // "Print topic..." |
| createMenuItem('Print topic...', 'Print topic without its subtopics', function() { |
| try { |
| getElementById('c').contentWindow.print(); |
| } catch (e) { |
| } |
| }, 'ap'); |
| |
| // "Print chapter..." |
| createMenuItem('Print chapter...', 'Print topic including subtopics', printChapter, 'app'); |
| |
| // "Help" |
| if (MENU_HELP) { |
| createMenuItem(MENU_HELP_LABEL, MENU_HELP_DESCRIPTION, 0, 'ai', MENU_HELP); |
| } |
| |
| // "About" |
| if (MENU_ABOUT) { |
| createMenuItem('About', 'Configuration details', 0, 'aa', 'about.html'); |
| } |
| |
| // show menu button |
| var menuButton = createElement(getElementById('h'), 'a', 'b'); |
| menuButton.href = '#'; |
| menuButton.alt = MENU_ICON_DESCRIPTION; |
| menuButton.title = MENU_ICON_DESCRIPTION; |
| setInnerHtml(menuButton, MENU_ICON); |
| addEvent(menuButton, 'click', menu.a); |
| |
| } |
| |
| function toggleHighlight(_event, initalize) { |
| |
| var enableHighlighting = 'false' == getCookie('highlight'); |
| if (initalize) { |
| enableHighlighting = !enableHighlighting; |
| } else { |
| setCookie('highlight', enableHighlighting ? 'true' : 'false'); |
| var contentFrameWindow = getElementById('c').contentWindow; |
| if (contentFrameWindow && contentFrameWindow.highlight && contentFrameWindow.toggleHighlight) { |
| contentFrameWindow.toggleHighlight(); |
| contentFrameWindow.highlight(); |
| } |
| } |
| setClassName(getElementById('ah'), enableHighlighting ? 'b x' : 'b'); |
| } |
| |
| function setFontSize(increase, initalize, updateContentFrameOnly) { |
| if (!MENU_FONT_SIZING) return; |
| var newFontSize; |
| var contentFrameDocument = getElementById('c').contentWindow.document; |
| var contentFrameDocumentElement = contentFrameDocument.documentElement || contentFrameDocument.body; |
| var toc = document.getElementById('t'); |
| var tocStyle = getComputedStyle(toc, null).getPropertyValue('font-size'); |
| var tocFontSize = parseFloat(tocStyle); |
| if (initalize) { |
| newFontSize = getCookie('font-size'); |
| } else if (increase && !initalize && tocFontSize < 64) { |
| newFontSize = (tocFontSize + 3); |
| } else if (!increase && !initalize && tocFontSize > 12) { |
| newFontSize = (tocFontSize - 3); |
| } |
| if (!newFontSize) return; |
| contentFrameDocumentElement.style.fontSize = newFontSize + 'px'; |
| if (!updateContentFrameOnly) { |
| toc.style.fontSize = newFontSize + 'px'; |
| searchPage.style.fontSize = newFontSize + 'px'; |
| } |
| setCookie('font-size', newFontSize, 365); |
| } |
| |
| function printChapter() { |
| var contentElement = getElementById('c'); |
| var contentWindow = contentElement.contentWindow; |
| var topicHref = contentWindow.location.href; |
| if (!topicHref) return; |
| var dummy = document.createElement('a'); |
| dummy.href = BASE_URL + 'x'; |
| var topic = topicHref.substring(dummy.href.length - 2); |
| if (topic.length > 7 && '/topic/' == topic.substring(0, 7)) topic = topic.substring(6); |
| else if (topic.length > 5 && '/nav/' == topic.substring(0, 5)) topic = '/..' + topic; |
| else if (topic.length > 8 && ('/rtopic/' == topic.substring(0, 8) || '/ntopic/' == topic.substring(0, 8))) topic = topic.substring(7); |
| var w = contentWindow.innerWidth || contentWindow.document.body.clientWidth; |
| var h = contentWindow.innerHeight || contentWindow.document.body.clientHeight; |
| var x = window.screenX; |
| var y = window.screenY; |
| for (var e = contentElement; !!e; e = e.offsetParent) { |
| if (e.tagName == "BODY") { |
| var xScroll = e.scrollLeft || document.documentElement.scrollLeft; |
| var yScroll = e.scrollTop || document.documentElement.scrollTop; |
| x += (e.offsetLeft - xScroll + e.clientLeft); |
| y += (e.offsetTop - yScroll + e.clientTop); |
| } else { |
| x += (e.offsetLeft - e.scrollLeft + e.clientLeft); |
| y += (e.offsetTop - e.scrollTop + e.clientTop); |
| } |
| } |
| var anchor = ''; |
| var anchorStart = topic.indexOf('#'); |
| if (anchorStart > 0) { |
| anchor = '&anchor=' + topic.substr(anchorStart + 1); |
| topic = topic.substr(0, anchorStart); |
| } |
| var query = ''; |
| var queryStart = topic.indexOf('?'); |
| if (queryStart > 0) { |
| query = '&' + topic.substr(queryStart + 1); |
| topic = topic.substr(0, queryStart); |
| } |
| window.open(BASE_URL + 'advanced/print.jsp?topic=' + topic + query + anchor, 'printWindow', 'directories=yes,location=no,menubar=yes,resizable=yes,scrollbars=yes,status=yes,titlebar=yes,toolbar=yes,width=' + w + ',height=' + h + ',left=' + x + ',top=' + y); |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // Tree |
| |
| function createTree(element, contentProvider, labelProvider, selectable) { |
| var root = createElement(element, 0, 'tree'); |
| function createNode(parent, node) { |
| contentProvider(node, createNodeChildrenFn(parent, node)); |
| }; |
| function createNodeChildrenFn(parent) { |
| return function(children, open) { |
| var ul = createElement(parent, 'ul'); |
| for (var i = 0; children && i < children.length; i++) { |
| var li = createElement(ul, 'li', 'closed'); |
| li.p = parent; |
| var child = children[i]; |
| if (!child.l) { |
| |
| // c(hildren): yes |
| li.c = 1; |
| |
| // i(nit) function to load children |
| li.i = (function(li, node) { |
| return function() { |
| createNode(li, node); |
| li.i = 0; |
| }; |
| })(li, child.n); |
| |
| // handle (to toggle subtree) |
| var handle = createElement(li, 'span', 'h'); |
| handle.innerHTML = TREE_HANDLE; |
| addEvent(handle, 'click', (function(li) { |
| return function(e) { |
| toggleLi(li); |
| stopPropagation(e); |
| |
| // focus next element (to avoid losing focus since the handle cannot be focused) |
| try { |
| li.childNodes[1].focus(); |
| } catch(e) {} |
| |
| }; |
| })(li)); |
| |
| } |
| var label = labelProvider(li, child.n); |
| setClassName(label, 'l'); |
| if (selectable) { |
| addEvent(label, 'click', (function(li) { |
| return function(e) { |
| if (element.s === li) return; |
| element.x(li); |
| stopPropagation(e); |
| }; |
| })(li)); |
| } |
| addEvent(label, 'dblclick', (function(li) { |
| return function(e) { |
| toggleLi(li); |
| stopPropagation(e); |
| } |
| })(li)); |
| if (open || getClassName(li) == 'open') toggleLi(li); |
| } |
| } |
| }; |
| element.x = function(li, scrollArea, closeSiblings) { |
| for (var n = element.s; isLi(n); n = n.p) { |
| n.xx = 0; |
| n.x = 0; |
| updateLiClasses(n); |
| } |
| element.s = li; |
| if (!li) return; |
| li.xx = 1; |
| updateLiClasses(li); |
| for (var n = li.p; isLi(n); n = n.p) { |
| if (!n.o) { |
| toggleLi(n); |
| } |
| n.x = 1; |
| updateLiClasses(n); |
| } |
| |
| // close siblings of the selected node and its ancestors |
| for (var current = li; closeSiblings && current.tagName == 'LI'; current = current.p) { |
| var ul = getParentElement(current); |
| for (var i = 0; i < ul.childNodes.length; i++) { |
| var n = ul.childNodes[i]; |
| if (current !== n && n.o) { |
| toggleLi(n); |
| } |
| } |
| } |
| |
| // scroll label into view if needed |
| for (var i = 0; i < li.childNodes.length; i++) { |
| var n = li.childNodes[i]; |
| if (n.tagName == 'A' || n.tagName == 'BUTTON') { |
| scrollIntoViewIfNeeded(scrollArea, n); |
| break; |
| } |
| } |
| |
| // update search field book scope |
| if (updateScopeByToc && li.toc) { |
| updateScopeByToc(li); |
| } |
| |
| }; |
| element.y = function(href, scrollArea, closeSiblings) { |
| contentProvider({topic: href}, function(children) { |
| if (!children || children.length != 1 || !children[0].n || !children[0].n.y) { |
| |
| // deselect current selection |
| element.x(0); |
| |
| return; |
| } |
| var expandPath = children[0].n.y.split('_'); |
| var parentLi = root; |
| var parentNode = {}; |
| var childNodes = children; |
| for (var i = 0; i < expandPath.length; i++) { |
| var nr = parseInt(expandPath[i]); |
| if (parentLi.i) { |
| (createNodeChildrenFn(parentLi, parentNode))(childNodes); |
| parentLi.i = 0; |
| } |
| var ul = 0; |
| for (var j = 0; j < parentLi.childNodes.length; j++) { |
| var n = parentLi.childNodes[j]; |
| if (n.tagName == 'UL') { |
| ul = n; |
| break; |
| } |
| } |
| var li = 0; |
| var liNr = 0; |
| for (var j = 0; j < ul.childNodes.length; j++) { |
| var n = ul.childNodes[j]; |
| if (n.tagName == 'LI') { |
| if (liNr == nr) { |
| li = n; |
| break; |
| } |
| liNr++; |
| } |
| } |
| if (i == expandPath.length - 1) { |
| element.x(li, scrollArea, closeSiblings); |
| } |
| parentLi = li; |
| var child = childNodes[i == 0 ? 0 : nr]; |
| parentNode = child.n; |
| childNodes = child.c; |
| } |
| }); |
| } |
| createNode(root); |
| |
| // handling via the keys up, down, left, right, home and end |
| addEvent(element, 'keydown', function(e) { |
| var keyCode = e.keyCode || window.event.keyCode; |
| if (keyCode < 35 || keyCode > 40) return; |
| |
| // compute focused tree node |
| var li; |
| for (li = e.target || e.srcElement; li && li !== root; ) { |
| if (isLi(li)) break; |
| li = getParentElement(li); |
| } |
| if (!li) return; |
| |
| // left/right |
| if (keyCode == 37 || keyCode == 39) { |
| if (keyCode == 37 ^ !li.o) { |
| toggleLi(li); |
| } else if (keyCode == 37) { |
| focusTreeNode(li.p); |
| } else { |
| focusFirstChildNode(li); |
| } |
| |
| // down |
| } else if(keyCode == 40) { |
| |
| // expanded? -> focus first child, ... |
| if (li.o) { |
| focusFirstChildNode(li); |
| preventDefault(e); |
| return; |
| } |
| |
| // ...otherwise -> focus next sibling at this or higher level |
| for (var level = li; isLi(level); level = level.p) { |
| for (var next = getNextSibling(level); next; next = getNextSibling(next)) { |
| if (!isLi(next)) continue; |
| focusTreeNode(next); |
| preventDefault(e); |
| return; |
| } |
| } |
| |
| // up |
| } else if(keyCode == 38) { |
| |
| // previous sibling? -> focus previous sibling, ... |
| for (var prev = getPreviousSibling(li); prev !== null; prev = getPreviousSibling(prev)) { |
| if (!isLi(prev)) continue; |
| focusDeepestVisibleChild(prev); |
| preventDefault(e); |
| return; |
| } |
| |
| // ...otherwise -> focus parent |
| focusTreeNode(li.p); |
| |
| // home |
| } else if(keyCode == 36) { |
| focusFirstChildNode(root); |
| |
| // end |
| } else if(keyCode == 35) { |
| focusDeepestVisibleChild(root); |
| |
| } |
| preventDefault(e); |
| |
| }); |
| element.f = function() { |
| focusTreeNode(element.s); |
| }; |
| if (selectable) { |
| addEvent(element, 'click', element.f); |
| } |
| |
| // visitor pattern: visit the nearby nodes first (first the selected node with its subtree deep-first, then the |
| // parent, then the siblings with their subtrees and repeating for each higher level with the parent (if any) |
| // and the siblings, without the already processed node and its subtree) |
| element.v = function(vistorFn) { |
| var todoSiblingsAndAncestorsOf = element.s; |
| var todoSubtrees = element.s ? [element.s] : toArray(root.childNodes[0].childNodes); |
| while (todoSubtrees.length || todoSiblingsAndAncestorsOf) { |
| var next; |
| |
| // subtree done? -> go one level up |
| if (!todoSubtrees.length) { |
| var sibling = todoSiblingsAndAncestorsOf; |
| while (sibling = getNextSibling(sibling)) { |
| todoSubtrees.unshift(sibling); |
| } |
| sibling = todoSiblingsAndAncestorsOf; |
| while (sibling = getPreviousSibling(sibling)) { |
| todoSubtrees.unshift(sibling); |
| } |
| if (todoSiblingsAndAncestorsOf.p && todoSiblingsAndAncestorsOf.p.tagName == 'LI') { |
| next = todoSiblingsAndAncestorsOf = todoSiblingsAndAncestorsOf.p; |
| } else { |
| todoSiblingsAndAncestorsOf = 0; |
| continue; |
| } |
| } else { |
| next = todoSubtrees.pop(); |
| |
| // add children of next (if any) |
| for (var i = 0; i < next.childNodes.length; i++) { |
| var n = next.childNodes[i]; |
| if (n.tagName != 'UL') continue; |
| for (var j = n.childNodes.length - 1; j >= 0; j--) { |
| var m = n.childNodes[j]; |
| if (isLi(m)) { |
| todoSubtrees.push(m); |
| } |
| } |
| } |
| |
| } |
| |
| // call visitor |
| if (!vistorFn(next)) return; |
| |
| } |
| |
| } |
| function toArray(nodeList) { |
| var result = []; |
| for (var i = 0; i < nodeList.length; i++) { |
| result.push(nodeList[i]); |
| } |
| return result; |
| } |
| |
| function toggleLi(li) { |
| if (!li.c) return; |
| if (li.i) { |
| li.i(); |
| } |
| li.o = !li.o; |
| updateLiClasses(li); |
| } |
| function isLi(element) { |
| return element && element.tagName == 'LI' |
| } |
| function updateLiClasses(li) { |
| setClassName(li, (li.o ? 'open': 'closed') + (li.xx ? ' xx' : '') + (li.x ? ' x' : '')) |
| } |
| function focusFirstChildNode(li) { |
| for (var i = 0; i < li.childNodes.length; i++) { |
| var n = li.childNodes[i]; |
| if (n.tagName != 'UL') continue; |
| for (var j = 0; j < n.childNodes.length; j++) { |
| var m = n.childNodes[j]; |
| if (isLi(m)) { |
| focusTreeNode(m); |
| return; |
| } |
| } |
| } |
| } |
| function focusDeepestVisibleChild(li) { |
| for (var i = 0; li.o && i < li.childNodes.length; i++) { |
| var n = li.childNodes[i]; |
| if (n.tagName != 'UL') continue; |
| for (var j = n.childNodes.length - 1; j >= 0; j--) { |
| var m = n.childNodes[j]; |
| if (!isLi(m)) continue; |
| focusDeepestVisibleChild(m); |
| return; |
| } |
| } |
| focusTreeNode(li); |
| } |
| function focusTreeNode(li) { |
| if (!li) return; |
| for (var i = 0; i < li.childNodes.length; i++) { |
| var n = li.childNodes[i]; |
| if (n.tagName != 'A' && n.tagName != 'BUTTON') continue; |
| try { |
| n.focus(); |
| } catch(e) {} |
| return; |
| } |
| } |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // Overlay |
| |
| function createOverlay(zIndex, withoutStyles) { |
| var overlay = createElement(); |
| var header = getElementById('h'); |
| getParentElement(header).insertBefore(overlay, header); |
| if (!withoutStyles) { |
| var overlayStyle = overlay.style; |
| overlayStyle.display = 'none'; |
| overlayStyle.zIndex = zIndex ? zIndex : 1; |
| overlayStyle.position = 'absolute'; |
| overlayStyle.height = '100%'; |
| overlayStyle.width = '100%'; |
| } |
| overlay.a = function() { overlayStyle.display = 'block'; }; |
| overlay.o = function() { overlayStyle.display = 'none'; }; |
| return overlay; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // Utility functions (polyfill/retrofit functions see below) |
| |
| function addEvent(element, type, fn) { |
| if (element.addEventListener) { |
| element.addEventListener(type, fn, false); |
| } else if (element.attachEvent) { |
| element['e' + type + fn] = fn; |
| element[type + fn] = function() { |
| element['e' + type + fn](window.event); |
| } |
| element.attachEvent('on' + type, element[type + fn]); |
| } |
| } |
| |
| function decodeHtml(htmlString) { |
| if (!htmlString) return htmlString; |
| var element = createElement(); |
| setInnerHtml(element, htmlString); |
| return element.textContent || element.innerText; |
| } |
| |
| function getElementById(id) { |
| return document.getElementById(id); |
| } |
| |
| function getParentElement(element) { |
| return element.parentElement; |
| } |
| |
| function getPreviousSibling(element) { |
| return element.previousSibling; |
| } |
| |
| function getNextSibling(element) { |
| return element.nextSibling; |
| } |
| |
| function getClassName(element) { |
| return element.className; |
| } |
| |
| function setClassName(element, value) { |
| element.className = value; |
| return element; |
| } |
| |
| function getAttribute(element, attribute) { |
| return element.getAttribute(attribute); |
| } |
| |
| function setAttribute(element, attribute, value) { |
| element.setAttribute(attribute, value); |
| return element; |
| } |
| |
| function setInnerHtml(element, innerHtml) { |
| element.innerHTML = innerHtml ? innerHtml : ''; |
| } |
| |
| function preventDefault(e) { |
| e = e || window.event; |
| if (!e) return; |
| try { |
| if (e.preventDefault) e.preventDefault(); |
| e.returnValue = false; |
| } catch(e) {} |
| } |
| |
| function stopPropagation(e) { |
| e = e || window.event; |
| if (!e) return; |
| e.cancelBubble = true; |
| if (e.stopPropagation) e.stopPropagation(); |
| } |
| |
| function getParams(queryPart) { |
| var params = {}; |
| queryPart.replace(/(?:^|&+)([^=&]+)=([^&]*)/gi, |
| function(_match, group1Param, group2Value) { params[group1Param] = decodeURIComponent(group2Value); }); |
| return params; |
| } |
| |
| function getCookie(cookieName, defaultValue) { |
| var name = cookieName + "="; |
| var decodedCookie = decodeURIComponent(document.cookie); |
| var allCookies = decodedCookie.split(';'); |
| for (var i = 0; i < allCookies.length; i++) { |
| var cookie = allCookies[i]; |
| while (cookie.charAt(0) == ' ') { |
| cookie = cookie.substring(1); |
| } |
| if (cookie.indexOf(name) == 0) { |
| return cookie.substring(name.length, cookie.length); |
| } |
| } |
| return defaultValue; |
| } |
| |
| function setCookie(cookieName, value) { |
| var d = new Date(); |
| d.setTime(d.getTime() + (365 * 24 * 60 * 60 * 1000)); |
| var expires = 'expires=' + d.toUTCString(); |
| document.cookie = cookieName + '=' + value + ';' + expires + ';path=/;samesite=strict'; |
| } |
| |
| var openRequests = {}; |
| function remoteRequest(url, callbackFn, cancelId) { |
| var request = new XMLHttpRequest(); |
| if (callbackFn) request.onreadystatechange = function() { |
| if (request.readyState == 4 && request.status == 200) callbackFn(request.responseText); |
| } |
| request.open('GET', url); |
| request.send(); |
| if (cancelId) { |
| if (openRequests[cancelId] && openRequests[cancelId].abort) openRequests[cancelId].abort(); |
| openRequests[cancelId] = request; |
| } |
| } |
| |
| var parseXml; |
| if (typeof window.DOMParser != 'undefined') { |
| parseXml = function(xmlStr) { |
| return (new window.DOMParser()).parseFromString(xmlStr, 'text/xml'); |
| }; |
| } else if ( typeof window.ActiveXObject != 'undefined' |
| && new window.ActiveXObject('Microsoft.XMLDOM')) { |
| parseXml = function(xmlStr) { |
| var xmlDoc = new window.ActiveXObject('Microsoft.XMLDOM'); |
| xmlDoc.async = 'false'; |
| xmlDoc.loadXML(xmlStr); |
| return xmlDoc; |
| }; |
| } |
| |
| function scrollIntoViewIfNeeded(scrollArea, element) { |
| if (!scrollArea) return; |
| try { |
| var scrollAreaBoundaries = scrollArea.getBoundingClientRect(); |
| var elementBoundaries = element.getBoundingClientRect(); |
| if ( elementBoundaries.top >= scrollAreaBoundaries.top |
| && elementBoundaries.bottom <= scrollAreaBoundaries.bottom) return; |
| |
| scrollArea.scrollTop += scrollArea.c |
| |
| // show element in upper third |
| ? (( (elementBoundaries.bottom - scrollAreaBoundaries.bottom) |
| + (elementBoundaries.top - scrollAreaBoundaries.top) * 2) / 3) |
| |
| // scroll as less as possible |
| : (elementBoundaries.bottom <= scrollAreaBoundaries.bottom |
| ? elementBoundaries.top - scrollAreaBoundaries.top |
| : elementBoundaries.bottom - scrollAreaBoundaries.bottom); |
| |
| } catch (e) {} |
| } |
| |
| function arrayContainsPrefix(array, value) { |
| for (var i = 0; i < array.length; i++) { |
| if (array[i].length <= value.length && value.substring(0, array[i].length) == array[i]) return true; |
| } |
| return false; |
| } |
| |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| // |
| // Polyfill/retrofit utility functions |
| |
| function createElement(parent, name, className, text) { |
| var element = document.createElement(name ? name : 'div'); |
| if (parent) { |
| try { |
| parent.appendChild(element); |
| } catch(e) { |
| |
| // POLYFILL IE<=8 |
| // HTML5 semantic tags (https://www.w3schools.com/html/html5_browsers.asp) |
| // polyfill adding child element to the empty HTML 5 semantic element 'aside' (for IE 8 and lower) |
| if (parent.tagName == 'ASIDE') { |
| var pp = parent.parentElement; |
| var rest = []; |
| for (var i = 0; i < pp.childNodes.length; i++) { |
| if (parent === pp.childNodes[i]) { |
| if (div) continue; |
| var div = document.createElement('div'); |
| for (var j = 0; j < parent.attributes.length; j++) { |
| var attribute = parent.attributes[j]; |
| if ('' + parent.getAttribute(attribute.name) != '' + div.getAttribute(attribute.name) |
| && !('' + parent.getAttribute(attribute.name) == 'null' |
| && '' + div.getAttribute(attribute.name) == '')) { |
| setAttribute(div, attribute.name, attribute.value); |
| } |
| } |
| pp.removeChild(parent); |
| div.appendChild(element); |
| rest.push(div); |
| i--; |
| continue; |
| } |
| if (rest && pp.childNodes[i].tagName == '/' + parent.tagName) { |
| pp.removeChild(pp.childNodes[i]); |
| i--; |
| continue; |
| } |
| if (!rest) continue; |
| rest.push(pp.removeChild(pp.childNodes[i])); |
| i--; |
| } |
| for (var i = 0; i < rest.length; i++) pp.appendChild(rest[i]); |
| } else throw e; |
| |
| } |
| } |
| if (className) { |
| setClassName(element, className); |
| } |
| if (text) { |
| element.appendChild(document.createTextNode(text)); |
| } |
| return element; |
| } |
| |
| }(window, document)); |