I am trying to use a Show More/Show Less button for texts to expand and contract the long texts/paragraphs. The code seems to work fine in all aspect. The one and only flaw is that I can still see the show more button even if the text is limited (say only 1 line). How can I set a condition for the button to only appear if a certain number of lines or text has been displayed (say 3 lines or 50 words or any such possible limitation). I am not being able to figure out how to do it as I am not that good in jQuery. Hence, I am here seeking a solution.
Codepen: [ https://codepen.io/zoomkraft/pen/ZEELQXL ][1]
In the sample above, try eradicating the paragraph limiting it to 1 or 2 line only. The show more button still shows when its not needed as there is not much text for expansion. The should be hidden for such limited texts.
[1]: https://codepen.io/zoomkraft/pen/ZEELQXL
UPDATED
HTML comes within while loop.
<?php while($content = $contents->fetch()){ ?>
<div class="text-container">
<div class="content hideContent">
<p><?php echo $content['uc_desc']; ?></p>
</div>
<div class="show-more">
<span>Show more</span>
</div>
</div>
<?php } ?>
I got the solution to why its not working in while loop.
Removed this
var lengthofContent = $(".content").text();
console.log(lengthofContent.length);
if(lengthofContent.length < 200){
$(this).find(".show-more").hide();
}
and added this
$('.content').each(function(k,v){
if ($(v).text().length < 200) {
$(v).removeClass('hideContent');
$(v).next().hide();
}
});
Can you add another class to the show option. Like this
<div class="show-more show-option">
<span>Show more</span>
</div>
then add the following in the script tag directly.
$('.content').each(function(key,value){
var lengthofContent = $(value).text();
if(lengthofContent.length < 200)
$(value).siblings('show-option').hide();
});
The value of 200 can be configured best based on the number you want.
Related
I have an HTML page that is an output of some program.
The program is used a lot to produce evidence and it will be helpful to export this evidence to a PDF.
The HTML is split into two columns.
I need to print (to PDF) multiple pages such that each page shows the two columns where different parts of the columns are aligned.
I rely on the browser ability to print to PDF instead of to the printer.
I tried to use jsPDF but it does not support <pre> tags properly which are prevalent in my text.
The document is a given HTML with two <div>s side by side with a scrollbar.
I already have the code that successfully aligns the two columns in the required positions, and a button that prints it using window.print(). It looks something like this:
function align(loc) {
$('#1').scrollTop($("#mark0"+loc).offset().top);
$('#2').scrollTop($("#mark1"+loc).offset().top);
}
function print() {
window.print();
}
// All locations are known in advance
function printAll() {
for (i=1; i<=3; i++) {
align(i);
print();
}
}
<div id=0 style='left:0; overflow:scroll; height:100%; width:50%'>
A lot of text...
<span id='mark01' />
A lot of text...
<span id='mark02' />
A lot of text...
<span id='mark03' />
A lot of text...
</div>
<div id=1 style='right:0; overflow:scroll; height:100%; width:50%'>
<pre>
Some text.
<b>
A lot of text...
<span id='mark11' />
Some text.
</b>
Some text.
<b>
A lot of text...
</b>
<span id='mark12' />
A lot of text...
<span id='mark13' />
<b>
A lot of text...
</b>
</pre>
</div>
Currently, I have to align the columns using the script (user choose one of the alignments), then print to PDF (user clicks on the print button), then align to a different position, then print again, and so forth.
Is there a way to automatize this process?
I want to create a javascript script that will call align(), then print() multiple times and it will be printed in a single PDF.
The printAll() example obviously does not work.
Using JS, I'd construct a new section laid out for print, then move the content into it.
The goal would be to produce reasonable DOM, like this:
<div id="printzone">
<div class="page">
<div class="col"> col1 section1 </div>
<div class="col"> col2 section1 </div>
</div>
<div class="page">
<div class="col"> col1 section2 </div>
<div class="col"> col2 section2 </div>
</div>
....
</div>
The first part is straightforward, but it seems obvious that the original DOM is not well-suited to the second task. You'll probably have to work with the raw source to accomplish the second step.
Perhaps something like:
// grab source
var col1Source = $('#0').innerHTML;
// treat '<span id="mark##" />' as a delimiter -- BOOM!
var col1Sections = col1Source.split(/<span id='mark\d+'[^>]+>/);
// do same for col2
for(var i = 0,
iMax = Math.max(col1Sections.length, col2Sections.length);
i < iMax;
i++
) {
var newPage = $('<div class="page">');
newPage.append('<div class="col">' + col1Sections[i] + '</div>');
newPage.append('<div class="col">' + col2Sections[i] + '</div>');
$('#printzone').append(newPage);
}
Once you've finished constructing the print zone, open up your dev tools and (1) delete the original #0 and #1 DOM nodes, then (2) play with CSS until the print layout is satisfactory.
I am always leery of asking dumb questions here but I need to move on and create a few more active pages but this is a lingering issue in my way ...The chtml in razor contains a switch ,,, in one of the cases there's three if statements.. THIS IS JUST ONE OF THEM depending on the if statements a different string in viewdata is to be fed into a div and the div class "hidden" is removed and the supplied text displayed....
I have over the past few hours regained my briefly lost ability to remove that hidden class (I hate css) but I have never been able to update the content of the div.
PLEASE Advise Thank you !!
<div id="divUnUsableEvent" class="hidden">
<div class="row clearfix">
<div class="col-md-1"></div>
<div id="systemExceptionLbl" style="font-size: 2em; color: red;"
class="text-danger:focus">
Please contact IS support
</div>
</div>
</div>
//alphascores Not present AND BetaSCores Not Present Ready for xxxxx //alphascores Not present AND BetaSCores Not Present Ready for xxxxx Scoring
if (!Convert.ToBoolean(#ViewData["alphaPresent"])
&& !Convert.ToBoolean(#ViewData["betaPresent"]))
{
<script type="text/javascript">
$(function() {
$('#UnUseableEvent').addClass("hidden");
var txtMsg = #Html.Raw(Json.Encode(ViewData["beforeAlpha"]));
$('#divUnUsableEvent').removeClass("hidden");
$('#systemExceptionLbl').removeClass("hidden");
$('#systemExceptionLbl').innerText = txtMsg;
});
</script>
<a id="XXXReScoreEvent"
href="#Url.Action("Readyforxxxxxx", "Exception", new { Id = (int)#ViewData["Id"] })"
class="btn btn-primary btn-default btn-too-large pull-left margin"
aria-label="XXXReScoreEvent">
<span class="glyphicon glyphicon-edit" aria-hidden="true"></span> Ready for xxxxxx Scoring
</a>
}
break;
I know its hitting the javascript, as that html element (a button) named '#UnUseableEvent' is correctly being hidden in this case. I of course would want the javascript out of this html page and just have function calls in the razor but baby steps
Specifically regarding the ('#systemExceptionLbl').innerText = txtMsg; I have tried
.text
.value
.innerHTML
all to no avail. I can see the correctly formatted Json.Encoded text reach the variable txtMsg, but again I cant get it into the div ..
I am having success now with displaying the div (remove class hidden) I was attempting to affect the wrong div name and the line removing the hidden class from the element $('#systemExceptionLbl') is not needed.
I even tried to skip the JQuery reference and go old school document.getElementById('systemExceptionLbl').innerHTML = txtMsg;
Ever tried :
$('#systemExceptionLbl').text( txtMsg );
or
$('#systemExceptionLbl').html( txtMsg );
as innerText is not a jquery function. Instead use .html() or .text() to insert data into it
I can't seem to work out how to get my first accordion panel to open automatically. Problem is, I can't set it to active as it is displaying data with PHP from a database so if I set the div to "active-panel" it applies it to all the panels. Any help would be great! Just to clarify, I'm just trying to get the first one to open automatically. Code:
$('.panel-holder').click(function () {
$(this).closest('.accordion').find('.panel-holder').removeClass('active-panel');
$(this).addClass('active-panel');
PHP
echo "<div class='panel-holder'>
<div class='panel-title'>". $results['job_title'] ."
<i class='icon arrow_carrot-down'></i>
</div>
<div class='panel-content'>
<p class='lead'>". $results['job_summary'] ."</p>
<p>". $results['job_description'] ."</p>
</div>
</div><!--end of individual accordian panel-->";
Just add the "active-panel" class to the first item in PHP only. Are those generated in a loop? Just create a counter variable that increases in every run of the loop. If this counter == 1 (or 0 if you want to start with 0 ;) ) add the css class to your markup.
Ended up creating the following solution:
$('.panel-holder').each(function () {
$(this).closest('.accordion').find('.panel-holder:first').addClass('active-panel');
});
This question may be related.
I have a Django recipe app that uses a form containing of a CharField TextArea. This field is used to enter a list of directions (string). I have chosen to separate each direction with a line break (ENTER in form), and use the following in my template (html) to keep line breaks as in original form
<div id="items">
<p>
{{ recipe.directions_field|safe }}
</p>
</div>
This will basically appear as something like
<div id="items">
<p>
Line one <br/>
Two <br/>
Three <br/>
</p>
</div>
What I want to do is to use jQuery to "check" (strikethrough) one single line (may contain of several words) in my template. I have tried the following, but as expected, this checks the entire paragraph.
<script>
$(document).ready(function() {
$("#items p").click(function () {
$(this).toggleClass('stroked');
});
});
</script>
Where my css has
.stroked{ text-decoration: line-through; }
In my Django view I replaced "\n" with html line break in order to make sure line breaks are not removed when shown in template.
directions = directions.replace("\n", "<br/>")
I think a solution like this would work if I could just find an easy way to use <br/> as a splitter instead of ". " or any other symbol. I couldn't make that work with <br/> in the example.
Any suggestions, either using a solution like this or another way? I guess there are many ways to solve this, but hope to find an easy implementation.
Thanks for any reply.
It's much easier if you wrap every single line into <span></span>, like this:
<div id="items">
<p>
<span>line one <br/></span>
<span>line two <br/></span>
<span>line three <br/></span>
</p>
</div>
So what you need to do in javascript is:
$(function(){
$('#items > p > span').click(function(){
if($(this).attr('class') == 'stroked'){
$(this).removeAttr('class');
}
else{
$(this).addClass('stroked');
}
});
});
I have some div boxes and when you click a link it replaces an existing box rather than stacks a new one below it.
It's probably best to show you rather than explain.
Or at least I would but creating a jsfiddle doesn't replicate what I see on my webpage.
My webpage is intranet so I cannot share.
This is the fiddle: http://jsfiddle.net/GR6pu/
(When trying to post I get asked to accompany a jsfiddle.net link with some code.
Not quite sure what is needed so I'll post this:)
var showed = 'com1';
function com(id) {
if (showed && showed !== id) {
document.getElementById(showed).style.display = 'none';
}
document.getElementById(id).style.display = 'block';
showed = id;
}
What should hopefully happen is:
You start in community box.
When you click 'lam' you get a box below it = 'lam activities'.
If you subsequently click 'dispatch' this 'lam activites' box is replaced with 'dispatch activities'.
This bit works fine on my website with what I have posted in the fiddle.
Then, in 'lam activities' if you click 't45' you should get another box below it, but on my website the 't45' box replaces the 'lam activities' box rather than stacks another below it.
My goal is to have the 't45' box stacked underneath the 'lam activities' box.
From reading other threads on the forum I know you like your posters to detail what they have tried...
My knowledge on all things web based is small.
4 weeks ago I had never created a website and I've managed to teach myself enough HTML and CSS to create a working website but Javascript is still new to me, hence I don't have the knowledge to fiddle about with the js to make it work.
I tried changing none to block but this then creates more boxes than I would like.
Thanks, Kristian
When you click 'lam' you get a box below it = 'lam activities'.
Then, in 'lam activities' if you click 't45' you should get another
box below it, but on my website the 't45' box replaces the 'lam
activities' box rather than stacks another below it.
my goal is to have the 't45' box stacked underneath the 'lam
activities' box.
Overall you got 2 issues, the HTML is invalid as closing tags are missing and your code is not correct, hence it will not show the expected elements.
Fixing your HTML
Your demo fiddle is broken in the first place and does not demonstrate the issue you have.
You cannot show lam1 if the lam1 element is inside the com2 element which you are still hiding display: none, please inspect your HTML after clicking t45:
The reason you end up with incorrect nested HTML like that is due to missing closing tags which creates invalid HTML.
All <a> tags are missing their matching </a> closing tags.
All main divtags, such as <div id="com1"..>, <div id="lam1"..>, etc.. are missing their matching </div> closing tags.
Browsers try a best-guess, adding closing tags where it seems most appropriate, hence you might end up with unexpected HTML, such as sibling elements becoming nested instead.
Edit: The </a> are not required (my bad), only the 3rd </div> was missing in each section. I updated the fiddle and posted code to reflect that
DEMO - Adding missing closing tags fixes the demo and now shows the issue you are having.
Fixing your code
Now that the missing closing tags are added fixing the HTML in the fiddle which now works and shows the issue we can fix your code.
Your second function will always hide the t45 element and then show the task-element, hence it "replaces" it. I'm assuming you want similar functionality whereby the task element is replaced as you click on different "tasks".
In that case you cannot use the showed id but need to keep a separate record of the task-id (or what ever you want to call it)
function lam(id) {
// this removes the t45 element you want to keep
// I'm assuming you want to track clicked lams separately
if (showed && showed !== id) {
document.getElementById(showed).style.display = 'none';
}
document.getElementById(id).style.display = 'block';
showed = id;
}
Change that to the following and both elements are visible.:
var taskId;
function lam(id) {
if (taskId && taskId !== id) {
document.getElementById(taskId).style.display = 'none';
}
document.getElementById(id).style.display = 'block';
taskId = id;
}
DEMO - Fixing the code.
Here is the fixed HTML and code for completeness from the fiddle above.
HTML:
<div class='whitebox'>
<div class='subheader'>community</div>
<div class='links'>
<a onclick="com('com1');"><div class='boxlink'>LAM</div>
<a onclick="com('com2');"><div class='boxlink'>DISPATCH</div>
<a onclick="com('com3');"><div class='boxlink'>PLANNING</div>
</div>
</div> <!-- closing </div> was missing -->
<div id="com1" style="display:none">
<div class='whitebox'>
<div class='subheader'>lam activities</div>
<div class='links'>
<a onclick="lam('lam1');"><div class='boxlink'>T45</div>
<a onclick="lam('lam2');"><div class='boxlink'>SYNC</div>
<a onclick="lam('lam3');"><div class='boxlink'>ESSS</div>
<a onclick="lam('lam4');"><div class='boxlink'>IND</div>
</div>
</div>
</div> <!-- closing </div> was missing -->
<div id="com2" style="display:none">
<div class='whitebox'>
<div class='subheader'>dispatch activities</div>
<div class='links'>
<a onclick="lam('lam2');"><div class='boxlink'>SYNC</div>
<a onclick="lam('lam3');"><div class='boxlink'>ESSS</div>
</div>
</div>
</div> <!-- closing </div> was missing -->
<div id="lam1" style="display:none">
<div class='whitebox'>
<div class='subheader'>t45 tasks</div>
<div class='links'>
<a onclick="t45('t451');"><div class='boxlink'>REMOVAL</div>
<a onclick="t45('t452');"><div class='boxlink'>ADJUST</div>
<a onclick="t45('t453');"><div class='boxlink'>RECEIPT</div>
</div>
</div>
</div> <!-- closing </div> was missing -->
<div id="lam2" style="display:none">
<div class='whitebox'>
<div class='subheader'>sync tasks</div>
<div class='links'>
<a onclick="t45('t451');"><div class='boxlink'>emea</div>
<a onclick="t45('t452');"><div class='boxlink'>namer</div>
<a onclick="t45('t453');"><div class='boxlink'>s asia</div>
<a onclick="t45('t454');"><div class='boxlink'>n asia</div>
</div>
</div>
</div> <!-- closing </div> was missing -->
JavaScript:
var showed = 'com1';
var taskId;
function com(id) {
if (showed && showed !== id) {
document.getElementById(showed).style.display = 'none';
}
document.getElementById(id).style.display = 'block';
showed = id;
}
function lam(id) {
if (taskId && taskId !== id) {
document.getElementById(taskId).style.display = 'none';
}
document.getElementById(id).style.display = 'block';
taskId = id;
}
Lets break this down:
if (showed && showed !== id) {
document.getElementById(showed).style.display='none';
}
If showed is set and is not equal to the new id passed in the function, get the element with the ID of id and set it to display:none;
document.getElementById(id).style.display='block';
Get the element with the ID of id and set it to display:block;
showed=id;
Set the showed variable to be the value of the id passed into the function.
So basically, the function hides the previous element and then shows the element that has the ID you passed into the function. If you don't want to hide the previous element, you just need to remove the part of the function that does that (the if( showed && showed !== id ) { ... } statement block)