MediaWiki:Common.js
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* Apogea Wiki Common JavaScript
*/
(function() {
'use strict';
/**
* Sprite preview for Page Forms
*/
function initSpritePreview() {
var inputs = document.querySelectorAll('input');
var found = false;
inputs.forEach(function(input) {
var name = input.getAttribute('name') || '';
// Match sprite fields
if (name.indexOf('sprite]') === -1) return;
found = true;
console.log('[Apogea] Found sprite field:', name);
// Skip if already has preview
if (input.dataset.hasPreview) return;
input.dataset.hasPreview = 'true';
// Extract variant index from field name (e.g., ItemEntry[1b][sprite] -> 1b)
var indexMatch = name.match(/\[(\d+[a-z]?)\]/);
var variantIndex = indexMatch ? indexMatch[1] : null;
// Create preview container
var preview = document.createElement('div');
preview.className = 'sprite-preview';
preview.style.cssText = 'margin-top: 5px; min-height: 48px;';
input.parentNode.appendChild(preview);
// Find corresponding name field with same variant index
var nameInput = null;
if (variantIndex) {
nameInput = document.querySelector('input[name*="[' + variantIndex + '][name]"]');
} else {
// Fallback for non-indexed fields
var container = input.closest('tr') || input.closest('fieldset') || input.parentNode.parentNode;
if (container) {
var allInputs = container.parentNode.querySelectorAll('input');
allInputs.forEach(function(inp) {
var n = inp.getAttribute('name') || '';
if (n.indexOf('[name]') !== -1) {
nameInput = inp;
}
});
}
}
function updatePreview() {
var spriteName = input.value.trim();
// Fall back to name field if sprite is empty
if (!spriteName && nameInput) {
spriteName = nameInput.value.trim();
}
if (!spriteName) {
preview.innerHTML = '<span style="color: #888;">No preview</span>';
return;
}
// Replace underscores with spaces for the filename
var fileName = spriteName.replace(/_/g, ' ') + '.png';
// Use MediaWiki API to get the actual file URL and dimensions
$.ajax({
url: mw.util.wikiScript('api'),
data: {
action: 'query',
titles: 'File:' + fileName,
prop: 'imageinfo',
iiprop: 'url|size',
format: 'json'
},
dataType: 'json',
success: function(data) {
var pages = data.query.pages;
var url = null;
var width = null;
var height = null;
for (var id in pages) {
if (pages[id].imageinfo && pages[id].imageinfo[0]) {
url = pages[id].imageinfo[0].url;
width = pages[id].imageinfo[0].width;
height = pages[id].imageinfo[0].height;
break;
}
}
if (url) {
// Scale up 2x
var scaledWidth = (width || 32) * 2;
var scaledHeight = (height || 32) * 2;
preview.innerHTML = '<img src="' + url + '" alt="' + spriteName + '" class="pixel-sprite" style="image-rendering: pixelated; width: ' + scaledWidth + 'px; height: ' + scaledHeight + 'px;">';
} else {
preview.innerHTML = '<span style="color: #c33;">Sprite not found: ' + fileName + '</span>';
}
},
error: function() {
preview.innerHTML = '<span style="color: #888;">Preview unavailable</span>';
}
});
}
// Update on input change (debounced)
var timeout;
input.addEventListener('input', function() {
clearTimeout(timeout);
timeout = setTimeout(updatePreview, 500);
});
// Also update when name field changes
if (nameInput) {
nameInput.addEventListener('input', function() {
if (!input.value.trim()) {
clearTimeout(timeout);
timeout = setTimeout(updatePreview, 500);
}
});
}
// Initial preview
updatePreview();
});
return found;
}
/**
* Live infobox preview for item forms
*/
function initInfoboxPreview() {
var containers = document.querySelectorAll('.item-form-container');
console.log('[Apogea] initInfoboxPreview called, found containers:', containers.length);
var found = false;
containers.forEach(function(container, idx) {
var previewDiv = container.querySelector('.infobox-preview');
console.log('[Apogea] Container', idx, '- has previewDiv:', !!previewDiv);
if (!previewDiv) return;
// Skip if already initialized
console.log('[Apogea] Container', idx, '- already initialized:', previewDiv.dataset.initialized);
if (previewDiv.dataset.initialized) return;
previewDiv.dataset.initialized = 'true';
found = true;
// Find variant index from any field in this container
var anyField = container.querySelector('input[name*="["], select[name*="["]');
console.log('[Apogea] Container', idx, '- anyField:', anyField ? anyField.getAttribute('name') : 'none');
var variantIndex = null;
if (anyField) {
var indexMatch = anyField.getAttribute('name').match(/\[(\d+[a-z]?)\]/);
variantIndex = indexMatch ? indexMatch[1] : null;
console.log('[Apogea] Container', idx, '- indexMatch:', indexMatch, '- variantIndex:', variantIndex);
}
console.log('[Apogea] Initializing infobox preview for variant:', variantIndex || 'default');
// Get all form fields in this container
var fields = container.querySelectorAll('input, select, textarea');
console.log('[Apogea] Container', idx, '- field count:', fields.length);
function getFieldValue(fieldName) {
var selector;
if (variantIndex) {
// Scoped to this variant's index
selector = '[name*="[' + variantIndex + '][' + fieldName + ']"]';
} else {
selector = '[name*="[' + fieldName + ']"]';
}
var field = container.querySelector(selector);
return field ? field.value.trim() : '';
}
function updateInfoboxPreview() {
console.log('[Apogea] updateInfoboxPreview called for variant:', variantIndex);
var name = getFieldValue('name') || mw.config.get('wgTitle') || 'Item';
var sprite = getFieldValue('sprite') || name;
var rarity = getFieldValue('rarity') || 'common';
var description = getFieldValue('description');
var damage = getFieldValue('damage');
var armor = getFieldValue('armor');
var defense = getFieldValue('defense');
var health = getFieldValue('health');
var mana = getFieldValue('mana');
var rng = getFieldValue('rng');
var attackSpeed = getFieldValue('attack_speed');
var moveSpeed = getFieldValue('move_speed');
var ability = getFieldValue('ability');
var magic = getFieldValue('magic');
var healthRegen = getFieldValue('health_regen');
var manaRegen = getFieldValue('mana_regen');
var weight = getFieldValue('weight');
var size = getFieldValue('size');
var slots = getFieldValue('container');
var type = getFieldValue('type');
var slot = getFieldValue('slot');
console.log('[Apogea] Variant', variantIndex, '- name:', name, 'sprite:', sprite);
// Build wikitext for preview with all params
var params = [
'preview=true',
'name=' + name,
'sprite=' + sprite,
'rarity=' + rarity,
'float=none'
];
if (description) params.push('description=' + description);
if (damage) params.push('damage=' + damage);
if (armor) params.push('armor=' + armor);
if (defense) params.push('defense=' + defense);
if (health) params.push('health=' + health);
if (mana) params.push('mana=' + mana);
if (rng) params.push('rng=' + rng);
if (attackSpeed) params.push('attack_speed=' + attackSpeed);
if (moveSpeed) params.push('move_speed=' + moveSpeed);
if (ability) params.push('ability=' + ability);
if (magic) params.push('magic=' + magic);
if (healthRegen) params.push('health_regen=' + healthRegen);
if (manaRegen) params.push('mana_regen=' + manaRegen);
if (weight) params.push('weight=' + weight);
if (size) params.push('size=' + size);
if (slots) params.push('container=' + slots);
if (type) params.push('type=' + type);
if (slot) params.push('slot=' + slot);
var wikitext = '{{Infobox Item|' + params.join('|') + '}}';
// Use API to parse the wikitext
$.ajax({
url: mw.util.wikiScript('api'),
data: {
action: 'parse',
text: wikitext,
contentmodel: 'wikitext',
prop: 'text',
format: 'json',
disablelimitreport: true
},
dataType: 'json',
success: function(data) {
if (data.parse && data.parse.text) {
previewDiv.innerHTML = data.parse.text['*'];
} else {
previewDiv.innerHTML = '<em style="color: #888;">Preview unavailable</em>';
}
},
error: function() {
previewDiv.innerHTML = '<em style="color: #888;">Preview unavailable</em>';
}
});
}
// Debounced update
var timeout;
console.log('[Apogea] Attaching listeners to', fields.length, 'fields for variant', variantIndex);
fields.forEach(function(field) {
field.addEventListener('input', function() {
console.log('[Apogea] Input event on field:', field.getAttribute('name'), 'for variant:', variantIndex);
clearTimeout(timeout);
timeout = setTimeout(updateInfoboxPreview, 800);
});
field.addEventListener('change', function() {
console.log('[Apogea] Change event on field:', field.getAttribute('name'), 'for variant:', variantIndex);
clearTimeout(timeout);
timeout = setTimeout(updateInfoboxPreview, 800);
});
});
// Initial preview immediately
updateInfoboxPreview();
});
return found;
}
// Poll for form elements until found
function waitForForm(callback, maxAttempts) {
var attempts = 0;
maxAttempts = maxAttempts || 20;
function check() {
attempts++;
var container = document.querySelector('.item-form-container');
if (container) {
console.log('[Apogea] Form found after ' + attempts + ' attempts');
callback();
} else if (attempts < maxAttempts) {
setTimeout(check, 250);
}
}
check();
}
/**
* Initialize Item Form features (only on FormEdit/Item pages)
*/
function initItemForm() {
// Try immediately
var spriteFound = initSpritePreview();
var infoboxFound = initInfoboxPreview();
// If not found, poll for form to load
if (!spriteFound || !infoboxFound) {
waitForForm(function() {
initSpritePreview();
initInfoboxPreview();
});
}
// Watch for dynamically added fields (e.g., "Add another" in Page Forms)
// Debounced to allow Page Forms to finish rendering new elements
var observerTimeout;
var observer = new MutationObserver(function(mutations) {
console.log('[Apogea] MutationObserver triggered, mutations:', mutations.length);
clearTimeout(observerTimeout);
observerTimeout = setTimeout(function() {
console.log('[Apogea] MutationObserver debounce fired, re-initializing...');
initSpritePreview();
initInfoboxPreview();
}, 300);
});
observer.observe(document.body, { childList: true, subtree: true });
}
// Main initialization
function init() {
console.log('[Apogea] Common.js loaded');
var pageName = mw.config.get('wgPageName');
var canonicalSpecialPage = mw.config.get('wgCanonicalSpecialPageName');
// Item form features - only on FormEdit pages for Item form
if (canonicalSpecialPage === 'FormEdit' && pageName.indexOf('Item') !== -1) {
console.log('[Apogea] Item form page detected');
initItemForm();
}
}
// Wait for DOM and jQuery
$(document).ready(init);
})();