forced_root_block option in TinyMCE - tinymce

I am trying to implement a custom WYSIWYG editor using a contenteditable <div>.
One of the major issues I am facing is the inconsistent way browsers handle ENTER keystroke (linebreaks). Chrome inserts <div>, Firefox inserts <br> and IE inserts <p>. I was taking a look at TinyMCE and it has a configuration option called forced_root_block. Setting forced_root_block to div actually works across all major browser. Does someone know how forced_root_block option in TinyMCE is able to achieve it across browsers ?

In the tinymce source (/tiny_mce/classs/dom/DomParser.js) you will find the following:
rootBlockName = "forced_root_block" in args ? args.forced_root_block : settings.forced_root_block;
whiteSpaceElements = schema.getWhiteSpaceElements();
startWhiteSpaceRegExp = /^[ \t\r\n]+/;
endWhiteSpaceRegExp = /[ \t\r\n]+$/;
allWhiteSpaceRegExp = /[ \t\r\n]+/g;
function addRootBlocks() {
var node = rootNode.firstChild, next, rootBlockNode;
while (node) {
next = node.next;
if (node.type == 3 || (node.type == 1 && node.name !== 'p' && !blockElements[node.name] && !node.attr('data-mce-type'))) {
if (!rootBlockNode) {
// Create a new root block element
rootBlockNode = createNode(rootBlockName, 1);
rootNode.insert(rootBlockNode, node);
rootBlockNode.append(node);
} else
rootBlockNode.append(node);
} else {
rootBlockNode = null;
}
node = next;
};
};
This obviously takes care of creating root block elements.
I am 99% sure that tinymce handles the 'ENTER' keystroke itself and stops the propagation/ default browser command.

Related

TInyMCE Preview Plugin : Link is not clickable

I am uses TinyMCE 4 where I have inserted source content as link
Sample Link
After inserting above content in the TinyMCE, if I click on the preview button of TinyMCE then anchor tag is coming in the form of link but it's not clickable.
Can anyone guide how anchor we can make it as clickable?
I have followed below links(by adding default_link_target: "_blank"):
https://community.tinymce.com/communityQuestion?id=90661000000MrWjAAK
&
How to open hyperlink in new window under tinymce text editor?
but none seems to be worked.
but none seems to be worked.
The preview plugin has code that specifically stops links from being clickable. If you look at the JavaScript code for the plugin you will see something like this:
var preventClicksOnLinksScript = (
'<script>' +
'document.addEventListener && document.addEventListener("click", function(e) {' +
'for (var elm = e.target; elm; elm = elm.parentNode) {' +
'if (elm.nodeName === "A") {' +
'e.preventDefault();' +
'}' +
'}' +
'}, false);' +
'</script> '
);
This code is there specifically to address an issue that could cause a link in preview to unintentionally remove the editor instance.
If you click a link in the preview pane that has a target=_top you will end up blowing away the editor and replacing it with the content of that link - likely not what you want.
I know it's an old thread but maybe it will help someone out there. If you want the links to open in a new window in tinymce prevew plugin remove this script:
<script>document.addEventListener && document.addEventListener("click", function(e) {for (var elm = e.target; elm; elm = elm.parentNode) {if (elm.nodeName === "A") {e.preventDefault();}}}, false);</script>
and place this one instead:
<script>function externalLinks() { for(var c = document.getElementsByTagName("a"), a = 0;a < c.length;a++) { var b = c[a]; b.getAttribute("href") && b.href.hostname !== location.hostname && (b.target = "_blank") } } ; externalLinks();<\/script>
Enjoy!

TinyMCE 3 - textarea id which fired blur event

When a TinyMCE editor blur occurs, I am trying to find the element id (or name) of the textarea which fired the blur event. I also want the element id (or name) of the element which gains the focus, but that part should be similar.
I'm getting closer in being able to get the iframe id of the tinymce editor, but I've only got it working in Chrome and I'm sure there is a better way of doing it. I need this to work across different browsers and devices.
For example, this below code returns the iframe id in Chrome which is okay since the iframe id only appends a suffix of "_ifr" to my textarea element id. I would prefer the element id of the textarea, but it's okay if I need to remove the iframe suffix.
EDIT: I think it's more clear if I add a complete TinyMCE Fiddle (instead of the code below):
http://fiddle.tinymce.com/HIeaab/1
setup : function(ed) {
ed.onInit.add(function(ed) {
ed.pasteAsPlainText = true;
/* BEGIN: Added this to handle JS blur event */
/* example modified from: http://tehhosh.blogspot.com/2012/06/setting-focus-and-blur-event-for.html */
var dom = ed.dom,
doc = ed.getDoc(),
el = doc.content_editable ? ed.getBody() : (tinymce.isGecko ? doc : ed.getWin());
tinymce.dom.Event.add(el, 'blur', function(e) {
//console.log('blur');
var event = e || window.event;
var target = event.target || event.srcElement;
console.log(event);
console.log(target);
console.log(target.frameElement.id);
console.log('the above outputs the following iframe id which triggered the blur (but only in Chrome): ' + 'idPrimeraVista_ifr');
})
tinymce.dom.Event.add(el, 'focus', function(e) {
//console.log('focus');
})
/* END: Added this to handle JS blur event */
});
}
Maybe it's better to give a background of what I'm trying to accomplish:
We have multiple textareas on a form which we're trying to "grammarcheck" with software called "languagetool" (that uses TinyMCE version 3.5.6). Upon losing focus on a textarea, we would like to invoke the grammarcheck for the textarea that lost focus and then return the focus to where it's supposed to go after the grammar check.
I've struggled with this for quite some time, and would greatly appreciate any feedback (even if it's general advice for doing this differently).
Many Thanks!
Simplify
TinyMCE provides a property on the Editor object for getting the editor instance ID: Editor.id
It also seems overkill to check for doc.content_editable and tinyMCE.isGecko because Editor.getBody() allows for cross-browser compatible event binding already (I checked IE8-11, and latest versions of Firefox and Chrome).
Note: I actually found that the logic was failing to properly assign ed.getBody() to el in Internet Explorer, so it wasn't achieving the cross-browser functionality you need anyway.
Try the following simplified event bindings:
tinyMCE.init({
mode : "textareas",
setup : function (ed) {
ed.onInit.add(function (ed) {
/* onBlur */
tinymce.dom.Event.add(ed.getBody(), 'blur', function (e) {
console.log('Editor with ID "' + ed.id + '" has blur.');
});
/* onFocus */
tinymce.dom.Event.add(ed.getBody(), 'focus', function (e) {
console.log('Editor with ID "' + ed.id + '" has focus.');
});
});
}
});
…or see this working TinyMCE Fiddle »
Aside: Your Fiddle wasn't properly initializing the editors because the plugin was failing to load. Since you don't need the plugin for this example, I removed it from the Fiddle to get it working.

Pressing enter key creates a blank span in tinymce editor

I am using tinyMCE editor in one of my project. When I press enter key inside the equation box,I want to reload the contents of the editor.It works well now but the problem I am facing here is an empty span with class AM that is automatically created on pressing enter key.The tinymce function for reloading the contents is :
tinyMCE.execCommand("mceRepaint");
I have made a javascript functin for this which is given below :
function loadlistener() {
//console.log('load');
$("#elm1_ifr").contents().keydown(function (event) {
//console.log('key');
var code = (event.keyCode ? event.keyCode : event.which);
//console.log(code);
if (code == 13 && amedit) {
tinyMCE.execCommand("mceRepaint");
tinyMCE.activeEditor.focus();
}
});
var p_parent = $("#elm1_ifr").contents().find("p");
setInterval(function () {
if (p_parent.find('span').length && p_parent.find('span')) {
amedit = true;
} else {
amedit = false;
}
}, 200)
};
So my question is how to prevent the creation of this empty span when enter key is pressed.
You can check it live Here
Pleas inspect the html so you can understand my question more clearly.

Prevent TinyMCE from removing span elements

Here is the problem demonstration
You can try it here: http://fiddle.tinymce.com/SLcaab
This is TinyMCE default configuration
less all the plugins
with extended_valid_elements: "span"
1 - Open the Html Source Editor
2 - Paste this html into the Html Source Editor:
<p><span>Hello</span></p>
<p>Google 1</p>
<p>Google 2</p>
3 - Click update in the Html Source Editor to paste the html in the editor
4 - Remember there is a span around 'Hello'.
5 - Place your cursor just before Google 2 and press backspace (the two links should merge inside the same paragraph element).
6 - Look at the resulting html using the Html Source Editor.
Result (problem): No more span in the html document even though we added 'span' to the extended_valid_elements in the TinyMCE settings.
Note: I removed all the plugins to make sure the problem is at the core of TinyMCE.
Edit 1 - I also tried: valid_children : "+p[span]" - still does not work
Edit 2: Only reproduced on WebKit (OK on Firefox and IE)
Insert extended_valid_elements : 'span' into tinymce.init:
tinymce.init({
selector: 'textarea.tinymce',
extended_valid_elements: 'span',
//other options
});
I have the same problem and I find solutions. Tiny MCE deleted SPAN tag without any attribute. Try us span with class or another attribute for example:
<h3><span class="emptyClass">text</span></h3>
In TinyMCE 4+ this method good work.
Tinymce remove span tag without any attribute. We can use span with any attribute so that it is not removed.
e.g <span class="my-class">Mahen</span>
Try this for 3.5.8:
Replace cleanupStylesWhenDeleting in tiny_mce_src.js (line 1121) with this::
function cleanupStylesWhenDeleting() {
function removeMergedFormatSpans(isDelete) {
var rng, blockElm, wrapperElm, bookmark, container, offset, elm;
function isAtStartOrEndOfElm() {
if (container.nodeType == 3) {
if (isDelete && offset == container.length) {
return true;
}
if (!isDelete && offset === 0) {
return true;
}
}
}
rng = selection.getRng();
var tmpRng = [rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset];
if (!rng.collapsed) {
isDelete = true;
}
container = rng[(isDelete ? 'start' : 'end') + 'Container'];
offset = rng[(isDelete ? 'start' : 'end') + 'Offset'];
if (container.nodeType == 3) {
blockElm = dom.getParent(rng.startContainer, dom.isBlock);
// On delete clone the root span of the next block element
if (isDelete) {
blockElm = dom.getNext(blockElm, dom.isBlock);
}
if (blockElm && (isAtStartOrEndOfElm() || !rng.collapsed)) {
// Wrap children of block in a EM and let WebKit stick is
// runtime styles junk into that EM
wrapperElm = dom.create('em', {'id': '__mceDel'});
each(tinymce.grep(blockElm.childNodes), function(node) {
wrapperElm.appendChild(node);
});
blockElm.appendChild(wrapperElm);
}
}
// Do the backspace/delete action
rng = dom.createRng();
rng.setStart(tmpRng[0], tmpRng[1]);
rng.setEnd(tmpRng[2], tmpRng[3]);
selection.setRng(rng);
editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
// Remove temp wrapper element
if (wrapperElm) {
bookmark = selection.getBookmark();
while (elm = dom.get('__mceDel')) {
dom.remove(elm, true);
}
selection.moveToBookmark(bookmark);
}
}
editor.onKeyDown.add(function(editor, e) {
var isDelete;
isDelete = e.keyCode == DELETE;
if (!isDefaultPrevented(e) && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
e.preventDefault();
removeMergedFormatSpans(isDelete);
}
});
editor.addCommand('Delete', function() {removeMergedFormatSpans();});
};
put an external link to tiny_mce_src.js in your html below the tiny_mce.js
It's possible to use the work around by writing it as a JavaScript script which prevents WYSIWIG from stripping empty tags. Here my issue was with including Font Awesome icons which use empty <i> or <span> tags.
<script>document.write('<i class="fa fa-facebook"></i>');</script>
In the Tinymce plugin parameters enable:
Use Joomla Text Filter.
Be sure your user group have set "No filtered" Option in global config > text filters.
Came across this question and was not happy with all the provided answers.
We do need to update wordpress at some point so changing core files is not an option. Adding attributes to elements just to fix a tinyMCE behaviour also doesn't seem to be the right thing.
With the following hook in the functions.php file tinyMCE will no longer remove empty <span></span> tags.
function tinyMCEoptions($options) {
// $options is the existing array of options for TinyMCE
// We simply add a new array element where the name is the name
// of the TinyMCE configuration setting. The value of the array
// object is the value to be used in the TinyMCE config.
$options['extended_valid_elements'] = 'span';
return $options;
}
add_filter('tiny_mce_before_init', 'tinyMCEoptions');
I was having same issue. empty SPAN tags are being removed. The solution i found is
verify_html: false,
Are you running the newest version of TinyMCE? I had the opposite problem - new versions of TinyMCE would add in unwanted span elements. Downgrading to v3.2.7 fixed the issue for me, that might also work for you if you are willing to use an old version.
Similar bugs have been reported, see the following link for bugs filtered on "span" element:
http://www.tinymce.com/develop/bugtracker_bugs.php#!order=desc&column=number&filter=span&status=open,verified&type=bug

how to determine if the browser supports selectionStart if there is no text selected

This code will return true if the browser supports selectionStart and some text is selected, but if no text is selected it returns false (even on browsers that support it):
if (el.selectionStart) {
}
How do you determine if the property is available regardless of whether text happens to be selected?
Thanks
Further googling revealed the answer:
if (el.selectionStart != undefined) {
}
Hopefully this will help you. I tested it on an old Android 4.2 (which returns false) and Chrome (which returns true).
function selectionSupport() {
var input = document.createElement("input");
input.setAttribute('value', '111');
input.selectionStart = 1;
input.selectionEnd = 2;
return (input.selectionStart === 1 && input.selectionEnd === 2);
}
var selectionIsSupported = selectionSupport();