Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
165 lines (144 sloc) 5.89 KB
/*
* Map BBCode parser and producer. See BBCODE.md for description.
*/
window.MapBBCodeProcessor = {
options: {
decimalDigits: 5,
brackets: '[]',
tagParams: false,
shareTag: 'mapid'
},
setOptions: function( options ) {
for( var i in options ) {
if( options.hasOwnProperty(i) )
this.options[i] = options[i];
}
},
_getRegExp: function() {
var openBr = this.options.brackets.substring(0, 1).replace(/([\[\({])/, '\\$1'),
closBr = this.options.brackets.substring(1, 2).replace(/([\]\)}])/, '\\$1');
var reCoord = '\\s*(-?\\d+(?:\\.\\d+)?)\\s*,\\s*(-?\\d+(?:\\.\\d+)?)',
reParams = '\\((?:([a-zA-Z0-9,]*)\\|)?(|[\\s\\S]*?[^\\\\])\\)',
reMapElement = reCoord + '(?:' + reCoord + ')*(?:\\s*' + reParams + ')?',
reMapOpeningTag = openBr + 'map(?:' + (this.options.tagParams ? '\\s+z=[\'"]([12]?\\d)[\'"](?:\\s+ll=[\'"]' + reCoord + '[\'"])?' : '=[\'"]?([12]?\\d)(?:,' + reCoord + ')?') + ')?[\'"]?' + closBr,
reMapEmpty = openBr + 'map' + closBr + '\\s*' + openBr + '/map' + closBr,
reMap = reMapOpeningTag + '(' + reMapElement + '(?:\\s*;' + reMapElement + ')*)?\\s*' + openBr + '/map' + closBr;
return {
coord: reCoord,
params: reParams,
mapElement: reMapElement,
map: reMap,
mapEmptyCompiled: new RegExp(reMapEmpty, 'i'),
mapCompiled: new RegExp(reMap, 'i')
};
},
// returns longest substring for determining a start of map bbcode, "[map" by default
getOpenTagSubstring: function() {
return this.options.brackets.substring(0, 1) + 'map';
},
// constructs opening tag, appending extra (either '=z,lat,lon' or 'z="" ll=""')
getOpenTagWithPart: function( extra ) {
return this.options.brackets.substring(0, 1) + 'map' + (extra && extra.length > 0 ? (this.options.tagParams ? (extra.substring(0, 1) == ' ' ? '' : ' ') : (extra.substring(0, 1) == '=' ? '' : '=')) + extra : '') + this.options.brackets.substring(1, 2);
},
// constructs opening tag for given zoom and coords (optional)
getOpenTag: function( zoom, coords ) {
return this.options.brackets.substring(0, 1) + 'map' + (zoom || zoom === '0' ? (this.options.tagParams ? ' z="' + zoom + '"' + (coords ? ' ll="' + coords + '"' : '') : '=' + zoom + (coords ? ',' + coords : '')) : '') + this.options.brackets.substring(1, 2);
},
// returns longest substring for determining an end of map bbcode, "[/map]" by default
getCloseTag: function() {
return this.options.brackets.substring(0, 1) + '/map' + this.options.brackets.substring(1, 2);
},
// construct mapid sequence, or get '[mapid]' substring for searching
getShareTag: function( id ) {
var openBr = this.options.brackets.substring(0, 1),
closBr = this.options.brackets.substring(1, 2),
mapid = this.options.shareTag || 'mapid';
return id ? openBr + mapid + closBr + id + openBr + '/' + mapid + closBr : openBr + mapid + closBr;
},
// returns compiled regular expression for correct map code (used in isValid())
getBBCodeRegExp: function() {
return this._getRegExp().mapCompiled;
},
// Checks that bbcode string is a valid map bbcode
isValid: function( bbcode ) {
return this._getRegExp().mapCompiled.test(bbcode);
},
// Check that bbcode is either valid and empty (use isValid() for validation)
isEmpty: function( bbcode ) {
return this._getRegExp().mapEmptyCompiled.test(bbcode);
},
// Converts bbcode string to an array of features and metadata
stringToObjects: function( bbcode ) {
var regExp = this._getRegExp(),
matches = bbcode.match(regExp.mapCompiled),
result = { objs: [] };
if( matches && matches[1] && matches[1].length && (+matches[1]) > 0 ) {
result.zoom = +matches[1];
if( matches[3] && matches[3].length > 0 ) {
try {
result.pos = L && L.LatLng ? new L.LatLng(matches[2], matches[3]) : [+matches[2], +matches[3]];
} catch(e) {}
}
}
if( matches && matches[4] ) {
var items = matches[4], itm,
reElementC = new RegExp('^\\s*(?:;\\s*)?(' + regExp.mapElement + ')'),
reCoordC = new RegExp('^' + regExp.coord);
itm = items.match(reElementC);
while( itm ) {
var s = itm[1],
coords = [], m, text = '', params = [];
m = s.match(reCoordC);
while( m ) {
coords.push(L && L.LatLng ? new L.LatLng(m[1], m[2]) : [+m[1], +m[2]]);
s = s.substring(m[0].length);
m = s.match(reCoordC);
}
if( itm[6] )
params = itm[6].split(',');
if( typeof itm[7] === 'string' && itm[7].length > 0 )
text = itm[7].replace(/\\\)/g, ')').replace(/^\s+|\s+$/g, '');
result.objs.push({ coords: coords, text: text, params: params });
items = items.substring(itm[0].length);
itm = items.match(reElementC);
}
}
return result;
},
// Takes an object like stringToObjects() produces and returns map bbcode
objectsToString: function( data ) {
var zoom, pos;
if( data.zoom > 0 ) {
zoom = data.zoom;
if( data.pos )
pos = this._latLngToString(data.pos);
}
var markers = [], paths = [], objs = data.objs || [];
for( var i = 0; i < objs.length; i++ ) {
if( !objs[i] || !('coords' in objs[i]) )
continue;
var coords = objs[i].coords, str = '';
for( var j = 0; j < coords.length; j++ ) {
if( j > 0 )
str = str + ' ';
str = str + this._latLngToString(coords[j]);
}
var text = objs[i].text || '', params = objs[i].params || [];
if( text.indexOf('|') >= 0 && params.length === 0 )
text = '|' + text;
if( text.length > 0 || params.length > 0 )
str = str + '(' + (params.length > 0 ? params.join(',') + '|' : '') + text.replace(/\)/g, '\\)') + ')';
if( coords.length ) {
if( coords.length == 1 )
markers.push(str);
else
paths.push(str);
}
}
return markers.length || paths.length || zoom ? this.getOpenTag(zoom, pos) + markers.concat(paths).join('; ') + this.getCloseTag() : '';
},
_latLngToString: function( latlng ) {
var mult = Math.pow(10, this.options.decimalDigits);
return '' + (Math.round((latlng.lat || latlng[0]) * mult) / mult) + ',' + (Math.round((latlng.lng || latlng[1]) * mult) / mult);
}
};