From b298fb73164916c68b04c9681c7b82762f1721d3 Mon Sep 17 00:00:00 2001 From: Amaia Castro Date: Fri, 10 Feb 2017 10:42:21 +0100 Subject: [PATCH 1/5] Show annotation context in annotation page Only works with quotes within the same html node for now --- app/models/legislation/annotation.rb | 11 +++++- .../legislation/annotations/show.html.erb | 2 +- ...add_context_for_legislation_annotations.rb | 5 +++ db/schema.rb | 3 +- .../annotations_controller_spec.rb | 28 ++++++------- spec/factories.rb | 26 +++++++++---- .../legislation/draft_versions_spec.rb | 39 ++++++++++--------- 7 files changed, 71 insertions(+), 43 deletions(-) create mode 100644 db/migrate/20170210083026_add_context_for_legislation_annotations.rb diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb index f9f612abd..096565404 100644 --- a/app/models/legislation/annotation.rb +++ b/app/models/legislation/annotation.rb @@ -14,7 +14,7 @@ class Legislation::Annotation < ActiveRecord::Base validates :draft_version, presence: true validates :author, presence: true - before_save :store_range + before_save :store_range, :store_context after_create :create_first_comment def store_range @@ -24,6 +24,15 @@ class Legislation::Annotation < ActiveRecord::Base self.range_end_offset = ranges.first["endOffset"] end + def store_context + html = draft_version.body_html + doc = Nokogiri::HTML(html) + selector = "/#{range_start}" + text = doc.xpath(selector).text + text[quote] = "#{quote}" + self.context = text + end + def create_first_comment comments.create(body: self.text, user: self.author) end diff --git a/app/views/legislation/annotations/show.html.erb b/app/views/legislation/annotations/show.html.erb index 25d56e99c..8529ea2af 100644 --- a/app/views/legislation/annotations/show.html.erb +++ b/app/views/legislation/annotations/show.html.erb @@ -15,7 +15,7 @@
- <%= @annotation.quote %> + <%= @annotation.context.html_safe || @annotation.quote %>
diff --git a/db/migrate/20170210083026_add_context_for_legislation_annotations.rb b/db/migrate/20170210083026_add_context_for_legislation_annotations.rb new file mode 100644 index 000000000..8bf19a64c --- /dev/null +++ b/db/migrate/20170210083026_add_context_for_legislation_annotations.rb @@ -0,0 +1,5 @@ +class AddContextForLegislationAnnotations < ActiveRecord::Migration + def change + add_column :legislation_annotations, :context, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index a847e445e..278ba8e60 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170125093101) do +ActiveRecord::Schema.define(version: 20170210083026) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -339,6 +339,7 @@ ActiveRecord::Schema.define(version: 20170125093101) do t.integer "range_start_offset" t.string "range_end" t.integer "range_end_offset" + t.text "context" end add_index "legislation_annotations", ["author_id"], name: "index_legislation_annotations_on_author_id", using: :btree diff --git a/spec/controllers/legislation/annotations_controller_spec.rb b/spec/controllers/legislation/annotations_controller_spec.rb index b8be3c630..5b1fd3d39 100644 --- a/spec/controllers/legislation/annotations_controller_spec.rb +++ b/spec/controllers/legislation/annotations_controller_spec.rb @@ -16,8 +16,8 @@ describe Legislation::AnnotationsController do post :create, process_id: @process.id, draft_version_id: @draft_version.id, legislation_annotation: { - "quote"=>"Ordenación Territorial", - "ranges"=>[{"start"=>"/p[1]", "startOffset"=>1, "end"=>"/p[1]", "endOffset"=>3}], + "quote"=>"ipsum", + "ranges"=>[{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}], "text": "una anotacion" } expect(Ahoy::Event.where(name: :legislation_annotation_created).count).to eq 1 @@ -30,8 +30,8 @@ describe Legislation::AnnotationsController do post :create, process_id: @process.id, draft_version_id: @final_version.id, legislation_annotation: { - "quote"=>"Ordenación Territorial", - "ranges"=>[{"start"=>"/p[1]", "startOffset"=>1, "end"=>"/p[1]", "endOffset"=>3}], + "quote"=>"ipsum", + "ranges"=>[{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}], "text": "una anotacion" } @@ -45,8 +45,8 @@ describe Legislation::AnnotationsController do xhr :post, :create, process_id: @process.id, draft_version_id: @draft_version.id, legislation_annotation: { - "quote"=>"Ordenación Territorial", - "ranges"=>[{"start"=>"/p[1]", "startOffset"=>1, "end"=>"/p[1]", "endOffset"=>3}], + "quote"=>"ipsum", + "ranges"=>[{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}], "text": "una anotacion" } end.to change { @draft_version.annotations.count }.by(1) @@ -60,8 +60,8 @@ describe Legislation::AnnotationsController do xhr :post, :create, process_id: @process.id, draft_version_id: @draft_version.id, legislation_annotation: { - "quote"=>"Ordenación Territorial", - "ranges"=>[{"start"=>"/p[1]", "startOffset"=>1, "end"=>"/p[1]", "endOffset"=>3}], + "quote"=>"ipsum", + "ranges"=>[{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}], "text": "una anotacion" } end.to_not change { @draft_version.annotations.count } @@ -74,8 +74,8 @@ describe Legislation::AnnotationsController do xhr :post, :create, process_id: @process.id, draft_version_id: @draft_version.id, legislation_annotation: { - "quote"=>"Ordenación Territorial", - "ranges"=>[{"start"=>"/p[1]", "startOffset"=>1, "end"=>"/p[1]", "endOffset"=>3}].to_json, + "quote"=>"ipsum", + "ranges"=>[{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}].to_json, "text": "una anotacion" } end.to change { @draft_version.annotations.count }.by(1) @@ -83,16 +83,16 @@ describe Legislation::AnnotationsController do it 'should create a new comment on an existing annotation when range is the same' do annotation = create(:legislation_annotation, draft_version: @draft_version, text: "my annotation", - ranges: [{"start"=>"/p[1]", "startOffset"=>5, "end"=>"/p[1]", "endOffset"=>10}], - range_start: "/p[1]", range_start_offset: 5, range_end: "/p[1]", range_end_offset: 10) + ranges: [{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}], + range_start: "/p[1]", range_start_offset: 6, range_end: "/p[1]", range_end_offset: 11) sign_in @user expect do xhr :post, :create, process_id: @process.id, draft_version_id: @draft_version.id, legislation_annotation: { - "quote"=>"Ordenación Territorial", - "ranges"=>[{"start"=>"/p[1]", "startOffset"=>5, "end"=>"/p[1]", "endOffset"=>10}], + "quote"=>"ipsum", + "ranges"=>[{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}], "text": "una anotacion" } end.to_not change { @draft_version.annotations.count } diff --git a/spec/factories.rb b/spec/factories.rb index 5c08ae1d9..437df8ea6 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -505,7 +505,19 @@ FactoryGirl.define do changelog "What changed in this version" status "draft" final_version false - body "Body of the legislation text" + body <<-LOREM_IPSUM +Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. + +Expetenda tincidunt in sed, ex partem placerat sea, porro commodo ex eam. His putant aeterno interesset at. Usu ea mundi tincidunt, omnium virtute aliquando ius ex. Ea aperiri sententiae duo. Usu nullam dolorum quaestio ei, sit vidit facilisis ea. Per ne impedit iracundia neglegentur. Consetetur neglegentur eum ut, vis animal legimus inimicus id. + +His audiam deserunt in, eum ubique voluptatibus te. In reque dicta usu. Ne rebum dissentiet eam, vim omnis deseruisse id. Ullum deleniti vituperata at quo, insolens complectitur te eos, ea pri dico munere propriae. Vel ferri facilis ut, qui paulo ridens praesent ad. Possim alterum qui cu. Accusamus consulatu ius te, cu decore soleat appareat usu. + +Est ei erat mucius quaeque. Ei his quas phaedrum, efficiantur mediocritatem ne sed, hinc oratio blandit ei sed. Blandit gloriatur eam et. Brute noluisse per et, verear disputando neglegentur at quo. Sea quem legere ei, unum soluta ne duo. Ludus complectitur quo te, ut vide autem homero pro. + +Vis id minim dicant sensibus. Pri aliquip conclusionemque ad, ad malis evertitur torquatos his. Has ei solum harum reprimique, id illum saperet tractatos his. Ei omnis soleat antiopam quo. Ad augue inani postulant mel, mel ea qualisque forensibus. + +Lorem salutandi eu mea, eam in soleat iriure assentior. Tamquam lobortis id qui. Ea sanctus democritum mei, per eu alterum electram adversarium. Ea vix probo dicta iuvaret, posse epicurei suavitate eam an, nam et vidit menandri. Ut his accusata petentium. +LOREM_IPSUM trait :published do status "published" @@ -520,12 +532,12 @@ FactoryGirl.define do draft_version factory: :legislation_draft_version author factory: :user quote "ipsum" - text "Loremp ipsum dolor" - ranges [{"start"=>"/div[1]", "startOffset"=>5, "end"=>"/div[1]", "endOffset"=>10}] - range_start "/div[1]" - range_start_offset 5 - range_end "/div[1]" - range_end_offset 10 + text "a comment" + ranges [{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}] + range_start "/p[1]" + range_start_offset 6 + range_end "/p[1]" + range_end_offset 11 end factory :legislation_question, class: 'Legislation::Question' do diff --git a/spec/features/legislation/draft_versions_spec.rb b/spec/features/legislation/draft_versions_spec.rb index fc6a1b88f..5b2192d46 100644 --- a/spec/features/legislation/draft_versions_spec.rb +++ b/spec/features/legislation/draft_versions_spec.rb @@ -137,7 +137,7 @@ feature 'Legislation Draft Versions' do scenario 'Visit as anonymous' do logout - draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) + draft_version = create(:legislation_draft_version, :published) visit legislation_process_draft_version_path(draft_version.process, draft_version) @@ -148,7 +148,7 @@ feature 'Legislation Draft Versions' do end scenario 'Create' do - draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) + draft_version = create(:legislation_draft_version, :published) visit legislation_process_draft_version_path(draft_version.process, draft_version) @@ -172,7 +172,7 @@ feature 'Legislation Draft Versions' do end scenario 'View annotations and comments' do - draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) + draft_version = create(:legislation_draft_version, :published) annotation1 = create(:legislation_annotation, draft_version: draft_version, text: "my annotation", ranges: [{"start"=>"/p[1]", "startOffset"=>5, "end"=>"/p[1]", "endOffset"=>10}]) annotation2 = create(:legislation_annotation, draft_version: draft_version, text: "my other annotation", ranges: [{"start"=>"/p[1]", "startOffset"=>12, "end"=>"/p[1]", "endOffset"=>19}]) @@ -187,8 +187,8 @@ feature 'Legislation Draft Versions' do end scenario "Publish new comment for an annotation from comments box" do - draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) - annotation = create(:legislation_annotation, draft_version: draft_version, text: "my annotation", ranges: [{"start"=>"/p[1]", "startOffset"=>5, "end"=>"/p[1]", "endOffset"=>10}]) + draft_version = create(:legislation_draft_version, :published) + annotation = create(:legislation_annotation, draft_version: draft_version, text: "my annotation", ranges: [{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}]) visit legislation_process_draft_version_path(draft_version.process, draft_version) @@ -205,25 +205,25 @@ feature 'Legislation Draft Versions' do context "Annotations page" do background do - @draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) - @annotation_1 = create(:legislation_annotation, draft_version: @draft_version, text: "my annotation", quote: "first quote") - @annotation_2 = create(:legislation_annotation, draft_version: @draft_version, text: "my other annotation", quote: "second quote") + @draft_version = create(:legislation_draft_version, :published) + @annotation_1 = create(:legislation_annotation, draft_version: @draft_version, text: "my annotation", quote: "ipsum", ranges: [{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}]) + @annotation_2 = create(:legislation_annotation, draft_version: @draft_version, text: "my other annotation", quote: "audiam", ranges: [{"start"=>"/p[3]", "startOffset"=>6, "end"=>"/p[3]", "endOffset"=>11}]) end scenario "See all annotations for a draft version" do visit legislation_process_draft_version_annotations_path(@draft_version.process, @draft_version) - expect(page).to have_content "first quote" - expect(page).to have_content "second quote" + expect(page).to have_content "ipsum" + expect(page).to have_content "audiam" end context "switching versions" do background do @process = create(:legislation_process) - @draft_version_1 = create(:legislation_draft_version, :published, process: @process, title: "Version 1", body: Faker::Lorem.paragraph) - @annotation_1 = create(:legislation_annotation, draft_version: @draft_version_1, text: "annotation for version 1", quote: "quote for version 1") - @draft_version_2 = create(:legislation_draft_version, :published, process: @process, title: "Version 2", body: Faker::Lorem.paragraph) - @annotation_1 = create(:legislation_annotation, draft_version: @draft_version_2, text: "annotation for version 2", quote: "quote for version 2") + @draft_version_1 = create(:legislation_draft_version, :published, process: @process, title: "Version 1", body: "Text with quote for version 1") + @annotation_1 = create(:legislation_annotation, draft_version: @draft_version_1, text: "annotation for version 1", quote: "quote for version 1", ranges: [{"start"=>"/p[1]", "startOffset"=>11, "end"=>"/p[1]", "endOffset"=>30}]) + @draft_version_2 = create(:legislation_draft_version, :published, process: @process, title: "Version 2", body: "Text with quote for version 2") + @annotation_1 = create(:legislation_annotation, draft_version: @draft_version_2, text: "annotation for version 2", quote: "quote for version 2", ranges: [{"start"=>"/p[1]", "startOffset"=>11, "end"=>"/p[1]", "endOffset"=>30}]) end scenario "without js" do @@ -251,17 +251,18 @@ feature 'Legislation Draft Versions' do context "Annotation comments page" do background do - @draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph) - @annotation_1 = create(:legislation_annotation, draft_version: @draft_version, text: "my annotation", quote: "first quote") - @annotation_2 = create(:legislation_annotation, draft_version: @draft_version, text: "my other annotation", quote: "second quote") + @draft_version = create(:legislation_draft_version, :published) + @annotation_1 = create(:legislation_annotation, draft_version: @draft_version, text: "my annotation", quote: "ipsum", ranges: [{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[1]", "endOffset"=>11}]) + @annotation_2 = create(:legislation_annotation, draft_version: @draft_version, text: "my other annotation", quote: "audiam", ranges: [{"start"=>"/p[3]", "startOffset"=>6, "end"=>"/p[3]", "endOffset"=>11}]) end scenario "See one annotation with replies for a draft version" do visit legislation_process_draft_version_annotation_path(@draft_version.process, @draft_version, @annotation_2) - expect(page).to_not have_content "first quote" - expect(page).to have_content "second quote" + expect(page).to_not have_content "ipsum" expect(page).to_not have_content "my annotation" + + expect(page).to have_content "audiam" expect(page).to have_content "my other annotation" end end From 4cb1bba5a76bb785e70f93784141b37963fe59dd Mon Sep 17 00:00:00 2001 From: Amaia Castro Date: Fri, 10 Feb 2017 15:55:03 +0100 Subject: [PATCH 2/5] Use range offsets instead of quote for substitution --- app/models/legislation/annotation.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb index 096565404..aa1f2ed80 100644 --- a/app/models/legislation/annotation.rb +++ b/app/models/legislation/annotation.rb @@ -29,7 +29,7 @@ class Legislation::Annotation < ActiveRecord::Base doc = Nokogiri::HTML(html) selector = "/#{range_start}" text = doc.xpath(selector).text - text[quote] = "#{quote}" + text[range_start_offset .. range_end_offset-1] = "#{quote}" self.context = text end From 6737d6afddd2f5aa760d1ede13ec30a304356922 Mon Sep 17 00:00:00 2001 From: Amaia Castro Date: Fri, 10 Feb 2017 18:16:09 +0100 Subject: [PATCH 3/5] Make annotation context work with multi-node annotations --- app/models/legislation/annotation.rb | 32 +++++++++++++-- spec/models/legislation/annotation_spec.rb | 47 ++++++++++++++++++++++ 2 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 spec/models/legislation/annotation_spec.rb diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb index aa1f2ed80..a4e76dea4 100644 --- a/app/models/legislation/annotation.rb +++ b/app/models/legislation/annotation.rb @@ -27,10 +27,34 @@ class Legislation::Annotation < ActiveRecord::Base def store_context html = draft_version.body_html doc = Nokogiri::HTML(html) - selector = "/#{range_start}" - text = doc.xpath(selector).text - text[range_start_offset .. range_end_offset-1] = "#{quote}" - self.context = text + + selector_start = "/html/body/#{range_start}" + el_start = doc.at_xpath(selector_start) + + selector_end = "/html/body/#{range_end}" + el_end = doc.at_xpath(selector_end) + + context_text = "" + + if el_start.path == el_end.path + context_text = el_start.text + quote_range = range_start_offset .. range_end_offset-1 + else + i = el_start + + while i.path != el_end.path + context_text << i.text + i = i.next_element + end + + context_text << el_end.text + + end_of_range = (el_end.text.size - range_end_offset) * -1 + quote_range = range_start_offset .. end_of_range-1 + end + + context_text[quote_range] = "#{quote}" + self.context = context_text end def create_first_comment diff --git a/spec/models/legislation/annotation_spec.rb b/spec/models/legislation/annotation_spec.rb new file mode 100644 index 000000000..4cf5c6f59 --- /dev/null +++ b/spec/models/legislation/annotation_spec.rb @@ -0,0 +1,47 @@ +require 'rails_helper' + +RSpec.describe Legislation::Annotation, type: :model do + let(:draft_version) { create(:legislation_draft_version) } + let(:annotation) { create(:legislation_annotation, draft_version: draft_version) } + + it "should be valid" do + expect(draft_version).to be_valid + expect(annotation).to be_valid + end + + it "calculates the context for multinode annotations" do + annotation = create(:legislation_annotation, + draft_version: draft_version, + quote: "ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. + +Expetenda tincidunt in sed, ex partem placerat sea, porro commodo ex eam. His putant aeterno interesset at. Usu ea mundi tincidunt, omnium virtute aliquando ius ex. Ea aperiri sententiae duo. Usu nullam dolorum quaestio ei, sit vidit facilisis ea. Per ne impedit iracundia neglegentur. Consetetur neglegentur eum ut, vis animal legimus inimicus id. + +His audiam", + ranges: [{"start"=>"/p[1]", "startOffset"=>6, "end"=>"/p[3]", "endOffset"=>11}] + ) + + expect(annotation.context).to eq("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\n\nExpetenda tincidunt in sed, ex partem placerat sea, porro commodo ex eam. His putant aeterno interesset at. Usu ea mundi tincidunt, omnium virtute aliquando ius ex. Ea aperiri sententiae duo. Usu nullam dolorum quaestio ei, sit vidit facilisis ea. Per ne impedit iracundia neglegentur. Consetetur neglegentur eum ut, vis animal legimus inimicus id.\n\nHis audiamdeserunt in, eum ubique voluptatibus te. In reque dicta usu. Ne rebum dissentiet eam, vim omnis deseruisse id. Ullum deleniti vituperata at quo, insolens complectitur te eos, ea pri dico munere propriae. Vel ferri facilis ut, qui paulo ridens praesent ad. Possim alterum qui cu. Accusamus consulatu ius te, cu decore soleat appareat usu.") + end + + it "calculates the context for multinode annotations 2" do + annotation = create(:legislation_annotation, + draft_version: draft_version, + quote: "Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\r\n\r\nExpetenda tincidunt in sed, ex partem placerat sea, porro commodo ex eam. His putant aeterno interesset at. Usu ea mundi tincidunt, omnium virtute aliquando ius ex. Ea aperiri sententiae duo", + ranges: [{"start"=>"/p[1]", "startOffset"=>273, "end"=>"/p[2]", "endOffset"=>190}] + ) + + expect(annotation.context).to eq("Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.\r\n\r\nExpetenda tincidunt in sed, ex partem placerat sea, porro commodo ex eam. His putant aeterno interesset at. Usu ea mundi tincidunt, omnium virtute aliquando ius ex. Ea aperiri sententiae duo. Usu nullam dolorum quaestio ei, sit vidit facilisis ea. Per ne impedit iracundia neglegentur. Consetetur neglegentur eum ut, vis animal legimus inimicus id.") + end + + it "calculates the context for multinode annotations 3" do + draft_version = create(:legislation_draft_version, body: "The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software.\r\n\r\nThe licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.\r\n\r\nWhen we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.\r\n\r\nDevelopers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software.\r\n\r\nA secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public.\r\n\r\nThe GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version.\r\n\r\nAn older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license.") + + annotation = create(:legislation_annotation, + draft_version: draft_version, + quote: "By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.\r\n\r\nWhen we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish)", + ranges: [{"start"=>"/p[2]", "startOffset"=>127, "end"=>"/p[3]", "endOffset"=>223}] + ) + + expect(annotation.context).to eq("The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.\r\n\r\nWhen we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.") + end +end From 8e741a6b4fbd238238d4979bd7cc6ff78d919dd3 Mon Sep 17 00:00:00 2001 From: Amaia Castro Date: Mon, 13 Feb 2017 09:53:36 +0100 Subject: [PATCH 4/5] Refactor and use first node start + quote + last node end for the context --- app/models/legislation/annotation.rb | 37 ++++++------------- .../legislation/annotations/show.html.erb | 2 +- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb index a4e76dea4..52e784dcf 100644 --- a/app/models/legislation/annotation.rb +++ b/app/models/legislation/annotation.rb @@ -25,36 +25,23 @@ class Legislation::Annotation < ActiveRecord::Base end def store_context - html = draft_version.body_html - doc = Nokogiri::HTML(html) + begin + html = draft_version.body_html + doc = Nokogiri::HTML(html) - selector_start = "/html/body/#{range_start}" - el_start = doc.at_xpath(selector_start) + selector_start = "/html/body/#{range_start}" + el_start = doc.at_xpath(selector_start) - selector_end = "/html/body/#{range_end}" - el_end = doc.at_xpath(selector_end) + selector_end = "/html/body/#{range_end}" + el_end = doc.at_xpath(selector_end) - context_text = "" + remainder_el_start = el_start.text[0 .. range_start_offset-1] + remainder_el_end = el_end.text[range_end_offset .. -1] - if el_start.path == el_end.path - context_text = el_start.text - quote_range = range_start_offset .. range_end_offset-1 - else - i = el_start - - while i.path != el_end.path - context_text << i.text - i = i.next_element - end - - context_text << el_end.text - - end_of_range = (el_end.text.size - range_end_offset) * -1 - quote_range = range_start_offset .. end_of_range-1 + self.context = "#{remainder_el_start}#{quote}#{remainder_el_end}" + rescue + "#{quote}" end - - context_text[quote_range] = "#{quote}" - self.context = context_text end def create_first_comment diff --git a/app/views/legislation/annotations/show.html.erb b/app/views/legislation/annotations/show.html.erb index 8529ea2af..20f5d1a98 100644 --- a/app/views/legislation/annotations/show.html.erb +++ b/app/views/legislation/annotations/show.html.erb @@ -15,7 +15,7 @@
- <%= @annotation.context.html_safe || @annotation.quote %> + <%= @annotation.context.try(:html_safe).presence || @annotation.quote %>
From 58b9135c711d8abd7fc9b7f29113c3e5bb76af86 Mon Sep 17 00:00:00 2001 From: Amaia Castro Date: Mon, 13 Feb 2017 11:18:33 +0100 Subject: [PATCH 5/5] Add context to annotation in index view --- app/models/legislation/annotation.rb | 2 +- app/views/legislation/annotations/index.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb index 52e784dcf..05eaad6f5 100644 --- a/app/models/legislation/annotation.rb +++ b/app/models/legislation/annotation.rb @@ -35,7 +35,7 @@ class Legislation::Annotation < ActiveRecord::Base selector_end = "/html/body/#{range_end}" el_end = doc.at_xpath(selector_end) - remainder_el_start = el_start.text[0 .. range_start_offset-1] + remainder_el_start = el_start.text[0 .. range_start_offset-1] unless range_start_offset.zero? remainder_el_end = el_end.text[range_end_offset .. -1] self.context = "#{remainder_el_start}#{quote}#{remainder_el_end}" diff --git a/app/views/legislation/annotations/index.html.erb b/app/views/legislation/annotations/index.html.erb index 87efc3614..d7b1ae3fe 100644 --- a/app/views/legislation/annotations/index.html.erb +++ b/app/views/legislation/annotations/index.html.erb @@ -20,7 +20,7 @@ <% end %>
- <%= annotation.quote %> + <%= annotation.context.try(:html_safe).presence || annotation.quote %>
<%= link_to legislation_process_draft_version_annotation_path(@process, @draft_version, annotation) do %> <%= t('.comments_count', count: annotation.comments_count) %>