Скопируйте форматированный текст в буфер обмена со стилями из css-классов - PullRequest
1 голос
/ 31 марта 2019

Я использовал этот метод , чтобы скопировать форматированный текст из HTML-элемента.Проблема заключается в том, что если стили не встроены в HTML, а исходят из CSS, этот метод не работает.Существующий код нарушает форматирование и не учитывает стили.Вот код:

HTML

<button onclick="copyToClip(document.getElementById('foo').innerHTML)">
  Copy the stuff
  </button>

<div id=foo>
  You can write some JS to generate this data. 
  It can contain rich stuff.
  <b> test </b> me <i> also </i>
  <div class="green">Hello world</div> You can use setData to put TWO COPIES into the same clipboard, one that is plain and one that is rich. That way your users can paste into either a
  <ul>
    <li>plain text editor</li>
    <li>or into a rich text editor</li>
  </ul>
</div>

CSS

.green {
  display: inline;
  color: green;
}

JavaScript

function copyToClip(str) {
  function listener(e) {
    e.clipboardData.setData("text/html", str);
    e.clipboardData.setData("text/plain", str);
    e.preventDefault();
  }
  document.addEventListener("copy", listener);
  document.execCommand("copy");
  document.removeEventListener("copy", listener);
};

Пример в Codepen .

1 Ответ

1 голос
/ 31 марта 2019

Разрыв строки, добавляемый к скопированному тексту, происходит потому, что " элементы уровня блока ", даже если вы добавляете "display : inline" в листе CSS

См. W3 HTML-блок и встроенные элементы

Чтобы избежать этого, нам нужно изменить любые элементы уровня блока, которые имеют встроенный дисплей, и восстановить все стили, включая стиль по умолчанию, для нового тега

Наконец код будет выглядеть так:

Codepen

Примечание : объяснение в комментарии к коду

function CopyToClipboard(element) {
	// array off all block level elements
	var block_level_elements = ['P','H1', 'H2', 'H3', 'H4', 'H5', 'H6','OL', 'UL','DIV','FORM','HR','TABLE'];	

	//create new Element so we can change elments like we need
	var newelment = document.createElement("div");

	//copy target Element to the new Element
	newelment.innerHTML = document.getElementById(element).innerHTML;

	//hide new Element to body
	newelment.style.opacity  = 0;
	// add new Element to body
	document.body.appendChild(newelment);

	//get all element childs
	var descendents = newelment.getElementsByTagName('*');

	//loop in childs
	for (var i = 0; i < descendents.length; ++i) {
		//get defult Style
	    var style = window.getComputedStyle(descendents[i]);
	    var dis = style.getPropertyValue('display');
	    //get defult tag name
	    var tagname = descendents[i].tagName;
		
		//---------------------------
		//this part is little tricky
		//---------------------------
		//true : Element is a block level elements and css display is inline
	    if(dis.includes("inline") && block_level_elements.includes(tagname)){
	    	//get all Element style include default style
			var defultcss = document.defaultView.getComputedStyle(descendents[i], "").cssText;
			//chang Element tag from block level elements to inline level elements (span)
			descendents[i].outerHTML = descendents[i].outerHTML.replace(new RegExp(tagname, "ig"),"span");			//todo: need to change RegExp to tag name only not inner text 
			//add all Element style include default style to new tag
			descendents[i].style.cssText = defultcss;
		}
	}
	//-----------------copy new Element--------------
	var doc = document;
	var range, selection;
    
	if (doc.body.createTextRange)
    {
		range = doc.body.createTextRange();
		range.moveToElementText(newelment);
		range.select();
	} 
    
    else if (window.getSelection)
    {
		selection = window.getSelection();        
		range = doc.createRange();
		range.selectNodeContents(newelment);
		selection.removeAllRanges();
		selection.addRange(range);
 	}
	document.execCommand('copy');
	window.getSelection().removeAllRanges();
	
	// remove new Element from document
	document.body.removeChild(newelment);  
	
	document.getElementById("copybtn").innerHTML="Copied";
	
}
.green {
  display: inline;
  color: green;
  white-space: nowrap;
}
  <button id='copybtn' onclick="CopyToClipboard('foo')">
  Copy the stuff
  </button>
  
<div id='foo'>
  You can write some JS to generate this data. 
  It can contain rich stuff.
  <b> test </b> me <i> also </i>
  <div class="green" style="color: green;">Hello world</div> , <h3 class="green" style="color: green;">header3</h3> You can use setData to put TWO COPIES into the same clipboard, one that is plain and one that is rich. That way your users can paste into either a
  <ul>
    <li>plain text editor</li>
    <li>or into a rich text editor</li>
  </ul>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...