MediaWiki:Gadget-switch-infobox.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)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
1 // <nowiki>
2 /* switch infobox code for infoboxes
3 * contains switching code for both:
4 * * originalInfoboxes:
5 * older infobox switching, such as [[Template:Infobox Bonuses]]
6 * which works my generating complete infoboxes for each version
7 * * moduleInfoboxes:
8 * newer switching, as implemented by [[Module:Infobox]]
9 * which generates one infobox and a resources pool for switching
10 * * synced switches
11 * as generated by [[Module:Synced switch]] and its template
12 *
13 * The script also facilitates synchronising infoboxes, so that if a button of one is pressed
14 * and another switchfobox on the same page also has that button, it will 'press' itself
15 * This only activates if there are matching version parameters in the infoboxes (i.e. the button text is the same)
16 * - thus it works best if the version parameters are all identical
17 *
18 * TODO: OOUI? (probably not, its a little clunky and large for this. It'd need so much styling it isn't worthwhile)
19 */
20 $(function () {
21 if (!($('.switch-infobox').length || $('.infobox-buttons').length)) {
22 return;
23 }
24
25 var SWITCH_REF_REGEX = /^\$(\d+)/,
26 CAN_LOCAL_STORAGE = true;
27 function getGenderFromLS() {
28 if (CAN_LOCAL_STORAGE) {
29 var x = window.localStorage.getItem('gender-render');
30 if (['m', 'f'].indexOf(x) > -1) {
31 return x;
32 }
33 }
34 return 'm';
35 }
36 /**
37 * Switch infobox psuedo-interface
38 *
39 * Switch infoboxes are given several similar functions so that they can be called similarly
40 * This is essentially like an interface or class structure, except I'm too lazy to implement that
41 *
42 * switchfo.beginSwitchEvent(event)
43 * the reactionary event to buttons being clicked/selects being selected/etc
44 * tells SwitchEventManager to switch all the boxes
45 * should extract an index and anchor from the currentTarget and pass that to the SwitchEventManager.trigger function
46 * event the jQuery event fired from $.click/$.change/etc
47 *
48 * switchfo.switch(index, anchor)
49 * do all the actual switching of the infobox to the infobox specified by the anchor and index
50 * prefer using the anchor if there is a conflict
51 *
52 * switchfo.defaultVer()
53 * called during script init
54 * returns either an anchor for the default version, if manually specified, or false if there is no default specified
55 * the page will automatically switch to the default version, or to version 1, when loaded.
56 *
57 */
58 /**
59 * Switch Infoboxes based on [[Module:Infobox]]
60 *
61 * - the preferred way to do switch infoboxes
62 * - generates one table and a resources table, swaps resources into the table as required
63 * - with enough buttons, becomes a dropdown <select>
64 *
65 * parameters
66 * $box jQuery object representing the infobox itself (.infobox-switch)
67 * index index of this infobox, from $.each
68 */
69 function SwitchInfobox($box, index) {
70 var self = this;
71 this.index = index;
72 this.$infobox = $box;
73 this.$resources = self.$infobox.next();
74 this.$buttons = self.$infobox.find('div.infobox-buttons');
75 this.isSelect = self.$buttons.hasClass('infobox-buttons-select');
76 this.$select = null;
77 this.originalClasses = {};
78
79 /* click/change event - triggers switch event manager */
80 this.beginSwitchEvent = function(e) {
81 var $tgt = $(e.currentTarget);
82 mw.log('beginSwitchEvent triggered in module infobox, id '+self.index);
83 if (self.isSelect) {
84 window.switchEventManager.trigger($tgt.val(), $tgt.find(' > option[data-switch-index='+$tgt.val()+']').attr('data-switch-anchor'));
85 } else {
86 window.switchEventManager.trigger($tgt.attr('data-switch-index'), $tgt.attr('data-switch-anchor'), self.$infobox);
87 }
88 };
89
90 /* switch event, triggered by manager */
91 this.switchInfobox = function(index, text) {
92 if (text === '@init@') {
93 text = self.$buttons.find('[data-switch-index="1"]').attr('data-switch-anchor');
94 }
95 var ind, txt, $thisButton = self.$buttons.find('[data-switch-anchor="'+text+'"]');
96 mw.log('switching module infobox, id '+self.index);
97 // prefer text
98 if ($thisButton.length) {
99 txt = text;
100 ind = $thisButton.attr('data-switch-index');
101 }
102 if (ind === undefined) {
103 return;
104 /*ind = index;
105 $thisButton = self.$buttons.find('[data-switch-index="'+ind+'"]');
106 if ($thisButton.length) {
107 txt = $thisButton.attr('data-switch-anchor');
108 }*/
109 }
110 if (txt === undefined) {
111 return;
112 }
113 if (self.isSelect) {
114 self.$select.val(ind);
115 } else {
116 self.$buttons.find('span.button').removeClass('button-selected');
117 $thisButton.addClass('button-selected');
118 }
119
120 self.$infobox.find('[data-attr-param][data-attr-param!=""]').each(function(i,e) {
121 var $e = $(e),
122 param = $e.attr('data-attr-param'),
123 $switches = self.$resources.find('span[data-attr-param="'+param+'"]'),
124 m,
125 $val,
126 $classTgt;
127
128 // check if we found some switch data
129 if (!$switches.length) return;
130
131 // find value
132 $val = $switches.find('span[data-attr-index="'+ind+'"]');
133 if (!$val.length) {
134 // didn't find it, use default value
135 $val = $switches.find('span[data-attr-index="0"]');
136 if (!$val.length) return;
137 }
138 // switch references support - $2 -> use the value for index 2
139 m = SWITCH_REF_REGEX.exec($val.html());
140 if (m) { // m is null if no matches
141 $val = $switches.find('span[data-attr-index="'+m[1]+'"]'); // m is [ entire match, capture ]
142 if (!$val.length) {
143 $val = $switches.find('span[data-attr-index="0"]'); // fallback again
144 if (!$val.length) return;
145 }
146 }
147 $val = $val.clone(true,true);
148 $e.empty().append($val.contents());
149
150 // class switching
151 // find the thing we're switching classes for
152 if ($e.is('td, th')) {
153 $classTgt = $e.parent('tr');
154 } else {
155 $classTgt = $e;
156 }
157
158 // reset classes
159 if (self.originalClasses.hasOwnProperty(param)) {
160 $classTgt.attr('class', self.originalClasses[param]);
161 } else {
162 $classTgt.removeAttr('class');
163 }
164
165 // change classes if needed
166 if ($val.attr('data-addclass') !== undefined) {
167 $classTgt.addClass($val.attr('data-addclass'));
168 }
169 });
170 // trigger complete event for inter-script functions
171 self.$buttons.trigger('switchinfoboxComplete', {txt:txt, num:ind});
172 //re-initialise quantity boxes, if any
173 if (window.rswiki && typeof(rswiki.initQtyBox) == 'function') {
174 rswiki.initQtyBox(self.$infobox)
175 }
176 console.log(this);
177 };
178
179 /* default version, return the anchor of the switchable if it exists */
180 this.defaultVer = function () {
181 var defver = self.$buttons.attr('data-default-version');
182 if (defver !== undefined) {
183 return { idx: defver, txt: self.$buttons.find('[data-switch-index="'+defver+'"]').attr('data-switch-anchor') };
184 }
185 return false;
186 };
187
188 this.isParentOf = function ($triggerer) {
189 return self.$infobox.find($triggerer).length > 0;
190 };
191
192 /* init */
193 mw.log('setting up module infobox, id '+self.index);
194 // setup original classes
195 this.$infobox.find('[data-attr-param][data-attr-param!=""]').each(function(i,e){
196 var $e = $(e), $classElem = $e, clas;
197 if ($e.is('td, th')) {
198 $classElem = $e.parent('tr');
199 }
200 clas = $classElem.attr('class');
201 if (typeof clas === 'string') {
202 self.originalClasses[$e.attr('data-attr-param')] = clas;
203 }
204 });
205
206 // setup select/buttons and events
207 if (self.isSelect) {
208 self.$select = $('<select>')
209 .attr({
210 id: 'infobox-select-' + self.index,
211 name: 'infobox-select-' + self.index,
212 });
213 self.$buttons.find('span.button').each(function(i, e){
214 var $e = $(e);
215 self.$select.append(
216 $('<option>').attr({
217 value: $e.attr('data-switch-index'),
218 'data-switch-index': $e.attr('data-switch-index'),
219 'data-switch-anchor': $e.attr('data-switch-anchor')
220 }).text($e.text())
221 );
222 });
223 self.$buttons.empty().append(self.$select);
224 self.$select.change(self.beginSwitchEvent);
225 } else {
226 self.$buttons
227 .attr({
228 id: 'infobox-buttons-'+self.index
229 })
230 .find('span').each(function(i,e) {
231 $(e).click(self.beginSwitchEvent);
232 });
233 }
234
235 self.$buttons.css('display', 'block');
236 self.switchInfobox(1, '@init@');
237
238 window.switchEventManager.addSwitchInfobox(this);
239 if (this.$infobox.find('.infobox-bonuses-image.render-m').length === 1 && this.$infobox.find('.infobox-bonuses-image.render-f').length === 1) {
240 this.genderswitch = new GenderRenderSwitcher(this.$infobox, this.index);
241 }
242 }
243
244 /**
245 * Special support for gender render switching in infobox bonuses (& synced switch)
246 * Currently specifically only supports male & female
247 * potential TODO: generalise?
248 *
249 * parameters
250 * $box jQuery object representing the infobox itself (.infobox-switch)
251 */
252 function GenderRenderSwitcher($box, index) {
253 var self = this;
254 this.$box = $box;
255 this.index = index;
256 this.$buttons = $('<div>').addClass('infobox-buttons').css('display', 'block');
257 this.button = {
258 m: $('<span>').addClass('button').attr('data-gender-render', 'm').text('Male'),
259 f: $('<span>').addClass('button').attr('data-gender-render', 'f').text('Female')
260 };
261 this.$td = $('<td>');
262 this.$td_inner = $('<div class="gender-render-inner">');
263 this.visible_gender = '';
264
265 // from interface, we can just get the SyncedSwitches to switch
266 this.beginSwitchEvent = function(event){
267 var $e = $(event.currentTarget);
268 var gen = $e.attr('data-gender-render');
269 mw.log('beginSwitchEvent for genderswitcher '+self.index+' - switching to '+gen);
270 window.switchEventManager.triggerGenderRenderSwitch(gen);
271 if (CAN_LOCAL_STORAGE) {
272 window.localStorage.setItem('gender-render', gen);
273 }
274 };
275 // do the actual switching
276 this.genderSwitch = function(gender) {
277 mw.log('switching gender for genderswitcher for '+self.index+' to '+gender);
278 self.$buttons.find('.button-selected').removeClass('button-selected');
279 self.button[gender].addClass('button-selected');
280
281 var x = self.$box.find('.infobox-bonuses-image.render-'+gender+'');
282 self.$td_inner.empty().append(x.find('>*').clone());
283 self.visible_gender = gender;
284 };
285 this.refreshImage = function(index,anchor) {
286 // for when a main infobox switch happens
287 // this is a post-switch function so the new images are in the original cells
288 // we just gotta clone them into the visible cell again
289 self.genderSwitch(self.visible_gender);
290 mw.log('refreshed image for genderswitcher '+self.index);
291 };
292
293
294 // other 'interface' methods just so stuff doesn't break, just in case
295 this.switchInfobox = function(ind,anchor){/* do nothing */};
296 this.defaultVer = function(){ return false; };
297
298 mw.log('Initialising genderswitcher for '+self.index);
299 var $c_m = this.$box.find('.infobox-bonuses-image.render-m'), $c_f=this.$box.find('.infobox-bonuses-image.render-f');
300 this.$td.addClass('gender-render').attr({
301 'style': $c_m.attr('style'),
302 'rowspan': $c_m.attr('rowspan')
303 }).append(this.$td_inner);
304 $c_m.parent().append(this.$td);
305 this.$buttons.append(this.button.m, this.button.f);
306 this.$td.append(this.$buttons);
307 this.$buttons.find('span.button').on('click', this.beginSwitchEvent);
308
309 $c_m.addClass('gender-render-hidden').attr('data-gender-render', 'm');
310 $c_f.addClass('gender-render-hidden').attr('data-gender-render', 'f');
311 window.switchEventManager.addGenderRenderSwitch(self);
312 window.switchEventManager.addPostSwitchEvent(this.refreshImage);
313 this.genderSwitch(getGenderFromLS());
314 }
315
316 /**
317 * Legacy switch infoboxes, as generated by [[Template:Switch infobox]]
318 *
319 *
320 * parameters
321 * $box jQuery object representing the infobox itself (.switch-infobox)
322 * index index of this infobox, from $.each
323 */
324 function LegacySwitchInfobox($box, index) {
325 var self = this;
326 this.$parent = $box;
327 this.index = index;
328 this.$originalButtons = self.$parent.find('.switch-infobox-triggers');
329 this.$items = self.$parent.find('.item');
330
331 /* click/change event - triggers switch event manager */
332 this.beginSwitchEvent = function(e) {
333 var $tgt = $(e.currentTarget);
334 mw.log('beginSwitchEvent triggered in legacy infobox, id '+self.index);
335 window.switchEventManager.trigger($tgt.attr('data-id'), $tgt.attr('data-anchor'), self.$parent);
336 };
337
338 /* click/change event - triggers switch event manager */
339 this.switchInfobox = function(index, text){
340 if (text === '@init@') {
341 text = self.$buttons.find('[data-switch-index="1"]').attr('data-switch-anchor');
342 }
343 var ind, txt, $thisButton = self.$buttons.find('[data-anchor="'+text+'"]').first();
344 mw.log('switching legacy infobox, id '+self.index);
345 if ($thisButton.length) {
346 txt = text;
347 ind = $thisButton.attr('data-id');
348 } else {
349 return;
350 /*ind = index;
351 $thisButton = self.$buttons.find('[data-id="'+ind+'"]');
352 if ($thisButton.length) {
353 txt = $thisButton.attr('data-anchor');
354 }*/
355 }
356 if (txt === undefined) {
357 return;
358 }
359 self.$buttons.find('.trigger').removeClass('button-selected');
360 self.$buttons.find('.trigger[data-id="'+ind+'"]').addClass('button-selected');
361
362 self.$items.filter('.showing').removeClass('showing');
363 self.$items.filter('[data-id="'+ind+'"]').addClass('showing');
364 };
365
366 /* default version - not supported by legacy, always false */
367 this.defaultVer = function () { return false; };
368
369 this.isParentOf = function ($triggerer) {
370 return self.$parent.find($triggerer).length > 0;
371 };
372
373 /* init */
374 mw.log('setting up legacy infobox, id '+self.index);
375 // add anchor text
376 self.$originalButtons.find('span.trigger.button').each(function(i,e){
377 var $e = $(e);
378 $e.attr('data-anchor', '#'+$e.text().replace(' ', '_'));
379 });
380
381 // append triggers to every item
382 // if contents has a infobox, add to a caption of that
383 // else just put at top
384 self.$items.each(function(i,e){
385 var $item = $(e);
386 if ($item.find('table.infobox').length > 0) {
387 if ($item.find('table.infobox caption').length < 1) {
388 $item.find('table.infobox').prepend('<caption>');
389 }
390 $item.find('table.infobox caption').first().prepend(self.$originalButtons.clone());
391 } else {
392 $item.prepend(self.$originalButtons.clone());
393 }
394 });
395 // remove buttons from current location
396 self.$originalButtons.remove();
397
398 // update selection
399 this.$buttons = self.$parent.find('.switch-infobox-triggers');
400 self.$buttons.find('.trigger').each(function (i,e) {
401 $(e).click(self.beginSwitchEvent);
402 });
403 self.switchInfobox(1, '@init@');
404
405 window.switchEventManager.addSwitchInfobox(this);
406 self.$parent.removeClass('loading').find('span.loading-button').remove();
407 }
408
409 /**
410 * Synced switches, as generated by [[Template:Synced switch]]
411 *
412 *
413 * parameters
414 * $box jQuery object representing the synced switch itself (.rsw-synced-switch)
415 * index index of this infobox, from $.each
416 */
417 function SyncedSwitch($box, index) {
418 var self = this;
419 this.index = index;
420 this.$syncedswitch = $box;
421 this.attachedLabels = false;
422
423 /* filling in interface - synced switch has no buttons to press so cannot trigger an event by itself */
424 this.beginSwitchEvent = function (){};
425
426 this.switchInfobox = function(index, text){
427 mw.log('switching synced switch, id '+self.index);
428 if (text === '@init@') {
429 text = self.$syncedswitch.find('[data-item="1"]').attr('data-item-text');
430 }
431 var $toShow = self.$syncedswitch.find('[data-item-text="'+text+'"]');
432 if (!(self.attachedLabels && $toShow.length)) {
433 return;
434 //$toShow = self.$syncedswitch.find('[data-item="'+index+'"]');
435 }
436 if (!$toShow.length) {
437 // show default instead
438 self.$syncedswitch.find('.rsw-synced-switch-item').removeClass('showing');
439 self.$syncedswitch.find('[data-item="0"]').addClass('showing');
440 } else {
441 self.$syncedswitch.find('.rsw-synced-switch-item').removeClass('showing');
442 $toShow.addClass('showing');
443 }
444 };
445
446 this.genderSwitch = function(gender){
447 var $gens = self.$syncedswitch.find('.render-m, .render-f');
448 var srch = '.render-'+gender;
449 if ($gens.length) {
450 $gens.each(function(i,e){
451 var $e = $(e);
452 if ($e.is(srch)) {
453 $e.removeClass('gender-render-hidden').addClass('gender-render-showing');
454 } else {
455 $e.removeClass('gender-render-showing').addClass('gender-render-hidden');
456 }
457 });
458 }
459 };
460
461 /* default version - not supported by synced switches, always false */
462 this.defaultVer = function () { return false; };
463
464 this.isParentOf = function ($triggerer) {
465 return self.$syncedswitch.find($triggerer).length > 0;
466 };
467
468 /* init */
469 mw.log('setting up synced switch, id '+self.index);
470 // attempt to apply some button text from a SwitchInfobox
471 if ($('.infobox.infobox-switch').length) {
472 self.attachedLabels = true;
473 var $linkedButtonTextInfobox = $('.infobox.infobox-switch').first();
474 self.$syncedswitch.find('.rsw-synced-switch-item').each(function(i,e){
475 var $e = $(e);
476 if ($e.attr('data-item-text') === undefined) {
477 $e.attr('data-item-text', $linkedButtonTextInfobox.find('[data-switch-index="'+i+'"]').attr('data-switch-anchor'));
478 }
479 });
480 }
481 self.switchInfobox(1, '@init@');
482 window.switchEventManager.addSwitchInfobox(this);
483 if (self.$syncedswitch.find('.render-m, .render-f').length) {
484 window.switchEventManager.addGenderRenderSwitch(self);
485 this.genderSwitch(getGenderFromLS());
486 }
487 }
488
489 /**
490 * Event manager
491 * Observer pattern
492 * Globally available as window.switchEventManager
493 *
494 * Methods
495 * addSwitchInfobox(l)
496 * adds switch infobox (of any type) to the list of switch infoboxes listening to trigger events
497 * l switch infobox
498 *
499 * addPreSwitchEvent(f)
500 * adds the function to a list of functions that runs when the switch event is triggered but before any other action is taken
501 * the function is passed the index and anchor (in that order) that was passed to the trigger function
502 * returning the boolean true from the function will cancel the switch event
503 * trying to add a non-function is a noop
504 * e function to run
505 *
506 * addPostSwitchEvent(f)
507 * 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)
508 * the function is passed the index and anchor (in that order) that was passed to the trigger function
509 * the return value is ignored
510 * trying to add a non-function is a noop
511 * e function to run
512 *
513 * trigger(i, a)
514 * triggers the switch event on all listeners
515 * will prefer switching to the anchor if available
516 * i index to switch to
517 * a anchor to switch to
518 *
519 * makeSwitchInfobox($box)
520 * creates the correct object for the passed switch infobox, based on the classes of the infobox
521 * is a noop if it does not match any of the selectors
522 * infobox is given an index based on the internal counter for the switch
523 * $box jQuery object for the switch infobox (the jQuery object passed to the above functions, see above for selectors checked)
524 *
525 * addIndex(i)
526 * updates the internal counter by adding i to it
527 * if i is not a number or is negative, is a noop
528 * used for manually setting up infoboxes (init) or creating a new type to plugin
529 * i number to add
530 */
531
532 function SwitchEventManager() {
533 var self = this, switchInfoboxes = [], genderRenderSwitchers = [], preSwitchEvents = [], postSwitchEvents = [], index = 0;
534
535 // actual switch infoboxes to change
536 this.addSwitchInfobox = function(l) {
537 switchInfoboxes.push(l);
538 };
539
540 this.addGenderRenderSwitch = function(gs) {
541 genderRenderSwitchers.push(gs);
542 };
543
544 // things to do when switch button is clicked but before any switching
545 this.addPreSwitchEvent = function(e) {
546 if (typeof(e) === 'function') {
547 preSwitchEvents.push(e);
548 }
549 };
550 this.addPostSwitchEvent = function(e) {
551 if (typeof(e) === 'function') {
552 postSwitchEvents.push(e);
553 }
554 };
555
556 this.trigger = function(index, anchor, $triggerer) {
557 mw.log('Triggering switch event for index '+index+'; text '+anchor);
558 // using a real for loop so we can use return to exit the trigger function
559 for (var i=0; i < preSwitchEvents.length; i++){
560 var ret = preSwitchEvents[i](index,anchor);
561 if (typeof(ret) === 'boolean') {
562 if (ret) {
563 mw.log('switching was cancelled');
564 return;
565 }
566 }
567 }
568
569 // close all tooltips on the page
570 $('.js-tooltip-wrapper').trigger('js-tooltip-close');
571
572 // trigger switching on listeners
573 switchInfoboxes.forEach(function (e) {
574 if (!e.isParentOf($triggerer)) {
575 e.switchInfobox(index, anchor);
576 }
577 });
578
579 // update hash
580 if (typeof anchor === 'string') {
581 var _anchor = anchor;
582 if (_anchor === '@init@') {
583 _anchor = '';
584 }
585
586 if (window.history && window.history.replaceState) {
587 if (window.location.hash !== '') {
588 window.history.replaceState({}, '', window.location.href.replace(window.location.hash, _anchor));
589 } else {
590 window.history.replaceState({}, '', window.location.href + _anchor);
591 }
592 } else {
593 // replaceState not supported, I guess we just change the hash normally?
594 window.location.hash = _anchor;
595 }
596 }
597
598 postSwitchEvents.forEach(function(e){
599 e(index, anchor);
600 });
601 };
602
603 this.triggerGenderRenderSwitch = function(gender){
604 mw.log(genderRenderSwitchers);
605 for (var i = 0; i<genderRenderSwitchers.length; i++) {
606 genderRenderSwitchers[i].genderSwitch(gender);
607 }
608 };
609
610 /* attempts to detect what type of switch infobox this is and applies the relevant type */
611 // mostly for external access
612 this.makeSwitchInfobox = function($e) {
613 if ($e.is('.infobox-switch')) {
614 return new SwitchInfobox($e, index++);
615 }
616 if ($e.hasClass('switch-infobox')) {
617 return new LegacySwitchInfobox($e, index++);
618 }
619 if ($e.hasClass('rsw-synced-switch')) {
620 return new SyncedSwitch($e, index++);
621 }
622 };
623 this.addIndex = function(i) {
624 if (typeof(i) === 'number') {
625 i += Math.max(Math.floor(i), 0);
626 }
627 };
628 this.applyDefaultVersion = function() {
629 if (window.location.hash !== '') {
630 self.trigger(1, window.location.hash);
631 return;
632 } else {
633 // real for loop so we can return out of the function
634 for (var i = 0; i<switchInfoboxes.length; i++) {
635 var defver = switchInfoboxes[i].defaultVer();
636 if (typeof(defver) === 'object') {
637 self.trigger(defver.idx, defver.txt);
638 return;
639 }
640 }
641 }
642 self.trigger(1, '@init@');
643 };
644 }
645
646 function init() {
647 // mirror rsw-util
648 try {
649 localStorage.setItem('test', 'test');
650 localStorage.removeItem('test');
651 CAN_LOCAL_STORAGE = true;
652 } catch (e) {
653 CAN_LOCAL_STORAGE = false;
654 }
655 var index = 0;
656 window.switchEventManager = new SwitchEventManager();
657 $('.infobox-switch').each(function(i,e){
658 return new SwitchInfobox($(e), index++);
659 });
660 $('.switch-infobox').each(function(i,e){
661 return new LegacySwitchInfobox($(e), index++);
662 });
663 $('.rsw-synced-switch').each(function(i,e){
664 return new SyncedSwitch($(e), index++);
665 });
666 window.switchEventManager.addIndex(index);
667 // reinitialize any kartographer map frames added due to a switch
668 if ($('.infobox-switch .mw-kartographer-map').length
669 || $('.infobox-switch-resources .mw-kartographer-map').length
670 || $('.switch-infobox .mw-kartographer-map').length
671 || $('.rsw-synced-switch .mw-kartographer-map').length) {
672 window.switchEventManager.addPostSwitchEvent(function() {
673 mw.hook('wikipage.content').fire($('a.mw-kartographer-map').parent());
674 });
675 }
676
677 window.switchEventManager.applyDefaultVersion();
678 }
679
680 $(init);
681 })
682 // </nowiki>