mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/VisualEditor
synced 2024-11-29 00:30:44 +00:00
01d6f17a3e
Change-Id: I909847686c8239a0b00cbaa9a0b1583826ee1487
286 lines
5.9 KiB
JavaScript
286 lines
5.9 KiB
JavaScript
/**
|
|
* General utilities for token transforms
|
|
*/
|
|
|
|
var Util = {
|
|
/**
|
|
* Determine if a tag name is block-level or not
|
|
*
|
|
* @static
|
|
* @method
|
|
* @param {String} name: Lower-case tag name
|
|
* @returns {Boolean}: True if tag is block-level, false otherwise.
|
|
*/
|
|
isBlockTag: function ( name ) {
|
|
switch ( name ) {
|
|
case 'div':
|
|
case 'table':
|
|
case 'td':
|
|
case 'tr':
|
|
case 'tbody':
|
|
case 'p':
|
|
case 'ul':
|
|
case 'ol':
|
|
case 'li':
|
|
case 'dl':
|
|
case 'dt':
|
|
case 'dd':
|
|
//case 'img': // hmm!
|
|
case 'pre':
|
|
case 'center':
|
|
// HTML5 heading content
|
|
case 'h1':
|
|
case 'h2':
|
|
case 'h3':
|
|
case 'h4':
|
|
case 'h5':
|
|
case 'h6':
|
|
case 'hgroup':
|
|
// HTML5 sectioning content
|
|
case 'article':
|
|
case 'aside':
|
|
case 'nav':
|
|
case 'section':
|
|
case 'header':
|
|
case 'footer':
|
|
case 'header':
|
|
case 'figure':
|
|
case 'figcaption':
|
|
case 'fieldset':
|
|
case 'details':
|
|
case 'blockquote':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Determine if a token is block-level or not
|
|
*
|
|
* @static
|
|
* @method
|
|
* @param {Object} token: The token to check
|
|
* @returns {Boolean}: True if token is block-level, false otherwise.
|
|
*/
|
|
isBlockToken: function ( token ) {
|
|
if ( token.constructor === TagTk ||
|
|
token.constructor === EndTagTk ||
|
|
token.constructor === SelfclosingTagTk ) {
|
|
return Util.isBlockTag( token.name.toLowerCase() );
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
kvTokensToString: function(tokens) {
|
|
if (!$.isArray(tokens)) {
|
|
return tokens;
|
|
} else {
|
|
// Ignore everything but strings
|
|
var out = [];
|
|
for (var i = 0, l = tokens.length; i < l; i++ ) {
|
|
var token = tokens[i];
|
|
if (token && token.constructor === String) {
|
|
out.push(token);
|
|
}
|
|
}
|
|
return out.join('');
|
|
}
|
|
},
|
|
|
|
toStringTokens: function(tokens, indent) {
|
|
if (!indent) indent = "";
|
|
if (tokens.constructor !== Array) {
|
|
return [tokens.toString(false, indent)];
|
|
} else if (tokens.length === 0) {
|
|
return [null];
|
|
} else {
|
|
var buf = [];
|
|
for (var i = 0, n = tokens.length; i < n; i++) {
|
|
buf.push(tokens[i].toString(false, indent));
|
|
}
|
|
return buf;
|
|
}
|
|
},
|
|
|
|
lookup: function ( kvs, key ) {
|
|
if ( ! kvs ) {
|
|
return null;
|
|
}
|
|
var kv;
|
|
for ( var i = 0, l = kvs.length; i < l; i++ ) {
|
|
kv = kvs[i];
|
|
if ( kv.k.trim() === key ) {
|
|
// found, return it.
|
|
return kv.v;
|
|
}
|
|
}
|
|
// nothing found!
|
|
return null;
|
|
},
|
|
|
|
lookupKV: function ( kvs, key ) {
|
|
if ( ! kvs ) {
|
|
return null;
|
|
}
|
|
var kv;
|
|
for ( var i = 0, l = kvs.length; i < l; i++ ) {
|
|
kv = kvs[i];
|
|
if ( kv.k.trim() === key ) {
|
|
// found, return it.
|
|
return kv;
|
|
}
|
|
}
|
|
// nothing found!
|
|
return null;
|
|
},
|
|
|
|
lookupValue: function ( kvs, key ) {
|
|
if ( ! kvs ) {
|
|
return null;
|
|
}
|
|
var kv;
|
|
for ( var i = 0, l = kvs.length; i < l; i++ ) {
|
|
kv = kvs[i];
|
|
if ( kv.v === key ) {
|
|
// found, return it.
|
|
return kv;
|
|
}
|
|
}
|
|
// nothing found!
|
|
return null;
|
|
},
|
|
|
|
/**
|
|
* Trim space and newlines from leading and trailing text tokens.
|
|
*/
|
|
tokenTrim: function ( tokens ) {
|
|
var l = tokens.length,
|
|
i, token;
|
|
// strip leading space
|
|
for ( i = 0; i < l; i++ ) {
|
|
token = tokens[i];
|
|
if ( token.constructor === String ) {
|
|
token = token.replace( /^\s+/, '' );
|
|
tokens[i] = token;
|
|
if ( token !== '' ) {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
// strip trailing space
|
|
for ( i = l - 1; i >= 0; i-- ) {
|
|
token = tokens[i];
|
|
if ( token.constructor === String ) {
|
|
token = token.replace( /\s+$/, '' );
|
|
tokens[i] = token;
|
|
if ( token !== '' ) {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return tokens;
|
|
},
|
|
|
|
// Strip 'end' tokens and trailing newlines
|
|
stripEOFTkfromTokens: function ( tokens ) {
|
|
// this.dp( 'stripping end or whitespace tokens' );
|
|
if ( tokens.constructor !== Array ) {
|
|
tokens = [ tokens ];
|
|
}
|
|
if ( ! tokens.length ) {
|
|
return tokens;
|
|
}
|
|
// Strip 'end' tokens and trailing newlines
|
|
var l = tokens[tokens.length - 1];
|
|
if ( l.constructor === EOFTk || l.constructor === NlTk ||
|
|
( l.constructor === String && l.match( /^\s+$/ ) ) ) {
|
|
var origTokens = tokens;
|
|
tokens = origTokens.slice();
|
|
tokens.rank = origTokens.rank;
|
|
while ( tokens.length &&
|
|
(( l.constructor === EOFTk || l.constructor === NlTk ) ||
|
|
( l.constructor === String && l.match( /^\s+$/ ) ) ) )
|
|
{
|
|
// this.dp( 'stripping end or whitespace tokens' );
|
|
tokens.pop();
|
|
l = tokens[tokens.length - 1];
|
|
}
|
|
}
|
|
return tokens;
|
|
},
|
|
|
|
/**
|
|
* Perform a shallow clone of a chunk of tokens
|
|
*/
|
|
cloneTokens: function ( chunk ) {
|
|
var out = [],
|
|
token, tmpToken;
|
|
for ( var i = 0, l = chunk.length; i < l; i++ ) {
|
|
token = chunk[i];
|
|
if ( token.constructor === String ) {
|
|
out.push( token );
|
|
} else {
|
|
tmpToken = $.extend( {}, token );
|
|
tmpToken.rank = 0;
|
|
out.push(tmpToken);
|
|
}
|
|
}
|
|
return out;
|
|
},
|
|
|
|
// Does this need separate UI/content inputs?
|
|
formatNum: function( num ) {
|
|
return num + '';
|
|
},
|
|
|
|
decodeURI: function ( s ) {
|
|
return s.replace( /%[0-9a-f][0-9a-f]/g, function( m ) {
|
|
try {
|
|
// JS library function
|
|
return decodeURI( m );
|
|
} catch ( e ) {
|
|
return m;
|
|
}
|
|
} );
|
|
},
|
|
|
|
sanitizeURI: function ( s ) {
|
|
var host = s.match(/^[a-zA-Z]+:\/\/[^\/]+(?:\/|$)/),
|
|
path = s,
|
|
anchor = null;
|
|
//console.warn( 'host: ' + host );
|
|
if ( host ) {
|
|
path = s.substr( host[0].length );
|
|
host = host[0];
|
|
} else {
|
|
host = '';
|
|
}
|
|
var bits = path.split('#');
|
|
if ( bits.length > 1 ) {
|
|
anchor = bits[bits.length - 1];
|
|
path = path.substr(0, path.length - anchor.length - 1);
|
|
}
|
|
host = host.replace( /%(?![0-9a-fA-F][0-9a-fA-F])|[#|]/g, function ( m ) {
|
|
return encodeURIComponent( m );
|
|
} );
|
|
path = path.replace( /%(?![0-9a-fA-F][0-9a-fA-F])|[ \[\]#|]/g, function ( m ) {
|
|
return encodeURIComponent( m );
|
|
} );
|
|
s = host + path;
|
|
if ( anchor !== null ) {
|
|
s += '#' + anchor;
|
|
}
|
|
return s;
|
|
}
|
|
};
|
|
|
|
if (typeof module == "object") {
|
|
module.exports.Util = Util;
|
|
}
|