mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/Math
synced 2024-12-11 07:26:03 +00:00
e4719c56a7
Change-Id: I5f0c9fc62a1e434576550e142d6b25f329e63e7f
163 lines
3.8 KiB
JavaScript
Executable file
163 lines
3.8 KiB
JavaScript
Executable file
#!/usr/bin/env node
|
|
|
|
/* jshint node: true */
|
|
|
|
( function () {
|
|
var i, count, group, symbol, symbols, symbolObject,
|
|
symbolsData, cssData, cssLines, index,
|
|
cssRules = [],
|
|
cssClasses = [],
|
|
symbolList = [],
|
|
symbolsFile = '../symbols.json',
|
|
cssFile = '../ve.ui.MWMathSymbols.css',
|
|
cssPrefix = '.ve-ui-mwMathSymbol-',
|
|
fs = require( 'fs' ),
|
|
http = require( 'http' ),
|
|
querystring = require( 'querystring' ),
|
|
SVGO = require( 'svgo' ),
|
|
svgo = new SVGO( {
|
|
plugins: [
|
|
{ convertTransform: false }
|
|
]
|
|
} ),
|
|
mathoidMaxConnections = 5;
|
|
|
|
symbolsData = fs.readFileSync( symbolsFile ).toString();
|
|
try {
|
|
cssData = fs.readFileSync( cssFile ).toString();
|
|
} catch ( e ) {}
|
|
|
|
function encodeURIComponentForCSS( str ) {
|
|
return encodeURIComponent( str )
|
|
.replace( /[!'\(\)\*]/g, function ( chr ) {
|
|
return '%' + chr.charCodeAt( 0 ).toString( 16 );
|
|
} );
|
|
}
|
|
|
|
function texToClass( tex ) {
|
|
// Make the className, replacing any non-alphanumerics with their character code
|
|
return tex.replace( /[^\w]/g, function ( c ) {
|
|
return '_' + c.charCodeAt( 0 ) + '_';
|
|
} );
|
|
}
|
|
|
|
function makeRequest( symbol ) {
|
|
var request,
|
|
data = querystring.stringify( {
|
|
q: symbol
|
|
} ),
|
|
// API call to mathoid
|
|
options = {
|
|
host: '192.168.37.177',
|
|
port: '10044',
|
|
path: '/',
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'Content-Length': Buffer.byteLength( data )
|
|
}
|
|
};
|
|
|
|
// Populate and make the API call
|
|
request = http.request( options, function ( res ) {
|
|
var body = '';
|
|
res.setEncoding( 'utf8' );
|
|
|
|
res.on( 'data', function ( data ) {
|
|
body += data;
|
|
} );
|
|
|
|
res.on( 'end', function () {
|
|
var className = texToClass( symbol ),
|
|
svg = JSON.parse( body ).svg;
|
|
|
|
if ( !svg ) {
|
|
console.log( symbol + ' FAILED: ' + body );
|
|
onEnd();
|
|
return;
|
|
}
|
|
|
|
svgo.optimize( svg, function ( result ) {
|
|
// write to the css file
|
|
cssRules.push(
|
|
cssPrefix + className + ' {\n' +
|
|
'\tbackground-image: url(data:image/svg+xml,' + encodeURIComponentForCSS( result.data ) + ');\n' +
|
|
'}'
|
|
);
|
|
console.log( symbol + ' -> ' + className );
|
|
} );
|
|
onEnd();
|
|
|
|
} );
|
|
} );
|
|
request.setTimeout( 10000 );
|
|
request.write( data );
|
|
request.end();
|
|
runNext();
|
|
}
|
|
|
|
function onEnd() {
|
|
count--;
|
|
runNext();
|
|
}
|
|
|
|
function runNext() {
|
|
if ( count < mathoidMaxConnections && symbolList.length ) {
|
|
count++;
|
|
makeRequest( symbolList.shift() );
|
|
}
|
|
if ( !symbolList.length && !count ) {
|
|
cssRules.sort();
|
|
fs.writeFileSync(
|
|
cssFile,
|
|
'/*!\n' +
|
|
' * This file is GENERATED by tools/makeSvgsAndCss.js\n' +
|
|
' * DO NOT EDIT\n' +
|
|
' */\n' +
|
|
'\n' +
|
|
cssRules.join( '\n\n' ) +
|
|
'\n'
|
|
);
|
|
}
|
|
}
|
|
|
|
if ( cssData ) {
|
|
cssLines = cssData.split( '\n' );
|
|
for ( i = 0; i < cssLines.length; i++ ) {
|
|
if ( cssLines[ i ].indexOf( cssPrefix ) === 0 ) {
|
|
cssRules.push( cssLines.slice( i, i + 3 ).join( '\n' ) );
|
|
cssClasses.push( cssLines[ i ].slice( cssPrefix.length, -2 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
symbolObject = JSON.parse( symbolsData );
|
|
for ( group in symbolObject ) {
|
|
symbols = symbolObject[ group ];
|
|
for ( i = 0; i < symbols.length; i++ ) {
|
|
symbol = symbols[ i ];
|
|
if ( symbol.duplicate || symbol.notWorking ) {
|
|
continue;
|
|
}
|
|
index = cssClasses.indexOf( texToClass( symbol.tex ) );
|
|
if ( index === -1 ) {
|
|
symbolList.push( symbol.tex );
|
|
} else {
|
|
// Remove CSS classes we found in the symbol list so that
|
|
// and the end of this loop, cssClasses contains classes
|
|
// that have been deleted from the symbol list
|
|
cssClasses.splice( index, 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove classes that are no longer in the JSON
|
|
cssRules = cssRules.filter( function ( rule ) {
|
|
return cssClasses.indexOf( rule.split( '\n' )[ 0 ].slice( cssPrefix.length, -2 ) ) === -1;
|
|
} );
|
|
|
|
count = 0;
|
|
runNext();
|
|
|
|
} )();
|