// ==UserScript==
// @name WME Assist
// @author borman84 (Boris Molodenkov), madnut, turbopirate, Griev0us + (add yourself here)
// @description Check and fix street names for POI and segments.
// @require https://greasyfork.org/scripts/31773-wme-assist-scanner/code/WME_Assist_Scanner.js?version=208266
// @require https://greasyfork.org/scripts/31774-wme-assist-analyzer/code/WME_Assist_Analyzer.js?version=208269
// @grant none
// @include /^https:\/\/(www|beta)\.waze\.com(\/\w{2,3}|\/\w{2,3}-\w{2,3}|\/\w{2,3}-\w{2,3}-\w{2,3})?\/editor\b/
// @version 0.5.28
// @namespace WazeRus
// ==/UserScript==
var WME_Assist = WME_Assist || {}
WME_Assist.debug = function (message) {
if (!$('#assist_debug').is(':checked')) return;
console.log("WME ASSIST DEBUG: " + message);
}
WME_Assist.info = function (message) {
console.log("WME ASSIST INFO: " + message);
}
WME_Assist.warning = function (message) {
console.log("WME ASSIST WARN: " + message);
}
WME_Assist.series = function (array, start, action, alldone) {
var helper = function (i) {
if (i < array.length) {
action(array[i], function () {
helper(i + 1);
});
} else {
if (alldone) {
alldone();
}
}
}
helper(start);
}
function run_wme_assist() {
var ver = '0.5.28';
var debug = WME_Assist.debug;
var info = WME_Assist.info;
var warning = WME_Assist.warning;
function getWazeApi() {
var wazeapi = window.Waze;
if (!wazeapi) return null;
if (!wazeapi.map) return null;
if (!wazeapi.model) return null;
if (!wazeapi.model.countries) return null;
if (!wazeapi.model.countries.top) return null;
return wazeapi;
}
var Rule = function (comment, func, variant) {
this.comment = comment;
this.correct = func;
this.variant = variant;
}
var CustomRule = function (oldname, newname) {
var title = '/' + oldname + '/ ➤ ' + newname;
this.oldname = oldname;
this.newname = newname;
this.custom = true;
$.extend(this, new Rule(title, function (text) {
return text.replace(new RegExp(oldname), newname);
}));
}
var ExperimentalRule = function (comment, func) {
this.comment = comment;
this.correct = func;
this.experimental = true;
}
var Rules = function (countryName) {
var rules_basicRU = function () {
return [
new Rule('Unbreak space in street name', function (text) {
return text.replace(/\s+/g, ' ');
}),
new Rule('ACUTE ACCENT in street name', function (text) {
return text.replace(/\u0301|\u0300|\"|\'/g, '');
}),
new Rule('Dash in street name', function (text) {
return text.replace(/\u2010|\u2011|\u2012|\u2013|\u2014|\u2015|\u2043|\u2212|\u2796/g, '-');
}),
new Rule('No space after the word', function (text) {
return text.replace(/\.(?!\s)/g, '. ');
}),
new Rule('Мусорный знак препинания после пробела', function (text) {
return text.replace(/(^|\s+)(\.|,|;)/g, '$1');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/улицаица/, 'улица');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/скя( |$)/, 'ская$1'); // Волгостроевскя набережная
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(мая)( |$)/, '$1Мая$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(мкрн?\.?|мк?р?-н)( |$)/, '$1микрорайон$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(р-о?н)( |$)/, '$1район$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(им\.?)( |$)/, '$1имени$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(пос\.?)( |$)/i, '$1посёлок$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(д\.?)( |$)/, '$1деревня$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(просп\.?)( |$)/i, '$1проспект$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(ул\.?)( |$)/i, '$1улица$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(р-д)( |$)/i, '$1разъезд$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(з-д)( |$)/i, '$1заезд$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(пер\.?)( |$)/i, '$1переулок$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(пр\.?|пр?-з?д\.?)( |$)/i, '$1проезд$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(пр?-к?т\.?)( |$)/i, '$1проспект$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(тр-т)( |$)/i, '$1тракт$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(пл\.?)( |$)/i, '$1площадь$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(ш\.?)( |$)/, '$1шоссе$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(б-р|бул\.?)( |$)/i, '$1бульвар$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(дор\.)( |$)/i, '$1дорога$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(о\.?)( |$)/, '$1остров$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(наб\.?)( |$)/i, '$1набережная$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(туп\.?)( |$)/i, '$1тупик$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(кв\.?)( |$)/i, '$1квартал$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(набережная р\.?)( |$)/i, '$1набережная реки$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/^На /, 'на ');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(\d)(-ая)( |$)/, '$1-я$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(\d)(-о?го|-ое)( |$)/, '$1$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(\d)(-[оыи]й)( |$)/, '$1-й$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(\d)(-ти)( |$)/, '$1-и$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(\d)й/, '$1-й');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(\d)я/, '$1-я');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(\d)(\sЛет)(\s|$)/, '$1 лет$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(Проектируемый проезд)\s+[№#]\s*(\d+)/, '$1 $2');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/([а-яё])-\s+/, '$1 - ');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/\s+км\./i, ' км');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/\[([^P]+)\]/, '$1');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^|\()СН?Т\s([^\)]+)/, '$1$2 снт');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/^ЖД$/i, 'ж/д');
}),
new Rule('Incorrect highway name', function (text) {
return text.replace(/^M-?(\d)/, 'М$1')
.replace(/^A-?(\d)/, 'А$1')
.replace(/^P-?(\d)/, 'Р$1')
.replace(/^([МАР])-(\d)/, '$1$2')
.replace(/^(\d{2})A-(\d)/, '$1А-$2')
.replace(/^(\d{2})K-(\d)/, '$1К-$2')
.replace(/^(\d{2})H-(\d)/, '$1Н-$2')
.replace(/^(\d{2})P-(\d)/, '$1Р-$2')
.replace(/^(\d+)А(:|\s+|$)/, '$1A$2')
.replace(/^(\d+)В(:|\s+|$)/, '$1B$2');
}),
];
};
var rules_RU = function () {
return rules_basicRU().concat([
new Rule('Incorrect status position', function (text) {
// Неоднозначные улицы, требуется проверка на город
// Москва: Козлова, Мишина
// Питер: Абросимова, Гусева, Комарова, Панфилова, Тарасова, Старцева, Крюкова, Миронова, Перфильева, Шарова, Зеленина, Осокина
// Великий Новгород: Яковлева, Ильина
// Ижевск: Черезова
// Краткие притяжательные прилагательные похожие на фамилии
var exAdjW = 'Репищева|Малая Зеленина|Карташихина|Опочинина|Остоумова|Гаврикова|Прасковьина|Усачёва|Бармалеева|Ильмянинова|Остоумова|Плуталова|Подрезова|Полозова|Рашетова|Сегалева|Шамшева|Эсперова|Замшина|Куракина|Ольгина|Опочинина|Осокина|Рюхина|Тосина|Веткина|Жукова|Абросимова|Черезова|Алымова|Княжнина|Ванчакова|Новоажимова|Чудинцева';
// Женские статусы
var wStatus = 'улица|набережная|дорога|линия|аллея|площадь|просека|автодорога|эстакада|магистраль|дамба|хорда|коса|деревня|переправа|площадка|дорожка|трасса';
// Мужские статусы
var mStatus = 'проспект|переулок|проезд|тупик|бульвар|тракт|просек|взвоз|спуск|разъезд|переезд|квартал|путепровод|мост|сад|сквер|тоннель|туннель|парк|проток|канал|остров|микрорайон|район|городок|посёлок|поселок|вал|проулок|объезд|заезд|съезд|обвод|обход|подъезд|выход';
// Средние статусы
var nStatus = 'шоссе|кольцо|село';
// Названия улиц похожие на прилагательные
var exW = 'Нехая|Тукая|Мая|Барклая|Батырая|Маклая|Бикбая|Амантая|Нечая|Эшпая|Орая|Прикамья|Алтая|Ухсая|Хузангая|Галлая|Николая|Гая|Эркая|Камая|Пченушая|Здоровья|Палантая|Ярвенпяя|Гулая|Заполярья|Крылья|Приморья|Калина Красная|Краснолесья|Мазая|Умырзая|Абая|Сибая|Алибая|Шахрая';
// Названия проспектов похожие на прилагательные
var exM = 'Расковой|Дуровой|Космодемьянской|.+?строй|Ковалевской|Борисовой|Давлетшиной|Крупской|Шевцовой|Чайкиной|Богомоловой|Савиной|Попковой|Петровой|Ангелиной|Терешковой|Новоселовой|Красноармейской|Гризодубовой|Красноярский рабочий|Цеткин|Молдагуловой|Чайкиной|Цветаевой|Тимофеевой|Дубровиной|Ульяны Громовой|[Нн]абережной|Давлетшиной|Перовской|Шпаковой|Ульяновой|Гачхой|Исаевой|Бой|Плевицкой';
// Отделить примечания в скобках (дублёр)
var brackets = '';
text = text.replace(/\s*(.*?)\s*(\(.*\))/,
function (all, s, b) {
brackets = b;
return s;
});
// Игнорируем исключения. Не нужно добавлять статус или изменять порядок слов
if (/^$| - |\/|,|:|дцать\s|десят\s|сорок\s|^\d+(:|$)|\d+[AB]|[МАРН]\d|\d{2}[АКНР]-|ТТК|КАД|ЗСД|АГ?ЗС|(^|\s|-)(лестница|зимник|объезд|заезд|съезд|обвод|обход|подъезд|closed|[Сс]троительство|[Дд]убл[её]р|Rail|грунтовка|[Тт]ропа|[Тт]рек|[Пп]лотина|метро|монорельс|ворота|шлагбаум|трамвай|пути|Транссиб|Мост|подход|подъезд|обход|въезд|выезд|разворот|шлагбаум|слобода|Грейдер|брод|на|в|к|под|с|от|во|из|по|об|у|о|над|около|при|перед|про|до|без|за|через|ж\/д|плотина|снт|кп|станция|[Пп]ромзона|паркинг|парковка|Козлова|Абросимова|Гусева|Комарова|Панфилова|Тарасова|Яковлева|Мишина|Старцева|Крюкова|Ильина|Миронова|Перфильева|Шарова|Зеленина|Жукова|Черезова|Осокина|~)(-|\s|$)/.test(text) )
return text + ' ' + brackets;
// коттеджный, дачный, клубный посёлок в начало
text = text.replace(/(.*?)(?:\s+)((?:.*ый )посёлок)/, '$2 $1');
// Добавляем пропущенный статус
if ( ! new RegExp('(^|\\s+)(' + wStatus + '|' + mStatus + '|' + nStatus + ')(\\s+|$)').test(text) ) {
if ( text == 'Набережная') {
text = 'Набережная улица';
} else
if ( new RegExp('(^|\\s+)(' + wStatus + '|' + mStatus + '|' + nStatus + ')(\\s+|$)', 'i' ).test(text) ) {
// Если статус есть, но записан с заглавной буквы
text = text.replace( new RegExp('(^|\\s+)(' + wStatus + '|' + mStatus + '|' + nStatus + ')(?=\\s+|$)', 'i' ), function (all, space, status) {
return space + status.toLowerCase();
});
} else
if ( /(^|\s+)[Оо]б[ъь]ездная(\s+|$)/.test(text)) {
text = text.replace(new RegExp('(^|\\s+)[Оо]б[ъь]ездная(\\s+|$)(?!=(' + wStatus + '))'), '$1Объездная дорога$2');
} else
if ( /(^|\s+)[Оо]кружная$/.test(text)) {
text = text.replace(/(^|\s+)[Оо]кружная$/, '$1Окружная дорога');
} else
if ( /[-аяь]я$/.test(text)) { // Прилагательное без статуса (Русско-Полянская)
text = text + ' улица';
} else
if (/[а-я]-[А-Я]/.test(text)) { // Не хватает пробелов вокруг тире (Москва-Петушки)
text = text.replace(/([а-я])-([А-Я])/g, '$1 - $2');
} else
text = 'улица ' + text;
}
// Голые числительные без склонения
if ( ! new RegExp('\\d\\s+мая(\\s|$)', 'i' ).test(text) )
text = text.replace(new RegExp('(\\d)(?=(\\s+[^\\s]+(?:-я|ая|ья|яя|яся))*\\s+(' + wStatus + ')(\\s|$))', 'g'), '$1-я'); // 1 линия
text = text.replace(new RegExp('(\\d)(?=(\\s+[^\\s]+(?:[-иоы]й|ин|[оеё]в))*\\s+(' + mStatus + ')(\\s|$))', 'g'), '$1-й'); // 2 проезд, 5 Донской проезд
// Распространённые сокращения
text = text.replace(/М\.\s+(?=Горького)/, 'Максима ');
text = text.replace(/К\.\s+(?=Маркса|Либкнехта)/, 'Карла ');
text = text.replace(/Р\.\s+(?=Люксембург)/, 'Розы ');
text = text.replace(/А\.\s+(?=Невского)/, 'Александра ');
text = text.replace(/Б\.\s+(?=Хмельницкого)/, 'Богдана ');
// Всё пишем заглавными буквами, кроме статусов, предлогов и гидронимов
text = text.replace(/(^|\s+)набережная улица/, '$1Набережная улица');
var foundStatus = false;
text = (' ' + text)
.replace(/([-\s])([^-\s]+)/g,
function(all, space, word) {
if ( ! foundStatus )
if ( new RegExp('^(' + wStatus+ '|' + mStatus + '|' + nStatus + ')$').test(word) ) {
foundStatus = true;
return all;
};
if ( /^(летия|лет|года|реч?к[аи]|канала?|острова?|стороны|год|съезда|имени|области|ручей|канавки|за|из|от|км|километр|де|в|к|о|с|у|на|и)$/i.test(word)
|| ( space == '-' && /^(лейтенанта|майора|полковника|губернатора|й|я|ти|го|е|ей|х)$/.test(word) ) )
return space + word.toLowerCase();
else return space + word.charAt(0).toUpperCase() + word.substr(1);
})
.replace(/\s+(.*)/, '$1')
.replace(/Железная дорога/, 'железная дорога')
.replace(/пос[её]лок остров/i, 'поселок Остров')
.replace(/улица остров (.*)/i, 'улица Остров $1')
.replace(/микрорайон в/i, 'микрорайон В');
// Статусы женского рода
if ( new RegExp('(^|\\s)(' + wStatus + ')(\\s|$)').test(text) ) {
// Распространённые сокращения
text = text.replace(/М\.\s+(?=[^\s]+?(?:ая|ья|яя|яся)( |$))/, 'Малая ');
text = text.replace(/Б\.\s+(?=[^\s]+?(?:ая|ья|яя|яся)( |$))/, 'Большая ');
// перед статусом могут быть только прилагательные
// Строителей 1-я улица -> улица Строителей 1-я
text = text.replace(new RegExp('(?:\\s*)(.+?)(?:\\s+)(' + wStatus + ')(?=\\s+|$)'),
function (all, adj, s) {
if ( new RegExp(exAdjW).test(adj) ) return all;
if ( (! new RegExp(exW).test(adj)) &&
(/^((\s+[^\s]+?(-я|ая|ья|яя|яся))+)$/.test(' ' + adj)) ) return all;
return s + ' ' + adj;
});
// Прилагательные вперёд
if ( ! new RegExp('(^|\\s|-)(' + exW + ')(-|\\s|$)').test(text) ) {
// улица Малая Зеленина -> Малая Зеленина улица
// улица Мягкая -> Мягкая улица
// улица Авиаконструктора Яковлева, улица Малиновая Гора
text = text.replace(new RegExp('(' + wStatus + ')((?:\\s+(?:' + exAdjW + ')|\\s+[^\\s]+(?:-я|ая|ья|яя|яся))+)$'), '$2 $1');
// улица *** Малая Набережная -> Малая Набережная улица ***
text = text.replace(new RegExp('(' + wStatus + ')(.*?)((?:\\s+[^\\s]+(?:-я|ая|ья|яя|яся))+)$'), '$3 $1$2');
// улица Мягкая 1-й Проезд -> Мягкая улица 1-й Проезд
text = text.replace(new RegExp('(' + wStatus + ')(?:\\s+)([^\\s]+(?:-я|ая|ья|яя|яся))(?=\\s+\\d+-й\\s+Проезд|\\s+\\d+-я\\s+Линия)'), '$2 $1');
};
// Числительное всегда вначале если оно согласовано с прилагательным
// Мягкая 1-я -> 1-я Мягкая
text = text.replace(/(.+(?:ая|ья|яя|яся))(?:\s+)(\d+-я)(?! Линия| Ферма| Рота)/, '$2 $1');
// улица 1-я Строителей -> 1-я улица Строителей
text = text.replace(new RegExp('(' + wStatus + ')(?:\\s+)(\\d+-я)(?!\\s+[^\\s]+(?:ая|ья|яя|яся|лка)( |$)|\\s+(' + wStatus + '|Ферма|Авеню|Пристань|Рота|Слобода))', 'i'), '$2 $1');
// 1-я улица Лесоперевалка -> улица 1-я Лесоперевалка
text = text.replace(new RegExp('(\\d+-я)\\s+(' + wStatus + ')\\s+([^\\s]+(?:лка|ель|аза|йка|летка|арка))$'), '$2 $1 $3');
} else
// Статусы мужского рода
if ( new RegExp('(^|\\s)(' + mStatus + ')(\\s|$)').test(text) ) {
// Распространённые сокращения
text = text.replace(/М\.\s+(?=[^\s]+?(?:[-иоы]й|ин|[оеё]в)( |$))/, 'Малый ');
text = text.replace(/Б\.\s+(?=[^\s]+?(?:[-иоы]й|ин|[оеё]в)( |$))/, 'Большой ');
// перед статусом могут быть только прилагательные
text = text.replace(new RegExp('(?:\\s*)(.+?)(?:\\s+)(' + mStatus + ')(?=\\s+|$)'),
function (all, adj, s){
// if ( /[а-яё]+([-иоы]й|ин)(\s+|$)/.test(adj) ) return all;
if ( (! new RegExp(exM, 'i').test(adj)) &&
(/^((\s+[^\s]+?([-иоы]й|ин|[оеё]в))+)$/.test(' ' + adj)) ) return all;
return s + ' ' + adj;
});
// Прилагательное вперёд
if (( ! new RegExp('(^|\\s)(' + exM + ')(\\s|$)', 'i').test(text) ) &&
( ! new RegExp('^(проезд|переулок)([^\.]*?)((?:\\s+[^\\s]+ой)+)$').test(text) ) ) {
// переулок *** 1-й -> 1-й переулок ***
text = text.replace(new RegExp('^(' + mStatus + ')([^\.]*?)((?:\\s+[^\\s]+(?:[-иоы]й|ин))+)$'), '$3 $1$2');
text = text.replace(
new RegExp('^(' + mStatus + ')((?:\\s+[^\\s]+(?:[-иоы]й|ин))+)$'), '$2 $1');
text = text.replace(
new RegExp('^(' + mStatus + ')(?:\\s+)([^\\s]+(?:[-иоы]й|ин))(?=\\s+\\d+-й\\s+Проезд|\\s+\\d+-я\\s+Линия)'), '$2 $1');
}
// Числительное всегда вначале если оно согласовано с прилагательным
// переулок 1-й Дунаевского -> 1-й переулок Дунаевского
//text = text.replace(new RegExp('(' + mStatus + ')(?:\\s+)(\\d+-й)(?!\\s+[^\\s]*(?:' + exM + ')|\\s+[^\\s]+(?:[-иоы]й|ин|[оеё]в)( |$)', 'i'), '$2 $1');
text = text.replace(/(.+[иоы]й)(?:\s+)(\d+-й)/, '$2 $1');
text = text.replace(new RegExp('(' + mStatus + ')(?:\\s+)(\\d+-й)(?!\\s+[^\\s]+[иоык][ий]( |$)|\\s+(' + mStatus + '|Ряд|км|километр|Поворот))', 'i'), '$2 $1');
} else
// Статусы среднего рода
if ( new RegExp('(^|\\s)(' + nStatus + ')(\\s|$)').test(text) ) {
// Энтузиастов шоссе -> шоссе Энтузиастов
text = text.replace(new RegExp('(?:\\s*)(.+?)(?:\\s+)(' + nStatus + ')(?=\\s+|$)'),
function (all, adj, s){
if ( /[а-яё]+(ое)(\s+|$)/.test(adj) ) return all;
return s + ' ' + adj;
});
// шоссе Воткинское -> Воткинское шоссе, Верхнее шоссе
text = text.replace( new RegExp('^(' + nStatus + ')(?:\\s+)(.+[ео]е)$'), '$2 $1');
}
// Возвращаем скобки в конце
return text + ' ' + brackets;
}),
new Rule('Move status to begin of name', function (text) {
return text.replace(/(.*)(улица)(.*)/, '$2 $1 $3');
}, 'Tula'),
new ExperimentalRule('Experimental', function (text) {
return text.replace(/experimental/, 'corrected_experimental');
}),
]);
};
var rules_BY = function () {
var isStatus = function (str) {
var list = ['улица', 'переулок', 'проспект', 'проезд',
'площадь', 'шоссе', 'бульвар', 'тракт',
'тупик', 'спуск', 'вуліца', 'завулак',
'праспект', 'праезд', 'плошча', 'шаша'];
if (list.indexOf(str) > -1) return true;
return false;
}
var isPseudoStatus = function (str) {
var list = ['шоссе', 'тракт', 'площадь', 'шаша', 'плошча', 'спуск'];
if (list.indexOf(str) > -1) return true;
return false;
}
var isNumber = function (str) {
return /([0-9])-[іыйя]/.test(str);
}
var replaceParts = function (text) {
var arr = text.split(' ');
var result = [];
var status;
var number;
var previousPart = '';
for (var i = 0; i < arr.length; ++i) {
var part = arr[i];
if (isStatus(part) && !isPseudoStatus(part)) {
status = part;
} else if (isNumber(part) && previousPart.toLowerCase() != 'героев') {
number = part;
} else {
result.push(part);
}
previousPart = part;
}
if (status) {
result.splice(0, 0, status);
}
if (number) {
result.push(number);
}
return result.join(' ');
}
return rules_basicRU().concat([
new Rule('Delete space in initials', function (text) {
return text.replace(/(^|\s+)([А-Я]\.)\s([А-Я]\.)/, '$1$2$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(тр-т)( |$)/, '$1тракт$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(вул\.?)( |$)/, '$1вуліца$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(зав)( |$)/, '$1завулак$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/(^| )(прасп)( |$)/, '$1праспект$3');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/-ая/, '-я').replace(/-ой/, '-й');
}),
new Rule('Incorrect street name', function (text) {
return text.replace(/([РрНнМмPpHM])-?([0-9])/, function (a, p1, p2) {
p1 = p1
.replace('р', 'Р')
.replace('н', 'Н')
.replace('м', 'М')
.replace('P', 'Р')
.replace('p', 'Р')
.replace('H', 'Н')
.replace('M', 'М');
return p1 + '-' + p2;
});
}),
new Rule('Incorrect street name', replaceParts),
]);
}
var getCountryRules = function (name) {
var commonRules = [
// Following rules must be at the end because
// previous rules might insert additional spaces
new Rule('Лишние пробелы', function (text) {
return text.replace(/[\s]+/g, ' ');
}),
new Rule('Пробелы в начале улицы или после открывающей скобки', function (text) {
return text.replace(/(^|\()[\s]+/, '$1');
}),
new Rule('Пробелы в конце улицы или перед закрывающей скобкой', function (text) {
return text.replace(/[\s]+(\)|$)/, '$1');
}),
];
var countryRules;
info('Get rules for country: ' + name);
switch (name) {
case 'Russia':
countryRules = rules_RU();
break;
case 'Ukraine':
countryRules = rules_RU();
break;
case 'Belarus':
countryRules = rules_BY();
break;
default:
info('There are not implemented rules for country: ' + name);
countryRules = [];
}
return countryRules.concat(commonRules);
}
var rules = [];
var customRulesNumber = 0;
var onAdd = function (rule) {}
var onEdit = function (index, rule) {}
var onDelete = function (index) {}
this.onAdd = function (cb) { onAdd = cb }
this.onEdit = function (cb) { onEdit = cb }
this.onDelete = function (cb) { onDelete = cb }
this.onCountryChange = function (name) {
info('Country was changed to ' + name);
rules.splice(customRulesNumber, rules.length - customRulesNumber);
rules = rules.concat(getCountryRules(name));
}
this.get = function (index) {
return rules[index];
}
this.correct = function (variant, text) {
var newtext = text;
var experimental = false;
for (var i = 0; i < rules.length; ++i) {
var rule = rules[i];
if (rule.experimental && !this.experimental) continue;
if (rule.variant && rule.variant != variant) continue;
var previous = newtext;
newtext = rule.correct(newtext);
var changed = (previous != newtext);
if (rule.experimental && previous != newtext) {
experimental = true;
}
previous = newtext;
// if (rule.custom && changed) {
// // prevent result overwriting by common rules
// break;
// }
}
return {
value: newtext,
experimental: experimental
};
}
var save = function (rules) {
if (localStorage) {
localStorage.setItem('assistRulesKey', JSON.stringify(rules.slice(0, customRulesNumber)));
}
}
this.load = function () {
if (localStorage) {
var str = localStorage.getItem('assistRulesKey');
if (str) {
var arr = JSON.parse(str);
for (var i = 0; i < arr.length; ++i) {
var rule = arr[i];
this.push(rule.oldname, rule.newname);
}
}
}
rules = rules.concat(getCountryRules(countryName));
}
this.push = function (oldname, newname) {
var rule = new CustomRule(oldname, newname);
rules.splice(customRulesNumber++, 0, rule);
onAdd(rule);
save(rules);
}
this.update = function (index, oldname, newname) {
var rule = new CustomRule(oldname, newname);
rules[index] = rule;
onEdit(index, rule);
save(rules);
}
this.remove = function (index) {
rules.splice(index, 1);
--customRulesNumber;
onDelete(index);
save(rules);
}
}
var ActionHelper = function (wazeapi) {
var WazeActionUpdateObject = require("Waze/Action/UpdateObject");
var WazeActionAddOrGetStreet = require("Waze/Action/AddOrGetStreet");
var WazeActionAddOrGetCity = require("Waze/Action/AddOrGetCity");
var ui;
var type2repo = function (type) {
var map = {
'venue': wazeapi.model.venues,
'segment': wazeapi.model.segments
};
return map[type];
}
this.setUi = function (u) {
ui = u;
}
this.Select = function (id, type, center, zoom) {
var attemptNum = 10;
var select = function () {
info('select: ' + id);
var obj = type2repo(type).objects[id];
wazeapi.model.events.unregister('mergeend', map, select);
if (obj) {
wazeapi.selectionManager.select([obj]);
} else if (--attemptNum > 0) {
wazeapi.model.events.register('mergeend', map, select);
}
WME_Assist.debug("Attempt number left: " + attemptNum);
wazeapi.map.setCenter(center, zoom);
}
return select;
}
this.isObjectVisible = function (obj) {
if (!onlyVisible) return true;
if (obj.geometry)
return wazeapi.map.getExtent().intersectsBounds(obj.geometry.getBounds());
return false;
}
var addOrGetStreet = function (cityId, name, isEmpty) {
var foundStreets = wazeapi.model.streets.getByAttributes({
cityID: cityId,
name: name,
});
if (foundStreets.length == 1)
return foundStreets[0];
var city = wazeapi.model.cities.objects[cityId];
var a = new WazeActionAddOrGetStreet(name, city, isEmpty);
wazeapi.model.actionManager.add(a);
return a.street;
}
var addOrGetCity = function (countryID, stateID, cityName) {
var foundCities = Waze.model.cities.getByAttributes({
countryID: countryID,
stateID: stateID,
name : cityName
});
if (foundCities.length == 1)
return foundCities[0];
var state = Waze.model.states.objects[stateID];
var country = Waze.model.countries.objects[countryID];
var a = new WazeActionAddOrGetCity(state, country, cityName);
Waze.model.actionManager.add(a);
return a.city;
}
var cityMap = {};
var onlyVisible = false;
this.newCityID = function (id) {
var newid = cityMap[id];
if (newid) return newid;
return id;
}
this.renameCity = function (oldname, newname) {
var oldcity = wazeapi.model.cities.getByAttributes({name: oldname});
if (oldcity.length === 0) {
console.log('City not found: ' + oldname);
return false;
}
var city = oldcity[0];
var newcity = addOrGetCity(city.countryID, city.stateID, newname);
cityMap[city.getID()] = newcity.getID();
onlyVisible = true;
console.log('Do not forget press reset button and re-enable script');
return true;
}
this.fixProblem = function (problem) {
var deferred = $.Deferred();
var attemptNum = 10; // after that we decide that object was removed
var fix = function () {
var obj = type2repo(problem.object.type).objects[problem.object.id];
wazeapi.model.events.unregister('mergeend', map, fix);
if (obj) {
// protect user manual fix
var currentValue = wazeapi.model.streets.objects[obj.attributes[problem.attrName]].name;
if (problem.reason == currentValue) {
var correctStreet = addOrGetStreet(problem.cityId, problem.newStreetName, problem.isEmpty);
var request = {};
request[problem.attrName] = correctStreet.getID();
wazeapi.model.actionManager.add(new WazeActionUpdateObject(obj, request));
} else {
ui.updateProblem(problem.object.id, '(ручное: ' + currentValue + ')');
}
deferred.resolve(obj.getID());
} else if (--attemptNum <= 0) {
ui.updateProblem(problem.object.id, '(Не исправлено. Удалено?)');
deferred.resolve(problem.object.id);
} else {
wazeapi.model.events.register('mergeend', map, fix);
wazeapi.map.setCenter(problem.detectPos, problem.zoom);
}
WME_Assist.debug('Attempt number left: ' + attemptNum);
}
fix();
return deferred.promise();
}
}
var Ui = function () {
var addon = document.createElement('section');
addon.innerHTML = '<b>WME Assist</b> v' + ver;
var section = document.createElement('p');
section.style.paddingTop = "8px";
section.style.textIndent = "16px";
section.id = "assist_options";
section.innerHTML = '<b>Настройки:</b><br/>' +
'<label><input type="checkbox" id="assist_enabled" value="0"/> Включен</label><br/>' +
'<label><input type="checkbox" id="assist_debug" value="0" checked/> Отладка</label><br/>';
var variant = document.createElement('p');
variant.id = 'variant_options';
variant.innerHTML = '<b>Правила:</b><br/>' +
'<label><input type="radio" name="assist_variant" value="Moscow" checked/> Россия</label><br/>' +
'<label><input type="radio" name="assist_variant" value="Tula"/> Тула</label><br/>';
section.appendChild(variant);
addon.appendChild(section);
section = document.createElement('p');
section.style.paddingTop = "8px";
section.style.textIndent = "16px";
section.id = "assist_custom_rules";
$(section)
.append($('<p>').addClass('message').css({'font-weight': 'bold'}).text('Пользовательские правила'))
.append($('<button>').prop('id', 'assist_add_custom_rule').addClass('btn btn-default btn-primary').text('Добавить'))
.append($('<button>').prop('id', 'assist_edit_custom_rule').addClass('btn btn-default').text('Изменить'))
.append($('<button>').prop('id', 'assist_del_custom_rule').addClass('btn btn-default btn-warning').text('Удалить'))
.append($('<ul>').addClass('result-list'));
addon.appendChild(section);
section = document.createElement('p');
section.style.paddingTop = "8px";
section.style.textIndent = "16px";
section.id = "assist_exceptions";
$(section)
.append($('<p title="Right click on error in list to add">').addClass('message').css({'font-weight': 'bold'}).text('Исключения'))
.append($('<ul>').addClass('result-list'));
addon.appendChild(section);
var newtab = document.createElement('li');
newtab.innerHTML = '<a href="#sidepanel-assist" data-toggle="tab">Assist</a>';
$('#user-info #user-tabs .nav-tabs').append(newtab);
addon.id = "sidepanel-assist";
addon.className = "tab-pane";
$('#user-info > div > .tab-content').append(addon);
var selectedCustomRule = -1;
this.selectedCustomRule = function () {
return selectedCustomRule;
}
this.addCustomRule = function (title) {
var thisrule = $('<li>').addClass('result').click(function () {
selectedCustomRule = $('#assist_custom_rules li.result').index(thisrule);
info('index: ' + selectedCustomRule);
$('#assist_custom_rules li.result').css({'background-color': ''});
$('#assist_custom_rules li.result').removeClass('active');
$(this).css({'background-color': 'lightblue'});
$(this).addClass('active');
}).hover(function () {
$(this).css({
cursor: 'pointer',
'background-color': 'lightblue'
});
}, function () {
$(this).css({
cursor: 'auto'
});
if (!$(this).hasClass('active')) {
$(this).css({
'background-color': ''
});
}
})
.append($('<p>').addClass('additional-info clearfix').text(title))
.appendTo($('#assist_custom_rules ul.result-list'));
}
this.updateCustomRule = function (index, title) {
$('#assist_custom_rules li.result').eq(index).find('p.additional-info').text(title);
}
this.removeCustomRule = function (index) {
$('#assist_custom_rules li.result').eq(index).remove();
selectedCustomRule = -1;
}
this.addException = function (name, del) {
var thisrule = $('<li>').addClass('result').click(function () {
var index = $('#assist_exceptions li.result').index(thisrule);
del(index);
}).hover(function () {
$(this).css({
cursor: 'pointer',
'background-color': 'lightblue'
});
}, function () {
$(this).css({
cursor: 'auto'
});
if (!$(this).hasClass('active')) {
$(this).css({
'background-color': ''
});
}
})
.append($('<p>').addClass('additional-info clearfix').text(name))
.appendTo($('#assist_exceptions ul.result-list'));
}
this.removeException = function (index) {
$('#assist_exceptions li.result').eq(index).remove();
}
this.showMainWindow = function () {
$('#WazeMap').css('overflow', 'hidden');
mainWindow.dialog('open');
mainWindow.dialog('option', 'position', {
my: 'right top',
at: 'right-50 top',
of: '#WazeMap',
});
// Minimize window
mainWindow.prev('.ui-dialog-titlebar').find('button').click();
}
this.hideMainWindow = function () {
mainWindow.dialog('close');
}
$('<div>', {
id: 'WME_AssistWindow',
title: 'WME Assist',
})
.append($('<div>').css({
padding: 10,
})
.append($('<button id="assist_fixall_btn" class="btn btn-danger">Исправить</button>'))
.append($('<button id="assist_scanarea_btn" class="btn btn-warning">Скан</button>'))
.append($('<button id="assist_clearfixed_btn" class="btn btn-success">Очистить</button>'))
.append($('<h2>Проблемы</h2>').css({
'font-size': '100%',
'font-weight': 'bold',
}))
.append($('<ol id="assist_unresolved_list"></ol>').css({
border: '1px solid lightgrey',
'padding-top': 2,
'padding-bottom': 2,
})))
.append($('<div>').css({
padding: 10,
})
.append($('<h2>Исправлено</h2>').css({
'font-size': '100%',
'font-weight': 'bold',
}))
.append($('<ol id="assist_fixed_list"></ol>').css({
border: '1px solid lightgrey',
'padding-top': 2,
'padding-bottom': 2,
})))
.appendTo($('#WazeMap'));
$('<div>').prop('id', 'assist_custom_rule_dialog')
.append($('<p>Заполните все поля</p>'))
.append($('<form>')
.append($('<fieldset>')
.append($('<label>').prop('for', 'oldname').text('Регулярное выражение'))
.append($('<input>', {
type: 'text',
name: 'oldname',
'class': 'text ui-widget-content ui-corner-all',
id: 'oldname',
}))
.append($('<label>').prop('for', 'newname').text('Текст замены'))
.append($('<input>', {
type: 'text',
name: 'newname',
'class': 'text ui-widget-content ui-corner-all',
id: 'newname',
}))
)
)
.appendTo($('#map'));
$('#assist_custom_rule_dialog label').css({display: 'block'});
$('#assist_custom_rule_dialog input').css({display: 'block', width: '100%'});
var customRuleDialog_Ok = function () {}
var customRuleDialog = $('#assist_custom_rule_dialog').dialog({
autoOpen: false,
height: 300,
width: 350,
modal: true,
buttons: {
Ok: function () {
customRuleDialog_Ok();
customRuleDialog.dialog('close');
},
Cancel: function () {
customRuleDialog.dialog('close');
}
}
});
var mainWindow = $('#WME_AssistWindow').dialog({
autoOpen: false,
appendTo: $('#WazeMap'),
width: 500,
draggable: true,
height: 600,
dragStop: function () {
$('#WME_AssistWindow').parent().css('height', 'auto');
}
});
mainWindow.parent('.ui-dialog').css({
'zIndex': 1040,
'opacity': '0.9',
});
mainWindow.prev('.ui-dialog-titlebar').css('background','lightblue');
mainWindow.prev('.ui-dialog-titlebar').find('.ui-dialog-title').append($('<span> - </span>'));
mainWindow.prev('.ui-dialog-titlebar').find('.ui-dialog-title')
.append($('<span>', {
id: 'assist-error-num',
title: 'Количество нерешенных проблем',
text: 0,
}).css({color: 'red'}));
mainWindow.prev('.ui-dialog-titlebar').find('.ui-dialog-title').append($('<span> / </span>'));
mainWindow.prev('.ui-dialog-titlebar').find('.ui-dialog-title')
.append($('<span>', {
id: 'assist-fixed-num',
title: 'Количество исправленных',
text: 0,
}).css({color: 'green'}));
mainWindow.prev('.ui-dialog-titlebar').find('.ui-dialog-title').append($('<span> - </span>'));
mainWindow.prev('.ui-dialog-titlebar').find('.ui-dialog-title')
.append($('<span>', {
id: 'assist-scan-progress',
title: 'Прогресс сканирования',
text: 0,
}).css({color: 'blue'}));
// Hack jquery ui dialog
var icon = mainWindow.prev('.ui-dialog-titlebar').find('span.ui-icon');
if (!icon.hasClass('ui-icon-minusthick')) {
icon.addClass('ui-icon-minusthick');
}
if (icon.hasClass('ui-icon-closethick')) {
icon.removeClass('ui-icon-closethick');
}
var btn = mainWindow.prev('.ui-dialog-titlebar').find('button');
mainWindow.prev('.ui-dialog-titlebar').find('button').unbind('click');
var visible = true;
var height;
mainWindow.prev('.ui-dialog-titlebar').find('button').click(function () {
if ($('#WME_AssistWindow').is(':visible')) {
$('#WME_AssistWindow').hide();
btn.prop('title', 'Развернуть');
icon.removeClass('ui-icon-minusthick');
icon.addClass('ui-icon-arrow-4-diag');
} else {
$('#WME_AssistWindow').show();
btn.prop('title', 'Свернуть');
icon.addClass('ui-icon-minusthick');
icon.removeClass('ui-icon-arrow-4-diag');
}
})
var self = this;
this.addProblem = function (id, text, func, exception, experimental) {
var problem = $('<li>')
.prop('id', 'issue-' + id)
.append($('<a>', {
href: "javascript:void(0)",
text: text,
click: function (event) {
func(event);
},
contextmenu: function (event) {
exception(event);
event.preventDefault();
event.stopPropagation();
},
}))
.appendTo($('#assist_unresolved_list'));
if (experimental) {
problem.children().css({color: 'red'}).prop('title', 'Experimental rule');
}
}
this.updateProblem = function (id, text) {
var a = $('li#issue-' + escapeId(id) + ' > a');
a.text(a.text() + ' ' + text);
}
this.setUnresolvedErrorNum = function (text) {
$('#assist-error-num').text(text);
}
this.setFixedErrorNum = function (text) {
$('#assist-fixed-num').text(text);
}
this.setScanProgress = function (text) {
$('#assist-scan-progress').text(text);
}
var escapeId = function (id) {
return String(id).replace(/\./g, "\\.");
}
this.moveToFixedList = function (id) {
$("#issue-" + escapeId(id)).appendTo($('#assist_fixed_list'));
}
this.removeError = function (id) {
$("#issue-" + escapeId(id)).remove();
}
var fixallBtn = $('#assist_fixall_btn');
var clearfixedBtn = $('#assist_clearfixed_btn');
var scanAreaBtn = $('#assist_scanarea_btn');
var unresolvedList = $('#assist_unresolved_list');
var fixedList = $('#assist_fixed_list');
var enableCheckbox = $('#assist_enabled');
var addCustomRuleBtn = $('#assist_add_custom_rule');
var editCustomRuleBtn = $('#assist_edit_custom_rule');
var delCustomRuleBtn = $('#assist_del_custom_rule');
this.fixallBtn = function () { return fixallBtn }
this.clearfixedBtn = function () { return clearfixedBtn }
this.scanAreaBtn = function () { return scanAreaBtn }
this.unresolvedList = function () { return unresolvedList }
this.fixedList = function () { return fixedList }
this.enableCheckbox = function () { return enableCheckbox }
this.variantRadio = function (value) {
if (!value) {
return $('[name=assist_variant]');
}
return $('[name=assist_variant][value=' + value + ']');
}
this.addCustomRuleBtn = function () { return addCustomRuleBtn }
this.editCustomRuleBtn = function () { return editCustomRuleBtn }
this.delCustomRuleBtn = function () { return delCustomRuleBtn }
this.customRuleDialog = function (title, params) {
var deferred = $.Deferred();
if (params) {
customRuleDialog.find('#oldname').val(params.oldname);
customRuleDialog.find('#newname').val(params.newname);
}
customRuleDialog_Ok = function () {
deferred.resolve({
oldname: customRuleDialog.find('#oldname').val(),
newname: customRuleDialog.find('#newname').val(),
});
}
customRuleDialog.dialog('option', 'title', title);
customRuleDialog.dialog('open');
return deferred.promise();
}
this.variant = function () {
return $('[name=assist_variant]:checked')[0].value;
}
};
var Application = function (wazeapi) {
var scaner = new WME_Assist.Scaner(wazeapi);
var analyzer = new WME_Assist.Analyzer(wazeapi);
var FULL_ZOOM_LEVEL = 5;
var scanForZoom = function (zoom) {
scaner.scan(wazeapi.map.calculateBounds(), zoom, function (bounds, zoom, data) {
console.log(data);
analyzer.analyze(bounds, zoom, data, function (obj, title, reason) {
ui.addProblem(obj.id, title, action.Select(obj.id, obj.type, obj.center, zoom), function () {
analyzer.addException(reason, function (id) {
ui.removeError(id);
ui.setUnresolvedErrorNum(analyzer.unresolvedErrorNum());
});
}, false);
ui.setUnresolvedErrorNum(analyzer.unresolvedErrorNum());
});
}, function (progress) {
ui.setScanProgress(Math.round(progress) + '%');
});
}
var fullscan = function () {
scanForZoom(FULL_ZOOM_LEVEL);
}
var scan = function () {
scanForZoom(wazeapi.map.getZoom());
}
var countryName = function () {
var id = wazeapi.model.countries.top.id;
var name = wazeapi.model.countries.objects[id].name;
return name;
}
var country = countryName();
var action = new ActionHelper(wazeapi);
var rules = new Rules(country);
var ui = new Ui();
analyzer.setRules(rules);
analyzer.setActionHelper(action);
action.setUi(ui);
analyzer.onExceptionAdd(function (name) {
ui.addException(name, function (index) {
if (confirm('Удалить исключение: ' + name + '?')) {
analyzer.removeException(index);
}
});
});
analyzer.onExceptionDelete(function (index) {
ui.removeException(index);
});
// rules.experimental = true;
rules.onAdd(function (rule) {
ui.addCustomRule(rule.comment);
});
rules.onEdit(function (index, rule) {
ui.updateCustomRule(index, rule.comment);
});
rules.onDelete(function (index) {
ui.removeCustomRule(index);
});
wazeapi.model.events.register('mergeend', map, function () {
var name = countryName();
if (name != country) {
rules.onCountryChange(name);
country = name;
}
});
analyzer.loadExceptions();
rules.load();
this.start = function () {
ui.enableCheckbox().click(function () {
if (ui.enableCheckbox().is(':checked')) {
localStorage.setItem('assist_enabled', true);
ui.showMainWindow();
info('enabled');
var savedVariant = localStorage.getItem('assist_variant');
if (savedVariant != null) {
ui.variantRadio(savedVariant).prop('checked', true);
analyzer.setVariant(ui.variant());
}
scan();
wazeapi.model.events.register('mergeend', map, scan);
} else {
localStorage.setItem('assist_enabled', false);
ui.hideMainWindow();
info('disabled');
wazeapi.model.events.unregister('mergeend', map, scan);
}
});
ui.variantRadio().click(function () {
localStorage.setItem('assist_variant', this.value);
analyzer.setVariant(ui.variant());
ui.scanAreaBtn().click();
});
if (localStorage.getItem('assist_enabled') == 'true') {
ui.enableCheckbox().click();
}
ui.fixallBtn().click(function () {
ui.fixallBtn().hide();
ui.clearfixedBtn().hide();
ui.scanAreaBtn().hide();
wazeapi.model.events.unregister('mergeend', map, scan);
setTimeout(function () {
analyzer.fixAll(function (id) {
ui.setUnresolvedErrorNum(analyzer.unresolvedErrorNum());
ui.setFixedErrorNum(analyzer.fixedErrorNum());
ui.moveToFixedList(id);
}, function () {
ui.fixallBtn().show();
ui.clearfixedBtn().show();
ui.scanAreaBtn().show();
wazeapi.model.events.register('mergeend', map, scan);
});
}, 0);
});
ui.clearfixedBtn().click(function () {
ui.fixedList().empty();
});
ui.scanAreaBtn().click(function () {
ui.fixedList().empty();
ui.unresolvedList().empty();
analyzer.reset();
ui.setUnresolvedErrorNum(0);
ui.setFixedErrorNum(0);
fullscan();
});
ui.addCustomRuleBtn().click(function () {
ui.customRuleDialog('Add', {
oldname: '',
newname: ''
}).done(function (response) {
rules.push(response.oldname, response.newname);
});
});
ui.editCustomRuleBtn().click(function () {
var id = ui.selectedCustomRule();
if (id >= 0) {
ui.customRuleDialog('Edit', {
oldname: rules.get(id).oldname,
newname: rules.get(id).newname
}).done(function (response) {
rules.update(id, response.oldname, response.newname);
});
} else {
alert('Правило не выбрано');
}
});
ui.delCustomRuleBtn().click(function () {
var id = ui.selectedCustomRule();
if (id >= 0) {
rules.remove(id);
} else {
alert('Правило не выбрано');
}
});
window.assist = this;
}
this.renameCity = action.renameCity;
};
function waitForWaze(done) {
var wazeapi = getWazeApi();
// Does not get jQuery.ui
// Relies on WME Toolbox plugin
if (wazeapi === null || !jQuery.ui) {
console.log("WME ASSIST: waiting for Waze");
setTimeout(function () {
waitForWaze(done);
}, 500);
return;
}
done(wazeapi);
}
function getByAttr(obj, attr) {
return obj.getByAttributes().filter(function (e) {
for (var key in attr) {
if (e.attributes[key] != attr[key]) {
return false;
}
}
return true;
});
}
waitForWaze(function (wazeapi) {
var app = new Application(wazeapi);
app.start();
});
}
run_wme_assist();