decidim-core 0.30.0.rc1 → 0.30.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/decidim/orders_helper.rb +2 -1
  3. data/app/helpers/decidim/participatory_space_helpers.rb +1 -1
  4. data/app/jobs/decidim/hide_child_resources_job.rb +24 -0
  5. data/app/models/decidim/report.rb +1 -1
  6. data/app/packs/src/decidim/map/provider/here.js +1 -1
  7. data/app/packs/stylesheets/decidim/_hashtags.scss +5 -0
  8. data/app/packs/stylesheets/decidim/application.scss +1 -0
  9. data/app/views/decidim/shared/_orders.html.erb +2 -2
  10. data/config/locales/ca.yml +3 -1
  11. data/config/locales/cs.yml +8 -0
  12. data/config/locales/de.yml +11 -0
  13. data/config/locales/en.yml +2 -0
  14. data/config/locales/es-MX.yml +2 -0
  15. data/config/locales/es-PY.yml +2 -0
  16. data/config/locales/es.yml +3 -1
  17. data/config/locales/eu.yml +9 -8
  18. data/config/locales/fi-plain.yml +9 -1
  19. data/config/locales/fi.yml +10 -2
  20. data/config/locales/fr-CA.yml +2 -0
  21. data/config/locales/fr.yml +2 -0
  22. data/config/locales/ro-RO.yml +24 -0
  23. data/config/locales/sv.yml +35 -0
  24. data/lib/decidim/core/test/shared_examples/reports_examples.rb +51 -0
  25. data/lib/decidim/core/test/shared_examples/social_share_examples.rb +21 -0
  26. data/lib/decidim/core/version.rb +1 -1
  27. data/lib/decidim/maintenance/import_models/category.rb +40 -8
  28. data/lib/decidim/maintenance/taxonomy_importer.rb +10 -0
  29. data/lib/decidim/map/provider/dynamic_map/here.rb +1 -40
  30. data/lib/decidim/moderation_tools.rb +15 -2
  31. data/lib/tasks/decidim_taxonomies.rake +6 -1
  32. data/lib/tasks/upgrade/clean_hidden_resources.rake +33 -0
  33. data/lib/tasks/upgrade/migrations.rake +4 -1
  34. metadata +9 -7
  35. data/app/packs/src/decidim/vendor/leaflet-tilelayer-here.js +0 -212
@@ -59,6 +59,56 @@ shared_examples "higher user role hides" do
59
59
  end
60
60
  end
61
61
 
62
+ shared_examples "higher user role hides resource with comments" do
63
+ context "and the admin hides a resource with comments" do
64
+ let!(:comments) { create_list(:comment, 2, body: "Dummy comment", commentable: reportable, author: user) }
65
+
66
+ before do
67
+ login_as user, scope: :user
68
+ Decidim::Ai::SpamDetection.create_reporting_user!
69
+ end
70
+ around do |example|
71
+ previous = Capybara.raise_server_errors
72
+
73
+ # Disabling server errors to that we can test page not found error.
74
+ Capybara.raise_server_errors = false
75
+ example.run
76
+ Capybara.raise_server_errors = previous
77
+ end
78
+
79
+ it "hides the resource" do
80
+ visit decidim.search_path
81
+ expect(page).to have_content(translated(comments.first.body))
82
+ expect(page).to have_content(translated(comments.second.body))
83
+
84
+ visit reportable_path
85
+
86
+ expect(page).to have_content(translated(comments.first.body))
87
+ expect(page).to have_content(translated(comments.second.body))
88
+
89
+ find("#dropdown-trigger-resource-#{reportable.id}").click
90
+ expect(page).to have_css(%(button[data-dialog-open="flagModal"]))
91
+ find(%(button[data-dialog-open="flagModal"])).click
92
+ expect(page).to have_css(".flag-modal", visible: :visible)
93
+
94
+ within ".flag-modal" do
95
+ find(:css, "input[name='report[hide]']").set(true)
96
+ click_on "Hide"
97
+ end
98
+
99
+ perform_enqueued_jobs
100
+
101
+ expect(reportable.reload).to be_hidden
102
+ expect(comments.first.reload).to be_hidden
103
+ expect(comments.second.reload).to be_hidden
104
+
105
+ visit decidim.search_path
106
+ expect(page).to have_no_content(translated(comments.first.body))
107
+ expect(page).to have_no_content(translated(comments.second.body))
108
+ end
109
+ end
110
+ end
111
+
62
112
  shared_examples "higher user role does not have hide" do
63
113
  context "and the admin reports" do
64
114
  before do
@@ -124,6 +174,7 @@ shared_examples "reports by user type" do
124
174
  let!(:user) { create(:user, :admin, :confirmed, organization:) }
125
175
  include_examples "higher user role reports"
126
176
  include_examples "higher user role hides"
177
+ include_examples "higher user role hides resource with comments"
127
178
  end
128
179
  context "When reporting user is process admin" do
129
180
  let!(:user) { create(:process_admin, :confirmed, participatory_process:) }
@@ -23,3 +23,24 @@ shared_examples "a social share meta tag" do |image|
23
23
  expect(find('meta[property="og:image"]', visible: false)[:content]).to end_with(image)
24
24
  end
25
25
  end
26
+
27
+ shared_examples "a social share widget" do
28
+ it "has the social share button" do
29
+ visit_resource
30
+
31
+ expect(page).to have_css('button[data-dialog-open="socialShare"]')
32
+ end
33
+
34
+ it "lists all the expected social share providers" do
35
+ visit_resource
36
+ click_on "Share"
37
+
38
+ within "#socialShare" do
39
+ expect(page).to have_css('a[title="Share to X"]')
40
+ expect(page).to have_css('a[title="Share to Facebook"]')
41
+ expect(page).to have_css('a[title="Share to WhatsApp"]')
42
+ expect(page).to have_css('a[title="Share to Telegram"]')
43
+ expect(page).to have_css(".share-modal__input")
44
+ end
45
+ end
46
+ end
@@ -4,7 +4,7 @@ module Decidim
4
4
  # This holds the decidim-core version.
5
5
  module Core
6
6
  def self.version
7
- "0.30.0.rc1"
7
+ "0.30.0.rc2"
8
8
  end
9
9
  end
10
10
  end
@@ -24,6 +24,14 @@ module Decidim
24
24
  false
25
25
  end
26
26
 
27
+ def full_name
28
+ return @full_name if defined?(@full_name)
29
+
30
+ @full_name = name.dup
31
+ @full_name[I18n.locale.to_s] = "#{parent.name[I18n.locale.to_s]} > #{@full_name[I18n.locale.to_s]}" if parent && parent.parent_id
32
+ @full_name
33
+ end
34
+
27
35
  def resources
28
36
  categorizations.filter_map do |categorization|
29
37
  next if invalid_categorization?(categorization)
@@ -36,16 +44,34 @@ module Decidim
36
44
  {
37
45
  name:,
38
46
  origin: to_global_id.to_s,
39
- children: subcategories.to_h do |subcategory|
40
- [
41
- subcategory.name[I18n.locale.to_s],
42
- subcategory.taxonomies
43
- ]
44
- end,
47
+ children: sub_taxonomy_children,
45
48
  resources:
46
49
  }
47
50
  end
48
51
 
52
+ # original categories are allowed one level more than the current taxonomies
53
+ def sub_taxonomy_children
54
+ subcategories.each_with_object({}) do |subcategory, hash|
55
+ hash[subcategory.name[I18n.locale.to_s]] = {
56
+ name: subcategory.name,
57
+ origin: subcategory.to_global_id.to_s,
58
+ resources: subcategory.resources,
59
+ children: {}
60
+ }
61
+
62
+ next unless subcategory.subcategories.any?
63
+
64
+ subcategory.subcategories.each do |last_category|
65
+ hash[last_category.full_name[I18n.locale.to_s]] = {
66
+ name: last_category.full_name,
67
+ origin: last_category.to_global_id.to_s,
68
+ resources: last_category.resources,
69
+ children: {}
70
+ }
71
+ end
72
+ end
73
+ end
74
+
49
75
  def self.children_taxonomies(participatory_space)
50
76
  Category.where(participatory_space:, parent_id: nil).to_h do |category|
51
77
  [
@@ -92,8 +118,14 @@ module Decidim
92
118
  internal_name: name,
93
119
  items: Category.where(participatory_space:).map do |category|
94
120
  names = [name]
95
- names << category.parent.name[I18n.locale.to_s] if category.parent
96
- names << category.name[I18n.locale.to_s]
121
+ if category.parent
122
+ names << if category.parent.parent
123
+ category.parent.parent.name[I18n.locale.to_s]
124
+ else
125
+ category.parent.name[I18n.locale.to_s]
126
+ end
127
+ end
128
+ names << category.full_name[I18n.locale.to_s]
97
129
  names
98
130
  end,
99
131
  components:
@@ -38,6 +38,8 @@ module Decidim
38
38
  item["children"].each do |child_name, child|
39
39
  import_taxonomy_item(taxonomy, child_name, child)
40
40
  end
41
+ rescue ActiveRecord::RecordInvalid => e
42
+ abort "Error importing taxonomy item #{name} with parent #{parent.name} (#{e.message})"
41
43
  end
42
44
 
43
45
  def apply_taxonomy_to_resource(object_id, taxonomy)
@@ -61,6 +63,8 @@ module Decidim
61
63
  end
62
64
  end
63
65
 
66
+ # rubocop:disable Metrics/CyclomaticComplexity
67
+ # rubocop:disable Metrics/PerceivedComplexity
64
68
  def import_filter(root, data)
65
69
  filter = find_taxonomy_filter!(root, data)
66
70
 
@@ -91,7 +95,11 @@ module Decidim
91
95
  result[:failed_components] << component_id
92
96
  end
93
97
  end
98
+ rescue ActiveRecord::RecordInvalid => e
99
+ abort "Error importing filter #{data} for root taxonomy #{root.name} (#{e.message})"
94
100
  end
101
+ # rubocop:enable Metrics/CyclomaticComplexity
102
+ # rubocop:enable Metrics/PerceivedComplexity
95
103
 
96
104
  def find_taxonomy(association, name)
97
105
  association.find_by("name->>? = ?", organization.default_locale, name)
@@ -105,6 +113,8 @@ module Decidim
105
113
  association.create!(name: { organization.default_locale => name }, organization:) do
106
114
  result[:taxonomies_created] << name
107
115
  end
116
+ rescue ActiveRecord::RecordInvalid => e
117
+ abort "Error creating taxonomy #{name} with parent #{association.new.parent.name[organization.default_locale]} (#{e.message})"
108
118
  end
109
119
 
110
120
  def find_taxonomy_filter!(root_taxonomy, data)
@@ -49,46 +49,7 @@ module Decidim
49
49
  private
50
50
 
51
51
  def language_code
52
- primary = I18n.locale.to_s
53
- secondary = primary.split("-")[0]
54
- available_language_codes[primary] || available_language_codes[secondary] || ""
55
- end
56
-
57
- def available_language_codes
58
- @available_language_codes ||= {
59
- "ar" => "ara", # Arabic
60
- "eu" => "baq", # Basque
61
- "ca" => "cat", # Catalan
62
- "zh" => "chi", # Chinese (simplified)
63
- # "" => "cht", # Chinese (traditional)
64
- "cs" => "cze", # Czech
65
- "da" => "dan", # Danish
66
- "nl" => "dut", # Dutch
67
- "en" => "eng", # English
68
- "fi" => "fin", # Finnish
69
- "fr" => "fre", # French
70
- "de" => "ger", # German
71
- "ga" => "gle", # Gaelic
72
- "el" => "gre", # Greek
73
- "he" => "heb", # Hebrew
74
- "hi" => "hin", # Hindi
75
- "id" => "ind", # Indonesian
76
- "it" => "ita", # Italian
77
- "no" => "nor", # Norwegian
78
- "fa" => "per", # Persian
79
- "pl" => "pol", # Polish
80
- "pt" => "por", # Portuguese
81
- "ru" => "rus", # Russian
82
- "si" => "sin", # Sinhalese
83
- "es" => "spa", # Spanish
84
- "sv" => "swe", # Swedish
85
- "th" => "tha", # Thai
86
- "tr" => "tur", # Turkish
87
- "uk" => "ukr", # Ukrainian
88
- "ur" => "urd", # Urdu
89
- "vi" => "vie", # Vietnamese
90
- "cy" => "wel" # Welsh
91
- }
52
+ I18n.locale.to_s
92
53
  end
93
54
  end
94
55
  end
@@ -58,6 +58,8 @@ module Decidim
58
58
 
59
59
  # Public: Broadcasts a notification to the author of the resource that has been hidden
60
60
  def send_notification_to_author
61
+ return if affected_users.blank?
62
+
61
63
  data = {
62
64
  event: "decidim.events.reports.resource_hidden",
63
65
  event_class: Decidim::ResourceHiddenEvent,
@@ -65,13 +67,12 @@ module Decidim
65
67
  extra: {
66
68
  report_reasons:
67
69
  },
68
- affected_users: @reportable.try(:authors) || [@reportable.try(:normalized_author)]
70
+ affected_users:
69
71
  }
70
72
 
71
73
  Decidim::EventsManager.publish(**data)
72
74
  end
73
75
 
74
- # Public: hides the resource
75
76
  def hide_with_admin_log!
76
77
  Decidim.traceability.perform_action!(
77
78
  "hide",
@@ -91,10 +92,22 @@ module Decidim
91
92
  @reportable.moderation.update!(hidden_at: Time.current)
92
93
  @reportable.try(:touch)
93
94
  end
95
+
96
+ if @reportable.is_a?(Decidim::Comments::Commentable)
97
+ @reportable.comment_threads.each do |comment|
98
+ Decidim::HideChildResourcesJob.perform_later(comment, @current_user.id)
99
+ end
100
+ end
101
+
102
+ send_notification_to_author
94
103
  end
95
104
 
96
105
  private
97
106
 
107
+ def affected_users
108
+ @affected_users ||= (@reportable.try(:authors) || [@reportable.try(:normalized_author)]).select { |author| author.is_a?(Decidim::User) }
109
+ end
110
+
98
111
  def report_reasons
99
112
  @reportable.moderation.reports.pluck(:reason).uniq
100
113
  end
@@ -82,6 +82,7 @@ namespace :decidim do
82
82
  task :import_all_plans, [] => :environment do |_task, _args|
83
83
  Rails.root.glob("tmp/taxonomies/*_plan.json").each do |file|
84
84
  log.info "Importing plan from #{file}"
85
+ Rake::Task["decidim:taxonomies:import_plan"].reenable
85
86
  Rake::Task["decidim:taxonomies:import_plan"].invoke(file)
86
87
  end
87
88
  end
@@ -93,7 +94,10 @@ namespace :decidim do
93
94
 
94
95
  data = JSON.parse(File.read(file))
95
96
  taxonomies = data["taxonomy_map"]
96
- abort "No taxonomies found in the file" unless taxonomies && taxonomies&.any?
97
+ unless taxonomies && taxonomies&.any?
98
+ log.warn "No metric (categories) taxonomies found in the file"
99
+ next
100
+ end
97
101
 
98
102
  total = taxonomies.count
99
103
  taxonomies.each_with_index do |(id, object_id), index|
@@ -112,6 +116,7 @@ namespace :decidim do
112
116
  task :update_all_metrics, [] => :environment do |_task, _args|
113
117
  Rails.root.glob("tmp/taxonomies/*_result.json").each do |file|
114
118
  log.info "Processing metrics from #{file}"
119
+ Rake::Task["decidim:taxonomies:update_metrics"].reenable
115
120
  Rake::Task["decidim:taxonomies:update_metrics"].invoke(file)
116
121
  end
117
122
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :decidim do
4
+ namespace :upgrade do
5
+ namespace :clean do
6
+ desc "Removes all related resources from hidden resource"
7
+ task hidden_resources: :environment do
8
+ logger.info("Removing child resources for hidden parents...")
9
+ Decidim::Moderation.hidden.find_each do |moderation_for_hidden_resource|
10
+ reportable = moderation_for_hidden_resource.reportable
11
+
12
+ current_user = if Decidim.module_installed?(:ai)
13
+ reportable.organization.users.find_by!(email: Decidim::Ai::SpamDetection.reporting_user_email)
14
+ else
15
+ reportable.organization.admins.first
16
+ end
17
+
18
+ tool = Decidim::ModerationTools.new(reportable, current_user)
19
+ tool.hide!
20
+ rescue NameError => e
21
+ log_error "Could not hide child resources for reportable id #{moderation_for_hidden_resource.id} because: #{e.message}"
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def log_error(msg)
28
+ puts msg
29
+ Rails.logger.error(msg)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -81,7 +81,10 @@ namespace :decidim do
81
81
 
82
82
  logger.warn("[Patch migration] Replacing content of #{File.basename(target_file)}")
83
83
 
84
- File.binwrite(target_file, new_source)
84
+ additional_comment = "# This file has been modified by `decidim upgrade:migrations` task on #{Time.now.utc}\n"
85
+ source = new_source.gsub(inserted_comment, "#{inserted_comment}#{additional_comment}")
86
+
87
+ File.binwrite(target_file, source)
85
88
  end
86
89
 
87
90
  def logger
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: decidim-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0.rc1
4
+ version: 0.30.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep Jaume Rey Peroy
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2025-02-18 00:00:00.000000000 Z
13
+ date: 2025-03-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: concurrent-ruby
@@ -780,28 +780,28 @@ dependencies:
780
780
  requirements:
781
781
  - - '='
782
782
  - !ruby/object:Gem::Version
783
- version: 0.30.0.rc1
783
+ version: 0.30.0.rc2
784
784
  type: :development
785
785
  prerelease: false
786
786
  version_requirements: !ruby/object:Gem::Requirement
787
787
  requirements:
788
788
  - - '='
789
789
  - !ruby/object:Gem::Version
790
- version: 0.30.0.rc1
790
+ version: 0.30.0.rc2
791
791
  - !ruby/object:Gem::Dependency
792
792
  name: decidim-dev
793
793
  requirement: !ruby/object:Gem::Requirement
794
794
  requirements:
795
795
  - - '='
796
796
  - !ruby/object:Gem::Version
797
- version: 0.30.0.rc1
797
+ version: 0.30.0.rc2
798
798
  type: :development
799
799
  prerelease: false
800
800
  version_requirements: !ruby/object:Gem::Requirement
801
801
  requirements:
802
802
  - - '='
803
803
  - !ruby/object:Gem::Version
804
- version: 0.30.0.rc1
804
+ version: 0.30.0.rc2
805
805
  description: Adds core features so other engines can hook into the framework.
806
806
  email:
807
807
  - josepjaume@gmail.com
@@ -1416,6 +1416,7 @@ files:
1416
1416
  - app/jobs/decidim/export_participatory_space_job.rb
1417
1417
  - app/jobs/decidim/find_and_update_descendants_job.rb
1418
1418
  - app/jobs/decidim/hide_all_created_by_author_job.rb
1419
+ - app/jobs/decidim/hide_child_resources_job.rb
1419
1420
  - app/jobs/decidim/machine_translation_fields_job.rb
1420
1421
  - app/jobs/decidim/machine_translation_resource_job.rb
1421
1422
  - app/jobs/decidim/machine_translation_save_job.rb
@@ -1732,7 +1733,6 @@ files:
1732
1733
  - app/packs/src/decidim/utilities/dom.js
1733
1734
  - app/packs/src/decidim/utilities/text.js
1734
1735
  - app/packs/src/decidim/vendor/jquery-tmpl.js
1735
- - app/packs/src/decidim/vendor/leaflet-tilelayer-here.js
1736
1736
  - app/packs/src/decidim/vendor/tribute.js
1737
1737
  - app/packs/src/decidim/vizzs/areachart.js
1738
1738
  - app/packs/src/decidim/vizzs/index.js
@@ -1759,6 +1759,7 @@ files:
1759
1759
  - app/packs/stylesheets/decidim/_fonts.scss
1760
1760
  - app/packs/stylesheets/decidim/_footer.scss
1761
1761
  - app/packs/stylesheets/decidim/_forms.scss
1762
+ - app/packs/stylesheets/decidim/_hashtags.scss
1762
1763
  - app/packs/stylesheets/decidim/_header.scss
1763
1764
  - app/packs/stylesheets/decidim/_hero.scss
1764
1765
  - app/packs/stylesheets/decidim/_home.scss
@@ -3080,6 +3081,7 @@ files:
3080
3081
  - lib/tasks/decidim_taxonomies.rake
3081
3082
  - lib/tasks/decidim_webpacker_tasks.rake
3082
3083
  - lib/tasks/upgrade/clean.rake
3084
+ - lib/tasks/upgrade/clean_hidden_resources.rake
3083
3085
  - lib/tasks/upgrade/decidim_active_storage_migration_tasks.rake
3084
3086
  - lib/tasks/upgrade/decidim_attachments.rake
3085
3087
  - lib/tasks/upgrade/decidim_content_blocks_tasks.rake
@@ -1,212 +0,0 @@
1
- /* eslint-disable */
2
-
3
- // 🍂class TileLayer.HERE
4
- // Tile layer for HERE maps tiles.
5
- L.TileLayer.HERE = L.TileLayer.extend({
6
-
7
- options: {
8
- subdomains: '1234',
9
- minZoom: 2,
10
- maxZoom: 18,
11
-
12
- // 🍂option scheme: String = 'normal.day'
13
- // The "map scheme", as documented in the HERE API.
14
- scheme: 'normal.day',
15
-
16
- // 🍂option resource: String = 'maptile'
17
- // The "map resource", as documented in the HERE API.
18
- resource: 'maptile',
19
-
20
- // 🍂option mapId: String = 'newest'
21
- // Version of the map tiles to be used, or a hash of an unique map
22
- mapId: 'newest',
23
-
24
- // 🍂option format: String = 'png8'
25
- // Image format to be used (`png8`, `png`, or `jpg`)
26
- format: 'png8',
27
-
28
- // 🍂option appId: String = ''
29
- // Required option. The `app_id` provided as part of the HERE credentials
30
- appId: '',
31
-
32
- // 🍂option appCode: String = ''
33
- // Required option. The `app_code` provided as part of the HERE credentials
34
- appCode: '',
35
-
36
- // 🍂option useCIT: boolean = false
37
- // Whether to use the CIT when loading the here-maptiles
38
- useCIT: false,
39
-
40
- // 🍂option useHTTPS: boolean = true
41
- // Whether to use HTTPS when loading the here-maptiles
42
- useHTTPS: true,
43
-
44
- // 🍂option language: String = ''
45
- // The language of the descriptions on the maps that are loaded
46
- language: '',
47
-
48
- // 🍂option language: String = ''
49
- // The second language of the descriptions on the maps that are loaded
50
- language2: '',
51
- },
52
-
53
-
54
- initialize: function initialize(options) {
55
- options = L.setOptions(this, options);
56
-
57
- // Decide if this scheme uses the aerial servers or the basemap servers
58
- var schemeStart = options.scheme.split('.')[0];
59
- options.tileResolution = 256;
60
-
61
- // {Base URL}{Path}/{resource (tile type)}/{map id}/{scheme}/{zoom}/{column}/{row}/{size}/{format}
62
- // ?apiKey={YOUR_API_KEY}
63
- // &{param}={value}
64
-
65
- var params = [
66
- 'apiKey=' + encodeURIComponent(options.apiKey)
67
- ];
68
- // Fallback to old app_id,app_code if no apiKey passed
69
- if(!options.apiKey) {
70
- params = [
71
- 'app_id=' + encodeURIComponent(options.appId),
72
- 'app_code=' + encodeURIComponent(options.appCode),
73
- ];
74
- }
75
- if(options.language) {
76
- params.push('lg=' + encodeURIComponent(options.language));
77
- }
78
- if(options.language2) {
79
- params.push('lg2=' + encodeURIComponent(options.language2));
80
- }
81
- var urlQuery = '?' + params.join('&');
82
-
83
- var path = '/maptile/2.1/{resource}/{mapId}/{scheme}/{z}/{x}/{y}/{tileResolution}/{format}' + urlQuery;
84
- var attributionPath = '/maptile/2.1/copyright/{mapId}?apiKey={apiKey}';
85
-
86
- var baseUrl = 'maps.ls.hereapi.com';
87
-
88
- // Old style with apiId/apiCode for compatibility
89
- if(!options.apiKey) {
90
- // make sure the CIT-url can be used
91
- baseUrl = 'maps' + (options.useCIT ? '.cit' : '') + '.api.here.com';
92
- attributionPath = '/maptile/2.1/copyright/{mapId}?app_id={appId}&app_code={appCode}';
93
- }
94
-
95
- var tileServer = 'base.' + baseUrl;
96
- if (schemeStart == 'satellite' || schemeStart == 'terrain' || schemeStart == 'hybrid') {
97
- tileServer = 'aerial.' + baseUrl;
98
- }
99
- if (options.scheme.indexOf('.traffic.') !== -1) {
100
- tileServer = 'traffic' + baseUrl;
101
- }
102
-
103
- var protocol = 'http' + (options.useHTTPS ? 's' : '');
104
- var tileUrl = protocol + '://{s}.' + tileServer + path;
105
-
106
- this._attributionUrl = L.Util.template(protocol + '://1.' + tileServer + attributionPath, this.options);
107
-
108
- L.TileLayer.prototype.initialize.call(this, tileUrl, options);
109
-
110
- this._attributionText = '';
111
-
112
- },
113
-
114
- onAdd: function onAdd(map) {
115
- L.TileLayer.prototype.onAdd.call(this, map);
116
-
117
- if (!this._attributionBBoxes) {
118
- this._fetchAttributionBBoxes();
119
- }
120
- },
121
-
122
- onRemove: function onRemove(map) {
123
- //
124
- // Remove the attribution text, and clear the cached text so it will be recalculated
125
- // if/when we are shown again.
126
- //
127
- this._map.attributionControl.removeAttribution(this._attributionText);
128
- this._attributionText = '';
129
-
130
- this._map.off('moveend zoomend resetview', this._findCopyrightBBox, this);
131
-
132
- //
133
- // Call the prototype last, once we have tidied up our own changes
134
- //
135
- L.TileLayer.prototype.onRemove.call(this, map);
136
- },
137
-
138
- _fetchAttributionBBoxes: function _onMapMove() {
139
- var xmlhttp = new XMLHttpRequest();
140
- xmlhttp.onreadystatechange = L.bind(function(){
141
- if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
142
- this._parseAttributionBBoxes(JSON.parse(xmlhttp.responseText));
143
- }
144
- }, this);
145
- xmlhttp.open("GET", this._attributionUrl, true);
146
- xmlhttp.send();
147
- },
148
-
149
- _parseAttributionBBoxes: function _parseAttributionBBoxes(json) {
150
- if (!this._map) { return; }
151
- var providers = json[this.options.scheme.split('.')[0]] || json.normal;
152
- for (var i=0; i<providers.length; i++) {
153
- if (providers[i].boxes) {
154
- for (var j=0; j<providers[i].boxes.length; j++) {
155
- var box = providers[i].boxes[j];
156
- providers[i].boxes[j] = L.latLngBounds( [ [box[0], box[1]], [box[2], box[3]] ]);
157
- }
158
- }
159
- }
160
-
161
- this._map.on('moveend zoomend resetview', this._findCopyrightBBox, this);
162
-
163
- this._attributionProviders = providers;
164
-
165
- this._findCopyrightBBox();
166
- },
167
-
168
- _findCopyrightBBox: function _findCopyrightBBox() {
169
- if (!this._map) { return; }
170
- var providers = this._attributionProviders;
171
- var visibleProviders = [];
172
- var zoom = this._map.getZoom();
173
- var visibleBounds = this._map.getBounds();
174
-
175
- for (var i=0; i<providers.length; i++) {
176
- if (providers[i].minLevel <= zoom && providers[i].maxLevel >= zoom) {
177
-
178
- if (!providers[i].boxes) {
179
- // No boxes = attribution always visible
180
- visibleProviders.push(providers[i]);
181
- } else {
182
- for (var j=0; j<providers[i].boxes.length; j++) {
183
- var box = providers[i].boxes[j];
184
- if (visibleBounds.intersects(box)) {
185
- visibleProviders.push(providers[i]);
186
- break;
187
- }
188
- }
189
- }
190
- }
191
- }
192
-
193
- var attributions = ['<a href="https://legal.here.com/en-gb/terms" target="_blank" rel="noopener noreferrer">HERE maps</a>'];
194
- for (var i=0; i<visibleProviders.length; i++) {
195
- var provider = visibleProviders[i];
196
- attributions.push('<abbr title="' + provider.alt + '">' + provider.label + '</abbr>');
197
- }
198
-
199
- var attributionText = '© ' + attributions.join(', ') + '. ';
200
-
201
- if (attributionText !== this._attributionText) {
202
- this._map.attributionControl.removeAttribution(this._attributionText);
203
- this._map.attributionControl.addAttribution(this._attributionText = attributionText);
204
- }
205
- },
206
-
207
- });
208
-
209
-
210
- L.tileLayer.here = function(opts){
211
- return new L.TileLayer.HERE(opts);
212
- }