mirror of
https://github.com/php-win-ext/phpredis.git
synced 2026-03-24 17:12:15 +01:00
317 lines
13 KiB
JavaScript
317 lines
13 KiB
JavaScript
var Doctum = {
|
|
treeJson: {"tree":{"l":0,"n":"","p":"","c":[{"l":1,"n":"[Global Namespace]","p":"[Global_Namespace]","c":[{"l":2,"n":"Redis","p":"Redis"},{"l":2,"n":"RedisArray","p":"RedisArray"},{"l":2,"n":"RedisCluster","p":"RedisCluster"},{"l":2,"n":"RedisClusterException","p":"RedisClusterException"},{"l":2,"n":"RedisException","p":"RedisException"},{"l":2,"n":"RedisSentinel","p":"RedisSentinel"}]}]},"treeOpenLevel":2},
|
|
/** @var boolean */
|
|
treeLoaded: false,
|
|
/** @var boolean */
|
|
listenersRegistered: false,
|
|
autoCompleteData: null,
|
|
/** @var boolean */
|
|
autoCompleteLoading: false,
|
|
/** @var boolean */
|
|
autoCompleteLoaded: false,
|
|
/** @var string|null */
|
|
rootPath: null,
|
|
/** @var string|null */
|
|
autoCompleteDataUrl: null,
|
|
/** @var HTMLElement|null */
|
|
doctumSearchAutoComplete: null,
|
|
/** @var HTMLElement|null */
|
|
doctumSearchAutoCompleteProgressBarContainer: null,
|
|
/** @var HTMLElement|null */
|
|
doctumSearchAutoCompleteProgressBar: null,
|
|
/** @var number */
|
|
doctumSearchAutoCompleteProgressBarPercent: 0,
|
|
/** @var autoComplete|null */
|
|
autoCompleteJS: null,
|
|
querySearchSecurityRegex: /([^0-9a-zA-Z:\\\\_\s])/gi,
|
|
buildTreeNode: function (treeNode, htmlNode, treeOpenLevel) {
|
|
var ulNode = document.createElement('ul');
|
|
for (var childKey in treeNode.c) {
|
|
var child = treeNode.c[childKey];
|
|
var liClass = document.createElement('li');
|
|
var hasChildren = child.hasOwnProperty('c');
|
|
var nodeSpecialName = (hasChildren ? 'namespace:' : 'class:') + child.p.replace(/\//g, '_');
|
|
liClass.setAttribute('data-name', nodeSpecialName);
|
|
|
|
// Create the node that will have the text
|
|
var divHd = document.createElement('div');
|
|
var levelCss = child.l - 1;
|
|
divHd.className = hasChildren ? 'hd' : 'hd leaf';
|
|
divHd.style.paddingLeft = (hasChildren ? (levelCss * 18) : (8 + (levelCss * 18))) + 'px';
|
|
if (hasChildren) {
|
|
if (child.l <= treeOpenLevel) {
|
|
liClass.className = 'opened';
|
|
}
|
|
var spanIcon = document.createElement('span');
|
|
spanIcon.className = 'icon icon-play';
|
|
divHd.appendChild(spanIcon);
|
|
}
|
|
var aLink = document.createElement('a');
|
|
|
|
// Edit the HTML link to work correctly based on the current depth
|
|
aLink.href = Doctum.rootPath + child.p + '.html';
|
|
aLink.innerText = child.n;
|
|
divHd.appendChild(aLink);
|
|
liClass.appendChild(divHd);
|
|
|
|
// It has children
|
|
if (hasChildren) {
|
|
var divBd = document.createElement('div');
|
|
divBd.className = 'bd';
|
|
Doctum.buildTreeNode(child, divBd, treeOpenLevel);
|
|
liClass.appendChild(divBd);
|
|
}
|
|
ulNode.appendChild(liClass);
|
|
}
|
|
htmlNode.appendChild(ulNode);
|
|
},
|
|
initListeners: function () {
|
|
if (Doctum.listenersRegistered) {
|
|
// Quick exit, already registered
|
|
return;
|
|
}
|
|
Doctum.listenersRegistered = true;
|
|
},
|
|
loadTree: function () {
|
|
if (Doctum.treeLoaded) {
|
|
// Quick exit, already registered
|
|
return;
|
|
}
|
|
Doctum.rootPath = document.body.getAttribute('data-root-path');
|
|
Doctum.buildTreeNode(Doctum.treeJson.tree, document.getElementById('api-tree'), Doctum.treeJson.treeOpenLevel);
|
|
|
|
// Toggle left-nav divs on click
|
|
$('#api-tree .hd span').on('click', function () {
|
|
$(this).parent().parent().toggleClass('opened');
|
|
});
|
|
|
|
// Expand the parent namespaces of the current page.
|
|
var expected = $('body').attr('data-name');
|
|
|
|
if (expected) {
|
|
// Open the currently selected node and its parents.
|
|
var container = $('#api-tree');
|
|
var node = $('#api-tree li[data-name="' + expected + '"]');
|
|
// Node might not be found when simulating namespaces
|
|
if (node.length > 0) {
|
|
node.addClass('active').addClass('opened');
|
|
node.parents('li').addClass('opened');
|
|
var scrollPos = node.offset().top - container.offset().top + container.scrollTop();
|
|
// Position the item nearer to the top of the screen.
|
|
scrollPos -= 200;
|
|
container.scrollTop(scrollPos);
|
|
}
|
|
}
|
|
Doctum.treeLoaded = true;
|
|
},
|
|
pagePartiallyLoaded: function (event) {
|
|
Doctum.initListeners();
|
|
Doctum.loadTree();
|
|
Doctum.loadAutoComplete();
|
|
},
|
|
pageFullyLoaded: function (event) {
|
|
// it may not have received DOMContentLoaded event
|
|
Doctum.initListeners();
|
|
Doctum.loadTree();
|
|
Doctum.loadAutoComplete();
|
|
// Fire the event in the search page too
|
|
if (typeof DoctumSearch === 'object') {
|
|
DoctumSearch.pageFullyLoaded();
|
|
}
|
|
},
|
|
loadAutoComplete: function () {
|
|
if (Doctum.autoCompleteLoaded) {
|
|
// Quick exit, already loaded
|
|
return;
|
|
}
|
|
Doctum.autoCompleteDataUrl = document.body.getAttribute('data-search-index-url');
|
|
Doctum.doctumSearchAutoComplete = document.getElementById('doctum-search-auto-complete');
|
|
Doctum.doctumSearchAutoCompleteProgressBarContainer = document.getElementById('search-progress-bar-container');
|
|
Doctum.doctumSearchAutoCompleteProgressBar = document.getElementById('search-progress-bar');
|
|
if (Doctum.doctumSearchAutoComplete !== null) {
|
|
// Wait for it to be loaded
|
|
Doctum.doctumSearchAutoComplete.addEventListener('init', function (_) {
|
|
Doctum.autoCompleteLoaded = true;
|
|
Doctum.doctumSearchAutoComplete.addEventListener('selection', function (event) {
|
|
// Go to selection page
|
|
window.location = Doctum.rootPath + event.detail.selection.value.p;
|
|
});
|
|
Doctum.doctumSearchAutoComplete.addEventListener('navigate', function (event) {
|
|
// Set selection in text box
|
|
if (typeof event.detail.selection.value === 'object') {
|
|
Doctum.doctumSearchAutoComplete.value = event.detail.selection.value.n;
|
|
}
|
|
});
|
|
Doctum.doctumSearchAutoComplete.addEventListener('results', function (event) {
|
|
Doctum.markProgressFinished();
|
|
});
|
|
});
|
|
}
|
|
// Check if the lib is loaded
|
|
if (typeof autoComplete === 'function') {
|
|
Doctum.bootAutoComplete();
|
|
}
|
|
},
|
|
markInProgress: function () {
|
|
Doctum.doctumSearchAutoCompleteProgressBarContainer.className = 'search-bar';
|
|
Doctum.doctumSearchAutoCompleteProgressBar.className = 'progress-bar indeterminate';
|
|
if (typeof DoctumSearch === 'object' && DoctumSearch.pageFullyLoaded) {
|
|
DoctumSearch.doctumSearchPageAutoCompleteProgressBarContainer.className = 'search-bar';
|
|
DoctumSearch.doctumSearchPageAutoCompleteProgressBar.className = 'progress-bar indeterminate';
|
|
}
|
|
},
|
|
markProgressFinished: function () {
|
|
Doctum.doctumSearchAutoCompleteProgressBarContainer.className = 'search-bar hidden';
|
|
Doctum.doctumSearchAutoCompleteProgressBar.className = 'progress-bar';
|
|
if (typeof DoctumSearch === 'object' && DoctumSearch.pageFullyLoaded) {
|
|
DoctumSearch.doctumSearchPageAutoCompleteProgressBarContainer.className = 'search-bar hidden';
|
|
DoctumSearch.doctumSearchPageAutoCompleteProgressBar.className = 'progress-bar';
|
|
}
|
|
},
|
|
makeProgress: function () {
|
|
Doctum.makeProgressOnProgressBar(
|
|
Doctum.doctumSearchAutoCompleteProgressBarPercent,
|
|
Doctum.doctumSearchAutoCompleteProgressBar
|
|
);
|
|
if (typeof DoctumSearch === 'object' && DoctumSearch.pageFullyLoaded) {
|
|
Doctum.makeProgressOnProgressBar(
|
|
Doctum.doctumSearchAutoCompleteProgressBarPercent,
|
|
DoctumSearch.doctumSearchPageAutoCompleteProgressBar
|
|
);
|
|
}
|
|
},
|
|
loadAutoCompleteData: function (query) {
|
|
return new Promise(function (resolve, reject) {
|
|
if (Doctum.autoCompleteData !== null) {
|
|
resolve(Doctum.autoCompleteData);
|
|
return;
|
|
}
|
|
Doctum.markInProgress();
|
|
function reqListener() {
|
|
Doctum.autoCompleteLoading = false;
|
|
Doctum.autoCompleteData = JSON.parse(this.responseText).items;
|
|
Doctum.markProgressFinished();
|
|
|
|
setTimeout(function () {
|
|
resolve(Doctum.autoCompleteData);
|
|
}, 50);// Let the UI render once before sending the results for processing. This gives time to the progress bar to hide
|
|
}
|
|
function reqError(err) {
|
|
Doctum.autoCompleteLoading = false;
|
|
Doctum.autoCompleteData = null;
|
|
console.error(err);
|
|
reject(err);
|
|
}
|
|
|
|
var oReq = new XMLHttpRequest();
|
|
oReq.onload = reqListener;
|
|
oReq.onerror = reqError;
|
|
oReq.onprogress = function (pe) {
|
|
if (pe.lengthComputable) {
|
|
Doctum.doctumSearchAutoCompleteProgressBarPercent = parseInt(pe.loaded / pe.total * 100, 10);
|
|
Doctum.makeProgress();
|
|
}
|
|
};
|
|
oReq.onloadend = function (_) {
|
|
Doctum.markProgressFinished();
|
|
};
|
|
oReq.open('get', Doctum.autoCompleteDataUrl, true);
|
|
oReq.send();
|
|
});
|
|
},
|
|
/**
|
|
* Make some progress on a progress bar
|
|
*
|
|
* @param number percentage
|
|
* @param HTMLElement progressBar
|
|
* @return void
|
|
*/
|
|
makeProgressOnProgressBar: function(percentage, progressBar) {
|
|
progressBar.className = 'progress-bar';
|
|
progressBar.style.width = percentage + '%';
|
|
progressBar.setAttribute(
|
|
'aria-valuenow', percentage
|
|
);
|
|
},
|
|
searchEngine: function (query, record) {
|
|
if (typeof query !== 'string') {
|
|
return '';
|
|
}
|
|
// replace all (mode = g) spaces and non breaking spaces (\s) by pipes
|
|
// g = global mode to mark also the second word searched
|
|
// i = case insensitive
|
|
// how this function works:
|
|
// First: search if the query has the keywords in sequence
|
|
// Second: replace the keywords by a mark and leave all the text in between non marked
|
|
|
|
if (record.match(new RegExp('(' + query.replace(/\s/g, ').*(') + ')', 'gi')) === null) {
|
|
return '';// Does not match
|
|
}
|
|
|
|
var replacedRecord = record.replace(new RegExp('(' + query.replace(/\s/g, '|') + ')', 'gi'), function (group) {
|
|
return '<mark class="auto-complete-highlight">' + group + '</mark>';
|
|
});
|
|
|
|
if (replacedRecord !== record) {
|
|
return replacedRecord;// This should not happen but just in case there was no match done
|
|
}
|
|
|
|
return '';
|
|
},
|
|
/**
|
|
* Clean the search query
|
|
*
|
|
* @param string query
|
|
* @return string
|
|
*/
|
|
cleanSearchQuery: function (query) {
|
|
// replace any chars that could lead to injecting code in our regex
|
|
// remove start or end spaces
|
|
// replace backslashes by an escaped version, use case in search: \myRootFunction
|
|
return query.replace(Doctum.querySearchSecurityRegex, '').trim().replace(/\\/g, '\\\\');
|
|
},
|
|
bootAutoComplete: function () {
|
|
Doctum.autoCompleteJS = new autoComplete(
|
|
{
|
|
selector: '#doctum-search-auto-complete',
|
|
searchEngine: function (query, record) {
|
|
return Doctum.searchEngine(query, record);
|
|
},
|
|
submit: true,
|
|
data: {
|
|
src: function (q) {
|
|
Doctum.markInProgress();
|
|
return Doctum.loadAutoCompleteData(q);
|
|
},
|
|
keys: ['n'],// Data 'Object' key to be searched
|
|
cache: false, // Is not compatible with async fetch of data
|
|
},
|
|
query: (input) => {
|
|
return Doctum.cleanSearchQuery(input);
|
|
},
|
|
trigger: (query) => {
|
|
return Doctum.cleanSearchQuery(query).length > 0;
|
|
},
|
|
resultsList: {
|
|
tag: 'ul',
|
|
class: 'auto-complete-dropdown-menu',
|
|
destination: '#auto-complete-results',
|
|
position: 'afterbegin',
|
|
maxResults: 500,
|
|
noResults: false,
|
|
},
|
|
resultItem: {
|
|
tag: 'li',
|
|
class: 'auto-complete-result',
|
|
highlight: 'auto-complete-highlight',
|
|
selected: 'auto-complete-selected'
|
|
},
|
|
}
|
|
);
|
|
}
|
|
};
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', Doctum.pagePartiallyLoaded, false);
|
|
window.addEventListener('load', Doctum.pageFullyLoaded, false);
|