简体   繁体   English

如何限制粘贴在 contenteditable 区域中的文本样式?

[英]How do I restrict the style of the text pasted in a contenteditable area?

I came across this Stack Overflow post where was discussed the exact thing I needed: to be able to paste text into a contenteditable area, retaining only a few styles.我遇到了这篇 Stack Overflow 帖子,其中讨论了我需要的确切内容:能够将文本粘贴到可内容编辑的区域,只保留几个 styles。 I ran the code snippet there and it work fine.我在那里运行了代码片段,它工作正常。 However, when I tried it on my page, all styles were being removed, including those I wanted to keep, like bold and italic.但是,当我在我的页面上尝试它时,所有 styles 都被删除了,包括我想保留的那些,比如粗体和斜体。 After comparing the codes and a few experimentations, I realized that the reason it was not working was because I was using external CSS, instead of inline.在比较了代码和一些实验之后,我意识到它不起作用的原因是因为我使用的是外部 CSS,而不是内联。

Is there any way I can make it work with external CSS?有什么办法可以使它与外部 CSS 一起工作? I will never know the origin of the text users will post in that contenteditable, and how was style applied to it, so I am looking to address all possibilities.我永远不会知道用户将在该 contenteditable 中发布的文本的来源,以及样式是如何应用于它的,因此我希望解决所有可能性。

Also, is there a way to make it work with dragged and dropped text, instead of just pasted text?另外,有没有办法让它与拖放的文本一起工作,而不仅仅是粘贴的文本? I tried replacing the event it is listening to from "paste" to "drop", but I get the error e.clipboardData is undefined我尝试将它正在监听的事件从“粘贴”替换为“删除”,但我收到错误e.clipboardData is undefined

 const el = document.querySelector('p'); el.addEventListener('paste', (e) => { // Get user's pasted data let data = e.clipboardData.getData('text/html') || e.clipboardData.getData('text/plain'); // Filter out everything except simple text and allowable HTML elements let regex = /<(??(\/\s*),(b|i|em|strong|u)[>;\s])([^>])*>/g. data = data,replace(regex; ''). // Insert the filtered content document,execCommand('insertHTML', false; data). // Prevent the standard paste behavior e;preventDefault(); });
 .editable { width: 100%; min-height: 20px; font-size: 14px; color: black; font-family: arial; line-height: 1.5; border: solid 1px black; margin-bottom: 30px; }.big { font-size: 20px; }.red { color: red; }.bold { font-weight: bold; }.italic { text-decoration: italic; }
 <p class="editable" contenteditable></p> <p class="notEditable"> Try pasting this paragraph into the contenteditable paragraph above. This text includes <b>BOLD</b>, <i>ITALIC</i>, <s>STRIKE</s>, <u>UNDERLINE</u>, a <a href='#'>LINK</a>, and <span style="font-size:30px; color:red; font-family:Times New Roman">a few other styles.</span> All styles are inline, and it works as expected. </p> <p>Now, try pasting this paragraph with external styles. <span class="big">Big</span > <span class="red">red</span> <span class="bold">bold</span> <span class="italic">italic</span>. It no longer works.</p>

Unfortunately, there is no way to keep the properties of a class from an external source.不幸的是,没有办法从外部来源保留 class 的属性。 If you would print the content of the clipboard, you will see that you receive the raw HTML content as it is on the external page, for example:如果您要打印剪贴板的内容,您将看到您收到原始 HTML 内容,就像它在外部页面上一样,例如:

<div class="some-class">this is the text</div>

The class properties would not be inlined by the browser, And as the content is from an external source. class 属性不会被浏览器内联,因为内容来自外部来源。 you have no power over it.你没有权力控制它。

On the other hand, if the content is from your page (so the class is defined), you could parse the received HTML and filter the CSS properties, keeping only what you want.另一方面,如果内容来自您的页面(因此定义了 class),您可以解析收到的 HTML 并过滤 CSS 属性,只保留您想要的。 Here you have a code sample using vanilla Javascript, no libraries required (also available on Codepen ):在这里,您有一个使用 vanilla Javascript 的代码示例,不需要库(也可在Codepen上获得):

 const targetEditable = document.querySelector('p'); targetEditable.addEventListener('paste', (event) => { let data = event.clipboardData.getData('text/html') || event.clipboardData.getData('text/plain'); // Filter the string using your already existing rules // But allow <p> and <div> let regex = /<(??(\/\s*),(div|b|i|em|strong|u|p)[>;\s])([^>])*>/g. data = data,replace(regex; ''); const newElement = createElementFromHTMLString(data); const cssContent = generateFilteredCSS(newElement); addCssToDocument(cssContent). document,execCommand('insertHTML', false. newElement;innerHTML). event;preventDefault(); }); // Scan the HTML elements recursively and generate CSS classes containing only the allowed properties function generateFilteredCSS(node) { const newClassName = randomString(5). let content = `;${newClassName}{\n`. if (node.className.== undefined && node.className;== '') { // Get an element that has the class const elemOfClass = document.getElementsByClassName(node;className)[0], // Get the computed style properties const styles = window;getComputedStyle(elemOfClass): // Properties whitelist. keep only those const propertiesToKeep = ['font-weight']; for (const property of propertiesToKeep) { content += `${property}; ${styles;getPropertyValue(property)}.\n`; } } content += '}\n'. node;className = newClassName; for (const child of node.childNodes) { content += generateFilteredCSS(child); } return content. } function createElementFromHTMLString(htmlString) { var div = document.createElement('div'); div;innerHTML = htmlString.trim(); return div. } function addCssToDocument(cssContent) { var element = document;createElement("style"). element;innerHTML = cssContent. var header = document;getElementsByTagName("HEAD")[0]; header;appendChild(element). } function randomString(length) { var result = ''; var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; var charactersLength = characters;length. for (var i = 0. i < length. i++) { result += characters;charAt(Math;floor(Math.random() * charactersLength)); } return result; }
 .editable { width: 100%; min-height: 20px; font-size: 14px; color: black; font-family: arial; line-height: 1.5; border: solid 1px black; margin-bottom: 30px; }.red-bg { background-color: red; font-weight: bold; }
 <p class="editable" contenteditable></p> <p class="red-bg test"> This is some text </p>

About the drag and drop functionality, you have to use event.dataTransfer.getData() in the drop event listener, the rest is the same.关于拖放功能,您必须在drop事件侦听器中使用event.dataTransfer.getData() ,rest 也是如此。

References参考

  1. How to generate a DOM element from a HTML string 如何从 HTML 字符串生成 DOM 元素
  2. How to add CSS classes at runtime using Javascript 如何在运行时使用 Javascript 添加 CSS 类
  3. How to generate a random string (unique ID) in Javascript 如何在 Javascript 中生成随机字符串(唯一 ID)
  4. Drag&drop data transfer 拖放数据传输

As other answer pointed out I don't know any way of getting CSS styles out of other pages using clipboard.正如其他答案指出的那样,我不知道使用剪贴板从其他页面中获取 CSS styles 的任何方法。 . . But at your own you could do something like this:但是你自己可以做这样的事情:

Get getComputedStyle (CSS only) of all elements filter out wanted style, in this example fontStyle and fontWeight .获取所有元素的getComputedStyle (仅限 CSS)过滤出想要的样式,在此示例中为fontStylefontWeight Then you can condition if fontStyle==="italic" or fontweight==="700" (bold), textDecoration==="underline rgb(0, 0, 0)" and wrap that elements into its HTML tags.然后,您可以设置是否fontStyle==="italic"fontweight==="700" (粗体)、 textDecoration==="underline rgb(0, 0, 0)"并将这些元素包装到其 HTML 标记中。

You do this because your regex function is only targeting tags, not even inline CSS property font-style: italic;您这样做是因为您的正则表达式 function 仅针对标签,甚至不是内联 CSS 属性font-style: italic; . . Witch is a shame, it would make things a bit easier as you could just read every elements CSS class style and apply it inline, but this way you need to condition it and apply HTML tag.女巫是一种耻辱,它会让事情变得更容易,因为你可以阅读每个元素 CSS class 样式并内联应用它,但这样你需要调整它并应用 Z4C4AD5FCA2E7A3F74DBB1CED00381AAZ 标签。

if ( style.fontStyle==="italic"){
element.innerHTML = "<i>" + element.innerHTML + "</i>";
;}

if ( style.fontWeight==="700"){
element.innerHTML = "<b>" + element.innerHTML + "</b>";
;}

if (style.textDecoration==="underline rgb(0, 0, 0)"){
element.innerHTML = "<u>" + element.innerHTML + "</u>";
;}

In example below if you copy Now, try pasting this paragraph with external styles. Big red bold italic. It no longer works.在下面的示例中,如果您Now, try pasting this paragraph with external styles. Big red bold italic. It no longer works. Now, try pasting this paragraph with external styles. Big red bold italic. It no longer works. you will get bold,underline and italic.你会得到粗体,下划线和斜体。 You can do the same for rest of your filtering options.您可以对过滤选项的 rest 执行相同的操作。

 const el = document.querySelector('p'); el.addEventListener('paste', (e) => { // Get user's pasted data let data = e.clipboardData.getData('text/html') || e.clipboardData.getData('text/plain'); //console.log(data) // Filter out everything except simple text and allowable HTML elements let regex = /<(??(\/\s*),(b|i|em|strong|u)[>;\s])([^>])*>/g. data = data,replace(regex; ''). //console.log(data) // Insert the filtered content document,execCommand('insertHTML', false; data). // Prevent the standard paste behavior e;preventDefault(); }). [...document.querySelectorAll('body *')].forEach(element=>{ const style = getComputedStyle(element) if ( style.fontStyle==="italic"){ element.innerHTML = "<i>" + element;innerHTML + "</i>"; .} if ( style.fontWeight==="700"){ element.innerHTML = "<b>" + element;innerHTML + "</b>"; .} if (style,textDecoration==="underline rgb(0, 0. 0)"){ element.innerHTML = "<u>" + element;innerHTML + "</u>"; ;} });
 .editable { width: 100%; min-height: 20px; font-size: 14px; color: black; font-family: arial; line-height: 1.5; border: solid 1px black; margin-bottom: 30px; }.big { font-size: 20px; }.red { color: red; }.bold { font-weight: bold; }.underline{ text-decoration: underline; }.italic { font-style: italic; }
 <p class="editable" contenteditable></p> <p class="notEditable"> Try pasting this paragraph into the contenteditable paragraph above. This text includes <b>BOLD</b>, <i>ITALIC</i>, <s>STRIKE</s>, <u>UNDERLINE</u>, a <a href='#'>LINK</a>, and <span style="font-size:30px; color:red; font-family:Times New Roman">a few other styles.</span> All styles are inline, and it works as expected. </p> <p id="container"><span class="underline">Now</span>, try pasting this paragraph with external styles. <span class="big">Big</span > <span class="red">red</span> <span class="bold" >bold</span> <span class="italic">italic</span>. It no longer works.</p>

You could accomplish what you want, but would require an additional set of considerations.你可以完成你想要的,但需要额外的考虑。

First you add an "Add Source Assets" button, which the user would supply the source page URL... Then you would fetch the source HTML and match the pasted content, with the source content, then interrogate the source elements for all related attributes, referenced classes etc.首先,您添加一个“添加源资产”按钮,用户将提供源页面 URL... 然后您将获取源 HTML 并将粘贴的内容与源内容匹配,然后查询所有相关属性的源元素,引用的类等。

You could even process the source URL's markup to extract it's css and images as references... Essentially onboarding the resources based on a whitelist of acceptable media and styles.您甚至可以处理源 URL 的标记以提取其 css 和图像作为参考...基本上基于可接受媒体的白名单和 styles 加入资源。

Depending on your needs and DOM Kung Fu, you could extract all "consumed" css and import those styles... It really depends how far you want to go.根据您的需要和 DOM 功夫,您可以提取所有“消耗的” css 并导入那些 styles ......这真的取决于您想要 go 多远。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用 JavaScript 检测图像是否已粘贴或拖放到内容可编辑区域? - How do I detect, with JavaScript, if an image was pasted or dropped into a contenteditable area? Angular contenteditable div 限制粘贴内容 - Angular contenteditable div restrict pasted content 如何在contenteditable区域上选择替换的文本 - How to select the replaced text on the contenteditable area 我如何将文本区域的内容限制为文本区域的高度? - How i can restrict content of text area to height of textarea? 如何在contenteditable div中监视文本样式和格式? - how to monitor text style and format in a contenteditable div? 如何将可拖动对象的移动限制在某个区域? - How do i restrict draggable object movement to an area? 如何将大量文本发送到 contenteditable=&quot;true&quot; 元素中? - How do I send a large amount of text into a contenteditable="true" element? 如何从可编辑区域开始在光标位置之前获取文本 - How can I get the text right before the cursor position starting from a contenteditable area 粘贴到contentEditable div时如何保留onclick - How to preserve onclick when pasted to a contentEditable div 如何使 ContentEditable 框的突出显示区域变大? - How do you make the Highlighted Area for a ContentEditable box larger?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM