User:Polygnotus/Scripts/Userinfo.js: Difference between revisions

Content deleted Content added
Created page with '// Wikipedia API Explorer Module const WikipediaAPI = { // Fetch Wikipedia userinfo data async fetchUserInfo() { const params = { action: 'query', meta: 'userinfo', uiprop: 'options', format: 'json', origin: '*' }; const url = 'https://en.wikipedia.org/w/api.php?' + new URLSearchParams(params); try { const response = await fetch(...'
 
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 1:
// Wikipedia UserOptions API Explorer Modulewith Tools Menu Integration
$(document).ready(function() {
const WikipediaAPI = {
// Add link to Tools menu on all pages
// Fetch Wikipedia userinfo data
mw.hook('wikipage.content').add(function() {
async fetchUserInfo() {
mw.loader.using(['mediawiki.util'], function() {
const params = {
action:// Only add the link if it doesn'query',t already exist
meta:if (!document.getElementById('userinfot-useroptions-api',)) {
uiprop: 'options', mw.util.addPortletLink(
'p-tb', // Target portlet ID (Tools menu)
format: 'json',
mw.config.get('wgServer') + '/wiki/Special:BlankPage/UserOptions', // Link URL
origin: '*'
'User Options API', // Link text
};
't-useroptions-api', // Link ID
'Explore user options via MediaWiki API' // Tooltip
const url = 'https://en.wikipedia.org/w/api.php?' + new URLSearchParams(params);
);
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json(});
} catch (error) {;
console.error('Wikipedia API error:', error);
throw error;
}
},
 
// Create JSON tree viewer
createJSONTree(containerId, data) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`Container with id '${containerId}' not found`);
return;
}
 
// Only run the main interface if we're on the specific page
// Clear container
if (mw.config.get('wgCanonicalSpecialPageName') === 'Blankpage' &&
container.innerHTML = '';
mw.config.get('wgPageName') === 'Special:BlankPage/UserOptions') {
$('#firstHeading').text('User Options API Explorer');
// Create tree structure
const tree = document.createElement('div');
tree.className = 'json-tree';
tree.appendChild(this.createNode('root', data, 0));
container.appendChild(tree);
var html = '<div id="useroptions-container">' +
// Add styles if not already present
'<div class="api-info" style="background: #e8f4f8; border: 1px solid #bee5eb; border-radius: 5px; padding: 15px; margin-bottom: 20px;">' +
this.addStyles();
'<strong>API Endpoint:</strong> ' + mw.config.get('wgServer') + '/w/api.php<br>' +
},
'<strong>Parameters:</strong> action=query, meta=userinfo, uiprop=options, format=json' +
 
'</div>' +
// Create individual node
'<div class="controls" style="margin-bottom: 20px;">' +
createNode(key, value, depth) {
'<button id="fetchBtn" class="btn btn-primary">Fetch User Options</button>' +
const node = document.createElement('div');
'<button id="expandBtn" class="btn btn-success">Expand All</button>' +
node.className = 'json-node';
'<button id="collapseBtn" class="btn btn-danger">Collapse All</button>' +
'</div>' +
'<div id="status"></div>' +
'<div id="jsonResult"></div>' +
'</div>';
if $(value === null'#mw-content-text') {.html(html);
node.innerHTML = `<span class="json-key">${key}:</span> <span class="json-null">null</span>`;
} else if (typeof value === 'string') {
node.innerHTML = `<span class="json-key">${key}:</span> <span class="json-string">"${this.escapeHtml(value)}"</span>`;
} else if (typeof value === 'number') {
node.innerHTML = `<span class="json-key">${key}:</span> <span class="json-number">${value}</span>`;
} else if (typeof value === 'boolean') {
node.innerHTML = `<span class="json-key">${key}:</span> <span class="json-boolean">${value}</span>`;
} else if (Array.isArray(value)) {
const toggleId = `toggle-${Date.now()}-${Math.random()}`;
const toggle = document.createElement('span');
toggle.className = 'json-toggle';
toggle.textContent = '▼';
toggle.id = toggleId;
const keySpan = document.createElement('span');
keySpan.className = 'json-key';
keySpan.textContent = `${key}:`;
const summary = document.createElement('span');
summary.className = 'json-collapsed';
summary.textContent = ` [${value.length} items]`;
node.appendChild(toggle);
node.appendChild(keySpan);
node.appendChild(summary);
const children = document.createElement('div');
children.className = 'json-children';
value.forEach((item, index) => {
children.appendChild(this.createNode(`[${index}]`, item, depth + 1));
});
node.appendChild(children);
toggle.onclick = () => this.toggleNode(toggleId);
} else if (typeof value === 'object') {
const keys = Object.keys(value);
const toggleId = `toggle-${Date.now()}-${Math.random()}`;
const toggle = document.createElement('span');
toggle.className = 'json-toggle';
toggle.textContent = '▼';
toggle.id = toggleId;
const keySpan = document.createElement('span');
keySpan.className = 'json-key';
keySpan.textContent = `${key}:`;
const summary = document.createElement('span');
summary.className = 'json-collapsed';
summary.textContent = ` {${keys.length} properties}`;
node.appendChild(toggle);
node.appendChild(keySpan);
node.appendChild(summary);
const children = document.createElement('div');
children.className = 'json-children';
keys.forEach(objKey => {
children.appendChild(this.createNode(objKey, value[objKey], depth + 1));
});
node.appendChild(children);
toggle.onclick = () => this.toggleNode(toggleId);
}
// Wikipedia UserOptions API Module
return node;
var UserOptionsAPI = {
},
fetchUserOptions: function() {
var params = {
action: 'query',
meta: 'userinfo',
uiprop: 'options',
format: 'json'
};
return new mw.Api().get(params);
},
 
createJSONTree: function(containerId, data) {
// Toggle node visibility
var container = document.getElementById(containerId);
toggleNode(toggleId) {
const toggle = document.getElementById if (toggleId!container) return;
const children = toggle.parentNode.querySelector('.json-children');
if (children.classList.contains('hidden')) {
children.classList.remove('hidden');
toggle.textContent = '▼';
} else {
children.classList.add('hidden');
toggle.textContent = '▶';
}
},
 
container.innerHTML = '';
// Expand all nodes
expandAll(containerId) {
const container var tree = document.getElementByIdcreateElement(containerId'div');
const toggles = container tree.querySelectorAll(className = '.json-toggletree');
tree.appendChild(this.createNode('response', data, 0));
toggles.forEach(toggle => {
const children = toggle container.parentNode.querySelectorappendChild('.json-children'tree);
if (children) {
childrenthis.classList.removeaddStyles('hidden');
toggle.textContent = '▼';},
}
});
},
 
createNode: function(key, value, depth) {
// Collapse all nodes
var node = document.createElement('div');
collapseAll(containerId) {
const container = document node.getElementById(containerId)className = 'json-node';
var self = this;
const toggles = container.querySelectorAll('.json-toggle');
toggles.forEach(toggle => {
const children = toggle.parentNode.querySelector if ('.json-children'value === null); {
node.innerHTML = '<span class="json-key">' + key + ':</span> <span class="json-null">null</span>';
if (children) {
children.classList.add} else if (typeof value === 'hiddenstring'); {
node.innerHTML = '<span class="json-key">' + key + ':</span> <span class="json-string">"' + this.escapeHtml(value) + '"</span>';
toggle.textContent = '▶';
} else if (typeof value === 'number') {
node.innerHTML = '<span class="json-key">' + key + ':</span> <span class="json-number">' + value + '</span>';
});
} else if (typeof value === 'boolean') {
},
node.innerHTML = '<span class="json-key">' + key + ':</span> <span class="json-boolean">' + value + '</span>';
} else if (Array.isArray(value)) {
var toggleId = 'toggle-' + Date.now() + '-' + Math.random().toString().replace('.', '');
var toggle = document.createElement('span');
toggle.className = 'json-toggle';
toggle.textContent = '▼';
toggle.id = toggleId;
var keySpan = document.createElement('span');
keySpan.className = 'json-key';
keySpan.textContent = key + ':';
var summary = document.createElement('span');
summary.className = 'json-collapsed';
summary.textContent = ' [' + value.length + ' items]';
node.appendChild(toggle);
node.appendChild(keySpan);
node.appendChild(summary);
var children = document.createElement('div');
children.className = 'json-children';
for (var i = 0; i < value.length; i++) {
children.appendChild(this.createNode('[' + i + ']', value[i], depth + 1));
}
node.appendChild(children);
// Create closure to preserve toggleId
(function(id) {
toggle.onclick = function() {
self.toggleNode(id);
};
})(toggleId);
} else if (typeof value === 'object') {
var keys = Object.keys(value);
var toggleId = 'toggle-' + Date.now() + '-' + Math.random();
var toggle = document.createElement('span');
toggle.className = 'json-toggle';
toggle.textContent = '▼';
toggle.id = toggleId;
var keySpan = document.createElement('span');
keySpan.className = 'json-key';
keySpan.textSize = key + ':';
var summary = document.createElement('span');
summary.className = 'json-collapsed';
summary.textContent = ' {' + keys.length + ' properties}';
node.appendChild(toggle);
node.appendChild(keySpan);
node.appendChild(summary);
var children = document.createElement('div');
children.className = 'json-children';
for (var j = 0; j < keys.length; j++) {
var objKey = keys[j];
children.appendChild(this.createNode(objKey, value[objKey], depth + 1));
}
node.appendChild(children);
toggle.onclick = function() {
self.toggleNode(toggleId);
};
}
return node;
},
 
toggleNode: function(toggleId) {
// Escape HTML
var toggle = document.getElementById(toggleId);
escapeHtml(text) {
const div = document.createElement if ('div'!toggle); {
console.error('Toggle element not found:', toggleId);
div.textContent = text;
return div.innerHTML return;
},
var children = toggle.parentNode.querySelector('.json-children');
if (!children) {
console.error('Children element not found for toggle:', toggleId);
return;
}
if (children.classList.contains('hidden')) {
children.classList.remove('hidden');
toggle.textContent = '▼';
} else {
children.classList.add('hidden');
toggle.textContent = '▶';
}
},
 
expandAll: function(containerId) {
// Add required CSS styles
var container = document.getElementById(containerId);
addStyles() {
if (document var toggles = container.getElementByIdquerySelectorAll('.json-tree-stylestoggle')) return;
for (var i = 0; i < toggles.length; i++) {
var toggle = toggles[i];
const style = document.createElement('style');
style.id var children = toggle.parentNode.querySelector('.json-tree-styleschildren');
if (children) {
style.textContent = `
children.classList.remove('hidden');
.json-tree {
font-family: 'Courier New', monospace toggle.textContent = '▼';
background: #f8f9fa; }
border: 1px solid #e1e5e9;}
border-radius: 5px;},
padding: 15px;
margin: 10px 0;
overflow-x: auto;
}
.json-node {
margin: 2px 0;
}
.json-key {
color: #0645ad;
font-weight: bold;
}
.json-string {
color: #d73a49;
}
.json-number {
color: #005cc5;
}
.json-boolean {
color: #6f42c1;
}
.json-null {
color: #6a737d;
}
.json-toggle {
cursor: pointer;
user-select: none;
display: inline-block;
width: 20px;
color: #666;
font-weight: bold;
}
.json-toggle:hover {
color: #0645ad;
}
.json-collapsed {
color: #666;
}
.json-children {
margin-left: 20px;
border-left: 1px solid #e1e5e9;
padding-left: 10px;
}
.json-children.hidden {
display: none;
}
`;
document.head.appendChild(style);
},
 
collapseAll: function(containerId) {
// Main function to fetch and display
async displayWikipediaData var container = document.getElementById(containerId) {;
var toggles = container.querySelectorAll('.json-toggle');
try {
const data for (var i = await0; thisi < toggles.fetchUserInfo()length; i++) {
var toggle = toggles[i];
this.createJSONTree(containerId, data);
var children = toggle.parentNode.querySelector('.json-children');
console.log('Wikipedia data loaded successfully');
} catch if (errorchildren) {
const container = document children.classList.getElementByIdadd(containerId'hidden');
if (container) { toggle.textContent = '▶';
}
container.innerHTML = `<div style="color: red; padding: 10px;">Error loading data: ${error.message}</div>`;
}
},
 
escapeHtml: function(text) {
var div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
},
 
addStyles: function() {
if (document.getElementById('json-tree-styles')) return;
var style = document.createElement('style');
style.id = 'json-tree-styles';
style.textContent =
'.json-tree {' +
'font-family: "Courier New", monospace;' +
'background: #f8f9fa;' +
'border: 1px solid #e1e5e9;' +
'border-radius: 5px;' +
'padding: 15px;' +
'margin: 10px 0;' +
'overflow-x: auto;' +
'max-height: 600px;' +
'overflow-y: auto;' +
'}' +
'.json-node {' +
'margin: 2px 0;' +
'}' +
'.json-key {' +
'color: #0645ad;' +
'font-weight: bold;' +
'}' +
'.json-string {' +
'color: #d73a49;' +
'}' +
'.json-number {' +
'color: #005cc5;' +
'}' +
'.json-boolean {' +
'color: #6f42c1;' +
'}' +
'.json-null {' +
'color: #6a737d;' +
'}' +
'.json-toggle {' +
'cursor: pointer;' +
'user-select: none;' +
'display: inline-block;' +
'width: 20px;' +
'color: #666;' +
'font-weight: bold;' +
'}' +
'.json-toggle:hover {' +
'color: #0645ad;' +
'}' +
'.json-collapsed {' +
'color: #666;' +
'}' +
'.json-children {' +
'margin-left: 20px;' +
'border-left: 1px solid #e1e5e9;' +
'padding-left: 10px;' +
'}' +
'.json-children.hidden {' +
'display: none;' +
'}' +
'.btn {' +
'display: inline-block;' +
'padding: 6px 12px;' +
'margin: 0 5px 5px 0;' +
'font-size: 14px;' +
'font-weight: normal;' +
'line-height: 1.42857143;' +
'text-align: center;' +
'white-space: nowrap;' +
'vertical-align: middle;' +
'cursor: pointer;' +
'border: 1px solid transparent;' +
'border-radius: 4px;' +
'text-decoration: none;' +
'}' +
'.btn-primary {' +
'color: #fff;' +
'background-color: #0645ad;' +
'border-color: #0645ad;' +
'}' +
'.btn-success {' +
'color: #fff;' +
'background-color: #28a745;' +
'border-color: #28a745;' +
'}' +
'.btn-danger {' +
'color: #fff;' +
'background-color: #dc3545;' +
'border-color: #dc3545;' +
'}' +
'.btn:hover {' +
'opacity: 0.8;' +
'}';
document.head.appendChild(style);
},
 
displayUserOptions: function(containerId) {
var statusDiv = document.getElementById('status');
var fetchBtn = document.getElementById('fetchBtn');
var self = this;
fetchBtn.disabled = true;
statusDiv.innerHTML = '<div style="color: #666; font-style: italic;">Fetching user options...</div>';
this.fetchUserOptions().done(function(data) {
statusDiv.innerHTML = '<div style="color: #28a745;">✓ User options loaded successfully</div>';
self.createJSONTree(containerId, data);
fetchBtn.disabled = false;
}).fail(function(error) {
statusDiv.innerHTML = '<div style="color: #d33; background: #ffeaea; padding: 10px; border-radius: 5px;">Error: ' + error + '</div>';
console.error('Fetch error:', error);
fetchBtn.disabled = false;
});
}
};
// Event listeners (only when on the correct page)
$('#fetchBtn').on('click', function() {
UserOptionsAPI.displayUserOptions('jsonResult');
});
$('#expandBtn').on('click', function() {
UserOptionsAPI.expandAll('jsonResult');
});
$('#collapseBtn').on('click', function() {
UserOptionsAPI.collapseAll('jsonResult');
});
// Auto-load on page load
UserOptionsAPI.displayUserOptions('jsonResult');
}
};
 
// Usage examples:
/*
// Fetch and display data
WikipediaAPI.displayWikipediaData('my-container');
 
// Or fetch data manually and create tree
WikipediaAPI.fetchUserInfo().then(data => {
WikipediaAPI.createJSONTree('my-container', data);
});
 
// Control functions
WikipediaAPI.expandAll('my-container');
WikipediaAPI.collapseAll('my-container');
*/