// ==UserScript==
// @name WME Road Selector Highlights
// @namespace https://greasyfork.org/users/11629-TheLastTaterTot
// @version 0.6.1
// @description Adds the ability to highlight segments that meet a set of custom conditions. Requires WME Road Selector to function.
// @author TheLastTaterTot
// @include https://editor-beta.waze.com/*editor/*
// @include https://www.waze.com/*editor/*
// @exclude https://www.waze.com/*user/editor/*
// @require https://greasyfork.org/scripts/17641-rsel-exprparser-basic/code/rsel-exprparser-basic.js?version=111918
// @run-at document-end
// ==/UserScript==
//---------------------------
// DEBUG:
//RSelEP = RSelExprParser;
//---------------------------
// TODO: Add option to draw highlights as under segments rather than on top (z=334) -- put it under show add'l line opts
// Add option to turn off RSel Highlights (not just hide the layer)
var RSel, rsh, rsh_seg, rsh_OL,
isFirefox = /\bfirefox\b/i.test(navigator.userAgent);
function RSH() {
this._clone = function (obj) {
if (!obj) {
return JSON.parse(JSON.stringify(this));
} else {
return JSON.parse(JSON.stringify(obj));
}
};
this._seq = function (b) {
return Array.apply(null, Array(b)).map(function (_, c) {
return c;
});
};
this._sum = function (arr) {
return arr.reduce(function (a, b) {
return a + b
});
};
this.presets = {
linePropObjKeys: [
'strokeColor',
'strokeOpacity',
'strokeDashstyle',
'strokeLinecap',
'strokeWidthScale',
'strokeDashSizeScale',
'strokeGapScale'
],
linePropIds: ['selRSHColors', 'numRSHOpacity', 'selRSHDash',
'selRSHCap', 'numRSHScaleWidth', 'numRSHDashSizeScale',
'numRSHGapScale'
],
linePropAttrType: ['value', 'valueAsNumber', 'selectedIndex',
'selectedIndex', 'valueAsNumber', 'valueAsNumber', 'valueAsNumber'
],
lineAttributes: {
strokeWidth: [4, 5, 7, 8, 9, 11, 13, 14, 14, 15, 15],
strokeDashstyle: ["solid", "- - - - -", "– ‧ – ‧"],
strokeDasharray: [
["solid"],
[1, 1],
[2, 1, 1, 1]
],
strokeLinecap: ["butt", "round", "square"]
},
defaultLineStyle: {
strokeColor: "#FFFF00",
strokeOpacity: 0.5,
strokeDashstyle: 0,
strokeLinecap: 0,
strokeWidthScale: 1,
strokeDashSizeScale: 1,
strokeGapScale: 1
}
};
this.STYLES = {Default: this._clone(this.presets.defaultLineStyle)};
this.getNewRuleObject = function(){
return {expr: {}, text: null, isValidated: null};
};
this.getNewStylesObject = function() {
return this._clone(this.STYLES.Default);
};
this.HIGHLIGHTS = [{
rule: this.getNewRuleObject(),
style: this.getNewStylesObject()
}];
this.lastIdx = 0;
this.idx = 0;
this.rulesStack = [0];
this.prevZoom = null;
this.doNotDrawLastHighlight = true;
this.triggerUpdate = true;
this.showSessionHighlights = false;
this.loadedSavedSession = false;
this.storeExpression = function(idx){
if (!idx) idx = this.idx;
var currExpr = RSel.getCurrentExpression();
this.HIGHLIGHTS[idx].rule = {
expr: (currExpr) ? currExpr : {},
text: (currExpr) ? RSel.getExpressionText(currExpr) : null,
isValidated: null
};
};
this.clearStoredExpression = function(idx) {
if (!idx) idx = this.idx;
this.HIGHLIGHTS[idx].rule = this.getNewRuleObject()
};
this.storeExprText = function(idx) {
if (!idx) idx = this.idx;
this.HIGHLIGHTS[idx].rule.text = RSel.getExpressionText(RSel.getCurrentExpression());
this.HIGHLIGHTS[idx].rule.isValidated = null;
};
this.validateExprText = function(idx, clearExprBox) {
if (!idx) idx = this.idx;
document.getElementById('outRSExpr').style.display = 'none';
if (rsh.HIGHLIGHTS[idx].rule.text) {
//console.log(rsh.HIGHLIGHTS[idx].rule.text);
RSelExprParser.updateExpression(rsh.HIGHLIGHTS[idx].rule.text);
var currExprText = document.getElementById('outRSExpr').value;
if (currExprText === rsh.HIGHLIGHTS[idx].rule.text) {
this.storeExpression(idx); // update the expr obj in case it needs to be
this.HIGHLIGHTS[idx].rule.isValidated = true;
//$('#outRSExpr').wrap('<div id="divRSExpr" style="padding: 4px; border: 1px solid transparent;"></div>');
//document.getElementById('outRSExpr').style.padding = '2px 0';
//document.getElementById('outRSExpr').style.border = '1px solid transparent';
//document.getElementById('outRSExpr').style.borderColor = '#8000FF';
} else {
this.HIGHLIGHTS[idx].rule.isValidated = false
if (!clearExprBox) {
document.getElementById('outRSExpr').innerHTML = '\
<div style="padding: 4px; background: repeating-linear-gradient(45deg, rgba(251,255,0,0.2), rgba(251,255,0,.2) 10px, rgba(255,224,0,0.4) 10px, rgba(255,224,0,0.4) 20px)">' +
document.getElementById('outRSExpr').innerHTML + '</div>' +
'<div style="font-size: 10px; color: crimson; font-weight: 600; outline: darkgray dotted 1px; margin-top: 5px; padding: 3px 5px;">' +
'<i class="fa fa-exclamation-triangle"></i> <b>RSel Highlights</b> was unable to parse the saved expression text to exactly match the original expression.' +
'<div style="font-size: 10px; font-weight: 600; margin-top: 4px;">' +
'Your original selection will be used for highlighting, but it cannot be edited – only deleted. ' +
'<b>Please make a bug report <a href="https://www.waze.com/forum/posting.php?mode=reply&f=819&t=173107" target="_blank">here</a></b>.' +
'</div></div>';
document.getElementById('outRSExpr').style.display = 'block';
}
}
}
if (clearExprBox) RSelExprParser.rselButtons.clear();
document.getElementById('outRSExpr').style.display = 'block';
return this.HIGHLIGHTS[idx].rule.isValidated;
};
this.recreateExpressionText = function(idx) {
if (!idx) idx = rsh.idx;
if (this.validateExprText(idx)) {
return this.HIGHLIGHTS[idx].rule.text;
} else if (rsh.HIGHLIGHTS[idx].rule.expr) { //resort to using
return RSel.getExpressionText(rsh.HIGHLIGHTS[idx].rule.expr)
}
};
this.addHighlighter = function () {
RSelExprParser.rselButtons.clear();
this.idx = this.HIGHLIGHTS.length; //next index
this.HIGHLIGHTS[this.idx] = {
rule: this.getNewRuleObject(),
style: this.getNewStylesObject()
};
this.lastIdx = this.idx;
this.rulesStack[this.idx] = this.idx;
this.triggerUpdate = true;
this.doNotDrawLastHighlight = true;
};
this.deleteHighlighter = function () {
RSelExprParser.rselButtons.clear();
this.HIGHLIGHTS.splice(this.idx, 1);
((this.idx - 1) > 0) ? this.idx--: this.idx = 0;
this.lastIdx = this.HIGHLIGHTS.length - 1;
this.rulesStack = this._seq(this.HIGHLIGHTS.length);
this.triggerUpdate = true;
};
/*this._getNonemptyExprIndexes = function (arrOfExpr) {
try {
var reverseIndices = [],
e = arrOfExpr.length,
r = 0;
while (e--) {
if (arrOfExpr[e].expr !== undefined && arrOfExpr[e].expr != null &&
Object.keys(arrOfExpr[e].expr).length !== 0)
reverseIndices[r++] = e;
}
return reverseIndices;
} catch (err) {
console.error(err);
}
}
// this._removeEmpty(arr,{ii}) - ii is an optional array of indices of arr to keep
this._removeEmpty = function (arr, ii) { //----Note: the expected indices should be reverse order (last->first)
//bc of the optimized negative while loop
try {
var reverseIndices = [],
arrnew = [],
e = arr.length,
r = 0;
if (typeof ii === 'undefined') {
while (e--) {
if (arr[e] !== undefined && arr[e] != null &&
arr[e].length !== undefined && Object.keys(arr[e]).length !== 0)
reverseIndices[r++] = e;
}
} else {
reverseIndices = ii;
r = ii.length;
}
while (r--) {
arrnew[r] = arr[reverseIndices[r]];
}
return arrnew;
} catch (err) {
console.error(err);
}
}
this.housekeeping = function () {
var numLayers = this.HIGHLIGHTS.length,
notEmptyIndexes = this._getNonemptyExprIndexes(this.HIGHLIGHTS),
numNewLayers = notEmptyIndexes.length,
p = this.presets.linePropObjKeys.length,
lineProp;
this.HIGHLIGHTS = this._removeEmpty(this.HIGHLIGHTS, notEmptyIndexes);
this.rulesStack = this._removeEmpty(this.rulesStack, notEmptyIndexes);
if (numLayers !== numNewLayers) {
this.lastIdx = numNewLayers - 1;
this.idx = this.rulesStack.indexOf(this.idx);
if (this.idx === -1) this.idx = this.lastIdx;
return true;
} else {
return false;
}
};*/
this.importHighlights = function (addThis) {
this.HIGHLIGHTS = addThis.HIGHLIGHTS;
this.rulesStack = addThis.rulesStack;
//this.housekeeping(); // -- TODO: annoying... keeps flipping the order. fix this, then reenable.
this.lastIdx = this.HIGHLIGHTS.length - 1;
this.idx = this.lastIdx;
this.triggerUpdate = true;
this.loadedSavedSession = true;
this.showSessionHighlights = !!addThis.showSessionHighlights;
this.doNotDrawLastHighlight = !!addThis.doNotDrawLastHighlight;
};
this.getCurrentExprText = RSelExprParser.getCurrentExprText;
}
//------------------------------------------------------------------------------
/*////////////////////////////////////////////////////////////////////////////*/
//
// TODO: Organize code...convert some functions to methods and prototypes
//
function RSelHighlights() {
function updatePrefsFromPanel() {
rsh.HIGHLIGHTS[rsh.idx].style.strokeColor = document.getElementById("selRSHColors").value;
rsh.HIGHLIGHTS[rsh.idx].style.strokeOpacity = document.getElementById("numRSHOpacity").valueAsNumber;
rsh.HIGHLIGHTS[rsh.idx].style.strokeDashstyle = document.getElementById("selRSHDash").selectedIndex;
rsh.HIGHLIGHTS[rsh.idx].style.strokeLinecap = document.getElementById("selRSHCap").selectedIndex;
rsh.HIGHLIGHTS[rsh.idx].style.strokeWidthScale = document.getElementById("numRSHScaleWidth").valueAsNumber;
rsh.HIGHLIGHTS[rsh.idx].style.strokeDashSizeScale = document.getElementById("numRSHDashSizeScale").valueAsNumber;
rsh.HIGHLIGHTS[rsh.idx].style.strokeGapScale = document.getElementById("numRSHGapScale").valueAsNumber;
rsh.storeExpression();
}
var updateHighlighterColorButton = function () {
// -----------------------------------------------------------------
// Recolor background of Highlight button
//$("#selRSHColors").val(hex).change();
document.getElementById('selRSHColorBtn').style.backgroundColor =
rsh.HIGHLIGHTS[rsh.idx].style.strokeColor;
document.getElementById('selRSHColors').value =
rsh.HIGHLIGHTS[rsh.idx].style.strokeColor;
}
var updateDashButtons = function () {
// Check to enable or disable line option input boxes
var dashSizeScaleObj = document.getElementById("numRSHDashSizeScale"),
strokeGapScaleObj = document.getElementById("numRSHGapScale");
if (rsh.HIGHLIGHTS[rsh.idx].style.strokeDashstyle !== 0) {
dashSizeScaleObj.disabled = false;
strokeGapScaleObj.disabled = false;
dashSizeScaleObj.style.backgroundColor = "#FFF";
strokeGapScaleObj.style.backgroundColor = "#FFF";
} else {
dashSizeScaleObj.disabled = true;
strokeGapScaleObj.disabled = true;
dashSizeScaleObj.style.backgroundColor = "#E0E0E0";
strokeGapScaleObj.style.backgroundColor = "#E0E0E0";
}
}
function updateEraseButton(disableBtn) {
if (disableBtn === undefined) {
try {
if (!rsh.showSessionHighlights || rsh.doNotDrawLastHighlight) {
disableBtn = true;
} else if (rsh.lastIdx === 0 &&
rsh.HIGHLIGHTS[rsh.idx].rule.expr &&
Object.keys(rsh.HIGHLIGHTS[rsh.idx].rule.expr).length !== 0) {
disableBtn = false;
} else {
disableBtn = true;
}
} catch (err) {
disableBtn = true;
}
}
if (disableBtn) {
$("a#btnRSHClearTop").addClass('disabled');
} else {
$("a#btnRSHClearTop").removeClass('disabled');
}
}
function updateLayerCountButtons() {
if (rsh.lastIdx !== 0) {
$("a#btnRSHSubtract").removeClass('disabled');
$("a#btnRSHClearAll").removeClass('disabled')
updateEraseButton(false);
} else {
$("a#btnRSHSubtract").addClass('disabled');
$("a#btnRSHClearAll").addClass('disabled');
updateEraseButton();
}
$("#txtRSHCount").html(rsh.idx + 1);
}
function updatePanelFromPrefs() {
//console.log('updatePanelFromPrefs()')
rsh.storeExpression(); //update rsh obj with current expression
// Apply panel settings from saved preferences
//$("#selRSHColors").val(rsh.HIGHLIGHTS[rsh.idx].style.strokeColor).change();
$("#numRSHOpacity").val(rsh.HIGHLIGHTS[rsh.idx].style.strokeOpacity).change();
$("#selRSHDash").val(rsh.presets.lineAttributes.strokeDashstyle[rsh.HIGHLIGHTS[rsh.idx].style.strokeDashstyle]).change();
$("#selRSHCap").val(rsh.presets.lineAttributes.strokeLinecap[rsh.HIGHLIGHTS[rsh.idx].style.strokeLinecap]).change();
$("#numRSHScaleWidth").val(rsh.HIGHLIGHTS[rsh.idx].style.strokeWidthScale).change();
$("#numRSHDashSizeScale").val(rsh.HIGHLIGHTS[rsh.idx].style.strokeDashSizeScale).change();
$("#numRSHGapScale").val(rsh.HIGHLIGHTS[rsh.idx].style.strokeGapScale).change();
updateHighlighterColorButton();
updateDashButtons();
updateLayerCountButtons();
}
// ---------------------------------------------------------------------
var setupLineStyles = function () {
var bgRoadColor = document.getElementById("selRSHBgRoadColor").value,
numHighlights = rsh.rulesStack.length;
updatePrefsFromPanel();
// preset line attributes for each zoom level
var z = 11;
while (z--) { // for each zoom level
rsh_seg[z] = {
hlLineStyle: [],
hlLineStyleOvrlp: [],
bgLineStyle: {}
};
var strokeWidthAtZoom = rsh.presets.lineAttributes.strokeWidth[z],
bgStrokeWidthAtZoom = strokeWidthAtZoom - parseInt(strokeWidthAtZoom *
0.5),
mm = numHighlights;
while (mm--) {
// Stroke width (line thickness)
var separationAmt = parseInt((strokeWidthAtZoom) / numHighlights),
strokeWidthScale = rsh.HIGHLIGHTS[mm].style.strokeWidthScale,
strokeWidthAtZoomScaledOvrlp = Math.round(((strokeWidthAtZoom + 2) - mm *
separationAmt) * strokeWidthScale),
strokeWidthAtZoomScaled = Math.round(strokeWidthAtZoom *
strokeWidthScale),
strokeOpacity = rsh.HIGHLIGHTS[mm].style.strokeOpacity,
strokeOpacityOvrlp = strokeOpacity;
// Dash style and customized gap size
var dashSpecs = rsh.presets.lineAttributes.strokeDasharray[
rsh.HIGHLIGHTS[mm].style.strokeDashstyle],
dashSizeScale = rsh.HIGHLIGHTS[mm].style.strokeDashSizeScale,
gapScale = rsh.HIGHLIGHTS[mm].style.strokeGapScale,
dashSize = dashSizeScale * strokeWidthAtZoomScaled,
gap = gapScale * strokeWidthAtZoomScaled,
dashSizeOvrlp = dashSizeScale * strokeWidthAtZoomScaledOvrlp,
gapOvrlp = gapScale * strokeWidthAtZoomScaledOvrlp,
strokeDashstyle, strokeDashstyleOvrlp;
// Make width 1 if the strokeWidth is less than 1 at this zoom
// Also increase opacity to compensate for the small strokeWidth
if (strokeWidthAtZoomScaled <= 1) {
strokeWidthAtZoomScaled = 1;
if (strokeOpacity < 0.9) strokeOpacity = 0.9;
}
// adjust strokeWidth for multiple highlights
strokeOpacityOvrlp = rsh.HIGHLIGHTS[mm].style.strokeOpacity;
if (strokeWidthAtZoomScaledOvrlp <= 1) {
strokeWidthAtZoomScaledOvrlp = 1;
if (strokeOpacityOvrlp < 0.9) strokeOpacityOvrlp = 0.9;
}
switch (rsh.HIGHLIGHTS[mm].style.strokeDashstyle) {
case 0:
strokeDashstyle = dashSpecs[0];
strokeDashstyleOvrlp = dashSpecs[0];
break;
case 1:
strokeDashstyle = dashSpecs[0]*dashSize + ' ' + dashSpecs[1]*gap;
strokeDashstyleOvrlp = dashSpecs[0]*dashSizeOvrlp + ' ' + dashSpecs[1]*gapOvrlp;
break;
case 2:
strokeDashstyle = dashSpecs[0]*dashSize + ' ' + dashSpecs[1]*gap +
' ' + dashSpecs[2]*strokeWidthAtZoomScaled + ' ' + dashSpecs[3]*gap;
strokeDashstyleOvrlp = dashSpecs[0]*dashSizeOvrlp + ' ' + dashSpecs[1]*gapOvrlp +
' ' + dashSpecs[2]*strokeWidthAtZoomScaledOvrlp + ' ' + dashSpecs[3]*gapOvrlp;
break;
}
rsh_seg[z].hlLineStyle[mm] = {
strokeColor: rsh.HIGHLIGHTS[mm].style.strokeColor,
strokeOpacity: strokeOpacity,
strokeDashstyle: strokeDashstyle,
strokeLinecap: rsh.presets.lineAttributes.strokeLinecap[rsh.HIGHLIGHTS[mm].style.strokeLinecap],
strokeWidth: strokeWidthAtZoomScaled,
graphicZIndex: mm + 1
};
rsh_seg[z].hlLineStyleOvrlp[mm] = {
strokeColor: rsh_seg[z].hlLineStyle[mm].strokeColor,
strokeOpacity: strokeOpacityOvrlp,
strokeDashstyle: strokeDashstyleOvrlp,
strokeLinecap: rsh_seg[z].hlLineStyle[mm].strokeLinecap,
strokeWidth: strokeWidthAtZoomScaledOvrlp,
graphicZIndex: mm + 1
};
}
// lineStyle for background (Bg) highlighting
if (bgStrokeWidthAtZoom < 1) bgStrokeWidthAtZoom = 1;
rsh_seg[z].bgLineStyle = {
strokeColor: bgRoadColor,
strokeOpacity: 0.9,
strokeWidth: bgStrokeWidthAtZoom,
strokeLinecap: "butt",
strokeDashstyle: "solid",
graphicZIndex: 0
};
}
rsh.triggerUpdate = false;
}
// ---------------------------------------------------------------------
function updateExprMenu() {
//console.log('updateExprMenu()')
// Dropup menu for selecting layers
var e = rsh.HIGHLIGHTS.length, htmlText = '',
exprText, selStatus;
while (e-- > 0) {
if (e === rsh.idx) {
selStatus = 'active ';
exprText = rsh.recreateExpressionText(e);
} else {
selStatus = '';
exprText = RSel.getExpressionText(rsh.HIGHLIGHTS[e].rule.expr);
}
if (!exprText) exprText = '';
htmlText += (e !== 0) ? '<li>' : '<li style="border-bottom: 0">';
htmlText += '<a id="liRSHexpr" name="' + e + '" ' +
'class = "rsh-expr-menu ' + selStatus +
'" ' + 'href="javascript:void(0)">' +
'<div class="rsh-btn-row">' +
'<div class="icon-sign-blank fa fa-square rsh-expr-color" style="color:' +
rsh.HIGHLIGHTS[e].style.strokeColor + '"></div>' +
exprText + ' </div> ' +
'</a></li>';
}
$(".rsh-expr-menu").html(htmlText);
updatePanelFromPrefs();
//------
$("a.rsh-expr-menu").click(function () {
if (rsh.triggerUpdate) Highlight();
rsh.idx = parseInt(this.name);
//console.log(rsh.idx);
updateExprMenu();
});
}
// ---------------------------------------------------------------------
function drawHighlights() {
var currExpr = RSel.getCurrentExpression();
if (currExpr !== null) {
rsh.storeExpression();
//rsh.HIGHLIGHTS[rsh.idx].rule.expr = currExpr;
}
rsh.doNotDrawLastHighlight = false;
updateExprMenu();
rsh.showSessionHighlights = true;
rsh_OL.setVisibility(true);
updateEraseButton(false);
Highlight();
sessionStorage.RSHighlights = JSON.stringify(rsh);
}
function eraseHighlight() {
//rsh.HIGHLIGHTS[rsh.idx].rule = {};
rsh.doNotDrawLastHighlight = true;
updateEraseButton(true);
rsh.clearStoredExpression();
updateExprMenu();
Highlight();
}
function clearAllHighlights() {
RSelExprParser.rselButtons.clear();
rsh = new RSH();
rsh.doNotDrawLastHighlight = true;
rsh_OL.destroyAllFeatureMaps();
rsh_OL.setVisibility(false);
updateExprMenu(); //reset expressions menu -- also updates panel with settings from rsh.HIGHLIGHTS[].style
setupLineStyles(); //reset line attributes in rsh.HIGHLIGHTS[].style
sessionStorage.RSHighlights = null;
}
// ---------------------------------------------------------------------
function addNewHighlighter() {
drawHighlights();
var currExpr = RSel.getCurrentExpression();
if ((rsh.HIGHLIGHTS[rsh.idx].rule.text === null || rsh.HIGHLIGHTS[rsh.idx].rule.text.length === 0) && currExpr === null) {
return false;
} else {
rsh.addHighlighter();
rsh.doNotDrawLastHighlight = true;
//updatePanelFromPrefs();
updateExprMenu();// -- also updates panel with settings from rsh.HIGHLIGHTS[].style
sessionStorage.RSHighlights = JSON.stringify(rsh);
return true;
}
}
function deleteHighlighter() {
if (rsh.lastIdx > 0) {
rsh.deleteHighlighter();
//updatePanelFromPrefs();
updateExprMenu();// -- also updates panel with settings from rsh.HIGHLIGHTS[].style
sessionStorage.RSHighlights = JSON.stringify(rsh);
return true;
} else {
return false;
}
}
// -----------------------------------------------------------------------------
var toggleDropBarMenu = function (hide) {
var dropbarPanel = document.getElementById("divRSHdropbarPanel"),
dropbarHeader = document.getElementById("divRSHdropbarHeader"),
dropbarContents = document.getElementById("divRSHdropbarContents"),
mainPanel = document.getElementById("divRSHmainPanel");
if (hide) {
mainPanel.style.borderBottomLeftRadius = "5px";
mainPanel.style.borderBottomRightRadius = "5px";
dropbarPanel.style.borderWidth = 0;
dropbarPanel.style.backgroundColor = "transparent";
dropbarHeader.style.backgroundColor = "transparent";
dropbarHeader.style.bottomBorderWidth = 0;
document.getElementById('aRSHdropbarLinkShow').style.display = 'inline-block';
document.getElementById('aRSHdropbarLinkHide').style.display = 'none';
$('div.rsh-styles-menu').css('display','none');
dropbarContents.style.display = "none";
} else {
mainPanel.style.borderBottomLeftRadius = 0;
mainPanel.style.borderBottomRightRadius = 0;
dropbarPanel.style.borderWidth = "2px";
dropbarPanel.style.backgroundColor = "#F9F9F9";
dropbarHeader.style.backgroundColor = "#DADBDC";
dropbarHeader.style.bottomBorderWidth = "1px";
document.getElementById('aRSHdropbarLinkShow').style.display = 'none';
document.getElementById('aRSHdropbarLinkHide').style.display = 'inline-block';
$('div.rsh-styles-menu').css('display','inline-block');
dropbarContents.style.display = "block";
}
};
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
function Highlight(optionalArg) {
var checkAllSegs = false;
if (rsh_OL.visibility) {
if (rsh.triggerUpdate) {
setupLineStyles();
rsh_OL.destroyFeaturesByMapKey(rsh.idx);
}
if (optionalArg === null) checkAllSegs = true;
var userBgHighlight = document.getElementById("cbRSHBgHighlight").checked,
userEditable = document.getElementById("cbRSEditable").checked,
userSuppressRoad = document.getElementById("cbRSHSuppRoad").checked,
currentZoom = Waze.map.zoom,
hlLineStyle = rsh._clone(rsh_seg[currentZoom].hlLineStyle),
hlLineStyleOvrlp = rsh_seg[currentZoom].hlLineStyleOvrlp,
bgLineStyle = rsh_seg[currentZoom].bgLineStyle,
segments = Waze.model.segments.objects, //***********
highlighterIndexes, newFeatureArray = [], newBgFeatureArray = [],
delFeatureArray = [], delBgFeat;
if (rsh.doNotDrawLastHighlight) {
if (userSuppressRoad) optionalArg = true; //must redraw because drawing of features with this setting enabled might change depending on which highlight rules are active
highlighterIndexes = rsh.rulesStack.filter(function(a){return a!==rsh.idx});
rsh_OL.destroyFeaturesByMapKey(rsh.idx);
/*var destroyThese = rsh_OL.getFeaturesByAttribute('rshIndex',rsh.idx);
if (destroyThese.length) {
rsh_OL.unsetFeatureMappings(destroyThese);
rsh_OL.destroyFeatures(destroyThese);
}*/
} else {
highlighterIndexes = rsh.rulesStack;
}
if (optionalArg === true) {
//console.log('Reset requested: rsh_OL.destroyAllFeatureMaps();')
rsh_OL.destroyAllFeatureMaps();
}
//Define separate objects to store features for each highlight rule
rsh.rulesStack.map(function(h){if(rsh_OL._featureMap[String(h)] === undefined) rsh_OL._featureMap[String(h)] = {};});
var ids = Object.keys(segments),
s = ids.length, seg, countHighlighted, h, H;
while (s--) {
if (checkAllSegs || rsh_OL.isOnScreen(ids[s])) { //only care about onscreen segments
seg = segments[ids[s]]; //segments.get(ids[s]),
countHighlighted = 0;
for (h of highlighterIndexes) {
H = String(h);
if ((seg.arePropertiesEditable() || !userEditable) &&
RSel.checkSegment(rsh.HIGHLIGHTS[h].rule.expr, seg)) { //test against selection criteria
countHighlighted++;
if (!rsh_OL._featureMap[H][ids[s]]) {//if highlight has not already been drawn...
if (countHighlighted === 1) {
newFeatureArray.push(rsh_OL.createLineFeature(seg, hlLineStyle[h], h, countHighlighted * userSuppressRoad));
} else {
newFeatureArray.push(rsh_OL.createLineFeature(seg, hlLineStyleOvrlp[h], h));
}
} //else if (optionalArg && optionalArg.constructor !== Boolean) {// else redraw??
//console.log(optionalArg);
//}
} else if (rsh_OL._featureMap[H][ids[s]]) { //seg no longer meets selection criteria, but it is still drawn...
delFeatureArray.concat(rsh_OL.getFeaturesByAttribute('rshID', 'h'+h+'-'+ids[s])); //log it for removal
}
}
//--------------------------------------------------------------------------------------
// Check if script should highlight "background roads" (i.e., roads that don't meet any of the other highlight criteria)
if (userBgHighlight && countHighlighted === 0 && !rsh_OL._featureMap.bg[ids[s]]) {
newBgFeatureArray.push(rsh_OL.createLineFeature(seg, bgLineStyle, 'bg'));
} else if (userBgHighlight && rsh_OL._featureMap.bg[ids[s]] && countHighlighted !== 0){
requestAnimationFrame(function(){
rsh_OL.destroyFeaturesBy('id',ids[s]);
/*delBgFeat = rsh_OL.getFeaturesByAttribute('id',ids[s]);
if (delBgFeat.length) {
rsh_OL.unsetFeatureMappings(delBgFeat);
rsh_OL.destroyFeatures(delBgFeat);
}*/
});
} //------------------------------------------------------------------------------------
} //isOnScreen
} //while
if (newFeatureArray.length) rsh_OL.addFeatures(newFeatureArray);
if (newBgFeatureArray.length) rsh_OL.addFeatures(newBgFeatureArray);
if (!userBgHighlight) {
requestAnimationFrame(function(){rsh_OL.destroyFeaturesByMapKey('bg')});
/*delBgFeat = rsh_OL.getFeaturesByAttribute('rshIndex','bg');
if (delBgFeat.length) {
rsh_OL._featureMap.bg = {};
rsh_OL.destroyFeatures(delBgFeat);
}*/
}
requestAnimationFrame(function(){rsh_OL.destroyFeatureArray(delFeatureArray)});
// Check if time to perform cleanup
for (h of rsh.rulesStack) {
H = String(h);
if (rsh_OL._featureMap[H] && Object.keys(rsh_OL._featureMap[H]).length > 5000) rsh_OL.cleanupFeatureMap(H);
}
if (Object.keys(rsh_OL._featureMap.bg).length > 10000) rsh_OL.cleanupFeatureMap('bg');
} else {
rsh.showSessionHighlights = false;
}
}
// -----------------------------------------------------------------------------
var initHighlightsLayer = function () {
var rsh_OL = new OL.Layer.Vector("Road Selector Highlights", { //W.map.getLayersByName("Road Selector Highlights")[0]
rendererOptions: { zIndexing: true },
uniqueName: '__RSel_Highlights',
displayInLayerSwitcher: true,
draggable:true
});
I18n.translations.en.layers.name.__RSel_Highlights = 'Road Selector Highlights';
Waze.map.addLayer(rsh_OL);
Waze.map.addControl(new OL.Control.DrawFeature(rsh_OL, OL.Handler.Path));
rsh_OL.setZIndex(501);
rsh_OL.setVisibility(rsh.showSessionHighlights);
rsh_OL._featureMap = {bg: {}};
/*rsh_OL.createBgLineFeature = function (segID, nodes, backgroundLine) {
return new OL.Feature.Vector(new OL.Geometry.LineString(nodes), null, backgroundLine);
};*/
rsh_OL._clone = rsh._clone;
rsh_OL.createLineFeature = function (seg, lineOptions, rshIndex, stack) {
var segID = seg.attributes.id,
vertices = seg.geometry.components,
rshID = 'h'+rshIndex+'-'+segID;
if (stack === undefined) { /* do nothing */
} else if (stack === 1) {
lineOptions.strokeOpacity = 0.9;
}
this._featureMap[String(rshIndex)][segID] = seg.geometry.bounds;
return new OL.Feature.Vector(new OL.Geometry.LineString(vertices), {id: segID, rshIndex: rshIndex, rshID: rshID, stack: stack}, lineOptions);
};
rsh_OL.unsetFeatureMappings = function (featArray) {
var numRemoved = 0;
featArray.map(function(a,i){
numRemoved++;
rsh_OL._featureMap[String(a.attributes.rshIndex)][a.attributes.id] = undefined;
});
//console.info('WMERSH:','Feature(s) unmapped =',numRemoved);
};
rsh_OL.destroyFeatureArray = function (featArray) {
if (featArray.length) {
this.destroyFeatures(featArray);
this.unsetFeatureMappings(featArray);
}
};
rsh_OL.destroyFeaturesBy = function(attrName, attrVal) {
var destroyThese = this.getFeaturesByAttribute(attrName,attrVal);
this.destroyFeatureArray(destroyThese);
/*if (destroyThese.length) {
this.unsetFeatureMappings(destroyThese);
this.destroyFeatures(destroyThese);
}*/
};
rsh_OL.destroyFeaturesByMapKey = function(featMapKey) {
if (featMapKey === undefined) featMapKey = rsh.idx;
var destroyThese = this.getFeaturesByAttribute('rshIndex',featMapKey);
if (destroyThese.length) {
this._featureMap[String(featMapKey)] = {};
//rsh_OL.unsetFeatureMappings(destroyThese);
this.destroyFeatures(destroyThese);
}
};
rsh_OL.destroyAllFeatureMaps = function() {
this.destroyFeatures();
this._featureMap = {bg: {}};
};
rsh_OL.cleanupFeatureMap = function(featMapKey) {
if (featMapKey === undefined) featMapKey = String(rsh.idx);
console.log('rsh_OL.cleanupFeatureMap("' + featMapKey + '")');
requestAnimationFrame(function() {
//calculate current active bounds at same scale
var currentCenter = W.map.getCenter(), //lon-lat
scalingFactor = W.map.getResolutionForZoom(W.map.zoom), //OL.Util.getScaleFromResolution(W.map.getResolutionForZoom(zoomOfDataExtent), W.map.baseLayer.units),
newDataBounds = W.map.getExtent().scale(scalingFactor, currentCenter),
featKeysSegID = Object.keys(rsh_OL._featureMap[featMapKey]),
nfeatKeysSegID = featKeysSegID.length,
f, segID, segBounds, featureMapBits = {};
for (f = featKeysSegID; f--;) {
segID = featKeysSegID[f];
segBounds = rsh_OL._featureMap[featMapKey][segID];
if ( segBounds !== undefined &&
newDataBounds.intersectsBounds(segBounds)) {
featureMapBits[segID] = segBounds;
}
}
console.log(Object.keys(featureMapBits).length);
rsh_OL._featureMap[featMapKey] = featureMapBits;
});
};
rsh_OL.isOnScreen = function(segID){
return W.map.getExtent().intersectsBounds(W.model.segments.objects[segID].geometry.bounds);
};
return rsh_OL;
};
// -----------------------------------------------------------------------------
var closeExprMenu = function(){
document.getElementById('btnRSHmenu').classList.remove('open');
window.removeEventListener('click',closeExprMenu,false);
};
var styleMenuDelete = function(that) {
delete rsh.STYLES[that.parentNode.name];
that.parentNode.parentNode.remove();
localStorage.RSHighlights_Styles = JSON.stringify(rsh.STYLES);
};
var stylesMenuActions = function(e) {
switch (this.name) {
case 'saveas':
e.stopPropagation();
var styleName = prompt("Please enter a name for your style:");
rsh.STYLES[styleName] = rsh.HIGHLIGHTS[rsh.idx].style;
$('.rsh-styles-menu ul').append('<li><a name="' + styleName + '">' + styleName + '<span class="fa fa-trash fa-pull-right fa-lg"></span></a></li>');
$('.rsh-styles-menu li>a').click(stylesMenuActions);
$('.rsh-styles-menu li>a>span.fa-trash').click(function(e){
e.stopPropagation();
styleMenuDelete(this);
});
localStorage.RSHighlights_Styles = JSON.stringify(rsh.STYLES);
break;
case 'setasdefault':
rsh.STYLES.default = rsh._clone(rsh.HIGHLIGHTS[rsh.idx].style);
rsh.STYLES.default.strokeColor = '#FFFF00';
localStorage.RSHighlights_Styles = JSON.stringify(rsh.STYLES);
break;
case 'resetdefault':
rsh.STYLES.default = rsh._clone(rsh.presets.defaultLineStyle);
localStorage.RSHighlights_Styles = JSON.stringify(rsh.STYLES);
break;
default:
var strokeColor = rsh.HIGHLIGHTS[rsh.idx].style.strokeColor;
rsh.HIGHLIGHTS[rsh.idx].style = rsh._clone(rsh.STYLES[this.name]);
rsh.HIGHLIGHTS[rsh.idx].style.strokeColor = strokeColor;
updatePanelFromPrefs();
rsh.triggerUpdate = true;
requestAnimationFrame(Highlight);
}
};
var copyToClipboard = function(str) {
var $temp = $("<input>");
$("body").append($temp);
$temp.val(str).select();
document.execCommand("copy");
$temp.remove();
};
var pasteFromClipboard = function() {
var $temp = $("<input>"),
str;
$("body").append($temp);
$temp.focus();
$temp.val('.').select();
document.execCommand("paste");
str = $temp.val()
$temp.remove();
console.log(str);
return str;
}
// -----------------------------------------------------------------------------
var InitRSelHighlights = function () { // return rsh
var checkForAutosave = function () { // return rsh
rsh = new RSH();
// Load autosaved parameters from sessionStorage
if (sessionStorage.RSHighlights) {
rsh.importHighlights(JSON.parse(sessionStorage.RSHighlights));
//console.log("WMERSH: Imported data from previous session.")
if (rsh.HIGHLIGHTS.length === 0 ||
(rsh.HIGHLIGHTS.length !== 0 && rsh.HIGHLIGHTS[0].rule.text === undefined)) rsh = new RSH();
}
//if (rsh.loadedSavedSession) {if (rsh.HIGHLIGHTS[rsh.lastIdx].rule !== null) rsh.addHighlighter(); }
if (rsh.showSessionHighlights === undefined) rsh.showSessionHighlights = false;
if (localStorage.RSHighlights === undefined) localStorage.RSHighlights = '{}';
if (localStorage.RSHighlights_Styles === undefined) {
localStorage.RSHighlights_Styles = '';
} else {
try {
var rshStyles = JSON.parse(localStorage.RSHighlights_Styles);
if (rshStyles.constructor === Object) rsh.STYLES = rshStyles;
} catch(err) { /* ignore */ }
}
if (localStorage.RSHighlights_Prefs === undefined) {
localStorage.RSHighlights_Prefs = '';
} else {
document.getElementById('cbRSHSuppRoad').checked = /&s/.test(localStorage.RSHighlights_Prefs); //suppress
document.getElementById("cbRSHBgHighlight").checked = /&t/.test(localStorage.RSHighlights_Prefs); //trace
}
return rsh;
};
var setupRSHInterface = function () {
// CSS for RSel Highlights
var rshCSS = document.createElement("style");
rshCSS.type = "text/css";
// UI panel
rshCSS.innerHTML =
'.rsh-main-panel { min-width: 285px; width: 100%; background-color: #BEDCE5; border-style: solid; border-width: 2px; border-collapse: collapse; ' +
' padding: 5px 8px; border-color: #93C4D3; margin-top: 15px; border-radius: 5px; vertical-align: middle; }\n' +
'.rsh-dropbar-panel { color: #444; border-style: inset; margin-top: 0; border-width: 2px; border-color: #D5D5D5; background-color: #f9f9f9; ' +
' border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }\n' + // border-bottom-left-radius: 5px; border-bottom-right-radius: 5px0
'.rsh-dropbar-panel table { border: 0; width: 100%; display: inline-table;}\n' +
'.rsh-dropbar-panel td { font-size: 7pt; font-weight: 600; line-height: 6px; padding: 0px 4px 4px 4px; margin: 0; vertical-align: middle; }\n' +
'.rsh-arrow-up { width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-bottom: 5px solid black; }\n' +
'.rsh-arrow-down { width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid black; }\n' +
'div.rsh-vcentered { position: relative; padding: 2px 5px 3px; width: 100%; display: inline-block; vertical-align: middle; text-align: left; }\n' +
'.rsh-dropbar-contents {display: block; margin: 8px 0px 0px; padding: 0; border: 0 }\n' +
'select.rsh-dropbar-panel { height:20px; width: 100px; background-color: #FFF; border: 1px solid #959595; margin: 0px 0px 2px 2px; padding: 0; }\n' +
'input.rsh-dropbar-panel { height:20px; width: 36px; background-color: #FFF; border: 1px solid #C1C1C1; border-radius: 0; margin: 0px 0px 2px 2px; padding: 0; }\n' +
'.rsh-dropbar-header { color: #000; border-bottom: 1px solid #c0c0c0; }\n' +
'a.rsh-link { text-decoration: none; }' +
'.rsh-btn-container>label { padding-left: 4px; }';
// Buttons
rshCSS.innerHTML +=
'.rsh-btn-row { position: relative; display: block; vertical-align: middle; margin: auto; padding: 0; }\n' +
'.rsh-btn-container { height: 25px; position: relative; display: inline-block; padding: 0; margin: 0px 1%; vertical-align: middle; }\n' +
'.rsh-btn-drop { height: 22px; background-color: #FEFEFE; border: 1px solid #CBE1E8; margin-top: 0px; margin-bottom: 0px !important}\n' +
'.rsh-btn-color { border-radius: 5px; line-height: 2; width: 24px; height: 25px; position: absolute; top: 0px; left: 0px; margin-right: -3px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; padding: 0; border-bottom: 2px solid rgba(0,0,0,0.3);}\n' +
'.rsh-btn-highlight { border-radius: 4px; width: 75px; padding-right: 5px; border-top-left-radius: 0px; border-bottom-left-radius: 0px; }\n' + //border-bottom: solid 2px #E4E4E4; border-top: 0; border-right: 0; border-left: 0; }' +
'.rsh-btn-counter, .rsh-btn-counter:hover, .rsh-btn-counter:active, .rsh-btn-counter.active, .rsh-btn-counter:focus { z-index: 0 !important;' +
' height: 25px; width: 25px; padding: 3px 4px; font-size: 14px; line-height: 1.4; cursor: pointer; color: #88888E; background-color: #CFE0E6; border-left: solid 1px #7AB0BE; border-bottom: 0; ' +
' box-shadow: inset 0px 2px 4px -1px rgba(0,0,0,0.2), inset 0px -2px 4px -2px rgba(0,0,0,0.2) }\n' +
'.rsh-btn-inner { border-radius: 5px; background-color: white; display: inline-block; }\n' +
'.rsh-btn { border-radius: 4px; font-size: 12px; line-height: 1.5; height: 25px; font-weight: bold; color: #396179; padding: 3px;}\n' + //background-color: #93C1D3;
'.rsh-btn:hover { opacity: 0.95; color: #264C5F; }\n' + //color: #48758C;
'.rsh-btn.disabled { color: #6C9AAE; cursor: not-allowed !important; opacity: .85;}\n' + //box-shadow: inset 0px 0px 0px 1px rgba(0,0,0,0.05);
'.rsh-btn:active, .rsh-btn:focus, .rsh-btn.active { background-image: none; outline: 0; -webkit-box-shadow: none; box-shadow: none; }\n' +
'a#btnRSHClearAll.rsh-btn { padding-top: 2px; border-left: solid 1px #B099B1; color: white; width: 25px;}\n' +
'a#btnRSHClearAll.rsh-btn.disabled { background-color: #ff8383; color: #FFE0E0 !important; opacity: 0.75;}\n' +
'.rsh-checkbox-row { width: 100%; padding: 0px 8px; display: inline;}\n' +
'.rsh-checkbox-row label { color: #396179; font-size: 10.5px; font-weight: 600 !important;}\n' +
'.rsh-btn>.tooltip-inner { font-weight: bold; }\n' +
'.fa-bars.rsh-icn { margin-left: 0; margin-right: -1%; line-height: 0.9; padding: 4px; height: 25px; display: inline-block; vertical-align: middle; color: #59899E; font-size: 17px; text-shadow: 0px 1px 0px rgba(255,255,255,0.5); border: 1px solid transparent; }\n' +
'.rsh-icn:hover, .rsh-icn:active, .rsh-icn:focus { border: 1px solid rgb(132, 174, 191); border-radius: 4px; cursor: pointer; }\n' +
'.rsh-styles-menu>ul>li>a { padding: 2px 15px; cursor: pointer; }\n' +
'.rsh-styles-menu .fa-trash:hover, .rsh-styles-menu .fa-trash:focus, .rsh-styles-menu .fa-trash:active {color: #ed503b;}\n' +
'.rsh-styles-menu .fa-trash { margin-top: 2.5px; color: lightgray; }\n' +
'.btn-group .rsh-btn2 { font-size: 13px; width: 21px; height: 22px; padding: 1px; border-width: 1px; border-radius: 3px; color: #396179; background: transparent; }\n' +
'.btn-group .rsh-btn2:focus, .btn-group .rsh-btn2:active { border: 1px solid #00BCD4; z-index: 2;}\n';
rshCSS.innerHTML += // Dropup expressions menu
'.dropdown-menu.rsh-expr-menu { right: -90px; padding: 1px; border-radius: 2px; font-size: 10px; max-height: 400px; width: 290px; overflow-x: hidden; overflow-y: auto;}\n' +
'.dropdown-menu.rsh-expr-menu>li { border-bottom: 1px solid #CBE1E8; margin: 0; padding: 0; }\n' +
'.dropdown-menu.rsh-expr-menu>li>a:active, .dropdown-menu.rsh-expr-menu>li>a.active { background-color: #D8E7EC; }\n' +
'.dropdown-menu.rsh-expr-menu>li>a { word-wrap: break-word; white-space: normal; padding-top: 8px; padding-bottom: 8px; padding-left:10px; padding-right:10px; }\n' +
'.divider.rsh-expr-menu { background-color: #CBE1E8; color: #CBE1E8; margin: 0; padding: 0; height: 2px; }\n' +
'.rsh-expr-color { display: inline-block; margin-left: 0px; margin-right: 8px; padding: 0; }\n' +
'';
// CSS-generated icons
rshCSS.innerHTML +=
'.rsh-icn-outerbox { display: inline-block; width: 13px; height: 11px; margin: 5px 3px 6px 3px; padding: 0; font-size: 0; border: 0; vertical-align: middle; line-height: 0px; }\n' +
'.rsh-icn-indark { display: inline-block; margin: 0; padding: 0; background-color: #555; }\n' +
'.rsh-icn-inwhite { display: inline-block; margin: 0; padding: 0; background-color: #FFF; }\n' +
'.rsh-icn-inclear { display: inline-block; margin: 0; padding: 0; background-color: transparent; }\n' +
'.rsh-icn-brdark { display: block; margin: 0; padding: 0; background-color: #555; }\n' +
'.rsh-icn-brclear { display: block; margin: 0; padding: 0; background-color: transparent; }\n' +
'.rsh-icn-ingray { display: inline-block; margin: 0; padding: 0; background-color: #bbbbbb; }\n' +
'.rsh-icn-2x2 { width: 2px; height: 2px }\n' +
'.rsh-icn-3x2 { width: 3px; height: 2px }\n' +
'.rsh-icn-2x1 { width: 2px; height: 1px }\n' +
'.rsh-icn-1x2 { width: 1px; height: 2px }\n' +
'.rsh-icn-1x1 { width: 1px; height: 1px }\n' +
'.rsh-icn-3x3 { width: 3px; height: 3px }\n' +
'.rsh-icn-4x3 { width: 4px; height: 3px }\n' +
'.rsh-icn-13x1 { width: 13px; height: 1px }\n';
document.body.appendChild(rshCSS);
//------------------------------------------------------------------
// CSS-HTML Icons
// [weight, opacity, stroke type, end cap, dash size, dash gap]
var rshIcons = [
'<div class="rsh-icn-outerbox"><div class="rsh-icn-brdark" style="width: 13px; height: 3px"></div><div class="rsh-icn-brclear" style="width: 13px; height: 2px"></div><div class="rsh-icn-brdark" style="width: 13px; height: 2px"></div><div class="rsh-icn-brclear" style="width: 13px; height: 3px"></div><div class="rsh-icn-brdark" style="width: 13px; height: 1px"></div></div>',
'<div class="rsh-icn-outerbox"><div class="rsh-icn-indark rsh-icn-3x3"></div><div class="rsh-icn-inwhite rsh-icn-3x3"></div><div class="rsh-icn-indark rsh-icn-3x3" style="background-color: #ababab !important"></div><div class="rsh-icn-inwhite rsh-icn-3x3" style="background-color: #f1f1f1 !important"></div><div class="rsh-icn-inwhite rsh-icn-3x3"></div><div class="rsh-icn-indark rsh-icn-3x3" style="background-color: #999999 !important"></div><div class="rsh-icn-inwhite rsh-icn-3x3" style="background-color: #f1f1f1 !important"></div><div class="rsh-icn-indark rsh-icn-3x3" style="background-color: #CCCCCC !important"></div><div class="rsh-icn-indark rsh-icn-3x3" style="background-color: #888888 !important"></div><div class="rsh-icn-inwhite rsh-icn-3x3" style="background-color: #fafafa !important"></div><div class="rsh-icn-indark rsh-icn-3x3" style="background-color: #bbbbbb !important"></div><div class="rsh-icn-inclear rsh-icn-3x3"></div><div class="rsh-icn-inwhite rsh-icn-3x3" style="background-color: #fbfbfB !important"></div><div class="rsh-icn-indark rsh-icn-3x3" style="background-color: #bbbbbb !important"></div><div class="rsh-icn-inclear rsh-icn-3x3"></div><div class="rsh-icn-indark rsh-icn-3x3" style="background-color: #dddddd !important"></div></div>',
'<div class="rsh-icn-outerbox"><div class="rsh-icn-brdark" style="width: 13px; height: 2px"></div><div class="rsh-icn-brclear" style="width: 13px; height: 2px"></div><div class="rsh-icn-indark" style="width: 6px; height: 2px"></div><div class="rsh-icn-inclear" style="width: 1px; height: 2px"></div><div class="rsh-icn-indark" style="width: 6px; height: 2px"></div><div class="rsh-icn-brclear" style="width: 13px; height: 2px"></div><div class="rsh-icn-indark" style="width: 3px; height: 3px"></div><div class="rsh-icn-inclear" style="width: 2px; height: 3px"></div><div class="rsh-icn-indark" style="width: 3px; height: 3px"></div><div class="rsh-icn-inclear" style="width: 2px; height: 3px"></div><div class="rsh-icn-indark" style="width: 3px; height: 3px"></div></div>',
'',
'<div class="rsh-icn-outerbox" style="width: 13px !important"><div class="rsh-icn-indark rsh-icn-1x2"></div><div class="rsh-icn-inclear rsh-icn-2x2"></div><div class="rsh-icn-indark rsh-icn-1x2"></div><div class="rsh-icn-inclear rsh-icn-2x2"></div><div class="rsh-icn-indark rsh-icn-1x2"></div><div class="rsh-icn-inclear rsh-icn-2x2"></div><div class="rsh-icn-indark rsh-icn-1x2"></div><div class="rsh-icn-inclear rsh-icn-2x2"></div><div class="rsh-icn-indark rsh-icn-1x2"></div><!-->>--><div class="rsh-icn-brclear" style="width: 13px; height: 3px"></div><!--<<--><div class="rsh-icn-indark rsh-icn-3x2"></div><div class="rsh-icn-inclear rsh-icn-2x2"></div><div class="rsh-icn-indark rsh-icn-3x2"></div><div class="rsh-icn-inclear rsh-icn-2x2"></div><div class="rsh-icn-indark rsh-icn-3x2"></div><!-->>--><div class="rsh-icn-brclear" style="width: 13px; height: 2px"></div><!--<<--><div class="rsh-icn-indark" style="width: 6px; height: 2px"></div><div class="rsh-icn-inclear" style="width: 2px; height: 2px"></div><div class="rsh-icn-indark" style="width: 5px; height: 2px"></div></div>',
'<div class="rsh-icn-outerbox"><div class="rsh-icn-brclear" style="width: 13px; height: 1px"></div><div class="rsh-icn-indark rsh-icn-4x3"></div><div class="rsh-icn-inclear" style="width: 5px; height: 3px"></div><div class="rsh-icn-indark rsh-icn-4x3"></div><div class="rsh-icn-brclear" style="width: 13px; height: 3px"></div><div class="rsh-icn-inclear rsh-icn-2x1"></div><div class="rsh-icn-ingray rsh-icn-1x1"></div><div class="rsh-icn-inclear" style="width: 7px; height: 1px"></div><div class="rsh-icn-ingray rsh-icn-1x1"></div><div class="rsh-icn-inclear rsh-icn-2x1"></div><div class="rsh-icn-inclear rsh-icn-2x1"></div><div class="rsh-icn-ingray" style="width: 9px; height: 1px"></div><div class="rsh-icn-inclear rsh-icn-2x1"></div><div class="rsh-icn-inclear rsh-icn-2x1"></div><div class="rsh-icn-ingray rsh-icn-1x1"></div><div class="rsh-icn-inclear" style="width: 7px; height: 1px"></div><div class="rsh-icn-ingray rsh-icn-1x1"></div><div class="rsh-icn-inclear rsh-icn-2x1"></div><div class="rsh-icn-brclear" style="width: 13px; height: 2px"></div></div>'
];
//------------------------------------------------------------------
// Main RSel Highlights panel
$("#RSselection").append(
'<div class="rsh-main-panel" id="divRSHmainPanel" style="padding-bottom: 5px;">' +
'<div class="rsh-btn-row">' +
' <div class="rsh-btn-container">' +
' <div class="rsh-btn-inner" style="margin-right: 6px;">' +
' <input type="color" id="selRSHColors" value="#FFFF00" class="btn rsh-btn-color" style="opacity: 0; float: left; position: relative; padding: 0; -webkit-appearance: none; -moz-appearance: none;" ' +
' list="colors" data-toggle="tooltip" title="Highlighter color">' + // highlight color
' <datalist id="colors">' +
' <option>#CCFF66</option><option>#28F311</option><option>#66FFCC</option><option>#00F2F2</option><option>#0037D1</option>' +
' <option>#FFFF00</option><option>#F5950E</option><option>#E1201B</option><option>#FF00FF</option><option>#8000FF</option>' +
' </datalist></input>' +
' <div id="selRSHColorBtn" class="btn rsh-btn-color fa fa-caret-down fa-lg" style="pointer-events: none; z-index: 1; background-color: yellow;"></div>' +
' <button id="btnRSHighlight" class="btn btn-primary rsh-btn rsh-btn-highlight active" ' + // HIGHLIGHT
' data-toggle="tooltip" title="Update map highlights"> Highlight</button>' +
' </div><div class="rsh-btn-inner" style="margin-right: 6px;">' +
' <a id="btnRSHClearTop" style="width: 26px;" class="btn btn-primary rsh-btn disabled" data-toggle="tooltip" title="Erase last highlight" href="javascript:void(0)">' + // undo eraser
' <span class="fa fa-eraser fa-lg"></span></a>' +
' </div></div>' +
' <div class="rsh-btn-container"><div class="btn-group rsh-btn-inner">' +
' <a id="btnRSHAdd" style="width: 24px;" class="btn btn-primary rsh-btn" data-toggle="tooltip" title="Add new highlighter rule" href="javascript:void(0)">' + // Add layer
' <span class="fa fa-plus"></span></a>' +
' <div id="btnRSHmenu" class="btn-group dropup">' +
' <div id="btnRSHCount" class="btn rsh-btn-counter">' +// layer counter
' <span id="txtRSHCount">0</span></div>' + // [#]
' <ul class="dropdown-menu pull-right dropdown-menu-right list-group rsh-expr-menu">' +
' <li></li>' +
' </ul>' +
' </div>' +
' <a id="btnRSHSubtract" style="width: 24px;" class="btn btn-primary rsh-btn disabled" data-toggle="tooltip" title="Delete selected highlight rule" href="javascript:void(0)">' + // border-right: solid 1px #7AB0BE;
' <span class="fa fa-minus"></span></a>' +
' <a id="btnRSHClearAll" class="btn btn-danger rsh-btn disabled" data-toggle="tooltip" title="Delete all highlighter rules" href="javascript:void(0)">' +
' <span class="fa fa-trash fa-lg"></span></a>' +
' </div></div>' +
' <div id="icnRSHmoreOpts" class="fa fa-bars pull-right rsh-icn" title="More highlight options" data-toggle="tooltip"></div>' +
'</div></div>');
$("#divRSHmainPanel").append(
'<div id="rshMoreOptions" style="display: none;">' +
'<div class="rsh-btn-row" style="margin: 6px -8px 0px; padding: 4px 0px 4px; border-top: 1px solid #93C4D3; border-bottom: 1px solid #93C4D3; background-color: #A1C4D1;">' +
' <div class="rsh-checkbox-row">' +
' <div class="checkbox-inline" style="width: width: 270px; display: inline-block; padding-left: 20px;">' +
' <input type="checkbox" id="cbRSHSuppRoad" class="btn" style="margin-right: 5px; margin-bottom: 7px;"></input>' +// Suppress roads
' <label for="cbRSHSuppRoad">Suppress apperance of roads under highlights</label>' +
' </div>' +
' </div>' +
' <div class="rsh-checkbox-row">' +
' <div class="checkbox-inline" style="width: 210px; display: inline-block; padding-left: 20px;">' +
' <input type="checkbox" id="cbRSHBgHighlight" class="btn">' +
' <label for="cbRSHBgHighlight">Trace over non-highlighted roads with a single color</label>' + // Trace background roads checkbox
' </div>' +
' <div style="display: inline-block">' +
' <input type="color" id="selRSHBgRoadColor" value="#c0c0c0" class="btn rsh-btn-drop" ' + // trace color
' list="bgRdcolors" style="width: 50px; height: 21px; padding: 2px 4px; background-color: #CBE1E8; position: relative; right: 3px; top: -2px;" ' +
' data-toggle="tooltip" title="Tracing color for non-highlighted roads">' +
' <datalist id="bgRdcolors">' +
' <option>#FFFFFF</option><option>#c0c0c0</option><option>#000000</option><option>#264B01</option><option>#634D41</option>' +
' </datalist>' +
' </div>' +
' </div>' +
'</div>' +
'<div class="form-inline" style="vertical-align: middle; margin: 6px -2px 0px -2px;">' +
'<select id="selRSHighlighter" class="form-control" style="padding: 0; width: 145px; min-width: 145px; height: 24px;"><option></option></select>' +
'<div class="btn-group" style="float: right; margin: 1px;">' +
'<a id="applyRSHighlighter" title="Load selected highlighter" style="margin-left: 5px;" class="btn btn-primary rsh-btn2"><i class="fa fa-upload fa-fw"></i></a>' +
'<a id="saveRSHighlighter" title="Save current highlighting rules" class="btn btn-primary rsh-btn2"><i class="fa fa-save fa-fw"></i></a>' +
'<a id="delRSHighlighter" title="Delete selected highlighter" class="btn btn-primary rsh-btn2"><i class="fa fa-times fa-fw"></i></a>' +
'<a id="importRSHighlighter" title="Import highlighters from clipboard" class="btn btn-primary rsh-btn2"><i class="fa fa-sign-in fa-flip-horizontal fa-fw"></i></a>' +
'<a id="exportRSHighlighter" title="Export selected highlighter" class="btn btn-primary rsh-btn2"><i class="fa fa-reply fa-flip-horizontal fa-fw"></i></a>' +
'<a id="exportAllRSHighlighter" title="Export all highlighters" class="btn btn-primary rsh-btn2"><i class=" fa fa-reply-all fa-flip-horizontal fa-fw"></i></a>' +
'</div>' +
'</div>' +
'</div>');
if (isFirefox) $('#cbRSHBgHighlight').parent().css('padding-left','28px');
$("div#divRSHmainPanel [data-toggle=tooltip]").tooltip({
placement: 'auto top',
delay: {
show: 1100,
hide: 100
},
html: true,
template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="my-tooltip-header"><b></b></div><div class="my-tooltip-body tooltip-inner" style="font-weight: bold; !important"></div></div>'
});
// Additional style options drop menu
$("#RSselection").append('\
<div id="divRSHdropbarPanel" class="rsh-dropbar-panel" style="min-width: 285px; width: 100%;">\
<div id="divRSHdropbarHeader" class="rsh-vcentered">\
<div style="display: inline-block">\
<a id="aRSHdropbarLinkShow" class="rsh-link" href="javascript:void(0);" style="display: none;"><i class="fa fa-chevron-up"></i> Show additional style options</a>\
<a id="aRSHdropbarLinkHide" style="display: inline-block;" class="rsh-link" href="javascript:void(0);"><i class="fa fa-chevron-down"></i> Hide additional style options</a>\
</div>\
<div class="dropdown fa-pull-right rsh-styles-menu open" style="display: none;">\
<button class="btn dropdown-toggle" type="button" data-toggle="dropdown" style="padding: 0; background: transparent; border: 0; color: #888; font-size: 11px; height: 100%;">\
<span class="fa fa-caret-square-o-down"></span></button>\
<ul class="dropdown-menu" style="top: 80%; left: initial; right: -3px; border-radius: 2px; font-size: 10px; min-width: 140px; max-width: 140px;">\
<li><a name="saveas" href="#">Save Style As...</a></li>\
<li><a name="saveasdefault" href="#">Save As Default</a></li>\
<li><a name="resetdefault" href="#">Reset Default Style</a></li>\
<li class="divider"></li>\
<li class="dropdown-header" style="padding: 2px 15px; font-size: 9px; text-transform: uppercase;">Load Saved Style</li>\
<li><a name="Default" href="#">Default</a></li>\
</ul>\
</div>\
</div>' + //closing for divRSHdropbarHeader
'<div id="divRSHdropbarContents" class="rsh-dropbar-contents">' +
// table for additional style options within dropbar panel
'<table class="rsh-dropbar-panel">' +
'<tr><td style="vertical-align: bottom">Thickness</td><td style="vertical-align: bottom">Opacity</td>' +
'<td rowspan=4>' +
// inner table for dash style options
'<table class="rsh-dropbar-panel" style="padding-left: 3px; padding-right: 3px; border-left: 1px solid #DFDFDF !important">' +
'<tr><td colspan=2 style="vertical-align: bottom">Dash style</td>' +
'</tr><tr><td colspan=2>' + rshIcons[2] +
'<select id="selRSHDash" class="rsh-dropbar-panel" style="border-color: #B4B4B4"></select></td>' +
'</tr><tr>' +
'<td style="vertical-align: bottom">Dash size</td><td style="vertical-align: bottom">Gap size</td>' +
'</tr><tr>' +
'<td>' + rshIcons[4] +
'<input type="number" id="numRSHDashSizeScale" style="border-radius: 3px; background-color: #EFEFEF;" class="rsh-dropbar-panel" min="0.1" max="10" value="1" step="0.1" title="Dash length (relative)" disabled \></td>' +
'<td>' + rshIcons[5] +
'<input type="number" id="numRSHGapScale" style="border-radius: 3px; background-color: #EFEFEF;" class="rsh-dropbar-panel" min="0.1" max="10" value="1" step="0.1" title="Dash gap size (relative)" disabled \></td>' +
'</tr></table></td>' +
'</tr><tr>' +
'<td>' + rshIcons[0] +
'<input type="number" id="numRSHScaleWidth" style="border-radius: 3px" class="rsh-dropbar-panel" min="0.1" max="10" value="1" step="0.1" title="Line weight (relative)"></td>' +
'<td>' + rshIcons[1] +
'<input type="number" id="numRSHOpacity" style="border-radius: 3px" class="rsh-dropbar-panel" min="0" max="1" value="0.5" step="0.1" title="Color opacity (0–1)"></td>' +
'</tr><tr>' +
'<td colspan=2 style="vertical-align: bottom">End cap</td>' +
'<tr><td colspan=2>' + '' +
'<select id="selRSHCap" class="rsh-dropbar-panel" style="border-color: #B4B4B4"></select></td>' +
'</tr></table>' +
'</div></div>');
};
//---------------------------------------
// Insert UI into side-panel of WME under RSel tab
setupRSHInterface();
toggleDropBarMenu(true);
//---------------------------------------
// Retrieve any data from saved sessionStorage
var rsh = checkForAutosave();
var rsh_saved = JSON.parse(localStorage.RSHighlights),
highlighterNames = Object.keys(rsh_saved);
for (var k of highlighterNames) {
document.getElementById("selRSHighlighter").add(new Option(k));
};
var d, c, dashSelection = document.getElementById("selRSHDash"),
capSelection = document.getElementById("selRSHCap"),
stylesHTML = '';
for (d = 0; d < rsh.presets.lineAttributes.strokeDashstyle.length; d++) {
dashSelection.add(new Option(rsh.presets.lineAttributes.strokeDashstyle[
d]));
};
for (c = 0; c < rsh.presets.lineAttributes.strokeLinecap.length; c++) {
capSelection.add(new Option(rsh.presets.lineAttributes.strokeLinecap[c]));
};
for (var styleName in rsh.STYLES) {
if (!/^Default$/.test(styleName)) {
stylesHTML += '<li><a name="' + styleName + '">' + styleName + '<span class="fa fa-trash fa-pull-right fa-lg"></span></a></li>';
}
}
$('.rsh-styles-menu ul').append(stylesHTML);
$('.rsh-styles-menu li>a').click(stylesMenuActions);
$('.rsh-styles-menu li>a>span.fa-trash').click(function(e){
e.stopPropagation();
styleMenuDelete(this);
});
return rsh
}
//------------------------------------------------------------------------
rsh = InitRSelHighlights();
// Update panel
//if (rsh.loadedSavedSession) {
rsh.recreateExpressionText();
updatePanelFromPrefs();
updateExprMenu();
//} else {
// updatePanelFromPrefs(rsh);
//}
rsh_seg = [];
// Add Road Selector Highlights layer to map
rsh_OL = initHighlightsLayer();
//------------------------------------------------------------------------
// Setup event listeners/triggers
document.getElementById("selRSHColors").addEventListener('click', function () {
document.getElementById("selRSHColors").onchange = function () {
rsh.triggerUpdate = true;
updatePrefsFromPanel();
updateHighlighterColorButton();
requestAnimationFrame(drawHighlights);
updateExprMenu();
document.getElementById("selRSHColors").onchange = null;
};
}, false);
//-----
document.getElementById('btnRSHCount').addEventListener('click', function(e){
if (document.getElementById('btnRSHmenu').classList.toggle('open')) {
rsh.storeExpression();
updateExprMenu();
setTimeout(function(){window.addEventListener('click',closeExprMenu,false)},100);
} else {
setTimeout(function(){window.removeEventListener('click',closeExprMenu,false)},100);
}
}, false);
//--------
$('#btnRSHighlight').click(drawHighlights);
$('#btnRSHAdd').click(addNewHighlighter);
$('#btnRSHSubtract').click(deleteHighlighter);
$('#btnRSHClearTop').click(eraseHighlight);
$('#btnRSHClearAll').click(clearAllHighlights);
$('#icnRSHmoreOpts').click(function () {
rsh.storeExpression();
($('#rshMoreOptions').css('display') === 'none') ? $('#rshMoreOptions').css('display','block'): $('#rshMoreOptions').css('display','none');
});
$("#aRSHdropbarLinkHide").click(function(){toggleDropBarMenu(true)});
$("#aRSHdropbarLinkShow").click(function(){toggleDropBarMenu(false)});
//--------
document.getElementById('cbRSHSuppRoad').onclick = function() {
if (this.checked) localStorage.RSHighlights_Prefs = localStorage.RSHighlights_Prefs.replace(/&s|$/,'&s');//suppress
else localStorage.RSHighlights_Prefs = localStorage.RSHighlights_Prefs.replace(/&s/,'');
requestAnimationFrame(Highlight);
};
document.getElementById("cbRSHBgHighlight").onclick = function () {
if (this.checked) localStorage.RSHighlights_Prefs = localStorage.RSHighlights_Prefs.replace(/&t|$/,'&t'); //trace
else localStorage.RSHighlights_Prefs = localStorage.RSHighlights_Prefs.replace(/&t/,'');
//rsh.triggerUpdate = true;
//updatePrefsFromPanel();
requestAnimationFrame(Highlight);
};
//--------
document.getElementById("selRSHDash").addEventListener('click', function () {
document.getElementById("selRSHDash").onchange = function () {
rsh.triggerUpdate = true;
updatePrefsFromPanel();
updateDashButtons();
requestAnimationFrame(Highlight);
//document.getElementById("selRSHDash").onblur = function () {
document.getElementById("selRSHDash").onchange = null;
//document.getElementById("selRSHDash").onblur = null;
//};
};
}, false);
//--------
document.getElementById("selRSHCap").addEventListener('click', function () {
document.getElementById("selRSHCap").onchange = function () {
rsh.triggerUpdate = true;
updatePrefsFromPanel();
requestAnimationFrame(Highlight);
//document.getElementById("selRSHCap").onblur = function () {
document.getElementById("selRSHCap").onchange = null;
//document.getElementById("selRSHCap").onblur = null;
//};
};
}, false);
//--------
document.getElementById("numRSHOpacity").onfocusin = function () {
document.getElementById("numRSHOpacity").onchange = function () {
rsh.triggerUpdate = true;
document.getElementById("numRSHOpacity").onblur = function () {
updatePrefsFromPanel();
requestAnimationFrame(Highlight);
document.getElementById("numRSHOpacity").onchange = null;
document.getElementById("numRSHOpacity").onblur = null;
};
};
};
//--------
document.getElementById("numRSHScaleWidth").onfocusin = function () {
document.getElementById("numRSHScaleWidth").onchange = function () {
rsh.triggerUpdate = true;
document.getElementById("numRSHScaleWidth").onblur = function () {
updatePrefsFromPanel();
requestAnimationFrame(Highlight);
document.getElementById("numRSHScaleWidth").onchange = null;
document.getElementById("numRSHScaleWidth").onblur = null;
};
};
};
//--------
document.getElementById("numRSHDashSizeScale").onfocusin = function () {
document.getElementById("numRSHDashSizeScale").onchange = function () {
rsh.triggerUpdate = true;
document.getElementById("numRSHDashSizeScale").onblur = function () {
updatePrefsFromPanel();
requestAnimationFrame(Highlight);
document.getElementById("numRSHDashSizeScale").onchange = null;
document.getElementById("numRSHDashSizeScale").onblur = null;
};
};
};
//--------
document.getElementById("numRSHGapScale").onfocusin = function () {
document.getElementById("numRSHGapScale").onchange = function () {
rsh.triggerUpdate = true;
document.getElementById("numRSHGapScale").onblur = function () {
updatePrefsFromPanel();
requestAnimationFrame(Highlight);
document.getElementById("numRSHGapScale").onchange = null;
document.getElementById("numRSHGapScale").onblur = null;
};
};
};
document.getElementById('selRSHighlighter').onchange = function() {
if (this.value !== null && this.value !== '') {
$('#applyRSHighlighter').css('color','#2196F3');
}
};
document.getElementById('applyRSHighlighter').onclick = function() {
var rsh_saved = JSON.parse(localStorage.RSHighlights),
highlighterName = document.getElementById("selRSHighlighter").value;
$('#applyRSHighlighter').css('color','');
RSelExprParser.rselButtons.clear();
rsh.importHighlights(rsh_saved[highlighterName]);
drawHighlights();
};
document.getElementById('saveRSHighlighter').onclick = function() {
var rsh_saved = JSON.parse(localStorage.RSHighlights),
selectedName = document.getElementById("selRSHighlighter").value;
var highlighterName = prompt('Please enter a name for this highlighter:', selectedName),
newOpt = document.createElement('option');
if (highlighterName !== null && highlighterName !== '') {
rsh_saved[highlighterName] = {HIGHLIGHTS: rsh.HIGHLIGHTS, rulesStack: rsh.rulesStack};
localStorage.RSHighlights = JSON.stringify(rsh_saved);
$('#selRSHighlighter').map(function(i, o) {
if (new RegExp('^' + highlighterName + '$').test(o.value)) return i
}).each(function(_, i) {
document.getElementById("selRSHighlighter").options.remove(i);
})
newOpt.appendChild(document.createTextNode(highlighterName));
document.getElementById("selRSHighlighter").appendChild(newOpt);
document.getElementById("selRSHighlighter").value = highlighterName;
}
};
document.getElementById('delRSHighlighter').onclick = function() {
var rsh_saved = JSON.parse(localStorage.RSHighlights),
higlighterName = document.getElementById("selRSHighlighter").value,
selIdx = document.getElementById("selRSHighlighter").selectedIndex;
if (selIdx) { //prevent the first option from being deleted
document.getElementById("selRSHighlighter").removeChild(document.getElementById("selRSHighlighter").options[selIdx]);
delete rsh_saved[higlighterName];
document.getElementById("selRSHighlighter").selectedIndex = 0;
localStorage.RSHighlights = JSON.stringify(rsh_saved);
}
};
document.getElementById('importRSHighlighter').onclick = function(){
var str = prompt('Paste exported RSel Highlights string to import highlighting rules:'),
rsh_import, rsh_saved, msgStr,
htmlStr = '<div id="rshMenuNote" style="position: absolute;bottom: 110%;width: 100px;left: -44px;white-space: normal;background-color: rgba(0,0,0,0.85);border-radius: 5px;color: white;font-size: 10px;padding: 5px;">';
if (str !== null && str !== '') {
rsh_import = JSON.parse(str);
if (rsh_import.constructor === Object) {
for (var r in rsh_import) { //do a quick check
if (!rsh_import[r].HIGHLIGHTS || !rsh_import[r].rulesStack) {
htmlStr = '<div id="rshMenuNote" style="position: absolute;bottom: 110%;width: 100px;left: -44px;white-space: normal;background-color: rgba(0,0,0,0.85);border-radius: 5px;color: red;font-size: 10px;padding: 5px;">',
msgStr = 'Import unsuccessful. The pasted string did not contain the expected data.';
setTimeout(function(){$('#importRSHighlighter').append(htmlStr + msgStr + '</div>')}, 300);
setTimeout(function(){$('#rshMenuNote').remove()}, 3000);
//alert('Import unsuccessful. The pasted string did not contain the expected data.');
return 1;
}
}
rsh_saved = JSON.parse(localStorage.RSHighlights);
$.extend(true, rsh_saved, rsh_import);
var numImported = Object.keys(rsh_import).length;
console.log(rsh_saved);
msgStr = 'Imported ' + numImported + ' sets of highlighters';
setTimeout(function(){$('#importRSHighlighter').append(htmlStr + msgStr + '</div>')}, 300);
setTimeout(function(){$('#rshMenuNote').remove()}, 3000);
//localStorage.RSHighlights = JSON.stringify(rsh_saved);
} else {
htmlStr = '<div id="rshMenuNote" style="position: absolute;bottom: 110%;width: 100px;left: -44px;white-space: normal;background-color: rgba(0,0,0,0.85);border-radius: 5px;color: red;font-size: 10px;padding: 5px;">',
msgStr = 'Import unsuccessful. The pasted string did not contain the expected data.';
setTimeout(function(){$('#importRSHighlighter').append(htmlStr + msgStr + '</div>')}, 300);
setTimeout(function(){$('#rshMenuNote').remove()}, 3000);
}
}
};
document.getElementById('exportRSHighlighter').onclick = function(){
var rsh_saved = JSON.parse(localStorage.RSHighlights),
highlighterName=document.getElementById("selRSHighlighter").value,
htmlStr, msgStr;
if (rsh_saved[highlighterName]) {
htmlStr = '<div id="rshMenuNote" style="position: absolute;bottom: 110%;width: 100px;left: -44px;white-space: normal;background-color: rgba(0,0,0,0.85);border-radius: 5px;color: white;font-size: 10px;padding: 5px;">',
msgStr = '"' + highlighterName + '" was copied to your clipboard';
copyToClipboard('{"' + highlighterName + '":' + JSON.stringify(rsh_saved[highlighterName]) + '}');
} else {
htmlStr = '<div id="rshMenuNote" style="position: absolute;bottom: 110%;width: 100px;left: -44px;white-space: normal;background-color: rgba(0,0,0,0.85);border-radius: 5px;color: red;font-size: 10px;padding: 5px;">',
msgStr = "Select a saved highlighter to export"
}
setTimeout(function(){$('#exportRSHighlighter').append(htmlStr + msgStr + '</div>')}, 300);
setTimeout(function(){$('#rshMenuNote').remove()}, 3000);
};
document.getElementById('exportAllRSHighlighter').onclick = function(){
var rsh_saved = JSON.parse(localStorage.RSHighlights),
htmlStr = '<div id="rshMenuNote" style="position: absolute;bottom: 110%;width: 100px;left: -46px;white-space: normal;background-color: rgba(0,0,0,0.85);border-radius: 5px;color: white;font-size: 10px;padding: 5px;">';
copyToClipboard(JSON.stringify(rsh_saved));
setTimeout(function(){$('#exportAllRSHighlighter').append(htmlStr + 'Data for all saved highlighters were copied to your clipboard</div>')}, 300);
setTimeout(function(){$('#rshMenuNote').remove()}, 3000);
};
//------------------------------------------------------------------------
window.addEventListener("beforeunload", function () {
//rsh.HIGHLIGHTS[rsh.lastIdx].rule = {};
//rsh.housekeeping();
//rsh.idx = rsh.lastIdx;
sessionStorage.RSHighlights = JSON.stringify(rsh);
}, false);
var timeoutCanceller1, timeoutCanceller2;
// Event listeners to redraw highlights
Waze.map.events.register("zoomend", Waze.map, function () {
//rsh_OL.adjustBounds(W.model.segments.currentDataBounds);
clearTimeout(timeoutCanceller1);
clearTimeout(timeoutCanceller2);
Highlight(true);
timeoutCanceller1 = setTimeout(function(){
Highlight();
timeoutCanceller2 = setTimeout(function(){
Highlight(null);
}, 1000);
}, 1000)
});
Waze.map.events.register("moveend", Waze.map, function () {
clearTimeout(timeoutCanceller1);
clearTimeout(timeoutCanceller2);
Highlight(true);
timeoutCanceller1 = setTimeout(function(){
Highlight();
timeoutCanceller2 = setTimeout(function(){
Highlight(null);
}, 1000);
}, 1000)
});
Waze.model.actionManager.events.register("afterundoaction", null, function(evt) {
evt.object.actions.map(function(a){
if (a.changedSegStates) {
a.changedSegStates.map(function(segID) {
rsh_OL.destroyFeaturesBy('id',segID);
});
Highlight();
}
});
});
Waze.map.segmentLayer.events.register('featuremodified', W.model.segments.objects, function(evt){
var segID = evt.feature.model.attributes.id;
rsh_OL.destroyFeaturesBy('id',segID);
Highlight();
});
//Waze.map.events.register("move", Waze.map, Highlight);
//Waze.map.events.register("changelayer", Waze.map, Highlight);
//Waze.map.events.register("visibilitychanged", Waze.map, Highlight);
//------------------------------------------------------------------------
setTimeout(Highlight,5000);
}
/*//////////////////////////////////////////////////////////////////////////*/
var waitForWMERSel = function () {
var waitCount = 0,
tryInitRSH = function () {
try {
if (typeof unsafeWindow !== 'undefined' && unsafeWindow.RoadSelector) {
/* unsafeWindow.RoadSelector:
checkSegment(expression, segment)
getCurrentExpression()
getExpressionText(expression)
getSavedNames()
getSavedExpression(name)
*/
RSel = unsafeWindow.RoadSelector;
RSelHighlights(RSel);
} else {
if (waitCount++ < 35) {
setTimeout(tryInitRSH, 600);
} else {
console.error(
'WME RSel Highlights: Could not link up with WME Road Selector.');
}
}
} catch (err) {
console.error(err)
}
};
tryInitRSH();
};
setTimeout(waitForWMERSel, 500);