From 981d9750bab9f9dd548103d3ab0f783cca68adf0 Mon Sep 17 00:00:00 2001 From: Kyle Hensel Date: Tue, 15 Jul 2025 18:29:16 +1000 Subject: [PATCH] use JOSM/tag2link to linkify tag values --- .github/workflows/lint.yml | 6 ++++++ .github/workflows/tests.yml | 4 ++-- app/helpers/browse_tags_helper.rb | 11 ++++++++++- config/initializers/tag2link.rb | 15 +++++++++++++++ package.json | 3 ++- test/helpers/browse_tags_helper_test.rb | 4 ++++ yarn.lock | 5 +++++ 7 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 config/initializers/tag2link.rb diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 092de794d..4dab6535e 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -95,6 +95,12 @@ jobs: run: | cp config/github.database.yml config/database.yml cp config/example.storage.yml config/storage.yml + - name: Cache node modules + uses: actions/setup-node@v4 + with: + cache: yarn + - name: Install node modules + run: bundle exec bin/yarn install - name: Setup database run: | sudo systemctl start postgresql diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cc06c48c0..10aab58fa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -43,6 +43,8 @@ jobs: cp config/github.database.yml config/database.yml cp config/example.storage.yml config/storage.yml touch config/settings.local.yml + - name: Install node modules + run: bundle exec bin/yarn install - name: Populate database run: | sed -f script/normalise-structure db/structure.sql > db/structure.expected @@ -50,8 +52,6 @@ jobs: bundle exec rails db:migrate sed -f script/normalise-structure db/structure.sql > db/structure.actual diff -uw db/structure.expected db/structure.actual - - name: Install node modules - run: bundle exec bin/yarn install - name: Export javascript strings run: bundle exec i18n export - name: Compile assets diff --git a/app/helpers/browse_tags_helper.rb b/app/helpers/browse_tags_helper.rb index bb79d9eaf..fc6df2506 100644 --- a/app/helpers/browse_tags_helper.rb +++ b/app/helpers/browse_tags_helper.rb @@ -40,7 +40,7 @@ module BrowseTagsHelper end svg + colour_value else - safe_join(value.split(";", -1).map { |x| linkify(h(x)) }, ";") + safe_join(value.split(";", -1).map { |x| tag2link_link(key, x) || linkify(h(x)) }, ";") end end @@ -127,6 +127,15 @@ module BrowseTagsHelper nil end + def tag2link_link(key, value) + # skip if it's a full URL + return nil if %r{^https?://}.match?(value) + + return nil unless TAG2LINK[key] + + link_to(h(value), TAG2LINK[key].gsub("$1", value), :rel => "nofollow") + end + def email_link(key, value) # Avoid converting conditional tags into emails, since EMAIL_REGEXP is quite permissive return nil unless %w[email contact:email].include? key diff --git a/config/initializers/tag2link.rb b/config/initializers/tag2link.rb new file mode 100644 index 000000000..418cc2a54 --- /dev/null +++ b/config/initializers/tag2link.rb @@ -0,0 +1,15 @@ +# A map of each OSM key to its formatter URL. For example: +# { "ref:vatin" => "https://example.com/$1" } +# The JSON data is an array with duplicate entries, which is not efficient for lookups. +# So, convert it to a hash and only keep the item with the best rank. +TAG2LINK = JSON.parse(Rails.root.join("node_modules/tag2link/index.json").read) + # exclude deprecated and third-party URLs + .reject { |item| item["rank"] == "deprecated" || item["source"] == "wikidata:P3303" } + .group_by { |item| item["key"] } + .transform_keys { |key| key.sub(/^Key:/, "") } + # move preferred to the start of the array + .transform_values { |items| items.sort_by { |item| item["rank"] == "preferred" ? 0 : 1 }.uniq { |item| item["url"] } } + # exclude any that are ambiguous, i.e. the best and second-best have the same rank + .reject { |_key, value| value[1] && value[0]["rank"] == value[1]["rank"] } + # keep only the best match + .transform_values { |items| items[0]["url"] } diff --git a/package.json b/package.json index 46cae3ae6..94acaf58c 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "leaflet": "^1.8.0", "leaflet.locatecontrol": "^0.84.1", "make-plural": "^7.4.0", - "osm-community-index": "^5.2.0" + "osm-community-index": "^5.2.0", + "tag2link": "^2025.7.21" }, "devDependencies": { "@stylistic/eslint-plugin-js": "^4.0.0", diff --git a/test/helpers/browse_tags_helper_test.rb b/test/helpers/browse_tags_helper_test.rb index 16351510a..4de7094fc 100644 --- a/test/helpers/browse_tags_helper_test.rb +++ b/test/helpers/browse_tags_helper_test.rb @@ -53,6 +53,10 @@ class BrowseTagsHelperTest < ActionView::TestCase html = format_value("wikimedia_commons", "File:Test.jpg") assert_dom_equal "File:Test.jpg", html + html = format_value("mapillary", "123;https://example.com") + assert_dom_equal "123;https://example.com", + html + html = format_value("colour", "#f00") dom = Rails::Dom::Testing.html_document_fragment.parse html assert_select dom, "svg>rect>@fill", "#f00" diff --git a/yarn.lock b/yarn.lock index d12437667..2e858560c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -652,6 +652,11 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +tag2link@^2025.7.21: + version "2025.7.21" + resolved "https://registry.yarnpkg.com/tag2link/-/tag2link-2025.7.21.tgz#7548bb665b3a90768ae10b8d3656492ff2142623" + integrity sha512-shSQq9ZJKHV9an9echuMFLyxJ/N9Zy89sJ5fKotaJbLg+wtsxzlwJUIe35QsmY/KE2pVlPs3sX/U06GJBIOogA== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" -- 2.39.5