This question already has answers here:
How can I highlight the line of text that is closest to the mouse?
(3 answers)
Closed 8 years ago.
I'm currently working on a website which will feature a bunch of stories for people to read (basically a blog). I want to make them as easy to read as possible and I figured it would be useful to 'highlight' lines of text with the cursor. Kinda like following the lines of text with your finger when reading a book.
I stumbled upon this answer, however I can't seem to get it to work for my page. It's also a pretty old answer so maybe there's an improved version of this?
If anyone could help me out I'd be forever grateful!
Wrote some jQuery code that, atleast to me, both looks and works better than the code in the post that you are referring to. Hope it fits your needs :)
There's also a live demo up at http://jsfiddle.net/gFTrS/2/
HTML
<div class="textWrapper">
<div class="highlight"></div>
<p>Your text goes here</p>
</div>
CSS
.textWrapper
{
position: relative;
width: 600px;
padding: 0px 10px;
margin: 0 auto;
cursor: default;
}
.textWrapper p
{
font: normal 12px Arial;
color: #000000;
line-height: 18px;
padding: 0;
margin: 0;
}
.highlight
{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 18px;
background: yellow;
z-index: -1;
display: none;
}
jQuery
$(document).ready(function()
{
var lineHeight = 18;
$('.textWrapper').hover(function()
{
$('.highlight', this).show();
$(this).mousemove(function(e)
{
var relativePos = e.pageY - this.offsetTop;
var textRow = (Math.ceil(relativePos / lineHeight) * lineHeight) - lineHeight;
if (textRow => 0)
{
$('.highlight', this).css('top', textRow + 'px');
}
});
}, function()
{
$('.highlight', this).hide();
});
});
Most of the answers and suggestions in the older post on SO you reffered to try to manipulate the DOM by adding spans or divs for each line. But that's actually not a waterproof approach since it is not cross- browser compatble, especially not with mobile browsers. You should use a dynamically jquery controlled div that jumps behind the lines. The div should be dynamically be positioned with a jquery function triggered on mousemove calculating the div jumping on line-height depending on mouse cursor position
Related
I work in a web development environment that uses WordPress. The theme we use is ThemeCo's Pro.
I'm still learning javascript (so please forgive me if I'm really far off), and I'm trying to use jQuery to write a piece of code that will allow an element to appear after scrolling 1vh of the page. Can anyone help me understand why this isn't working? I can't tell if it's my code, or my theme might not be allowing it. The theme itself uses jQuery on the front end, but has a javascript file I may edit, but for the most part, the frontend editor is pretty reliable for code.
I'm using pieces from this question to help me write it, as well as referencing the jQuery library.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
var minH = $(window).height() * 1;
if (scroll >= minH) {
$("#circle-menu").fadeTo(500, 1);
}
else {
$("#circle-menu").fadeTo(500, 0);
}
});
Just to make sure I understand what you're trying to do, I'll quickly reiterate what your code does: Basically, minH is supposed to be 1vh, and if scroll is >= minH, you want #circle-menu to fade in.
That being said, I think we have to look at a couple potential issues with the code above:
1vh is really just 1/100 of the viewport height, which can be calculated as:
// this is 1vh, which is what you're going for
$(window).height() / 100
As opposed to:
// this is 100vh
$(window).height() * 1
The second would be that you're using fadeTo. The difference between fadeIn/fadeOut and fadeTo is that fadeTo doesn't affect an element's display property. It only affects an element's opacity property. This means that if the theme's default value for the menu's display property is set to "none", fadeTo is not going to make it fade into sight. To get around this, in my opinion, it would be better to use fadeIn and fadeOut instead, especially since it doesn't seem like you're trying to control different levels of opacity (which is what fadeTo is really needed for).
I made a quick code snippet to demonstrate the above fixes.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
var vh = $(window).height() / 100;
var minH = vh;
if (scroll >= minH) {
$("#circle-menu").fadeIn(500);
}
else {
$("#circle-menu").fadeOut(500);
}
});
p {
margin-top: 10vh;
height: 150vh;
border: 2px solid #666;
}
#circle-menu {
font-family: 'Segoe UI', verdana, sans-serif;
font-size: 20px;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 50px;
box-shadow: 1px 2px 3px rgba(50,50,50,0.1);
z-index: 1;
display: none;
background-color: steelblue;
color: white;
padding-left: 20px;
padding-top: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="circle-menu">Menu</div>
<p></p>
I have a jQuery custom scrollbar, and I invoke it like this:
<script>
(function($){
$(window).on("load",function(){
$(".main_text,#C2,.png_container").mCustomScrollbar();
});
})(jQuery);
That works correctly for all of the page elements except .png_container, but unlike the other sections, that section is only used in a JavaScript variable that is used to substitute text in a placeholder ID, and I think that's where the problem is.
Here is how it's called from an "onclick" button event:
<div class="main_text">
<div id="C2">Main Text</div>
</div>
if (type == 101) {
var X = "<header>First Section</header><br>A classic example of good form/<br><br>More information<ul type=\"circle\"><li>Element Point 1<br></li><li>Element Point 1</li></ul><i><span class=\"span_01\">So much better</i></span><br><br><div class=\"png_container\"><img class=\"png_format\" src=\"images/Element 001.png\"></div>"}
document.querySelector("#C2").innerHTML = X;}
The png_container has a separate set of scroll bars, but they are not replaced by the custom scroll bars (the other page sections do get the custom scroll bars).
Here is the relevant css:
.png_container{
overflow: auto;
overflow-y: auto;
overflow-x: auto;
height: 400px;
width: 800px;
border: 2px solid;
border-color: green;
}
#C2{
color:#DBDBDB;
font-family: camphorW04-Thin,calibri,arial;
font-size: 14pt;
text-indent: 0px;
width: auto;
margin: auto;
margin-left: 20px;
margin-right: 250px;
}
So my question is: how can I replace the scroll bars on a section that is embedded in a JavaScript variable, as shown above?
My research has found some similar questions, but none that answer this specific question, so I hope somebody knows the answer. Thanks very much for any ideas.
You initialize the mCustomScrollbar plugin on load this way:
$(window).on("load",function(){
$(".main_text,#C2,.png_container").mCustomScrollbar();
});
The two first selectors have matching elements at this moment. But there is no existing element to match the last selector since .png_container is appended on click.
So you can safely remove .png_container from the load handler...
And initialise mCustomScrollbar on .png_container when it exists.
$(window).on("load",function(){
$(".main_text,#C2").mCustomScrollbar(); // Remove .png_container
});
$(".something").on("click",function(){
if (type == 101) {
var X = "<header>First Section</header><br>A classic example of good form/<br><br>More information<ul type=\"circle\"><li>Element Point 1<br></li><li>Element Point 1</li></ul><i><span class=\"span_01\">So much better</i></span><br><br><div class=\"png_container\"><img class=\"png_format\" src=\"images/Element 001.png\"></div>"}
document.querySelector("#C2").innerHTML = X;
$(".png_container").mCustomScrollbar(); // Add this.
}
When clicking on a link I need to load a huge pdf on FancyBox overlay. Until the pdf is loaded I'm displaying a FancyBox loader. The problem is I need to add a text like "Please Wait...etc" in the FancyBox loader. Can any one help?
This is My Code:
<p>
<a class="fancypdf" href="hugepdf.pdf">Click
Here To View The PDF</a>
</p>
<script type="text/javascript">
$(document).ready(function() {
$(".fancypdf").click(function(event) {
$.fancybox.open(this.href, {
type : "iframe"
});
$.fancybox.showLoading();
$("iframe.fancybox-iframe").load(function() {
$.fancybox.hideLoading();
content: {
text: 'Loading...',}
});
event.preventDefault();
});
});
</script>
P.S.
You can modify following fiddle.
DEMO
Please have a look at below modifications:
Updated Fiddle Link: http://jsfiddle.net/PudLq/619/
1) added CSS class as:
#fancybox-loading{
background-repeat: no-repeat;
background-position: center -108px;
text-align: center;
}
#fancybox-loading div{
margin: auto;
}
.overrideLoading{
background: none !important;
color: white;
width: 92px !important;
}
2) after showing loading animation; altering the loading div HTML as per our need as follows:
$.fancybox.showLoading();
$('#fancybox-loading').append("<div class='overrideLoading'>Please Wait...</div>");
3) On hiding the animation; As suggested by "rockmandew" there is absolutely no need of reverting our HTML/CSS changes. On calling $.fancybox.showLoading() again directly; default loading animation will be shown to user. I have tested it and added one more link in fiddle to show default loading animation. Please click on "Show Default loading" to see that effect.
I hope this will help you.
I didn't have a chance to tweak the resulting positioning being a little off-center, but this may be a more simple solution:
http://jsfiddle.net/PudLq/621/
Simply add your text to an :after pseudo element with a content: rule and modify the styles of the loading wrapper to accomodate.
here's the CSS I added:
#fancybox-loading {
background: #000;
padding: 5px;
border-radius: 6px;}
#fancybox-loading:after {
content:"Please wait...";
display:inline-block;
color:#fff;}
#fancybox-loading div {margin:auto;}
Here is a forked version of your Fiddle.
I've basically span with the text "Please Wait". Then I've applied some CSS to that to position it as you did with #fancybox-loading .
Here is the new javascript code -
$(".on").click(function () {
var target = $('#target');
var overlay = $('#overlay');
overlay.width(target.width()).height(target.height()).css({
'left': target.position().left,
'top': target.position().top
}).fadeIn(200);
$.fancybox.showLoading();
$('#fancybox-loading').css({
'left': (target.width() - $('#fancybox-loading').width()) / 2,
'top': (target.height() - $('#fancybox-loading').height()) / 2,
'margin': 0
});
var labelWidth = 80;
$('body').append($('<span>', {
'class': 'waitText'
}).text("Please Wait").css({
'width': labelWidth,
'left': (target.width() - labelWidth) / 2,
'top': ((target.height() - $('#fancybox-loading').height()) / 2) + $('#fancybox-loading').height()
}));
});
$(".off").click(function () {
$('#overlay').fadeOut(200);
$.fancybox.hideLoading();
$('.waitText').remove();
});
And my new CSS -
.waitText {
position: fixed;
margin: auto;
color: white;
text-align: center;
}
Following vijayP's answers:
JsFiddle: http://jsfiddle.net/rockmandew/kmfeppec/
I modified his CSS class of "overrideLoading":
.overrideLoading{
background: none !important;
color: white;
position: absolute;
top: 42px;
}
As you can see I added a "position:absolute" and a "top" position - you can modify this to however you need it to appear.
Next I altered his jQuery, which I modified to actually append a new element:
$('#fancybox-loading div').append("<div class='overrideLoading'>Please Wait...</div>");
As you can see, that reduced your required jQuery to one line.
Finally, I removed the last part of the function, which was removing the class. Since this is no longer required, you can just keep the FancyBox "hideLoading" call.
For learning purposes, I removed the following from the last function:
$('#fancybox-loading div').removeClass("overrideLoading");
$('#fancybox-loading div').text("");
Again, here is the JsFiddle: http://jsfiddle.net/rockmandew/kmfeppec/
First Update:
I saw that the first user to answer, updated his answer and while works, I would suggest shying away from "!important" tags as much as possible. I too refined my answer and developed a solution that didn't use any !important tags.
What was originally: $('#fancybox-loading div').append("Please Wait..."); was now changed to:
$('#target ~ #overlay').append("<div class='overrideLoading'>Please Wait...</div>");
I noticed an earlier comment from you, which specified that you wanted to target specific loading overlays - what this function does is it: Selects every '#overlay' element that is preceded by a '#target' element - you can insert whatever target you want.
I removed all instances of the "!important" tag - this is just best/standard practice.
.overrideLoading{
color: white;
position: absolute;
top: 86px;
left: 16px;
}
Updated JsFiddle: https://jsfiddle.net/rockmandew/kmfeppec/7/
This question already has answers here:
How can i position a dropdown at cursor position inside a textarea?
(2 answers)
Closed 9 years ago.
I've seen a few questions like this but can't find a solution. I have a textbox. When the user is typing along, if they press #, I'd like to show a list of items they can select from, at that caret's position (i.e. the place in the textbox where the next character typed will appear, not the location of the mouse cursor).
JSfiddle: http://jsfiddle.net/LR8pe/
Code:
$(".textarea").bind("keypress", function (e) {
if (String.fromCharCode(e.keyCode) == '#') {
$(".list").show();
} else{
$(".list").hide();
}
});
I have the basic mechanics down, but showing/hiding at the position of the caret is where I'm stuck.
I'm using jquery/knockout, but pure JS is fine with me.
Here is a purely CSS approach:
http://jsfiddle.net/p774G/2/
Surround your textarea and list in a container:
<div class="spacer"></div>
<div class="list-container">
<textarea class="textarea"></textarea>
<ul class="list">
<li>item</li>
</ul>
</div>
Modify your CSS so that the textarea is a fixed size, then position your list at the bottom of it:
textarea
{
width: 300px;
height: 70px;
padding: 3px;
}
.list {
list-style: none;
background-color: gray;
display: none;
position: absolute;
top: 76px;
left: 0;
margin: 0;
padding: 0;
border: 0;
}
.list-container
{
position: relative;
}
.list li
{
padding: 5px;
width: 294px;
}
EDIT:
I would not recommend spawning this box where the mouse cursor is, as you do not know where the user will have his or her cursor. It could be off the page for all you know. This is a bad user experience. Instead spawn it below the textarea as I did in my answer.
Using your jsFiddle: http://jsfiddle.net/zCLu9/1/
Basically, I created 2 global variables responsible for holding the mouse's X and Y coordinates which are updated on mousemove so they're always (well, almost always) accurate. Then those coordinates are used to set the offset of the .list element whenever it's supposed to be displayed.
I also set the element's position to absolute in the CSS.
I have what is for all intents a mouseover tooltip. It lives on multiple page elements (dynamically generated, so I never know how many there will be or what their positions are.)
I've had complaints that on lower-resolution screens, the tooltips on items in the rightmost column of elements run offscreen. Since I don't know the position of the parent item when it's created, I need a way to detect (before the mouseover actually happens) that the tooltip div will partially be offscreen when displayed, and change the css accordingly.
I know what the css needs to be; what I'm having trouble with is the detecting part. I've seen a few questions that are similar, but the solutions all involve using prototype or jquery plugins. I'm limited to core jquery (or just plain javascript) on this project.
Any pointers out there?
Here is a quick demo I put together on jsFiddle: http://jsfiddle.net/2gGrd/
HTML:
<p class="left">Left</p>
<p class="center">Center</p>
<p class="right">Right</p>
CSS:
p {
position: absolute;
top: 50%;
}
.left {
left: 0;
}
.center {
left: 50%;
}
.right {
right: 0;
}
.toolTip {
width: 100px;
height: 25px;
background: red;
color: green;
position: absolute;
}
JavaScript:
var tip;
$('p').hover(function() {
$(this).css('color', 'red');
var xpos = $(this).width() / 2 + $(this).offset().left;
var ypos = $(this).height() / 2 + $(this).offset().top;
tip = createToolTip('thing', xpos, ypos);
$(this).parent().append(tip);
tip.offset({
left: tip.offset().left - tip.width() / 2
});
if (tip.offset().left < 0) tip.offset({
left: 0
});
if (tip.offset().left + tip.width() > $('body').width()) {
tip.offset({
left: $('body').width() - (tip.width())
});
}
}, function() {
$(this).css('color', '');
$(tip).remove();
});
function createToolTip(text, x, y) {
return $('<div />').addClass('toolTip').css('left', x).css('top', y).text(text);
}
It's not perfect code, nor is it the same idea as you have for the tool tips, but hopefully it answers the question about keeping the items on screen.