Handling Show More/Less text in React Native - html

I'm getting a response from a remote API in HTML format. The whole thing is not supposed to be shown unless you press Read More button
The response looks as follows:
"<p>A suspension concentrate (SC) formulation containing 450 g/litre of napropamide (41.4% w/w) for the control of annual grass and broad-leaved weeds in winter oilseed rape.</p>\r\n<p><strong>DIRECTIONS FOR USE</strong><br /> IMPORTANT: This information is approved as part of the product label. All instructions within this section must be read carefully in order to obtain safe and successful use of this product.</p>\r\n<p><strong>RESTRICTION/WARNINGS</strong><br /> Weed control may be reduced where the spray is mixed too deeply into the soil. <br />Do not treat crops adversely affected by poor soil, adverse weather or cultural conditions. <br />Avoid spray overlap, particularly on headlands. <br />It is important to ensure that the seedbed is free from clods and weeds, and in good tilth.<br /> Incorporation under wet conditions is not satisfactory. <br />AC650 can be used on a wide range of soils but should not be applied to Sands (ADAS ’85 system)
...
I render it using react-native-render-html library which unfortunately does not have numberOfLines prop.
I tried a solution suggested on Github that involves adding custom renderer that substitutes all the <p> tags with react native <Text> tag which has numberOfLines props that I need:
<HTML
html={`<p>${description}</p>`}
renderers={{p: (_, children) => <Text numberOfLines={5}>{children}</Text>}}
/>
It worked but the problem is that I have several <p> tags inside my description variable and it shows all of them shortened to whatever number of lines I entered instead of shortening the whole article. So I figured that I must use a unique tag to wrap the whole HTML content and then apply the same logic
<HTML
html={`<section>${description}</section>`}
renderers={{section: (_, children) => <Text>{children}</Text>}}
/>
Again, the solution worked but it messed up the content inside. Line breaks were not applied, etc.
After a few more Google searches up stumbled upon a 3rd party library called react-native-read-more-text
I understand that it only works with content inside <Text> tag so once again I wrapped by <Text> using template string
<ReadMore
numberOfLines={10}
renderTruncatedFooter={renderTruncatedFooter}
renderRevealedFooter={renderRevealedFooter}>
<HTML
html={`<Text>${description}</Text>`}
/>
</ReadMore>
This time I received an error:
I would appreciate any help

My suggestion would rather be not to mess-up with react-native-render-html, and instead do the following:
wrap your HTML content inside a container which height approximates 5 lines;
this container has a fading effect towards its bottom (typical in user-review platforms such as Goodreads);
at the bottom of this container, a "read more" button can be pressed to expand the container height to fit the html content height.
If however you need one tag renderer in peculiar to implement such feature, you should take a look at this SO post: https://stackoverflow.com/a/69200348/2779871

This is now supported by react-native-render-html
import HTML from 'react-native-render-html'; // V6.3.4
const defaultTextProps = {
numberOfLines: 10,
};
return (
<HTML
source={{ html: text }}
defaultTextProps={defaultTextProps}
/>
);
Github Issue
I hope this helps. I would be interested to know what you went with in the end as I am currently solving a similar use case.

Related

Can we auto-expand an HTML 'details' when a hyperlink points to it?

I am creating a page with language information. Since it is extremely long, I collapse each language with details/summary tags and have them in alphabetic sections with each initial letter also a collapsed details. Currently, each language is coded like
<details>
<summary id="am"><b>am — Amharic</b></summary>
<p><img src="/wp-content/uploads/2018/05/GBV-Amharic-150.jpg"/>About 22 million native speakers, … [more info]</p><br clear="all"/>
</details>
If I put a link elsewhere like http://domain.TLD/path/#am, I'd like to take the user to that page, scroll to that section, and expand the details. If that's possible, do I have the wrong syntax for one or both sides? It is not working now—nothing expands and it goes to the top of the page as if the # were not there. But the address field shows the full URI of the link, #id included.
"path/" is interpreted by Wordpress and/or a Wordpress-generated .htaccess, so perhaps that somehow prevents it working correctly.
You have the correct syntax for directing a user to an element with the id "am."
You can check the URL the browser used to display the page with jQuery. For your example if a link sent a user to http://domain.TLD/path/#am the following code would trigger if the browser contained "path/#am" as part of the URL.
jQuery(document).ready(function($) {
if(window.location.href.indexOf("path/#am")){
/* do something to the element in jQuery -- likely apply a class.
*/
}
There are many animation and scrolling libraries related to jQuery as well.

HTML XPath: Extracting text mixed in with multiple level and complex tags?

related questions before:
HTML XPath: Extracting text mixed in with multiple tags?
HTML XPath: Selectively avoiding tags when extracting text
//sorry for my poor English
I'm a beginner of writing web crawler, I'm trying to extract main content from a web pages(in Chinese) by xpath(though I have learned that there are algorithms both taditional and machine learning ways to extracting web main content) ,and I'm a very beginner at writing xpath rules.
I'm in faced with a web page that contains text mixed in complex tags,I summarize it as follows,where character(e.g. A,A2) means text only,'...' means more tags even nested without text.I want to get "AA2BB2CDEFGHIJKLMNOP"
...
<div id="artibody" class="art_context">
<div align="center">...</div>
<div align="center"><font>A</font>A2</div>
<div align="left"><br><br><strong>B</strong>B2</div>
<div align="left">
<p>C<a>D</a>E</p>
<p>F<a>G</a>H<a>I</a>J</p>K
</div>
<div align="center">...</div>
<div align="center"><font>L</font></div>
<p>M</p><!--M contains only text luckly-->
<p>N</p>
<p>O</p>
<p>P<span>...</span><div class="shareBox">...</div>
</p>
<span id="arctTailMark"></span>
<script>
var page_navigation = document.getElementById('page_navigation');
...
</script>
<div style="padding:10px 0 30px 0">...</div>
</div>
Thanks for previous questions, I write a rule
'string(//div[#class=\"art_context\"])'
I get all content in plain text I want without tags ,but the js code in <script> is extracted as well.I tried the following,but it seems not helpful.There are still js codes in it .
'string(//div[#class=\"art_context\" and not(self::script)])'
The following one get "\r\n" only.
'//div[#class=\"art_context\" and not(self::script)]/text()'
Here are my questions:
1.How to write the xpath rule to meet my need : extracting content in div[#id="artibody"] except codes in <script>
2.Is the rule for question1 simple and powerful? Maybe I will meet more pages with a div[#id="artibody"] but the descendant nodes are quite different.
3.Any further suggestions on my task? Extracting web content from one website,but the main content lays in <div> with different id,class,and descendant node structure. I run the spider on my laptop(Intel corei5 3225,8G RAM) while using machine learning algorithms may decrease the crawl speed significantly.At the same time writing many xpath rule seems bothering.
I'd appreciate it if you could give me any suggestions on this question(and my English).
To get all descendant text nodes except the script contents, you can use this:
//div[#class="art_context"]//*[not(self::script)]/text()
In natural language: “Get all text nodes from descendants of all div[#class="art_context"] elements that are not script elements”.
The // after div[#class="art_context"] is needed to select descendants, not just children.
In comparison, the //div[#class="art_context" and not(self::script)]/text() expression in the question says “Get all text-node children of all div[#class="art_context"] elements that are not also script elements.”
So the and not(self::script) part in the expression in the question is redundant, because all the expression is doing is selecting just //div[#class="art_context"] anyway, and then the /text() part is selecting only the text-node direct children of that div, which is just line breaks.
Also, if instead of using XPath to just get the set of text nodes, you want to use XPath to get the result as a single string, you can use the functions string-join(…) and normalize-space(…):
normalize-space(string-join(//div[#class="art_context"]//*[not(self::script)]/text(), ""))

What do square brackets mean in html?

I am assisting on a project right now and building out templates for the first time, trying to wrap my head around a few things but one aspect of the html that's confusing me are certain things sitting in square brackets. I've never used these in html before so I'm just wondering what they are for (when I open the page in a browser they all show up as text)
Here's a bit of the code:
<div class="container">
[HASBREADCRUMBS]
<ol class="nav-breadcrumb">
[BREADCRUMBS]
</ol>
[/HASBREADCRUMBS]
<h1 class="header-title" style="color:[TITLECOLOR];font-size:[TITLESIZE];">[TITLE]</h1>
</div>
It's using some templating engine and the whole page is parsed before getting output to the browser. During parsing, those square bracket tags work as something else (depending on the templating engine used).
So, for example, [HASBREADCRUMBS] and [/HASBREADCRUMBS] could denote a piece of code that might be similar to:
if (breadcrumbs) {
and:
} // closed if
and for each value of the breadcrumbs object (whatever it might be) one ordered HTML list is rendered with the breadcrumb value as its content ([BREADCRUMBS]).
So in short: it's not HTML, that part of the file never reaches the browser but is converted into proper HTML (based on conditions, can also use loops, etc.) before rendering.
The square brackets have nothing to do with HTML. They probably belong to the template and will be replaced by actual value from the template engine.

CKEditor 4 and nonstandard HTML element

Here is a nonstandard HTML element that I defined (AngularJS makes this easy):
<exercise id="Sample Exercise" language="Scala" lectureId="5437">
This is the text of the lecture
</exercise>
If I use this element in an HTML document, each time I switch from CKEditor's rendered mode to source mode a new empty paragraph is added between each of the block elements in the document:
<p> </p>
The 2nd time I switch, I get two insertions:
<p> </p>
<p> </p>
The 3rd time I switch, I get three insertions between each block-level element, etc:
<p> </p>
<p> </p>
<p> </p>
Can anyone suggest a workaround?
It seemed easier to avoid custom elements and so I used HTML5 data attributes.
<div class="exercise" data-id="Challenge #42" data-language="Scala" data-lectureid="5437">
<p>Create a program that outputs the meaning of life, the universe, and everything.</p></div>
This worked out. Maybe greater integration between CKEditor and AngularJS will evolve over time.
Pekka's question is very good - why do you need to load a custom element into CKEditor? Neither browsers (which do one part of WYSIWYG editing) not CKEditor (which does another part) know how to handle this element, what it means, how to render it and how editing features should work around it. For example, if I understood your question, you wrote about <exercise> that it is a block element. How do CKEditor and browsers know that it is a block element? :|
Second thing you should understand is that CKEditor is not a WYSIWYG website builder, but a "documents" editor. Its content has to have a meaning for it and that tag won't have it.
Anyway, if you must go this way, there are some things you can do.
Here are two answers that can give you an idea what you can do: CKEditor strips <i> Tag.
If you'll decide not to protect source of your <exercise> tags, but to render them, then you should also know about the CKEDITOR.dtd object, which I described briefly here: ckeditor how to allow for .insertHtml("<customTag myAttr='value'"></customTag>").

Disable auto-adding of <p> tag

I'm trying to remove auto-adding of <p> tag in CQ5(Version 5.6.0.20130125). I've tried to add these properties to the text component I'm using but with no effect.(source)
removeSingleParagraphContainer true
singeParagraphContainerReplacement (empty string)
I've also tried this solution. Again, no effect.
Is it possible to disable auto-adding of <p> tag?
Thanks for any ideas
EDIT I've tried this answer but CQ still adds <p> tags to my code. For example, I have this HTML code
<strong>Headquarters:</strong>
<p>MY - COMPANY a.s.<br>
Random Street 77<br>
Random City</p>
and after I submit it, the code changes to
<p><strong>Headquarters:</strong></p>
<p>MY - COMPANY a.s.<br>
Random Street 77<br>
Random City</p>
my RTE looks like this
<text jcr:primaryType="cq:widget"
hideLabel="{Boolean}true"
name="./text"
xtype="richtext">
<htmlRules jcr:primaryType="nt:unstructured">
<docType jcr:primaryType="nt:unstructured">
...
</docType>
<blockHandling
jcr:primaryType="nt:unstructured"
removeSingleParagraphContainer="{Boolean}true"/>
</htmlRules>
</text>
EDIT2 this is what my hierarchy looks like
You can keep the RTE from surrounding your text with <p> tags by setting the removeSingleParagraphContainer property to true as long as you only create one paragraph.
With Chrome on Mac OS X (at least), holding shift while pressing enter inserts line breaks instead of paragraph breaks so you can still create text with multiple lines. Since you said in your last question that you're using the misctools plugin, you can use the source edit view to peek at the markup as you go.
Finally, to set the removeSingleParagraphContainer property, you'll need to create another child called blockHandling under your htmlRules node in your dialog. You don't need to mess with singeParagraphContainerReplacement property, but if you did, you would set it on the same node:
<rtePlugins jcr:primaryType="nt:unstructured">
...
</rtePlugins>
<htmlRules jcr:primaryType="nt:unstructured">
<docType jcr:primaryType="nt:unstructured">
...
</docType>
<blockHandling
jcr:primaryType="nt:unstructured"
removeSingleParagraphContainer="{Boolean}true"/>
</htmlRules>
Edit regarding your edit: using the source edit feature of the misctools plugin and pasting this exact text saves and loads without p tags for me in Chrome on Mac OS X:
<strong>Headquarters:</strong><br>
MY - COMPANY a.s.<br>
Random Street 77<br>
Random City
Are you sure your dialog.xml deployed properly? Maybe double-check that your component's dialog hierarchy looks how you'd expect it to in CRXDE Lite:
The property removeSingleParagraphContainer should be added in node with xtype is richtext.
Example:
<text jcr:primaryType="cq:Widget"
hideLabel="{Boolean}true"
name="./text"
height="{Long}520"
removeSingleParagraphContainer="{Boolean}true"
xtype="richtext">
CRXDE Lite: configuration in crxde lite
Note: And this configuration is only used for single paragraph.
Refer: more info about removeSingleParagraphContainer
Try using #context='html' in your code. This lets you set the context of the text as html so even if there are tags in your dialog value, they will be rendered as equivalent html and not as tag on the page.
eg :
{properties.something #context='html'}
For Touch UI, you can also create a custom paraformat option in the AEM Touch UI, cq/gui/components/authoring/dialog/richtext, and then using Java Backend, Sling Model, to text-transform the output, so that your Sightly HTL can render the output Html as expected. For the full tutorial, you can find it here.
https://sourcedcode.com/blog/aem/aem-richtext-remove-p-tag-removesingleparagraphcontainer-for-touch-ui
Try using #context='unsafe' in your code. You should be able to get rid of the unnecessary HTML tags, worked for me