How can I "word wrap" a div within a container div? - javascript

I am making a comma separated "tag" type system, and I want the tags to scroll left to right, then go to the next line if the next tag would cause that line to be wider than the max width of the container.
I get different results if I use <span> or <div>
<span class="tag"><span class="tagspan" ></span></span>
<div class="tag"><span class="tagspan" ></span></div>
but neither one correctly wraps to the next line. ( If I use span it WILL wrap to next line, but it will break the tag in half and place the rest of it on the next line ).
Surely there must be an easy fix for this. I am trying to avoid having to calculate the width of each line and compare its current width to the width it would be if the next tag were added, then deciding if there needs to be a line break or not.
Any suggestions would be greatly appreciated.
JS Bin Here
jQuery:
$('document').ready( function() {
var value;
var tag;
var cloned;
$('#tag').on( 'change keyup', function(){
value = $('#tag').val();
tag = value.split(',');
if (tag[1] != null && tag[0] !== ''){
cloned = $('.tag').first().clone().appendTo('#container');
$(cloned).find('span').html(tag[0]);
$(cloned).css({'opacity' : '1', 'width' : $(cloned).find('span').width() + 'px'});
$('#tag').val('');
}
if (tag[1] != null && tag[0] === ''){
$('#tag').val('');
}
console.log($('.tagspan').width() + 'px');
});
});

You can use float:left to your tag elements instead of the container and drop the display:inline-flex attribute which results in a line break if your tags reach the end of the line. Edit: change the outer span elements to divs for that effect.
// thanks Gary ;)

This is more related to CSS styling than JavaScript code, I think I got it working just tweaking two classes in your CSS code:
span {
vertical-align:middle;
display: inline-flex;
word-break: keep-all;
}
#container {
text-align: left;
display: block;
min-width:400px;
max-width:400px;
height:100px;
border:1px solid;
}
This is how it looks like:
The thing is, span elements must fit into its parent element, that's why you should make children display inline and not its parent.
Working example: Wrap span tags into DIV

Given that you were working with flexbox, you might want to try add to your .container class flex-wrap:wrap; This acheives a similar effect.

There are a few styles that are causing problems for you (referencing the JSBin you posted). The following should fix your problems:
.tag {
border: 3px ridge #336699;
height: 20px;
background: rgba(0, 0, 170, .25);
border-radius: 20px;
text-align: center;
font-family: arial;
font-size: 15px;
color: #336699;
font-weight: bold;
padding: 2px 8px;
margin: 2px;
opacity: 0.0001;
float: left;
display: none;
}
#container {
width: 400px;
height: 100px;
border: 1px solid;
}
then adjust your JavaScript to the following:
$(function() {
var value,
tag,
cloned;
$('#tag').on('change keyup', function(e) {
value = $('#tag').val();
tag = value.split(',');
if (tag[1] != null && tag[0] !== '') {
cloned = $('.tag').first().clone().appendTo('#container');
$(cloned).find('span').html(tag[0]);
$(cloned).css({'opacity' : '1', 'min-width' : $(cloned).find('span').width() + 'px', 'display': 'inline-block'});
$('#tag').val('');
}
if (tag[1] != null && tag[0] === '') {
$('#tag').val('');
}
});
});
I've posted a functioning JSFiddle if you'd like to see it in action here: http://jsfiddle.net/autoboxer/opqcxm9k/
Cheers,
autoboxer

Related

HTML element to display tooltip on hover

I have several HTML elements that I need to display a tooltip on hover. These are not conventional HTML elements and come from a generated script on the backend, which I do not have permissions to alter. What I want to know, from a front end perspective, is how I can display a tooltip without declaring this in the HTML.
I tried using Bootstrap tooltips, but you need to declare this in the HTML tag as a title, so it's not useful. So, as the example shows below, I need some text saying 'Action' to appear in a tooltip when you hover over the 'Action' element that contains 'should'. Same will be applied when you hover over the text 'approximate number of' contained in the 'Quantifier' element - the word 'Quantifier' should be displayed. Hope this makes sense.
<body>
One string that <Action>should</Action> work is
<Quantifier>approximate number of</Quantifier> other things.
<script>
$(document).ready(function(){
$("Action").hover(function(){
});
$("Quantifier").hover(function(){
});
});
</script>
<body>
So far non-conclusive, as I can only change CSS values and not tooltip text.
You can try updating the title property on those elements. One thing to note is that HTML tags will appear in lowercase when compiled.
$(document).ready(function() {
var style = document.createElement('style');
style.type = 'text/css';
$('head')[0].appendChild(style);
style.innerHTML =
`action, quantifier {
position: relative;
display: inline-block;
margin-top: 20px;
}
action[title]:hover:after, quantifier[title]:hover:after {
content: attr(title);
position: absolute;
top: -100%;
left: 0;
}
action[title]:hover:after {
color: red;
border: solid 1px black;
}
quantifier[title]:hover:after {
color: blue;
border: solid 1px black;
}`;
$('action')[0].title = 'Action';
$('quantifier')[0].title = 'Quantifier';
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
One string that <Action>should</Action> work is
<Quantifier>approximate number of</Quantifier> other things.
</body>
add a tooltip for an tag with JS/jQuery without change the html structure. You can modify the css based on requirement.
jQuery(function($){
//If you are able to add class then use $('.add_tooltip').hover
// use $('Quantifier, Action').hover
$('Quantifier, Action').hover(
function () {
//let text = $(this).html(); //this is for html content of hover element
let text = $(this).prop("tagName");
//Add the tag name of hover element to tooltip div
$(this).append('<div class = "tooltip">'+text+'</div>');
//display the tooltip with animation.
$(this).find('.tooltip').hide().fadeIn('slow');
},
//On hover out remove the tooltip.
function () {
$(this).find('.tooltip').remove();
}
);
});
Quantifier, Action{
cursor: pointer;
position:relative;
}
.tooltip{
display: inherit;
background: black;
margin: auto;
padding: 10px;
position: absolute;
z-index: 1000;
width: 200px;
height: 40px;
color: #fff;
top: 18px;
left:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
One string that <Action>should</Action> work is
<Quantifier>approximate number of</Quantifier> other things.

CSS selector and border issue

I would like to achieve the following with my code:
Issue (a) Change only Click Here to be surrounded by a box.
Issue (b) The border for the box in (a) should disappear and reappear.
Currently, I face the following issues with my code:
Issue (a)
For (a), my code does not just change Click Here to be surrounded by a box. It also changes Pinterest to be surrounded by a box. I believe the issue is with selecting the top level ul but I have not succeeded in doing so.
Relevant CSS code
.cover-buttons ul:first-of-type li:nth-last-child(5) a {
color: black;
border: 1px solid black;
padding: 14px 18px!important;
font-weight: 400;
line-height: 17px;
font-size: 12px;
display: inline-block;
transition: all .2s ease;
overflow: hidden;
border-radius: 2px;
box-sizing: border-box;
list-style-type: none;
font-family: 'Varela Round', 'Poppins', sans-serif;
}
Issue (b)
For (b), I can't seem to get the box border to blink.
Relevant Javascript code
$(function(){
var count = 0, $input = jQuery('.buttons.medium.button-outlined').not('.add-review, .bookmark, .show-dropdown, .sn-share'), interval = setInterval(function() {
if ($input.hasClass('blur')) {
$input.removeClass('blur').addClass('focus'); ++count;
} else {
$input.removeClass('focus').addClass('blur');
}
if (count === 3) { clearInterval(interval); }
}, 2000);
});
Relevant CSS code
.focus {
border: 1px solid white;
}
.blur {
border: 1px solid black;
}
The strange thing about issue (b) is that it seems to work when I change the background-color as shown here: https://jsfiddle.net/75nvLs4x/12/. However, when I try to modify the border thickness it does not work.
Full script including HTML is included here: https://jsfiddle.net/75nvLs4x/14/
Thank you for your help.
Issue A
Your selector is: .cover-buttons ul li:nth-last-child(5) a this will affect any ul inside .cover-buttons. As there are two uls that have li:nth-last-child(5), both have the li:nth-last-child applied.
You can fix this by saying only the ul that's directly inside .cover-buttons and only the li directly inside that ul
.cover-buttons > ul > li:nth-last-child(5) a
Issue B
Your border issue is due to specificity - the border in the .cover-buttons ul li:nth-last-child(5) a section is more specific than just .focus so is always used. You could add !important to the border inside .focus, but that's not best practice - instead, remove the border from the main block and it works fine.
Updated fiddle: https://jsfiddle.net/75nvLs4x/18/

How to set a max-width only to text nodes not in a tag?

I have mixed well and bad formatted text from a legacy wordpress database. Well formated is inside p tags and bad formatted is outside. So at the end the HTML is like that:
<div>
<p>Good text</p>
<blockquote>Good text</blockquote>
Problematic text <strong>like this</strong> one.
<p>Good text</p>
</div>
The p text has a max-width set and is centered:
p {
max-width: 300px;
margin: 0 auto;
padding: 10px;
}
The blockquote element or other divs are not width-limited.
As you can see in this fiddle example, my problem is that the non-p text is left-aligned. I don't know if it's possible to center using just CSS. Using javascript my approach was to do this:
jQuery("div").contents().filter(function() { return this.nodeType === 3; }).wrap('<p>');
This is ok in general, buy when you have strong or em tags in the middle it doesn't work (example).
So, is CSS able to do this? If not, how to do in Javascript? Of course, I prefer the CSS option, but JS is a better option than reformat the whole database :)
Clarification: The objective is to limit with max-width only the p-tags and the bad-fomatted text elements (which include text and some tags like strong or em). Other elements must have 100% width, it is, not limited by the 300px max-width (i.e. blockquote must use all the available screen size).
Here's a jQuery solution that will wrap the contents that aren't already in <p> or <blockquote>.
Can be easily adapted to include other acceptable tags
var $container = $('div'),
$contents = $container.contents();
var validTags = ['P', 'BLOCKQUOTE'];
var newP = null;
$contents.each(function (i) {
if (this.nodeType === 3 || $.inArray(this.tagName, validTags) == -1) {
if (!newP) { // start creating a new <p>
newP = $('<p style="color:red">')
}
newP.append(this); // append to the new <p>
} else {
if (newP) {
$(this).before(newP); //insert new <p> if there is one
newP = null; //reset
}
}
/* in case text is after all valid tags, add to end */
if (i == $contents.length - 1 && newP) {
$container.append(newP);
}
});
Note that <div> can't be appended to <p> (invalid child) so this approach would probably need some more refinement for situations like that. It does work on sample provided however
DEMO
To center all the content inside the div:
CSS:
div {
text-align: center;
}
To center some divs (example 1st and 3rd from 4), selecting them by id:
CSS:
div#sect1, div#sect3{
text-align: center;
}
HTML:
<div id="sect1>
<!-- contents -->
</div>
<div id="sect2>
<!-- contents -->
</div>
<div id="sect3>
<!-- contents -->
</div>
<div id="sect4>
<!-- contents -->
</div>
Try adding the same styles to the body and the strong tags:
strong {
font-weight: normal; margin: 0 auto;
padding: 10px;}
body {
max-width: 300px;
margin: 0 auto;
padding: 10px;
}
Why don't you apply the max-width on the container element and remove it from other descendent elements.
div.container {
max-width: 300px;
margin: 0 auto;
}
check this fiddle.
EDIT:
you can use the negative margins if you know your main container width. e.g. use -150px margin if your content area is 300px and it's container is 600px and you want bloquote to be 600px wide.
Fiddle
<style>
body{
text-align:center;
}
div:before{
text-align:center;
max-width:300px;
margin:0 auto;
}
p{
max-width: 300px;
margin: 0 auto;
padding: 10px;
}
blockquote{
font-size: 2em;
width:100%;
margin:0 auto;
}
</style>

How to prevent textarea from scrolling to the top when its value changed?

Consider the following example: (Live demo here)
HTML:
<textarea></textarea>
<div id="button">Click Here</div>
CSS:
textarea {
height: 80px;
width: 150px;
background-color: #bbb;
resize: none;
border: none;
}
#button {
width: 150px;
background-color: #333;
color: #eee;
text-align: center;
}
JS:
$(function() {
var textarea = $("textarea");
textarea.val("Hello\nStack\nOverflow!\nThere\nAre\nLots\nOf\nGreat\nPeople\nHere");
$("#button").click(function() {
textarea.val(textarea.val() + "!");
});
textarea.scrollTop(9999).focus(); // Arbitrary big enough number to scroll to the bottom
});
When the #button is clicked, textarea value changes, and for some reason the scroll bar goes to the top (I checked this in Firefox, not sure about other browsers).
Why this is happening ?
How could I fix that ?
I found here one possible solution, but I wonder if there are other solutions.
You can save the scrollTop offset, set the value, and reset the scrollTop to the old offset:
var $textarea = ...;
var top = $textarea.scrollTop();
$textarea.val('foo');
$textarea.scrollTop(top);
Try it here: http://jsfiddle.net/QGJeE/7/
Another solution(harder to imply as there is no unique cross-browser-way):
Instead of changing the value of the textarea create a textRange of the textarea's content and modify the ranges text.

How do I make my "alert bar" push down everything of my website?

I wrote an alert bar like this:
alertmsg{
font-family:Arial,Helvetica,sans-serif;
font-size:135%;
font-weight:bold;
overflow: hidden;
width: 100%;
text-align: center;
position: fixed;
top: 0px;
left: 0px;
background-color: #fff;
height: 56px;
color: #000;
font: 20px/40px arial, sans-serif;
display:none;
padding-top:12px;
-webkit-box-shadow: 3px 3px 5px #888;
-moz-box-shadow: 3px 3px 5px #888;
box-shadow: 3px 3px 5px #888;
}
function alertbar(m, timeout){
if(!timeout){
var timeout = 3000;
}
var $alertdiv = $('<div id = "alertmsg"/>');
$alertdiv.text(m);
$alertdiv.bind('click', function() {
$(this).slideUp(200);
});
$(document.body).append($alertdiv);
$("#alertmsg").slideDown("slow");
setTimeout(function() { $alertdiv.slideUp(200) }, timeout);
return false
}
Pretty simple. I call alertbar("Go go go!"); to have this alert drop down.
However, it covers the body's page. I want it to sort of "push down" on the entire page (all the elements)....sort of like StackOverflow does it I guess.
I think it's the position: fixed that is your problem. This will place your element relative to the window and take it out of the normal flow.
Use position:static (or relative) and make sure the alertmsg element is at the top of the markup.
There's a couple things you must do:
Change the position CSS attribute of the "alert bar" to not be fixed and just be normal (remove that property).
Change your JavaScript to prepend the alertdiv, rather than append it. This will make it the first thing in the body.
$('body').prepend($alertdiv);
Slide your $alertdiv down normally.
Now something that you didn't take into account in your code is what happens when you run alertbar more than once. You'll append more than one to the body. If this is a concern, try doing something like this:
var exists = $('#alertmsg').length > 0;
var $alertdiv = exists ? $('#alertmsg') : $('<div id="alertmsg" />');
Now only prepend to the body if it doesn't exist already.
if (!exists)
$('body').prepend($alertdiv);
If you want to keep the position: fixed then just expand the body's top padding to the size of the alertbox.
$("#alertmsg").slideDown("slow", function() {
var paddingTopStr = "+" + $(this).outerHeight().toString() + "px";
$('body').css({ paddingTop: paddingTopStr });
});
You will also have to return the padding after:
setTimeout(function() {
var paddingTopStr = "-" + $(this).outerHeight().toString() + "px";
$('body').css({ paddingTop: paddingTopStr });
$alertdiv.slideUp(200) }, timeout);
}
Same for the click event.
You could wrap the rest of your content (to be pushed down) in a separate div and then insert your alert bar before it

Categories