summaryrefslogtreecommitdiff
path: root/skins/common
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2009-02-22 13:37:51 +0100
committerPierre Schmitz <pierre@archlinux.de>2009-02-22 13:37:51 +0100
commitb9b85843572bf283f48285001e276ba7e61b63f6 (patch)
tree4c6f4571552ada9ccfb4030481dcf77308f8b254 /skins/common
parentd9a20acc4e789cca747ad360d87ee3f3e7aa58c1 (diff)
updated to MediaWiki 1.14.0
Diffstat (limited to 'skins/common')
-rw-r--r--skins/common/ajax.js11
-rw-r--r--skins/common/ajaxsearch.js103
-rw-r--r--skins/common/ajaxwatch.js15
-rw-r--r--skins/common/block.js2
-rw-r--r--skins/common/cologneblue.css13
-rw-r--r--skins/common/common_rtl.css5
-rw-r--r--skins/common/diff.css67
-rw-r--r--skins/common/diff.js2
-rw-r--r--skins/common/enhancedchanges.js40
-rw-r--r--skins/common/mwsuggest.js248
-rw-r--r--skins/common/oldshared.css15
-rw-r--r--skins/common/prefs.js45
-rw-r--r--skins/common/preview.js1
-rw-r--r--skins/common/protect.js527
-rw-r--r--skins/common/shared.css76
-rw-r--r--skins/common/wikibits.js281
-rw-r--r--skins/common/wikiprintable.css2
-rw-r--r--skins/common/wikistandard.css2
18 files changed, 931 insertions, 524 deletions
diff --git a/skins/common/ajax.js b/skins/common/ajax.js
index 854d7a00..afcfa708 100644
--- a/skins/common/ajax.js
+++ b/skins/common/ajax.js
@@ -154,3 +154,14 @@ function sajax_do_call(func_name, args, target) {
return true;
}
+
+/**
+ * @return boolean whether the browser supports XMLHttpRequest
+ */
+function wfSupportsAjax() {
+ var request = sajax_init_object();
+ var supportsAjax = request ? true : false;
+ delete request;
+ return supportsAjax;
+}
+
diff --git a/skins/common/ajaxsearch.js b/skins/common/ajaxsearch.js
deleted file mode 100644
index b9fb56f3..00000000
--- a/skins/common/ajaxsearch.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// remote scripting library
-// (c) copyright 2005 modernmethod, inc
-
-var started;
-var typing;
-var memory=null;
-var body=null;
-var oldbody=null;
-
-// Remove the typing barrier to allow call() to complete
-function Search_doneTyping()
-{
- typing=false;
-}
-
-// Wait 500ms to run call()
-function Searching_Go()
-{
- setTimeout("Searching_Call()", 500);
-}
-
-// If the user is typing wait until they are done.
-function Search_Typing() {
- started=true;
- typing=true;
- setTimeout("Search_doneTyping()", 500);
-
- // I believe these are needed by IE for when the users press return?
- if (window.event)
- {
- if (event.keyCode == 13)
- {
- event.cancelBubble = true;
- event.returnValue = true;
- }
- }
-}
-
-// Set the body div to the results
-function Searching_SetResult( request )
-{
- if ( request.status != 200 ) {
- alert("Error: " + request.status + " " + request.statusText + ": " + request.responseText);
- return;
- }
-
- var result = request.responseText;
-
- //body.innerHTML = result;
- t = document.getElementById("searchTarget");
- if ( t == null ) {
- oldbody=body.innerHTML;
- body.innerHTML= '<div id="searchTargetContainer"><div id="searchTarget" ></div></div>' ;
- t = document.getElementById("searchTarget");
- }
- t.innerHTML = result;
- t.style.display='block';
-}
-
-function Searching_Hide_Results()
-{
- t = document.getElementById("searchTarget");
- t.style.display='none';
- body.innerHTML = oldbody;
-}
-
-
-// This will call the php function that will eventually
-// return a results table
-function Searching_Call()
-{
- var x;
- Searching_Go();
-
- //Don't proceed if user is typing
- if (typing)
- return;
-
- x = document.getElementById("searchInput").value;
-
- // Don't search again if the query is the same
- if (x==memory)
- return;
-
- memory=x;
- if (started) {
- // Don't search for blank or < 3 chars.
- if ((x=="") || (x.length < 3))
- {
- return;
- }
-
- sajax_do_call( "wfSajaxSearch", [ x ], Searching_SetResult );
- }
-}
-
-//Initialize
-function sajax_onload() {
- x = document.getElementById( 'searchInput' );
- x.onkeypress= function() { Search_Typing(); };
- Searching_Go();
- body = document.getElementById("content");
-}
diff --git a/skins/common/ajaxwatch.js b/skins/common/ajaxwatch.js
index b30e4ffd..c8d90b80 100644
--- a/skins/common/ajaxwatch.js
+++ b/skins/common/ajaxwatch.js
@@ -101,6 +101,11 @@ wgAjaxWatch.processResult = function(request) {
if(wgAjaxWatch.timeoutID) {
window.clearTimeout(wgAjaxWatch.timeoutID);
}
+ // Bug 12395 - avoid some watch link confusion on edit
+ var watchthis = document.getElementById("wpWatchthis");
+ if( watchthis && response.match(/^<[uw]#>/) ) {
+ watchthis.checked = response.match(/^<w#>/) ? "checked" : "";
+ }
return;
};
@@ -146,13 +151,3 @@ wgAjaxWatch.onLoad = function() {
};
hookEvent("load", wgAjaxWatch.onLoad);
-
-/**
- * @return boolean whether the browser supports XMLHttpRequest
- */
-function wfSupportsAjax() {
- var request = sajax_init_object();
- var supportsAjax = request ? true : false;
- delete request;
- return supportsAjax;
-}
diff --git a/skins/common/block.js b/skins/common/block.js
index 78ae3bf2..6f7be0cd 100644
--- a/skins/common/block.js
+++ b/skins/common/block.js
@@ -1,3 +1,5 @@
+addOnloadHook(considerChangingExpiryFocus);
+
function considerChangingExpiryFocus() {
if (!document.getElementById) {
return;
diff --git a/skins/common/cologneblue.css b/skins/common/cologneblue.css
index 670996ea..2723bbef 100644
--- a/skins/common/cologneblue.css
+++ b/skins/common/cologneblue.css
@@ -94,16 +94,3 @@ a.new, #quickbar a.new { color: #CC2200; }
h2, h3, h4, h5, h6 { margin-bottom: 0; }
small { font-size: 75%; }
input.mw-searchInput { width: 106px; }
-
-/* Recreating-deleted-page/reupload file warning and log entries */
-div#mw-upload-deleted-warn,
-div#mw-recreate-deleted-warn {
- padding: 3px;
- margin-top: 3px;
- margin-bottom: 3px;
- border: 1px solid #6688AA;
-}
-div#mw-upload-deleted-warn ul li,
-div#mw-recreate-deleted-warn ul li {
- font-size: 90%;
-} \ No newline at end of file
diff --git a/skins/common/common_rtl.css b/skins/common/common_rtl.css
index cda3835d..11fc995b 100644
--- a/skins/common/common_rtl.css
+++ b/skins/common/common_rtl.css
@@ -28,8 +28,9 @@ div.tright, div.floatright {
div.tleft, div.floatleft {
clear: left;
}
-/* Convenience links to edit block and delete reasons */
-p.mw-ipb-conveniencelinks, p.mw-filedelete-editreasons, p.mw-delete-editreasons {
+/* Convenience links to edit block, delete and protect reasons */
+p.mw-ipb-conveniencelinks, p.mw-protect-editreasons,
+p.mw-filedelete-editreasons, p.mw-delete-editreasons {
float: left;
}
table.filehistory th {
diff --git a/skins/common/diff.css b/skins/common/diff.css
index b262222a..6afa3734 100644
--- a/skins/common/diff.css
+++ b/skins/common/diff.css
@@ -74,3 +74,70 @@ table.diff td div {
table: */
/* overflow: visible; */
}
+
+/*
+ * Styles for the HTML Diff
+ */
+div.diff-switchtype{
+ text-align: center;
+ font-weight: bold;
+ font-size: smaller;
+}
+
+span.diff-html-added {
+ font-size: 100%;
+ background-color: #20ff20
+}
+
+span.diff-html-removed {
+ font-size: 100%;
+ text-decoration: line-through;
+ background-color: #ff2020
+}
+
+span.diff-html-changed {
+ background: url(images/diffunderline.gif) bottom repeat-x;
+ /* Hack for IE5.5, see http://lists.wikimedia.org/pipermail/wikitech-l/2008-November/040273.html */
+ *background-color: #c6c6fd; /* light blue */
+}
+
+span.diff-html-added img{
+ border: 5px solid #ccffcc;
+}
+
+span.diff-html-removed img{
+ border: 5px solid #fdc6c6;
+}
+
+span.diff-html-changed img{
+ border: 5px dotted #000099;
+
+}
+
+span.diff-html-changed {
+ position: relative; /* this is key */
+ cursor: help;
+}
+
+span.diff-html-changed span.tip {
+ display: none; /* so is this */
+}
+
+/* tooltip will display on :hover event */
+
+span.diff-html-changed:hover span.tip {
+ display: block;
+ z-index: 95;
+ position: absolute;
+ top: 2.5em;
+ left: 0;
+ width: auto;
+ line-height: 1.2em;
+ padding: 3px 7px 4px 6px;
+ border: 1px solid #336;
+ background-color: #f7f7ee;
+ font-size: 10px;
+ text-align: left;
+}
+
+
diff --git a/skins/common/diff.js b/skins/common/diff.js
index e80a895c..5fd151fc 100644
--- a/skins/common/diff.js
+++ b/skins/common/diff.js
@@ -17,4 +17,4 @@ if (navigator && navigator.product == "Gecko" && navigator.productSub < "2002113
lastSheet.insertRule(
"table.diff td div { overflow: visible; }",
lastSheet.cssRules.length);
-} \ No newline at end of file
+}
diff --git a/skins/common/enhancedchanges.js b/skins/common/enhancedchanges.js
new file mode 100644
index 00000000..b1789c9e
--- /dev/null
+++ b/skins/common/enhancedchanges.js
@@ -0,0 +1,40 @@
+/*
+ JavaScript file for enhanced recentchanges
+ */
+
+/*
+ * Add the CSS to hide parts that should be collapsed
+ *
+ * We do this with JS so everything will be expanded by default
+ * if JS is disabled
+ */
+appendCSS('.mw-changeslist-hidden {'+
+ ' display:none;'+
+ '}'+
+ 'div.mw-changeslist-expanded {'+
+ ' display:block;'+
+ '}'+
+ 'span.mw-changeslist-expanded {'+
+ ' display:inline !important;'+
+ ' visibility:visible !important;'+
+ '}'
+);
+
+/*
+ * Switch an RC line between hidden/shown
+ * @param int idNumber : the id number of the RC group
+*/
+function toggleVisibility(idNumber) {
+ var openarrow = document.getElementById("mw-rc-openarrow-"+idNumber);
+ var closearrow = document.getElementById("mw-rc-closearrow-"+idNumber);
+ var subentries = document.getElementById("mw-rc-subentries-"+idNumber);
+ if (openarrow.className == 'mw-changeslist-expanded') {
+ openarrow.className = 'mw-changeslist-hidden';
+ closearrow.className = 'mw-changeslist-expanded';
+ subentries.className = 'mw-changeslist-expanded';
+ } else {
+ openarrow.className = 'mw-changeslist-expanded';
+ closearrow.className = 'mw-changeslist-hidden';
+ subentries.className = 'mw-changeslist-hidden';
+ }
+}
diff --git a/skins/common/mwsuggest.js b/skins/common/mwsuggest.js
index 52470060..061a6451 100644
--- a/skins/common/mwsuggest.js
+++ b/skins/common/mwsuggest.js
@@ -1,13 +1,13 @@
/*
* OpenSearch ajax suggestion engine for MediaWiki
- *
+ *
* uses core MediaWiki open search support to fetch suggestions
* and show them below search boxes and other inputs
*
* by Robert Stojnic (April 2008)
*/
-
-// search_box_id -> Results object
+
+// search_box_id -> Results object
var os_map = {};
// cached data, url -> json_text
var os_cache = {};
@@ -31,16 +31,38 @@ var os_autoload_forms = new Array('searchform', 'searchform2', 'powersearch', 's
var os_is_stopped = false;
// max lines to show in suggest table
var os_max_lines_per_suggest = 7;
-
-/** Timeout timer class that will fetch the results */
+// number of steps to animate expansion/contraction of container width
+var os_animation_steps = 6;
+// num of pixels of smallest step
+var os_animation_min_step = 2;
+// delay between steps (in ms)
+var os_animation_delay = 30;
+// max width of container in percent of normal size (1 == 100%)
+var os_container_max_width = 2;
+// currently active animation timer
+var os_animation_timer = null;
+
+/** Timeout timer class that will fetch the results */
function os_Timer(id,r,query){
this.id = id;
this.r = r;
- this.query = query;
+ this.query = query;
+}
+
+/** Timer user to animate expansion/contraction of container width */
+function os_AnimationTimer(r, target){
+ this.r = r;
+ var current = document.getElementById(r.container).offsetWidth;
+ this.inc = Math.round((target-current) / os_animation_steps);
+ if(this.inc < os_animation_min_step && this.inc >=0)
+ this.inc = os_animation_min_step; // minimal animation step
+ if(this.inc > -os_animation_min_step && this.inc <0)
+ this.inc = -os_animation_min_step;
+ this.target = target;
}
/** Property class for single search box */
-function os_Results(name, formname){
+function os_Results(name, formname){
this.searchform = formname; // id of the searchform
this.searchbox = name; // id of the searchbox
this.container = name+"Suggest"; // div that holds results
@@ -50,9 +72,9 @@ function os_Results(name, formname){
this.query = null; // last processed query
this.results = null; // parsed titles
this.resultCount = 0; // number of results
- this.original = null; // query that user entered
+ this.original = null; // query that user entered
this.selected = -1; // which result is selected
- this.containerCount = 0; // number of results visible in container
+ this.containerCount = 0; // number of results visible in container
this.containerRow = 0; // height of result field in the container
this.containerTotal = 0; // total height of the container will all results
this.visible = false; // if container is visible
@@ -78,15 +100,15 @@ function os_showResults(r){
c.scrollTop = 0;
c.style.visibility = "visible";
r.visible = true;
- }
+ }
}
function os_operaWidthFix(x){
// TODO: better css2 incompatibility detection here
if(is_opera || is_khtml || navigator.userAgent.toLowerCase().indexOf('firefox/1')!=-1){
- return x - 30; // opera&konqueror & old firefox don't understand overflow-x, estimate scrollbar width
- }
- return x;
+ return 30; // opera&konqueror & old firefox don't understand overflow-x, estimate scrollbar width
+ }
+ return 0;
}
function os_encodeQuery(value){
@@ -175,20 +197,20 @@ function os_getElementPosition(elemID){
function os_createContainer(r){
var c = document.createElement("div");
var s = document.getElementById(r.searchbox);
- var pos = os_getElementPosition(r.searchbox);
+ var pos = os_getElementPosition(r.searchbox);
var left = pos.left;
var top = pos.top + s.offsetHeight;
c.className = "os-suggest";
- c.setAttribute("id", r.container);
- document.body.appendChild(c);
-
- // dynamically generated style params
+ c.setAttribute("id", r.container);
+ document.body.appendChild(c);
+
+ // dynamically generated style params
// IE workaround, cannot explicitely set "style" attribute
c = document.getElementById(r.container);
c.style.top = top+"px";
c.style.left = left+"px";
c.style.width = s.offsetWidth+"px";
-
+
// mouse event handlers
c.onmouseover = function(event) { os_eventMouseover(r.searchbox, event); };
c.onmousemove = function(event) { os_eventMousemove(r.searchbox, event); };
@@ -198,13 +220,13 @@ function os_createContainer(r){
}
/** change container height to fit to screen */
-function os_fitContainer(r){
+function os_fitContainer(r){
var c = document.getElementById(r.container);
var h = os_availableHeight(r) - 20;
var inc = r.containerRow;
h = parseInt(h/inc) * inc;
if(h < (2 * inc) && r.resultCount > 1) // min: two results
- h = 2 * inc;
+ h = 2 * inc;
if((h/inc) > os_max_lines_per_suggest )
h = inc * os_max_lines_per_suggest;
if(h < r.containerTotal){
@@ -217,11 +239,41 @@ function os_fitContainer(r){
}
/** If some entries are longer than the box, replace text with "..." */
function os_trimResultText(r){
+ // find max width, first see if we could expand the container to fit it
+ var maxW = 0;
+ for(var i=0;i<r.resultCount;i++){
+ var e = document.getElementById(r.resultText+i);
+ if(e.offsetWidth > maxW)
+ maxW = e.offsetWidth;
+ }
var w = document.getElementById(r.container).offsetWidth;
- if(r.containerCount < r.resultCount){
- w -= 20; // give 20px for scrollbar
+ var fix = 0;
+ if(r.containerCount < r.resultCount){
+ fix = 20; // give 20px for scrollbar
} else
- w = os_operaWidthFix(w);
+ fix = os_operaWidthFix(w);
+ if(fix < 4)
+ fix = 4; // basic padding
+ maxW += fix;
+
+ // resize container to fit more data if permitted
+ var normW = document.getElementById(r.searchbox).offsetWidth;
+ var prop = maxW / normW;
+ if(prop > os_container_max_width)
+ prop = os_container_max_width;
+ else if(prop < 1)
+ prop = 1;
+ var newW = Math.round( normW * prop );
+ if( w != newW ){
+ w = newW;
+ if( os_animation_timer != null )
+ clearInterval(os_animation_timer.id)
+ os_animation_timer = new os_AnimationTimer(r,w);
+ os_animation_timer.id = setInterval("os_animateChangeWidth()",os_animation_delay);
+ w -= fix; // this much is reserved
+ }
+
+ // trim results
if(w < 10)
return;
for(var i=0;i<r.resultCount;i++){
@@ -233,7 +285,7 @@ function os_trimResultText(r){
while(e.offsetWidth > w && (e.offsetWidth < lastW || iteration<2)){
changedText = true;
lastW = e.offsetWidth;
- var l = e.innerHTML;
+ var l = e.innerHTML;
e.innerHTML = l.substring(0,l.length-replace)+"...";
iteration++;
replace = 4; // how many chars to replace
@@ -245,8 +297,31 @@ function os_trimResultText(r){
}
}
+/** Invoked on timer to animate change in container width */
+function os_animateChangeWidth(){
+ var r = os_animation_timer.r;
+ var c = document.getElementById(r.container);
+ var w = c.offsetWidth;
+ var normW = document.getElementById(r.searchbox).offsetWidth;
+ var normL = os_getElementPosition(r.searchbox).left;
+ var inc = os_animation_timer.inc;
+ var target = os_animation_timer.target;
+ var nw = w + inc;
+ if( (inc > 0 && nw >= target) || (inc <= 0 && nw <= target) ){
+ // finished !
+ c.style.width = target+"px";
+ clearInterval(os_animation_timer.id)
+ os_animation_timer = null;
+ } else{
+ // in-progress
+ c.style.width = nw+"px";
+ if(document.documentElement.dir == "rtl")
+ c.style.left = (normL + normW + (target - nw) - os_animation_timer.target - 1)+"px";
+ }
+}
+
/** Handles data from XMLHttpRequest, and updates the suggest results */
-function os_updateResults(r, query, text, cacheKey){
+function os_updateResults(r, query, text, cacheKey){
os_cache[cacheKey] = text;
r.query = query;
r.original = query;
@@ -254,7 +329,7 @@ function os_updateResults(r, query, text, cacheKey){
r.results = null;
r.resultCount = 0;
os_hideResults(r);
- } else{
+ } else{
try {
var p = eval('('+text+')'); // simple json parse, could do a safer one
if(p.length<2 || p[1].length == 0){
@@ -262,29 +337,30 @@ function os_updateResults(r, query, text, cacheKey){
r.resultCount = 0;
os_hideResults(r);
return;
- }
+ }
var c = document.getElementById(r.container);
if(c == null)
- c = os_createContainer(r);
+ c = os_createContainer(r);
c.innerHTML = os_createResultTable(r,p[1]);
// init container table sizes
- var t = document.getElementById(r.resultTable);
- r.containerTotal = t.offsetHeight;
+ var t = document.getElementById(r.resultTable);
+ r.containerTotal = t.offsetHeight;
r.containerRow = t.offsetHeight / r.resultCount;
- os_trimResultText(r);
+ os_fitContainer(r);
+ os_trimResultText(r);
os_showResults(r);
} catch(e){
// bad response from server or such
- os_hideResults(r);
+ os_hideResults(r);
os_cache[cacheKey] = null;
}
- }
+ }
}
/** Create the result table to be placed in the container div */
function os_createResultTable(r, results){
var c = document.getElementById(r.container);
- var width = os_operaWidthFix(c.offsetWidth);
+ var width = c.offsetWidth - os_operaWidthFix(c.offsetWidth);
var html = "<table class=\"os-suggest-results\" id=\""+r.resultTable+"\" style=\"width: "+width+"px;\">";
r.results = new Array();
r.resultCount = results.length;
@@ -299,14 +375,14 @@ function os_createResultTable(r, results){
/** Fetch namespaces from checkboxes or hidden fields in the search form,
if none defined use wgSearchNamespaces global */
-function os_getNamespaces(r){
+function os_getNamespaces(r){
var namespaces = "";
var elements = document.forms[r.searchform].elements;
for(i=0; i < elements.length; i++){
var name = elements[i].name;
- if(typeof name != 'undefined' && name.length > 2
- && name[0]=='n' && name[1]=='s'
- && ((elements[i].type=='checkbox' && elements[i].checked)
+ if(typeof name != 'undefined' && name.length > 2
+ && name[0]=='n' && name[1]=='s'
+ && ((elements[i].type=='checkbox' && elements[i].checked)
|| (elements[i].type=='hidden' && elements[i].value=="1")) ){
if(namespaces!="")
namespaces+="|";
@@ -321,7 +397,7 @@ function os_getNamespaces(r){
/** Update results if user hasn't already typed something else */
function os_updateIfRelevant(r, query, text, cacheKey){
var t = document.getElementById(r.searchbox);
- if(t != null && t.value == query){ // check if response is still relevant
+ if(t != null && t.value == query){ // check if response is still relevant
os_updateResults(r, query, text, cacheKey);
}
r.query = query;
@@ -337,22 +413,22 @@ function os_delayedFetch(){
var path = wgMWSuggestTemplate.replace("{namespaces}",os_getNamespaces(r))
.replace("{dbname}",wgDBname)
.replace("{searchTerms}",os_encodeQuery(query));
-
+
// try to get from cache, if not fetch using ajax
var cached = os_cache[path];
if(cached != null){
os_updateIfRelevant(r, query, cached, path);
- } else{
+ } else{
var xmlhttp = sajax_init_object();
if(xmlhttp){
- try {
+ try {
xmlhttp.open("GET", path, true);
xmlhttp.onreadystatechange=function(){
- if (xmlhttp.readyState==4 && typeof os_updateIfRelevant == 'function') {
+ if (xmlhttp.readyState==4 && typeof os_updateIfRelevant == 'function') {
os_updateIfRelevant(r, query, xmlhttp.responseText, path);
}
};
- xmlhttp.send(null);
+ xmlhttp.send(null);
} catch (e) {
if (window.location.hostname == "localhost") {
alert("Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing.");
@@ -370,23 +446,23 @@ function os_fetchResults(r, query, timeout){
return;
} else if(query == r.query)
return; // no change
-
+
os_is_stopped = false; // make sure we're running
-
- /* var cacheKey = wgDBname+":"+query;
+
+ /* var cacheKey = wgDBname+":"+query;
var cached = os_cache[cacheKey];
if(cached != null){
os_updateResults(r,wgDBname,query,cached);
return;
} */
-
+
// cancel any pending fetches
if(os_timer != null && os_timer.id != null)
clearTimeout(os_timer.id);
- // schedule delayed fetching of results
+ // schedule delayed fetching of results
if(timeout != 0){
os_timer = new os_Timer(setTimeout("os_delayedFetch()",timeout),r,query);
- } else{
+ } else{
os_timer = new os_Timer(null,r,query);
os_delayedFetch(); // do it now!
}
@@ -397,11 +473,11 @@ function os_changeHighlight(r, cur, next, updateSearchBox){
if (next >= r.resultCount)
next = r.resultCount-1;
if (next < -1)
- next = -1;
+ next = -1;
r.selected = next;
if (cur == next)
return; // nothing to do.
-
+
if(cur >= 0){
var curRow = document.getElementById(r.resultTable + cur);
if(curRow != null)
@@ -415,7 +491,7 @@ function os_changeHighlight(r, cur, next, updateSearchBox){
newText = r.results[next];
} else
newText = r.original;
-
+
// adjust the scrollbar if any
if(r.containerCount < r.resultCount){
var c = document.getElementById(r.container);
@@ -426,10 +502,10 @@ function os_changeHighlight(r, cur, next, updateSearchBox){
else if(next >= vEnd)
c.scrollTop = (next - r.containerCount + 1) * r.containerRow;
}
-
+
// update the contents of the search box
if(updateSearchBox){
- os_updateSearchQuery(r,newText);
+ os_updateSearchQuery(r,newText);
}
}
@@ -463,8 +539,8 @@ function os_getTarget(e){
/********************
- * Keyboard events
- ********************/
+ * Keyboard events
+ ********************/
/** Event handler that will fetch results on keyup */
function os_eventKeyup(e){
@@ -472,8 +548,8 @@ function os_eventKeyup(e){
var r = os_map[targ.id];
if(r == null)
return; // not our event
-
- // some browsers won't generate keypressed for arrow keys, catch it
+
+ // some browsers won't generate keypressed for arrow keys, catch it
if(os_keypressed_count == 0){
os_processKey(r,os_cur_keypressed,targ);
}
@@ -484,8 +560,8 @@ function os_eventKeyup(e){
/** catch arrows up/down and escape to hide the suggestions */
function os_processKey(r,keypressed,targ){
if (keypressed == 40){ // Arrow Down
- if (r.visible) {
- os_changeHighlight(r, r.selected, r.selected+1, true);
+ if (r.visible) {
+ os_changeHighlight(r, r.selected, r.selected+1, true);
} else if(os_timer == null){
// user wants to get suggestions now
r.query = "";
@@ -505,12 +581,12 @@ function os_processKey(r,keypressed,targ){
}
/** When keys is held down use a timer to output regular events */
-function os_eventKeypress(e){
+function os_eventKeypress(e){
var targ = os_getTarget(e);
var r = os_map[targ.id];
if(r == null)
return; // not our event
-
+
var keypressed = os_cur_keypressed;
if(keypressed == 38 || keypressed == 40){
var d = new Date()
@@ -520,7 +596,7 @@ function os_eventKeypress(e){
return;
}
}
-
+
os_keypressed_count++;
os_processKey(r,keypressed,targ);
}
@@ -532,21 +608,21 @@ function os_eventKeydown(e){
var r = os_map[targ.id];
if(r == null)
return; // not our event
-
+
os_mouse_moved = false;
- os_cur_keypressed = (window.Event) ? e.which : e.keyCode;
+ os_cur_keypressed = (e.keyCode == undefined) ? e.which : e.keyCode;
os_last_keypress = 0;
os_keypressed_count = 0;
}
/** Event: loss of focus of input box */
-function os_eventBlur(e){
+function os_eventBlur(e){
var targ = os_getTarget(e);
var r = os_map[targ.id];
if(r == null)
return; // not our event
- if(!os_mouse_pressed)
+ if(!os_mouse_pressed)
os_hideResults(r);
}
@@ -558,19 +634,19 @@ function os_eventFocus(e){
/********************
- * Mouse events
- ********************/
+ * Mouse events
+ ********************/
/** Mouse over the container */
function os_eventMouseover(srcId, e){
- var targ = os_getTarget(e);
+ var targ = os_getTarget(e);
var r = os_map[srcId];
if(r == null || !os_mouse_moved)
return; // not our event
var num = os_getNumberSuffix(targ.id);
if(num >= 0)
os_changeHighlight(r,r.selected,num,false);
-
+
}
/* Get row where the event occured (from its id) */
@@ -596,7 +672,7 @@ function os_eventMousedown(srcId, e){
if(r == null)
return; // not our event
var num = os_getNumberSuffix(targ.id);
-
+
os_mouse_pressed = true;
if(num >= 0){
os_mouse_num = num;
@@ -604,7 +680,7 @@ function os_eventMousedown(srcId, e){
}
// keep the focus on the search field
document.getElementById(r.searchbox).focus();
-
+
return false; // prevents selection
}
@@ -615,7 +691,7 @@ function os_eventMouseup(srcId, e){
if(r == null)
return; // not our event
var num = os_getNumberSuffix(targ.id);
-
+
if(num >= 0 && os_mouse_num == num){
os_updateSearchQuery(r,r.results[num]);
os_hideResults(r);
@@ -654,10 +730,10 @@ function os_eventOnsubmit(e){
var r = os_map[os_autoload_inputs[i]];
if(r != null){
var b = document.getElementById(r.searchform);
- if(b != null && b == targ){
+ if(b != null && b == targ){
// set query value so the handler won't try to fetch additional results
r.query = document.getElementById(r.searchbox).value;
- }
+ }
os_hideResults(r);
}
}
@@ -674,7 +750,7 @@ function os_hookEvent(element, hookName, hookFunct) {
/** Init Result objects and event handlers */
function os_initHandlers(name, formname, element){
- var r = new os_Results(name, formname);
+ var r = new os_Results(name, formname);
// event handler
os_hookEvent(element, "keyup", function(event) { os_eventKeyup(event); });
os_hookEvent(element, "keydown", function(event) { os_eventKeydown(event); });
@@ -684,10 +760,10 @@ function os_initHandlers(name, formname, element){
element.setAttribute("autocomplete","off");
// stopping handler
os_hookEvent(document.getElementById(formname), "submit", function(event){ return os_eventOnsubmit(event); });
- os_map[name] = r;
+ os_map[name] = r;
// toggle link
if(document.getElementById(r.toggle) == null){
- // TODO: disable this while we figure out a way for this to work in all browsers
+ // TODO: disable this while we figure out a way for this to work in all browsers
/* if(name=='searchInput'){
// special case: place above the main search box
var t = os_createToggle(r,"os-suggest-toggle");
@@ -708,7 +784,7 @@ function os_initHandlers(name, formname, element){
t.style.visibility = "visible";
} */
}
-
+
}
/** Return the span element that contains the toggle link */
@@ -722,7 +798,7 @@ function os_createToggle(r,className){
var msg = document.createTextNode(wgMWSuggestMessages[0]);
link.appendChild(msg);
t.appendChild(link);
- return t;
+ return t;
}
/** Call when user clicks on some of the toggle links */
@@ -732,7 +808,7 @@ function os_toggle(inputId,formName){
if(r == null){
os_enableSuggestionsOn(inputId,formName);
r = os_map[inputId];
- msg = wgMWSuggestMessages[0];
+ msg = wgMWSuggestMessages[0];
} else{
os_disableSuggestionsOn(inputId,formName);
msg = wgMWSuggestMessages[1];
@@ -756,7 +832,7 @@ function os_disableSuggestionsOn(inputId){
os_hideResults(r);
// turn autocomplete on !
document.getElementById(inputId).setAttribute("autocomplete","on");
- // remove descriptor
+ // remove descriptor
os_map[inputId] = null;
}
}
@@ -769,7 +845,7 @@ function os_MWSuggestInit() {
element = document.getElementById( id );
if(element != null)
os_initHandlers(id,form,element);
- }
+ }
}
hookEvent("load", os_MWSuggestInit);
diff --git a/skins/common/oldshared.css b/skins/common/oldshared.css
index 5cffb073..3acd5e23 100644
--- a/skins/common/oldshared.css
+++ b/skins/common/oldshared.css
@@ -201,10 +201,6 @@ table.small { font-size: 100% }
font-size:150%;
margin:5px;
}
-.searchmatch {
- color: red;
- font-weight: bold;
-}
.sharedUploadNotice {
font-style: italic;
}
@@ -406,13 +402,6 @@ table.multipageimage td {
.templatesUsed { margin-top: 1em; }
-/* Recreating-deleted-page/reupload file warning and log entries */
-div#mw-upload-deleted-warn ul li,
-div#mw-recreate-deleted-warn ul li {
- font-size: 95%;
-}
-
-
.MediaTransformError {
border: thin solid #777;
background-color: #ccc;
@@ -423,3 +412,7 @@ div#mw-recreate-deleted-warn ul li {
vertical-align: middle;
font-size: 90%;
}
+
+form#specialpages {
+ display: inline;
+}
diff --git a/skins/common/prefs.js b/skins/common/prefs.js
index d9a612f9..c2554c00 100644
--- a/skins/common/prefs.js
+++ b/skins/common/prefs.js
@@ -95,6 +95,7 @@ function unhidetzbutton() {
if (tzb) {
tzb.style.display = 'inline';
}
+ updateTimezoneSelection(false);
}
// in [-]HH:MM format...
@@ -113,6 +114,50 @@ function fetchTimezone() {
function guessTimezone(box) {
document.getElementsByName("wpHourDiff")[0].value = fetchTimezone();
+ updateTimezoneSelection(true);
+}
+
+function updateTimezoneSelection(force_offset) {
+ var wpTimeZone = document.getElementsByName("wpTimeZone")[0];
+ var wpHourDiff = document.getElementsByName("wpHourDiff")[0];
+ var wpLocalTime = document.getElementById("wpLocalTime");
+ var wpServerTime = document.getElementsByName("wpServerTime")[0];
+ var minDiff = 0;
+
+ if (force_offset) wpTimeZone.selectedIndex = 1;
+ if (wpTimeZone.selectedIndex == 1) {
+ wpHourDiff.disabled = false;
+ var diffArr = wpHourDiff.value.split(':');
+ if (diffArr.length == 1) {
+ minDiff = parseInt(diffArr[0], 10) * 60;
+ } else {
+ minDiff = Math.abs(parseInt(diffArr[0], 10))*60 + parseInt(diffArr[1], 10);
+ if (parseInt(diffArr[0], 10) < 0) minDiff = -minDiff;
+ }
+ } else {
+ wpHourDiff.disabled = true;
+ var diffArr = wpTimeZone.options[wpTimeZone.selectedIndex].value.split('|');
+ minDiff = parseInt(diffArr[1], 10);
+ }
+ if (isNaN(minDiff)) minDiff = 0;
+ var localTime = parseInt(wpServerTime.value, 10) + minDiff;
+ while (localTime < 0) localTime += 1440;
+ while (localTime >= 1440) localTime -= 1440;
+
+ var hour = String(Math.floor(localTime/60));
+ if (hour.length<2) hour = '0'+hour;
+ var min = String(localTime%60);
+ if (min.length<2) min = '0'+min;
+ changeText(wpLocalTime, hour+':'+min);
+
+ if (wpTimeZone.selectedIndex != 1) {
+ hour = String(Math.abs(Math.floor(minDiff/60)));
+ if (hour.length<2) hour = '0'+hour;
+ if (minDiff < 0) hour = '-'+hour;
+ min = String(minDiff%60);
+ if (min.length<2) min = '0'+min;
+ wpHourDiff.value = hour+':'+min;
+ }
}
hookEvent("load", unhidetzbutton);
diff --git a/skins/common/preview.js b/skins/common/preview.js
index 8c5c07d3..faf611f0 100644
--- a/skins/common/preview.js
+++ b/skins/common/preview.js
@@ -87,6 +87,7 @@ function lpStatusUpdate() {
var previewContainer = document.getElementById( lpIdPreview );
if ( previewContainer && previewElement ) {
previewContainer.innerHTML = previewElement.firstChild.data;
+ previewContainer.style.display = 'block';
} else {
/* Should never happen */
window.alert(i18n(wgLivepreviewMessageFailed));
diff --git a/skins/common/protect.js b/skins/common/protect.js
index 863b95bd..d9650c82 100644
--- a/skins/common/protect.js
+++ b/skins/common/protect.js
@@ -1,218 +1,351 @@
-/**
- * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
- * on the protection form
- *
- * @param String tableId Identifier of the table containing UI bits
- * @param String labelText Text to use for the checkbox label
- */
-function protectInitialize( tableId, labelText, types ) {
- if( !( document.createTextNode && document.getElementById && document.getElementsByTagName ) )
- return false;
-
- var box = document.getElementById( tableId );
- if( !box )
- return false;
+
+var ProtectionForm = {
+ 'existingMatch': false,
+
+ /**
+ * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
+ * on the protection form
+ *
+ * @param Object opts : parameters with members:
+ * tableId Identifier of the table containing UI bits
+ * labelText Text to use for the checkbox label
+ * numTypes The number of protection types
+ * existingMatch True if all the existing expiry times match
+ */
+ 'init': function( opts ) {
+ if( !( document.createTextNode && document.getElementById && document.getElementsByTagName ) )
+ return false;
+
+ var box = document.getElementById( opts.tableId );
+ if( !box )
+ return false;
- var tbody = box.getElementsByTagName( 'tbody' )[0];
- var row = document.createElement( 'tr' );
- tbody.appendChild( row );
-
- row.appendChild( document.createElement( 'td' ) );
- var col = document.createElement( 'td' );
- row.appendChild( col );
- // If there is only one protection type, there is nothing to chain
- if( types > 1 ) {
- var check = document.createElement( 'input' );
- check.id = 'mwProtectUnchained';
- check.type = 'checkbox';
- col.appendChild( check );
- addClickHandler( check, protectChainUpdate );
-
- col.appendChild( document.createTextNode( ' ' ) );
- var label = document.createElement( 'label' );
- label.htmlFor = 'mwProtectUnchained';
- label.appendChild( document.createTextNode( labelText ) );
- col.appendChild( label );
-
- check.checked = !protectAllMatch();
- protectEnable( check.checked );
- }
-
- setCascadeCheckbox();
-
- return true;
-}
+ var boxbody = box.getElementsByTagName('tbody')[0]
+ var row = document.createElement( 'tr' );
+ boxbody.insertBefore( row, boxbody.firstChild );
+
+ this.existingMatch = opts.existingMatch;
+
+ var cell = document.createElement( 'td' );
+ row.appendChild( cell );
+ // If there is only one protection type, there is nothing to chain
+ if( opts.numTypes > 1 ) {
+ var check = document.createElement( 'input' );
+ check.id = 'mwProtectUnchained';
+ check.type = 'checkbox';
+ cell.appendChild( check );
+ addClickHandler( check, function() { ProtectionForm.onChainClick(); } );
+
+ cell.appendChild( document.createTextNode( ' ' ) );
+ var label = document.createElement( 'label' );
+ label.htmlFor = 'mwProtectUnchained';
+ label.appendChild( document.createTextNode( opts.labelText ) );
+ cell.appendChild( label );
+
+ check.checked = !this.areAllTypesMatching();
+ this.enableUnchainedInputs( check.checked );
+ }
+
+ this.updateCascadeCheckbox();
+
+ return true;
+ },
-/**
-* Determine if, given the cascadeable protection levels
-* and what is currently selected, if the cascade box
-* can be checked
-*
-* @return boolean
-*
-*/
-function setCascadeCheckbox() {
- // For non-existent titles, there is no cascade option
- if( !document.getElementById( 'mwProtect-cascade' ) ) {
+ /**
+ * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
+ */
+ 'updateCascadeCheckbox': function() {
+ // For non-existent titles, there is no cascade option
+ if( !document.getElementById( 'mwProtect-cascade' ) ) {
+ return;
+ }
+ var lists = this.getLevelSelectors();
+ for( var i = 0; i < lists.length; i++ ) {
+ if( lists[i].selectedIndex > -1 ) {
+ var items = lists[i].getElementsByTagName( 'option' );
+ var selected = items[ lists[i].selectedIndex ].value;
+ if( !this.isCascadeableLevel(selected) ) {
+ document.getElementById( 'mwProtect-cascade' ).checked = false;
+ document.getElementById( 'mwProtect-cascade' ).disabled = true;
+ return;
+ }
+ }
+ }
+ document.getElementById( 'mwProtect-cascade' ).disabled = false;
+ },
+
+ /**
+ * Is this protection level cascadeable?
+ * @param String level
+ *
+ * @return boolean
+ *
+ */
+ 'isCascadeableLevel': function( level ) {
+ for (var k = 0; k < wgCascadeableLevels.length; k++) {
+ if ( wgCascadeableLevels[k] == level ) {
+ return true;
+ }
+ }
return false;
- }
- var lists = protectSelectors();
- for( var i = 0; i < lists.length; i++ ) {
- if( lists[i].selectedIndex > -1 ) {
- var items = lists[i].getElementsByTagName( 'option' );
- var selected = items[ lists[i].selectedIndex ].value;
- if( !isCascadeableLevel(selected) ) {
- document.getElementById( 'mwProtect-cascade' ).checked = false;
- document.getElementById( 'mwProtect-cascade' ).disabled = true;
- return false;
+ },
+
+ /**
+ * When protection levels are locked together, update the rest
+ * when one action's level changes
+ *
+ * @param Element source Level selector that changed
+ */
+ 'updateLevels': function(source) {
+ if( !this.isUnchained() )
+ this.setAllSelectors( source.selectedIndex );
+ this.updateCascadeCheckbox();
+ },
+
+ /**
+ * When protection levels are locked together, update the
+ * expiries when one changes
+ *
+ * @param Element source expiry input that changed
+ */
+
+ 'updateExpiry': function(source) {
+ if( !this.isUnchained() ) {
+ var expiry = source.value;
+ this.forEachExpiryInput(function(element) {
+ element.value = expiry;
+ });
+ }
+ var listId = source.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' );
+ var list = document.getElementById( listId );
+ if (list && list.value != 'othertime' ) {
+ if ( this.isUnchained() ) {
+ list.value = 'othertime';
+ } else {
+ this.forEachExpirySelector(function(element) {
+ element.value = 'othertime';
+ });
}
}
- }
- document.getElementById( 'mwProtect-cascade' ).disabled = false;
- return true;
-}
+ },
-/**
-* Is this protection level cascadeable?
-* @param String level
-*
-* @return boolean
-*
-*/
-function isCascadeableLevel( level ) {
- for (var k = 0; k < wgCascadeableLevels.length; k++) {
- if ( wgCascadeableLevels[k] == level ) {
- return true;
- }
- }
- return false;
-}
+ /**
+ * When protection levels are locked together, update the
+ * expiry lists when one changes and clear the custom inputs
+ *
+ * @param Element source expiry selector that changed
+ */
+ 'updateExpiryList': function(source) {
+ if( !this.isUnchained() ) {
+ var expiry = source.value;
+ this.forEachExpirySelector(function(element) {
+ element.value = expiry;
+ });
+ this.forEachExpiryInput(function(element) {
+ element.value = '';
+ });
+ }
+ },
-/**
- * When protection levels are locked together, update the rest
- * when one action's level changes
- *
- * @param Element source Level selector that changed
- */
-function protectLevelsUpdate(source) {
- if( !protectUnchained() )
- protectUpdateAll( source.selectedIndex );
- setCascadeCheckbox();
-}
+ /**
+ * Update chain status and enable/disable various bits of the UI
+ * when the user changes the "unlock move permissions" checkbox
+ */
+ 'onChainClick': function() {
+ if( this.isUnchained() ) {
+ this.enableUnchainedInputs( true );
+ } else {
+ this.setAllSelectors( this.getMaxLevel() );
+ this.enableUnchainedInputs( false );
+ }
+ this.updateCascadeCheckbox();
+ },
-/**
- * Update chain status and enable/disable various bits of the UI
- * when the user changes the "unlock move permissions" checkbox
- */
-function protectChainUpdate() {
- if( protectUnchained() ) {
- protectEnable( true );
- } else {
- protectChain();
- protectEnable( false );
- }
- setCascadeCheckbox();
-}
+ /**
+ * Returns true if the named attribute in all objects in the given array are matching
+ */
+ 'matchAttribute' : function( objects, attrName ) {
+ var value = null;
-/**
- * Are all actions protected at the same level?
- *
- * @return boolean
- */
-function protectAllMatch() {
- var values = new Array();
- protectForSelectors(function(set) {
- values[values.length] = set.selectedIndex;
- });
- for (var i = 1; i < values.length; i++) {
- if (values[i] != values[0]) {
- return false;
+ // Check levels
+ for ( var i = 0; i < objects.length; i++ ) {
+ var element = objects[i];
+ if ( value == null ) {
+ value = element[attrName];
+ } else {
+ if ( value != element[attrName] ) {
+ return false;
+ }
+ }
}
- }
- return true;
-}
+ return true;
+ },
-/**
- * Is protection chaining on or off?
- *
- * @return bool
- */
-function protectUnchained() {
- var unchain = document.getElementById( 'mwProtectUnchained' );
- return unchain
- ? unchain.checked
- : true; // No control, so we need to let the user set both levels
-}
+ /**
+ * Are all actions protected at the same level, with the same expiry time?
+ *
+ * @return boolean
+ */
+ 'areAllTypesMatching': function() {
+ return this.existingMatch
+ && this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' )
+ && this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' )
+ && this.matchAttribute( this.getExpiryInputs(), 'value' );
+ },
+
+ /**
+ * Is protection chaining off?
+ *
+ * @return bool
+ */
+ 'isUnchained': function() {
+ var element = document.getElementById( 'mwProtectUnchained' );
+ return element
+ ? element.checked
+ : true; // No control, so we need to let the user set both levels
+ },
+
+ /**
+ * Find the highest protection level in any selector
+ */
+ 'getMaxLevel': function() {
+ var maxIndex = -1;
+ this.forEachLevelSelector(function(element) {
+ if (element.selectedIndex > maxIndex) {
+ maxIndex = element.selectedIndex;
+ }
+ });
+ return maxIndex;
+ },
-/**
- * Find the highest-protected action and set all others to that level
- */
-function protectChain() {
- var maxIndex = -1;
- protectForSelectors(function(set) {
- if (set.selectedIndex > maxIndex) {
- maxIndex = set.selectedIndex;
+ /**
+ * Protect all actions at the specified level
+ *
+ * @param int index Protection level
+ */
+ 'setAllSelectors': function(index) {
+ this.forEachLevelSelector(function(element) {
+ if (element.selectedIndex != index) {
+ element.selectedIndex = index;
+ }
+ });
+ },
+
+ /**
+ * Apply a callback to each protection selector
+ *
+ * @param callable func Callback function
+ */
+ 'forEachLevelSelector': function(func) {
+ var selectors = this.getLevelSelectors();
+ for (var i = 0; i < selectors.length; i++) {
+ func(selectors[i]);
}
- });
- protectUpdateAll(maxIndex);
-}
+ },
+
+ /**
+ * Get a list of all protection selectors on the page
+ *
+ * @return Array
+ */
+ 'getLevelSelectors': function() {
+ var all = document.getElementsByTagName("select");
+ var ours = new Array();
+ for (var i = 0; i < all.length; i++) {
+ var element = all[i];
+ if (element.id.match(/^mwProtect-level-/)) {
+ ours[ours.length] = element;
+ }
+ }
+ return ours;
+ },
-/**
- * Protect all actions at the specified level
- *
- * @param int index Protection level
- */
-function protectUpdateAll(index) {
- protectForSelectors(function(set) {
- if (set.selectedIndex != index) {
- set.selectedIndex = index;
+ /**
+ * Apply a callback to each expiry input
+ *
+ * @param callable func Callback function
+ */
+ 'forEachExpiryInput': function(func) {
+ var inputs = this.getExpiryInputs();
+ for (var i = 0; i < inputs.length; i++) {
+ func(inputs[i]);
}
- });
-}
+ },
-/**
- * Apply a callback to each protection selector
- *
- * @param callable func Callback function
- */
-function protectForSelectors(func) {
- var selectors = protectSelectors();
- for (var i = 0; i < selectors.length; i++) {
- func(selectors[i]);
- }
-}
+ /**
+ * Get a list of all expiry inputs on the page
+ *
+ * @return Array
+ */
+ 'getExpiryInputs': function() {
+ var all = document.getElementsByTagName("input");
+ var ours = new Array();
+ for (var i = 0; i < all.length; i++) {
+ var element = all[i];
+ if (element.name.match(/^mwProtect-expiry-/)) {
+ ours[ours.length] = element;
+ }
+ }
+ return ours;
+ },
-/**
- * Get a list of all protection selectors on the page
- *
- * @return Array
- */
-function protectSelectors() {
- var all = document.getElementsByTagName("select");
- var ours = new Array();
- for (var i = 0; i < all.length; i++) {
- var set = all[i];
- if (set.id.match(/^mwProtect-level-/)) {
- ours[ours.length] = set;
+ /**
+ * Apply a callback to each expiry selector list
+ * @param callable func Callback function
+ */
+ 'forEachExpirySelector': function(func) {
+ var inputs = this.getExpirySelectors();
+ for (var i = 0; i < inputs.length; i++) {
+ func(inputs[i]);
}
- }
- return ours;
-}
+ },
-/**
- * Enable/disable protection selectors
- *
- * @param boolean val Enable?
- */
-function protectEnable(val) {
- // fixme
- var first = true;
- protectForSelectors(function(set) {
- if (first) {
- first = false;
- } else {
- set.disabled = !val;
- set.style.visible = val ? "visible" : "hidden";
+ /**
+ * Get a list of all expiry selector lists on the page
+ *
+ * @return Array
+ */
+ 'getExpirySelectors': function() {
+ var all = document.getElementsByTagName("select");
+ var ours = new Array();
+ for (var i = 0; i < all.length; i++) {
+ var element = all[i];
+ if (element.id.match(/^mwProtectExpirySelection-/)) {
+ ours[ours.length] = element;
+ }
}
- });
+ return ours;
+ },
+
+ /**
+ * Enable/disable protection selectors and expiry inputs
+ *
+ * @param boolean val Enable?
+ */
+ 'enableUnchainedInputs': function(val) {
+ var first = true;
+ this.forEachLevelSelector(function(element) {
+ if (first) {
+ first = false;
+ } else {
+ element.disabled = !val;
+ }
+ });
+ first = true;
+ this.forEachExpiryInput(function(element) {
+ if (first) {
+ first = false;
+ } else {
+ element.disabled = !val;
+ }
+ });
+ first = true;
+ this.forEachExpirySelector(function(element) {
+ if (first) {
+ first = false;
+ } else {
+ element.disabled = !val;
+ }
+ });
+ }
}
diff --git a/skins/common/shared.css b/skins/common/shared.css
index d42fc1c0..bd306167 100644
--- a/skins/common/shared.css
+++ b/skins/common/shared.css
@@ -9,6 +9,10 @@
img.tex { vertical-align: middle; }
span.texhtml { font-family: serif; }
+/* add a bit of margin space between the preview and the toolbar */
+/* this replaces the ugly <p><br /></p> we used to insert into the page source */
+#wikiPreview.ontop { margin-bottom: 1em; }
+
/* Stop floats from intruding into edit area in previews */
#toolbar, #wpTextbox1 { clear: both; }
@@ -88,8 +92,9 @@ body.ltr .magnify { float:right; }
.mw-hidden-cats-hidden { display: none; }
.catlinks-allhidden { display: none; }
-/* Convenience links to edit block and delete reasons */
-p.mw-ipb-conveniencelinks, p.mw-filedelete-editreasons, p.mw-delete-editreasons {
+/* Convenience links to edit block, delete and protect reasons */
+p.mw-ipb-conveniencelinks, p.mw-protect-editreasons,
+p.mw-filedelete-editreasons, p.mw-delete-editreasons {
font-size: 90%;
float: right;
}
@@ -101,12 +106,18 @@ div.searchresult {
}
.mw-search-results li {
padding-bottom: 1em;
+ list-style:none;
}
.mw-search-result-data {
color: green;
font-size: 97%;
}
+td#mw-search-menu {
+ padding-left:6em;
+ font-size:85%;
+}
+
div#mw-search-interwiki {
float: right;
width: 18em;
@@ -131,8 +142,26 @@ span.searchalttitle {
div.searchdidyoumean {
font-size: 127%;
- padding-bottom:1ex;
- padding-top:1ex;
+ margin-bottom: 1ex;
+ margin-top: 1ex;
+ /* Note that this color won't affect the link, as desired. */
+ color: #c00;
+}
+
+div.searchdidyoumean em {
+ font-weight: bold;
+}
+
+.searchmatch {
+ font-weight: bold;
+}
+
+div.searchresults {
+ border:1px solid darkblue;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ padding-left: 20px;
+ padding-right: 20px;
}
/*
@@ -157,6 +186,7 @@ table.mw-userrights-groups * td,table.mw-userrights-groups * th {
left: 0px;
width: 0px;
background-color: white;
+ background-color: Window;
border-style: solid;
border-color: #AAAAAA;
border-width: 1px;
@@ -220,7 +250,13 @@ td.os-suggest-result-hl {
border: 1px dashed #aaa;
}
-table.mw-listgrouprights-table {
+/*
+ * Special:ListGroupRights styling
+ * Special:Statistics styling
+*/
+
+table.mw-listgrouprights-table,
+table.mw-statistics-table {
border: 1px solid #ccc;
border-collapse: collapse;
}
@@ -229,11 +265,16 @@ table.mw-listgrouprights-table tr {
vertical-align: top;
}
-table.mw-listgrouprights-table td, table.mw-listgrouprights-table th {
+table.mw-listgrouprights-table td, table.mw-listgrouprights-table th,
+table.mw-statistics-table td, table.mw-statistics-table th {
padding: 0.5em 0.2em 0.5em 0.2em;
border: 1px solid #ccc;
}
+td.mw-statistics-numbers {
+ text-align: right;
+}
+
/* Special:SpecialPages styling */
h4.mw-specialpagesgroup {
background-color: #dcdcdc;
@@ -247,3 +288,26 @@ h4.mw-specialpagesgroup {
#shared-image-dup, #shared-image-conflict {
font-style: italic;
}
+
+/* Special:EmailUser styling */
+table.mw-emailuser-table {
+ width: 98%;
+}
+td#mw-emailuser-sender, td#mw-emailuser-recipient {
+ font-weight: bold;
+}
+
+/*
+ * Recreating deleted page warning
+ * Reupload file warning
+ * Page protection warning
+ * incl. log entries for these warnings
+ */
+div.mw-warning-with-logexcerpt {
+ padding: 3px;
+ margin-bottom: 3px;
+ border: 2px solid #2F6FAB;
+}
+div.mw-warning-with-logexcerpt ul li {
+ font-size: 90%;
+}
diff --git a/skins/common/wikibits.js b/skins/common/wikibits.js
index 59f15cef..089d22d7 100644
--- a/skins/common/wikibits.js
+++ b/skins/common/wikibits.js
@@ -44,15 +44,14 @@ function addOnloadHook(hookFunct) {
}
function hookEvent(hookName, hookFunct) {
- if (window.addEventListener) {
- window.addEventListener(hookName, hookFunct, false);
- } else if (window.attachEvent) {
- window.attachEvent("on" + hookName, hookFunct);
- }
+ addHandler(window, hookName, hookFunct);
}
function importScript(page) {
- return importScriptURI(wgScript + '?action=raw&ctype=text/javascript&title=' + encodeURIComponent(page.replace(/ /g,'_')));
+ var uri = wgScript + '?title=' +
+ encodeURIComponent(page.replace(/ /g,'_')).replace('%2F','/').replace('%3A',':') +
+ '&action=raw&ctype=text/javascript';
+ return importScriptURI(uri);
}
var loadedScripts = {}; // included-scripts tracker
@@ -104,22 +103,6 @@ if (wgBreakFrames) {
}
}
-// for enhanced RecentChanges
-function toggleVisibility(_levelId, _otherId, _linkId) {
- var thisLevel = document.getElementById(_levelId);
- var otherLevel = document.getElementById(_otherId);
- var linkLevel = document.getElementById(_linkId);
- if (thisLevel.style.display == 'none') {
- thisLevel.style.display = 'block';
- otherLevel.style.display = 'none';
- linkLevel.style.display = 'inline';
- } else {
- thisLevel.style.display = 'none';
- otherLevel.style.display = 'inline';
- linkLevel.style.display = 'none';
- }
-}
-
function showTocToggle() {
if (document.createTextNode) {
// Uses DOM calls to avoid document.write + XHTML issues
@@ -309,6 +292,28 @@ function addPortletLink(portlet, href, text, id, tooltip, accesskey, nextnode) {
return item;
}
+function getInnerText(el) {
+ if (typeof el == "string") return el;
+ if (typeof el == "undefined") { return el };
+ if (el.textContent) return el.textContent; // not needed but it is faster
+ if (el.innerText) return el.innerText; // IE doesn't have textContent
+ var str = "";
+
+ var cs = el.childNodes;
+ var l = cs.length;
+ for (var i = 0; i < l; i++) {
+ switch (cs[i].nodeType) {
+ case 1: //ELEMENT_NODE
+ str += ts_getInnerText(cs[i]);
+ break;
+ case 3: //TEXT_NODE
+ str += cs[i].nodeValue;
+ break;
+ }
+ }
+ return str;
+}
+
/**
* Set up accesskeys/tooltips from the deprecated ta array. If doId
@@ -449,8 +454,19 @@ function toggle_element_check(ida,idb) {
From http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/
*/
function getElementsByClassName(oElm, strTagName, oClassNames){
- var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
+ if ( typeof( oElm.getElementsByClassName ) == "function" ) {
+ /* Use a native implementation where possible FF3, Saf3.2, Opera 9.5 */
+ var arrNativeReturn = oElm.getElementsByClassName( oClassNames );
+ if ( strTagName == "*" )
+ return arrNativeReturn;
+ for ( var h=0; h < arrNativeReturn.length; h++ ) {
+ if( arrNativeReturn[h].tagName.toLowerCase() == strTagName.toLowerCase() )
+ arrReturnElements[arrReturnElements.length] = arrNativeReturn[h];
+ }
+ return arrReturnElements;
+ }
+ var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrRegExpClassNames = new Array();
if(typeof oClassNames == "object"){
for(var i=0; i<oClassNames.length; i++){
@@ -518,8 +534,9 @@ var ts_image_up = "sort_up.gif";
var ts_image_down = "sort_down.gif";
var ts_image_none = "sort_none.gif";
var ts_europeandate = wgContentLanguage != "en"; // The non-American-inclined can change to "true"
-var ts_alternate_row_colors = true;
-var SORT_COLUMN_INDEX;
+var ts_alternate_row_colors = false;
+var ts_number_transform_table = null;
+var ts_number_regex = null;
function sortables_init() {
var idnum = 0;
@@ -549,7 +566,14 @@ function ts_makeSortable(table) {
for (var i = 0; i < firstRow.cells.length; i++) {
var cell = firstRow.cells[i];
if ((" "+cell.className+" ").indexOf(" unsortable ") == -1) {
- cell.innerHTML += '&nbsp;&nbsp;<a href="#" class="sortheader" onclick="ts_resortTable(this);return false;"><span class="sortarrow"><img src="'+ ts_image_path + ts_image_none + '" alt="&darr;"/></span></a>';
+ cell.innerHTML += '&nbsp;&nbsp;'
+ + '<a href="#" class="sortheader" '
+ + 'onclick="ts_resortTable(this);return false;">'
+ + '<span class="sortarrow">'
+ + '<img src="'
+ + ts_image_path
+ + ts_image_none
+ + '" alt="&darr;"/></span></a>';
}
}
if (ts_alternate_row_colors) {
@@ -558,25 +582,7 @@ function ts_makeSortable(table) {
}
function ts_getInnerText(el) {
- if (typeof el == "string") return el;
- if (typeof el == "undefined") { return el };
- if (el.textContent) return el.textContent; // not needed but it is faster
- if (el.innerText) return el.innerText; // IE doesn't have textContent
- var str = "";
-
- var cs = el.childNodes;
- var l = cs.length;
- for (var i = 0; i < l; i++) {
- switch (cs[i].nodeType) {
- case 1: //ELEMENT_NODE
- str += ts_getInnerText(cs[i]);
- break;
- case 3: //TEXT_NODE
- str += cs[i].nodeValue;
- break;
- }
- }
- return str;
+ return getInnerText( el );
}
function ts_resortTable(lnk) {
@@ -592,9 +598,14 @@ function ts_resortTable(lnk) {
table = table.parentNode;
if (!table) return;
- // Work out a type for the column
if (table.rows.length <= 1) return;
+ // Generate the number transform table if it's not done already
+ if (ts_number_transform_table == null) {
+ ts_initTransformTable();
+ }
+
+ // Work out a type for the column
// Skip the first row if that's where the headings are
var rowStart = (table.tHead && table.tHead.rows.length > 0 ? 0 : 1);
@@ -607,39 +618,52 @@ function ts_resortTable(lnk) {
}
}
- sortfn = ts_sort_caseinsensitive;
- if (itm.match(/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/))
- sortfn = ts_sort_date;
- if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/))
- sortfn = ts_sort_date;
- if (itm.match(/^\d\d[\/.-]\d\d[\/.-]\d\d$/))
- sortfn = ts_sort_date;
- if (itm.match(/^[\u00a3$\u20ac]/)) // pound dollar euro
- sortfn = ts_sort_currency;
- if (itm.match(/^[\d.,]+\%?$/))
- sortfn = ts_sort_numeric;
+ // TODO: bug 8226, localised date formats
+ var sortfn = ts_sort_generic;
+ var preprocessor = ts_toLowerCase;
+ if (/^\d\d[\/. -][a-zA-Z]{3}[\/. -]\d\d\d\d$/.test(itm)) {
+ preprocessor = ts_dateToSortKey;
+ } else if (/^\d\d[\/.-]\d\d[\/.-]\d\d\d\d$/.test(itm)) {
+ preprocessor = ts_dateToSortKey;
+ } else if (/^\d\d[\/.-]\d\d[\/.-]\d\d$/.test(itm)) {
+ preprocessor = ts_dateToSortKey;
+ // pound dollar euro yen currency cents
+ } else if (/(^[\u00a3$\u20ac\u00a4\u00a5]|\u00a2$)/.test(itm)) {
+ preprocessor = ts_currencyToSortKey;
+ } else if (ts_number_regex.test(itm)) {
+ preprocessor = ts_parseFloat;
+ }
var reverse = (span.getAttribute("sortdir") == 'down');
var newRows = new Array();
+ var staticRows = new Array();
for (var j = rowStart; j < table.rows.length; j++) {
var row = table.rows[j];
- var keyText = ts_getInnerText(row.cells[column]);
- var oldIndex = (reverse ? -j : j);
+ if((" "+row.className+" ").indexOf(" unsortable ") < 0) {
+ var keyText = ts_getInnerText(row.cells[column]);
+ var oldIndex = (reverse ? -j : j);
+ var preprocessed = preprocessor( keyText );
- newRows[newRows.length] = new Array(row, keyText, oldIndex);
+ newRows[newRows.length] = new Array(row, preprocessed, oldIndex);
+ } else staticRows[staticRows.length] = new Array(row, false, j-rowStart);
}
newRows.sort(sortfn);
var arrowHTML;
if (reverse) {
- arrowHTML = '<img src="'+ ts_image_path + ts_image_down + '" alt="&darr;"/>';
- newRows.reverse();
- span.setAttribute('sortdir','up');
+ arrowHTML = '<img src="'+ ts_image_path + ts_image_down + '" alt="&darr;"/>';
+ newRows.reverse();
+ span.setAttribute('sortdir','up');
} else {
- arrowHTML = '<img src="'+ ts_image_path + ts_image_up + '" alt="&uarr;"/>';
- span.setAttribute('sortdir','down');
+ arrowHTML = '<img src="'+ ts_image_path + ts_image_up + '" alt="&uarr;"/>';
+ span.setAttribute('sortdir','down');
+ }
+
+ for (var i = 0; i < staticRows.length; i++) {
+ var row = staticRows[i];
+ newRows.splice(row[2], 0, row);
}
// We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
@@ -661,7 +685,66 @@ function ts_resortTable(lnk) {
}
span.innerHTML = arrowHTML;
- ts_alternate(table);
+ if (ts_alternate_row_colors) {
+ ts_alternate(table);
+ }
+}
+
+function ts_initTransformTable() {
+ if ( typeof wgSeparatorTransformTable == "undefined"
+ || ( wgSeparatorTransformTable[0] == '' && wgDigitTransformTable[2] == '' ) )
+ {
+ digitClass = "[0-9,.]";
+ ts_number_transform_table = false;
+ } else {
+ ts_number_transform_table = {};
+ // Unpack the transform table
+ // Separators
+ ascii = wgSeparatorTransformTable[0].split("\t");
+ localised = wgSeparatorTransformTable[1].split("\t");
+ for ( var i = 0; i < ascii.length; i++ ) {
+ ts_number_transform_table[localised[i]] = ascii[i];
+ }
+ // Digits
+ ascii = wgDigitTransformTable[0].split("\t");
+ localised = wgDigitTransformTable[1].split("\t");
+ for ( var i = 0; i < ascii.length; i++ ) {
+ ts_number_transform_table[localised[i]] = ascii[i];
+ }
+
+ // Construct regex for number identification
+ digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ',', '\\.'];
+ maxDigitLength = 1;
+ for ( var digit in ts_number_transform_table ) {
+ // Escape regex metacharacters
+ digits.push(
+ digit.replace( /[\\\\$\*\+\?\.\(\)\|\{\}\[\]\-]/,
+ function( s ) { return '\\' + s; } )
+ );
+ if (digit.length > maxDigitLength) {
+ maxDigitLength = digit.length;
+ }
+ }
+ if ( maxDigitLength > 1 ) {
+ digitClass = '[' + digits.join( '', digits ) + ']';
+ } else {
+ digitClass = '(' + digits.join( '|', digits ) + ')';
+ }
+ }
+
+ // We allow a trailing percent sign, which we just strip. This works fine
+ // if percents and regular numbers aren't being mixed.
+ ts_number_regex = new RegExp(
+ "^(" +
+ "[+-]?[0-9][0-9,]*(\\.[0-9,]*)?(E[+-]?[0-9][0-9,]*)?" + // Fortran-style scientific
+ "|" +
+ "[+-]?" + digitClass + "+%?" + // Generic localised
+ ")$", "i"
+ );
+}
+
+function ts_toLowerCase( s ) {
+ return s.toLowerCase();
}
function ts_dateToSortKey(date) {
@@ -705,38 +788,34 @@ function ts_dateToSortKey(date) {
return "00000000";
}
-function ts_parseFloat(num) {
- if (!num) return 0;
- num = parseFloat(num.replace(/,/g, ""));
- return (isNaN(num) ? 0 : num);
-}
-
-function ts_sort_date(a,b) {
- var aa = ts_dateToSortKey(a[1]);
- var bb = ts_dateToSortKey(b[1]);
- return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]);
-}
-
-function ts_sort_currency(a,b) {
- var aa = ts_parseFloat(a[1].replace(/[^0-9.]/g,''));
- var bb = ts_parseFloat(b[1].replace(/[^0-9.]/g,''));
- return (aa != bb ? aa - bb : a[2] - b[2]);
-}
+function ts_parseFloat( s ) {
+ if ( !s ) {
+ return 0;
+ }
+ if (ts_number_transform_table != false) {
+ var newNum = '', c;
+
+ for ( var p = 0; p < s.length; p++ ) {
+ c = s.charAt( p );
+ if (c in ts_number_transform_table) {
+ newNum += ts_number_transform_table[c];
+ } else {
+ newNum += c;
+ }
+ }
+ s = newNum;
+ }
-function ts_sort_numeric(a,b) {
- var aa = ts_parseFloat(a[1]);
- var bb = ts_parseFloat(b[1]);
- return (aa != bb ? aa - bb : a[2] - b[2]);
+ num = parseFloat(s.replace(/,/g, ""));
+ return (isNaN(num) ? s : num);
}
-function ts_sort_caseinsensitive(a,b) {
- var aa = a[1].toLowerCase();
- var bb = b[1].toLowerCase();
- return (aa < bb ? -1 : aa > bb ? 1 : a[2] - b[2]);
+function ts_currencyToSortKey( s ) {
+ return ts_parseFloat(s.replace(/[^0-9.,]/g,''));
}
-function ts_sort_default(a,b) {
- return (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2]);
+function ts_sort_generic(a, b) {
+ return a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : a[2] - b[2];
}
function ts_alternate(table) {
@@ -805,6 +884,7 @@ function jsMsg( message, className ) {
}
messageDiv.setAttribute( 'id', 'mw-js-message' );
+ messageDiv.style.display = 'block';
if( className ) {
messageDiv.setAttribute( 'class', 'mw-js-message-'+className );
}
@@ -895,6 +975,21 @@ function addHandler( element, attach, handler ) {
function addClickHandler( element, handler ) {
addHandler( element, 'click', handler );
}
+
+/**
+ * Removes an event handler from an element
+ *
+ * @param Element element Element to remove handler from
+ * @param String remove Event to remove
+ * @param callable handler Event handler callback to remove
+ */
+function removeHandler( element, remove, handler ) {
+ if( window.removeEventListener ) {
+ element.removeEventListener( remove, handler, false );
+ } else if( window.detachEvent ) {
+ element.detachEvent( 'on' + remove, handler );
+ }
+}
//note: all skins should call runOnloadHook() at the end of html output,
// so the below should be redundant. It's there just in case.
hookEvent("load", runOnloadHook);
diff --git a/skins/common/wikiprintable.css b/skins/common/wikiprintable.css
index 58e132d6..8b099bb2 100644
--- a/skins/common/wikiprintable.css
+++ b/skins/common/wikiprintable.css
@@ -21,7 +21,7 @@ a, a.external, a.new, a.stub {
}
/* Hide ugly UI stuff */
-#quickbar, #topbar, #footer, #siteNotice,
+#quickbar, #topbar, #logo, #footer, #siteNotice,
.editsection, .toctoggle {
display: none;
}
diff --git a/skins/common/wikistandard.css b/skins/common/wikistandard.css
index 3fe8d2fb..5bf59246 100644
--- a/skins/common/wikistandard.css
+++ b/skins/common/wikistandard.css
@@ -5,7 +5,7 @@
#powersearch {
background: #DDEEFF; border-style: solid; border-width: 1px; padding: 2px;
}
-#quickbar { width: 140px; padding: 4px; visibility: visible; z-index:99;font-size:95%;}
+#quickbar { width: 140px; height:100%; padding: 4px; visibility: visible; z-index:99;font-size:95%;}
#topbar { padding: 4px;font-size:95%; }