MediaWiki:Gadget-switch-infobox-sandbox.js: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
No edit summary Tag: Reverted |
No edit summary |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
"use strict"; |
|||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } |
|||
/* switch infobox code for infoboxes |
/* switch infobox code for infoboxes |
||
* contains switching code for both: |
* contains switching code for both: |
||
Line 18: | Line 21: | ||
*/ |
*/ |
||
$(function () { |
$(function () { |
||
var SWITCH_REF_REGEX = /^\$(\d+)/, |
|||
CAN_LOCAL_STORAGE = true; |
|||
function getGenderFromLS() { |
|||
if (CAN_LOCAL_STORAGE) { |
|||
var x = window.localStorage.getItem('gender-render'); |
|||
if (['m', 'f'].indexOf(x) > -1) { |
|||
return x; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return 'm'; |
|||
} |
|||
/** |
|||
* Switch infobox psuedo-interface |
|||
* |
|||
* Switch infoboxes are given several similar functions so that they can be called similarly |
|||
* This is essentially like an interface or class structure, except I'm too lazy to implement that |
|||
* |
|||
* switchfo.beginSwitchEvent(event) |
|||
* the reactionary event to buttons being clicked/selects being selected/etc |
|||
* tells SwitchEventManager to switch all the boxes |
|||
* should extract an index and anchor from the currentTarget and pass that to the SwitchEventManager.trigger function |
|||
* event the jQuery event fired from $.click/$.change/etc |
|||
* |
|||
* switchfo.switch(index, anchor) |
|||
* do all the actual switching of the infobox to the infobox specified by the anchor and index |
|||
* prefer using the anchor if there is a conflict |
|||
* |
|||
* switchfo.defaultVer() |
|||
* called during script init |
|||
* returns either an anchor for the default version, if manually specified, or false if there is no default specified |
|||
* the page will automatically switch to the default version, or to version 1, when loaded. |
|||
* |
|||
*/ |
|||
/** |
|||
* Switch Infoboxes based on [[Module:Infobox]] |
|||
* |
|||
* - the preferred way to do switch infoboxes |
|||
* - generates one table and a resources table, swaps resources into the table as required |
|||
* - with enough buttons, becomes a dropdown <select> |
|||
* |
|||
* parameters |
|||
* $box jQuery object representing the infobox itself (.infobox-switch) |
|||
* index index of this infobox, from $.each |
|||
*/ |
|||
function SwitchInfobox($box, index, version_index_offset) { |
|||
var self = this; |
|||
this.index = index; |
|||
this.version_index_offset = version_index_offset; |
|||
this.$infobox = $box; |
|||
this.$infobox.data('SwitchInfobox', self); |
|||
this.$resources = self.$infobox.next(); |
|||
this.$buttons = self.$infobox.find('div.infobox-buttons'); |
|||
this.version_count = this.$buttons.find('span.button').length; |
|||
this.isSelect = self.$buttons.hasClass('infobox-buttons-select'); |
|||
this.$select = null; |
|||
this.originalClasses = {}; |
|||
/* click/change event - triggers switch event manager */ |
|||
this.beginSwitchEvent = function (e) { |
|||
var $tgt = $(e.currentTarget); |
|||
mw.log('beginSwitchEvent triggered in module infobox, id ' + self.index); |
|||
if (self.isSelect) { |
|||
window.switchEventManager.trigger($tgt.val(), $tgt.find(' > option[data-switch-index=' + $tgt.val() + ']').attr('data-switch-anchor'), self); |
|||
} else { |
|||
window.switchEventManager.trigger($tgt.attr('data-switch-index'), $tgt.attr('data-switch-anchor'), self); |
|||
} |
|||
}; |
|||
/* switch event, triggered by manager */ |
|||
this.switchInfobox = function (index, text) { |
|||
if (text === '@init@') { |
|||
text = self.$buttons.find('[data-switch-index="1"]').attr('data-switch-anchor'); |
|||
} |
|||
var ind, |
|||
txt, |
|||
$thisButton = self.$buttons.find('[data-switch-anchor="' + text + '"]'); |
|||
mw.log('switching module infobox, id ' + self.index); |
|||
// prefer text |
|||
if ($thisButton.length) { |
|||
txt = text; |
|||
ind = $thisButton.attr('data-switch-index'); |
|||
} |
|||
if (ind === undefined) { |
|||
return; |
|||
/*ind = index; |
|||
$thisButton = self.$buttons.find('[data-switch-index="'+ind+'"]'); |
|||
if ($thisButton.length) { |
|||
txt = $thisButton.attr('data-switch-anchor'); |
|||
}*/ |
|||
} |
|||
if (txt === undefined) { |
|||
return; |
|||
} |
|||
if (self.isSelect) { |
|||
self.$select.val(ind); |
|||
} else { |
|||
self.$buttons.find('span.button').removeClass('button-selected'); |
|||
$thisButton.addClass('button-selected'); |
|||
} |
|||
self.$infobox.find('[data-attr-param][data-attr-param!=""]').each(function (i, e) { |
|||
var $e = $(e), |
|||
param = $e.attr('data-attr-param'), |
|||
$switches = self.$resources.find('span[data-attr-param="' + param + '"]'), |
|||
m, |
|||
$val, |
|||
$classTgt; |
|||
// check if we found some switch data |
|||
/* click/change event - triggers switch event manager */ |
|||
if (!$switches.length) return; |
|||
this.beginSwitchEvent = function(e) { |
|||
var $tgt = $(e.currentTarget); |
|||
mw.log('beginSwitchEvent triggered in module infobox, id '+self.index); |
|||
if (self.isSelect) { |
|||
window.switchEventManager.trigger($tgt.val(), $tgt.find(' > option[data-switch-index='+$tgt.val()+']').attr('data-switch-anchor'), self); |
|||
} else { |
|||
window.switchEventManager.trigger($tgt.attr('data-switch-index'), $tgt.attr('data-switch-anchor'), self); |
|||
} |
|||
}; |
|||
// find value |
|||
/* switch event, triggered by manager */ |
|||
$val = $switches.find('span[data-attr-index="' + ind + '"]'); |
|||
this.switchInfobox = function(index, text) { |
|||
if (!$val.length) { |
|||
if (text === '@init@') { |
|||
// didn't find it, use default value |
|||
text = self.$buttons.find('[data-switch-index="1"]').attr('data-switch-anchor'); |
|||
$val = $switches.find('span[data-attr-index="0"]'); |
|||
} |
|||
if (!$val.length) return; |
|||
var ind, txt, $thisButton = self.$buttons.find('[data-switch-anchor="'+text+'"]'); |
|||
} |
|||
mw.log('switching module infobox, id '+self.index); |
|||
// switch references support - $2 -> use the value for index 2 |
|||
// prefer text |
|||
m = SWITCH_REF_REGEX.exec($val.html()); |
|||
if ($thisButton.length) { |
|||
if (m) { |
|||
txt = text; |
|||
// m is null if no matches |
|||
ind = $thisButton.attr('data-switch-index'); |
|||
$val = $switches.find('span[data-attr-index="' + m[1] + '"]'); // m is [ entire match, capture ] |
|||
} |
|||
if (!$val.length) { |
|||
if (ind === undefined) { |
|||
$val = $switches.find('span[data-attr-index="0"]'); // fallback again |
|||
return; |
|||
if (!$val.length) return; |
|||
/*ind = index; |
|||
} |
|||
$thisButton = self.$buttons.find('[data-switch-index="'+ind+'"]'); |
|||
} |
|||
if ($thisButton.length) { |
|||
$val = $val.clone(true, true); |
|||
txt = $thisButton.attr('data-switch-anchor'); |
|||
$e.empty().append($val.contents()); |
|||
}*/ |
|||
} |
|||
if (txt === undefined) { |
|||
return; |
|||
} |
|||
if (self.isSelect) { |
|||
self.$select.val(ind); |
|||
} else { |
|||
self.$buttons.find('span.button').removeClass('button-selected'); |
|||
$thisButton.addClass('button-selected'); |
|||
} |
|||
self.$infobox.find('[data-attr-param][data-attr-param!=""]').each(function(i,e) { |
|||
var $e = $(e), |
|||
param = $e.attr('data-attr-param'), |
|||
$switches = self.$resources.find('span[data-attr-param="'+param+'"]'), |
|||
m, |
|||
$val, |
|||
$classTgt; |
|||
// check if we found some switch data |
|||
if (!$switches.length) return; |
|||
// class switching |
|||
// find value |
|||
// find the thing we're switching classes for |
|||
$val = $switches.find('span[data-attr-index="'+ind+'"]'); |
|||
if ($e.is('td, th')) { |
|||
$classTgt = $e.parent('tr'); |
|||
// didn't find it, use default value |
|||
} else { |
|||
$val = $switches.find('span[data-attr-index="0"]'); |
|||
$classTgt = $e; |
|||
if (!$val.length) return; |
|||
} |
|||
} |
|||
// switch references support - $2 -> use the value for index 2 |
|||
m = SWITCH_REF_REGEX.exec($val.html()); |
|||
if (m) { // m is null if no matches |
|||
$val = $switches.find('span[data-attr-index="'+m[1]+'"]'); // m is [ entire match, capture ] |
|||
if (!$val.length) { |
|||
$val = $switches.find('span[data-attr-index="0"]'); // fallback again |
|||
if (!$val.length) return; |
|||
} |
|||
} |
|||
$val = $val.clone(true,true); |
|||
$e.empty().append($val.contents()); |
|||
// reset classes |
|||
// class switching |
|||
if (self.originalClasses.hasOwnProperty(param)) { |
|||
// find the thing we're switching classes for |
|||
$classTgt.attr('class', self.originalClasses[param]); |
|||
if ($e.is('td, th')) { |
|||
} else { |
|||
$classTgt = $e.parent('tr'); |
|||
$classTgt.removeAttr('class'); |
|||
} else { |
|||
} |
|||
$classTgt = $e; |
|||
} |
|||
// change classes if needed |
|||
if ($val.attr('data-addclass') !== undefined) { |
|||
if (self.originalClasses.hasOwnProperty(param)) { |
|||
$classTgt.addClass($val.attr('data-addclass')); |
|||
} |
|||
} else { |
|||
}); |
|||
$classTgt.removeAttr('class'); |
|||
// trigger complete event for inter-script functions |
|||
} |
|||
self.$buttons.trigger('switchinfoboxComplete', { |
|||
txt: txt, |
|||
num: ind |
|||
}); |
|||
//re-initialise quantity boxes, if any |
|||
if (window.rswiki && typeof rswiki.initQtyBox == 'function') { |
|||
rswiki.initQtyBox(self.$infobox); |
|||
} |
|||
//console.log(this); |
|||
}; |
|||
/* default version, return the anchor of the switchable if it exists */ |
|||
// change classes if needed |
|||
this.defaultVer = function () { |
|||
if ($val.attr('data-addclass') !== undefined) { |
|||
var defver = self.$buttons.attr('data-default-version'); |
|||
if (defver !== undefined) { |
|||
} |
|||
return { |
|||
}); |
|||
idx: defver, |
|||
// trigger complete event for inter-script functions |
|||
txt: self.$buttons.find('[data-switch-index="' + defver + '"]').attr('data-switch-anchor') |
|||
self.$buttons.trigger('switchinfoboxComplete', {txt:txt, num:ind}); |
|||
}; |
|||
//re-initialise quantity boxes, if any |
|||
} |
|||
if (window.rswiki && typeof(rswiki.initQtyBox) == 'function') { |
|||
return false; |
|||
rswiki.initQtyBox(self.$infobox) |
|||
}; |
|||
} |
|||
this.isParentOf = function ($triggerer) { |
|||
//console.log(this); |
|||
return self.$infobox.find($triggerer).length > 0; |
|||
}; |
|||
}; |
|||
this.currentlyShowing = function () { |
|||
/* default version, return the anchor of the switchable if it exists */ |
|||
if (self.isSelect) { |
|||
this.defaultVer = function () { |
|||
var sel = self.$select.val(); |
|||
return { |
|||
if (defver !== undefined) { |
|||
index: sel, |
|||
return { idx: defver, txt: self.$buttons.find('[data-switch-index="'+defver+'"]').attr('data-switch-anchor') }; |
|||
text: self.$select.find('option[value="' + sel + '"]').attr('data-switch-anchor') |
|||
} |
|||
}; |
|||
return false; |
|||
} else { |
|||
}; |
|||
var buttn = self.$buttons.find('.button-selected'); |
|||
return { |
|||
this.isParentOf = function ($triggerer) { |
|||
index: buttn.attr('data-switch-index'), |
|||
return self.$infobox.find($triggerer).length > 0; |
|||
text: buttn.attr('data-switch-anchor') |
|||
}; |
|||
}; |
|||
} |
|||
this.currentlyShowing = function(){ |
|||
}; |
|||
if (self.isSelect) { |
|||
var sel = self.$select.val(); |
|||
return {index: sel, text: self.$select.find('option[value="'+sel+'"]').attr('data-switch-anchor')} |
|||
} else { |
|||
var buttn = self.$buttons.find('.button-selected'); |
|||
return {index: buttn.attr('data-switch-index'), text: buttn.attr('data-switch-anchor')} |
|||
} |
|||
} |
|||
/* init */ |
|||
mw.log('setting up module infobox, id ' + self.index); |
|||
// setup original classes |
|||
this.$infobox.find('[data-attr-param][data-attr-param!=""]').each(function (i, e) { |
|||
var $e = $(e), |
|||
$classElem = $e, |
|||
if ($e.is('td, th')) { |
|||
clas; |
|||
$classElem = $e.parent('tr'); |
|||
if ($e.is('td, th')) { |
|||
} |
|||
$classElem = $e.parent('tr'); |
|||
} |
|||
if (typeof clas === 'string') { |
|||
clas = $classElem.attr('class'); |
|||
self.originalClasses[$e.attr('data-attr-param')] = clas; |
|||
if (typeof clas === 'string') { |
|||
} |
|||
self.originalClasses[$e.attr('data-attr-param')] = clas; |
|||
}); |
|||
} |
|||
}); |
|||
// setup select/buttons and events |
|||
if (self.isSelect) { |
|||
self.$select = $('<select>').attr({ |
|||
id: 'infobox-select-' + self.index, |
|||
.attr({ |
|||
name: 'infobox-select-' + self.index |
|||
}); |
|||
name: 'infobox-select-' + self.index, |
|||
self.$buttons.find('span.button').each(function (i, e) { |
|||
}); |
|||
var $e = $(e); |
|||
self.$buttons.find('span.button').each(function(i, e){ |
|||
self.$select.append($('<option>').attr({ |
|||
var $e = $(e); |
|||
value: $e.attr('data-switch-index'), |
|||
self.$select.append( |
|||
'data-switch-index': $e.attr('data-switch-index'), |
|||
$('<option>').attr({ |
|||
'data-switch-anchor': $e.attr('data-switch-anchor') |
|||
}).text($e.text())); |
|||
'data-switch-index': $e.attr('data-switch-index'), |
|||
}); |
|||
'data-switch-anchor': $e.attr('data-switch-anchor') |
|||
self.$buttons.empty().append(self.$select); |
|||
}).text($e.text()) |
|||
self.$select.change(self.beginSwitchEvent); |
|||
); |
|||
} else { |
|||
}); |
|||
self.$buttons.attr({ |
|||
id: 'infobox-buttons-' + self.index |
|||
self.$select.change(self.beginSwitchEvent); |
|||
}).find('span').each(function (i, e) { |
|||
} else { |
|||
$(e).click(self.beginSwitchEvent); |
|||
self.$buttons |
|||
}); |
|||
.attr({ |
|||
} |
|||
id: 'infobox-buttons-'+self.index |
|||
self.$buttons.css('display', 'flex'); |
|||
}) |
|||
self.switchInfobox(1, '@init@'); |
|||
.find('span').each(function(i,e) { |
|||
window.switchEventManager.addSwitchInfobox(this); |
|||
$(e).click(self.beginSwitchEvent); |
|||
if (this.$infobox.find('.infobox-bonuses-image.render-m').length === 1 && this.$infobox.find('.infobox-bonuses-image.render-f').length === 1) { |
|||
}); |
|||
this.genderswitch = new GenderRenderSwitcher(this.$infobox, this.index); |
|||
} |
|||
} |
|||
} |
|||
/** |
|||
self.$buttons.css('display', 'flex'); |
|||
* Special support for gender render switching in infobox bonuses (& synced switch) |
|||
self.switchInfobox(1, '@init@'); |
|||
* Currently specifically only supports male & female |
|||
* potential TODO: generalise? |
|||
* |
|||
* parameters |
|||
* $box jQuery object representing the infobox itself (.infobox-switch) |
|||
*/ |
|||
function GenderRenderSwitcher($box, index, version_index_offset) { |
|||
var self = this; |
|||
this.$box = $box; |
|||
this.$box.data('SwitchInfobox', self); |
|||
this.index = index; |
|||
this.version_index_offset = version_index_offset; |
|||
this.version_count = 2; |
|||
this.$buttons = $('<div>').addClass('infobox-buttons').css('display', 'flex'); |
|||
this.button = { |
|||
m: $('<span>').addClass('button').attr('data-gender-render', 'm').text('Male'), |
|||
f: $('<span>').addClass('button').attr('data-gender-render', 'f').text('Female') |
|||
}; |
|||
this.$td = $('<td>'); |
|||
this.$td_inner = $('<div class="gender-render-inner">'); |
|||
this.visible_gender = ''; |
|||
// from interface, we can just get the SyncedSwitches to switch |
|||
window.switchEventManager.addSwitchInfobox(this); |
|||
this.beginSwitchEvent = function (event) { |
|||
if (this.$infobox.find('.infobox-bonuses-image.render-m').length === 1 && this.$infobox.find('.infobox-bonuses-image.render-f').length === 1) { |
|||
var $e = $(event.currentTarget); |
|||
this.genderswitch = new GenderRenderSwitcher(this.$infobox, this.index); |
|||
var gen = $e.attr('data-gender-render'); |
|||
} |
|||
mw.log('beginSwitchEvent for genderswitcher ' + self.index + ' - switching to ' + gen); |
|||
} |
|||
window.switchEventManager.triggerGenderRenderSwitch(gen); |
|||
if (CAN_LOCAL_STORAGE) { |
|||
/** |
|||
window.localStorage.setItem('gender-render', gen); |
|||
* Special support for gender render switching in infobox bonuses (& synced switch) |
|||
} |
|||
* Currently specifically only supports male & female |
|||
}; |
|||
* potential TODO: generalise? |
|||
// do the actual switching |
|||
* |
|||
this.genderSwitch = function (gender) { |
|||
* parameters |
|||
mw.log('switching gender for genderswitcher for ' + self.index + ' to ' + gender); |
|||
* $box jQuery object representing the infobox itself (.infobox-switch) |
|||
self.$buttons.find('.button-selected').removeClass('button-selected'); |
|||
*/ |
|||
self.button[gender].addClass('button-selected'); |
|||
function GenderRenderSwitcher($box, index, version_index_offset) { |
|||
var x = self.$box.find('.infobox-bonuses-image.render-' + gender + ''); |
|||
var self = this; |
|||
self.$td_inner.empty().append(x.find('>*').clone()); |
|||
this.$box = $box; |
|||
self.visible_gender = gender; |
|||
this.$box.data('SwitchInfobox', self); |
|||
}; |
|||
this.index = index; |
|||
this.refreshImage = function (index, anchor) { |
|||
this.version_index_offset = version_index_offset; |
|||
// for when a main infobox switch happens |
|||
this.version_count = 2; |
|||
// this is a post-switch function so the new images are in the original cells |
|||
this.$buttons = $('<div>').addClass('infobox-buttons').css('display', 'flex'); |
|||
// we just gotta clone them into the visible cell again |
|||
this.button = { |
|||
self.genderSwitch(self.visible_gender); |
|||
m: $('<span>').addClass('button').attr('data-gender-render', 'm').text('Male'), |
|||
mw.log('refreshed image for genderswitcher ' + self.index); |
|||
f: $('<span>').addClass('button').attr('data-gender-render', 'f').text('Female') |
|||
}; |
|||
this.currentlyShowing = function () { |
|||
return { |
|||
this.$td_inner = $('<div class="gender-render-inner">'); |
|||
index: -1, |
|||
this.visible_gender = ''; |
|||
text: self.visible_gender |
|||
}; |
|||
// from interface, we can just get the SyncedSwitches to switch |
|||
}; |
|||
this.beginSwitchEvent = function(event){ |
|||
var $e = $(event.currentTarget); |
|||
var gen = $e.attr('data-gender-render'); |
|||
mw.log('beginSwitchEvent for genderswitcher '+self.index+' - switching to '+gen); |
|||
window.switchEventManager.triggerGenderRenderSwitch(gen); |
|||
if (CAN_LOCAL_STORAGE) { |
|||
window.localStorage.setItem('gender-render', gen); |
|||
} |
|||
}; |
|||
// do the actual switching |
|||
this.genderSwitch = function(gender) { |
|||
mw.log('switching gender for genderswitcher for '+self.index+' to '+gender); |
|||
self.$buttons.find('.button-selected').removeClass('button-selected'); |
|||
self.button[gender].addClass('button-selected'); |
|||
// other 'interface' methods just so stuff doesn't break, just in case |
|||
var x = self.$box.find('.infobox-bonuses-image.render-'+gender+''); |
|||
this.switchInfobox = function (ind, anchor) {/* do nothing */}; |
|||
self.$td_inner.empty().append(x.find('>*').clone()); |
|||
this.defaultVer = function () { |
|||
self.visible_gender = gender; |
|||
return false; |
|||
}; |
|||
}; |
|||
this.refreshImage = function(index,anchor) { |
|||
mw.log('Initialising genderswitcher for ' + self.index); |
|||
// for when a main infobox switch happens |
|||
var $c_m = this.$box.find('.infobox-bonuses-image.render-m'), |
|||
// this is a post-switch function so the new images are in the original cells |
|||
$c_f = this.$box.find('.infobox-bonuses-image.render-f'); |
|||
// we just gotta clone them into the visible cell again |
|||
this.$td.addClass('gender-render').attr({ |
|||
self.genderSwitch(self.visible_gender); |
|||
'style': $c_m.attr('style'), |
|||
mw.log('refreshed image for genderswitcher '+self.index); |
|||
'rowspan': $c_m.attr('rowspan') |
|||
}; |
|||
}).append(this.$td_inner); |
|||
this.currentlyShowing = function(){ |
|||
$c_m.parent().append(this.$td); |
|||
return {index: -1, text: self.visible_gender} |
|||
this.$buttons.append(this.button.m, this.button.f); |
|||
} |
|||
this.$td.append(this.$buttons); |
|||
this.$buttons.find('span.button').on('click', this.beginSwitchEvent); |
|||
// other 'interface' methods just so stuff doesn't break, just in case |
|||
$c_m.addClass('gender-render-hidden').attr('data-gender-render', 'm'); |
|||
this.switchInfobox = function(ind,anchor){/* do nothing */}; |
|||
$c_f.addClass('gender-render-hidden').attr('data-gender-render', 'f'); |
|||
this.defaultVer = function(){ return false; }; |
|||
window.switchEventManager.addGenderRenderSwitch(self); |
|||
window.switchEventManager.addPostSwitchEvent(this.refreshImage); |
|||
this.genderSwitch(getGenderFromLS()); |
|||
} |
|||
/** |
|||
mw.log('Initialising genderswitcher for '+self.index); |
|||
* Legacy switch infoboxes, as generated by [[Template:Switch infobox]] |
|||
var $c_m = this.$box.find('.infobox-bonuses-image.render-m'), $c_f=this.$box.find('.infobox-bonuses-image.render-f'); |
|||
* |
|||
this.$td.addClass('gender-render').attr({ |
|||
* |
|||
'style': $c_m.attr('style'), |
|||
* parameters |
|||
'rowspan': $c_m.attr('rowspan') |
|||
* $box jQuery object representing the infobox itself (.switch-infobox) |
|||
}).append(this.$td_inner); |
|||
* index index of this infobox, from $.each |
|||
$c_m.parent().append(this.$td); |
|||
*/ |
|||
this.$buttons.append(this.button.m, this.button.f); |
|||
function LegacySwitchInfobox($box, index, version_index_offset) { |
|||
this.$td.append(this.$buttons); |
|||
var self = this; |
|||
this.$buttons.find('span.button').on('click', this.beginSwitchEvent); |
|||
this.$infobox = $box; |
|||
this.$infobox.data('SwitchInfobox', self); |
|||
this.$parent = $box; |
|||
this.index = index; |
|||
this.version_index_offset = version_index_offset; |
|||
this.$originalButtons = self.$parent.find('.switch-infobox-triggers'); |
|||
this.$items = self.$parent.find('.item'); |
|||
this.version_count = self.$originalButtons.find('span.trigger.button').length; |
|||
/* click/change event - triggers switch event manager */ |
|||
$c_m.addClass('gender-render-hidden').attr('data-gender-render', 'm'); |
|||
this.beginSwitchEvent = function (e) { |
|||
$c_f.addClass('gender-render-hidden').attr('data-gender-render', 'f'); |
|||
var $tgt = $(e.currentTarget); |
|||
window.switchEventManager.addGenderRenderSwitch(self); |
|||
mw.log('beginSwitchEvent triggered in legacy infobox, id ' + self.index); |
|||
window.switchEventManager.addPostSwitchEvent(this.refreshImage); |
|||
window.switchEventManager.trigger($tgt.attr('data-id'), $tgt.attr('data-anchor'), self); |
|||
this.genderSwitch(getGenderFromLS()); |
|||
}; |
|||
} |
|||
/* click/change event - triggers switch event manager */ |
|||
/** |
|||
this.switchInfobox = function (index, text) { |
|||
* Legacy switch infoboxes, as generated by [[Template:Switch infobox]] |
|||
if (text === '@init@') { |
|||
* |
|||
text = self.$buttons.find('[data-id="1"]').attr('data-anchor'); |
|||
* |
|||
} |
|||
* parameters |
|||
var ind, |
|||
* $box jQuery object representing the infobox itself (.switch-infobox) |
|||
txt, |
|||
* index index of this infobox, from $.each |
|||
$thisButton = self.$buttons.find('[data-anchor="' + text + '"]').first(); |
|||
*/ |
|||
mw.log('switching legacy infobox, id ' + self.index); |
|||
function LegacySwitchInfobox($box, index, version_index_offset) { |
|||
if ($thisButton.length) { |
|||
var self = this; |
|||
txt = text; |
|||
this.$infobox = $box; |
|||
ind = $thisButton.attr('data-id'); |
|||
this.$infobox.data('SwitchInfobox', self); |
|||
} else { |
|||
this.$parent = $box; |
|||
return; |
|||
this.index = index; |
|||
/*ind = index; |
|||
this.version_index_offset = version_index_offset; |
|||
$thisButton = self.$buttons.find('[data-id="'+ind+'"]'); |
|||
if ($thisButton.length) { |
|||
this.$items = self.$parent.find('.item'); |
|||
txt = $thisButton.attr('data-anchor'); |
|||
this.version_count = self.$originalButtons.find('span.trigger.button').length; |
|||
}*/ |
|||
} |
|||
if (txt === undefined) { |
|||
return; |
|||
} |
|||
self.$buttons.find('.trigger').removeClass('button-selected'); |
|||
self.$buttons.find('.trigger[data-id="' + ind + '"]').addClass('button-selected'); |
|||
self.$items.filter('.showing').removeClass('showing'); |
|||
self.$items.filter('[data-id="' + ind + '"]').addClass('showing'); |
|||
}; |
|||
/* default version - not supported by legacy, always false */ |
|||
/* click/change event - triggers switch event manager */ |
|||
this.defaultVer = function () { |
|||
return false; |
|||
var $tgt = $(e.currentTarget); |
|||
}; |
|||
mw.log('beginSwitchEvent triggered in legacy infobox, id '+self.index); |
|||
this.isParentOf = function ($triggerer) { |
|||
window.switchEventManager.trigger($tgt.attr('data-id'), $tgt.attr('data-anchor'), self); |
|||
return self.$parent.find($triggerer).length > 0; |
|||
}; |
|||
}; |
|||
this.currentlyShowing = function () { |
|||
var buttn = self.$buttons.find('.button-selected'); |
|||
return { |
|||
index: buttn.attr('data-id'), |
|||
text: buttn.attr('data-anchor') |
|||
}; |
|||
}; |
|||
/* init */ |
|||
/* click/change event - triggers switch event manager */ |
|||
mw.log('setting up legacy infobox, id ' + self.index); |
|||
this.switchInfobox = function(index, text){ |
|||
// add anchor text |
|||
if (text === '@init@') { |
|||
self.$originalButtons.find('span.trigger.button').each(function (i, e) { |
|||
var $e = $(e); |
|||
} |
|||
var anchorText = $e.text().split(' ').join('_'); |
|||
var ind, txt, $thisButton = self.$buttons.find('[data-anchor="'+text+'"]').first(); |
|||
$e.attr('data-anchor', '#' + anchorText); |
|||
mw.log('switching legacy infobox, id '+self.index); |
|||
}); |
|||
if ($thisButton.length) { |
|||
txt = text; |
|||
ind = $thisButton.attr('data-id'); |
|||
} else { |
|||
return; |
|||
/*ind = index; |
|||
$thisButton = self.$buttons.find('[data-id="'+ind+'"]'); |
|||
if ($thisButton.length) { |
|||
txt = $thisButton.attr('data-anchor'); |
|||
}*/ |
|||
} |
|||
if (txt === undefined) { |
|||
return; |
|||
} |
|||
self.$buttons.find('.trigger').removeClass('button-selected'); |
|||
self.$buttons.find('.trigger[data-id="'+ind+'"]').addClass('button-selected'); |
|||
self.$items.filter('.showing').removeClass('showing'); |
|||
self.$items.filter('[data-id="'+ind+'"]').addClass('showing'); |
|||
}; |
|||
/* default version - not supported by legacy, always false */ |
|||
this.defaultVer = function () { return false; }; |
|||
this.isParentOf = function ($triggerer) { |
|||
return self.$parent.find($triggerer).length > 0; |
|||
}; |
|||
this.currentlyShowing = function(){ |
|||
var buttn = self.$buttons.find('.button-selected'); |
|||
return {index: buttn.attr('data-id'), text: buttn.attr('data-anchor')} |
|||
} |
|||
// append triggers to every item |
|||
/* init */ |
|||
// if contents has a infobox, add to a caption of that |
|||
mw.log('setting up legacy infobox, id '+self.index); |
|||
// else just put at top |
|||
// add anchor text |
|||
self.$items.each(function (i, e) { |
|||
var $item = $(e); |
|||
if ($item.find('table.infobox').length > 0) { |
|||
var anchorText = $e.text().split(' ').join('_'); |
|||
if ($item.find('table.infobox caption').length < 1) { |
|||
$e.attr('data-anchor', '#'+anchorText); |
|||
$item.find('table.infobox').prepend('<caption>'); |
|||
}); |
|||
} |
|||
$item.find('table.infobox caption').first().prepend(self.$originalButtons.clone()); |
|||
} else { |
|||
$item.prepend(self.$originalButtons.clone()); |
|||
} |
|||
}); |
|||
// remove buttons from current location |
|||
self.$originalButtons.remove(); |
|||
// update selection |
|||
// append triggers to every item |
|||
this.$buttons = self.$parent.find('.switch-infobox-triggers'); |
|||
// if contents has a infobox, add to a caption of that |
|||
self.$buttons.find('.trigger').each(function (i, e) { |
|||
// else just put at top |
|||
$(e).click(self.beginSwitchEvent); |
|||
self.$items.each(function(i,e){ |
|||
}); |
|||
self.switchInfobox(1, '@init@'); |
|||
if ($item.find('table.infobox').length > 0) { |
|||
window.switchEventManager.addSwitchInfobox(this); |
|||
if ($item.find('table.infobox caption').length < 1) { |
|||
self.$parent.removeClass('loading').find('span.loading-button').remove(); |
|||
$item.find('table.infobox').prepend('<caption>'); |
|||
} |
|||
} |
|||
$item.find('table.infobox caption').first().prepend(self.$originalButtons.clone()); |
|||
} else { |
|||
$item.prepend(self.$originalButtons.clone()); |
|||
} |
|||
}); |
|||
// remove buttons from current location |
|||
self.$originalButtons.remove(); |
|||
/** |
|||
// update selection |
|||
* Synced switches, as generated by [[Template:Synced switch]] |
|||
this.$buttons = self.$parent.find('.switch-infobox-triggers'); |
|||
* |
|||
self.$buttons.find('.trigger').each(function (i,e) { |
|||
* |
|||
$(e).click(self.beginSwitchEvent); |
|||
* parameters |
|||
}); |
|||
* $box jQuery object representing the synced switch itself (.rsw-synced-switch) |
|||
self.switchInfobox(1, '@init@'); |
|||
* index index of this infobox, from $.each |
|||
*/ |
|||
window.switchEventManager.addSwitchInfobox(this); |
|||
function SyncedSwitch($box, index, version_index_offset) { |
|||
self.$parent.removeClass('loading').find('span.loading-button').remove(); |
|||
var self = this; |
|||
} |
|||
this.index = index; |
|||
this.version_index_offset = version_index_offset; //not actually used |
|||
this.version_count = 0; // we don't increment from this |
|||
this.$syncedswitch = $box; |
|||
this.$syncedswitch.data('SwitchInfobox', self); |
|||
this.attachedLabels = false; |
|||
this.is_synced_switch = true; |
|||
/* filling in interface - synced switch has no buttons to press so cannot trigger an event by itself */ |
|||
/** |
|||
this.beginSwitchEvent = function () {}; |
|||
* Synced switches, as generated by [[Template:Synced switch]] |
|||
this.switchInfobox = function (index, text) { |
|||
* |
|||
mw.log('switching synced switch, id ' + self.index + ", looking for " + index + ' - ' + text); |
|||
* |
|||
if (text === '@init@') { |
|||
* parameters |
|||
text = self.$syncedswitch.find('[data-item="1"]').attr('data-item-text'); |
|||
* $box jQuery object representing the synced switch itself (.rsw-synced-switch) |
|||
} |
|||
* index index of this infobox, from $.each |
|||
var $toShow = self.$syncedswitch.find('[data-item-text="' + text + '"]'); |
|||
*/ |
|||
if (!(self.attachedLabels && $toShow.length)) { |
|||
function SyncedSwitch($box, index, version_index_offset) { |
|||
//return; |
|||
var self = this; |
|||
$toShow = self.$syncedswitch.find('[data-item="' + index + '"]'); |
|||
this.index = index; |
|||
} |
|||
this.version_index_offset = version_index_offset; //not actually used |
|||
if (!$toShow.length) { |
|||
this.version_count = 0; // we don't increment from this |
|||
// show default instead |
|||
this.$syncedswitch = $box; |
|||
self.$syncedswitch.find('.rsw-synced-switch-item').removeClass('showing'); |
|||
self.$syncedswitch.find('[data-item="0"]').addClass('showing'); |
|||
this.attachedLabels = false; |
|||
} else { |
|||
this.is_synced_switch = true; |
|||
self.$syncedswitch.find('.rsw-synced-switch-item').removeClass('showing'); |
|||
$toShow.addClass('showing'); |
|||
} |
|||
}; |
|||
this.genderSwitch = function (gender) { |
|||
var $gens = self.$syncedswitch.find('.render-m, .render-f'); |
|||
var srch = '.render-' + gender; |
|||
if ($gens.length) { |
|||
$gens.each(function (i, e) { |
|||
var $e = $(e); |
|||
if ($e.is(srch)) { |
|||
$e.removeClass('gender-render-hidden').addClass('gender-render-showing'); |
|||
} else { |
|||
$e.removeClass('gender-render-showing').addClass('gender-render-hidden'); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
/* default version - not supported by synced switches, always false */ |
|||
/* filling in interface - synced switch has no buttons to press so cannot trigger an event by itself */ |
|||
this.defaultVer = function () { |
|||
return false; |
|||
}; |
|||
this.isParentOf = function ($triggerer) { |
|||
return self.$syncedswitch.find($triggerer).length > 0; |
|||
}; |
|||
this.currentlyShowing = function () { |
|||
var buttn = self.$syncedswitch.find('.rsw-synced-switch-item.showing'); |
|||
return { |
|||
index: buttn.attr('data-item'), |
|||
text: buttn.attr('data-item-text') |
|||
}; |
|||
}; |
|||
/* init */ |
|||
this.switchInfobox = function(index, text){ |
|||
mw.log('setting up synced switch, id ' + self.index); |
|||
// attempt to apply some button text from a SwitchInfobox |
|||
if (text === '@init@') { |
|||
if ($('.infobox.infobox-switch').length && !$('.multi-infobox').length) { |
|||
text = self.$syncedswitch.find('[data-item="1"]').attr('data-item-text'); |
|||
self.attachedLabels = true; |
|||
} |
|||
var $linkedButtonTextInfobox = $('.infobox.infobox-switch').first(); |
|||
var $toShow = self.$syncedswitch.find('[data-item-text="'+text+'"]'); |
|||
self.$syncedswitch.find('.rsw-synced-switch-item').each(function (i, e) { |
|||
if (!(self.attachedLabels && $toShow.length)) { |
|||
var $e = $(e); |
|||
//return; |
|||
if ($e.attr('data-item-text') === undefined) { |
|||
$toShow = self.$syncedswitch.find('[data-item="'+index+'"]'); |
|||
$e.attr('data-item-text', $linkedButtonTextInfobox.find('[data-switch-index="' + i + '"]').attr('data-switch-anchor')); |
|||
} |
|||
} |
|||
if (!$toShow.length) { |
|||
}); |
|||
// show default instead |
|||
} |
|||
self.$syncedswitch.find('.rsw-synced-switch-item').removeClass('showing'); |
|||
self.switchInfobox(1, '@init@'); |
|||
self.$syncedswitch.find('[data-item="0"]').addClass('showing'); |
|||
window.switchEventManager.addSwitchInfobox(this); |
|||
} else { |
|||
if (self.$syncedswitch.find('.render-m, .render-f').length) { |
|||
window.switchEventManager.addGenderRenderSwitch(self); |
|||
$toShow.addClass('showing'); |
|||
this.genderSwitch(getGenderFromLS()); |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
/** |
|||
this.genderSwitch = function(gender){ |
|||
* An infobox that doesn't switch |
|||
var $gens = self.$syncedswitch.find('.render-m, .render-f'); |
|||
* used to make sure MultiInfoboxes interact with SyncedSwitches correctly |
|||
var srch = '.render-'+gender; |
|||
* |
|||
if ($gens.length) { |
|||
*/ |
|||
$gens.each(function(i,e){ |
|||
function NonSwitchingInfobox($box, index, version_index_offset) { |
|||
var $e = $(e); |
|||
var self = this; |
|||
if ($e.is(srch)) { |
|||
this.$infobox = $box; |
|||
$e.removeClass('gender-render-hidden').addClass('gender-render-showing'); |
|||
this.index = index; |
|||
} else { |
|||
this.version_index_offset = version_index_offset; |
|||
$e.removeClass('gender-render-showing').addClass('gender-render-hidden'); |
|||
this.$infobox.data('SwitchInfobox', self); |
|||
} |
|||
this.version_count = 1; |
|||
}); |
|||
this.beginSwitchEvent = function () {}; //do nothing |
|||
} |
|||
this.switchInfobox = function (index, text) { |
|||
}; |
|||
return; |
|||
}; //do nothing |
|||
/* default version - not supported by synced switches, always false */ |
|||
this.defaultVer = function () { |
|||
return true; |
|||
}; |
|||
this.isParentOf = function ($triggerer) { |
|||
this.isParentOf = function ($triggerer) { |
|||
return false; |
|||
}; |
|||
}; |
|||
this.currentlyShowing = function(){ |
|||
this.currentlyShowing = function () { |
|||
var buttn = self.$syncedswitch.find('.rsw-synced-switch-item.showing'); |
|||
return { |
|||
return {index: buttn.attr('data-item'), text: buttn.attr('data-item-text')} |
|||
text: null, |
|||
} |
|||
index: 1 |
|||
}; |
|||
/* init */ |
|||
}; |
|||
mw.log('setting up synced switch, id '+self.index); |
|||
} |
|||
// attempt to apply some button text from a SwitchInfobox |
|||
if ($('.infobox.infobox-switch').length && !$('.multi-infobox').length) { |
|||
self.attachedLabels = true; |
|||
var $linkedButtonTextInfobox = $('.infobox.infobox-switch').first(); |
|||
self.$syncedswitch.find('.rsw-synced-switch-item').each(function(i,e){ |
|||
var $e = $(e); |
|||
if ($e.attr('data-item-text') === undefined) { |
|||
$e.attr('data-item-text', $linkedButtonTextInfobox.find('[data-switch-index="'+i+'"]').attr('data-switch-anchor')); |
|||
} |
|||
}); |
|||
} |
|||
self.switchInfobox(1, '@init@'); |
|||
window.switchEventManager.addSwitchInfobox(this); |
|||
if (self.$syncedswitch.find('.render-m, .render-f').length) { |
|||
window.switchEventManager.addGenderRenderSwitch(self); |
|||
this.genderSwitch(getGenderFromLS()); |
|||
} |
|||
} |
|||
/** |
|||
* An infobox that doesn't switch |
|||
* used to make sure MultiInfoboxes interact with SyncedSwitches correctly |
|||
* |
|||
*/ |
|||
function NonSwitchingInfobox($box, index, version_index_offset){ |
|||
var self = this; |
|||
this.$infobox = $box; |
|||
this.index = index; |
|||
this.version_index_offset = version_index_offset; |
|||
this.$infobox.data('SwitchInfobox', self); |
|||
this.version_count = 1; |
|||
this.beginSwitchEvent = function (){}; //do nothing |
|||
this.switchInfobox = function(index, text){return}; //do nothing |
|||
this.defaultVer = function () {return true;}; |
|||
this.isParentOf = function ($triggerer) {return false;}; |
|||
this.currentlyShowing = function(){ |
|||
return {text:null, index: 1}; |
|||
}; |
|||
} |
|||
/** |
|||
* Event manager |
|||
* Observer pattern |
|||
* Globally available as window.switchEventManager |
|||
* |
|||
* Methods |
|||
* addSwitchInfobox(l) |
|||
* adds switch infobox (of any type) to the list of switch infoboxes listening to trigger events |
|||
* l switch infobox |
|||
* |
|||
* addPreSwitchEvent(f) |
|||
* adds the function to a list of functions that runs when the switch event is triggered but before any other action is taken |
|||
* the function is passed the index and anchor (in that order) that was passed to the trigger function |
|||
* returning the boolean true from the function will cancel the switch event |
|||
* trying to add a non-function is a noop |
|||
* e function to run |
|||
* |
|||
* addPostSwitchEvent(f) |
|||
* adds the function to a list of functions that runs when the switch event is completed, after all of the switching is completed (including the hash change) |
|||
* the function is passed the index and anchor (in that order) that was passed to the trigger function |
|||
* the return value is ignored |
|||
* trying to add a non-function is a noop |
|||
* e function to run |
|||
* |
|||
* trigger(i, a) |
|||
* triggers the switch event on all listeners |
|||
* will prefer switching to the anchor if available |
|||
* i index to switch to |
|||
* a anchor to switch to |
|||
* |
|||
* makeSwitchInfobox($box) |
|||
* creates the correct object for the passed switch infobox, based on the classes of the infobox |
|||
* is a noop if it does not match any of the selectors |
|||
* infobox is given an index based on the internal counter for the switch |
|||
* $box jQuery object for the switch infobox (the jQuery object passed to the above functions, see above for selectors checked) |
|||
* |
|||
* addIndex(i) |
|||
* updates the internal counter by adding i to it |
|||
* if i is not a number or is negative, is a noop |
|||
* used for manually setting up infoboxes (init) or creating a new type to plugin |
|||
* i number to add |
|||
*/ |
|||
function SwitchEventManager() { |
|||
var self = this, |
|||
var self = this, switchInfoboxes = [], syncedSwitches=[], genderRenderSwitchers = [], preSwitchEvents = [], postSwitchEvents = [], index = 0, version_offset = 0; |
|||
switchInfoboxes = [], |
|||
window.switchEventManager = this; |
|||
syncedSwitches = [], |
|||
genderRenderSwitchers = [], |
|||
// actual switch infoboxes to change |
|||
preSwitchEvents = [], |
|||
this.addSwitchInfobox = function(l) { |
|||
postSwitchEvents = [], |
|||
switchInfoboxes.push(l); |
|||
index = 0, |
|||
if (l.is_synced_switch) { |
|||
version_offset = 0; |
|||
syncedSwitches.push(l); |
|||
window.switchEventManager = this; |
|||
} |
|||
}; |
|||
// actual switch infoboxes to change |
|||
this.addGenderRenderSwitch = function(gs) { |
|||
this.addSwitchInfobox = function (l) { |
|||
gs.version_index_offset = version_offset; |
|||
switchInfoboxes.push(l); |
|||
if (l.is_synced_switch) { |
|||
version_offset += gs.version_count; |
|||
syncedSwitches.push(l); |
|||
}; |
|||
} |
|||
}; |
|||
// things to do when switch button is clicked but before any switching |
|||
this.addGenderRenderSwitch = function (gs) { |
|||
gs.version_index_offset = version_offset; |
|||
if (typeof(e) === 'function') { |
|||
genderRenderSwitchers.push(gs); |
|||
version_offset += gs.version_count; |
|||
} |
|||
}; |
|||
this.addPostSwitchEvent = function(e) { |
|||
if (typeof(e) === 'function') { |
|||
postSwitchEvents.push(e); |
|||
} |
|||
}; |
|||
// things to do when switch button is clicked but before any switching |
|||
this.trigger = function(index, anchor, triggerer) { |
|||
this.addPreSwitchEvent = function (e) { |
|||
mw.log('Triggering switch event for index '+index+'; text '+anchor); |
|||
if (typeof e === 'function') { |
|||
// using a real for loop so we can use return to exit the trigger function |
|||
preSwitchEvents.push(e); |
|||
} |
|||
var ret = preSwitchEvents[i](index,anchor); |
|||
}; |
|||
if (typeof(ret) === 'boolean') { |
|||
this.addPostSwitchEvent = function (e) { |
|||
if (ret) { |
|||
if (typeof e === 'function') { |
|||
mw.log('switching was cancelled'); |
|||
postSwitchEvents.push(e); |
|||
return; |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
this.trigger = function (index, anchor, triggerer) { |
|||
} |
|||
mw.log('Triggering switch event for index ' + index + '; text ' + anchor); |
|||
// using a real for loop so we can use return to exit the trigger function |
|||
for (var i = 0; i < preSwitchEvents.length; i++) { |
|||
var ret = preSwitchEvents[i](index, anchor); |
|||
if (typeof ret === 'boolean') { |
|||
if (ret) { |
|||
mw.log('switching was cancelled'); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
// close all tooltips on the page |
|||
$('.js-tooltip-wrapper').trigger('js-tooltip-close'); |
|||
// trigger switching on listeners |
|||
switchInfoboxes.forEach(function (e) { |
|||
if (triggerer === null || !e.isParentOf(triggerer.$infobox)) { |
|||
if (e.is_synced_switch && triggerer !== null) { |
|||
e.switchInfobox(parseInt(index) + triggerer.version_index_offset, anchor); |
|||
} else { |
|||
e.switchInfobox(index, anchor); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
// update hash |
|||
if (typeof anchor === 'string') { |
|||
var _anchor = anchor; |
|||
if (_anchor === '@init@') { |
|||
_anchor = ''; |
|||
} |
|||
} |
|||
if (window.history && window.history.replaceState) { |
|||
if (window.location.hash !== '') { |
|||
window.history.replaceState({}, '', window.location.href.replace(window.location.hash, _anchor)); |
|||
} else { |
|||
window.history.replaceState({}, '', window.location.href.replace(window.location.hash, _anchor)); |
|||
window.history.replaceState({}, '', window.location.href + _anchor); |
|||
} else { |
|||
} |
|||
window.history.replaceState({}, '', window.location.href + _anchor); |
|||
} else { |
|||
} |
|||
// replaceState not supported, I guess we just change the hash normally? |
|||
} else { |
|||
window.location.hash = _anchor; |
|||
// replaceState not supported, I guess we just change the hash normally? |
|||
} |
|||
window.location.hash = _anchor; |
|||
} |
|||
} |
|||
postSwitchEvents.forEach(function (e) { |
|||
} |
|||
e(index, anchor); |
|||
}); |
|||
}; |
|||
this.triggerGenderRenderSwitch = function (gender) { |
|||
mw.log(genderRenderSwitchers); |
|||
for (var i = 0; i < genderRenderSwitchers.length; i++) { |
|||
genderRenderSwitchers[i].genderSwitch(gender); |
|||
} |
|||
}; |
|||
this.triggerMultiInfoboxTabChange = function ($multiInfobox) { |
|||
mw.log('switching syncedswitches from tabber click', $multiInfobox); |
|||
setTimeout(function () { |
|||
var $tabcontents = $multiInfobox.find('div.tabber > div.tabbertab[style=""]'); |
|||
var $infobox = $tabcontents.find('.infobox').first(); |
|||
var swinfo = $infobox.data('SwitchInfobox'); |
|||
mw.log('switchingdata', $tabcontents, $infobox, swinfo); |
|||
if (swinfo !== null && swinfo !== undefined) { |
|||
var cs = swinfo.currentlyShowing(); |
|||
var ind = parseInt(cs.index) + swinfo.version_index_offset; |
|||
mw.log('inside if', cs, ind); |
|||
syncedSwitches.forEach(function (e) { |
|||
mw.log('inside foreach', e); |
|||
e.switchInfobox(ind, ''); |
|||
}); |
|||
} else { |
|||
mw.log('swinfo is undefnull'); |
|||
} |
|||
}, 20); |
|||
}; |
|||
/* attempts to detect what type of switch infobox this is and applies the relevant type */ |
|||
postSwitchEvents.forEach(function(e){ |
|||
// mostly for external access |
|||
e(index, anchor); |
|||
this.makeSwitchInfobox = function ($e) { |
|||
}); |
|||
if ($e.is('.infobox-switch')) { |
|||
}; |
|||
return new SwitchInfobox($e, index++, version_offset); |
|||
} |
|||
if ($e.hasClass('switch-infobox')) { |
|||
return new LegacySwitchInfobox($e, index++, version_offset); |
|||
} |
|||
if ($e.hasClass('rsw-synced-switch')) { |
|||
return new SyncedSwitch($e, index++, version_offset); |
|||
} |
|||
if ($e.hasClass('infobox')) { |
|||
return new NonSwitchingInfobox($e, index++, version_offset); |
|||
} |
|||
console.log('Invalid element sent to SwitchEventManager.makeSwitchInfobox:', $e); |
|||
}; |
|||
this.addIndex = function (i) { |
|||
if (typeof i === 'number') { |
|||
i += Math.max(Math.floor(i), 0); |
|||
} |
|||
}; |
|||
this.applyDefaultVersion = function () { |
|||
if (window.location.hash !== '') { |
|||
self.trigger(1, window.location.hash, null); |
|||
return; |
|||
} else { |
|||
// real for loop so we can return out of the function |
|||
for (var i = 0; i < switchInfoboxes.length; i++) { |
|||
var defver = switchInfoboxes[i].defaultVer(); |
|||
if (_typeof(defver) === 'object') { |
|||
self.trigger(defver.idx, defver.txt, null); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
self.trigger(1, '@init@', null); |
|||
}; |
|||
// init |
|||
this.triggerGenderRenderSwitch = function(gender){ |
|||
this.init = function () { |
|||
mw.log(genderRenderSwitchers); |
|||
$('.infobox, .switch-infobox, .rsw-synced-switch').each(function (i, e) { |
|||
for (var i = 0; i<genderRenderSwitchers.length; i++) { |
|||
var obj = self.makeSwitchInfobox($(e)); |
|||
genderRenderSwitchers[i].genderSwitch(gender); |
|||
version_offset += obj.version_count; |
|||
} |
|||
}); |
|||
this.triggerMultiInfoboxTabChange = function($multiInfobox) { |
|||
mw.log('switching syncedswitches from tabber click', $multiInfobox) |
|||
setTimeout(function(){ |
|||
var $tabcontents = $multiInfobox.find('div.tabber > div.tabbertab[style=""]'); |
|||
var $infobox = $tabcontents.find('.infobox').first(); |
|||
var swinfo = $infobox.data('SwitchInfobox'); |
|||
mw.log('switchingdata', $tabcontents, $infobox, swinfo); |
|||
if (swinfo !== null && swinfo !== undefined) { |
|||
var cs = swinfo.currentlyShowing(); |
|||
var ind = parseInt(cs.index) + swinfo.version_index_offset; |
|||
mw.log('inside if', cs, ind) |
|||
syncedSwitches.forEach(function (e) { |
|||
mw.log('inside foreach', e); |
|||
e.switchInfobox(ind, ''); |
|||
}); |
|||
} else {mw.log('swinfo is undefnull');} |
|||
}, 20); |
|||
}; |
|||
/* attempts to detect what type of switch infobox this is and applies the relevant type */ |
|||
// mostly for external access |
|||
this.makeSwitchInfobox = function($e) { |
|||
if ($e.is('.infobox-switch')) { |
|||
return new SwitchInfobox($e, index++, version_offset); |
|||
} |
|||
if ($e.hasClass('switch-infobox')) { |
|||
return new LegacySwitchInfobox($e, index++, version_offset); |
|||
} |
|||
if ($e.hasClass('rsw-synced-switch')) { |
|||
return new SyncedSwitch($e, index++, version_offset); |
|||
} |
|||
if ($e.hasClass('infobox')) { |
|||
return new NonSwitchingInfobox($e, index++, version_offset); |
|||
} |
|||
console.log('Invalid element sent to SwitchEventManager.makeSwitchInfobox:', $e) |
|||
}; |
|||
this.addIndex = function(i) { |
|||
if (typeof(i) === 'number') { |
|||
i += Math.max(Math.floor(i), 0); |
|||
} |
|||
}; |
|||
this.applyDefaultVersion = function() { |
|||
if (window.location.hash !== '') { |
|||
self.trigger(1, window.location.hash, null); |
|||
return; |
|||
} else { |
|||
// real for loop so we can return out of the function |
|||
for (var i = 0; i<switchInfoboxes.length; i++) { |
|||
var defver = switchInfoboxes[i].defaultVer(); |
|||
if (typeof(defver) === 'object') { |
|||
self.trigger(defver.idx, defver.txt, null); |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
self.trigger(1, '@init@', null); |
|||
}; |
|||
// init |
|||
this.init = function(){ |
|||
$('.infobox, .switch-infobox, .rsw-synced-switch').each(function(i,e){ |
|||
var obj = self.makeSwitchInfobox($(e)); |
|||
version_offset += obj.version_count; |
|||
}); |
|||
// for {{Multi Infobox}} |
|||
// there isn't a hook for tabber being ready, so we just gotta check until it is |
|||
function initMultiInfobox(){ |
|||
if ($('#mw-content-text .multi-infobox .tabber.tabberlive').length) { // class tabberlive is added when it is ready |
|||
$('#mw-content-text .multi-infobox').each(function(i,e){ |
|||
$(e).find('.tabber > ul.tabbernav > li').click(function(ev){ |
|||
self.triggerMultiInfoboxTabChange($(ev.currentTarget).parents('.multi-infobox')); |
|||
}); |
|||
}); |
|||
$('#mw-content-text .multi-infobox .tabber.tabberlive ul.tabbernav li.tabberactive').click(); //trigger event once now |
|||
} else { |
|||
window.setTimeout(initMultiInfobox, 20); |
|||
} |
|||
} |
|||
if ($('#mw-content-text .multi-infobox').length) { |
|||
initMultiInfobox(); |
|||
} |
|||
self.applyDefaultVersion(); |
|||
} |
|||
this.init(); |
|||
} |
|||
// for {{Multi Infobox}} |
|||
mw.hook('wikipage.content').add(function init( $content ) { |
|||
// there isn't a hook for tabber being ready, so we just gotta check until it is |
|||
if (!($content.find('.switch-infobox').length || $content.find('.infobox-buttons').length)) { |
|||
function initMultiInfobox() { |
|||
return; |
|||
if ($('#mw-content-text .multi-infobox .tabber.tabberlive').length) { |
|||
} |
|||
// class tabberlive is added when it is ready |
|||
// mirror rsw-mw.util |
|||
$('#mw-content-text .multi-infobox').each(function (i, e) { |
|||
try { |
|||
$(e).find('.tabber > ul.tabbernav > li').click(function (ev) { |
|||
localStorage.setItem('test', 'test'); |
|||
self.triggerMultiInfoboxTabChange($(ev.currentTarget).parents('.multi-infobox')); |
|||
localStorage.removeItem('test'); |
|||
}); |
|||
CAN_LOCAL_STORAGE = true; |
|||
}); |
|||
} catch (e) { |
|||
$('#mw-content-text .multi-infobox .tabber.tabberlive ul.tabbernav li.tabberactive').click(); //trigger event once now |
|||
CAN_LOCAL_STORAGE = false; |
|||
} else { |
|||
} |
|||
window.setTimeout(initMultiInfobox, 20); |
|||
window.switchEventManager = new SwitchEventManager(); |
|||
} |
|||
} |
|||
if ($('#mw-content-text .multi-infobox').length) { |
|||
initMultiInfobox(); |
|||
} |
|||
self.applyDefaultVersion(); |
|||
}; |
|||
this.init(); |
|||
} |
|||
mw.hook('wikipage.content').add(function init($content) { |
|||
if (!($content.find('.switch-infobox').length || $content.find('.infobox-buttons').length)) { |
|||
return; |
|||
} |
|||
// mirror rsw-util |
|||
try { |
|||
localStorage.setItem('test', 'test'); |
|||
localStorage.removeItem('test'); |
|||
CAN_LOCAL_STORAGE = true; |
|||
} catch (e) { |
|||
CAN_LOCAL_STORAGE = false; |
|||
} |
|||
window.switchEventManager = new SwitchEventManager(); |
|||
// reinitialize any kartographer map frames added due to a switch |
|||
if ($content.find('.infobox-switch .mw-kartographer-map').length || $content.find('.infobox-switch-resources .mw-kartographer-map').length || $content.find('.switch-infobox .mw-kartographer-map').length || $content.find('.rsw-synced-switch .mw-kartographer-map').length) { |
|||
window.switchEventManager.addPostSwitchEvent(function () { |
|||
|| $content.find('.infobox-switch-resources .mw-kartographer-map').length |
|||
mw.hook('wikipage.content').fire($content.find('a.mw-kartographer-map').parent()); |
|||
}); |
|||
|| $content.find('.rsw-synced-switch .mw-kartographer-map').length) { |
|||
} |
|||
window.switchEventManager.addPostSwitchEvent(function() { |
|||
}); |
|||
mw.hook('wikipage.content').fire($content.find('a.mw-kartographer-map').parent()); |
|||
}); |
|||
} |
|||
}); |
|||
}) |
Latest revision as of 12:06, 20 October 2024
"use strict";
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
/* switch infobox code for infoboxes
* contains switching code for both:
* * originalInfoboxes:
* older infobox switching, such as [[Template:Infobox Bonuses]]
* which works my generating complete infoboxes for each version
* * moduleInfoboxes:
* newer switching, as implemented by [[Module:Infobox]]
* which generates one infobox and a resources pool for switching
* * synced switches
* as generated by [[Module:Synced switch]] and its template
*
* The script also facilitates synchronising infoboxes, so that if a button of one is pressed
* and another switchfobox on the same page also has that button, it will 'press' itself
* This only activates if there are matching version parameters in the infoboxes (i.e. the button text is the same)
* - thus it works best if the version parameters are all identical
*
* TODO: OOUI? (probably not, its a little clunky and large for this. It'd need so much styling it isn't worthwhile)
*/
$(function () {
var SWITCH_REF_REGEX = /^\$(\d+)/,
CAN_LOCAL_STORAGE = true;
function getGenderFromLS() {
if (CAN_LOCAL_STORAGE) {
var x = window.localStorage.getItem('gender-render');
if (['m', 'f'].indexOf(x) > -1) {
return x;
}
}
return 'm';
}
/**
* Switch infobox psuedo-interface
*
* Switch infoboxes are given several similar functions so that they can be called similarly
* This is essentially like an interface or class structure, except I'm too lazy to implement that
*
* switchfo.beginSwitchEvent(event)
* the reactionary event to buttons being clicked/selects being selected/etc
* tells SwitchEventManager to switch all the boxes
* should extract an index and anchor from the currentTarget and pass that to the SwitchEventManager.trigger function
* event the jQuery event fired from $.click/$.change/etc
*
* switchfo.switch(index, anchor)
* do all the actual switching of the infobox to the infobox specified by the anchor and index
* prefer using the anchor if there is a conflict
*
* switchfo.defaultVer()
* called during script init
* returns either an anchor for the default version, if manually specified, or false if there is no default specified
* the page will automatically switch to the default version, or to version 1, when loaded.
*
*/
/**
* Switch Infoboxes based on [[Module:Infobox]]
*
* - the preferred way to do switch infoboxes
* - generates one table and a resources table, swaps resources into the table as required
* - with enough buttons, becomes a dropdown <select>
*
* parameters
* $box jQuery object representing the infobox itself (.infobox-switch)
* index index of this infobox, from $.each
*/
function SwitchInfobox($box, index, version_index_offset) {
var self = this;
this.index = index;
this.version_index_offset = version_index_offset;
this.$infobox = $box;
this.$infobox.data('SwitchInfobox', self);
this.$resources = self.$infobox.next();
this.$buttons = self.$infobox.find('div.infobox-buttons');
this.version_count = this.$buttons.find('span.button').length;
this.isSelect = self.$buttons.hasClass('infobox-buttons-select');
this.$select = null;
this.originalClasses = {};
/* click/change event - triggers switch event manager */
this.beginSwitchEvent = function (e) {
var $tgt = $(e.currentTarget);
mw.log('beginSwitchEvent triggered in module infobox, id ' + self.index);
if (self.isSelect) {
window.switchEventManager.trigger($tgt.val(), $tgt.find(' > option[data-switch-index=' + $tgt.val() + ']').attr('data-switch-anchor'), self);
} else {
window.switchEventManager.trigger($tgt.attr('data-switch-index'), $tgt.attr('data-switch-anchor'), self);
}
};
/* switch event, triggered by manager */
this.switchInfobox = function (index, text) {
if (text === '@init@') {
text = self.$buttons.find('[data-switch-index="1"]').attr('data-switch-anchor');
}
var ind,
txt,
$thisButton = self.$buttons.find('[data-switch-anchor="' + text + '"]');
mw.log('switching module infobox, id ' + self.index);
// prefer text
if ($thisButton.length) {
txt = text;
ind = $thisButton.attr('data-switch-index');
}
if (ind === undefined) {
return;
/*ind = index;
$thisButton = self.$buttons.find('[data-switch-index="'+ind+'"]');
if ($thisButton.length) {
txt = $thisButton.attr('data-switch-anchor');
}*/
}
if (txt === undefined) {
return;
}
if (self.isSelect) {
self.$select.val(ind);
} else {
self.$buttons.find('span.button').removeClass('button-selected');
$thisButton.addClass('button-selected');
}
self.$infobox.find('[data-attr-param][data-attr-param!=""]').each(function (i, e) {
var $e = $(e),
param = $e.attr('data-attr-param'),
$switches = self.$resources.find('span[data-attr-param="' + param + '"]'),
m,
$val,
$classTgt;
// check if we found some switch data
if (!$switches.length) return;
// find value
$val = $switches.find('span[data-attr-index="' + ind + '"]');
if (!$val.length) {
// didn't find it, use default value
$val = $switches.find('span[data-attr-index="0"]');
if (!$val.length) return;
}
// switch references support - $2 -> use the value for index 2
m = SWITCH_REF_REGEX.exec($val.html());
if (m) {
// m is null if no matches
$val = $switches.find('span[data-attr-index="' + m[1] + '"]'); // m is [ entire match, capture ]
if (!$val.length) {
$val = $switches.find('span[data-attr-index="0"]'); // fallback again
if (!$val.length) return;
}
}
$val = $val.clone(true, true);
$e.empty().append($val.contents());
// class switching
// find the thing we're switching classes for
if ($e.is('td, th')) {
$classTgt = $e.parent('tr');
} else {
$classTgt = $e;
}
// reset classes
if (self.originalClasses.hasOwnProperty(param)) {
$classTgt.attr('class', self.originalClasses[param]);
} else {
$classTgt.removeAttr('class');
}
// change classes if needed
if ($val.attr('data-addclass') !== undefined) {
$classTgt.addClass($val.attr('data-addclass'));
}
});
// trigger complete event for inter-script functions
self.$buttons.trigger('switchinfoboxComplete', {
txt: txt,
num: ind
});
//re-initialise quantity boxes, if any
if (window.rswiki && typeof rswiki.initQtyBox == 'function') {
rswiki.initQtyBox(self.$infobox);
}
//console.log(this);
};
/* default version, return the anchor of the switchable if it exists */
this.defaultVer = function () {
var defver = self.$buttons.attr('data-default-version');
if (defver !== undefined) {
return {
idx: defver,
txt: self.$buttons.find('[data-switch-index="' + defver + '"]').attr('data-switch-anchor')
};
}
return false;
};
this.isParentOf = function ($triggerer) {
return self.$infobox.find($triggerer).length > 0;
};
this.currentlyShowing = function () {
if (self.isSelect) {
var sel = self.$select.val();
return {
index: sel,
text: self.$select.find('option[value="' + sel + '"]').attr('data-switch-anchor')
};
} else {
var buttn = self.$buttons.find('.button-selected');
return {
index: buttn.attr('data-switch-index'),
text: buttn.attr('data-switch-anchor')
};
}
};
/* init */
mw.log('setting up module infobox, id ' + self.index);
// setup original classes
this.$infobox.find('[data-attr-param][data-attr-param!=""]').each(function (i, e) {
var $e = $(e),
$classElem = $e,
clas;
if ($e.is('td, th')) {
$classElem = $e.parent('tr');
}
clas = $classElem.attr('class');
if (typeof clas === 'string') {
self.originalClasses[$e.attr('data-attr-param')] = clas;
}
});
// setup select/buttons and events
if (self.isSelect) {
self.$select = $('<select>').attr({
id: 'infobox-select-' + self.index,
name: 'infobox-select-' + self.index
});
self.$buttons.find('span.button').each(function (i, e) {
var $e = $(e);
self.$select.append($('<option>').attr({
value: $e.attr('data-switch-index'),
'data-switch-index': $e.attr('data-switch-index'),
'data-switch-anchor': $e.attr('data-switch-anchor')
}).text($e.text()));
});
self.$buttons.empty().append(self.$select);
self.$select.change(self.beginSwitchEvent);
} else {
self.$buttons.attr({
id: 'infobox-buttons-' + self.index
}).find('span').each(function (i, e) {
$(e).click(self.beginSwitchEvent);
});
}
self.$buttons.css('display', 'flex');
self.switchInfobox(1, '@init@');
window.switchEventManager.addSwitchInfobox(this);
if (this.$infobox.find('.infobox-bonuses-image.render-m').length === 1 && this.$infobox.find('.infobox-bonuses-image.render-f').length === 1) {
this.genderswitch = new GenderRenderSwitcher(this.$infobox, this.index);
}
}
/**
* Special support for gender render switching in infobox bonuses (& synced switch)
* Currently specifically only supports male & female
* potential TODO: generalise?
*
* parameters
* $box jQuery object representing the infobox itself (.infobox-switch)
*/
function GenderRenderSwitcher($box, index, version_index_offset) {
var self = this;
this.$box = $box;
this.$box.data('SwitchInfobox', self);
this.index = index;
this.version_index_offset = version_index_offset;
this.version_count = 2;
this.$buttons = $('<div>').addClass('infobox-buttons').css('display', 'flex');
this.button = {
m: $('<span>').addClass('button').attr('data-gender-render', 'm').text('Male'),
f: $('<span>').addClass('button').attr('data-gender-render', 'f').text('Female')
};
this.$td = $('<td>');
this.$td_inner = $('<div class="gender-render-inner">');
this.visible_gender = '';
// from interface, we can just get the SyncedSwitches to switch
this.beginSwitchEvent = function (event) {
var $e = $(event.currentTarget);
var gen = $e.attr('data-gender-render');
mw.log('beginSwitchEvent for genderswitcher ' + self.index + ' - switching to ' + gen);
window.switchEventManager.triggerGenderRenderSwitch(gen);
if (CAN_LOCAL_STORAGE) {
window.localStorage.setItem('gender-render', gen);
}
};
// do the actual switching
this.genderSwitch = function (gender) {
mw.log('switching gender for genderswitcher for ' + self.index + ' to ' + gender);
self.$buttons.find('.button-selected').removeClass('button-selected');
self.button[gender].addClass('button-selected');
var x = self.$box.find('.infobox-bonuses-image.render-' + gender + '');
self.$td_inner.empty().append(x.find('>*').clone());
self.visible_gender = gender;
};
this.refreshImage = function (index, anchor) {
// for when a main infobox switch happens
// this is a post-switch function so the new images are in the original cells
// we just gotta clone them into the visible cell again
self.genderSwitch(self.visible_gender);
mw.log('refreshed image for genderswitcher ' + self.index);
};
this.currentlyShowing = function () {
return {
index: -1,
text: self.visible_gender
};
};
// other 'interface' methods just so stuff doesn't break, just in case
this.switchInfobox = function (ind, anchor) {/* do nothing */};
this.defaultVer = function () {
return false;
};
mw.log('Initialising genderswitcher for ' + self.index);
var $c_m = this.$box.find('.infobox-bonuses-image.render-m'),
$c_f = this.$box.find('.infobox-bonuses-image.render-f');
this.$td.addClass('gender-render').attr({
'style': $c_m.attr('style'),
'rowspan': $c_m.attr('rowspan')
}).append(this.$td_inner);
$c_m.parent().append(this.$td);
this.$buttons.append(this.button.m, this.button.f);
this.$td.append(this.$buttons);
this.$buttons.find('span.button').on('click', this.beginSwitchEvent);
$c_m.addClass('gender-render-hidden').attr('data-gender-render', 'm');
$c_f.addClass('gender-render-hidden').attr('data-gender-render', 'f');
window.switchEventManager.addGenderRenderSwitch(self);
window.switchEventManager.addPostSwitchEvent(this.refreshImage);
this.genderSwitch(getGenderFromLS());
}
/**
* Legacy switch infoboxes, as generated by [[Template:Switch infobox]]
*
*
* parameters
* $box jQuery object representing the infobox itself (.switch-infobox)
* index index of this infobox, from $.each
*/
function LegacySwitchInfobox($box, index, version_index_offset) {
var self = this;
this.$infobox = $box;
this.$infobox.data('SwitchInfobox', self);
this.$parent = $box;
this.index = index;
this.version_index_offset = version_index_offset;
this.$originalButtons = self.$parent.find('.switch-infobox-triggers');
this.$items = self.$parent.find('.item');
this.version_count = self.$originalButtons.find('span.trigger.button').length;
/* click/change event - triggers switch event manager */
this.beginSwitchEvent = function (e) {
var $tgt = $(e.currentTarget);
mw.log('beginSwitchEvent triggered in legacy infobox, id ' + self.index);
window.switchEventManager.trigger($tgt.attr('data-id'), $tgt.attr('data-anchor'), self);
};
/* click/change event - triggers switch event manager */
this.switchInfobox = function (index, text) {
if (text === '@init@') {
text = self.$buttons.find('[data-id="1"]').attr('data-anchor');
}
var ind,
txt,
$thisButton = self.$buttons.find('[data-anchor="' + text + '"]').first();
mw.log('switching legacy infobox, id ' + self.index);
if ($thisButton.length) {
txt = text;
ind = $thisButton.attr('data-id');
} else {
return;
/*ind = index;
$thisButton = self.$buttons.find('[data-id="'+ind+'"]');
if ($thisButton.length) {
txt = $thisButton.attr('data-anchor');
}*/
}
if (txt === undefined) {
return;
}
self.$buttons.find('.trigger').removeClass('button-selected');
self.$buttons.find('.trigger[data-id="' + ind + '"]').addClass('button-selected');
self.$items.filter('.showing').removeClass('showing');
self.$items.filter('[data-id="' + ind + '"]').addClass('showing');
};
/* default version - not supported by legacy, always false */
this.defaultVer = function () {
return false;
};
this.isParentOf = function ($triggerer) {
return self.$parent.find($triggerer).length > 0;
};
this.currentlyShowing = function () {
var buttn = self.$buttons.find('.button-selected');
return {
index: buttn.attr('data-id'),
text: buttn.attr('data-anchor')
};
};
/* init */
mw.log('setting up legacy infobox, id ' + self.index);
// add anchor text
self.$originalButtons.find('span.trigger.button').each(function (i, e) {
var $e = $(e);
var anchorText = $e.text().split(' ').join('_');
$e.attr('data-anchor', '#' + anchorText);
});
// append triggers to every item
// if contents has a infobox, add to a caption of that
// else just put at top
self.$items.each(function (i, e) {
var $item = $(e);
if ($item.find('table.infobox').length > 0) {
if ($item.find('table.infobox caption').length < 1) {
$item.find('table.infobox').prepend('<caption>');
}
$item.find('table.infobox caption').first().prepend(self.$originalButtons.clone());
} else {
$item.prepend(self.$originalButtons.clone());
}
});
// remove buttons from current location
self.$originalButtons.remove();
// update selection
this.$buttons = self.$parent.find('.switch-infobox-triggers');
self.$buttons.find('.trigger').each(function (i, e) {
$(e).click(self.beginSwitchEvent);
});
self.switchInfobox(1, '@init@');
window.switchEventManager.addSwitchInfobox(this);
self.$parent.removeClass('loading').find('span.loading-button').remove();
}
/**
* Synced switches, as generated by [[Template:Synced switch]]
*
*
* parameters
* $box jQuery object representing the synced switch itself (.rsw-synced-switch)
* index index of this infobox, from $.each
*/
function SyncedSwitch($box, index, version_index_offset) {
var self = this;
this.index = index;
this.version_index_offset = version_index_offset; //not actually used
this.version_count = 0; // we don't increment from this
this.$syncedswitch = $box;
this.$syncedswitch.data('SwitchInfobox', self);
this.attachedLabels = false;
this.is_synced_switch = true;
/* filling in interface - synced switch has no buttons to press so cannot trigger an event by itself */
this.beginSwitchEvent = function () {};
this.switchInfobox = function (index, text) {
mw.log('switching synced switch, id ' + self.index + ", looking for " + index + ' - ' + text);
if (text === '@init@') {
text = self.$syncedswitch.find('[data-item="1"]').attr('data-item-text');
}
var $toShow = self.$syncedswitch.find('[data-item-text="' + text + '"]');
if (!(self.attachedLabels && $toShow.length)) {
//return;
$toShow = self.$syncedswitch.find('[data-item="' + index + '"]');
}
if (!$toShow.length) {
// show default instead
self.$syncedswitch.find('.rsw-synced-switch-item').removeClass('showing');
self.$syncedswitch.find('[data-item="0"]').addClass('showing');
} else {
self.$syncedswitch.find('.rsw-synced-switch-item').removeClass('showing');
$toShow.addClass('showing');
}
};
this.genderSwitch = function (gender) {
var $gens = self.$syncedswitch.find('.render-m, .render-f');
var srch = '.render-' + gender;
if ($gens.length) {
$gens.each(function (i, e) {
var $e = $(e);
if ($e.is(srch)) {
$e.removeClass('gender-render-hidden').addClass('gender-render-showing');
} else {
$e.removeClass('gender-render-showing').addClass('gender-render-hidden');
}
});
}
};
/* default version - not supported by synced switches, always false */
this.defaultVer = function () {
return false;
};
this.isParentOf = function ($triggerer) {
return self.$syncedswitch.find($triggerer).length > 0;
};
this.currentlyShowing = function () {
var buttn = self.$syncedswitch.find('.rsw-synced-switch-item.showing');
return {
index: buttn.attr('data-item'),
text: buttn.attr('data-item-text')
};
};
/* init */
mw.log('setting up synced switch, id ' + self.index);
// attempt to apply some button text from a SwitchInfobox
if ($('.infobox.infobox-switch').length && !$('.multi-infobox').length) {
self.attachedLabels = true;
var $linkedButtonTextInfobox = $('.infobox.infobox-switch').first();
self.$syncedswitch.find('.rsw-synced-switch-item').each(function (i, e) {
var $e = $(e);
if ($e.attr('data-item-text') === undefined) {
$e.attr('data-item-text', $linkedButtonTextInfobox.find('[data-switch-index="' + i + '"]').attr('data-switch-anchor'));
}
});
}
self.switchInfobox(1, '@init@');
window.switchEventManager.addSwitchInfobox(this);
if (self.$syncedswitch.find('.render-m, .render-f').length) {
window.switchEventManager.addGenderRenderSwitch(self);
this.genderSwitch(getGenderFromLS());
}
}
/**
* An infobox that doesn't switch
* used to make sure MultiInfoboxes interact with SyncedSwitches correctly
*
*/
function NonSwitchingInfobox($box, index, version_index_offset) {
var self = this;
this.$infobox = $box;
this.index = index;
this.version_index_offset = version_index_offset;
this.$infobox.data('SwitchInfobox', self);
this.version_count = 1;
this.beginSwitchEvent = function () {}; //do nothing
this.switchInfobox = function (index, text) {
return;
}; //do nothing
this.defaultVer = function () {
return true;
};
this.isParentOf = function ($triggerer) {
return false;
};
this.currentlyShowing = function () {
return {
text: null,
index: 1
};
};
}
/**
* Event manager
* Observer pattern
* Globally available as window.switchEventManager
*
* Methods
* addSwitchInfobox(l)
* adds switch infobox (of any type) to the list of switch infoboxes listening to trigger events
* l switch infobox
*
* addPreSwitchEvent(f)
* adds the function to a list of functions that runs when the switch event is triggered but before any other action is taken
* the function is passed the index and anchor (in that order) that was passed to the trigger function
* returning the boolean true from the function will cancel the switch event
* trying to add a non-function is a noop
* e function to run
*
* addPostSwitchEvent(f)
* adds the function to a list of functions that runs when the switch event is completed, after all of the switching is completed (including the hash change)
* the function is passed the index and anchor (in that order) that was passed to the trigger function
* the return value is ignored
* trying to add a non-function is a noop
* e function to run
*
* trigger(i, a)
* triggers the switch event on all listeners
* will prefer switching to the anchor if available
* i index to switch to
* a anchor to switch to
*
* makeSwitchInfobox($box)
* creates the correct object for the passed switch infobox, based on the classes of the infobox
* is a noop if it does not match any of the selectors
* infobox is given an index based on the internal counter for the switch
* $box jQuery object for the switch infobox (the jQuery object passed to the above functions, see above for selectors checked)
*
* addIndex(i)
* updates the internal counter by adding i to it
* if i is not a number or is negative, is a noop
* used for manually setting up infoboxes (init) or creating a new type to plugin
* i number to add
*/
function SwitchEventManager() {
var self = this,
switchInfoboxes = [],
syncedSwitches = [],
genderRenderSwitchers = [],
preSwitchEvents = [],
postSwitchEvents = [],
index = 0,
version_offset = 0;
window.switchEventManager = this;
// actual switch infoboxes to change
this.addSwitchInfobox = function (l) {
switchInfoboxes.push(l);
if (l.is_synced_switch) {
syncedSwitches.push(l);
}
};
this.addGenderRenderSwitch = function (gs) {
gs.version_index_offset = version_offset;
genderRenderSwitchers.push(gs);
version_offset += gs.version_count;
};
// things to do when switch button is clicked but before any switching
this.addPreSwitchEvent = function (e) {
if (typeof e === 'function') {
preSwitchEvents.push(e);
}
};
this.addPostSwitchEvent = function (e) {
if (typeof e === 'function') {
postSwitchEvents.push(e);
}
};
this.trigger = function (index, anchor, triggerer) {
mw.log('Triggering switch event for index ' + index + '; text ' + anchor);
// using a real for loop so we can use return to exit the trigger function
for (var i = 0; i < preSwitchEvents.length; i++) {
var ret = preSwitchEvents[i](index, anchor);
if (typeof ret === 'boolean') {
if (ret) {
mw.log('switching was cancelled');
return;
}
}
}
// close all tooltips on the page
$('.js-tooltip-wrapper').trigger('js-tooltip-close');
// trigger switching on listeners
switchInfoboxes.forEach(function (e) {
if (triggerer === null || !e.isParentOf(triggerer.$infobox)) {
if (e.is_synced_switch && triggerer !== null) {
e.switchInfobox(parseInt(index) + triggerer.version_index_offset, anchor);
} else {
e.switchInfobox(index, anchor);
}
}
});
// update hash
if (typeof anchor === 'string') {
var _anchor = anchor;
if (_anchor === '@init@') {
_anchor = '';
}
if (window.history && window.history.replaceState) {
if (window.location.hash !== '') {
window.history.replaceState({}, '', window.location.href.replace(window.location.hash, _anchor));
} else {
window.history.replaceState({}, '', window.location.href + _anchor);
}
} else {
// replaceState not supported, I guess we just change the hash normally?
window.location.hash = _anchor;
}
}
postSwitchEvents.forEach(function (e) {
e(index, anchor);
});
};
this.triggerGenderRenderSwitch = function (gender) {
mw.log(genderRenderSwitchers);
for (var i = 0; i < genderRenderSwitchers.length; i++) {
genderRenderSwitchers[i].genderSwitch(gender);
}
};
this.triggerMultiInfoboxTabChange = function ($multiInfobox) {
mw.log('switching syncedswitches from tabber click', $multiInfobox);
setTimeout(function () {
var $tabcontents = $multiInfobox.find('div.tabber > div.tabbertab[style=""]');
var $infobox = $tabcontents.find('.infobox').first();
var swinfo = $infobox.data('SwitchInfobox');
mw.log('switchingdata', $tabcontents, $infobox, swinfo);
if (swinfo !== null && swinfo !== undefined) {
var cs = swinfo.currentlyShowing();
var ind = parseInt(cs.index) + swinfo.version_index_offset;
mw.log('inside if', cs, ind);
syncedSwitches.forEach(function (e) {
mw.log('inside foreach', e);
e.switchInfobox(ind, '');
});
} else {
mw.log('swinfo is undefnull');
}
}, 20);
};
/* attempts to detect what type of switch infobox this is and applies the relevant type */
// mostly for external access
this.makeSwitchInfobox = function ($e) {
if ($e.is('.infobox-switch')) {
return new SwitchInfobox($e, index++, version_offset);
}
if ($e.hasClass('switch-infobox')) {
return new LegacySwitchInfobox($e, index++, version_offset);
}
if ($e.hasClass('rsw-synced-switch')) {
return new SyncedSwitch($e, index++, version_offset);
}
if ($e.hasClass('infobox')) {
return new NonSwitchingInfobox($e, index++, version_offset);
}
console.log('Invalid element sent to SwitchEventManager.makeSwitchInfobox:', $e);
};
this.addIndex = function (i) {
if (typeof i === 'number') {
i += Math.max(Math.floor(i), 0);
}
};
this.applyDefaultVersion = function () {
if (window.location.hash !== '') {
self.trigger(1, window.location.hash, null);
return;
} else {
// real for loop so we can return out of the function
for (var i = 0; i < switchInfoboxes.length; i++) {
var defver = switchInfoboxes[i].defaultVer();
if (_typeof(defver) === 'object') {
self.trigger(defver.idx, defver.txt, null);
return;
}
}
}
self.trigger(1, '@init@', null);
};
// init
this.init = function () {
$('.infobox, .switch-infobox, .rsw-synced-switch').each(function (i, e) {
var obj = self.makeSwitchInfobox($(e));
version_offset += obj.version_count;
});
// for {{Multi Infobox}}
// there isn't a hook for tabber being ready, so we just gotta check until it is
function initMultiInfobox() {
if ($('#mw-content-text .multi-infobox .tabber.tabberlive').length) {
// class tabberlive is added when it is ready
$('#mw-content-text .multi-infobox').each(function (i, e) {
$(e).find('.tabber > ul.tabbernav > li').click(function (ev) {
self.triggerMultiInfoboxTabChange($(ev.currentTarget).parents('.multi-infobox'));
});
});
$('#mw-content-text .multi-infobox .tabber.tabberlive ul.tabbernav li.tabberactive').click(); //trigger event once now
} else {
window.setTimeout(initMultiInfobox, 20);
}
}
if ($('#mw-content-text .multi-infobox').length) {
initMultiInfobox();
}
self.applyDefaultVersion();
};
this.init();
}
mw.hook('wikipage.content').add(function init($content) {
if (!($content.find('.switch-infobox').length || $content.find('.infobox-buttons').length)) {
return;
}
// mirror rsw-util
try {
localStorage.setItem('test', 'test');
localStorage.removeItem('test');
CAN_LOCAL_STORAGE = true;
} catch (e) {
CAN_LOCAL_STORAGE = false;
}
window.switchEventManager = new SwitchEventManager();
// reinitialize any kartographer map frames added due to a switch
if ($content.find('.infobox-switch .mw-kartographer-map').length || $content.find('.infobox-switch-resources .mw-kartographer-map').length || $content.find('.switch-infobox .mw-kartographer-map').length || $content.find('.rsw-synced-switch .mw-kartographer-map').length) {
window.switchEventManager.addPostSwitchEvent(function () {
mw.hook('wikipage.content').fire($content.find('a.mw-kartographer-map').parent());
});
}
});
});