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.
- checksums.yaml +4 -4
- data/README.md +120 -47
- data/app/assets/builds/trix-embed.js +38 -19
- data/app/assets/builds/trix-embed.metafile.json +1 -1
- data/app/javascript/controller.js +342 -145
- data/app/javascript/enumerable.js +19 -0
- data/app/javascript/forms.js +134 -0
- data/app/javascript/guard.js +29 -47
- data/app/javascript/index.js +9 -3
- data/app/javascript/media.js +12 -2
- data/app/javascript/metadata.js +4 -0
- data/app/javascript/renderer.js +155 -75
- data/app/javascript/store.js +13 -1
- data/app/javascript/templates.js +45 -28
- data/app/javascript/urls.js +57 -42
- data/app/models/trix_embed/attachment.rb +20 -6
- data/app/views/action_text/contents/_content.html.erb +1 -1
- data/lib/trix_embed/engine.rb +1 -1
- data/lib/trix_embed/version.rb +1 -1
- metadata +37 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d839c80df9c7dc70b3336dccb40896128aadff60d97fc7d4ceb5d7afe14fe87a
|
4
|
+
data.tar.gz: 56632a5f6852a5ea1d03348f724d96bc93cd306a497fa5e776660ab355ad8708
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35e20db3bea5b867c1b5c9c0ddff48b7055670a11d78c94b299d4c1d9340082084d2cf2ad7c68eab6ae3a66f289a6b664ace9a6ca65c74664816d54203e4aa45
|
7
|
+
data.tar.gz: d588233eb5e1d897dfdfc02fa40d65896e009698393db4fbd23221fd8e25fc1fa1a07e71545b04aa8083fde4af5e0be191f654c5ce0e95a49918a56a0ee65547
|
data/README.md
CHANGED
@@ -1,15 +1,41 @@
|
|
1
1
|
# Trix Embed
|
2
2
|
|
3
|
-
|
3
|
+
#### Take control over what external links and embedded media is permitted in the Trix editor via copy/paste
|
4
|
+
|
5
|
+
<!-- Tocer[start]: Auto-generated, don't remove. -->
|
6
|
+
|
7
|
+
## Table of Contents
|
8
|
+
|
9
|
+
- [Setup](#setup)
|
10
|
+
- [Features](#features)
|
11
|
+
- [Allow / Block Lists](#allow--block-lists)
|
12
|
+
- [Template Overrides](#template-overrides)
|
13
|
+
- [Basic Usage](#basic-usage)
|
14
|
+
- [Allow Lists](#allow-lists)
|
15
|
+
- [Block Lists](#block-lists)
|
16
|
+
- [Sponsors](#sponsors)
|
17
|
+
- [Developing](#developing)
|
18
|
+
- [Releasing](#releasing)
|
19
|
+
- [License](#license)
|
20
|
+
|
21
|
+
<!-- Tocer[finish]: Auto-generated, don't remove. -->
|
22
|
+
|
23
|
+
## Dependencies
|
24
|
+
|
25
|
+
- [ActionText](https://github.com/rails/rails/tree/main/actiontext)
|
26
|
+
- [Stimulus](https://github.com/hotwired/stimulus)
|
27
|
+
- [Trix](https://github.com/basecamp/trix)
|
4
28
|
|
5
29
|
## Setup
|
6
30
|
|
7
31
|
```sh
|
8
|
-
|
32
|
+
bundle add trix_embed
|
33
|
+
yarn add trix-embed@$(bundle show trix_embed | ruby -ne 'puts $_.split(/-/).last')
|
9
34
|
```
|
10
35
|
|
11
36
|
```js
|
12
|
-
import 'trix'
|
37
|
+
import Trix from 'trix'
|
38
|
+
import "@rails/actiontext"
|
13
39
|
import { Application, Controller } from '@hotwired/stimulus'
|
14
40
|
import TrixEmbed from 'trix-embed'
|
15
41
|
|
@@ -17,18 +43,93 @@ const application = Application.start()
|
|
17
43
|
TrixEmbed.initialize({ application, Controller, Trix })
|
18
44
|
```
|
19
45
|
|
20
|
-
##
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
46
|
+
## Features
|
47
|
+
|
48
|
+
### Allow / Block Lists
|
49
|
+
|
50
|
+
Configure allow and/or block lists for external links and embedded media in your Trix editors.
|
51
|
+
|
52
|
+
__⚠︎ Block lists have precendence!__
|
53
|
+
|
54
|
+
- allowed link hosts
|
55
|
+
- blocked link hosts
|
56
|
+
- allowed media hosts
|
57
|
+
- blocked media hosts
|
58
|
+
|
59
|
+
_Note that you can also use wildcards `*` in any of lists._
|
60
|
+
|
61
|
+
### Template Overrides
|
62
|
+
|
63
|
+
TODO: document...
|
64
|
+
|
65
|
+
## Basic Usage
|
66
|
+
|
67
|
+
### Allow Lists
|
68
|
+
|
69
|
+
- Allow everything
|
70
|
+
|
71
|
+
```html
|
72
|
+
<form>
|
73
|
+
<input id="content" name="content" type="hidden">
|
74
|
+
<trix-editor id="editor" input="content"
|
75
|
+
data-controller="trix-embed"
|
76
|
+
data-trix-embed-allowed-link-hosts-value='["*"]'
|
77
|
+
data-trix-embed-allowed-media-hosts-value='["*"]'>
|
78
|
+
</trix-editor>
|
79
|
+
</form>
|
80
|
+
```
|
81
|
+
|
82
|
+
- Allow links to all hosts and allow media (images, videos, etc.) from the following hosts: `vimeo.com, voomly.com, youtube.com`
|
83
|
+
|
84
|
+
```html
|
85
|
+
<form>
|
86
|
+
<input id="content" name="content" type="hidden">
|
87
|
+
<trix-editor id="editor" input="content"
|
88
|
+
data-controller="trix-embed"
|
89
|
+
data-trix-embed-allowed-link-hosts-value='["*"]'
|
90
|
+
data-trix-embed-allowed-media-hosts-value='["vimeo.com", "voomly.com", "youtube.com"]'>
|
91
|
+
</trix-editor>
|
92
|
+
</form>
|
93
|
+
```
|
94
|
+
|
95
|
+
### Block Lists
|
96
|
+
|
97
|
+
- Block everything
|
98
|
+
|
99
|
+
```html
|
100
|
+
<form>
|
101
|
+
<input id="content" name="content" type="hidden">
|
102
|
+
<trix-editor id="editor" input="content"
|
103
|
+
data-controller="trix-embed"
|
104
|
+
data-trix-embed-block-link-hosts-value='["*"]'
|
105
|
+
data-trix-embed-block-media-hosts-value='["*"]'>
|
106
|
+
</trix-editor>
|
107
|
+
</form>
|
108
|
+
```
|
109
|
+
|
110
|
+
...or simply.
|
111
|
+
|
112
|
+
```html
|
113
|
+
<form>
|
114
|
+
<input id="content" name="content" type="hidden">
|
115
|
+
<trix-editor id="editor" input="content" data-controller="trix-embed">
|
116
|
+
</trix-editor>
|
117
|
+
</form>
|
118
|
+
```
|
119
|
+
|
120
|
+
- Block links to the following hosts: `4chan.org, 8chan.net, thepiratebay.org`
|
121
|
+
and block media (images, videos, etc.) from the following hosts: `deviantart.com, imgur.com, tumblr.com`
|
122
|
+
|
123
|
+
```html
|
124
|
+
<form>
|
125
|
+
<input id="content" name="content" type="hidden">
|
126
|
+
<trix-editor id="editor" input="content"
|
127
|
+
data-controller="trix-embed"
|
128
|
+
data-trix-embed-blocked-link-hosts-value='["4chan.org", "8chan.net", "thepiratebay.org"]'
|
129
|
+
data-trix-embed-blocked-media-hosts-value='["deviantart.com", "imgur.com", "tumblr.com"]'>
|
130
|
+
</trix-editor>
|
131
|
+
</form>
|
132
|
+
```
|
32
133
|
|
33
134
|
## Sponsors
|
34
135
|
|
@@ -46,45 +147,17 @@ TrixEmbed.initialize({ application, Controller, Trix })
|
|
46
147
|
```sh
|
47
148
|
git clone https://github.com/hopsoft/trix_embed.git
|
48
149
|
cd trix_embed
|
49
|
-
|
50
|
-
yarn build
|
51
|
-
yarn dev
|
150
|
+
bin/dev
|
52
151
|
```
|
53
|
-
### Docker
|
54
|
-
|
55
|
-
This project supports a fully Dockerized development experience.
|
56
|
-
|
57
|
-
1. Simply run the following commands to get started.
|
58
|
-
|
59
|
-
```sh
|
60
|
-
git clone -o github https://github.com/hopsoft/trix_embed.git
|
61
|
-
cd trix_embed
|
62
|
-
```
|
63
|
-
|
64
|
-
```sh
|
65
|
-
docker compose up -d # start the envionment (will take a few minutes on 1st run)
|
66
|
-
open http://localhost:3000 # in a browser
|
67
|
-
```
|
68
|
-
|
69
|
-
And, if you're using the [containers gem (WIP)](https://github.com/hopsoft/containers).
|
70
|
-
|
71
|
-
```sh
|
72
|
-
containers up # start the envionment (will take a few minutes on 1st run)
|
73
|
-
open http://localhost:3000 # in a browser
|
74
|
-
```
|
75
|
-
|
76
|
-
1. Edit files using your preferred tools on the host machine.
|
77
|
-
|
78
|
-
1. That's it!
|
79
152
|
|
80
153
|
## Releasing
|
81
154
|
|
82
155
|
1. Run `yarn` and `bundle` to pick up the latest
|
83
|
-
1. Bump version
|
84
|
-
1. Run `yarn build`
|
156
|
+
1. Bump version numbers at `lib/trix_embed/version.rb` and `package.json` _(make sure they match)_. Pre-release versions use `.preN`
|
157
|
+
1. Run `yarn build` - *builds both the Ruby gem and the NPM package*
|
85
158
|
1. Commit and push changes to GitHub
|
86
159
|
1. Run `rake release`
|
87
|
-
1. Run `yarn publish --no-git-tag-version --access public`
|
160
|
+
1. Run `yarn publish --new-version X.X.X --no-git-tag-version --access public`
|
88
161
|
1. Yarn will prompt you for the new version. Pre-release versions use `-preN`
|
89
162
|
1. Commit and push changes to GitHub
|
90
163
|
1. Create a new release on GitHub ([here](https://github.com/hopsoft/trix_embed/releases)) and generate the changelog for the stable release for it
|
@@ -1,22 +1,41 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
/*
|
2
|
+
trix-embed 0.0.3 (MIT)
|
3
|
+
Copyright © 2023 Nate Hopkins (hopsoft) <natehop@gmail.com>
|
4
|
+
*/
|
5
|
+
var ge=Object.defineProperty,be=Object.defineProperties;var ye=Object.getOwnPropertyDescriptors;var B=Object.getOwnPropertySymbols;var xe=Object.prototype.hasOwnProperty,we=Object.prototype.propertyIsEnumerable;var N=(r,e,t)=>e in r?ge(r,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):r[e]=t,E=(r,e)=>{for(var t in e||(e={}))xe.call(e,t)&&N(r,t,e[t]);if(B)for(var t of B(e))we.call(e,t)&&N(r,t,e[t]);return r},L=(r,e)=>be(r,ye(e));var J=(r,e,t)=>(N(r,typeof e!="symbol"?e+"":e,t),t);var _={version:"0.0.3"};var R={name:"AES-GCM",length:256},ve=!0,Ee=["encrypt","decrypt"];async function Le(){let e=["encrypt","decrypt"];return await crypto.subtle.generateKey(R,!0,e)}async function Te(r){let e=await crypto.subtle.exportKey("jwk",r);return JSON.stringify(e)}async function G(r){let e=JSON.parse(r);return await crypto.subtle.importKey("jwk",e,R,ve,Ee)}async function Se(r,e){let t=new TextEncoder().encode(String(r)),n=crypto.getRandomValues(new Uint8Array(12)),i=await crypto.subtle.encrypt(L(E({},R),{iv:n}),e,t),s={ciphertext:btoa(String.fromCharCode(...new Uint8Array(i))),iv:btoa(String.fromCharCode(...n))};return btoa(JSON.stringify(s))}async function Ae(r,e){let t=JSON.parse(atob(r)),n=new Uint8Array(atob(t.ciphertext).split("").map(a=>a.charCodeAt(0))),i=new Uint8Array(atob(t.iv).split("").map(a=>a.charCodeAt(0))),s=await crypto.subtle.decrypt(L(E({},R),{iv:i}),e,n);return new TextDecoder().decode(s)}async function T(){let r=await Le(),e=await Te(r);return btoa(e)}async function x(r,e=[]){let t=await G(atob(r));return Promise.all(e.map(n=>Se(n,t)))}async function X(r,e=[]){let t=await G(atob(r));return Promise.all(e.map(n=>Ae(n,t)))}async function Q(r=[]){let e=await T(),t=await x(e,r);return console.log(`data-trix-embed-key-value="${e}"`),console.log(`data-trix-embed-hosts-value='${JSON.stringify(t)}'`),{key:e,encryptedValues:t}}var Y=r=>Math.floor(Math.random()*r),w=(r,e=null)=>{let t=[...r];e==="all"&&(e=t.length);let n=t.length,i=[],s=new Set;for(;i.length<e;){let a=Y(n);for(;s.has(a);)a=Y(n);s.add(a),i.push(t[a])}return typeof e=="number"?i:i[0]};function b(r,e=t=>{}){try{let t=new URL(String(r).trim());return t&&e&&e(t),t}catch(t){console.info(`Failed to parse URL! value='${r}']`)}return null}function Z(r,e=t=>{}){var n;let t=(n=b(r))==null?void 0:n.host;return t&&e&&e(t),t}function O(r){return document.createTreeWalker(r,NodeFilter.SHOW_TEXT,e=>e.nodeValue.match(/http/gi)?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP)}function ke(r){let e=new Set,t=O(r),n;for(;n=t.nextNode();)n.nodeValue.split(/\s+/).filter(i=>i.startsWith("http")).forEach(i=>b(i,s=>e.add(s.href)));return[...e]}function U(r){if(r.src){let e=r.src.trim();if(e.length)return e}if(r.href){let e=r.href.trim();if(e.length)return e}return""}function Re(r){let e=new Set;return r.src&&b(r.src,n=>e.add(n.href)),r.href&&b(r.href,n=>e.add(n.href)),r.querySelectorAll("[src], [href]").forEach(n=>b(U(n),i=>e.add(i.href))),[...e]}function C(r,e=[],t=[]){let n=Z(r);return t.includes("*")||t.find(i=>n.endsWith(i))?!1:!!(e.find(i=>n.endsWith(i))||e.includes("*")&&(n||r.startsWith("data:")||r.startsWith("news:")||r.startsWith("tel:")))}function ee(r){return[...r.reduce((e,t)=>(Z(t,n=>e.add(n)),e),new Set)]}function te(r){let e=Re(r),t=ke(r);return[...new Set([...e,...t])]}var re={attachment:"trix-embed/attachment"};var ie={avif:"image/avif",bmp:"image/bmp",gif:"image/gif",heic:"image/heic",heif:"image/heif",ico:"image/x-icon",jp2:"image/jp2",jpeg:"image/jpeg",jpg:"image/jpeg",jxr:"image/vnd.ms-photo",png:"image/png",svg:"image/svg+xml",tif:"image/tiff",tiff:"image/tiff",webp:"image/webp"};var Ue=ie,Me=["animate","animateMotion","animateTransform","area","audio","base","embed","feDisplacementMap","feImage","feTile","filter","font-face-uri","iframe","image","link","object","script","source","track","use","video"],Ne=["audio","embed","iframe","img","input","script","source","track","video","frame","frameset","object","picture","use"],ne="trix-editor",se="action-text-attachment",ae=Me.concat(Ne);function oe(r){return!!Object.values(ie).find(e=>e===P(r))}function P(r){let e;if(e=b(r),!e)return null;let t=e.pathname.lastIndexOf(".");if(!t)return null;let n=e.pathname.substring(t+1);return Ue[n]}var j,H,ce=new Set,Oe=`${ne}[data-controller~="trix-embed"]`;function de(r){var n;let{method:e,action:t}=r||{};return t=((n=b(t))==null?void 0:n.pathname)||t,`${e}:${t}`.trim().toLowerCase()}function me(r,e){if(!r)return;let t=de(r);ce.add({key:t,form:r,input:e})}function Ce(r){var l;let e=de(r),t=[...ce].filter(o=>o.key===e);if(!t.length)return!0;if(r.trixEmbedPasting)return!1;if(r.querySelector(Oe))return!0;let n=new FormData(r),i=((l=b(r.action))==null?void 0:l.searchParams)||new URLSearchParams;return!t.map(o=>o.input).map(o=>!(o.name&&(n.has(o.name)||i.has(o.name))||o.id&&(n.has(o.id)||i.has(o.id)))).includes(!1)}function le(r){Ce(r.target)||r.preventDefault()}function F(r){r.removeEventListener("submit",le,!0),r.addEventListener("submit",le,!0)}function Pe(){if(j)return;let r=Document.prototype.createElement;j={value:function(){let e=r.apply(this,arguments);try{String(arguments[0]).toUpperCase()==="FORM"&&F(e)}catch(t){}return e},configurable:!1},Object.defineProperty(Document.prototype,"createElement",j)}function D(r=0){if(!document.body&&r<10)return setTimeout(()=>D(r+1),50);H||(H=new MutationObserver(e=>e.forEach(t=>t.addedNodes.forEach(n=>{n instanceof HTMLFormElement&&F(n)}))),H.observe(document.body,{childList:!0,subtree:!0}))}addEventListener("load",()=>D());Pe();D();document.querySelectorAll("form").forEach(r=>F(r));var S=class{constructor(e){this.controller=e}preventAttachments(){var e,t,n,i,s;(e=this.editor)==null||e.removeAttribute("data-direct-upload-url"),(t=this.editor)==null||t.removeAttribute("data-blob-url-template"),(n=this.editor)==null||n.addEventListener("trix-file-accept",a=>a.preventDefault(),!0),(s=(i=this.toolbar)==null?void 0:i.querySelector('[data-trix-button-group="file-tools"]'))==null||s.remove()}async preventLinks(){var n,i;let e=await this.controller.allowedLinkHosts;!(await this.controller.blockedLinkHosts).length&&e.includes("*")||(i=(n=this.toolbar)==null?void 0:n.querySelector('[data-trix-action="link"]'))==null||i.remove()}protect(e=0){if(!this.toolbar&&e<10)return setTimeout(()=>this.protect(e+1),25);this.preventAttachments(),this.preventLinks(),this.form&&me(this.form,this.input)}get editor(){return this.controller.element}get toolbar(){return this.controller.toolbarElement}get form(){return this.controller.formElement}get input(){return this.controller.inputElement}};var A=class{constructor(e){var n,i,s;let t=[location.pathname,(i=b((n=e.formElement)==null?void 0:n.action))==null?void 0:i.pathname,(s=e.element.closest("[id]"))==null?void 0:s.id];this.controller=e,this.identifier=t.filter(a=>a&&a.length).join("/").replace(/\/{2,}/g,"/"),this.base=this.obfuscate(this.identifier)}split(e){let t=Math.ceil(e.length/2);return[e.slice(0,t),e.slice(t)]}obfuscate(e){var i;let t=[...e].map(s=>s.charCodeAt(0));return[(i=this.split(t)[1])==null?void 0:i.reverse(),t[0]].flat().join("")}read(e){return sessionStorage.getItem(this.generateStorageKey(e))}write(e,t){return sessionStorage.setItem(this.generateStorageKey(e),t)}remove(e){return sessionStorage.removeItem(this.generateStorageKey(e))}generateStorageKey(e){let t=[...this.obfuscate(e)],[n,i]=this.split(t);return btoa(`${n}/${this.base}/${i}`)}};var V={link:"<a href='{{url}}'>{{label}}</a>",embedded:`
|
6
|
+
<span>
|
7
|
+
<strong>{{label}}</strong>
|
8
|
+
<span>{{description}}</span>
|
9
|
+
<del>{{url}}</del>
|
10
|
+
</span>
|
11
|
+
`,prohibited:`
|
12
|
+
<span>
|
13
|
+
<strong>{{label}}</strong>
|
14
|
+
<span>{{description}}</span>
|
15
|
+
<del>{{url}}</del>
|
16
|
+
</span>
|
17
|
+
`,error:`
|
18
|
+
<div data-trix-embed data-trix-embed-error>
|
19
|
+
<h1>{{header}}</h1>
|
20
|
+
<pre><code>{{error.stack}}</code></pre>
|
21
|
+
</div>
|
22
|
+
`,iframe:`
|
23
|
+
<div data-trix-embed>
|
24
|
+
<iframe src='{{src}}' loading='lazy' referrerpolicy='no-referrer' scrolling='no'></iframe>
|
25
|
+
</div>
|
26
|
+
`,image:`
|
27
|
+
<div data-trix-embed>
|
28
|
+
<img src='{{src}}' loading='lazy'></img>
|
29
|
+
</div>
|
30
|
+
`,warning:`
|
31
|
+
<div data-trix-embed data-trix-embed-warning>
|
32
|
+
<h1>{{header}}</h1>
|
33
|
+
<h3>{{subheader}}</h3>
|
5
34
|
|
6
|
-
<h2>
|
7
|
-
<ul
|
8
|
-
<li>Media is only supported from allowed hosts.</li>
|
9
|
-
</ul>
|
35
|
+
<h2>{{prohibited.header}}</h2>
|
36
|
+
<ul>{{prohibited.hosts}}</ul>
|
10
37
|
|
11
|
-
<h2>
|
12
|
-
<ul
|
13
|
-
<li>Allowed hosts not configured.</li>
|
14
|
-
</ul>
|
15
|
-
</div>
|
16
|
-
`,exception:`
|
17
|
-
<div style='background-color:lightyellow; color:red; border:solid 1px red; padding:20px;'>
|
18
|
-
<h1>Unhandled Exception!</h1>
|
19
|
-
<p>Show a programmer the message below.</p>
|
20
|
-
<pre style="background-color:darkslategray; color:whitesmoke; padding:10px;"><code></code></pre>
|
38
|
+
<h2>{{allowed.header}}</h2>
|
39
|
+
<ul>{{allowed.hosts}}</ul>
|
21
40
|
</div>
|
22
|
-
`};function z(n){let e=document.createElement("template");return e.innerHTML=me[n],e}var w=class{constructor(e){this.controller=e,this.initializeTempates()}initializeTempates(){["error","exception","header","iframe","image"].forEach(t=>this.initializeTemplate(t))}initializeTemplate(e){let t;this.controller[`has${e.charAt(0).toUpperCase()+e.slice(1)}TemplateValue`]&&(t=document.getElementById(this.controller[`${e}TemplateValue`])),this[`${e}Template`]=t||z(e)}renderHeader(e){let t=this.headerTemplate.content.firstElementChild.cloneNode(!0),i=t.tagName.match(/h1/i)?t:t.querySelector("h1");return i.innerHTML=e,t.outerHTML}renderLinks(e=["https://example.com","https://test.com"]){return e=e.filter(i=>{let r=!1;return h(i,o=>r=!0),r}).sort(),e.length?`<ul>${e.map(i=>`<li><a href='${i}'>${i}</a></li>`).join("")}</ul><br>`:void 0}renderEmbed(e="https://example.com"){let t;if(J(e)){t=this.imageTemplate.content.firstElementChild.cloneNode(!0);let i=t.tagName.match(/img/i)?t:t.querySelector("img");i.src=e}else{t=this.iframeTemplate.content.firstElementChild.cloneNode(!0);let i=t.tagName.match(/iframe/i)?t:t.querySelector("iframe");i.src=e}return t.outerHTML}renderEmbeds(e=["https://example.com","https://test.com"]){if(e!=null&&e.length)return e.map(t=>this.renderEmbed(t))}renderErrors(e=["https://example.com","https://test.com"],t=[]){if(!(e!=null&&e.length))return;let i=this.errorTemplate.content.firstElementChild.cloneNode(!0),r=i.querySelector('[data-list="prohibited-hosts"]'),o=i.querySelector('[data-list="allowed-hosts"]');if(r){let s=I(e).sort();s.length&&(r.innerHTML=s.map(a=>`<li>${a}</li>`).join(""))}return o&&t.length&&(o.innerHTML=t.map(s=>`<li>${s}</li>`).join("")),i.outerHTML}renderException(e){let t=this.exceptionTemplate.content.firstElementChild.cloneNode(!0),i=t.querySelector("code");return i.innerHTML=e.message,t.outerHTML}};var ue={Controller:null,Trix:null};function B(n=ue){var i;let{Controller:e,Trix:t}=n;return i=class extends e{async connect(){var r;this.store=new E(this),this.guard=new T(this),await this.rememberConfig(),this.paranoid&&this.guard.protect(),(r=this.toolbarElement.querySelector('[data-trix-button-group="file-tools"]'))==null||r.remove(),window.addEventListener("beforeunload",()=>this.disconnect())}disconnect(){this.paranoid&&this.guard.cleanup(),this.forgetConfig()}async paste(r){let{html:o,string:s,range:a}=r.paste,u=o||s||"",d=this.buildPastedTemplate(u),p=d.content.firstElementChild,l=this.sanitizePastedElement(p).innerHTML.trim(),y=q(p);if(!y.length)return;r.preventDefault(),this.editor.setSelectedRange(a);let C=await this.hosts,f=new w(this);try{let g=y.filter(c=>H(c));Array.from(d.content.firstElementChild.querySelectorAll("iframe")).forEach(c=>{g.includes(c.src)||g.push(c.src)});let k=g.filter(c=>R(c,C)),W=g.filter(c=>!k.includes(c)),j=y.filter(c=>!g.includes(c)),L=j.filter(c=>R(c,C)),_=j.filter(c=>!L.includes(c)),m;if(m=W,m.length&&await this.insert(f.renderErrors(m,C.sort())),m=_,m.length&&(await this.insert(f.renderHeader("Pasted URLs")),await this.insert(f.renderLinks(m),{disposition:"inline"})),m=k,m.length&&(m.length>1&&await this.insert(f.renderHeader("Embedded Media")),await this.insert(f.renderEmbeds(m))),m=L,m.length&&await this.insert(f.renderEmbeds(L)),k[0]===l||L[0]===l)return this.editor.insertLineBreak();l.length&&(await this.insert(f.renderHeader("Pasted Content",l)),this.editor.insertLineBreak(),this.insert(l,{disposition:"inline"}))}catch(g){this.insert(f.renderException(g))}}buildPastedTemplate(r){let o=document.createElement("template");return o.innerHTML=`<div>${r.trim()}</div>`,o}sanitizePastedElement(r){r=r.cloneNode(!0),r.querySelectorAll(F.join(", ")).forEach(a=>a.remove());let o=r.querySelectorAll("*"),s=r.innerHTML.match(/\r\n|\n|\r/g)||[];return(s.length?o.length/s.length:0)<=.1&&(r.innerHTML=r.innerHTML.replaceAll(/\r\n|\n|\r/g,"<br>")),r}insertAttachment(r,o={delay:0}){let{delay:s}=o;return new Promise(a=>{setTimeout(()=>{let u=new t.Attachment({content:r,contentType:"application/vnd.trix-embed"});this.editor.insertAttachment(u),a()},s)})}insertHTML(r,o={delay:0}){let{delay:s}=o;return new Promise(a=>{setTimeout(()=>{this.editor.insertHTML(r),this.editor.moveCursorInDirection("forward"),this.editor.insertLineBreak(),this.editor.moveCursorInDirection("backward"),a()},s)})}insert(r,o={delay:0,disposition:"attachment"}){let{delay:s,disposition:a}=o;return r!=null&&r.length?new Promise(u=>{setTimeout(()=>{if(typeof r=="string")return a==="inline"?this.insertHTML(r,{delay:s}).then(u):this.insertAttachment(r,{delay:s}).then(u);if(Array.isArray(r))return a==="inline"?r.reduce((d,p,x)=>d.then(this.insertHTML(p,{delay:s})),Promise.resolve()).then(u):r.reduce((d,p,x)=>d.then(this.insertAttachment(p,{delay:s})),Promise.resolve()).then(u);u()})}):Promise.resolve()}get editor(){return this.element.editor}get toolbarElement(){let r=this.element.previousElementSibling;return r!=null&&r.tagName.match(/trix-toolbar/i)?r:null}get inputElement(){return document.getElementById(this.element.getAttribute("input"))}get formElement(){return this.element.closest("form")}get paranoid(){return!!this.store.read("paranoid")}get key(){try{return JSON.parse(this.store.read("key"))[2]}catch(r){}}get hosts(){try{return K(this.key,JSON.parse(this.store.read("hosts")))}catch(r){return[]}}get reservedDomains(){return["example.com","test.com","invalid.com","example.cat","nic.example","example.co.uk"]}async rememberConfig(){let r=await v(),o=await b(r,this.reservedDomains),s=await b(r,this.hostsValue);this.store.write("key",JSON.stringify([o[0],o[1],r,o[2]])),this.element.removeAttribute("data-trix-embed-key-value"),this.store.write("hosts",JSON.stringify(s)),this.element.removeAttribute("data-trix-embed-hosts-value"),this.paranoidValue!==!1&&(this.store.write("paranoid",JSON.stringify(o.slice(3))),this.element.removeAttribute("data-trix-embed-paranoid"))}forgetConfig(){this.store.remove("key"),this.store.remove("hosts"),this.store.remove("paranoid")}},S(i,"values",{validTemplate:String,errorTemplate:String,headerTemplate:String,iframeTemplate:String,imageTemplate:String,hosts:Array,paranoid:{type:Boolean,default:!0}}),i}var he={application:null,Controller:null,Trix:null};function pe(n=he){let{application:e,Controller:t,Trix:i}=n;e.register("trix-embed",B({Controller:t,Trix:i}))}self.TrixEmbed={initialize:pe,generateKey:v,encryptValues:b,generateKeyAndEncryptValues:$};var qe=self.TrixEmbed;export{qe as default};
|
41
|
+
`};var je=[se,"a","abbr","acronym","address","b","big","blockquote","br","cite","code","dd","del","dfn","div","dl","dt","em","figcaption","figure","h1","h2","h3","h4","h5","h6","hr","i","iframe","img","ins","kbd","li","ol","p","pre","samp","small","span","strong","sub","sup","time","tt","ul","var"],He=["abbr","allow","allowfullscreen","allowpaymentrequest","alt","caption","cite","content-type","credentialless","csp","data-trix-embed","data-trix-embed-error","data-trix-embed-prohibited","data-trix-embed-warning","datetime","filename","filesize","height","href","lang","loading","name","presentation","previewable","referrerpolicy","sandbox","sgid","src","srcdoc","title","url","width","xml:lang"],k=class{constructor(e){this.controller=e,this.initializeTempates()}sanitize(e){let t=document.createElement("template");t.innerHTML=`<div>${e}</div>`;let n=t.content.firstElementChild;return[n].concat([...n.querySelectorAll("*")]).forEach(s=>{je.includes(s.tagName.toLowerCase())?[...s.attributes].forEach(a=>{He.includes(a.name.toLowerCase())||s.removeAttribute(a.name)}):s.remove()}),n.innerHTML}initializeTempates(){this.templates=V,Object.keys(V).forEach(e=>this.initializeTemplate(e))}initializeTemplate(e){var s,a;let t=`${e}TemplateValue`,n=this.controller[t],i=n?(a=(s=document.getElementById(n))==null?void 0:s.innerHTML)==null?void 0:a.trim():null;return this.controller[t]=null,i&&(this.templates[e]=i),this.templates[e]}render(e,t={}){return this.templates[e].replace(/{{(.*?)}}/g,(i,s)=>s.split(".").reduce((a,l)=>a[l],t))}renderEmbed(e="https://example.com"){let t=oe(e)?this.render("image",{src:e}):this.render("iframe",{src:e});return this.sanitize(t)}renderEmbeds(e=["https://example.com","https://test.com"]){if(e!=null&&e.length)return e.map(t=>this.renderEmbed(t))}renderWarnings(e=["https://example.com","https://test.com"],t=[],n=[]){if(!(e!=null&&e.length))return;t=[...t].sort(),t.includes("*")&&t.splice(t.indexOf("*"),1),n=[...n],n.includes("*")&&n.splice(n.indexOf("*"),1);let i=[...new Set([...n,...ee(e)])].sort();return this.render("warning",{header:"Copy/Paste Warning",subheader:"Content includes URLs or media from prohibited hosts or restricted protocols.",prohibited:{header:"Prohibited Hosts",hosts:i.length?i.map(s=>`<li>${s}</li>`).join(""):"<li>URLs and media are restricted to allowed hosts and standard protocols.</li>"},allowed:{header:"Allowed Hosts",hosts:t.length?t.map(s=>`<li>${s}</li>`).join(""):"<li>Allowed hosts not configured.</li>"}})}renderError(e){return this.render("error",{header:"Unhandled Exception!",subheader:"Report this problem to a software engineer.",error:e})}};function he(r={Controller:null,Trix:null}){var n;let{Controller:e,Trix:t}=r;return n=class extends e{connect(){this.onPaste=this.paste.bind(this),this.element.addEventListener("trix-paste",this.onPaste,!0),this.onBeforeFetchResponse=this.beforeFetchResponse.bind(this),addEventListener("turbo:before-fetch-response",this.onBeforeFetchResponse,!0),this.onBeforeUnload=this.forgetConfig.bind(this),addEventListener("beforeunload",this.onBeforeUnload,!0),this.store=new A(this),this.guard=new S(this),!this.key&&this.rememberConfig().then(()=>{this.paranoid&&this.guard.protect()})}reconnect(){let i=this.element.getAttribute("data-controller")||"",s=new Set(i.split(" "));s.add("trix-embed"),this.element.setAttribute("data-controller",[...s].join(" ").trim())}disconnect(){this.element.removeEventListener("trix-paste",this.onPaste,!0),removeEventListener("turbo:before-fetch-response",this.onBeforeFetchResponse,!0),removeEventListener("beforeunload",this.onBeforeUnload,!0),this.reconnect()}beforeFetchResponse(i){try{i.target.querySelectorAll("trix-editor").includes(this.element)&&this.forgetConfig()}catch(s){}}async paste(i){this.formElement&&(this.formElement.trixEmbedPasting=!0);try{let{html:s,string:a,range:l}=i.paste,o=s||a||"",d=this.createTemplateElement(o),c=te(d);if(!c.length)return;i.preventDefault(),this.editor.setSelectedRange(l);try{let m=new k(this),h=await this.allowedMediaHosts,u=await this.blockedMediaHosts,p=new Set(c.filter(g=>P(g)));[...d.querySelectorAll("iframe")].forEach(g=>p.add(g.src)),p=[...p];let y=p.filter(g=>C(g,h,u)),v=p.filter(g=>!y.includes(g)),W=await this.allowedLinkHosts,K=await this.blockedLinkHosts,$=c.filter(g=>!p.includes(g)),z=$.filter(g=>C(g,W,K)),q=$.filter(g=>!z.includes(g));if(v.length||q.length){let g=[...new Set([...v,...q])],pe=[...new Set([...h,...W])].filter(M=>!this.reservedDomains.includes(M)),fe=[...new Set([...u,...K])].filter(M=>!this.reservedDomains.includes(M));await this.insert(m.renderWarnings(g,pe,fe))}if(y.length&&await this.insert(m.renderEmbeds(y)),c.length===1&&y.length===1)return;let I=this.sanitizePastedElement(d,{renderer:m,validMediaURLs:y,validLinkURLs:z}).innerHTML.trim();I.length&&await this.insert(I,{disposition:"inline"})}catch(m){this.insert(renderer.renderError(m))}}finally{this.formElement&&delete this.formElement.trixEmbedPasting}}createTemplateElement(i){let s=document.createElement("template");return s.innerHTML=`<div>${i.trim()}</div>`,s.content.firstElementChild}extractLabelFromElement(i,s={default:null}){let a=i.title;return a&&a.length||(a=i.textContent.trim(),a&&a.length)?a:s.default}sanitizePastedElement(i,s={renderer:null,validMediaURLs:[],validLinkURLs:[]}){let{renderer:a,validMediaURLs:l,validLinkURLs:o}=s;i=i.cloneNode(!0);let d=O(i),c=[],m;for(;m=d.nextNode();)m.replacements=m.replacements||new Set,c.push(m),m.nodeValue.split(/\s+/).filter(p=>p.startsWith("http")).forEach(p=>{var v;let f=(v=b(p))==null?void 0:v.href,y=o.includes(f)||o.includes(f)?a.render("link",{url:f,label:f}):a.render("prohibited",{url:f,label:"Prohibited URL:",description:""});m.replacements.add({match:p,replacement:y})});return c.forEach(h=>{if(!h.replacements.size)return;let u=h.nodeValue;[...h.replacements].sort((f,y)=>y.match.length-f.match.length).forEach(f=>u=u.replaceAll(f.match,f.replacement)),h.replaceWith(this.createTemplateElement(u))}),i.querySelectorAll("a").forEach(h=>{let u=U(h),p=this.extractLabelFromElement(h,{default:u}),f=o.includes(u)?a.render("link",{url:u,label:p}):a.render("prohibited",{url:u,label:"Prohibited Link:",description:`(${p})`});h.replaceWith(this.createTemplateElement(f))}),i.querySelectorAll(ae.join(", ")).forEach(h=>{let u=U(h),p=this.extractLabelFromElement(h,{default:u}),f=l.includes(u)?a.render("embedded",{url:u,label:"Allowed Media:",description:"(Embedded Above)"}):a.render("prohibited",{url:u,label:"Prohibited Media:",description:""});h.replaceWith(this.createTemplateElement(f))}),i.innerHTML.replaceAll(/(\n|\r|\f|\v)+/g,"<br>"),i}createAttachment(i){return new t.Attachment({content:i,contentType:re.attachment})}insertNewlines(i=1,s={delay:1}){let{delay:a}=s;return new Promise(l=>{setTimeout(()=>{for(let o=0;o<i;o++)this.editor.insertLineBreak();l()},a)})}insertAttachment(i,s={delay:1}){let{delay:a}=s;return new Promise(l=>{setTimeout(()=>{this.editor.insertAttachment(this.createAttachment(i)),this.insertNewlines(1,{delay:a}).finally(l)},a)})}insertHTML(i,s={delay:1}){let{delay:a}=s;return new Promise(l=>{setTimeout(()=>{this.editor.insertHTML(i),this.insertNewlines(1,{delay:a}).finally(l)},a)})}insert(i,s={delay:1,disposition:"attachment"}){let{delay:a,disposition:l}=s;return i!=null&&i.length?new Promise(o=>{setTimeout(()=>{if(typeof i=="string")return l==="inline"?this.insertHTML(i,{delay:a}).catch(d=>this.renderError(d)).finally(o):this.insertAttachment(i,{delay:a}).catch(d=>this.renderError(d)).finally(o);if(Array.isArray(i)){let d=l==="inline"?i.map(c=>this.insertHTML(c,{delay:a+1})):i.map(c=>this.insertAttachment(c,{delay:a+1}));return Promise.all(d).catch(c=>this.renderError(c)).finally(o)}o()})}):Promise.resolve()}get editor(){return this.element.editor}get toolbarElement(){let i=this.element.getAttribute("toolbar"),s=i?document.getElementById(i):null;if(!s){let a=this.element.previousElementSibling;s=a!=null&&a.tagName.match(/trix-toolbar/i)?a:null}return s}get formElement(){return this.element.closest("form")}get inputElement(){var s;let i=this.element.getAttribute("input");return i?(s=this.formElement)==null?void 0:s.querySelector(`#${i}`):null}get paranoid(){return!!this.store.read("paranoid")}get key(){try{return JSON.parse(this.store.read("key"))[2]}catch(i){return null}}get hostsValueDescriptors(){return Object.values(this.valueDescriptorMap).filter(i=>i.name.endsWith("HostsValue"))}get reservedDomains(){return["embed.example","embed.invalid","embed.local","embed.localhost","embed.test","trix.embed.example","trix.embed.invalid","trix.embed.local","trix.embed.localhost","trix.embed.test","trix.example","trix.invalid","trix.local","trix.localhost","trix.test","www.embed.example","www.embed.invalid","www.embed.local","www.embed.localhost","www.embed.test","www.trix.example","www.trix.invalid","www.trix.local","www.trix.localhost","www.trix.test"]}rememberConfig(){return new Promise(async i=>{let s,a=await T();s=await x(a,w(this.reservedDomains,3)),this.store.write("key",JSON.stringify([s[0],s[1],a,s[2]])),this.paranoidValue!==!1&&(s=await x(a,w(this.reservedDomains,4)),this.store.write("paranoid",JSON.stringify(s))),this.element.removeAttribute("data-trix-embed-paranoid-value"),this.hostsValueDescriptors.forEach(async l=>{let{name:o}=l,d=o.slice(0,o.lastIndexOf("Value")),c=this[o];c.length<4&&(c=c.concat(w(this.reservedDomains,4-c.length))),this.store.write(d,JSON.stringify(await x(a,c))),this.hasOwnProperty(d)||Object.defineProperty(this,d,{get:async()=>{try{return(await X(this.key,JSON.parse(this.store.read(d)))).filter(h=>!this.reservedDomains.includes(h))}catch(m){return console.error(`Failed to get '${d}'!`,m),[]}}}),this.element.removeAttribute(`data-trix-embed-${l.key}`)}),s=await x(a,w(this.reservedDomains,4)),this.store.write("securityHosts",s),s=await x(a,w(this.reservedDomains,4)),this.store.write("obscurityHosts",s),i()})}forgetConfig(){var i,s,a,l;try{(i=this.store)==null||i.remove("key"),(s=this.store)==null||s.remove("paranoid"),this.hostsValueDescriptors.forEach(async o=>{var m;let{name:d}=o,c=d.slice(0,d.lastIndexOf("Value"));(m=this.store)==null||m.remove(c)}),(a=this.store)==null||a.remove("securityHosts"),(l=this.store)==null||l.remove("obscurityHosts")}catch(o){}}},J(n,"values",{embeddedTemplate:String,errorTemplate:String,iframeTemplate:String,imageTemplate:String,linkTemplate:String,prohibitedTemplate:String,warningTemplate:String,allowedLinkHosts:Array,blockedLinkHosts:Array,allowedMediaHosts:Array,blockedMediaHosts:Array,paranoid:{type:Boolean,default:!0}}),n}var ue=!1,Fe={application:null,Controller:null,Trix:null};function De(r=Fe){if(ue)return;let{application:e,Controller:t,Trix:n}=r;e.register("trix-embed",he({Controller:t,Trix:n})),ue=!0}self.TrixEmbed=L(E({},_),{encryptValues:x,generateKey:T,generateKeyAndEncryptValues:Q,initialize:De});var Tt=self.TrixEmbed;export{Tt as default};
|
@@ -1 +1 @@
|
|
1
|
-
{"inputs":{"app/javascript/encryption.js":{"bytes":4095,"imports":[{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/urls.js":{"bytes":
|
1
|
+
{"inputs":{"app/javascript/metadata.js":{"bytes":86,"imports":[],"format":"esm"},"app/javascript/encryption.js":{"bytes":4095,"imports":[{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/enumerable.js":{"bytes":517,"imports":[],"format":"esm"},"app/javascript/urls.js":{"bytes":3338,"imports":[],"format":"esm"},"app/javascript/media.js":{"bytes":3618,"imports":[{"path":"app/javascript/urls.js","kind":"import-statement","original":"./urls"}],"format":"esm"},"app/javascript/forms.js":{"bytes":3377,"imports":[{"path":"app/javascript/media.js","kind":"import-statement","original":"./media"},{"path":"app/javascript/urls.js","kind":"import-statement","original":"./urls"}],"format":"esm"},"app/javascript/guard.js":{"bytes":1211,"imports":[{"path":"app/javascript/forms.js","kind":"import-statement","original":"./forms"}],"format":"esm"},"app/javascript/store.js":{"bytes":1219,"imports":[{"path":"app/javascript/urls.js","kind":"import-statement","original":"./urls"}],"format":"esm"},"app/javascript/templates.js":{"bytes":1235,"imports":[],"format":"esm"},"app/javascript/renderer.js":{"bytes":5234,"imports":[{"path":"app/javascript/urls.js","kind":"import-statement","original":"./urls"},{"path":"app/javascript/media.js","kind":"import-statement","original":"./media"},{"path":"app/javascript/templates.js","kind":"import-statement","original":"./templates"}],"format":"esm"},"app/javascript/controller.js":{"bytes":16506,"imports":[{"path":"app/javascript/enumerable.js","kind":"import-statement","original":"./enumerable"},{"path":"app/javascript/encryption.js","kind":"import-statement","original":"./encryption"},{"path":"app/javascript/urls.js","kind":"import-statement","original":"./urls"},{"path":"app/javascript/media.js","kind":"import-statement","original":"./media"},{"path":"app/javascript/guard.js","kind":"import-statement","original":"./guard"},{"path":"app/javascript/store.js","kind":"import-statement","original":"./store"},{"path":"app/javascript/renderer.js","kind":"import-statement","original":"./renderer"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"},"app/javascript/index.js":{"bytes":669,"imports":[{"path":"app/javascript/metadata.js","kind":"import-statement","original":"./metadata"},{"path":"app/javascript/encryption.js","kind":"import-statement","original":"./encryption"},{"path":"app/javascript/controller.js","kind":"import-statement","original":"./controller"},{"path":"<runtime>","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"app/assets/builds/trix-embed.js":{"imports":[],"exports":["default"],"entryPoint":"app/javascript/index.js","inputs":{"app/javascript/metadata.js":{"bytesInOutput":24},"app/javascript/encryption.js":{"bytesInOutput":1346},"app/javascript/enumerable.js":{"bytesInOutput":226},"app/javascript/urls.js":{"bytesInOutput":1200},"app/javascript/media.js":{"bytesInOutput":935},"app/javascript/forms.js":{"bytesInOutput":1352},"app/javascript/guard.js":{"bytesInOutput":1002},"app/javascript/store.js":{"bytesInOutput":835},"app/javascript/templates.js":{"bytesInOutput":969},"app/javascript/renderer.js":{"bytesInOutput":2628},"app/javascript/controller.js":{"bytesInOutput":7934},"app/javascript/index.js":{"bytesInOutput":311}},"bytes":19276}}}
|