Is there any way to detect with JavaScript/jQuery if an element is strike-through and underlined.
So let's say we have:
<u><s>text here.</s>other text here.</u>
Is it possible to detect if the text within <s>
is also underlined?
*Ideally, it would not be allowed to look if <u>
has any <s>
children.
I've been toying around with it and it seems peculiar that both styles use the same CSS property, which in turn makes me wonder how it even works in the first place.
To make my problem clearer:
I'm playing around with a self-made wysiwyg editor, for usability reasons I'm trying to implement a listener on the text which alters (lights up) editing buttons. e.g. when a part of text is bold the "B" button changes to an active state. I'm currently handling this by getting the element at the cursor and checking if the element is bold or inherits it.
The problem with underline and striketrough is that they are neither overwriting the text-decoration attribute of each other, and are not visible in css
when I put the cursor on a underlined text-fragment, the text-decoration
property only shows as underline
, while the text is both underline
and line-through
. In such situations I cannot know what the exact relation is between the <u>
element and the <s>
element; the <s>
element could be 100 parents back as far as I could know.
A lot of text, but I hope it kinda clears up my situation.
Is there any way to detect with JavaScript/jQuery if an element is strike-through and underlined.
So let's say we have:
<u><s>text here.</s>other text here.</u>
Is it possible to detect if the text within <s>
is also underlined?
*Ideally, it would not be allowed to look if <u>
has any <s>
children.
I've been toying around with it and it seems peculiar that both styles use the same CSS property, which in turn makes me wonder how it even works in the first place.
To make my problem clearer:
I'm playing around with a self-made wysiwyg editor, for usability reasons I'm trying to implement a listener on the text which alters (lights up) editing buttons. e.g. when a part of text is bold the "B" button changes to an active state. I'm currently handling this by getting the element at the cursor and checking if the element is bold or inherits it.
The problem with underline and striketrough is that they are neither overwriting the text-decoration attribute of each other, and are not visible in css
when I put the cursor on a underlined text-fragment, the text-decoration
property only shows as underline
, while the text is both underline
and line-through
. In such situations I cannot know what the exact relation is between the <u>
element and the <s>
element; the <s>
element could be 100 parents back as far as I could know.
A lot of text, but I hope it kinda clears up my situation.
Share Improve this question edited Oct 19, 2014 at 23:20 David Thomas 254k53 gold badges381 silver badges419 bronze badges asked Oct 19, 2014 at 22:34 RebirthRebirth 1,0118 silver badges14 bronze badges 5-
You can insert it in any invisible element and check for
$('u s').length
in it – Cheery Commented Oct 19, 2014 at 22:37 -
what if the bination is
<s><u></u></s>
or even something like<s><div><u></u></div><p><u></u></p></s>
(just to cover my bases). – Rebirth Commented Oct 19, 2014 at 22:39 - @Rebirth Check my answer. It works even if style is provided through CSS. – redV Commented Oct 19, 2014 at 23:00
-
@Rebirth can you just walk all over the parents and check their
text-decoration
s? – Cheery Commented Oct 19, 2014 at 23:10 -
I probably could but I'm not sure that's a smart move with
R
posibilities – Rebirth Commented Oct 19, 2014 at 23:12
3 Answers
Reset to default 5Here is the robust way of doing it. @Cheery answer works well but it fails if italic or underline or any other font-style provided through CSS. Credit is given to Tim Down for his numerous answers for these kind of questions.
function checkState(element, check) {
var doc = document;
var text = doc.getElementById(element);
if (doc.body.createTextRange) { // ms
var range = doc.body.createTextRange();
range.moveToElementText(text);
range.select();
} else if (window.getSelection) { // moz, opera, webkit
var selection = window.getSelection();
var range = doc.createRange();
range.selectNodeContents(text);
selection.removeAllRanges();
selection.addRange(range);
}
var range, checked = false;
if (window.getSelection) {
var sel = window.getSelection();
if (sel && sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
document.designMode = "on";
sel.removeAllRanges();
sel.addRange(range);
}
}
if (document.queryCommandState) {
checked = document.queryCommandState(check);
}
if (document.designMode == "on") {
document.designMode = "off";
}
if (window.getSelection) {
if (window.getSelection().empty) { // Chrome
window.getSelection().empty();
} else if (window.getSelection().removeAllRanges) { // Firefox
window.getSelection().removeAllRanges();
}
} else if (document.selection) { // IE?
document.selection.empty();
}
return checked;
}
alert(checkState('c', 'underline')); // italic, bold etc..
var str = '<u><s>text here.</s>other text here.</u>';
var el = $('<div>').html(str);
alert($('u s', el).length);
what if the bination is
or even something like
so what, check inverse too..
var str = '<s><div><u></u></div><p><u></u></p></s>';
var el = $('<div>').html(str);
alert($('u s', el).length || $('s u', el).length);
if the initial string is not a valid html then you do not know how some browsers will behave at its output.
ps: made some simple example, by click..
$(function(){
$('.wrapper').on('click', '*', function() {
var styles = ['line-through', 'underline'], counter = [0, 0], tags = ['S', 'U'];
$(this).parentsUntil('.wrapper').andSelf().each(function() {
var current = $(this).css('text-decoration'), $tag = $(this)[0];
$.each(styles, function(index, style) {
if (current.indexOf(style) > -1 || $tag.tagName == tags[index]) counter[index] += 1;
});
});
var results = [];
if (counter[0] > 0) results.push('striked');
if (counter[1] > 0) results.push('underlined');
alert(results.join(' and '));
return false;
});
});
.strike {
text-decoration: line-through;
}
.underline {
text-decoration: underline;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div class='wrapper'>
<div class='strike'>
striked <u>underlined</u>
</div>
<div class='underline'>
underlined <s>striked</s>
</div>
</div>
A somewhat horrible approach, but the only way I could see that doesn't involve explicitly checking nesting, or relying on default CSS surviving any theming (<s>
won't always, necessarily, have text-decoration: line-through;
, similarly <u>
won't always, necessarily, have text-decoration: underline;
):
// the text-decoration styles you want to find:
var styles = ['line-through', 'underline'];
// finding all elements within the <body>, and
// filtering them:
var underlinedAndLineThrough = $('body *').filter(function() {
// caching because of re-use:
var self = $(this),
decor = self.css('text-decoration');
// if the 'text-decoration' style is found in the array of styles we're
// looking for:
if (styles.indexOf(decor) > -1) {
// we add that style as a class-name to the current element, and all
// descendants:
self.find('*').add(self).addClass(decor);
// we return the current element (to keep it in the collection):
return self;
}
// filtering again:
}).filter(function(){
// we keep the current element of the collection if it has all the css styles
// we're looking for:
return $(this).is('.' + styles.join('.'));
});
console.log(underlinedAndLineThrough);
JS Fiddle demo.
References:
- JavaScript:
Array.prototype.indexOf()
.Array.prototype.join()
.
- jQuery:
add()
.addClass()
.filter()
.find()
.is()
.