acts_as_content_highlightable 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +40 -7
- data/app/controller/acts_as_content_highlightable/content_highlights_controller.rb +22 -4
- data/changelog.md +11 -0
- data/lib/acts_as_content_highlightable.rb +5 -0
- data/lib/acts_as_content_highlightable/html_node_parser.rb +4 -0
- data/lib/acts_as_content_highlightable/model.rb +10 -7
- data/lib/acts_as_content_highlightable/version.rb +1 -1
- data/lib/generators/acts_as_content_highlightable/templates/active_record_content_highlight_model.rb +11 -0
- data/vendor/assets/javascripts/content_highlight.js +2 -1
- data/vendor/assets/stylesheets/content_highlight.css +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9b3aed4076a41c98413e268a0d75338d354688d
|
4
|
+
data.tar.gz: 8d2549d2c07a4debbf75340fbe230a8e557190fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9ae7c75565bb626c59e835b8e1f35e696045f785c331ab98f8da28d666fdef2980adf5673ddb2e4b9de1750586ea26ad25e99f39b30623eef45ef73ddf65043
|
7
|
+
data.tar.gz: 2b7df5e8250b997c20bb3ac07d0e2b711bdf3185a818b1c0509ce1b9331c4ea1fa24be0aa396efd04bc88220a9c549815a56ff4f42c9adfdb97387f69492756d
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -46,13 +46,13 @@ bundle exec rake db:migrate
|
|
46
46
|
```
|
47
47
|
|
48
48
|
#### 3. Set your model as content_highlightable
|
49
|
-
Add `acts_as_content_highlightable_on` to the model and choose the column that has the HTML content that you want to highlight.
|
49
|
+
Add `acts_as_content_highlightable_on` to the model and choose the column (or columns) that has the HTML content that you want to highlight.
|
50
50
|
|
51
51
|
```
|
52
52
|
Class Post < ApplicationRecord
|
53
|
-
validates :summary, :presence => true
|
54
|
-
acts_as_content_highlightable_on :summary
|
55
|
-
# summary
|
53
|
+
validates :summary, :content, :presence => true
|
54
|
+
acts_as_content_highlightable_on [:summary, :content]
|
55
|
+
# summary and content are columns on Post model that stores HTML text content
|
56
56
|
end
|
57
57
|
```
|
58
58
|
|
@@ -67,10 +67,36 @@ and this to your application.css file
|
|
67
67
|
```
|
68
68
|
|
69
69
|
#### 5. Retroactively tag text nodes
|
70
|
-
This gem creates a `before_save` callback to tag every html node in the content (e.g. `:summary`) with a data attribute `data-chnode="
|
70
|
+
This gem creates a `before_save` callback to tag every html node in the content (e.g. `:summary`) with a data attribute `data-chnode="<unique_random_hex>"`. This is essential to save, persist and display highlights. To retroactively tag the nodes, use some variant of the following code
|
71
71
|
```
|
72
72
|
Post.all.each{|post| post.prepare_for_content_highlights && post.save}
|
73
73
|
```
|
74
|
+
Please note that the data in your content column will be altered by this gem - it adds data attributes to text nodes of the html content. If your content is plain text, it will be converted into html text. See examples below
|
75
|
+
```
|
76
|
+
<!--Example 1 (plain text) -->
|
77
|
+
Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.
|
78
|
+
|
79
|
+
<!--Example 2 (html text) -->
|
80
|
+
<p>Far far away, behind the word mountains, far from the countries <em>Vokalia and Consonantia</em>, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean.</p>
|
81
|
+
<p>A small river named Duden flows by their place and supplies <b>it with the necessary <i>regelialia</i>. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.</p>
|
82
|
+
|
83
|
+
<!--Example 3 (already tagged html text) -->
|
84
|
+
<p data-chnode="aba2519">Far far away, behind the word mountains, far from the countries <em data-chnode="c13d177">Vokalia and Consonantia</em>, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean.</p>
|
85
|
+
<p data-chnode="98dbae1">A small river named Duden flows by their place and supplies <b data-chnode="d1a2419">it with the necessary <i data-chnode="123ddb3">regelialia</i>. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.</p>
|
86
|
+
```
|
87
|
+
becomes
|
88
|
+
```
|
89
|
+
<!--Example 1 (plain text - wrapped in <p> tag and added node identifier) -->
|
90
|
+
<p data-chnode="d1a2419">Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.</p>
|
91
|
+
|
92
|
+
<!--Example 2 (html text - added node identifiers) -->
|
93
|
+
<p data-chnode="aba2519">Far far away, behind the word mountains, far from the countries <em data-chnode="c13d177">Vokalia and Consonantia</em>, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean.</p>
|
94
|
+
<p data-chnode="98dbae1">A small river named Duden flows by their place and supplies <b data-chnode="d1a2419">it with the necessary <i data-chnode="123ddb3">regelialia</i>. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.</p>
|
95
|
+
|
96
|
+
<!--Example 3 (already tagged html text - node identifiers preserved)-->
|
97
|
+
<p data-chnode="aba2519">Far far away, behind the word mountains, far from the countries <em data-chnode="c13d177">Vokalia and Consonantia</em>, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean.</p>
|
98
|
+
<p data-chnode="98dbae1">A small river named Duden flows by their place and supplies <b data-chnode="d1a2419">it with the necessary <i data-chnode="123ddb3">regelialia</i>. It is a paradisematic country, in which roasted parts of sentences fly into your mouth.</p>
|
99
|
+
```
|
74
100
|
|
75
101
|
#### 6. Invoke the Content Highlighter in your view
|
76
102
|
Here is a sample posts/show view
|
@@ -85,6 +111,7 @@ Here is a sample posts/show view
|
|
85
111
|
nodeIdentifierKey: "<%=ActsAsContentHighlightable.unique_html_node_identifier_key%>",
|
86
112
|
highlightableType: "Post",
|
87
113
|
highlightableId: "1",
|
114
|
+
highlightableColumn: "summary", // required if your model has more than 1 highlightable column
|
88
115
|
readOnly: false
|
89
116
|
});
|
90
117
|
worker.init();
|
@@ -101,10 +128,16 @@ Use the `ContentHighlight#highlights_to_show` method to selectively show certain
|
|
101
128
|
#### 2. Enrich Highlights
|
102
129
|
`ContentHighlight#enrich_highlights` lets us modify the `description`, set permissions to remove `can_cancel`, and change css classes to distinguish the user's vs others' highlights `lifetime_class_ends`
|
103
130
|
|
104
|
-
#### 3.
|
131
|
+
#### 3. Set Add/remove permissions
|
132
|
+
`ContentHighlight#can_add_highlights?(highlightable, user)` and `content_highlight#can_remove_highlight?(user)` lets us set permissions to add/remove highlights based on the user, highlightable etc.
|
133
|
+
|
134
|
+
#### 4. Custom Node identifier Key
|
135
|
+
`ActsAsContentHighlightable.unique_html_node_identifier_key = 'somekey'` shall be initialized in the rails app, preferably in the `config/initializers/acts_as_content_highlightable.rb`. This will let us use a node identifier key. The default is `chnode`, and nodes will be tagged `data-chnode`. Note that changing this will render your earlier node tags useless, and you might have to re tag all the text nodes with the new key.
|
136
|
+
|
137
|
+
#### 5. Custom Styling
|
105
138
|
Check out [content_highlight.css](./vendor/assets/stylesheets/content_highlight.css)
|
106
139
|
|
107
|
-
####
|
140
|
+
#### 6. More Javascript options
|
108
141
|
`highlightableType` and `highlightableId` are required. Highlights can be set `readOnly` - no addition or removal. You may never need more but check out the [content_highlight.js](./vendor/assets/javascripts/content_highlight.js) file for more configuration options.
|
109
142
|
|
110
143
|
## Development
|
@@ -2,12 +2,13 @@ module ActsAsContentHighlightable
|
|
2
2
|
class ContentHighlightsController < ApplicationController
|
3
3
|
before_action :set_highlighter_user
|
4
4
|
before_action :get_highlightable
|
5
|
+
before_action :set_highlightable_column, :only => [:add]
|
5
6
|
|
6
7
|
def add
|
7
|
-
if @highlightable.present?
|
8
|
+
if @highlightable.present? and (ContentHighlight.respond_to?(:can_add_highlights?) ? ContentHighlight.can_add_highlights?(@highlightable, @highlighter_user) : true)
|
8
9
|
content_highlight = @highlightable.content_highlights.new({
|
9
10
|
:user => @highlighter_user,
|
10
|
-
:highlightable_column => @
|
11
|
+
:highlightable_column => @highlightable_column,
|
11
12
|
:content => params[:content],
|
12
13
|
:container_node_identifier_key => params[:common_ancestor_identifier_key],
|
13
14
|
:container_node_identifier => params[:common_ancestor_identifier],
|
@@ -26,7 +27,7 @@ module ActsAsContentHighlightable
|
|
26
27
|
|
27
28
|
def remove
|
28
29
|
content_highlight = @highlightable.content_highlights.where(:id => params[:content_highlight_id]).first
|
29
|
-
if content_highlight.present? and (content_highlight.user == @highlighter_user)
|
30
|
+
if content_highlight.present? and (content_highlight.respond_to?(:can_remove_highlight?) ? content_highlight.can_remove_highlight?(@highlighter_user) : (content_highlight.user == @highlighter_user))
|
30
31
|
remove_highlights = @highlightable.content_highlights.where(:id => content_highlight.id).enrich_highlights(@highlighter_user).as_json
|
31
32
|
content_highlight.destroy
|
32
33
|
else
|
@@ -36,10 +37,27 @@ module ActsAsContentHighlightable
|
|
36
37
|
end
|
37
38
|
|
38
39
|
private
|
40
|
+
|
41
|
+
def set_highlightable_column
|
42
|
+
if params[:highlightable_column].blank? and @highlightable.highlightable_columns.size > 1
|
43
|
+
raise ArgumentError.new("More than one highlightable column found. Please provide highlightable_column in your parameters")
|
44
|
+
elsif params[:highlightable_column].blank?
|
45
|
+
@highlightable_column = @highlightable.highlightable_columns.first.to_s
|
46
|
+
else
|
47
|
+
@highlightable_column = params[:highlightable_column].to_s
|
48
|
+
end
|
49
|
+
if not @highlightable.respond_to?(:highlightable_columns)
|
50
|
+
raise ArgumentError.new("Highlightable column not found. Please check the parameter: highlightable_column")
|
51
|
+
end
|
52
|
+
if not @highlightable.highlightable_columns.include? @highlightable_column
|
53
|
+
raise ArgumentError.new("Invalid Highlightable column")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
39
57
|
def get_highlightable
|
40
58
|
highlightable_model = params[:highlightable_type].to_s.constantize
|
41
59
|
@highlightable = highlightable_model.respond_to?(:find_by_id) && highlightable_model.find_by_id(params[:highlightable_id])
|
42
|
-
@highlightable = nil unless @highlightable.respond_to?(:
|
60
|
+
@highlightable = nil unless @highlightable.respond_to?(:highlightable_columns)
|
43
61
|
end
|
44
62
|
|
45
63
|
def set_highlighter_user
|
data/changelog.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# v 0.2.0
|
2
|
+
(July, 10, 2017)
|
3
|
+
|
4
|
+
* Supports multiple content_highlightable columns per model
|
5
|
+
```
|
6
|
+
acts_as_content_highlightable_on [:summary, :content]
|
7
|
+
```
|
8
|
+
* Added ActsAsContentHighlightabl.extract_text_from_html(text) method
|
9
|
+
- can be used to extract text from HTML content.
|
10
|
+
* Extract `can_remove_highlight?(user)` method from controller to ContentHighlight model
|
11
|
+
- Can customize removal permissions - better than just checking (highlight.user == current_user)
|
@@ -13,6 +13,11 @@ module ActsAsContentHighlightable
|
|
13
13
|
mattr_accessor :mount
|
14
14
|
self.mount = true
|
15
15
|
|
16
|
+
def self.extract_text_from_html(text)
|
17
|
+
return nil unless text.is_a? String
|
18
|
+
return ActsAsContentHighlightable::HtmlNodeParser.new(text).body_text
|
19
|
+
end
|
20
|
+
|
16
21
|
ActiveSupport.on_load(:active_record) do
|
17
22
|
extend ActsAsContentHighlightable::Model
|
18
23
|
end
|
@@ -1,21 +1,24 @@
|
|
1
1
|
module ActsAsContentHighlightable
|
2
2
|
module Model
|
3
|
-
def acts_as_content_highlightable_on(
|
4
|
-
|
5
|
-
|
3
|
+
def acts_as_content_highlightable_on(column_names)
|
4
|
+
column_names = [column_names].flatten
|
5
|
+
if not column_names.all? {|column_name| self.column_names.include? column_name.to_s}
|
6
|
+
raise ArgumentError, "acts_as_content_highlightable_on: One or more invalid attribute #{column_names}"
|
6
7
|
end
|
7
8
|
|
8
9
|
class_eval do
|
9
10
|
has_many :content_highlights, :as => :highlightable
|
11
|
+
before_save :prepare_for_content_highlights, :if => column_names.map{|column_name| "#{column_name}_changed?"}
|
10
12
|
end
|
11
13
|
|
12
14
|
class_eval %{
|
13
|
-
|
14
|
-
|
15
|
-
return "#{column_name.to_s}"
|
15
|
+
def highlightable_columns
|
16
|
+
return #{column_names.map(&:to_s)}
|
16
17
|
end
|
17
18
|
def prepare_for_content_highlights
|
18
|
-
|
19
|
+
#{column_names}.each do |column_name|
|
20
|
+
self[column_name.to_sym] = ActsAsContentHighlightable::HtmlNodeParser.new(self[column_name.to_sym]).assign_unique_node_identifiers("data-" + ActsAsContentHighlightable.unique_html_node_identifier_key).body_content
|
21
|
+
end
|
19
22
|
end
|
20
23
|
}
|
21
24
|
end
|
data/lib/generators/acts_as_content_highlightable/templates/active_record_content_highlight_model.rb
CHANGED
@@ -14,6 +14,17 @@ class ContentHighlight < ActiveRecord::Base
|
|
14
14
|
highlightable.content_highlights
|
15
15
|
end
|
16
16
|
|
17
|
+
# Set Add Permissions here
|
18
|
+
def self.can_add_highlights?(highlightable, user)
|
19
|
+
return true # e.g. highlightable.can_highlight?(user)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set remove permissions here
|
23
|
+
def can_remove_highlight?(user)
|
24
|
+
return (self.user == user)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
17
28
|
# This method is used to show details on the poptips with permissions to remove highlights
|
18
29
|
def self.enrich_highlights(user)
|
19
30
|
ContentHighlight.joins(:user)
|
@@ -40,6 +40,7 @@ var contentHighlightWorker = function(element, options){
|
|
40
40
|
this.settings = {
|
41
41
|
highlightableType: options.highlightableType || "",
|
42
42
|
highlightableId: options.highlightableId || "",
|
43
|
+
highlightableColumn: options.highlightableColumn || "",
|
43
44
|
readOnly: options.readOnly || false,
|
44
45
|
nodeIdentifierKey: options.nodeIdentifierKey || "chnode",
|
45
46
|
highlightClass: options.highlightClass || "content-highlight",
|
@@ -52,7 +53,7 @@ var contentHighlightWorker = function(element, options){
|
|
52
53
|
removeFromServerPath: options.removeFromServerPath || element.dataset.removehighlightspath || "/content_highlights/remove?",
|
53
54
|
}
|
54
55
|
|
55
|
-
this.sendToServerParams = "highlightable_type=" + this.settings.highlightableType + "&highlightable_id=" + this.settings.highlightableId;
|
56
|
+
this.sendToServerParams = "highlightable_type=" + this.settings.highlightableType + "&highlightable_id=" + this.settings.highlightableId + "&highlightable_column=" + this.settings.highlightableColumn;
|
56
57
|
|
57
58
|
if(!rangy || !rangy.getSelection){
|
58
59
|
return;
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_content_highlightable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Karthik Ravichandran
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-07-
|
11
|
+
date: 2017-07-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -100,6 +100,7 @@ files:
|
|
100
100
|
- app/controller/acts_as_content_highlightable/content_highlights_controller.rb
|
101
101
|
- bin/console
|
102
102
|
- bin/setup
|
103
|
+
- changelog.md
|
103
104
|
- config/routes.rb
|
104
105
|
- lib/acts_as_content_highlightable.rb
|
105
106
|
- lib/acts_as_content_highlightable/engine.rb
|