I'm trying to inject the ➕ emoji (acting as a button) next to each message on a website. Example:
This is what I'm currently doing:
contentscript.js:
document.getElementsByClassName("className").innerHTML = "➕";
This isn't showing anything. I also presume it won't show to the complete left; how can I do this?
If there is only one item in the DOM with the class name you want to add the item to you could do this
document.getElementsByClassName("className")[0].innerHTML += "➕";
Using the += operator will append the new value to the current value of the innerHTML
Otherwise you would have to loop over the collection of elements returned (see #Alex K comment above)
document.getElementsByClassName("className")[0].innerHTML += "<span class='icon'>➕</span>";
document.getElementsByClassName("icon")[0].addEventListener("click", clickFunction);
function clickFunction(){
alert("Clicked"+ this);
}
/* add whatever styles you need here */
.className {
position: relative;
padding-left: 20px;
}
.icon {
color: red;
position: absolute;
top: 0;
left: 0;
}
<div class="className">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam iaculis non quam non tristique. Cras ut imperdiet quam, pellentesque finibus nisl. Sed egestas dapibus turpis a rhoncus.</div>
Related
I want to get the index of matched string from the html to highlight the particular match in html.
The issue is I am using the tooltip with title in footnote link (which has footnote text). So.. when I am trying to highlight something in footnote it's highlighting in the footnote referenced tooltip.
Is there any way to skip the match of html attributes and jump to next match? (as I need the index of particular match so I can not use `$(selector).text();
please help me with this - below is the example of my code:
var selectedContent = $(selector).html();
var regex = new RegExp('/The text from footnote/', 'gi');
var indices = [];
while(result = regex.exec(selectedContent))
{
indices .push(result.index);
}
The regex is matching the text in footnote tooltip which is used as footnote reference.
My code sample is here. Please check it.
Try this:
var regex = new RegExp("(?!<[^>]+)" + textToHighlight + "(?![^<]+>)", 'gi');
var finalHtml = selectedContent.replace(regex, '<highlight class="highlight">'+textToHighlight+'</highlight>');
if(finalHtml)
$('#lipsumContainer').html(finalHtml);
[EDIT]
Here is a highlightText() function that searching for a string directly in textnodes, which means it won't affect attributes, however it won't find text if it's split between different elements.
In this example it will highlight selected text:
function highlightText(node, text) {
if (!node)
return;
if (node.nodeType == 3) { //process textnode
const index = node.data.indexOf(text);
if (index == -1)
return;
const textNodeMark = node.splitText(index),
textNodeAfter = textNodeMark.splitText(text.length),
mark = document.createElement("mark");
mark.appendChild(textNodeMark);
node.parentNode.insertBefore(mark, textNodeAfter);
} else {
for (let n of node.childNodes) {
if (n.tagName !== "MARK")
highlightText(n, text);
}
}
}
/* demo highlight selected text */
const container = document.getElementById("lipsumContainer");
container.addEventListener("click", e => {
const text = document.getSelection().toString().trim();
if (text === "")
return;
for(let m of container.querySelectorAll("mark"))
m.parentNode.replaceChild(m.firstChild, m); // remove previous marks;
container.normalize(); // join any split textnodes
highlightText(container, text); // add new highlighting
}, true);
$('#lipsum').on('mouseenter', '#_contentFoot1', function(){
var tooltipPosition = $(this).position();
var title = $(this).data('title');
var tooltipHtml = '<div class="tooltip">'+
'<span class="tooltiptext">'+title+'</span>'+'</div>';
$('body').append(tooltipHtml);
$('.tooltip').attr("style", "top: "+tooltipPosition.top+"px;left: "+tooltipPosition.left+"px;");
})
$('#lipsum').on('mouseleave', '#_contentFoot1', function(){
$('.tooltip').remove();
})
.tooltip .tooltiptext::after {
content: " ";
position: absolute;
top: 100%;
/* At the bottom of the tooltip */
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: black transparent transparent transparent;
}
.tooltip {
position: absolute;
display: inline-block;
border-bottom: 1px dotted black;
}
.tooltip .tooltiptext {
visibility: visible;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 150%;
left: 50%;
margin-left: -60px;
}
mark {
background-color: lightgreen;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="lipsumContainer">
<div id="lipsum">
<p><b>bold</b> <i>italic</i></p>
<p><b>bold</b> <i>italic</i></p>
<p>
Vivamus vel commodo nisl, sed maximus lectus. Donec semper suscipit porta. Ut facilisis turpis pellentesque purus laoreet sagittis. Donec at scelerisque dui. Nullam hendrerit eros et lacinia venenatis. Nullam sodales nulla sit amet est ultrices,
sit amet tempus risus consequat.<a id="_contentFoot1" href="#_foot1" data-toglggle="tooltip" data-title="The 1st footnote text"><sup>[1]</sup></a> Fusce suscipit ipsum vel dapibus sagittis. Nullam tellus nisl, egestas ut feugiat non, porttitor
eget erat. Suspendisse placerat dictum nulla non sollicitudin. Maecenas nec tortor felis. Donec id cursus ligula, a volutpat sapien.
</p>
</div>
<div class="footnotes">
<p id="_foot1">
[1] <span>The 1st footnote text</span>
</p>
</div>
</div>
In the example, I have create a variable countMatch to skip the first match.
https://jsfiddle.net/f1sbh7x6/
So I got some divs, which I split up with lettering.js. What this does is just splitting up an element into <span>s containing the single characters.
When I got a string with multiple words like "Hello World!", lettering.js will create a separate span for the space between the words. That span won't have a width, since its "empty" → there's no space between the words.
So theoretically I should be able to select those "empty" spans with span:blank (and manually setting a width for the space) since :blank selects whitespace aswell.
That didn't work tho.
So I tried using JavaScript, but even that failed.
I tried several methods:
$("span[class^='char']").each(function(){
// method 1:
this.innerHTML.trim();
// method 2:
$(this).text().trim();
// method 3:
$(this).text().replace(/\s/g, '');
// method 4:
$(this).text().replace(' ', '');
});
But all of those methods failed.
The selector isn't the problem. It selects every span I want it to.
Another method would just be to set a min-width for every span, which is pretty shabby tho and isn't always working nicely.
Anyone got an idea how I can get those "empty" <span>s to show as spaces?
Here's a link with a live example of the problem if you want to check it out.
Update: Removing display:inline-block from the span elements makes the space show up. I can't remove it tho, since the transform animation stops working properly without it.
You can use the :empty pseudo selector and add a space via content in CSS;
span:empty{
content:' ';
display: inline-block;
}
<span>A</span>
<span></span>
<span>B</span>
You can use letter-spacing to remove white space between the text.
<!DOCTYPE html>
<html>
<head>
<style>
div.a {
width: auto;
border: 1px solid black;
letter-spacing:0px
}
div.b {
width: 150px;
border: 1px solid black;
}
div.c {
width: 50%;
border: 1px solid black;
}
</style>
</head>
<body>
<h1>The width Property</h1>
<h2>width: auto (default)</h2>
<div class="a">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam semper diam at erat pulvinar, at pulvinar felis blandit. Vestibulum volutpat tellus diam, consequat gravida libero rhoncus ut. Maecenas imperdiet felis nisi, fringilla luctus felis hendrerit sit amet. Pellentesque interdum, nisl nec interdum maximus, augue diam porttitor lorem, et sollicitudin felis neque sit amet erat.</div>
</body>
</html>
I have exampled below two div boxes with <h4> headers and followed with <p> with text. In an accordion style, I want to click each title and see the text appear, I've done this by setting the text div container box to max-height: 0; and opacity: 0; then max height a value and opacity 1 on click.
My issue is that I expect the animation to happen simultaneously for both boxes (one that slides up and hides, the other that slides down and appears), However, I get the animation running in order slide up and disappear forwarded by slide down and appear.
How can I get them both at the same time?
document.addEventListener('DOMContentLoaded', function() {
// main click handler for the whole page
document.addEventListener('click', function(event) {
var clickedElem = event.target;
if (clickedElem.matches(".slide-card h4")) {
var activeCards = document.querySelectorAll(".card-active");
if (activeCards) {
for (var i = 0; i < activeCards.length; i++) {
if (activeCards[i]) toggle(activeCards[i], "card-active");
}
}
toggle(clickedElem.parentNode, "card-active");
}
});
});
function toggle(el, elClass) {
if (el.matches("." + elClass)) {
el.classList.remove(elClass);
} else {
el.classList.add(elClass);
}
}
h4 {
cursor: pointer !important;
}
.slide-card {
border: 1px solid white;
padding: 1em;
}
.animated-slides-cards {
background: pink;
padding: 1em;
}
.card-body {
opacity: 0;
max-height: 0;
transition: all 0.75s ease-out;
}
.card-active .card-body {
opacity: 1;
max-height: 400px;
}
<div class="animated-slides-cards">
<div data="0" class="slide-card block-padding margin-bottom-05x card-active">
<h4 class="blue">Harness the power of the crowd</h4>
<div class="grey card-body">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mattis eros vitae metus sodales eget suscipit purus rhoncus. Proin ultrices gravida dolor, non porttitor enim interdum vitae. Integer feugiat lacinia tincidunt. Nulla laoreet tristique
tristique. Sed elementum justo a nisl elementum sit amet accumsan nisi tempor. Nulla quis eros et massa dignissim imperdiet a vitae purus.</p>
</div>
</div>
<div data="1" class="slide-card block-padding margin-bottom-05x">
<h4 class="blue">Slots straight into your systems</h4>
<div class="grey card-body">
<p>Using simple APIs, SmartCrowd™ connects to your systems and allocates tasks to ambassadors using your existing digital channels. You can opt for full integration or simply use Limitless Live Messenger on your website to maintain a single customer
view.</p>
</div>
</div>
</div>
I am not sure if this is easily possible, but I thought I would ask just in case:
I am using the following CSS rules on a list of text:
{
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
}
As expected, any text that goes outside the list will be truncated and have an ellipsis placed on the end.
I want to have an active title property for only those list items that trigger the text-overflow rule on the list. So you can hover the mouse over any text that is truncated and see a tooltip of its full text.
Something tells me this is difficult, if not impossible, to do. However I would love to be proven wrong. I am preferably looking for a solution that uses as little JavaScript as possible.
We use a similar, more generic ellipsify, which works perfectly for most cases. We also apply the title attribute (for all elements). Only applying the title if the element ellipsifies, is indeed difficult. The example below assumes that, if the element has the same width as the parent, we should set the title. Without the if statement it would always apply the title.
document.querySelectorAll('.ellipsify').forEach(function (elem) {
if (parseFloat(window.getComputedStyle(elem).width) === parseFloat(window.getComputedStyle(elem.parentElement).width)) {
elem.setAttribute('title', elem.textContent);
}
});
.ellipsify {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: 100%;
display: inline-block;
}
div {
width: 100px;
}
<div>
<span class="ellipsify">dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna</span>
<span class="ellipsify">dolor sit amet</span>
</div>
This is how i approached the solution.
If you don't want to use java-script.
Here is a Link to fiddle: https://jsfiddle.net/fryc4j52/1/
SNIPPET:
.ellipse{
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin:0;
padding:0;
}
.content li{
margin:0;
padding:0;
overflow:hidden;
}
.ellipse:hover{
width: auto;
border: 2px solid #eee;
box-shadow: 0px 3px 10px 0px black;
padding:2px;
white-space: normal;
word-break: break-word;
z-index:5;
}
<ul class="content">
<li class="ellipse">A very looooooooooooooooooooooooooooooooooooooong line.</li>
<li> Other text</li>
<li class="ellipse">A veryvvvvvvvvvvvvvvvvvvvvvvverrrrryyyyyyyyy looooooooooooooooooooooooooooooooooooooong line.</li>
</ul>
document.querySelectorAll('.ellipsis').forEach(function (e) {
if (e.offsetWidth < e.scrollWidth) {
e.setAttribute('title', e.textContent);
} else{
e.removeAttribute('title');
}
});
.ellipsis {
text-overflow: ellipsis;
display: inline-block;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
}
You can measure for the presence of overflow with a little JavaScript and only add the title attribute if it the element would have overflowed (had it not been truncated).
Constrain the content with a style.
Copy the content into a hidden test element with the same width.
Don't limit wrapping on the test element, allowing it to overflow.
Compare the heights.
$(".smart-overflow").each(function() {
var elementToTest = $(this),
contentToTest = $(this).text(),
testElement = $("<div/>").css({
position: "absolute",
left: "-10000px",
width: elementToTest.width() + "px"
}).appendTo("body").text(contentToTest);
if (testElement.height() > elementToTest.height()) {
elementToTest.attr("title", contentToTest);
}
});
.smart-overflow {
width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="smart-overflow">
short text
</div>
<div class="smart-overflow">
short text
</div>
<div class="smart-overflow">
Longer text; there should be a tooltip here.
</div>
<div class="smart-overflow">
More long text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vestibulum lorem eget justo tempus posuere. Integer ac sagittis nisi. Phasellus eu malesuada sapien. Aliquam erat volutpat. Nunc aliquet neque sagittis eros ullamcorper,
blandit facilisis magna gravida. Nulla a euismod turpis.
</div>
<div class="smart-overflow">
More long text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vestibulum lorem eget justo tempus posuere. Integer ac sagittis nisi. Phasellus eu malesuada sapien. Aliquam erat volutpat. Nunc aliquet neque sagittis eros ullamcorper,
blandit facilisis magna gravida. Nulla a euismod turpis.
</div>
<div class="smart-overflow">
short text
</div>
<div class="smart-overflow">
short text
</div>
jQuery used here for conciseness, but certainly not required.
What I need to achieve can be seen on this demo.
Basically a page with a rectangle area that you reach by scrolling down, where there's content that appears as if it were a position: fixed element. In the demo above, the revealed content is a page displayed through an iframe - I'm happy with just an image.
I only need this to work on iOS 8. From what I can see, the demo does it through some custom scrolling mechanism. I suspect they have somehow overwritten scrolling altogether - although I can't confirm it's a custom scrolling framework like iScroll.
My own approach was to re-position a clip: rect area on a position: fixed background image, through a onscroll handler. Sort of like moving a mask around, on an image. Example here
The code I use in my JS onscroll handler to re-position the clipping rectangle:
topY = adDiv.getBoundingClientRect().top + window.pageYOffset - adDiv.ownerDocument.documentElement.clientTop;
scrollT = (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
newY = topY - scrollT;
newHeight = rectHeight + newY;
document.getElementById("bgImg").style.clip = "rect("+newY+"px,1900px,"+newHeight+"px,0px)";
I'd be happy with this if there weren't for a delay while re-positioning the clip: rect area; you can see it if you test on anything iOS 8 (there is a slight delay when you scroll/swipe up and down around the area that reveals the image). Wasn't able to overcome this and fear it's by-design.
EDIT: please note I need to have the content that is above and below the reveal area, see-through; so with a transparent background that would allow you to see the page's background; can't mess with anything above and below.
I've stripped the demo you linked down to the essentials, in which there seems to be three elements of importance, one container, one which is used for the clipping, and the third for the content.
<div class="container">
<div class="clip-box">
<div class="content">
...
</div>
</div>
</div>
The "container" defines the area you want to use in line with the text;
.container {
position: relative;
width: 100%;
height: 10em;
}
The clip-element is where the interesting happens. It's made to fill the parent, which makes the clip: rect(auto ... auto) clip the element (and therefore also it's children) at its edges. It's important that this element is set position: absolute or position: fixed, as clipping only applies to absolutely positioned elements.
.clip-box {
position: absolute;
left: 0;
top: 0;
width:100%;
height:100%;
clip: rect(auto auto auto auto);
}
Lastly we have the content as a child of the clip-element. It is set to a fixed position but will only render in the clip-rect area defined by the parents’ bounding-box.
.content {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0;
}
Here's a snippet of the above which uses only css.
body {
background-image: url("http://lorempixel.com/500/500/");
background-size: cover;
color: #FFF;
margin: 0;
text-align: center;
}
img {
width: 100%;
}
.content p {
position: absolute;
top: 0;
left: 0;
text-align: left;
}
.window {
position: relative;
width: 100%;
height: 10em;
}
.clip-box {
position: absolute;
left: 0;
top: 0;
width:100%;
height:100%;
clip: rect(auto auto auto auto);
}
.content {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 0;
}
<p>
Lorem ipsum
<br>dolor sit amet,
<br>consectetur adipiscing elit.
<br>Morbi convallis
<br>accumsan neque,
<br>eu accumsan magna
<br>laoreet cursus.
<br>Etiam feugiat mattis
<br>nunc eget luctus.
<br>Proin vel dictum est.
<br>Nullam suscipit quam
<br>at ullamcorper vestibulum.
<br>Lorem ipsum
<br>dolor sit amet,
<br>consectetur adipiscing elit.
<br>Curabitur rutrum
<br>elementum ligula,
<br>suscipit sodales
<br>nisl convallis a.
</p>
<div class="window">
<div class="clip-box">
<div class="content">
<img src="http://lorempixel.com/500/400/">
<p>
Lorem ipsum
<br>dolor sit amet,
<br>consectetur adipiscing elit.
<br>Morbi convallis
<br>accumsan neque,
<br>eu accumsan magna
<br>laoreet cursus.
<br>Etiam feugiat mattis
<br>nunc eget luctus.
<br>Proin vel dictum est.
<br>Nullam suscipit quam
<br>at ullamcorper vestibulum.
<br>Lorem ipsum
<br>dolor sit amet,
<br>consectetur adipiscing elit.
<br>Curabitur rutrum
<br>elementum ligula,
<br>suscipit sodales
<br>nisl convallis a.
</p>
</div>
</div>
</div>
<p>
Lorem ipsum
<br>dolor sit amet,
<br>consectetur adipiscing elit.
<br>Morbi convallis
<br>accumsan neque,
<br>eu accumsan magna
<br>laoreet cursus.
<br>Etiam feugiat mattis
<br>nunc eget luctus.
<br>Proin vel dictum est.
<br>Nullam suscipit quam
<br>at ullamcorper vestibulum.
<br>Lorem ipsum
<br>dolor sit amet,
<br>consectetur adipiscing elit.
<br>Curabitur rutrum
<br>elementum ligula,
<br>suscipit sodales
<br>nisl convallis a.
</p>
You should however note that the clip property is deprecated and developers are advised to use clip-path instead. This is an experimental technology though and if you're only wanting to use images anyway I'd recommend using background-attachment: fixed; which will give you the same result as the code above.