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.
// Skin Switch Button for monobook to oasis and vice versa
// and for monobook and oasis to wikiamobile.
// The button in oasis is on the bottom toolbar.
importScriptPage('SkinSwitchButton/code.js', 'dev');
// SyntaxHighlight for monobook.
importScriptPage('MonobookHighlight.js', 'dev');
/*importArticles({
type: 'script',
articles: [
'u:dev:MonobookHighlight.js'
'u:dev:SkinSwitchButton/code.js'
]
}); */
// __NOWYSIWYG__ <syntaxhighlight lang="javascript">
/* Copyright (C) 2012 Lunarity
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*jshint curly:false laxbreak:true smarttabs:true jquery:true es5:true */
/*global mediaWiki */
// Prevent double runs
if (!window.DisplayClockJS || typeof(window.DisplayClockJS.kill) !== 'function')
(function($, mw, window, Date) {
"use strict";
// The default emulates the old appearance
var config = {
format: '\u00A0UTC: %2d %2H:%2M:%2S',
location: 'header',
// Shannon's Sampling Theorem: Signal=1Hz, sample it at 2Hz for 100% accuracy
interval: 500,
monofonts: "Monaco, Consolas, 'Lucida Console', monospace",
hoverText: {
en: "Click here to make the server purge and regenerate (update) this page",
es: "Haga clic aquí para purgar el servidor y actualizar esta página"
}
};
config.hoverText = config.hoverText[mw.config.get('wgUserLanguage')] || config.hoverText.en;
// Config comes in 2 flavours: Backwards compat raw format string and object conf.
if ($.isPlainObject(window.DisplayClockJS)) {
$.extend(config, window.DisplayClockJS);
} else if (window.DisplayClockJS) {
config.format = window.DisplayClockJS;
}
window.DisplayClockJS = config;
// We need mw.util to build this so it's created later on.
var $link;
// Day names are available from MediaWiki:Monday, Mon.
// We can bulk AJAX all of them but I really don't want to do that.
// NOTE: Index 0 of these arrays are an empty string, hence the slice
// NOTE: These are Wiki Content Language months, not user language
var printDateFormatted = makePrintDateFormatted(
mw.config.get('wgMonthNames').slice(1),
mw.config.get('wgMonthNamesShort').slice(1)
);
var clockInterval = null;
// Public function to remove the clock from the UI
function killClock() {
if (clockInterval !== null) {
window.clearInterval(clockInterval);
clockInterval = null;
$('#DisplayClockJS').remove();
}
delete config.kill;
}
config.kill = $.noop;
var startUp = function($) {
// Prevent double runs and avoid two clocks at once.
if ($('#DisplayClockJS, #displayTimer, #showdate').length) return;
var $parent, css, mode = 'append';
if (({oasis:1, wikia:1})[mw.config.get('skin')] === 1) {
css = { // Common styles
position: 'absolute',
fontFamily: config.monofonts,
lineHeight: 'normal'
};
$parent = $('#WikiHeader div.buttons');
if ($parent.length) {
css.top = '-1.33em';
css.right = 0;
} else { // Try an edit page
$parent = $('#EditPageHeader');
if ($parent.length) (function($, $parent, css) {
var $sibling = $parent.find('#HelpLink'),
$container = $sibling.offsetParent(), // Should be === $parent
offset = $sibling.position(); // WARN: Reflow
if (!offset) offset = { left: $container.innerWidth() };
// Position ourself a few px left of the HelpLink
offset = $container.innerWidth() - offset.left + 10;
// In case the Help Link is missing for some reason...
$sibling = $sibling.find('a').add($parent.find('#NotificationsLink > a'));
// Don't try to purge an edit page
$link.removeAttr('href').removeAttr('title');
// More CSS rules
css.right = offset + 'px';
css.top = '5px';
css.fontSize = '11px';
// For consistency, match color with header
css.color = $sibling.css('color');
})($, $parent, css);
}
} else {
$parent = $('#column-one');
css = {
textTransform: 'none',
fontFamily: config.monofonts
};
mode = 'append';
}
// Unable to find any acceptable attachment point
if (!$parent.length) {
if (window.console) window.console.error('DISPLAYCLOCK: Failed to attach to page!');
return;
}
// Attach everything
$link.css(css);
var $node = ($parent.is('ul') ? $(document.createElement('li')).append($link) : $link);
$parent[mode]($node.prop('id', 'DisplayClockJS'));
// Start
updateTime();
// 500ms is the floor, negative or tiny values will be lifted up to 500 as
// anything smaller than that is a waste of CPU power
var interval = config.interval > 500 ? config.interval : 500;
clockInterval = window.setInterval(updateTime, interval);
config.kill = killClock;
};
mw.loader.using('mediawiki.util', function() {
$link = $(document.createElement('a'))
.prop({
href: '?action=purge',
title: config.hoverText + ''
})
.data('DisplayClockJS', config) // Magic flag to help detect removal
;
$(startUp);
startUp = null;
});
function updateTime() {
// Check for removed from DOM, data is deleted when .remove() is called
if (!$link.data('DisplayClockJS')) return killClock();
var d = new Date();
d.setMinutes(d.getMinutes() + d.getTimezoneOffset()); // To UTC
$link.text(printDateFormatted(d, config.format + ''));
}
// Based on C strftime but without the parts we can't get at (because the JS
// calendar functions suck)
// NOT supported: [%a %A %b %B] %c %Z
// POSIX Extra: %u (Monday as Day 1 instead of Sunday)
// %V %G %g (ISO 8601 Week/Year)
// It also adds a 'select from list using index' feature
// '%{Day 1;Day 2;Day 3;Day Any}d', if first day of month then 'Day 1', etc
function makePrintDateFormatted(monthsLong, monthsShort, daysLong, daysShort) {
/*jshint bitwise:false */
var Cases = {
// Double percent (insert percent char)
'%': function() { return '%'; },
// Day of month number (1-31)
d: function(d) {
var r = d.getDate();
return { v: r, i: r - 1 };
},
// ISO 8601 Year, used in conjunction with %V
G: function(d) {
var r = d.getFullYear(), day = d.getDate(), month = d.getMonth();
// If we're in the first 3 days of the year then we need to see if we are
// in the ISO week of this year, or last ISO week of last year.
if (month === 0 && day < 4) {
day = d.getDay();
// Sunday, Friday, Saturday means we're in last year
if (day === 0 || day > 4) --r;
} else if (month === 11 && day > 28) { // Last 3 days
// If the last week is only 3 or less days long then this week is
// actually part of next year
// Next Year: 29=M 30=M,T 31=M,T,W
month = d.getDay();
if (month !== 0 && month < day - 27) ++r;
}
return r;
},
// ISO 8601 Short 2 digit Year
g: function(d) { return Cases.G(d) % 100; },
// Hour number (0-23)
H: function(d) { return d.getHours(); },
// Hour number (1-12)
I: function(d) {
var r = d.getHours() % 12;
return { i: r, v: r || 12 }; // 0 becomes 12
},
// Day of year (1-366)
j: function(d, ys) {
// Calculation is 'get first day of year' subtract that from our date
// (the result is milliseconds) then divide by ms in a day and floor.
var r = (d - ys) / 864e5 | 0;
return { i: r, v: r + 1 };
},
// Month (0-12)
m: function(d) {
var r = d.getMonth();
return { i: r, v: r + 1 };
},
// Minute (0-59)
M: function(d) { return d.getMinutes(); },
// AM/PM
p: function(d) { return d.getHours() < 12 ? 'AM' : 'PM'; },
// Seconds (0-59)
S: function(d) { return d.getSeconds(); },
// Day of week (1-7) [1=Monday]
u: function(d) {
var r = (d.getDay() + 6) % 7;
return { i: r, v: r + 1 };
},
// Week of year using Sunday as first day of week (0-53)
U: function(d, ys) {
// Week 0 = Everything up to first Sunday, first Sunday = Week 1
// This is important, if first day is Sunday, there is no Week 0
var doy = Cases.j(d, ys).i; // Day of year
doy += ys.getDay() || 7;
return doy / 7 | 0;
},
// ISO 8601 Week (Monday is first day, Week 1 is the one with the first Thursday)
// Range: 1-53
V: function calculateISOWeek(d, ys) {
var r = { v: Cases.W(d, ys) }, thurs = ys.getDay();
if (thurs > 1 && thurs < 5) {
// If the first day is a monday then the week count is already right.
// If the day is Tuesday, Wednesday, Thursday then we have to correct
// for an extra week here.
++r.v;
} else if (r.v === 0) {
// Week 0 Friday / Saturday / Sunday is part of last year
// (This recursion is safe since r.v won't be 0 again)
r = d.getFullYear() - 1;
return calculateISOWeek(new Date(r, 11, 31), new Date(r, 0, 1));
}
r.i = r.v - 1;
return r;
},
// Day of week (1-7) [1=Sunday]
w: function(d) {
var r = d.getDay();
return { i: r, v: r + 1 };
},
// Week of year using Monday as first day of week (0-53)
W: function(d, ys) {
var doy = Cases.j(d, ys).i;
doy += (ys.getDay() + 6) % 7 || 7;
return doy / 7 | 0;
},
// Locale dependent time string (arbitrary text)
X: function(d) {
return d.toLocaleTimeString();
},
// Locale dependent date string (arbitrary text)
x: function(d) {
return d.toLocaleDateString();
},
// Year (last 2 digits only)
y: function(d) { return d.getFullYear() % 100; },
// Year (Full)
Y: function(d) { return d.getFullYear(); }
};
// Optional features that must be provided by an external data source
if (daysLong) {
Cases.A = function(d) {
return daysLong[d.getDay()];
};
}
if (daysShort) {
Cases.a = function(d) {
return daysShort[d.getDay()];
};
}
if (monthsLong) {
Cases.B = function(d) {
return monthsLong[d.getMonth()];
};
}
if (monthsShort) {
Cases.b = function(d) {
return monthsShort[d.getMonth()];
};
}
function padString(s, l, c) {
c = c || (typeof(s) === 'number' ? '0' : ' ');
l = l - (s += '').length | 0; // Floor/NaN->0
if (l <= 0) return s;
do { // Power-of-2, max 32 iterations (run out of RAM before that)
if ((l & 1) === 1) s = c + s;
c += c;
} while ((l >>>= 1) !== 0);
return s;
}
// NOTE: This code has been profiled and optimised. It can attain 100,000+
// executions per second using reasonably complex format strings in Chrome.
function printDateFormatted(date, format) {
var regex = /%([0-9]*)(?:\{([^\}]*)\})?([A-Za-z%])/g,
result = '', yearstart = new Date(date.getFullYear(), 0, 1),
li = 0, m, list, pass, passFn,
cases = Cases, pad = padString, toInt = window.parseInt;
while ((m = regex.exec(format)) !== null) {
result += format.substring(li, m.index);
li = regex.lastIndex;
passFn = cases[m[3]];
if (typeof(passFn) !== 'function') {
result += '¿' + m[3] + '?';
continue;
}
pass = passFn(date, yearstart);
// Look for a 'choose' list
if (m[2]) {
if (typeof(pass) === 'object') {
pass = pass.i === void 0 ? pass.v : pass.i;
}
if (typeof(pass) === 'number') {
list = m[2].split(';');
if (!(pass > -1 && pass < list.length)) pass = list.length - 1;
pass = list[pass];
}
} else if (typeof(pass) === 'object') {
pass = pass.v;
}
result += pad(pass, toInt(m[1], 10));
}
result += format.substr(li);
return result;
}
return printDateFormatted;
}
})(jQuery, mediaWiki, window, Date);
// </syntaxhighlight>