【发布时间】:2015-07-01 22:14:56
【问题描述】:
我的网站上有一个 TinyMCE 编辑器,我希望以 A4 格式显示可编辑区域(或整个内容)。
基本上,我想以与在 MS Word 中相同的方式查看文档。 (宽度、分页符等)
这可能吗?请指出正确的方向。
【问题讨论】:
标签: javascript tinymce tinymce-4
我的网站上有一个 TinyMCE 编辑器,我希望以 A4 格式显示可编辑区域(或整个内容)。
基本上,我想以与在 MS Word 中相同的方式查看文档。 (宽度、分页符等)
这可能吗?请指出正确的方向。
【问题讨论】:
标签: javascript tinymce tinymce-4
每个人都说这很难,但 Google 已经在 Google Docs 中做到了(提示:您可以使用 Google API,甚至可以获取文档的 PDF 版本。我没有这样做,因为我们编辑器中需要额外的功能。)
这是我的解决方案:
想法:
Ruler 比尝试显示每个页面要容易得多,这意味着拆分内容...虽然它会很糟糕...即使使用 css 剪辑,我也尝试过完整的 A4 页面,但它是弄乱了文本选择,所以我不知道...我希望我能做到,但是...
我在 HTML 标签中使用 SVG 的原因是因为它是我唯一可以放在那里的东西...如果您选择 TinyMCE 中的所有文本,您可以擦除我的标尺,甚至复制和粘贴...即使您使用 contenteditable ="false"...选择有限。
https://jsfiddle.net/mzvarik/59smpdv8/
// plugin pravítko
tinymce.PluginManager.add('ruler', function(editor) {
var domHtml;
var lastPageBreaks;
function refreshRuler()
{
console.log("ddd");
try {
domHtml = $( editor.getDoc().getElementsByTagName('HTML')[0] );
// HACK - erase this, I have to put my CSS here
console.log($('tinystyle').html() );
domHtml.find('head').append( $('<style>'+$('tinystyle').html()+'</style>'));
} catch (e) {
return setTimeout(refreshRuler, 50);
}
var dpi = 96
var cm = dpi/2.54;
var a4px = cm * (29.7-5.7); // A4 height in px, -5.5 are my additional margins in my PDF print
// ruler begins (in px)
var startMargin = 4;
// max size (in px) = document size + extra to be sure, idk, the height is too small for some reason
var imgH = domHtml.height() + a4px*5;
var pageBreakHeight = 14; // height of the pagebreak line in tinyMce
var pageBreaks = [];
domHtml.find('.mce-pagebreak').each(function(){
pageBreaks[pageBreaks.length] = $(this).offset().top;
});
pageBreaks.sort();
// if pageBreak is too close next page, then ignore it
if (lastPageBreaks == pageBreaks) {
return; // no change
}
lastPageBreaks = pageBreaks;
console.log("Redraw ruler");
var s = '';
s+= '<svg width="100%" height="'+imgH+'" xmlns="http://www.w3.org/2000/svg">';
s+= '<style>';
s+= '.pageNumber{font-weight:bold;font-size:19px;font-family:verdana;text-shadow:1px 1px 1px rgba(0,0,0,.6);}';
s+= '</style>';
var pages = Math.ceil(imgH/a4px);
var i, j, curY = startMargin;
for (i=0; i<pages; i++)
{
var blockH = a4px;
var isPageBreak = 0;
for (var j=0; j<pageBreaks.length; j++) {
if (pageBreaks[j] < curY + blockH) {
// musime zmensit velikost stranky
blockH = pageBreaks[j] - curY;
// pagebreak prijde na konec stranky
isPageBreak = 1;
pageBreaks.splice(j, 1);
}
}
s+= '<line x1="0" y1="'+curY+'" x2="100%" y2="'+curY+'" stroke-width="1" stroke="red"/>';
// zacneme pravitko
s+= '<pattern id="ruler'+i+'" x="0" y="'+curY+'" width="37.79527559055118" height="37.79527559055118" patternUnits="userSpaceOnUse">';
s+= '<line x1="0" y1="0" x2="100%" y2="0" stroke-width="1" stroke="black"/>';
s+= '</pattern>';
s+= '<rect x="0" y="'+curY+'" width="100%" height="'+blockH+'" fill="url(#ruler'+i+')" />';
// napiseme cislo strany
s+= '<text x="10" y="'+(curY+19+5)+'" class="pageNumber" fill="#ffffff">'+(i+1)+'.</text>';
curY+= blockH;
if (isPageBreak) {
//s+= '<rect x="0" y="'+curY+'" width="100%" height="'+pageBreakHeight+'" fill="#FFFFFF" />';
curY+= pageBreakHeight;
}
}
s+= '</svg>';
domHtml.css('background-image', 'url("data:image/svg+xml;utf8,'+encodeURIComponent(s)+'")');
}
editor.on('NodeChange', refreshRuler);
editor.on("init", refreshRuler);
});
tinymce.init({
plugins: "ruler pagebreak",
toolbar1: "pagebreak",
selector: 'textarea',
height: 300
});
顺便说一句。 想象一下 Google 会制作免费的富文本编辑器!
CKEditor 也做不来还要付费,可惜了!
【讨论】:
这是可能的,但很难,容易出错,而且你不会接近 MS Word。也许你可以用一种左右的字体来调整它。
您需要做的是custom CSS 和custom template。模板应该类似于带有白色页面的灰色背景(带有阴影:)。使用 Javascript 定义一些将自定义类添加到模板的按钮,您将获得边距设置(窄、宽、正常、无值)。对于分页符,您可以插入一个特殊的<hr> 来设置底层页面模板的样式,就好像它结束而另一个开始一样。请记住,您必须替换几乎所有自定义 CSS 才能使其可以打印。另外,您应该让 tinymce 全屏显示。
我见过的另一种(非常奇怪的)方法是 tinymce 和 PDF renderer library 或同等文件的组合。这样您就可以正确地获得所见即所得。
希望对您有所帮助。
【讨论】:
// plugin pravítko, modified by SerhatSoylemez
tinymce.PluginManager.add("editor-ruler", function(editor) {
var domHtml;
var lastPageBreaks;
var pagen= tinymce.util.I18n.translate("p.");
function refreshRuler() {
try {
domHtml = $(editor.getDoc().getElementsByTagName('HTML')[0]);
} catch (e) {
return setTimeout(refreshRuler, 50);
}
var dpi = 96
var cm = dpi/2.54;
var a4px = cm * (29.7); // A4 height in px, -5.5 are my additional margins in my PDF print
// ruler begins (in px)
var startMargin = 0;
// max size (in px) = document size + extra to be sure, idk, the height is too small for some reason
var imgH = domHtml.height() + a4px*5;
var pageBreakHeight = 4; // height of the pagebreak line in tinyMce
var pageBreaks = []; // I changed .mce-pagebreak with .page-break !!!
domHtml.find('.page-break').each(function() {
pageBreaks[pageBreaks.length] = $(this).offset().top;
});
pageBreaks.sort();
// if pageBreak is too close next page, then ignore it
if (lastPageBreaks == pageBreaks) {
return; // no change
}
lastPageBreaks = pageBreaks;
// console.log("Redraw ruler");
var s = '';
s+= '<svg width="100%" height="'+imgH+'" xmlns="http://www.w3.org/2000/svg">';
s+= '<style>';
s+= '.pageNumber{font-weight:bold;font-size:20px;font-family:verdana;text-shadow:1px 1px 1px rgba(0,0,0,.6);}';
s+= '</style>';
var pages = Math.ceil(imgH/a4px);
var i, j, curY = startMargin;
for (i=0; i<pages; i++) {
var blockH = a4px;
var isPageBreak = 0;
for (var j=0; j<pageBreaks.length; j++) {
if (pageBreaks[j] < curY + blockH) {
// musime zmensit velikost stranky
blockH = pageBreaks[j] - curY;
// pagebreak prijde na konec stranky
isPageBreak = 1;
pageBreaks.splice(j, 1);
}
}
curY2 = curY+38;
s+= '<line x1="0" y1="'+curY2+'" x2="100%" y2="'+curY2+'" stroke-width="1" stroke="red"/>';
// zacneme pravitko
s+= '<pattern id="ruler'+i+'" x="0" y="'+curY+'" width="37.79527559055118" height="37.79527559055118" patternUnits="userSpaceOnUse">';
s+= '<line x1="0" y1="0" x2="100%" y2="0" stroke-width="1" stroke="black"/>';
s+= '<line x1="24" y1="0" x2="0" y2="100%" stroke-width="1" stroke="black"/>';
s+= '</pattern>';
s+= '<rect x="0" y="'+curY+'" width="100%" height="'+blockH+'" fill="url(#ruler'+i+')" />';
// napiseme cislo strany
s+= '<text x="10" y="'+(curY2+19+5)+'" class="pageNumber" fill="#e03e2d">'+pagen+(i+1)+'.</text>';
curY+= blockH;
if (isPageBreak) {
//s+= '<rect x="0" y="'+curY+'" width="100%" height="'+pageBreakHeight+'" fill="#ffffff" />';
curY+= pageBreakHeight;
}
}
s+= '</svg>';
domHtml.css('background-image', 'url("data:image/svg+xml;utf8,'+encodeURIComponent(s)+'")');
}
function deleteRuler() {
domHtml.css('background-image', '');
}
var toggleState = false;
editor.on("NodeChange", function () {
if (toggleState == true) {
refreshRuler();
}
});
editor.on("init", function () {
if (toggleState == true) {
refreshRuler();
}
});
editor.ui.registry.addIcon("square_foot", '<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24">'+
'<g><rect fill="none" height="24" width="24"/></g><g><g><path d="M17.66,17.66l-1.06,1.06l-0.71-0.71l1.06-1.06l-1.94-1.94l-1.06,1.06l-0.71-0.71'+
'l1.06-1.06l-1.94-1.94l-1.06,1.06 l-0.71-0.71l1.06-1.06L9.7,9.7l-1.06,1.06l-0.71-0.71l1.06-1.06L7.05,7.05L5.99,8.11L5.28,7.4l1.06-1.06L4,4'+
'v14c0,1.1,0.9,2,2,2 h14L17.66,17.66z M7,17v-5.76L12.76,17H7z"/></g></g></svg>');
editor.ui.registry.addToggleMenuItem("ruler", {
text: "Show ruler",
icon: "square_foot",
onAction: function() {
toggleState = !toggleState;
if (toggleState == false) {
deleteRuler();
} else {
refreshRuler();
}
},
onSetup: function(api) {
api.setActive(toggleState);
return function() {};
}
});
});
function loadJavascript(url) {
var script = document.createElement("script");
script.src = url;
document.head.appendChild(script);
}
loadJavascript("https://code.jquery.com/jquery-3.5.1.min.js");
【讨论】: