မီႇတီႇယႃႇဝီႇၶီႇ:Gadget-twinkle.js
မၢႆတွင်း: ဝၢႆးသေသိမ်းပၼ်ယဝ်ႉ၊ တွၼ်ႈတႃႇ ၸဝ်ႈၵဝ်ႇ တေႁၼ်လႆႈ လွင်ႈလႅၵ်ႈလၢႆႈၼၼ်ႉ ၸဝ်ႈၵဝ်ႇတေၸၢင်ႈလႆႈလတ်းၶၢမ်ႈ ၶႅတ်ႉၶျ် တူဝ်ပိုတ်ႇဝႅပ်ႉၸဝ်ႈၵဝ်ႇယဝ်ႉ။
- ၽွင်းမိူဝ်ႈတိုၵ်ႉၼဵၵ်း Reload တီႈ Firefox / Safari: ၼၼ်ႉ ၼဵၵ်းဝႆႉပႃး Shift ၊ဢမ်ႇၼၼ် ၼဵၵ်းပၼ် Ctrl-F5 ဢမ်ႇၼၼ် Ctrl-R (တီႈၼႂ်း Mac ၼႆ ၼဵၵ်းပၼ်⌘-R)
- တီႈၼႂ်း Google Chrome: ၼဵၵ်းပၼ် Ctrl-Shift-R (တီႈၼႂ်း Mac ၼႆႉ ၼဵၵ်းပၼ်⌘-Shift-R )
- ၽွင်းမိူဝ်ႈ တိုၵ်ႉၼဵၵ်း Refreshတီႈ Internet Explorer/ Edge: ၼဵၵ်းဝႆႉပၼ် Ctrl ဢမ်ႇၼၼ် ၼဵၵ်းပၼ် Ctrl-F5
- တီႈၼႂ်း Opera: ၵႂႃႇၸူးတီႈ Menu → Settings (ပေႃးပဵၼ်တီႈၼႂ်း Mac ၸိုင် Opera → Preferences ) သေ သိုပ်ႇၵႂႃႇ Privacy & security → Clear browsing data → Cached images and files ၼၼ်ႉလႄႈ။
window.twinkleConfigExists = false;
if ( userIsInGroup( 'sysop' ) || twUserIsWhitelisted() ) {
twinkleConfigExists = true;
}
function twUserIsWhitelisted() {
return userIsInGroup( 'autoconfirmed' ) || userIsInGroup( 'confirmed' );
}
if ( window.TwinkleConfig == undefined )
window.TwinkleConfig = {};
if ( TwinkleConfig.portletId == undefined )
TwinkleConfig.portletId = 'p-cactions';
/**
* Add a portlet menu to one of the navigation areas on the page.
* Available navigation areas depend on the script used.
*
* NOTE: If anyone is brave enough to reuse this directly, please shoot
* me a note. Otherwise I might change the signature down the line and
* your script breaks. Amalthea.
*
* @param String portlet -- id of the target portlet (skin dependent)
* @param String id -- id of the portlet menu to create, preferably start with "p-".
* @param String text -- name of the portlet menu to create. Visibility depends on the class used.
* @param String type -- type of portlet. pass "menu" to make this portlet a drop down menu (vector only)
* @param String next -- place before this menu, or otherwise at the end.
*
* @return jQuery -- the new portlet
*/
function twAddPortlet( portlet, id, text, type, next )
{
var $portlet, $item, $where, $h5, outerDivClass, innerDivClass, skin;
skin = mw.config.get( 'skin' );
// verify/normalize input
type = ( skin === "vector" && type === "menu" && ( portlet === "left-navigation" || portlet === "right-navigation" )) ? "menu" : "";
switch ( skin )
{
case "vector":
if ( $.inArray( portlet, [ "portal", "left-navigation", "right-navigation" ] ) === -1 ) {
portlet = "mw-panel";
}
if ( portlet === "mw-panel" ) {
outerDivClass = "portal";
innerDivClass = "body";
} else if ( type === "menu" ) {
outerDivClass = "vectorMenu extraMenu emptyPortlet";
innerDivClass = "menu";
} else {
outerDivClass = "vectorTabs extraMenu emptyPortlet";
innerDivClass = "";
}
break;
case "modern":
if ( portlet !== "mw_contentwrapper" ) {
portlet = "mw_portlets";
}
outerDivClass = "portlet";
innerDivClass = "pBody";
break;
default:
portlet = "column-one";
outerDivClass = "portlet";
innerDivClass = "pBody";
break;
}
$portlet = $( '#' + portlet );
$item = $( '#' + id );
if ( $item.length ) {
return $item.parent().is( $portlet ) ? $item : $();
}
// Build the DOM elements.
$item = $( '<div>', { 'id': id, 'class': outerDivClass } );
$h5 = $( '<h5>' );
if ( type === "menu" ) {
$h5
.append( $( '<span>', { 'text': text } ) )
.append( $( '<a>', { 'href': '#' } ).append( $( '<span>', { 'text': text } ) ) );
} else {
$h5.text( text );
}
$item.append( $h5 ).append( $( '<div>', { 'class': innerDivClass } ).append( '<ul></ul>' ) );
if ( next ) {
$where = $( '#' + next );
if ( $where.parent().is( $portlet ) ) {
$where.before( $item );
} else {
$portlet.append( $item );
}
} else {
$portlet.append( $item );
}
return $item;
}
//Build a portlet menu if it doesn't exist yet, and add the portlet link.
function twAddPortletLink( task, text, id, tooltip, accesskey )
{
var link;
if (TwinkleConfig.portletArea) {
twAddPortlet(
TwinkleConfig.portletArea,
TwinkleConfig.portletId,
TwinkleConfig.portletName,
TwinkleConfig.portletType,
TwinkleConfig.portletNext
);
}
link = mw.util.addPortletLink(
TwinkleConfig.portletId,
typeof task ==="string" ? task : "#",
text, id, tooltip, accesskey, TwinkleConfig.portletNext
);
if ( $.isFunction(task) ) {
$(link).click( function (e) { task.call(this, e); e.preventDefault(); } );
}
return link;
}
/**
* QuickForm is for the creation of simple and standard forms without much specific coding.
*/
function QuickForm( event, eventType ) {
this.root = new QuickForm.element({ type: 'form', event: event, eventType: eventType });
}
QuickForm.prototype.render = function QuickFormRender() {
var ret = this.root.render();
ret.names = {};
return ret;
};
QuickForm.prototype.append = function QuickFormRender( data ) {
return this.root.append( data );
};
QuickForm.element = function QuickFormElement( data ) {
if ( !( this instanceof QuickForm.element ) ) {
return new QuickForm.element( data );
} else if ( data instanceof QuickForm.element ) {
this.data = data.data;
this.childs = data.childs;
this.id = data.id;
} else {
this.data = data;
this.childs = [];
this.id = QuickForm.element.id++;
}
};
QuickForm.element.id = 0;
QuickForm.element.prototype.append = function QuickFormElementAppend( data ) {
var child = QuickForm.element( data );
this.childs.push( child );
return child;
};
QuickForm.element.prototype.render = function QuickFormElementRender() {
var current = this.compute();
$.each( this.childs, function() { current[1].append( this.render() ); } );
return current[0];
};
QuickForm.element.prototype.compute = function QuickFormElementCompute( in_id ) {
var $node, $child, $label, data = this.data,
id = ( in_id ? in_id + '_' : '' ) + 'node_' + this.id,
cur_id, current, $cur_div, $input;
if ( data.adminonly && !userIsInGroup( 'sysop' ) ) {
// hell hack alpha
data.type = 'hidden';
}
switch( data.type ) {
case 'form':
$node = $( '<form name="id" class="quickform" action="javascript:void(0);">' );
if ( data.event ) {
$.on( data.eventType || 'submit', data.event );
}
break;
case 'select':
$node = $( '<div>', { 'id': 'div_' + id } );
$child = $( '<select>', { 'name': data.name } );
$node.append( $child );
if ( data.label ) {
$label = $( '<label>', { 'for': id, 'text': data.label } );
$node.append( $label );
}
if ( data.multiple ) {
$child.prop( 'multiple', true );
}
if ( data.size ) {
$child.attr( 'size', data.size );
}
if ( data.event ) {
$child.on( 'change', data.event );
}
if ( data.list ) {
for ( var i = 0; i < data.list.length; ++i ) {
current = data.list[i];
current.type = current.list ? 'optgroup' : 'option';
$child.append( QuickForm.element( current ).compute()[0] );
}
}
break;
case 'option':
$node = $( '<option>', {
'value': data.value,
'label': data.label,
'text': data.label,
'data': {
'values': data.value
}
});
if ( data.selected ) {
$node.prop( 'selected', true );
}
if ( data.disabled ) {
$node.prop( 'disabled', true );
}
break;
case 'optgroup':
$node = $( '<optgroup>', { 'label': data.label } );
if ( data.list ) {
for ( var i = 0; i < data.list.length; ++i ) {
var current = data.list[i];
current.type = 'option'; // must be options here
$node.append( QuickForm.element( current ).compute()[0] );
}
}
break;
case 'field':
$label = $( '<legend>', { 'text': data.label } );
$node = $( '<fieldset>' ).append( $label );
if ( data.name ) {
$node.attr( 'name', data.name );
}
break;
case 'checkbox':
case 'radio':
$node = $( '<div>' );
if ( data.list ) {
for ( var i = 0; i < data.list.length; ++i ) {
cur_id = id + '_' + i;
current = data.list[i];
if ( current.type === 'header' ) {
// inline hack
$cur_div = $( '<h6>', { 'text': current.label } );
$node.append( $cur_div );
if ( current.tooltip ) {
QuickForm.element.generateTooltip( $cur_div, current );
}
continue;
}
$cur_div = $( '<div>' );
$input = $( '<input>', {
'value': current.value,
'name': current.name || data.name,
'type': data.type,
'id': cur_id,
'data': {
'values': current.value
}
});
$cur_div.append( $input );
$node.append( $cur_div );
if ( current.checked ) {
$input.prop( 'checked', true );
}
if ( current.disabled ) {
$input.prop( 'disabled', true );
}
if ( data.event ) {
$input.on( 'change', data.event );
} else if ( current.event ) {
$input.on( 'change', current.event );
}
$label = $( '<label>', { 'for': cur_id, 'text': current.label } );
$cur_div.append( $label );
if ( current.tooltip ) {
QuickForm.element.generateTooltip( $label, current );
}
if ( current.subgroup ) {
var tmpgroup, $subgroup;
tmpgroup = $.extend( {}, current.subgroup );
tmpgroup.name = (current.name || data.name) + '.' + tmpgroup.name;
if ( !tmpgroup.type ) {
tmpgroup.type = data.type;
}
$subgroup = QuickForm.element( tmpgroup ).compute( cur_id )[0];
$subgroup.style( 'marginLeft', '3em' );
$input.data({ 'subgroup': $subgroup, 'shown': false });
if ( current.checked ) {
$cur_div.append( $subgroup );
}
$input.on( 'change', function(e) {
var $target = $( e.target ), name;
if ( !e.target.checked ) {
$target.data( 'subgroup' ).remove();
return;
}
$target.parent().append( $target.data( 'subgroup' ) );
if ( $target.attr( 'type' ) !== 'radio' ) {
return;
}
name = $target.attr( 'name' );
if ( typeof e.target.form.names[name] !== 'undefined' ) {
e.target.form.names[name].data( 'subgroup' ).remove();
}
e.target.form.names[name] = $target;
});
} else if ( data.type === 'radio' ) {
$input.on( 'change', function(e) {
var name = $( e.target ).attr( 'name' );
if ( e.target.checked ) {
if ( typeof e.target.form.names[name] !== 'undefined' ) {
e.target.form.names[name].data( 'subgroup' ).remove();
}
delete e.target.form.names[name];
}
});
}
}
}
break;
case 'input':
$node = $( '<div>' );
if ( data.label ) {
$node.append( $label = $( '<label>', { 'for': id, 'text': data.label } ) );
}
$input = $( '<input>', { 'name': data.name, 'type': 'text' } );
$node.append( $input );
if ( data.value ) {
$input.val( data.value );
}
if ( data.size ) {
$input.attr( 'size', data.size );
}
if ( data.disabled ) {
$input.prop( 'disabled', true );
}
if ( data.readonly ) {
$input.prop( 'readonly', true );
}
if ( data.maxlength ) {
$input.attr( 'maxlength', data.maxlength );
}
if ( data.event ) {
$input.on( 'keyup', data.event );
}
break;
case 'dyninput':
var min = data.min || 1;
var max = data.max || Infinity;
$node = $( '<div>' ).append( $label = $( '<h5>', { 'text': data.label } ) );
$cur_div = $( '<div>' );
$node.append( $cur_div );
current = QuickForm.elements({
type: 'button',
label: 'more',
disabled: min >= max,
event: function(e) {
var data = $( e.target ).data(),
area = data.area;
elem = new QuickForm.element( data.sublist );
e.stopPropagation();
data.area.append( elem.render() );
if ( ++data.counter >= data.max ) {
$( e.target ).prop( 'disabled', true );
}
}
}).compute();
var sublist = {
type: '_dyninput_element',
label: data.sublabel || data.label,
name: data.name,
value: data.value,
size: data.size,
remove: false,
maxlength: data.maxlength,
event: data.event
};
$node.append( current[0] );
for ( var i = 0; i < min; ++i ) {
$cur_div.append( QuickForm.element( sublist ).render() );
}
$.extend( sublist, {
'remove': true,
'button': current[1],
'elements': $cur_div
});
current[1].data({
'sublist': sublist,
'area': $cur_node,
'max': max - min,
'counter': 0
});
break;
case '_dyninput_element': // Private, similar to normal input
$node = $( '<div>' );
if ( data.label ) {
$label = $( '<label>', { 'for': id, 'text': data.label } )
$node.append( $label );
}
$input = $( '<input>', { 'name': data.name, 'type': 'text' } );
$node.append( $input );
if ( data.value ) {
$input.attr( 'value', data.value );
}
if ( data.size ) {
$input.attr( 'size', data.size );
}
if ( data.maxlength ) {
$input.attr( 'maxlength', data.maxlength );
}
if ( data.event ) {
$input.on( 'keyup', data.event );
}
if ( data.remove ) {
current = QuickForm.element({
type: 'button',
label: 'remove',
event: function(e) {
var data = $( e.target ).data(),
$node = data.input,
$more = data.button;
$node.remove();
--more.counter;
$more.removeAttribute( 'disabled' );
e.stopPropagation();
}
}).compute();
$node.append( current[0] );
current[1].data({ 'input': $node, 'button': data.button });
}
break;
case 'hidden':
$node = $( '<input>', {
'name': data.name,
'type': 'hidden',
'value': data.value,
'data': {
'values': data.value
}
});
break;
case 'header':
$node = $( '<h5>', { 'text': data.label } );
break;
case 'div':
$node = $( '<div>' );
break;
case 'submit':
$node = $( '<span>' );
$child = $( '<input>', { 'type': 'submit', 'name': data.name || 'submit' } );
$node.append( $child );
if ( data.label ) {
$child.attr( 'value', data.label );
}
if ( data.disabled ) {
$child.prop( 'disabled', true );
}
break;
case 'button':
$node = $( '<span>' );
$child = $( '<input>', { 'type': 'button', 'name': data.name } );
$node.append( $child );
if ( data.label ) {
$child.attr( 'value', data.label );
}
if ( data.disabled ) {
$child.prop( 'disabled', true );
}
if ( data.event ) {
$child.on( 'click', data.event );
}
break;
case 'textarea':
$node = $( '<div>' );
if ( data.label ) {
$label = $( '<h5>', { 'for': id, 'text': data.label } );
$node.append( $label );
}
$cur_div = $( '<textarea>', { 'name': data.name } );
$node.append( $cur_div );
if ( data.cols ) {
$cur_div.attr( 'cols', data.cols );
}
if ( data.rows ) {
$cur_div.attr( 'rows', data.rows );
}
if ( data.disabled ) {
$cur_div.prop( 'disabled', true );
}
if ( data.readonly ) {
$cur_div.prop( 'readonly', true );
}
if ( data.value ) {
$cur_div.val( data.value );
}
break;
default:
throw new Error("QuickForm: Unknown element type " + data.type.toString());
}
if ( !$child ) {
$child = $node;
}
if ( data.tooltip ) {
QuickForm.element.generateTooltip( $label || $node , data );
}
if ( data.extra ) {
$child.data( 'extra', extra );
}
$child.attr( 'id', data.id || id );
return [ $node, $child ];
};
QuickForm.element.generateTooltip = function QuickFormElementGenerateTooltip( $node, data ) {
$( '<span>', {
'class': 'ui-icon ui-icon-help ui-icon-inline twinkle-tooltip'
}).appendTo( $node );
};
/*
* returns an array containing the values of elements with the given name, that has it's
* checked property set to true. (i.e. a checkbox or a radiobutton is checked), or select options
* that have selected set to true. (don't try to mix selects with radio/checkboxes, please)
* Type is optional and can specify if either radio or checkbox (for the event
* that both checkboxes and radiobuttons have the same name.
*/
HTMLFormElement.prototype.getChecked = function( name, type ) {
var elements = this.elements[name];
if( !elements ) {
// if the element doesn't exists, return null.
return null;
}
var return_array = [];
if( elements instanceof HTMLSelectElement ) {
var options = elements.options;
for( var i = 0; i < options.length; ++i ) {
if( options[i].selected ) {
if( options[i].values ) {
return_array.push( options[i].values );
} else {
return_array.push( options[i].value );
}
}
}
} else if( elements instanceof HTMLInputElement ) {
if( type != null && elements.type != type ) {
return [];
} else if( elements.checked ) {
return [ elements.value ];
}
} else {
for( var i = 0; i < elements.length; ++i ) {
if( elements[i].checked ) {
if( type != null && elements[i].type != type ) {
continue;
}
if( elements[i].values ) {
return_array.push( elements[i].values );
} else {
return_array.push( elements[i].value );
}
}
}
}
return return_array;
}
/*
* returns an array containing the values of elements with the given name, that has non-empty strings
* type is "text" or given.
*/
HTMLFormElement.prototype.getTexts = function( name, type ) {
type == type || 'text';
var elements = this.elements[name];
if( !elements ) {
// if the element doesn't exists, return null.
return null;
}
var return_array = [];
for( var i = 0; i < elements.length; ++i ) {
if( elements[i].value != '' ) {
return_array.push( elements[i].value );
}
}
return return_array;
}
/**
* Will escape a string to be used in a RegExp
*/
RegExp.escape = function( text, space_fix ) {
if ( !arguments.callee.sRE ) {
arguments.callee.sRE = /(\/|\.|\*|\+|\?|\||\(|\)|\[|\]|\{|\}|\\|\$|\^)/g;
}
text = text.replace( arguments.callee.sRE , '\\$1' );
// Special Mediawiki escape, underscore/space is the same, often at lest:
if( space_fix ) {
text = text.replace( / |_/g, '[_ ]' );
}
return text;
}
// Sprintf implementation based on perl similar
function sprintf() {
if( arguments.length == 0 ) {
throw "Not enough arguments for sprintf";
}
var result = "";
var format = arguments[0];
var index = 1;
var current_index = 1;
var flags = {};
var in_operator = false;
var relative = false;
var precision = false;
var fixed = false;
var vector = false;
var vector_delimiter = '.';
for( var i = 0; i < format.length; ++i ) {
var current_char = format.charAt(i);
if( in_operator ) {
switch( current_char ) {
case 'i':
current_char = 'd';
break;
case 'F':
current_char = 'f';
break;
case '%':
case 'c':
case 's':
case 'd':
case 'u':
case 'o':
case 'x':
case 'e':
case 'f':
case 'g':
case 'X':
case 'E':
case 'G':
case 'b':
var value = arguments[current_index];
if( vector ) {
r = value.toString().split( '' );
result += value.toString().split('').map( function( value ) {
return sprintf.format( current_char, value.charCodeAt(), flags );
}).join( vector_delimiter );
} else {
result += sprintf.format( current_char, value, flags );
}
if( !fixed ) {
++index;
}
current_index = index;
flags = {};
relative = false;
in_operator = false;
precision = false;
fixed = false;
vector = false;
vector_delimiter = '.';
break;
case 'v':
vector = true;
break;
case ' ':
case '0':
case '-':
case '+':
case '#':
flags[current_char] = true;
break;
case '*':
relative = true;
break;
case '.':
precision = true;
break;
}
if( /\d/.test( current_char ) ) {
var num = parseInt( format.substr( i ) );
var len = num.toString().length;
i += len - 1;
var next = format.charAt( i + 1 );
if( next == '$' ) {
if( num <= 0 || num >= arguments.length ) {
throw "out of bound";
}
if( relative ) {
if( precision ) {
flags['precision'] = arguments[num];
precision = false;
} else if( format.charAt( i + 2 ) == 'v' ) {
vector_delimiter = arguments[num];
}else {
flags['width'] = arguments[num];
}
relative = false;
} else {
fixed = true;
current_index = num;
}
++i;
} else if( precision ) {
flags['precision'] = num;
precision = false;
} else {
flags['width'] = num;
}
} else if ( relative && !/\d/.test( format.charAt( i + 1 ) ) ) {
if( precision ) {
flags['precision'] = arguments[current_index];
precision = false;
} else if( format.charAt( i + 1 ) == 'v' ) {
vector_delimiter = arguments[current_index];
} else {
flags['width'] = arguments[current_index];
}
++index;
if( !fixed ) {
current_index++;
}
relative = false;
}
} else {
if( current_char == '%' ) {
in_operator = true;
continue;
} else {
result += current_char;
continue;
}
}
}
return result;
}
sprintf.format = function sprintfFormat( type, value, flags ) {
// Similar to how perl printf works
if( value == undefined ) {
if( type == 's' ) {
return '';
} else {
return '0';
}
}
var result;
var prefix = '';
var fill = '';
var fillchar = ' ';
switch( type ) {
case '%':
result = '%';
break;
case 'c':
result = String.fromCharCode( parseInt( value ) );
break;
case 's':
result = value.toString();
break;
case 'd':
result = parseInt( value ).toString();
break;
case 'u':
result = Math.abs( parseInt( value ) ).toString(); // it's not correct, but JS lacks unsigned ints
break;
case 'o':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(8);
break;
case 'x':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16);
break;
case 'b':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(2);
break;
case 'e':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toExponential( digits ).toString();
break;
case 'f':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toFixed( digits ).toString();
case 'g':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toPrecision( digits ).toString();
break;
case 'X':
result = (new Number( Math.abs( parseInt( value ) ) ) ).toString(16).toUpperCase();
break;
case 'E':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toExponential( digits ).toString().toUpperCase();
break;
case 'G':
var digits = flags['precision'] ? flags['precision'] : 6;
result = (new Number( value ) ).toPrecision( digits ).toString().toUpperCase();
break;
}
if(flags['+'] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) {
prefix = '+';
}
if(flags[' '] && parseFloat( value ) > 0 && ['d','e','f','g','E','G'].indexOf(type) != -1 ) {
prefix = ' ';
}
if( flags['#'] && parseInt( value ) != 0 ) {
switch(type) {
case 'o':
prefix = '0';
break;
case 'x':
case 'X':
prefix = '0x';
break;
case 'b':
prefix = '0b';
break;
}
}
if( flags['0'] && !flags['-'] ) {
fillchar = '0';
}
if( flags['width'] && flags['width'] > ( result.length + prefix.length ) ) {
var tofill = flags['width'] - result.length - prefix.length;
for( var i = 0; i < tofill; ++i ) {
fill += fillchar;
}
}
if( flags['-'] && !flags['0'] ) {
result += fill;
} else {
result = fill + result;
}
return prefix + result;
}
var Bytes = function ( value ) {
if( typeof(value) == 'string' ) {
var res = /(\d+) ?(\w?)(i?)B?/.exec( value );
var number = res[1];
var mag = res[2];
var si = res[3];
if( ! number ) {
this.number = 0;
return;
}
if( !si ) {
this.value = number * Math.pow( 10, Bytes.magnitudes[mag] * 3 );
} else {
this.value = number * Math.pow( 2, Bytes.magnitudes[mag] * 10 );
}
} else {
this.value = value;
}
}
Bytes.magnitudes = {
'': 0,
'K': 1,
'M': 2,
'G': 3,
'T': 4,
'P': 5,
'E': 6,
'Z': 7,
'Y': 8
}
Bytes.rmagnitudes = {
0: '',
1: 'K',
2: 'M',
3: 'G',
4: 'T',
5: 'P',
6: 'E',
7: 'Z',
8: 'Y'
}
Bytes.prototype.valueOf = function() {
return this.value;
}
Bytes.prototype.toString = function( magnitude ) {
var tmp = this.value;
if( magnitude ) {
var si = /i/.test(magnitude);
var mag = magnitude.replace( /.*?(\w)i?B?.*/g, '$1' );
if( si ) {
tmp /= Math.pow( 2, Bytes.magnitudes[mag] * 10 );
} else {
tmp /= Math.pow( 10, Bytes.magnitudes[mag] * 3 );
}
if( parseInt( tmp ) != tmp ) {
tmp = (new Number( tmp ) ).toPrecision( 4 );
}
return tmp + ' ' + mag + (si?'i':'') + 'B';
} else {
// si per default
var current = 0;
while( tmp >= 1024 ) {
tmp /= 1024;
++current;
}
tmp = this.value / Math.pow( 2, current * 10 );
if( parseInt( tmp ) != tmp ) {
tmp = (new Number( tmp ) ).toPrecision( 4 );
}
return tmp + ' ' + Bytes.rmagnitudes[current] + ( current > 0 ? 'iB' : 'B' );
}
}
String.prototype.ltrim = function stringPrototypeLtrim( chars ) {
chars = chars || "\\s*";
return this.replace( new RegExp("^[" + chars + "]+", "g"), "" );
}
String.prototype.rtrim = function stringPrototypeRtrim( chars ) {
chars = chars || "\\s*";
return this.replace( new RegExp("[" + chars + "]+$", "g"), "" );
}
String.prototype.trim = function stringPrototypeTrim( chars ) {
return this.rtrim(chars).ltrim(chars);
}
String.prototype.splitWeightedByKeys = function stringPrototypeSplitWeightedByKeys( start, end, skip ) {
if( start.length != end.length ) {
throw 'start marker and end marker must be of the same length';
}
var level = 0;
var initial = null;
var result = [];
if( !( skip instanceof Array ) ) {
if( typeof( skip ) == 'undefined' ) {
skip = [];
} else if( typeof( skip ) == 'string' ) {
skip = [ skip ];
} else {
throw "non-applicable skip parameter";
}
}
for( var i = 0; i < this.length; ++i ) {
for( var j = 0; j < skip.length; ++j ) {
if( this.substr( i, skip[j].length ) == skip[j] ) {
i += skip[j].length - 1;
continue;
}
}
if( this.substr( i, start.length ) == start ) {
if( initial == null ) {
initial = i;
}
++level;
i += start.length - 1;
} else if( this.substr( i, end.length ) == end ) {
--level;
i += end.length - 1;
}
if( level == 0 && initial != null ) {
result.push( this.substring( initial, i + 1 ) );
initial = null;
}
}
return result;
}
Array.prototype.uniq = function arrayPrototypeUniq() {
var result = [];
for( var i = 0; i < this.length; ++i ) {
var current = this[i];
if( result.indexOf( current ) == -1 ) {
result.push( current );
}
}
return result;
}
Array.prototype.dups = function arrayPrototypeUniq() {
var uniques = [];
var result = [];
for( var i = 0; i < this.length; ++i ) {
var current = this[i];
if( uniques.indexOf( current ) == -1 ) {
uniques.push( current );
} else {
result.push( current );
}
}
return result;
}
Array.prototype.chunk = function arrayChunk( size ) {
if( typeof( size ) != 'number' || size <= 0 ) { // pretty impossible to do anything :)
return [ this ]; // we return an array consisting of this array.
}
var result = [];
var current;
for(var i = 0; i < this.length; ++i ) {
if( i % size == 0 ) { // when 'i' is 0, this is always true, so we start by creating one.
current = [];
result.push( current );
}
current.push( this[i] );
}
return result;
}
var Unbinder = function unbinder( string ) {
if( typeof( string ) != 'string' ) {
throw "not a string";
}
this.content = string;
this.counter = 0;
this.history = {};
this.prefix = '%UNIQ::' + Math.random() + '::';
this.postfix = '::UNIQ%';
}
Unbinder.prototype = {
unbind: function UnbinderUnbind( prefix, postfix ) {
var re = new RegExp( prefix + '(.*?)' + postfix, 'g' );
this.content = this.content.replace( re, Unbinder.getCallback( this ) );
},
rebind: function UnbinderRebind() {
var content = this.content;
content.self = this;
for( var current in this.history )
if( this.history.hasOwnProperty( current ) )
content = content.replace( current, this.history[current] );
return content;
},
prefix: null, // %UNIQ::0.5955981644938324::
postfix: null, // ::UNIQ%
content: null, // string
counter: null, // 0++
history: null // {}
};
Unbinder.getCallback = function UnbinderGetCallback(self) {
return function UnbinderCallback( match , a , b ) {
var current = self.prefix + self.counter + self.postfix;
self.history[current] = match;
++self.counter;
return current;
};
};
function clone( obj, deep ) {
var objectClone = new obj.constructor();
for ( var property in obj )
if ( !deep ) {
objectClone[property] = obj[property];
}
else if ( typeof obj[property] == 'object' ) {
objectClone[property] = clone( obj[property], deep );
}
else {
objectClone[property] = obj[property];
}
return objectClone;
}
function ln( ns, title ) {
var ns2ln = {
'0' : 'la',
'1' : 'lat',
'2' : 'lu',
'3' : 'lut',
'4' : 'lw',
'5' : 'lwt',
'6' : 'li',
'7' : 'lit',
'8' : 'lm',
'9' : 'lmt',
'10': 'lt',
'11': 'ltt',
'12': 'lh',
'13': 'lht',
'14': 'lc',
'15': 'lct',
'100': 'lp',
'101': 'lpt'
};
return "\{\{" + ns2ln[ns] + "|" + title + "\}\}";
}
// Helper functions to change case of a string
String.prototype.toUpperCaseFirstChar = function() {
return this.substr( 0, 1 ).toUpperCase() + this.substr( 1 );
}
String.prototype.toLowerCaseFirstChar = function() {
return this.substr( 0, 1 ).toLowerCase() + this.substr( 1 );
}
String.prototype.toUpperCaseEachWord = function( delim ) {
delim = delim ? delim : ' ';
return this.split( delim ).map( function(v) { return v.toUpperCaseFirstChar() } ).join( delim );
}
String.prototype.toLowerCaseEachWord = function( delim ) {
delim = delim ? delim : ' ';
return this.split( delim ).map( function(v) { return v.toLowerCaseFirstChar() } ).join( delim );
}
/**
* Helper functions to get the month as a string instead of a number
*/
Date.monthNames = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
Date.monthNamesAbbrev = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
Date.prototype.getMonthName = function() {
return Date.monthNames[ this.getMonth() ];
}
Date.prototype.getMonthNameAbbrev = function() {
return Date.monthNamesAbbrev[ this.getMonth() ];
}
Date.prototype.getUTCMonthName = function() {
return Date.monthNames[ this.getUTCMonth() ];
}
Date.prototype.getUTCMonthNameAbbrev = function() {
return Date.monthNamesAbbrev[ this.getUTCMonth() ];
}
// Accessor functions for wikiediting and api-access
var Wikipedia = {};
// we dump all XHR here so they won't loose props
Wikipedia.dump = [];
Wikipedia.numberOfActionsLeft = 0;
Wikipedia.nbrOfCheckpointsLeft = 0;
Wikipedia.actionCompleted = function( self ) {
if( --Wikipedia.numberOfActionsLeft <= 0 && Wikipedia.nbrOfCheckpointsLeft <= 0 ) {
Wikipedia.actionCompleted.event( self );
}
}
// Change per action wanted
Wikipedia.actionCompleted.event = function() {
new Status( Wikipedia.actionCompleted.notice, Wikipedia.actionCompleted.postfix, 'info' );
if( Wikipedia.actionCompleted.redirect != null ) {
// if it isn't an url, make it an relative to self (probably this is the case)
if( !/^\w+\:\/\//.test( Wikipedia.actionCompleted.redirect ) ) {
Wikipedia.actionCompleted.redirect = mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace( '$1', encodeURIComponent( Wikipedia.actionCompleted.redirect ).replace( /\%2F/g, '/' ) );
}
window.setTimeout( function() { window.location = Wikipedia.actionCompleted.redirect } , Wikipedia.actionCompleted.timeOut );
}
}
if ( typeof(wpActionCompletedTimeOut) == 'undefined' )
var wpActionCompletedTimeOut = 5000;
if ( typeof(wpMaxLag) == 'undefined' )
var wpMaxLag = 10; // Maximum lag allowed, 5-10 is a good value, the higher value, the more agressive.
Wikipedia.editCount = 10;
Wikipedia.actionCompleted.timeOut = wpActionCompletedTimeOut;
Wikipedia.actionCompleted.redirect = null;
Wikipedia.actionCompleted.notice = 'Action';
Wikipedia.actionCompleted.postfix = 'completed';
Wikipedia.addCheckpoint = function() {
++Wikipedia.nbrOfCheckpointsLeft;
}
Wikipedia.removeCheckpoint = function() {
if( --Wikipedia.nbrOfCheckpointsLeft <= 0 && Wikipedia.numberOfActionsLeft <= 0 ) {
Wikipedia.actionCompleted.event();
}
}
/*
currentAction: text, the current action (required)
query: Object, the query (required)
oninit: function, the function to call when page gotten
*/
Wikipedia.api = function( currentAction, query, oninit, statelem ) {
this.currentAction = currentAction;
this.query = query;
this.query['format'] = 'xml'; //LET THE FORCE BE WITH YOU!!!
this.oninit = oninit;
if( statelem ) {
statelem.status( currentAction )
} else {
this.statelem = new Status( currentAction );
}
++Wikipedia.numberOfActionsLeft;
}
Wikipedia.api.prototype = {
currentAction: '',
oninit: null,
query: null,
responseXML: null,
statelem: null,
counter: 0,
post: function() {
var xmlhttp = sajax_init_object();
Wikipedia.dump.push( xmlhttp );
xmlhttp.obj = this;
xmlhttp.overrideMimeType('text/xml');
xmlhttp.open( 'POST' , mw.config.get('wgServer') + wgScriptPath + '/api.php', true);
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlhttp.onerror = function() {
this.obj.statelem.error( "Error " + this.status + " occurred while quering the api." );
}
xmlhttp.onload = function() {
this.obj.responseXML = this.responseXML;
if( this.obj.oninit ) {
this.obj.oninit( this.obj );
}
Wikipedia.actionCompleted();
};
xmlhttp.send( QueryString.create( this.query ) );
}
}
/*
currentAction: text, the current action (required)
query: Object, the query (required)
oninit: function, the function to call when page gotten (required)
onsuccess: function, a function to call when post succeeded
onerror: function, a function to call when we abort failed posts
onretry: function, a function to call when we try to retry a post
*/
Wikipedia.wiki = function( currentAction, query, oninit, onsuccess, onerror, onretry ) {
this.currentAction = currentAction;
this.query = query;
this.oninit = oninit;
this.onsuccess = onsuccess;
this.onerror = onerror;
this.onretry = onretry;
this.statelem = new Status( currentAction );
++Wikipedia.numberOfActionsLeft;
}
Wikipedia.wiki.prototype = {
currentAction: '',
onsuccess: null,
onerror: null,
onretry: null,
oninit: null,
query: null,
postData: null,
responseXML: null,
statelem: null,
counter: 0,
post: function( data ) {
this.postData = data;
if( Wikipedia.editCount <= 0 ) {
this.query['maxlag'] = wpMaxLag; // are we a bot?
} else {
--Wikipedia.editCount;
}
var xmlhttp = sajax_init_object();
Wikipedia.dump.push( xmlhttp );
xmlhttp.obj = this;
xmlhttp.overrideMimeType('text/xml');
xmlhttp.open( 'POST' , mw.config.get('wgServer') + wgScriptPath + '/index.php?useskin=monobook&' + QueryString.create( this.query ), true);
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlhttp.onerror = function(e) {
var self = this.obj;
self.statelem.error( "Error " + this.status + " occurred while posting the document." );
}
xmlhttp.onload = function(e) {
var self = this.obj;
var status = this.status;
if( status != 200 ) {
if( status == 503 ) {
var retry = this.getResponseHeader( 'Retry-After' );
var lag = this.getResponseHeader( 'X-Database-Lag' );
if( lag ) {
self.statelem.warn( "current lag of " + lag + " seconds is more than our defined maximum lag of " + wpMaxLag + " seconds, will retry in " + retry + " seconds" );
window.setTimeout( function( self ) { self.post( self.postData ); }, retry * 1000, self );
return;
} else {
self.statelem.error( "Error " + status + " occurred while posting the document." );
}
}
return;
}
var xmlDoc;
xmlDoc = self.responseXML = this.responseXML;
var xpathExpr = 'boolean(//div[@class=\'previewnote\']/p/strong[contains(.,\'Sorry! We could not process your edit due to a loss of session data\')])';
var nosession = xmlDoc.evaluate( xpathExpr, xmlDoc, null, XPathResult.BOOLEAN_TYPE, null ).booleanValue;
if( nosession ) {
// Grabbing the shipping token, and repost
var new_token = xmlDoc.evaluate( '//input[@name="wfEditToken"]/@value', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
self.postData['wfEditToken'] = new_token;
self.post( self.postData );
} else {
if( self.onsuccess ) {
self.onsuccess( self );
} else {
var link = document.createElement( 'a' );
link.setAttribute( 'href', mw.config.get('wgArticlePath').replace( '$1', self.query['title'] ) );
link.setAttribute( 'title', self.query['title'] );
link.appendChild( document.createTextNode( self.query['title'] ) );
self.statelem.info( [ 'completed (' , link , ')' ] );
}
Wikipedia.actionCompleted();
}
};
xmlhttp.send( QueryString.create( this.postData ) );
},
get: function() {
this.onloading( this );
var redirect_query = {
'action': 'query',
'titles': this.query['title'],
'redirects': ''
}
var wikipedia_api = new Wikipedia.api( "resolving eventual redirect", redirect_query, this.postget, this.statelem );
wikipedia_api.parent = this;
wikipedia_api.post();
},
postget: function() {
var xmlDoc = self.responseXML = this.responseXML;
var to = xmlDoc.evaluate( '//redirects/r/@to', xmlDoc, null, XPathResult.STRING_TYPE, null ).stringValue;
if( !this.parent.followRedirect ) {
this.parent.statelem.info('ignoring eventual redirect');
} else if( to ) {
this.parent.query['title'] = to;
}
this.parent.onloading( this );
var xmlhttp = sajax_init_object();
Wikipedia.dump.push( xmlhttp );
xmlhttp.obj = this.parent;
xmlhttp.overrideMimeType('text/xml');
xmlhttp.open( 'GET' , mw.config.get('wgServer') + wgScriptPath + '/index.php?useskin=monobook&' + QueryString.create( this.parent.query ), true);
xmlhttp.onerror = function() {
var self = this.obj;
self.statelem.error( "Error " + this.status + " occurred while receiving the document." );
}
xmlhttp.onload = function() {
this.obj.onloaded( this.obj );
this.obj.responseXML = this.responseXML;
this.obj.responseText = this.responseText;
this.obj.oninit( this.obj );
};
xmlhttp.send( null );
},
onloading: function() {
this.statelem.status( 'loading data...' );
},
onloaded: function() {
this.statelem.status( 'data loaded...' );
}
}
Number.prototype.zeroFill = function( length ) {
var str = this.toFixed();
if( !length ) { return str; }
while( str.length < length ) { str = '0' + str; }
return str;
}
var Mediawiki = {};
Mediawiki.Template = {
parse: function( text, start ) {
var count = -1;
var level = -1;
var equals = -1;
var current = '';
var result = {
name: '',
parameters: {}
};
for( var i = start; i < text.length; ++i ) {
var test3 = text.substr( i, 3 );
if( test3 == '\{\{\{' ) {
current += '\{\{\{';
i += 2;
++level;
continue;
}
if( test3 == '\}\}\}' ) {
current += '\}\}\}';
i += 2;
--level;
continue;
}
var test2 = text.substr( i, 2 );
if( test2 == '\{\{' || test2 == '\[\[' ) {
current += test2;
++i;
++level;
continue;
}
if( test2 == '\]\]' ) {
current += test2;
++i;
--level;
continue;
}
if( test2 == '\}\}' ) {
current += test2;
++i;
--level;
if( level <= 0 ) {
if( count == -1 ) {
result.name = current.substring(2).trim();
++count;
} else {
if( equals != -1 ) {
var key = current.substring( 0, equals ).trim();
var value = current.substring( equals ).trim();
result.parameters[key] = value;
equals = -1;
} else {
result.parameters[count] = current;
++count;
}
}
break;
}
continue;
}
if( text.charAt(i) == '|' && level <= 0 ) {
if( count == -1 ) {
result.name = current.substring(2).trim();
++count;
} else {
if( equals != -1 ) {
var key = current.substring( 0, equals ).trim();
var value = current.substring( equals + 1 ).trim();
result.parameters[key] = value;
equals = -1;
} else {
result.parameters[count] = current;
++count;
}
}
current = '';
} else if( equals == -1 && text.charAt(i) == '=' && level <= 0 ) {
equals = current.length;
current += text.charAt(i);
} else {
current += text.charAt(i);
}
}
return result;
}
}
Mediawiki.Page = function mediawikiPage( text ) {
this.text = text;
}
Mediawiki.Page.prototype = {
text: '',
removeLink: function( link_target ) {
var first_char = link_target.substr( 0, 1 );
var link_re_string = "[" + first_char.toUpperCase() + first_char.toLowerCase() + ']' + RegExp.escape( link_target.substr( 1 ), true );
var link_simple_re = new RegExp( "\\[\\[(" + link_re_string + ")\\|?\\]\\]", 'g' );
var link_named_re = new RegExp( "\\[\\[" + link_re_string + "\\|(.+?)\\]\\]", 'g' );
if( link_simple_re.test(this.text) ) {
this.text = this.text.replace( link_simple_re, "$1" );
} else {
this.text = this.text.replace( link_named_re, "$1" );
}
},
commentOutImage: function( image, reason ) {
var unbinder = new Unbinder( this.text );
unbinder.unbind( '<!--', '-->' );
reason = reason ? ' ' + reason + ': ' : '';
var first_char = image.substr( 0, 1 );
var image_re_string = "[" + first_char.toUpperCase() + first_char.toLowerCase() + ']' + RegExp.escape( image.substr( 1 ), true );
/*
* Check for normal image links, i.e. [[Image:Foobar.png|...]]
* Will eat the whole link
*/
var links_re = new RegExp( "\\[\\[(?:[Ii]mage|[Ff]ile):\\s*" + image_re_string );
var allLinks = unbinder.content.splitWeightedByKeys( '[[', ']]' ).uniq();
for( var i = 0; i < allLinks.length; ++i ) {
if( links_re.test( allLinks[i] ) ) {
var replacement = '<!-- ' + reason + allLinks[i] + ' -->';
unbinder.content = unbinder.content.replace( allLinks[i], replacement, 'g' );
}
}
// unbind the newly created comments
unbinder.unbind( '<!--', '-->' );
/*
* Check for gallery images, i.e. instances that must start on a new line, eventually preceded with some space, and must include Image: prefix
* Will eat the whole line.
*/
var gallery_image_re = new RegExp( "(^\\s*(?:[Ii]mage|[Ff]ile):\\s*" + image_re_string + ".*?$)", 'mg' );
unbinder.content.replace( gallery_image_re, "<!-- " + reason + "$1 -->" );
// unbind the newly created comments
unbinder.unbind( '<!--', '-->' );
/*
* Check free image usages, for example as template arguments, might have the Image: prefix excluded, but must be preceeded by an |
* Will only eat the image name and the preceeding bar and an eventual named parameter
*/
var free_image_re = new RegExp( "(\\|\\s*(?:[\\w\\s]+\\=)?\\s*(?:(?:[Ii]mage|[Ff]ile):\\s*)?" + image_re_string + ")", 'mg' );
unbinder.content.replace( free_image_re, "<!-- " + reason + "$1 -->" );
// Rebind the content now, we are done!
this.text = unbinder.rebind();
},
addToImageComment: function( image, data ) {
var first_char = image.substr( 0, 1 );
var image_re_string = "(?:[Ii]mage|[Ff]ile):\\s*[" + first_char.toUpperCase() + first_char.toLowerCase() + ']' + RegExp.escape( image.substr( 1 ), true );
var links_re = new RegExp( "\\[\\[" + image_re_string );
var allLinks = this.text.splitWeightedByKeys( '[[', ']]' ).uniq();
for( var i = 0; i < allLinks.length; ++i ) {
if( links_re.test( allLinks[i] ) ) {
var replacement = allLinks[i];
// just put it at the end?
replacement = replacement.replace( /\]\]$/, '|' + data + ']]' );
this.text = this.text.replace( allLinks[i], replacement, 'g' );
}
}
var gallery_re = new RegExp( "^(\\s*" + image_re_string + '.*?)\\|?(.*?)$', 'mg' );
var replacement = "$1|$2 " + data;
this.text = this.text.replace( gallery_re, replacement );
},
removeTemplate: function( template ) {
var first_char = template.substr( 0, 1 );
var template_re_string = "(?:[Tt]emplate:)?\\s*[" + first_char.toUpperCase() + first_char.toLowerCase() + ']' + RegExp.escape( template.substr( 1 ), true );
var links_re = new RegExp( "\\\{\\\{" + template_re_string );
var allTemplates = this.text.splitWeightedByKeys( '{\{', '}}', [ '{{{', '}}}' ] ).uniq();
for( var i = 0; i < allTemplates.length; ++i ) {
if( links_re.test( allTemplates[i] ) ) {
this.text = this.text.replace( allTemplates[i], '', 'g' );
}
}
},
getText: function() {
return this.text;
}
}
// Simple helper functions to see what groups a user might belong
function userIsInGroup( group ) {
return ( mw.config.get('wgUserGroups') != null && mw.config.get('wgUserGroups').indexOf( group ) != -1 ) || ( mw.config.get('wgUserGroups') == null && group == 'anon' );
}
function userIsAnon() {
return mw.config.get('wgUserGroups') == null;
}
// AOL Proxy IP Addresses (2007-02-03)
var AOLNetworks = [
'64.12.96.0/19',
'149.174.160.0/20',
'152.163.240.0/21',
'152.163.248.0/22',
'152.163.252.0/23',
'152.163.96.0/22',
'152.163.100.0/23',
'195.93.32.0/22',
'195.93.48.0/22',
'195.93.64.0/19',
'195.93.96.0/19',
'195.93.16.0/20',
'198.81.0.0/22',
'198.81.16.0/20',
'198.81.8.0/23',
'202.67.64.128/25',
'205.188.192.0/20',
'205.188.208.0/23',
'205.188.112.0/20',
'205.188.146.144/30',
'207.200.112.0/21',
];
// AOL Client IP Addresses (2007-02-03)
var AOLClients = [
'172.128.0.0/10',
'172.192.0.0/12',
'172.208.0.0/14',
'202.67.66.0/23',
'172.200.0.0/15',
'172.202.0.0/15',
'172.212.0.0/14',
'172.216.0.0/16',
'202.67.68.0/22',
'202.67.72.0/21',
'202.67.80.0/20',
'202.67.96.0/19',
];
/**
* ipadress is in the format 1.2.3.4 and network is in the format 1.2.3.4/5
*/
function isInNetwork( ipaddress, network ) {
var iparr = ipaddress.split('.');
var ip = (parseInt(iparr[0]) << 24) + (parseInt(iparr[1]) << 16) + (parseInt(iparr[2]) << 8) + (parseInt(iparr[3]));
var netmask = 0xffffffff << network.split('/')[1];
var netarr = network.split('/')[0].split('.');
var net = (parseInt(netarr[0]) << 24) + (parseInt(netarr[1]) << 16) + (parseInt(netarr[2]) << 8) + (parseInt(netarr[3]));
return (ip & netmask) == net;
}
/* Returns true if given string contains a valid IP-address, that is, from 0.0.0.0 to 255.255.255.255*/
function isIPAddress( string ){
var res = /(\d{1,4})\.(\d{1,3})\.(\d{1,3})\.(\d{1,4})/.exec( string );
return res != null && res.slice( 1, 5 ).every( function( e ) { return e < 256; } );
}
/**
* Maps the querystring to an object
*
* Functions:
*
* QueryString.exists(key)
* returns true if the particular key is set
* QueryString.get(key)
* returns the value associated to the key
* QueryString.equals(key, value)
* returns true if the value associated with given key equals given value
* QueryString.toString()
* returns the query string as a string
* QueryString.create( hash )
* creates an querystring and encodes strings via encodeURIComponent and joins arrays with |
*
* In static context, the value of location.search.substring(1), else the value given to the constructor is going to be used. The mapped hash is saved in the object.
*
* Example:
*
* var value = QueryString.get('key');
* var obj = new QueryString('foo=bar&baz=quux');
* value = obj.get('foo');
*/
function QueryString(qString) {
this.string = qString;
this.params = {};
if( qString.length == 0 ) {
return;
}
qString.replace(/\+/, ' ');
var args = qString.split('&');
for( var i = 0; i < args.length; ++i ) {
var pair = args[i].split( '=' );
var key = decodeURIComponent( pair[0] ), value = key;
if( pair.length == 2 ) {
value = decodeURIComponent( pair[1] );
}
this.params[key] = value;
}
}
QueryString.static = null;
QueryString.staticInit = function() {
if( QueryString.static == null ) {
QueryString.static = new QueryString(location.search.substring(1));
}
}
QueryString.get = function(key) {
QueryString.staticInit();
return QueryString.static.get(key);
};
QueryString.prototype.get = function(key) {
return this.params[key] ? this.params[key] : null;
};
QueryString.exists = function(key) {
QueryString.staticInit();
return QueryString.static.exists(key);
}
QueryString.prototype.exists = function(key) {
return this.params[key] ? true : false;
}
QueryString.equals = function(key, value) {
QueryString.staticInit();
return QueryString.static.equals(key, value);
}
QueryString.prototype.equals = function(key, value) {
return this.params[key] == value ? true : false;
}
QueryString.toString = function() {
QueryString.staticInit();
return QueryString.static.toString();
}
QueryString.prototype.toString = function() {
return this.string ? this.string : null;
}
QueryString.create = function( arr ) {
var resarr = Array();
var editToken; // KLUGE: this should always be the last item in the query string (bug TW-B-0013)
for( var i in arr ) {
if( typeof arr[i] == 'undefined' ) {
continue;
}
var res;
if( arr[i] instanceof Array ){
var v = Array();
for(var j = 0; j < arr[i].length; ++j ) {
v[j] = encodeURIComponent( arr[i][j] );
}
res = v.join('|');
} else {
res = encodeURIComponent( arr[i] );
}
if( i == 'wpEditToken' ) {
editToken = res;
} else {
resarr.push( encodeURIComponent( i ) + '=' + res );
}
}
if( typeof editToken != 'undefined' ) {
resarr.push( 'wpEditToken=' + editToken );
}
return resarr.join('&');
}
QueryString.prototype.create = QueryString.create;
/**
* Simple exception handling
*/
var Exception = function( message ) {
this.message = message || '';
this.name = "Exception";
}
Exception.prototype.what = function() {
return this.message;
}
function Status( text, stat, type ) {
this.text = this.codify(text);
this.stat = this.codify(stat);
this.type = type || 'status';
this.generate();
if( stat ) {
this.render();
}
}
Status.init = function( root ) {
if( !( root instanceof Element ) ) {
throw new Exception( 'object not an instance of Element' );
}
while( root.hasChildNodes() ) {
root.removeChild( root.firstChild );
}
Status.root = root;
var cssNode = document.createElement('style');
cssNode.type = 'text/css';
cssNode.rel = 'stylesheet';
cssNode.appendChild( document.createTextNode("")); // Safari bugfix
document.getElementsByTagName("head")[0].appendChild(cssNode);
var styles = cssNode.sheet ? cssNode.sheet : cssNode.stylesSheet;
styles.insertRule(".tw_status_status { color: SteelBlue; }", 0);
styles.insertRule(".tw_status_info { color: ForestGreen; }", 0);
styles.insertRule(".tw_status_warn { color: OrangeRed; }", 0);
styles.insertRule(".tw_status_error { color: OrangeRed; font-weight: 900; }", 0);
}
Status.root = null;
Status.prototype = {
stat: null,
text: null,
type: 'status',
target: null,
node: null,
linked: false,
link: function() {
if( ! this.linked && Status.root ) {
Status.root.appendChild( this.node );
this.linked = true;
}
},
unlink: function() {
if( this.linked ) {
Status.root.removeChild( this.node );
this.linked = false;
}
},
codify: function( obj ) {
if ( ! ( obj instanceof Array ) ) {
obj = [ obj ];
}
var result;
result = document.createDocumentFragment();
for( var i = 0; i < obj.length; ++i ) {
if( typeof obj[i] == 'string' ) {
result.appendChild( document.createTextNode( obj[i] ) );
} else if( obj[i] instanceof Element ) {
result.appendChild( obj[i] );
} // Else cosmic radiation made something shit
}
return result;
},
update: function( status, type ) {
this.stat = this.codify( status );
if( type ) {
this.type = type;
}
this.render();
},
generate: function() {
this.node = document.createElement( 'div' );
this.node.appendChild( document.createElement('span') ).appendChild( this.text );
this.node.appendChild( document.createElement('span') ).appendChild( document.createTextNode( ': ' ) );
this.target = this.node.appendChild( document.createElement( 'span' ) );
this.target.appendChild( document.createTextNode( '' ) ); // dummy node
},
render: function() {
this.node.className = 'tw_status_' + this.type;
while( this.target.hasChildNodes() ) {
this.target.removeChild( this.target.firstChild );
}
this.target.appendChild( this.stat );
this.link();
},
status: function( status ) {
this.update( status, 'status');
},
info: function( status ) {
this.update( status, 'info');
},
warn: function( status ) {
this.update( status, 'warn');
},
error: function( status ) {
this.update( status, 'error');
}
}
Status.status = function( text, status ) {
return new Status( text, status, 'status' );
}
Status.info = function( text, status ) {
return new Status( text, status, 'info' );
}
Status.warn = function( text, status ) {
return new Status( text, status, 'error' );
}
Status.error = function( text, status ) {
return new Status( text, status, 'error' );
}
// Simple helper function to create a simple node
function htmlNode( type, content, color ) {
var node = document.createElement( type );
if( color ) {
node.style.color = color;
}
node.appendChild( document.createTextNode( content ) );
return node;
}
// A simple dragable window
function SimpleWindow( width, height ) {
var $window = $( '<div>', { 'class': 'twinkle-dialog-content' } ), $widget;
this.$window = $window;
this.$window.dialog({
autoOpen: true,
buttons: { "Placeholder button": function() {} },
dialogClass: 'twinkle-dialog',
width: Math.min( parseInt( window.innerWidth, 10 ), parseInt( width || 800, 10 ) ),
height: Math.min( parseInt( window.innerHeight, 10 ), parseInt( height || 600, 10 ) + 20 ),
close: function(e, ui) { $(e.target).dialog('destroy').remove(); },
resize: function(e, ui) { $(this).css( 'maxHeight', '' ); }
});
$widget = this.$window.dialog( "widget" );
// delete the placeholder button (it's only there so the buttonpane gets created)
$widget.find( "button" ).remove();
// add container for the buttons we add
$widget.find( ".ui-dialog-buttonpane" ).append( $( '<span>', { 'class': 'twinkle-dialog-buttons' } ) );
}
SimpleWindow.prototype = {
buttons: [],
hasFooterLinks: false,
scriptName: null,
focus: function(e) {
this.$window.dialog( "moveToTop" );
return this;
},
close: function(e) {
e.preventDefault();
this.$window.dialog( "close" );
return this;
},
display: function(e) {
var $dialog;
if ( this.scriptName) {
$dialog = this.$window.dialog("widget");
$dialog.find(".twinkle-dialog-scriptname").remove();
$dialog.find(".ui-dialog-title").prepend(
// U+00B7 MIDDLE DOT = ·
$( '<span>', { 'class': 'twinkle-dialog-scriptname', 'text': this.scriptName + " \u00B7" } )
);
}
$dialog = $this.$window.dialog("open");
// tie in with NAVPOP
if (window.setupTooltips) {
dialog.parent()[0].ranSetupTooltipsAlready = false;
setupTooltips(dialog.parent()[0]);
}
},
title: function( str ) {
this.$window.dialog( "option", "title", str );
return this;
},
width: function( w ) {
w = Math.min( parseInt( window.innerWidth, 10 ), parseInt( w, 10 ) );
this.$window.dialog( "option", "width", w );
return this;
},
height: function( h ) {
h = Math.min( parseInt( window.innerHeight, 10 ), parseInt( h, 10 ) + 20 );
this.$window.dialog( "option", "height", h );
return this;
},
content: function( what ) {
return this.empty().append( what );
},
empty: function() {
this.buttons = [];
this.$window.dialog( "widget" ).find( ".twinkle-dialog-buttons" ).empty();
this.$window.empty();
return this;
},
append: function( what ) {
var buttons = this.buttons;
this.$window.append( what );
// look for submit buttons in the content, hide them, and add a proxy button to the button pane
this.$window.find('input[type="submit"], button[type="submit"]').each( function() {
var $what = $(this);
// look for submit buttons in the content, hide them, and add a proxy button to the button pane
$what.css( 'display', 'none' );
buttons.push(
$( '<button>' ).text( $what.val() || 'Submit Query' ).click( function() { $what.click(); } )
);
});
if ( buttons.length > 0) {
this.$window
.dialog( "widget" )
.find( ".twinkle-dialog-buttons" )
.empty()
.append( buttons )
.removeAttr( "data-empty" );
} else {
this.$window
.dialog( "widget" )
.find( ".twinkle-dialog-buttons" )
.attr( "data-empty", "data-empty" );
}
return this;
},
modality: function( modal ) {
this.$window.dialog( "option", "modal", modal );
return this;
}
};
// When Twinkle modules are imported, we can't be sure that this base module
// has been loaded yet. For that reason, modules using them need
// to initialize themselves using
// window.TwinkleInit = (window.TwinkleInit || []).concat( someInitializationFunction );
// for maximal robustness. Looks weird, works well.
$(function()
{
var funcs = window.TwinkleInit;
window.TwinkleInit = {
concat : function(func) {
func();
return window.TwinkleInit;
}
}; // redefine the concat method used to enqueue initializers: From now on, they just execute immediately.
if (funcs) for (var i=0; i<funcs.length; i++) funcs[i]();
});