您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Creates point with same address
当前为
// ==UserScript== // @name WME Address Point Helper // @author Andrei Pavlenko // @version 1.12.5 // @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor.*$/ // @exclude https://www.waze.com/user/*editor/* // @exclude https://www.waze.com/*/user/*editor/* // @grant none // @description Creates point with same address // @namespace https://gf.qytechs.cn/users/182795 // @require https://gf.qytechs.cn/scripts/24851-wazewrap/code/WazeWrap.js // @require https://gf.qytechs.cn/scripts/16071-wme-keyboard-shortcuts/code/WME%20Keyboard%20Shortcuts.js // ==/UserScript== var locale var settings = { addNavigationPoint: false, inheritNavigationPoint: false, autoSetHNToName: false, noDuplicates: false } var translations = { 'en': { createPoint: 'Create POI', createResidential: 'Create residential', addEntryPoint: 'Add entry point', inheritEntryPoint: 'Inherit parent\'s landmark entry point', copyHNToName: 'Copy house number into name', noDuplicates: 'Do not create duplicates' }, 'uk': { createPoint: 'Створити POI точку', createResidential: 'Створити АТ', addEntryPoint: 'Додавати точку в\'їзду', inheritEntryPoint: 'Наслідувати точку в\'їзду батьківського ПОІ', copyHNToName: 'Копіювати номер будинку в назву', noDuplicates: 'Не створювати дублікатів' }, 'ru': { createPoint: 'Создать POI точку', createResidential: 'Создать АТ', addEntryPoint: 'Создавать точку въезда', inheritEntryPoint: 'Наследовать точку въезда родительского ПОИ', copyHNToName: 'Копировать номер дома в название', noDuplicates: 'Не создавать дубликатов' } } var hnValidators = { 'Ukraine': hn => { let valid = false try { valid = /^\d+[А-ЯЇІЄ]{0,3}$/i.test(hn) } catch (e) { /* Do nothing */ } return valid }, 'default': hn => { return /.+/.test(hn) } }; (function () { setTimeout(init, 1000) })() function init () { try { if ( document.getElementById('sidebarContent') !== null && document.getElementById('user-tabs') !== null && WazeWrap.Ready ) { initLocale() createScriptTab() initSettings() registerKeyboardShortcuts() registerEventListeners() } else { setTimeout(init, 1000) return } } catch (err) { setTimeout(1000, init) return } } function createScriptTab () { const html = ` <div id="sidepanel-aph"> <p>WME Address Point Helper 📍</p> <div class="controls-container"><input type="checkbox" id="aph-add-navigation-point"><label for="aph-add-navigation-point">${translate('addEntryPoint')}</label></div> <div class="controls-container"><input type="checkbox" id="aph-inherit-navigation-point"><label for="aph-inherit-navigation-point">${translate('inheritEntryPoint')}</label></div> <div class="controls-container"><input type="checkbox" id="aph-set-name"><label for="aph-set-name">${translate('copyHNToName')}</label></div> <div class="controls-container"><input type="checkbox" id="aph-no-duplicates"><label for="aph-no-duplicates">${translate('noDuplicates')}</label></div> </div> ` new WazeWrap.Interface.Tab('APH📍', html) var APHAddNavigationPoint = $('#aph-add-navigation-point') var APHInheritNavigationPoint = $('#aph-inherit-navigation-point') var APHSetName = $('#aph-set-name') var APHNoDuplicates = $('#aph-no-duplicates') APHAddNavigationPoint.change(() => { settings.addNavigationPoint = APHAddNavigationPoint.prop('checked') }) APHInheritNavigationPoint.change(() => { settings.inheritNavigationPoint = APHInheritNavigationPoint.prop('checked') }) APHSetName.change(() => { settings.autoSetHNToName = APHSetName.prop('checked') }) APHNoDuplicates.change(() => { settings.noDuplicates = APHNoDuplicates.prop('checked') }) } function initSettings () { var savedSettings = localStorage.getItem('aph-settings') if (savedSettings) { settings = JSON.parse(savedSettings) } setChecked('aph-add-navigation-point', settings.addNavigationPoint) setChecked('aph-inherit-navigation-point', settings.inheritNavigationPoint) setChecked('aph-set-name', settings.autoSetHNToName) setChecked('aph-no-duplicates', settings.noDuplicates) window.addEventListener('beforeunload', saveSettings) } function initLocale () { locale = I18n.currentLocale() } function translate (keyword) { let translation = translations[locale] || translations['en'] return translation[keyword] || translations['en'][keyword] || 'Unknown' } function saveSettings () { if (localStorage) { localStorage.setItem('aph-settings', JSON.stringify(settings)) } } function isValidSelection () { if (!W.selectionManager.hasSelectedFeatures()) return false if (W.selectionManager.getSelectedFeatures().length !== 1) return false if (W.selectionManager.getSelectedFeatures()[0].model.type !== 'venue') return false return true } function showButtons () { if (!isValidSelection()) return var buttons = ` <div id="aph-buttons" style="margin-top: 8px"> <div class="btn-toolbar"> <input type="button" id="aph-create-point" class="aph-btn btn btn-default" value="${translate('createPoint')}"> <input type="button" id="aph-create-residential" class="aph-btn btn btn-default" value="${translate('createResidential')}"> </div> </div> ` if (!$('#aph-buttons').length) { $('#venue-edit-general .address-edit').append(buttons) $('#aph-create-point').click(createPoint) $('#aph-create-residential').click(createResidential) } const valid = validateSelectedPoiHN() $('#aph-create-point').prop('disabled', !valid.validForPoint) $('#aph-create-residential').prop('disabled', !valid.vadlidForResidential) } function validateSelectedPoiHN () { let result = { validForPoint: false, vadlidForResidential: false } let country = W.model.getTopCountry().name let validator = hnValidators[country] || hnValidators['default'] let selectedPoiHN = getSelectedLandmarkAddress().attributes.houseNumber result.vadlidForResidential = validator(selectedPoiHN) result.validForPoint = /\d+/.test(selectedPoiHN) return result } function createResidential () { isValidSelection() && createPoint({ isResidential: true }) } function createPoint ({ isResidential = false } = {}) { if (!isValidSelection()) return var LandmarkFeature = require('Waze/Feature/Vector/Landmark') var AddLandmarkAction = require('Waze/Action/AddLandmark') var UpdateObjectAction = require('Waze/Action/UpdateObject') var UpdateFeatureAddressAction = require('Waze/Action/UpdateFeatureAddress') var NewPoint = new LandmarkFeature() var { lat, lon } = getPointCoordinates() var address = getSelectedLandmarkAddress() var lockRank = getPointLockRank() var pointGeometry = new OpenLayers.Geometry.Point(lon, lat) NewPoint.geometry = pointGeometry NewPoint.attributes.categories.push('OTHER') NewPoint.attributes.lockRank = lockRank NewPoint.attributes.residential = isResidential if (settings.addNavigationPoint) { var entryPoint, parentEntryPoint = W.selectionManager.getSelectedFeatures()[0].model.attributes.entryExitPoints[0] if (settings.inheritNavigationPoint && parentEntryPoint !== undefined) { entryPoint = new NavigationPoint(parentEntryPoint.getPoint()) } else { entryPoint = new NavigationPoint(pointGeometry.clone()) } NewPoint.attributes.entryExitPoints.push(entryPoint) } if (!!address.attributes.houseNumber) { NewPoint.attributes.name = address.attributes.houseNumber NewPoint.attributes.houseNumber = address.attributes.houseNumber } var newAddressAttributes = { streetName: address.getStreetName(), emptyStreet: false, cityName: address.getCityName(), emptyCity: false, stateID: address.getState().getID(), countryID: address.getCountry().getID(), } if (settings.noDuplicates && hasDuplicate(NewPoint, newAddressAttributes)) { console.log('This point already exists.') return } W.selectionManager.unselectAll() var addedLandmark = new AddLandmarkAction(NewPoint) W.model.actionManager.add(addedLandmark) W.model.actionManager.add(new UpdateFeatureAddressAction(NewPoint, newAddressAttributes)) if (!!address.attributes.houseNumber) { W.model.actionManager.add(new UpdateObjectAction(NewPoint, {houseNumber: address.attributes.houseNumber})); } W.selectionManager.setSelectedModels([addedLandmark.venue]) } function hasDuplicate (poi, addr) { const venues = W.model.venues.objects for (let key in venues) { if (!venues.hasOwnProperty(key)) continue const currentVenue = venues[key] const currentAddress = currentVenue.getAddress() let equalNames = true if (!!currentVenue.attributes.name && !!poi.attributes.name) { if (currentVenue.attributes.name != poi.attributes.name) { equalNames = false } } if ( equalNames && poi.attributes.houseNumber == currentVenue.attributes.houseNumber && poi.attributes.residential == currentVenue.attributes.residential && addr.streetName == currentAddress.getStreetName() && addr.cityName == currentAddress.getCityName() && addr.countryID == currentAddress.getCountry().getID() ) return true } return false } // Высчитываем координаты центра выбраного лэндмарка function getPointCoordinates () { const selectedLandmarkGeometry = W.selectionManager.getSelectedFeatures()[0].geometry var coords if (/polygon/i.test(selectedLandmarkGeometry.id)) { var polygonCenteroid = selectedLandmarkGeometry.components[0].getCentroid() var geometryComponents = selectedLandmarkGeometry.components[0].components var flatComponentsCoords = [] geometryComponents.forEach(c => flatComponentsCoords.push(c.x, c.y)) var interiorPoint = getInteriorPointOfArray( flatComponentsCoords, 2, [polygonCenteroid.x, polygonCenteroid.y] ) coords = { lon: interiorPoint[0], lat: interiorPoint[1] } } else { coords = { lon: selectedLandmarkGeometry.x, lat: selectedLandmarkGeometry.y } } coords = addRandomOffsetToCoords(coords) return coords } function addRandomOffsetToCoords (coords) { var { lat, lon } = coords lat += Math.random() * 2 + 1 lon += Math.random() * 2 + 1 return { lat, lon } } function getSelectedLandmarkAddress () { const selectedLandmark = W.selectionManager.getSelectedFeatures()[0] const address = selectedLandmark.model.getAddress() return address } function getPointLockRank () { const selectedLandmark = W.selectionManager.getSelectedFeatures()[0] const userRank = W.loginManager.user.rank const parentFeatureLockRank = selectedLandmark.model.getLockRank() if (userRank >= parentFeatureLockRank) { return parentFeatureLockRank } else if (userRank >= 1) { return 1 } else { return 0 } } function setChecked (checkboxId, checked) { $('#' + checkboxId).prop('checked', checked) } function registerKeyboardShortcuts () { const scriptName = 'AddressPointHelper' WMEKSRegisterKeyboardShortcut(scriptName, 'Address Point Helper', 'APHCreatePoint', translate('createPoint'), createPoint, '-1') WMEKSRegisterKeyboardShortcut(scriptName, 'Address Point Helper', 'APHCreateResidential', translate('createResidential'), createResidential, '-1') WMEKSLoadKeyboardShortcuts(scriptName) window.addEventListener('beforeunload', function () { WMEKSSaveKeyboardShortcuts(scriptName) }, false) } function registerEventListeners () { let UpdateObjectAction = require('Waze/Action/UpdateObject') W.model.actionManager.events.register('afteraction', null, action => { // Задаем номер дома в название, если нужно. Пока не нашел более лаконичного способа определить что // произошло именно изменение адреса. Можно тестить регуляркой поле _description, но будут проблемы с // нюансами содержания этого поля на разных языках if (settings.autoSetHNToName) { try { let subAction = action.action.subActions[0] let houseNumber = subAction.attributes.houseNumber let feature = subAction.feature if (feature.attributes.categories.includes('OTHER') && feature.attributes.name === '') { W.model.actionManager.add(new UpdateObjectAction(feature, { name: houseNumber })) } } catch (e) { /* Do nothing */ } } }) W.selectionManager.events.register('selectionchanged', null, showButtons) W.model.actionManager.events.register('afteraction', null, showButtons) setTimeout(wrapSelectionHandlers, 2000) } function wrapSelectionHandlers () { // POI Helper trows error and breaks event handlers execution // Wrap each handler in try/catch to fix this let wrappedHandlers = W.selectionManager.events.listeners.selectionchanged.map(listener => { return { obj: listener.obj, func: function () { try { listener.func.apply(this, arguments) } catch (error) { console.error(error) } } } }) W.selectionManager.events.listeners.selectionchanged = wrappedHandlers } /* * https://github.com/openlayers/openlayers */ function getInteriorPointOfArray (flatCoordinates, stride, flatCenters) { let offset = 0 let flatCentersOffset = 0 let ends = [flatCoordinates.length] let i, ii, x, x1, x2, y1, y2 const y = flatCenters[flatCentersOffset + 1] const intersections = [] // Calculate intersections with the horizontal line for (let r = 0, rr = ends.length; r < rr; ++r) { const end = ends[r] x1 = flatCoordinates[end - stride] y1 = flatCoordinates[end - stride + 1] for (i = offset; i < end; i += stride) { x2 = flatCoordinates[i] y2 = flatCoordinates[i + 1] if ((y <= y1 && y2 <= y) || (y1 <= y && y <= y2)) { x = (y - y1) / (y2 - y1) * (x2 - x1) + x1 intersections.push(x) } x1 = x2 y1 = y2 } } // Find the longest segment of the horizontal line that has its center point // inside the linear ring. let pointX = NaN let maxSegmentLength = -Infinity intersections.sort(numberSafeCompareFunction) x1 = intersections[0] for (i = 1, ii = intersections.length; i < ii; ++i) { x2 = intersections[i] const segmentLength = Math.abs(x2 - x1) if (segmentLength > maxSegmentLength) { x = (x1 + x2) / 2 if (linearRingsContainsXY(flatCoordinates, offset, ends, stride, x, y)) { pointX = x maxSegmentLength = segmentLength } } x1 = x2 } if (isNaN(pointX)) { // There is no horizontal line that has its center point inside the linear // ring. Use the center of the the linear ring's extent. pointX = flatCenters[flatCentersOffset] } return [pointX, y, maxSegmentLength] } function numberSafeCompareFunction (a, b) { return a > b ? 1 : a < b ? -1 : 0 } function linearRingContainsXY (flatCoordinates, offset, end, stride, x, y) { // http://geomalgorithms.com/a03-_inclusion.html // Copyright 2000 softSurfer, 2012 Dan Sunday // This code may be freely used and modified for any purpose // providing that this copyright notice is included with it. // SoftSurfer makes no warranty for this code, and cannot be held // liable for any real or imagined damage resulting from its use. // Users of this code must verify correctness for their application. let wn = 0 let x1 = flatCoordinates[end - stride] let y1 = flatCoordinates[end - stride + 1] for (; offset < end; offset += stride) { const x2 = flatCoordinates[offset] const y2 = flatCoordinates[offset + 1] if (y1 <= y) { if (y2 > y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) > 0) { wn++ } } else if (y2 <= y && ((x2 - x1) * (y - y1)) - ((x - x1) * (y2 - y1)) < 0) { wn-- } x1 = x2 y1 = y2 } return wn !== 0 } function linearRingsContainsXY (flatCoordinates, offset, ends, stride, x, y) { if (ends.length === 0) { return false } if (!linearRingContainsXY(flatCoordinates, offset, ends[0], stride, x, y)) { return false } for (let i = 1, ii = ends.length; i < ii; ++i) { if (linearRingContainsXY(flatCoordinates, ends[i - 1], ends[i], stride, x, y)) { return false } } return true } /* **************************************** */ var _createClass = function () { function a (b, c) {for (var f, d = 0; d < c.length; d++) f = c[d], f.enumerable = f.enumerable || !1, f.configurable = !0, 'value' in f && (f.writable = !0), Object.defineProperty(b, f.key, f)} return function (b, c, d) {return c && a(b.prototype, c), d && a(b, d), b} }() function _classCallCheck (a, b) {if (!(a instanceof b)) throw new TypeError('Cannot call a class as a function')} var NavigationPoint = function () { function a (b) {_classCallCheck(this, a), this._point = b.clone(), this._entry = !0, this._exit = !0, this._isPrimary = !0, this._name = ''} return _createClass(a, [{ key: 'with', value: function _with () { var b = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {} return null == b.point && (b.point = this.toJSON().point), new this.constructor((this.toJSON().point, b.point)) } }, { key: 'getPoint', value: function getPoint () {return this._point.clone()} }, { key: 'getEntry', value: function getEntry () {return this._entry} }, { key: 'getExit', value: function getExit () {return this._exit} }, { key: 'getName', value: function getName () {return this._name} }, { key: 'isPrimary', value: function isPrimary () {return this._isPrimary} }, { key: 'toJSON', value: function toJSON () { return { point: this._point, entry: this._entry, exit: this._exit, primary: this._isPrimary, name: this._name } } }, { key: 'clone', value: function clone () {return this.with()} }]), a }()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址