diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 01e74400a..b9d072f5a 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -49,8 +49,9 @@
//= require markdown-it
//= require markdown_editor
//= require cocoon
-//= require allegations
//= require legislation
+//= require legislation_allegations
+//= require legislation_annotatable
//= require custom
var initialize_modules = function() {
@@ -74,8 +75,9 @@ var initialize_modules = function() {
App.Banners.initialize();
App.SocialShare.initialize();
App.MarkdownEditor.initialize();
- App.Allegations.initialize();
+ App.LegislationAllegations.initialize();
App.Legislation.initialize();
+ App.LegislationAnnotatable.initialize();
};
$(function(){
diff --git a/app/assets/javascripts/allegations.js.coffee b/app/assets/javascripts/legislation_allegations.js.coffee
similarity index 74%
rename from app/assets/javascripts/allegations.js.coffee
rename to app/assets/javascripts/legislation_allegations.js.coffee
index d57fa30ed..e01a8b5d4 100644
--- a/app/assets/javascripts/allegations.js.coffee
+++ b/app/assets/javascripts/legislation_allegations.js.coffee
@@ -1,4 +1,4 @@
-App.Allegations =
+App.LegislationAllegations =
toggle_comments: ->
$('.draft-allegation').toggleClass('comments-on');
@@ -8,10 +8,10 @@ App.Allegations =
click: (e) ->
e.preventDefault();
e.stopPropagation();
- App.Allegations.toggle_comments()
+ App.LegislationAllegations.toggle_comments()
$('.js-toggle-allegations').on
click: (e) ->
# Toggle comments when the section title is visible
if $(this).find('.draft-panel .panel-title:visible').length == 0
- App.Allegations.toggle_comments()
+ App.LegislationAllegations.toggle_comments()
diff --git a/app/assets/javascripts/legislation_annotatable.js.coffee b/app/assets/javascripts/legislation_annotatable.js.coffee
new file mode 100644
index 000000000..fa5df598a
--- /dev/null
+++ b/app/assets/javascripts/legislation_annotatable.js.coffee
@@ -0,0 +1,38 @@
+_t = (key) -> new Gettext().gettext(key)
+
+App.LegislationAnnotatable =
+ initialize: ->
+ current_user_id = $('html').data('current-user-id')
+ if current_user_id == ""
+ annotator.ui.editor.Editor.template = [
+ '
'
+ ].join('\n')
+
+ $(".legislation-annotatable").each ->
+ $this = $(this)
+ ann_type = "legislation_draft_version"
+ ann_id = $this.data("legislation-draft-version-id")
+ base_url = $this.data("legislation-annotatable-base-url")
+
+ app = new annotator.App()
+ .include ->
+ beforeAnnotationCreated: (ann) ->
+ ann["legislation_draft_version_id"] = ann_id
+ ann.permissions = ann.permissions || {}
+ ann.permissions.admin = []
+ .include(annotator.ui.main, { element: this })
+ .include(annotator.storage.http, { prefix: base_url, urls: { search: "/annotations/search" } })
+
+ app.start().then ->
+ app.ident.identity = current_user_id
+
+ options = {}
+ options["legislation_draft_version_id"] = ann_id
+ app.annotations.load(options)
diff --git a/app/controllers/legislation/annotations_controller.rb b/app/controllers/legislation/annotations_controller.rb
new file mode 100644
index 000000000..7e053f510
--- /dev/null
+++ b/app/controllers/legislation/annotations_controller.rb
@@ -0,0 +1,32 @@
+class Legislation::AnnotationsController < ApplicationController
+ skip_before_action :verify_authenticity_token
+
+ before_action :authenticate_user!, only: [:create]
+
+ load_and_authorize_resource :process
+ load_and_authorize_resource :draft_version, through: :process
+ load_and_authorize_resource
+
+ def create
+ @annotation = Legislation::Annotation.new(annotation_params)
+ @annotation.user = current_user
+ if @annotation.save
+ render json: @annotation.to_json
+ end
+ end
+
+ def search
+ @annotations = Legislation::Annotation.where(legislation_draft_version_id: params[:legislation_draft_version_id])
+ annotations_hash = { total: @annotations.size, rows: @annotations }
+ render json: annotations_hash.to_json
+ end
+
+ private
+
+ def annotation_params
+ params
+ .require(:annotation)
+ .permit(:quote, :text, ranges: [:start, :startOffset, :end, :endOffset])
+ .merge(legislation_draft_version_id: params[:legislation_draft_version_id])
+ end
+end
diff --git a/app/models/abilities/everyone.rb b/app/models/abilities/everyone.rb
index b71e1f7d5..e29880e95 100644
--- a/app/models/abilities/everyone.rb
+++ b/app/models/abilities/everyone.rb
@@ -15,6 +15,7 @@ module Abilities
can [:read, :changes, :go_to_version], Legislation::DraftVersion
can [:read], Legislation::Question
can [:create], Legislation::Answer
+ can [:search, :read, :create], Legislation::Annotation
end
end
end
diff --git a/app/models/legislation/annotation.rb b/app/models/legislation/annotation.rb
new file mode 100644
index 000000000..365f84ad0
--- /dev/null
+++ b/app/models/legislation/annotation.rb
@@ -0,0 +1,6 @@
+class Legislation::Annotation < ActiveRecord::Base
+ serialize :ranges, Array
+
+ belongs_to :draft_version, class_name: 'Legislation::DraftVersion', foreign_key: 'legislation_draft_version_id'
+ belongs_to :user
+end
diff --git a/app/views/legislation/draft_versions/show.html.erb b/app/views/legislation/draft_versions/show.html.erb
index 5ff3a76ba..8ab20eea9 100644
--- a/app/views/legislation/draft_versions/show.html.erb
+++ b/app/views/legislation/draft_versions/show.html.erb
@@ -44,7 +44,12 @@
<%= t('.text_body') %>
- <%= @draft_version.body_html.html_safe %>
+
+ <%= @draft_version.body_html.html_safe %>
+
diff --git a/config/routes.rb b/config/routes.rb
index 0ef0187f6..956b68f32 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -101,7 +101,9 @@ Rails.application.routes.draw do
resources :draft_versions, only: [:show] do
get :go_to_version, on: :collection
get :changes
- resources :annotations
+ resources :annotations do
+ get :search, on: :collection
+ end
end
end
end
diff --git a/db/migrate/20170103125835_create_legislation_annotations.rb b/db/migrate/20170103125835_create_legislation_annotations.rb
new file mode 100644
index 000000000..723bf3813
--- /dev/null
+++ b/db/migrate/20170103125835_create_legislation_annotations.rb
@@ -0,0 +1,16 @@
+class CreateLegislationAnnotations < ActiveRecord::Migration
+ def change
+ create_table :legislation_annotations do |t|
+ t.string :quote
+ t.text :ranges
+ t.text :text
+
+ t.references :legislation_draft_version, index: true
+ t.references :user, index: true
+
+ t.datetime :hidden_at, index: true
+
+ t.timestamps null: false
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d949dbb3a..39e3ec56c 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: 20161229213217) do
+ActiveRecord::Schema.define(version: 20170103125835) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -228,6 +228,21 @@ ActiveRecord::Schema.define(version: 20161229213217) do
t.datetime "updated_at", null: false
end
+ create_table "legislation_annotations", force: :cascade do |t|
+ t.string "quote"
+ t.text "ranges"
+ t.text "text"
+ t.integer "legislation_draft_version_id"
+ t.integer "user_id"
+ t.datetime "hidden_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ end
+
+ add_index "legislation_annotations", ["hidden_at"], name: "index_legislation_annotations_on_hidden_at", using: :btree
+ add_index "legislation_annotations", ["legislation_draft_version_id"], name: "index_legislation_annotations_on_legislation_draft_version_id", using: :btree
+ add_index "legislation_annotations", ["user_id"], name: "index_legislation_annotations_on_user_id", using: :btree
+
create_table "legislation_answers", force: :cascade do |t|
t.integer "legislation_question_id"
t.integer "legislation_question_option_id"
diff --git a/spec/factories.rb b/spec/factories.rb
index 731e1fef1..fe0750756 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -399,6 +399,18 @@ FactoryGirl.define do
status "draft"
final_version false
body "Body of the legislation text"
+
+ trait :published do
+ status "published"
+ end
+ end
+
+ factory :legislation_annotation, class: 'Legislation::Annotation' do
+ draft_version factory: :legislation_draft_version
+ user
+ quote "ipsum"
+ text "Loremp ipsum dolor"
+ ranges [{"start"=>"/div[1]", "startOffset"=>5, "end"=>"/div[1]", "endOffset"=>10}]
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 594cb8cdc..7df1939be 100644
--- a/spec/features/legislation/draft_versions_spec.rb
+++ b/spec/features/legislation/draft_versions_spec.rb
@@ -119,4 +119,45 @@ feature 'Legislation Draft Versions' do
end
end
+ context 'Annotations', :js do
+ let(:user) { create(:user) }
+ background { login_as user }
+
+ scenario 'Create' do
+ draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph)
+
+ visit legislation_process_draft_version_path(draft_version.process, draft_version)
+
+ page.find(:css, ".legislation-annotatable").double_click
+ page.find(:css, ".annotator-adder button").click
+ fill_in 'annotator-field-0', with: 'this is my annotation'
+ page.find(:css, ".annotator-controls a[href='#save']").click
+
+ expect(page).to have_css ".annotator-hl"
+ first(:css, ".annotator-hl").click
+ expect(page).to have_content "this is my annotation"
+
+ visit legislation_process_draft_version_path(draft_version.process, draft_version)
+
+ expect(page).to have_css ".annotator-hl"
+ first(:css, ".annotator-hl").click
+ expect(page).to have_content "this is my annotation"
+ end
+
+ scenario 'Search' do
+ draft_version = create(:legislation_draft_version, :published, body: Faker::Lorem.paragraph)
+ 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}])
+
+ visit legislation_process_draft_version_path(draft_version.process, draft_version)
+
+ expect(page).to have_css ".annotator-hl"
+ first(:css, ".annotator-hl").click
+ expect(page).to have_content "my annotation"
+
+ all(".annotator-hl")[1].click
+ expect(page).to have_content "my other annotation"
+ end
+ end
+
end