Prevent Chrome from wrapping contents of joined <p> with a <span> - javascript

I have observed an undesirable behaviour in Chrome that occurs when one joins two <p>'s by deleting the separation between them. Although the <p> tags are joined properly, Chrome wraps the right-most <p> tag's content with a <span>.
Edit: this happens for all block elements, not just p tags.
Example:
For example, when the separating </p><p> are deleted from the following block:
<div contenteditable="true"><p>p one.</p><p>p two.</p></div>
It becomes:
<div contenteditable="true"><p>p one.<span style="font-size: 16px; line-height: 1.44;">p two.</span></p>
Example in a fiddle: Chrome wrapping contents of joined <p> with a <span>.
Question:
Is there an easy way to prevent chrome from doing this? It results in horrible markup that I'd like very much to be rid of.

There is a way but you need to pro-actively set a few styles. The idea is to tell Chrome that the styles are already taken care of, so it doesn't need to add SPAN to meet the styles requirement.
basically, you need to add the chrome added styles to a span class under your contenteditable div ( see example below).
Edited fiddle
For you example:
I added an "edit" class to the contenteditable DIV
I added an .edit p, span class in the style
This becomes:
.edit {
border: 1px solid gray;
padding: 10px;
}
.edit p, span {
line-height: 1.44; font-size: 16px;
}
And the DIV:
<div contenteditable="true" class="edit">...</div>
Note that you normally don't need the font-size: 16px;. I needed to add this one because fiddle defines some font size in contenteditable. On a standalone page I didn't need it.
You need to apply this Chrome 'patch' to any elements where it happens (so if you need UL, OL... then add what is needed following my example logic above)

I know it is not really an answer to solve it, but a hint how it could be fixed (but it is to long to be a comment to Petah question how i would solve it)
in general you would check when such bugs could happen. for the case of the span creation you would listen to all keydown and keypress events and check if the key is the backspace/delete key or for every key that inserts chars if it is a real selection.
if this is the case then you need to check the current selection (either the position of the insert mark, or the real selection) then you know which is the next following text-element or node. then you need to check the in the next following keypress and keyup if there is a span created directly after your insert mark. depending on the browser bug you need some further checking. if there is one create unwrap its content again. additionale Mutation events and helper attributes could be used.
But i need to say that i gave up in doing this myself and switched over to ckeditor 4. most of the it's features i don't need and it is a really big library. but cause of the huge number of such bugs i did not see another solution for me.
EDIT
Here an update of the js fiddle that shows the idea with a Mutable event:
http://jsfiddle.net/THPmr/6/
But that is not bullet proofed, it is just to show how it could be achived ( only tested in chrome 27.0.1422.0, and probably would not work if more then one text element is contained in the second p )

Here is my take on removing the extra spans
document.querySelector('[contenteditable=true]')
.addEventListener('DOMNodeInserted', function(event) {
if (event.target.tagName == 'SPAN') {
event.target.outerHTML = event.target.innerHTML;
}
});

The CSS is influencing how the markup is made inside contenteditable:
div, pre {
border: 1px solid gray;
padding: 10px;
line-height: 1.44;
}
Delete the line-height line and the problem doesn't occur any more.
There are in general several bugs with contenteditable related to default styling : How to avoid WebKit contentEditable copy-paste resulting in unwanted CSS?
EDIT JsFiddle IS indirectly influencing this (tinkerbin behaves differently) because of its' CSS (normalize.css). Try this:
Run your fiddle
Inspect a <p>
Disable all font-size declarations in the CSS stack - including your line-height
do the backspace
there is no inline span
Solution 1 : Use classes and id's.
Don't declare font-size for p or div but for p.main-content, or more simply, .main-content.
If the font-size of your elements inside contenteditable is coming from the browsers' internal default CSS then Chrome won't add extra markup/inline styling.
Solution 2 : Use a Sanitizer.
I'd personally go with #1 as it's never a good practice to specify font-sizes and typo in so generic tags.

The best way I found so far is to listen to DOMNodeInserted and check the tagName. If it is a span, you can remove the tag and but leave the contents. This also keeps the cursor at the correct place.
function unwrap(el, target) {
if ( !target ) {
target = el.parentNode;
}
while (el.firstChild) {
target.appendChild(el.firstChild);
}
el.parentNode.removeChild(el);
}
var AutoFix = true;
document.getElementById('editable')
.addEventListener('DOMNodeInserted', function(ev) {
if ( !AutoFix ) {
return;
}
if ( ev.target.tagName=='SPAN' ) {
unwrap(ev.target);
}
});
I've added a boolean 'AutoFix' so you can disable the automatic dom changes when you do need to insert a span, since this event fires on any dom change. E.g. if you have a toolbar that allows the user to insert something like <span class="highlight">...</span>.
The code has no side effects in IE or FireFox as far as I can see.

This irritated me as well, but I found a solution that works well enough for now.
$('#container span').filter(function() {
$(this).removeAttr("style");
return $(this).html().trim().length == 0;
}).remove();
I simply remove the style tag from the span element and remove it altogether if it's empty. You could probably filter based on the attribute style, but as I'm already doing a loop to check to remove empty spans, I thought it was best to do both at the same time.
It does create a flicker for a microsecond when chrome first tries to insert the style inherited for the span, but you only see that once immediately after deletion.
It isn't perfect, but it's quick and concise.

Found this link from a comment posted on someone's blog:
(Fixed bug where the latest WebKit versions would produce span element…)
https://github.com/tinymce/tinymce/commit/8e6422aefa9b6cc526a218559eaf036f1d2868cf

Please see the answers here: https://stackoverflow.com/a/24494280/2615633
To fix the problem you may just use this plugin: jquery.chromeinsertfix

After several attempts of using provided solutions, I came up with this script:
var content = obj.textContent;
obj.innerHTML = '';
obj.textContent = content;
When someone pastes a text with html encoded chars, putting it to innerHTML results with a valid html tags, that is why I decided to purge innerHTML content before placing content into obj

Related

On IE11 Windows 8.1, button remains highlighted after clicking

I'm working on a (relatively) complex web application, and encountering a very specific issue. On the specific OS and Browser mentioned in the title, in one of the forms that shows up, when some buttons are clicked, they remain "highlighted" as if the mouse were still hovering over them, even when the mouse leaves the button element or if the user clicks on a separate element on the page. It looks like this:
(the "First Name", "Last Name", etc. elements are the buttons)
The specific behavior of these buttons is that when they are clicked, they put a specific bit of text into the text form shown, then focus the text form. This is done using some standard jQuery functions (.val(), .focus(), etc.) On any OS/browser pair I have seen other than Win8.1/IE11, this does not happen. (it doesn't happen on Win7/IE11 even!) And as far as I can tell, there are no other handlers attached to the buttons than click, and the only styles that seem to be applied have to do with size, color, and text.
Honestly, I'm completely stumped about this behavior. I've even tried doing things as making sure to call .blur() on the button, trigger mouseout events, etc. and nothing seems to make a dent in this. The only thing that seems to cause the highlighting to go away is to click very close to the buttons, but not on them, or to drag-select some text.
EDIT December 7, 2015: This has been on my backburner for a while with other more-pressing issues to deal with. But I'm going to do my best to provide a nice update with more information so that this can hopefully be resolved. (assuming this isn't some browser bug in the specific version of IE on Windows 8.1)
I have verified that the only event handler attached to the button is an onclick handler defined in the HTML itself by checking what IE11's dev tools see as the event handlers on the element:
<input type="button" value="${someValue}" onclick="autoText('${token}');"/>
autotext is a very simple function that does what is described above, but here is the actual source code for it:
function autoText(token) {
if(null != lastFocus) {
var str = lastFocus.val(),
tokenStr = '$\{' + token + '\}',
newStr = str.substring(0, pos) +
tokenStr + str.substring(pos, str.length);
lastFocus.val(newStr);
var lastPos = pos + tokenStr.length;
lastFocus.focus();
lastFocus.caret(lastPos);
lastFocus.keypress();
}
where lastFocus is set to the text input element that was last focused and pos is set to where the caret is in the text input element.
The button that has the onclick listener is in the following hierarchy, as given to me by Chrome: html -> body -> div -> div#templateFormDiv -> form#prefsEmailTemplatesSave -> table -> tbody -> tr -> td -> input (where -> indicates it is the parent)
html has the classes mod-js mod-canvas mod-no-touch mod-postmessage mod-contenteditable mod-cookies mod-filereader mod-formvalidation mod-fileinput mod-formattribute mod-getusermedia
body has no CSS classes
div has ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ui-dialog-buttons ui-draggable ui-resizable
div#templateFormDiv has the classes hidden preferencesDialog ui-dialog-content ui-widget-content
form#prefsEmailTemplatesSave has the class savePrefsForm
table, tbody, tr, td, and input don't have any classes associated with them.
The CSS rules for all the listed classes, ids, and tags are as follows:
*{padding: 0; margin: 0;}
body {
margin:0;
padding:0;
height:100%;
font-family:'Lucida Grande',Verdana,Arial,Sans-Serif;
min-height: 100%;
font-size: 62.5%;
color: #333;
}
form {
margin:0;
padding:0;
}
.hidden {
display: none;
}
All other classes, as far as I can tell, are included as part of bits of jQuery or are there as markers for DOM queries. (e.g.: savePrefsForm)
div#templateFormDiv has a dialog attached to it via a jQuery dialog() call.
form.savePrefsForm is selected and all found elements have an ajaxForm attached to them via jQuery. In a similar vein, #prefsEmailTemplatesSave is selected and submitted if the #templateFormDiv dialog has its save button pressed and it passes some validation logic.
The last thing I can think of to note here is that there is a TinyMCE editable text area next to where the buttons are. No parent/child relationship, but rather a sibling one.
I'll try to think of any further details that matter and include them if I do, otherwise I'll just answer any further questions that anyone has about what is going on.
Have same issue on IE 9-11 Windows 8.1-10. Every button that not cause postback, remains highlighted after click. On the other sites buttons work properly, so it was clearly my issue. I found it because CSS selector "hover" in my styles:
.navigationLink:hover {
}
I have changed it to:
a.navigationLink:hover {
}
and now buttons highlighting works properly. I can't understand what kind of magic is it. Any help would be appreciated.

Line clamping using a class element and Javascript

I have a PHP script that outputs data. It is all conveniently wrapped inside a p class.
It outputs the same data and same class multiple times, so there are like 6 blocks of text, each block being wrapped inside p class.
I need to reduce each block to 3 lines using any method possible. I already tried using PHP in various ways to no avail.
I came across Clamp.js which looked great. The only issue is, it will only work using ID. I can change the p class tags to p id, however, they'd all have to share the same ID, which, obviously, won't work.
Here's the current code I've tried:
var module = document.getElementsByClassName("clampjs");
$clamp(module, {clamp: 1});
And the HTML (times 6):
<div class="headtab">
Forum title<p class="bold">Posted By:</p> username <p class="bold">In:</p> category</div>
<div class="maintext">
<p class="clampjs">TEXT I WANT TO BE CLAMPED</p>
</div>
Like I say, it works fine when I use an ID, but obviously, only for the first block of text as the ID HAS to stay the same, that's why I'm using p class.
Sadly, what I've tried above doesn't work at all. Does anybody know a little fix for this script, or perhaps a different script that will clamp objects using a class element? Jquery is acceptable too.
Jsfiddle
Working code thanks to the accepted answer:
$(document).ready( function() {
$('.clampjs').css({ //changes the css of the clicked content.
'max-height':'75px', //give what ever height you want.
'overflow':'hidden'
});
});
this could be easily done with just editing your css
$('.clampjs').click( function() {
$(this).css({ //changes the css of the clicked content.
'height':'100px', //give what ever height you want.
'overflow':'hidden'
});
});
just now tested in my page it works...

How can I style a part of text which is between two <br> elements?

I'm trying to add CSS to a part of text from an XML rss feed (and I can't change it).
And what about using Javascript?
The problem is that I want it smaller with right-alignment.
The part of text I'm talking about is "This offer is valid till ##/##/##".
here is the problem:
http://jsfiddle.net/WC5F8/1/
.itemContent br {
text-align:right;
font-size: 0.5em;
}
This is impossible with just CSS, all the text in that div element is character data (CDATA) interspersed with the br elements. With CSS you can only target entire elements and their entire contents. If you cannot change or rewrite the HTML, you cannot restyle a subset of the CDATA of a single element.
With Javascript it's hard, since you have the same limitations of not being able to select entire elements. You'd have to start splitting content by arbitrary criteria, such as hoping there's always the same number of <br> elements. The solution would be inherently unstable.
The problem is that JavaScript is processed asynchronously. In your code, jQuery will first look for any .itemContent elements (but will not find any). Then FeedEk loads the RSS file and inserts it's contents to the DOM. That's why your code doesn't work, you look for the elements too early.
You can only access the .itemContent elements after jQuery finished loading and processing the RSS. Unfortunately FeedEk doesn't provide a callback method, so you don't know when it finished. There is a workaround when you use jQuery's ajaxSetup. FeedEk internally uses jQuery's Ajax functions, which provide a way to invoke a function after the Ajax request and it's processing finished.
I tested this with the code you provided and it worked for me. Just replace your own FeedEk call:
$(document).ready(function () {
jQuery.ajaxSetup({
complete: function () {
$('.itemContent').each(function(i, element) {
$($(element).find('br')[0].nextSibling)
.wrap('<div class="offervalid"/>')
.before('<br><br><br><br><br>'); // if you really need <br>s
});
}
});
$('#divRss').FeedEk({
FeedUrl: 'http://dimmituquando.blogspot.com/feeds/posts/default',
MaxCount: 10
});
});
This is possible with just CSS, without Javascript, if you are willing to give up on hiding the <br>. That is to say, don't hide all the <br>s in the div, only the last one.
li > div > br:last-child {
display:none;
}
.itemContent {font-size:.5em}
.itemContent::first-line {font-size:2em}
The trick is to halve the font size for the whole div, and then restore the first part of the div (up to the first br) to the original size.
Updated fiddle
Using javascript, you would need to modify the feed's html to wrap that piece of text in a div so that you can style it.
http://jsfiddle.net/WC5F8/2/
$(".itemContent").html(function(i,html){
return html.replace(/(offerta valida fino al \d+\/\d+\/\d+)/i,"<div class='offervalid'>$1</div>");
});
css:
.itemContent .offervalid {
float:right;
font-size: 0.5em;
}
Note, i think there's a typo in your sample code. Offer valid till 2031?
try this, using inline-style-tags:
<span style="text-align:right; font-size: 0.5em;">This offer is valid till ##/##/##</span>

How do I change the CSS of child of an a-element

I'm getting a bit confused with my work.
My Problem is, I want to change a Element that's covered with an Element.
the HTML-structure:
<ul class="calendar-content">
<li>
<a href="#day02" onClick="popup('02');">
<span class="day"><strong>02</strong></span>
<span class="content" id="content">
<small>02</small>
<strong>Inhalt Tag 01</strong>
</span>
</a>
</li>
The user is only seeing the first span(class=day). After a click on the link the
second span(class=content) should "appear".
My first idea was:
.calender-content .a:visited .content{
display:block;
}
Or this one:
//.calender .content got margin-left:120px and is out of view
.calender-content .a:visited .content{
margin-left:0px;
}
But nothing happens. Maybe it isn't valid but I saw stuff like this before.
I just want to display the second span after the link is visited.
Either setting the display style to block or changing the margin to 0 and animate that with
-transition.
But nothing the styles doesn't appear on the span element.
If there's a way arround in CSS, that would be great. So I don't have to use JS.
Cheers Dan
Should be:
.calendar-content a:visited .content { display: block; }
You have ".a", which means "elements with class 'a'", not "elements with tag name 'a'" :-)
Now the thing is, I'm not sure that ":visited" will be "true" (or whatever the appropriate term would be) if your <a> tag isn't really something that "visits" another URL. If that's the case, then your event handler can add a class to the anchor. If your event handler does allow the anchor to move to the label, then I think it should work.
Your first problem is the . notation that means "class" and not "tag". See #Pointy's answer for details and fix.
But then, you shouldn't rely on :visited. Indeed, it can be used for history sniffing, and browsers will probably end up removing support for most CSS properties that change layout (such as display), just like Firefox already does.
A pure CSS solution would be to use the :target pseudo-class. However, it is not supported in IE ≤ 8. If it is a requirement, you should go to JS.
Any way you choose, you should refactor your markup. The link should not contain something it toggles. <small> is a good example of an awful markup-as-presentation use. Use a classed span.

HTML elements for JavaScript hooks

Most of my development life, I have done a JavaScript generated button like so:
<span>Open/hide</span>
With CSS like
span {
cursor: pointer;
}
This seemed to work for me, and IMO, it looks and seems better than
open/hide
However, I'm starting to think people might use links because they are better accessible to screen readers. It also makes sense that the browser will allow you to tab to a link - but not necessarily a span with a CSS style (like my previous example).
Is there a way to get the best of both worlds? That is, a button that can be tabbed to, accessible to screen readers and also not implying a semantic link to another document, and not having to use hacky ways to stop the link from going anywhere?
Note: These are for JS inserted buttons only, not existing links of which their behavior is changed with JS.
That is, a button that can be tabbed to, accessible to screen readers and also not implying a semantic link to another document
Yes, and curiously enough it's called just that: <button>. Or <input type="button"> if you only need text content. You can then add a load of CSS to it to stop it looking like a default form button if you prefer.
The one problem is IE, which adds an extra couple of pixels of unremovable padding to button widgets, and moves the content of the button down and to the right one pixel when clicked. Often this doesn't matter. If you don't need zero padding you could also compensate by adding padding on all browsers except IE.
Another semantically sound possibility is to use an <input type="image">, although that obviously requires the content to be an image. Relying on the alt text instead doesn't work due to IE's rendering of broken image icons.
Whilst buttons are semantically by far the most appropriate element, if you don't want this styling trouble you can continue to use a span or other meaningless element (like SO does), but at least improve the keyboard accessibility by giving it a tabindex value. It will then be focusable like a link, though unfortunately you need extra scripting if you want to make it activatable from keyboard (catch at least keypress codes 13 and 32). You can also label such an element as a button with ARIA for accessibility, athough to be honest I'm not convinced this really does anything much useful for today's toolset.
Sometimes when the action is related to another element on the page, such as with the suggested ‘open/hide’ button, it seems legitimate to me to use an internal link to that element. (With a JS-assigned onclick though, not any of that inline JS or horrific javascript: pseudo-URLs.)
.hidden { display: none; }
open/hide
<div id="foo"> blah </div>
for (var i= document.links.length; i-->0;)
if (document.links[i].className==='toggler')
document.links[i].onclick= toggle;
function toggle() {
var el= document.getElementById(this.hash.substring(1));
el.className= el.className==='hidden'? 'hidden' : '';
}
or similar idiom in your library of choice. This will do something useful in non-JavaScript browsers; you can also add a rule to check the current location's hash, so that if someone opens your show-link in a new tab that document will be showing the element in question.
It seems doing
<span tabIndex="n">foo</span>
allows you to tab it. However, pressing enter while it's focused doesn't simulate clicking it. Which I guess is easily remedied by putting a keydown event on it as well.
I would say that the button fits your requirements ...
<input type="button" class="js_button" value="Javascript Button" />
CSS:
.js_button, .js_button:active, js_button:focus {
background-color: #FFF;
border: none;
margin: 0 0;
padding: 0 0;
}
Buttons can be tabbed to, are semantic, automatically have tab indexes and keypress actions, and do not imply links to other documents. The only difficulty is removing the mousedown animation -- I'll look around and see if there's anything out there for removing that animation without hacks.
You can link to any object in the page if you provide the id or the name of the element.
For example:
https://stackoverflow.com/questions/1659137/html-elements-for-javascript-hooks#comments-1659137
HTML elements for JavaScript hooks

Categories

Resources