Angular read more button based on NUMBER OF LINES not number of letters - css

What I need is an Angular or CSS solution which will add a "read more" button if the text is more than 5 lines long.
I have an Angular page which displays text, which has a letter limit of 150 characters.
{{post.post_text | limitTo:letterLimit}}
But in some instances the posts are too long, because they have been written with many many line breaks ie :
my post
line 2
line 3
l
i
n
e
...still less than 150 chars, but it begins to break my page.
So I need is an Angular or CSS solution which will add a "read more" button if the text is more than 5 lines long.
Forgive me, but this is my first attempt at Angular, I don't know where to start! Any help would be much appreciated.
so far
I have only found answers and tutorials which relate to number of characters. I really need a solution based on number of lines or total line-height. Thanks.

You can try such a filter:
{{post.post_text | limitTo:letterLimit | maxLines: linesLimit}} // toggle lines limit with the show more
app.filter('maxLines', function() {
return function(txt, limit) {
var parts = txt.split("\n");
if(limit == 0) return parts.join('<br/>');
return parts.slice(0,limit).join('<br/>');
}
})
In view:
<button class="show-more" ng-if="checkLines(checkLines(resource.description)"></button>
In Controller:
$scope.lines_limit_default = 3;// ex.
function checkLines(txt) {
if(txt && txt != null) {
return (txt.split("\n").length > $scope.lines_limit_default) ? true : false;
} else return false;
};

Related

DocXtemplater multiple tags on a single line behavior

I am replacing an old program for template-merging with docxtemplater and am trying to recreate the old programs prefix functionality.
I want the line removed if all prefixed tags ({$tag}) on that line are undefined.
The issue being that if all the tags on that line are undefined docxtemplater still creates a blank line.
All the examples I have found online tend to reference inverted-sections or rawtags, which both seem to be designed for a single tag per line opposed to multiple tags side by side.
I have looked into using rawtags and writing a custom-parser / nullGetter. However I am still none the wiser to removing the blank line.
I am using:
const options = {
paragraphLoop: true,
linebreaks: false,
parser: function(tag) {
return {
get(scope, context) {
console.log(tag);
console.log(scope);
console.log(context);
if (tag[0] == "$") {
tag = tag.substr(1); // needs to then remove line break
}
return scope[tag];
}
}
},
nullGetter: function nullGetter(part, scopeManager) {
if (!part.module) {
return "";
}
if (part.module === "rawxml") {
return "";
}
return "";
}
};
doc = new Docxtemplater(zip, options);
The prefix in the program I am replacing acts as follows:
data:
existingtag: EXISTINGTAG
Template.docx:
1 text above
{$existingtag}{$nonexistingtag}
text below
2 text above
{$existingtag}{$existingtag}
text below
3 text above
{$nonexistingtag}{$nonexistingtag}
text below
old program produced (What I want to produce)
1 text above
EXISTINGTAG
text below
2 text above
EXISTINGTAGEXISTINGTAG
text below
3 text above
text below
my docxtemplater produces (extra line in example 3):
1 text above
EXISTINGTAG
text below
2 text above
EXISTINGTAGEXISTINGTAG
text below
3 text above
text below
I'm the creator of docxtemplater and I don't think that there is a way to do what you want to achieve without taking a lot of time to handle this case.
The problem is that the tags such as :
{xxx}{yyy}
have access only to the text that they are in, but they cannot have any effect ouside of that text, so it is not possible to remove a paragraph conditionnally.
There is one tag that has access to the whole paragraph, that is the raw xml tag, prefixed by a "#", like this :
{#raw}
It is used to add rawXML and if the raw value is an empty string, than that paragraph will be removed.
Edit : I have actually worked on a module back in the time to achieve quite similar functionnality, it is a paid module : https://docxtemplater.com/modules/paragraph-placeholder/

RStudio Visual editor - data.frame preview too narrow, does not resize

I'm trying to use the RStudio Visual Editor more for Quarto notebooks.
I really like it, but I there's an issue that makes it unusable: when I print a data.frame from a chunk, it gets printed in a very narrow rectangle that does not scale up (as it would with the normal source editor).
This makes it unusable because often I can't see the full variable names or the full values.
I tried looking at the options (Global Options > R Markdown > Visual) but I can't find anything that changes this: Editor content width only changes the width of the text and code, not the chunk output.
Coercing a data.frame to tibble also doesn't fix this.
I'm using RStudio 2022.07.2 Build 576.
Alright I know I answered this question before. I can't find that question or my answer in Stack Overflow, but I found the script I used to create & test the answer. I tested it because I think it was a few years ago. Everything seems to work.
This isn't a permanent solution. It will persist until you restart RStudio.
Step 1: Right-click anywhere in RStudio and select 'Inspect Element' from the dropdown to open developer tools. If you weren't aware, it's just like a browser that way.
Step 2: You need to use the console. Whether you use the console drawer (three dots) or the console tab (top of the inspector window, second from the left).
The first JS function
At the cursor, you'll paste two javascript functions. I store these in an RMD, within a JS chunk. They won't do anything when you knit.
allOf = document.querySelectorAll('[data-ordinal]'); //find them all
if (allOf==undefined || allOf==null) {
allOf = document.querySelector('[data-ordinal]'); // if there is only one
}
sAdd = "max-width: none;" // create style to add
try{
for(i = 0, n = allOf.length; i < n; i++){ //loop through them all
styler = allOf[i].getAttribute("style");
if (styler==undefined || styler==null) { // if there are no HTML styles set
styler = "";
console.log("No style attributes found for ", i);
}
if (styler!="width: 100%; max-width: 800px;") {// if this isn't a chunk output as expected
continue;
console.log("Attributes not changed for ", i);
}
allOf[i].setAttribute("style",styler+sAdd);
console.log("Attributes set for ", i);
}} catch(error) {
console.error(error);
}
The second JS function
allMore = document.querySelectorAll('.ace_lineWidgetContainer > div'); // first child of class
if (allMore==undefined || allMore==null) {
allMore = document.querySelector('.ace_lineWidgetContainer > div'); // if there is only one
}
sAdd2 = "overflow: visible;" // create style to add
try{
for(j = 0, m = allMore.length; j < m; j++){ //loop through them all
styler2 = allMore[j].getAttribute("style");
if (styler2==undefined || styler2==null) { // if there are no HTML styles set
styler2 = "";
console.log("No styles were found for ", j)
}
allMore[j].setAttribute("style",styler2+sAdd2); // append new styles
allMore[j].style.height = null; // remove the height style
console.log("Attributes set for ", j);
}} catch(error) {
console.error(error);
}
The console after entering the functions.
The inline rendered chunks before and after side by side

Change line-height depending on number of characters

In my React website I'd like to change the line-height property of a word I have that changes length (based on some other logic). What I'm doing is that every letter of the word is on a separate line:
.myWord {
line-height: 3.9;
word-break: break-all;
}
outputs:
m
y
w
o
r
d
But I also need it to line up with another element next to it, so that it would always be equally tall. The current line-height is only fitting for a word that is 6 letters long.
I found a similar question on stackoverflow with a jQuery answer:
var cnt = $(".tweeter_widget").text().length;
if (cnt > 10) {
$(".tweeter_widget").css("line-height", "5px");
}
If someone could translate that into JSX or provide a different answer, I would highly appreciate.
The logic would basically be:
If the word is 6 letters long, line-height will be 3.9
If the word is 5 letters long, line-height will be 4.2
...
I only need it for 3-6 letter words so it's no problem to write them all out.
Given that I am not totally sure to have understood your question but...
Let's say that we have a MyWord component, in relation to the length of the text given, we need to apply to the element a certain amount of line-height property.
I would first of all have a map of the length-lineHeight matches, something like this:
// the key is the text length, the value is the applicable line-height
const HEIGHTS = {
5: 4.2,
6: 3.9
}
If it useful, we could keep a default, just in case we missed something
const DEFAULT_HEIGHT = 1
Then, we need a simple MyWord component that only takes a text prop. We assign an inline style property value upon the text prop length:
const MyWord = ({ text }) => (
<div
className="myWord"
style={{
lineHeight: HEIGHTS[text.length] || DEFAULT_HEIGHT
}}
>
{ text }
</div>
)
This is just an idea of mine, whether I got the question at all... I made a sample Pen... https://codepen.io/ciamiz/pen/VEXNQo

Difference between two element styles with Google Chrome

I use Google Chrome developer tools and I am constantly inspecting one element against another back and forth to find out what may be causing a particular styling issue.
It would be nice to compare the differences in style between element 1 and element 2.
Can this be done with chrome currently or via some workaround? Is there a tool out there that can do what I am looking for?
Current example of style difference is that I have an inline H4 next to a A where the A is appearing higher in vertical alignment. I am not seeking a solution in this question as I will sort it out.
Update: As a result of this discussion, the "CSS Diff" Chrome extension was created.
Great question and cool idea for extension!
Proof of concept
As a proof of concept, we can do a small trick here and avoid creating extension. Chrome keeps elements you select via 'inspect element' button in variables. Last selected element in $0, one before that in $1 etc. Basing on this, I've created a small snippet that compares last two inspected elements:
(function(a,b){
var aComputed = getComputedStyle(a);
var bComputed = getComputedStyle(b);
console.log('------------------------------------------');
console.log('You are comparing: ');
console.log('A:', a);
console.log('B:', b);
console.log('------------------------------------------');
for(var aname in aComputed) {
var avalue = aComputed[aname];
var bvalue = bComputed[aname];
if( aname === 'length' || aname === 'cssText' || typeof avalue === "function" ) {
continue;
}
if( avalue !== bvalue ) {
console.warn('Attribute ' + aname + ' differs: ');
console.log('A:', avalue);
console.log('B:', bvalue);
}
}
console.log('------------------------------------------');
})($0,$1);
How to use it?
Inspect two elements you want to compare, one after another, and paste the code above to console.
Result

Last line of a paragraph contains a single word only [duplicate]

This question already has answers here:
Widow/Orphan Control with JavaScript?
(7 answers)
Closed 8 years ago.
A common problem when working with typography in HTML/CSS is something we call "horunge" in Swedish ("widow" in english).
What it is:
Let's say you have a box with a width of 200px and with the text "I love typograpy very much". Now the text breaks and becomes:
I love typography very
much
As a designer I don't want a word bastard (single word / row). If this was a document/PDF etc. I would break the word before very and look like this:
I love typography
very much
which looks much better.
Can I solve this with a CSS rule or with a javascript? The rule should be to never let a word stand empty on a row.
I know it can be solved by adding a <br /> but that's not a solution that works with dynamic widths, feed content, different translations, browser font rendering issues etc.
Update (solution)
I solved my problem with this jquery plugin: http://matthewlein.com/widowfix/
A simple jQuery / regrex solution could look like the following, if you add the class "noWidows" to the tag of any element that contains text you are worried about.
Such as:
<p class="noWidows">This is a very important body of text.</p>
And then use this script:
$('.noWidows').each(function(i,d){
$(d).html( $(d).text().replace(/\s(?=[^\s]*$)/g, " ") )
});
This uses regex to find and replace the last space in the string with a non-breaking character. Which means the last two words will be forced onto the same line. It's a good solution if you have space around the end of the line because this could cause the text to run outside of an element with a fixed width, or if not fixed, cause the element to become larger.
Just wanted to add to this page as it helped me a lot.
If you have (widows) actually should be orphans as widows are single words that land on the next page and not single words on a new line.
Working with postcodes like "N12 5GG" will result in the full postcode being on a new line together but still classed as an orphan so a work around is this. (changed the class to "noWidow2" so you can use both versions.
123 Some_road, Some_town, N12 5GG
$('.noWidows2').each(function(i,d){
var value=" "
$(d).html($(d).text().replace(/\s(?=[^\s]*$)/g, value).replace(/\s(?=[^\s]*$)/g, value));
});
This will result is the last 3 white spaces being on a new line together making the postcode issue work.
End Result
123 Some_road,
Some_town, N12 5GG
I made a little script here, with the help of this function to find line height.
It's just an approach, it may or may not work, didn't have time to test throughly.
As of now, text_element must be a jQuery object.
function avoidBastardWord( text_element )
{
var string = text_element.text();
var parent = text_element.parent();
var parent_width = parent.width();
var parent_height = parent.height();
// determine how many lines the text is split into
var lines = parent_height / getLineHeight(text_element.parent()[0]);
// if the text element width is less than the parent width,
// there may be a widow
if ( text_element.width() < parent_width )
{
// find the last word of the entire text
var last_word = text_element.text().split(' ').pop();
// remove it from our text, creating a temporary string
var temp_string = string.substring( 0, string.length - last_word.length - 1);
// set the new one-word-less text string into our element
text_element.text( temp_string );
// check lines again with this new text with one word less
var new_lines = parent.height() / getLineHeight(text_element.parent()[0]);
// if now there are less lines, it means that word was a widow
if ( new_lines != lines )
{
// separate each word
temp_string = string.split(' ');
// put a space before the second word from the last
// (the one before the widow word)
temp_string[ temp_string.length - 2 ] = '<br>' + temp_string[ temp_string.length - 2 ] ;
// recreate the string again
temp_string = temp_string.join(' ');
// our element html becomes the string
text_element.html( temp_string );
}
else
{
// put back the original text into the element
text_element.text( string );
}
}
}
Different browsers have different font settings. Try to play a little to see the differences. I tested it on IE8 and Opera, modifying the string every time and it seemed to work ok.
I would like to hear some feedback and improve because I think it may come in handy anyway.
Just play with it! :)
There are also CSS widows and orphans properties: see the about.com article.
Not sure about browser support...
EDIT: more information about WebKit implementation here: https://bugs.webkit.org/buglist.cgi?quicksearch=orphans.
Manually, you could replace the space in between with
I've been looking for ways to dynamically add it in. I found a few, but haven't been able to make it work myself.
$('span').each(function() {
var w = this.textContent.split(" ");
if (w.length > 1) {
w[w.length - 2] += " " + w[w.length - 1];
w.pop();
this.innerHTML = (w.join(" "));
}
});
#foo {
width: 124px;
border: 1px solid #ccc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
<span class="orphan">hello there I am a string really really long, I wonder how many lines I have</span>
</div>

Resources