TinyMCE steals the focus when calling execCommand - tinymce

I have a bunch of inputs on my HTML page, plus a textarea which is replaced by a TinyMCE editor. There are various scenarios where this page is loaded and every time one of the inputs must get the focus. But when the TinyMCE is initialized, it just steals the focus. I narrowed down the problem to an execCommand call which sets the default font size in TinyMCE.
The issue can be reproduced in this simplified code:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/5/tinymce.min.js" referrerpolicy="origin"></script>
<script>
tinymce.init({
selector: 'textarea',
setup: function(editor) {
editor.on('init', function() {
this.execCommand("fontSize", false, "14pt"); // <<---- This line causes the TinyMCE editor to steal the focus!
});
}
});
</script>
</head>
<body>
<input id="inp" />
<textarea>Hello, World!</textarea>
<script>
document.getElementById("inp").focus();
</script>
</body>
</html>
I have tested this in Firefox, Chrome, and Edge, and the same issue happened in all of them. Any idea how I can prevent this? I do not want to set the focus again once the TinyMCE is done initializing, since at that point the page has scrolled to the wrong spot.

I know I said I did not want to set the focus "again" once the TinyMCE is done initialization, but I ended up doing something similar to that. Instead of setting the focus at the bottom of the page, I moved the code inside the tinymce.init and also called $(document).scrollTop(0);. Here is the code:
tinymce.init({
selector: 'textarea',
setup: function(editor) {
editor.on('init', function() {
this.execCommand("fontSize", false, "14pt"); // <<---- This line causes the TinyMCE editor to steal the focus!
// Scroll to the top of the page.
$(document).scrollTop(0);
// Now set the focus.
document.getElementById("inp").focus();
});
}
});
I believe there is a bug in TinyMCE and I hope it gets fixed in one of the future revs. I also hope this workaround helps someone down the road.

While you are issuing the command to change the font size, you aren't actually setting a default font in the TinyMCE editor. You are firing those commands, but if there is any content to be loaded into the editor, it won't have this font information applied.
To set default font information in TinyMCE use CSS, either via the content_css or content_style configuration options:
https://www.tiny.cloud/docs/configure/content-appearance/#content_style
https://www.tiny.cloud/docs/configure/content-appearance/#content_css
Here are examples that show the differences between the two approaches.
In this example: https://fiddle.tiny.cloud/oAhaab
...commands to set the default font family and size are issued, but they aren't applied to the content that is then loaded into the editor. They are fired, but don't end up applying to content loaded into the editor.
Whereas,in this example: https://fiddle.tiny.cloud/nAhaab
...the default font information is applied to loaded content via CSS as expected.

Related

insert html code in TinyMCE document

I want to insert custom html code in document via code button (like this for example taken from bootstrap + some JS code):
<link rel="stylesheet" ref="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js" integrity="sha512-K1qjQ+NcF2TYO/eI3M6v8EiNYZfA95pQumfvcVrTHtwQVDG+aHRqLi/ETn2uB+1JqwYqVG3LIvdm9lj6imS/pQ==" crossorigin="anonymous"></script>
<script>
$(document).ready(function() {
console.log("Hello world");
});
</script>
I wan't this to be in the source code of the document (not in text) so it can be rendered properly.
I have tried many settings (it would be long list, I spent whole afternoon with this smile) but nothing works, i.e. code is stripped / changed when I close the code window and open again.
for the context, I use TinyMCE as editor for CMS and sometimes there is need to add extra style or javascript library
So I would be very grateful if somebody could post tinymce 4.2 init settings which allows this... or say if it's even possible
You may use the tinymce command mceInsertContent:
my_editor_instance.execCommand('mceInsertContent', ui, '<my>html</my>');

Magnific Popup - Popup disappearing on click

I've just recently implemented the 'Magnific Popup' and the popup comes up fine, however when I click an input box the entire popup disappears back to the parent page. On the examples shown on the plugin website, the entire dialog box is clickable until you click outside of that box.
I'm hoping its just something extremely simple I've missed, but it's still doing my head in.
I really appreciate any help I can get!
Thanks :)
If you're using "ajax" content type, you need to make sure that you've got only one root node.
http://dimsemenov.com/plugins/magnific-popup/documentation.html#ajax_type
E.g., this is correct contents of ajax file:
<div>
html content
<script src="something.js"></script>
</div>
Incorrect:
<script src="something.js"></script>
<div>
html content
</div>
Incorrect:
<div>
html content
</div>
<div>Another content</div>
Also make sure that closeOnContentClick is set to false http://dimsemenov.com/plugins/magnific-popup/documentation.html#closeoncontentclick
If, for whatever reason, you can't change the contents of ajax file, you may parse content in parseAjax callback, like described here (so the mfpResponse.data contains only one root node).
I can't reply yet (too low rep..) so adding it like this:
seems that this also counts for type: 'inline'. Safe to always wrap content by a div..
$.magnificPopup.open({
items: {
src: '<div>'+ html +'</div>'
},
type: 'inline',
closeOnContentClick: false
}, 0);
I had the same error.
Turned out to be a dumb mistake from my side, i had the same class on my opener and my inline div.
Open
<div id="popup" class="dialog mfp-hide"></div>
Of course they needed to be different classes like so:
Open
<div id="popup" class="dialog-box mfp-hide"></div>
Dmitry explains the problem here https://github.com/dimsemenov/Magnific-Popup/issues/34
Add modal:true in the magnificPopup:
$('.your_class').magnificPopup({
type: 'ajax',
modal:true
});

TinyMCE inside JavaScript Pop-up

I have got problem with TinyMCE when TinyMCE is in Pop-up. Look on my explanation of this problem.
This code is in my JSON pop-up
<!-- TinyMCE -->
<script type="text/javascript" src="../../Scripts/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "simple"
});
</script>
<!-- Gets replaced with TinyMCE, remember HTML in a textarea should be encoded -->
<textarea id="elm1" name="elm1" rows="8" cols="80" style="width: 80%">
Pełny opis...
</textarea>
<br />
When pop-up show first time you can see this editor
When pop-up show second time you can see this editor
In my opinion problem is here (only once is working this JS)
<script type="text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "simple"
});
</script>
In the second case you see the textarea html element. This is probably because of the fact that you didn't shut down tinymce correctly when closing the first pop-up.
What happened behind the curtain is that the html structures are gone, but tinymce still got the editor instance registred and won't open up a new one with the same id when you reopen the pop-up. Solution here is to shut down tinymce when closing the pop-up.
To shut down an editor instance use:
tinymce.execCommand('mceRemoveControl',true,'your_editor_id');
To reinitialize use
tinymce.execCommand('mceAddControl',true,'your_editor_id');
Tinymce takes as editor id the id of the source html element (your textarea). In case there is none "content" is the default.

:active pseudo-class doesn't work in mobile safari

In Webkit on iPhone/iPad/iPod, specifying styling for an :active pseudo-class for an <a> tag doesn't trigger when you tap on the element. How can I get this to trigger? Example code:
<style>
a:active {
background-color: red;
}
</style>
<!-- snip -->
Click me
<body ontouchstart="">
...
</body>
Applied just once, as opposed to every button element seemed to fix all buttons on the page. Alternatively you could use this small JS library called 'Fastclick'. It speed up click events on touch devices and takes care of this issue too.
As other answers have stated, iOS Safari doesn't trigger the :active pseudo-class unless a touch event is attached to the element, but so far this behaviour has been "magical". I came across this little blurb on the Safari Developer Library that explains it (emphasis mine):
You can also use the -webkit-tap-highlight-color CSS property in combination with setting a touch event to configure buttons to behave similar to the desktop. On iOS, mouse events are sent so quickly that the down or active state is never received. Therefore, the :active pseudo state is triggered only when there is a touch event set on the HTML element—for example, when ontouchstart is set on the element as follows:
<button class="action" ontouchstart=""
style="-webkit-tap-highlight-color: rgba(0,0,0,0);">
Testing Touch on iOS
</button>
Now when the button is tapped and held on iOS, the button changes to the specified color without the surrounding transparent gray color appearing.
In other words, setting an ontouchstart event (even if it's empty) is explicitly telling the browser to react to touch events.
In my opinion, this is flawed behaviour, and probably dates back to the time when the "mobile" web was basically nonexistent (take a look at those screenshots on the linked page to see what I mean), and everything was mouse oriented. It is interesting to note that other, newer mobile browsers, such as on Android, display `:active' pseudo-state on touch just fine, without any hacks like what is needed for iOS.
(Side-note: If you want to use your own custom styles on iOS, you can also disable the default grey translucent box that iOS uses in place of the :active pseudo-state by using the -webkit-tap-highlight-color CSS property, as explained in the same linked page above.)
After some experimentation, the expected solution of setting an ontouchstart event on the <body> element that all touch events then bubble to does not work fully. If the element is visible in the viewport when the page loads, then it works fine, but scrolling down and tapping an element that was out of the viewport does not trigger the :active pseudo-state like it should. So, instead of
<!DOCTYPE html>
<html><body ontouchstart></body></html>
attach the event to all elements instead of relying on the event bubbling up to the body (using jQuery):
$('body *').on('touchstart', function (){});
However, I am not aware of the performance implications of this, so beware.
EDIT: There is one serious flaw with this solution: even touching an element while scrolling the page will activate the :active pseudo state. The sensitivity is too strong. Android solves this by introducing a very small delay before the state is shown, which is cancelled if the page is scrolled. In light of this, I suggest using this only on select elements. In my case, I am developing a web-app for use out in the field which is basically a list of buttons to navigate pages and submit actions. Because the whole page is pretty much buttons in some cases, this won't work for me. You can, however, set the :hover pseudo-state to fill in for this instead. After disabling the default grey box, this works perfectly.
Add an event handler for ontouchstart in your <a> tag. This causes the CSS to magically work.
<a ontouchstart="">Click me</a>
This works for me:
document.addEventListener("touchstart", function() {},false);
Note: if you do this trick it is also worth removing the default tap–highlight colour Mobile Safari applies using the following CSS rule.
html {
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
As of Dec 8, 2016, the accepted answer (<body ontouchstart="">...</body>) does not work for me on Safari 10 (iPhone 5s): That hack only works for those elements that were visible on page load.
However, adding:
<script type='application/javascript'>
document.addEventListener("touchstart", function() {}, false);
</script>
to the head does work the way I want, with the downside that now all touch events during scrolling also trigger the :active pseudo-state on the touched elements. (If this is a problem for you, you might consider FighterJet's :hover workaround.)
//hover for ios
-webkit-tap-highlight-color: #ccc;
This works for me, add to your CSS on the element that you want to highlight
Are you using all of the pseudo-classes or just the one? If you're using at least two, make sure they're in the right order or they all break:
a:link
a:visited
a:hover
a:active
..in that order. Also, If you're just using :active, add a:link, even if you're not styling it.
For those who don't want to use the ontouchstart, you can use this code
<script>
document.addEventListener("touchstart", function(){}, true);
</script>
I've published a tool that should solve this issue for you.
On the surface the problem looks simple, but in reality the touch & click behaviour needs to be customized quite extensively, including timeout functions and things like "what happens when you scroll a list of links" or "what happens when you press link and then move mouse/finger away from active area"
This should solve it all at once: https://www.npmjs.com/package/active-touch
You'll need to either have your :active styles assigned to .active class or choose your own class name. By default the script will work with all link elements, but you can overwrite it with your own array of selectors.
Honest, helpful feedback and contributions much appreciated!
I tried this answer and its variants, but none seemed to work reliably (and I dislike relying on 'magic' for stuff like this). So I did the following instead, which works perfectly on all platforms, not just Apple:
Renamed css declarations that used :active to .active.
Made a list of all the affected elements and added pointerdown/mousedown/touchstart event handlers to apply the .active class and pointerup/mouseup/touchend event handlers to remove it. Using jQuery:
let controlActivationEvents = window.PointerEvent ? "pointerdown" : "touchstart mousedown";
let controlDeactivationEvents = window.PointerEvent ? "pointerup pointerleave" : "touchend mouseup mouseleave";
let clickableThings = '<comma separated list of selectors>';
$(clickableThings).on(controlActivationEvents,function (e) {
$(this).addClass('active');
}).on(controlDeactivationEvents, function (e) {
$(this).removeClass('active');
});
This was a bit tedious, but now I have a solution that is less vulnerable to breakage between Apple OS versions. (And who needs something like this breaking?)
A solution is to rely on :target instead of :active:
<style>
a:target {
background-color: red;
}
</style>
<!-- snip -->
<a id="click-me" href="#click-me">Click me</a>
The style will be triggered when the anchor is targeted by the current url, which is robust even on mobile. The drawback is you need an other link to clear the anchor in the url. Complete example:
a:target {
background-color: red;
}
<a id="click-me" href="#click-me">Click me</a>
<a id="clear" href="#">Clear</a>
No 100% related to this question,
but you can use css sibling hack to achieve this as well
HTML
<input tabindex="0" type="checkbox" id="145"/>
<label for="145"> info</label>
<span> sea</span>
SCSS
input {
&:checked + label {
background-color: red;
}
}
If you would like to use pure html/css tooltip
span {
display: none;
}
input {
&:checked ~ span {
display: block;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<style>
a{color: red;}
a:hover{color: blue;}
</style>
</head>
<body>
<div class="main" role="main">
Hover
</div>
</body>
</html>

tinyMCE - source code editing in a textarea

I'm playing around with MCE, I was wondering if there was the possibility of letting the user enter source code into a post, much like the 101010 button in this form.
You'll need to add plugins: "code" to the initialization code as follows:
tinymce.init({
plugins: "code"
});
https://www.tinymce.com/docs/plugins/code/
The option exists. One of the optional buttons has 'html' written on it and can be used to go into HTML editing mode. You can see it in this full featured example - 6 places left of the top-right corner.
Try 'code' plugin along with tinymce.min.js
e.g.
<script src="~/Scripts/tinymce/tinymce.min.js"></script>
<script src="~/Scripts/tinymce/plugins/code/plugin.min.js"></script>
<script>
tinymce.init({
selector: 'textarea',
plugins: "code",
toolbar: "code" });
</script>