trix_embed 0.0.2 → 0.0.3

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.
@@ -4,10 +4,10 @@
4
4
  // @param {Function} callback - Function to be called with the URL object
5
5
  // @returns {URL, null} URL object
6
6
  //
7
- export function createURL(value, callback = url => {}) {
7
+ export function createURLObject(value, callback = url => {}) {
8
8
  try {
9
9
  const url = new URL(String(value).trim())
10
- if (callback) callback(url)
10
+ if (url && callback) callback(url)
11
11
  return url
12
12
  } catch (_error) {
13
13
  console.info(`Failed to parse URL! value='${value}']`)
@@ -21,67 +21,82 @@ export function createURL(value, callback = url => {}) {
21
21
  // @param {Function} callback - Function to be called with the URL host
22
22
  // @returns {String, null} URL host
23
23
  //
24
- function createURLHost(value, callback = host => {}) {
25
- let host = null
26
- createURL(value, url => (host = url.host))
24
+ function extractURLHost(value, callback = host => {}) {
25
+ let host = createURLObject(value)?.host
27
26
  if (host && callback) callback(host)
28
27
  return host
29
28
  }
30
29
 
31
- function extractURLsFromTextNodes(element) {
32
- const urls = []
33
- const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, node => {
34
- const value = node.nodeValue
35
- if (!value.includes('http')) return NodeFilter.FILTER_REJECT
36
- return NodeFilter.FILTER_ACCEPT
30
+ export function createURLTextNodeTreeWalker(element) {
31
+ return document.createTreeWalker(element, NodeFilter.SHOW_TEXT, node => {
32
+ return node.nodeValue.match(/http/gi) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
37
33
  })
34
+ }
35
+
36
+ function extractURLsFromTextNodes(element) {
37
+ const urls = new Set()
38
+ const walker = createURLTextNodeTreeWalker(element)
38
39
 
39
40
  let node
40
41
  while ((node = walker.nextNode()))
41
42
  node.nodeValue
42
43
  .split(/\s+/)
43
44
  .filter(val => val.startsWith('http'))
44
- .forEach(match =>
45
- createURL(match, url => {
46
- if (!urls.includes(url.href)) urls.push(url.href)
47
- })
48
- )
45
+ .forEach(match => createURLObject(match, url => urls.add(url.href)))
49
46
 
50
- return urls
47
+ return [...urls]
51
48
  }
52
49
 
53
- function extractURLsFromElements(element) {
54
- const urls = []
50
+ export function extractURLFromElement(element) {
51
+ if (element.src) {
52
+ const url = element.src.trim()
53
+ if (url.length) return url
54
+ }
55
+
56
+ if (element.href) {
57
+ const url = element.href.trim()
58
+ if (url.length) return url
59
+ }
55
60
 
56
- if (element.src) createURL(element.src, url => urls.push(url.href))
57
- if (element.href)
58
- createURL(element.href, url => {
59
- if (!urls.includes(url.href)) urls.push(url.href)
60
- })
61
+ return ''
62
+ }
63
+
64
+ function extractURLsFromElementNodes(element) {
65
+ const urls = new Set()
66
+
67
+ if (element.src) createURLObject(element.src, url => urls.add(url.href))
68
+ if (element.href) createURLObject(element.href, url => urls.add(url.href))
61
69
 
62
70
  const elements = element.querySelectorAll('[src], [href]')
63
- elements.forEach(el => {
64
- createURL(el.src || el.href, url => {
65
- if (!urls.includes(url.href)) urls.push(url.href)
66
- })
67
- })
71
+ elements.forEach(el => createURLObject(extractURLFromElement(el), u => urls.add(u.href)))
68
72
 
69
- return urls
73
+ return [...urls]
70
74
  }
71
75
 
72
- export function validateURL(value, allowedHosts = []) {
73
- let valid = false
74
- createURLHost(value, host => (valid = !!allowedHosts.find(allowedHost => host.includes(allowedHost))))
75
- return valid
76
+ export function validateURL(value, allowedHosts = [], blockedHosts = []) {
77
+ const host = extractURLHost(value)
78
+
79
+ if (blockedHosts.includes('*')) return false
80
+ if (blockedHosts.find(blockedHosts => host.endsWith(blockedHosts))) return false
81
+ if (allowedHosts.find(allowedHosts => host.endsWith(allowedHosts))) return true
82
+
83
+ if (allowedHosts.includes('*')) {
84
+ if (host) return true
85
+ if (value.startsWith('data:')) return true
86
+ if (value.startsWith('news:')) return true
87
+ if (value.startsWith('tel:')) return true
88
+ }
89
+
90
+ return false
76
91
  }
77
92
 
78
93
  export function extractURLHosts(values) {
79
- return values.reduce((hosts, value) => {
80
- createURLHost(value, host => {
81
- if (!hosts.includes(host)) hosts.push(host)
82
- })
83
- return hosts
84
- }, [])
94
+ return [
95
+ ...values.reduce((hosts, value) => {
96
+ extractURLHost(value, host => hosts.add(host))
97
+ return hosts
98
+ }, new Set())
99
+ ]
85
100
  }
86
101
 
87
102
  // Extracts all URLs from an HTML element (all inclusive i.e. elements and text nodes)
@@ -89,8 +104,8 @@ export function extractURLHosts(values) {
89
104
  // @param {HTMLElement} element - HTML element
90
105
  // @returns {String[]} list of unique URLs
91
106
  //
92
- export function extractURLsFromElement(element) {
93
- const elementURLs = extractURLsFromElements(element)
107
+ export function extractURLs(element) {
108
+ const elementURLs = extractURLsFromElementNodes(element)
94
109
  const textNodeURLs = extractURLsFromTextNodes(element)
95
110
  const uniqueURLs = new Set([...elementURLs, ...textNodeURLs])
96
111
  return [...uniqueURLs]
@@ -6,14 +6,28 @@ module TrixEmbed
6
6
  include GlobalID::Identification
7
7
  include ActionText::Attachable
8
8
 
9
- CONTENT_TYPE = "application/vnd.trix-embed"
10
9
  ALLOWED_TAGS = ActionText::ContentHelper.allowed_tags + %w[iframe]
11
- ALLOWED_ATTRIBUTES = ActionText::ContentHelper.allowed_attributes + %w[allow allowfullscreen allowpaymentrequest credentialless csp loading referrerpolicy sandbox srcdoc]
10
+ ALLOWED_ATTRIBUTES = (
11
+ ActionText::ContentHelper.allowed_attributes + %w[
12
+ allow
13
+ allowfullscreen
14
+ allowpaymentrequest
15
+ credentialless
16
+ csp
17
+ data-trix-embed
18
+ data-trix-embed-error
19
+ data-trix-embed-prohibited
20
+ data-trix-embed-warning
21
+ loading
22
+ referrerpolicy
23
+ sandbox
24
+ srcdoc
25
+ ]) - %w[class style]
12
26
 
13
27
  class << self
14
- def rewrite_action_text_content(content)
28
+ def rewrite_for_display(content)
15
29
  fragment = Nokogiri::HTML.fragment(content)
16
- matches = fragment.css("#{ActionText::Attachment.tag_name}[sgid][content-type='#{CONTENT_TYPE}']")
30
+ matches = fragment.css("#{ActionText::Attachment.tag_name}[sgid][content-type='#{Mime::Type.lookup_by_extension(:trix_embed_attachment)}']")
17
31
 
18
32
  matches.each do |match|
19
33
  attachment = ActionText::Attachment.from_node(match)
@@ -37,9 +51,9 @@ module TrixEmbed
37
51
  fragment.to_html.html_safe
38
52
  end
39
53
 
40
- def rewrite_trix_html(trix_html)
54
+ def rewrite_for_storage(trix_html)
41
55
  fragment = Nokogiri::HTML.fragment(trix_html)
42
- matches = fragment.css("[data-trix-attachment][data-trix-content-type='#{CONTENT_TYPE}']")
56
+ matches = fragment.css("[data-trix-attachment][data-trix-content-type='#{Mime::Type.lookup_by_extension(:trix_embed_attachment)}']")
43
57
 
44
58
  matches.each do |match|
45
59
  data = JSON.parse(match["data-trix-attachment"]).deep_transform_keys(&:underscore)
@@ -1 +1 @@
1
- <%= TrixEmbed::Attachment.rewrite_action_text_content render_action_text_content(content) %>
1
+ <%= TrixEmbed::Attachment.rewrite_for_display render_action_text_content(content) %>
@@ -16,7 +16,7 @@ module TrixEmbed
16
16
  config.trix_embed = ActiveSupport::OrderedOptions.new
17
17
 
18
18
  initializer "trix_embed.configuration" do
19
- Mime::Type.register "application/vnd.trix-embed", :trix_embed
19
+ Mime::Type.register "trix-embed/attachment", :trix_embed_attachment
20
20
 
21
21
  ActiveSupport.on_load :action_controller do
22
22
  helper TrixEmbed::ApplicationHelper
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TrixEmbed
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trix_embed
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Hopkins (hopsoft)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-15 00:00:00.000000000 Z
11
+ date: 2023-08-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: amazing_print
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: capybara
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -220,6 +234,20 @@ dependencies:
220
234
  - - ">="
221
235
  - !ruby/object:Gem::Version
222
236
  version: '0'
237
+ - !ruby/object:Gem::Dependency
238
+ name: rerun
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
223
251
  - !ruby/object:Gem::Dependency
224
252
  name: rexml
225
253
  requirement: !ruby/object:Gem::Requirement
@@ -304,7 +332,8 @@ dependencies:
304
332
  - - ">="
305
333
  - !ruby/object:Gem::Version
306
334
  version: '0'
307
- description: A Stimulus controller to safely embed external media in the Trix editor
335
+ description: Take control over what external links and embedded media is permitted
336
+ in the Trix editor via copy/paste
308
337
  email:
309
338
  - natehop@gmail.com
310
339
  executables: []
@@ -318,9 +347,12 @@ files:
318
347
  - app/helpers/trix_embed/application_helper.rb
319
348
  - app/javascript/controller.js
320
349
  - app/javascript/encryption.js
350
+ - app/javascript/enumerable.js
351
+ - app/javascript/forms.js
321
352
  - app/javascript/guard.js
322
353
  - app/javascript/index.js
323
354
  - app/javascript/media.js
355
+ - app/javascript/metadata.js
324
356
  - app/javascript/renderer.js
325
357
  - app/javascript/store.js
326
358
  - app/javascript/templates.js
@@ -358,5 +390,6 @@ requirements: []
358
390
  rubygems_version: 3.1.6
359
391
  signing_key:
360
392
  specification_version: 4
361
- summary: A Stimulus controller to safely embed external media in the Trix editor
393
+ summary: Take control over what external links and embedded media is permitted in
394
+ the Trix editor via copy/paste
362
395
  test_files: []