How to recursively search the DOM and return first element that has a specified class - dom

For example - return the 1st element that has class = "title".
The result in this case should be div3.1
Should only use vanilla JS.
<body>
<div class="container">
<div class="abc"> div1</div>
<div class="abc"> div2
<div class="abc">div2.1
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, ipsum?</p>
</div>
<div class="abc">div2.2</div>
<div class="abc">div2.3</div>
</div>
<div class="abc"> div3
<div class="title">div3.1</div>
<div class="title">div3.2
<img src="" alt="">
</div>
</div>
</body>

I don't know about recursively, but querySelector() does just that. It will find the first element that matches the given parameter. The parameter is a CSS selector, so:
id: #abc
class: .abc
attribute: [abc]
tag: div
There's the old school way as well using getElementsByClassName():
var abc = document.getElementsByClassName('abc')[0];
The getElementsByClassName() returns a HTMLCollection/NodeList of all elements with a given className, using the bracket notation ([0]) suffix insures that it only returns the first element of the NodeList.
Demo
var title1 = document.querySelector('.title');
var title2 = document.getElementsByClassName('title')[0];
console.log(title1.textContent);
console.log(title2.textContent);
<body>
<div class="container">
<div class="abc"> div1</div>
<div class="abc"> div2
<div class="abc">div2.1
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, ipsum?</p>
</div>
<div class="abc">div2.2</div>
<div class="abc">div2.3</div>
</div>
<div class="abc"> div3
<div class="title">div3.1</div>
<div class="title">div3.2
<img src="" alt="">
</div>
</div>
</div>
</body>

I'm afraid you provided too little details in your question. If you want to find element with specified class, you can use document.querySelector method.
You can't "recursively" search whole DOM (starting from certain node I'm assuming?), but you can search specific DOM "branch" (element and its parents, up to document body). You can use function like:
function findElementWithClass(sourceElement, className){
var element = sourceElement; //selected DOM node
while(element !== document.body){
if(element.classList.contains(className)){
break;
}
element = element.parentNode;
}
return element;
}
After while loop you can make additional check if element you wanted has been found - if not, you can return false or do whatever you like.
JS Fiddle link: https://jsfiddle.net/8o9jzt8h/

Related

AEM HTL looping using data-sly-repeat

<footer id="footer">
<div class="container">
<div class="row double">
<div class="6u">
<div class="row collapse-at-2">
<div data-sly-repeat="${properties.colNum}" data-sly-unwrap>
<div class="6u">
<h3>Accumsan</h3>
<ul class="alt">
<li>Nascetur nunc varius</li>
<li>Vis faucibus sed tempor</li>
<li>Massa amet lobortis vel</li>
<li>Nascetur nunc varius</li>
</ul>
</div>
</div>
</div>
</div>
<div class="6u">
<h2>Aliquam Interdum</h2>
<p>Blandit nunc tempor lobortis nunc non. Mi accumsan. Justo aliquet massa adipiscing cubilia eu accumsan id. Arcu accumsan faucibus vis ultricies adipiscing ornare ut. Mi accumsan justo aliquet.</p>
<ul class="icons">
<li><span class="label">Twitter</span></li>
<li><span class="label">Facebook</span></li>
<li><span class="label">Instagram</span></li>
<li><span class="label">LinkedIn</span></li>
<li><span class="label">Pinterest</span></li>
</ul>
</div>
</div>
<ul class="copyright">
<li>© Untitled. All rights reserved.</li>
</ul>
</div>
</footer>
I am trying to use data-sly-repeat to loop and I have verified that the value of colNum is 2 but still the loop is running only once. In other words, it doesn't loop through irrespective of the value. I also hardcoded the value 3 but it still won't run the loop more than once. Not sure what I am doing wrong here.
Thanks in advance
In sightly you can only iterate over a collection using sly-repeat or sly-list.So instead here instead using the ColNum directly you will have to make a simple collection .
Refer: https://docs.adobe.com/docs/en/htl/docs/block-statements.html
It seems you have misunderstood how data-sly-repeat is intended to be used. You can read their documentation to get clarification.
Two things:
data-sly-repeat repeats the whole element that is marked, while data-sly-list only repeats the content of the element. In your case it seems list is more appropriate.. You can eliminate the actual div that you are currently unwrapping.
Rather than passing in a number of times to repeat the HTML you pass in a list of things to iterate over. The html is rendered for each item in the list, with the ${item} variable being used to hold the current item.
So, you'll have to write some Java of JS code to turn your colNum into a list of that size.
For example, using the JS Use API. (see this question for ways to create empty iterable arrays)
"use strict";
use(function () {
let n = properties.get("colNum", 0);
return {
columns: [...Array(100)] // empty, iterable, array of size n
};
});
And calling it from the HTL. Notice I removed the extraneous div and am using data-sly-list to loop over the n length array of empty elements
<div class="row collapse-at-2"
data-sly-use.config="<JS-file-name>"
data-sly-list="${config.columns}">
<div class="6u">
<h3>Accumsan</h3>
<ul class="alt">
<li>Nascetur nunc varius</li>
<li>Vis faucibus sed tempor</li>
<li>Massa amet lobortis vel</li>
<li>Nascetur nunc varius</li>
</ul>
</div>
</div>
data-sly-repeat needs an iterable object. You can provide a dummy array with the needed number of elements or, even better, an array with usefull things, such as column names or data.

wrap content elements in specific pages differently

All of my content elements are wrapped using stdWrap.wrap.
I am looking for a solution to wrap content elements in the page which i have my ke_search added differently .
Why do you need another HTML-markup?
Normaly you have another <div> around your search results which should enable you to add another styling by CSS.
your page may look like:
<body>
<div class="header">
:
</div>
<div class="content">
<div id="C123">
<h3>my very special CE</h3>
<p class="bodytext">with some text to demonstrate.</p>
</div>
<div id="345">
<h3>your search results:</h3>
<div class="search-results">
<a href="index.php?id=67&s=special">
<div id="C123">
<h3>my very special CE</h3>
<p class="bodytext">with some text to demonstrate.</p>
</div>
</a>
<a href="index.php?id=83&s=special">
<div id="C52">
<h2>just a demo</h3>
<p class="bodytext">this text is nothing special.</p>
</div>
</a>
</div>
</div>
</div>
</body>
with appropiate CSS the first CE looks completely different to the same CE in the search results.
h3 { color:black; font-size:16px; }
p.bodytext { color:#444; font-size:12px; }
.search-results h3 { color:blue; font-size:10px; font-weight:bold; }
.search-results p.bodytext { color:#44b; font-size:10px; font-style:italics; }
I answer my own question:
You can conditionally wrap specific content elements using the following typoscript snippet.
tt_content {
stdWrap {
if.value = tx_kesearch_pi2
{
wrap = |
innerWrap >
}
wrap = <div class="someotherclass">|</div>
}
}

remove decoration tags aem sightly

How can I remove the decoration tags only in preview/publish mode in AEM sightly?
I have seen the question and answer: AEM/CQ: Conditional CSS class on decoration tag
This removes the decoration but stops me from editing the components because it removes the decoration in edit and design mode as well. What is the condition required so that it will only remove the decoration tags in preview/publish?
I have also seen that it is possible to add the following code into the activate method of my java-use class:
if (!getWcmMode().isEdit() && !getWcmMode().isDesign()) {
IncludeOptions.getOptions(getRequest(), true).setDecorationTagName("");
}
This removes all but one of the decoration tags see example below:
HTML in wcmmode=disabled without the above code in the activate method:
<ul class="timeline">
<div class="section timelineTag">
<div class="section timelineTag">
<div class="section timelineTag">
<li class="clear"></li>
</ul>
HTML in wcmmode=disabled with the above code in the activate method:
<ul class="timeline">
<div class="section timelineTag">
<li class="event" href="#">
<li class="event" href="#">
<li class="clear"></li>
</ul>
How can I remove the first decoration DIV tag in the ul as it does not disappear when I add the specified code to the activate method?
As requested here is a detailed look at the component in question (updated 07/05/2015):
Java Class
public class TimelineClass extends WCMUse {
#Override
public void activate() throws Exception {
//Remove default wrapping performed by AEM for the preview mode
if (!getWcmMode().isEdit() && !getWcmMode().isDesign()) {
IncludeOptions.getOptions(getRequest(), true).setDecorationTagName("");
}
}
}
HTML code:
- There are two components involved in this. First of all the container component that includes the ul tag
- Then the tag component which is dragged and dropped from the sidekick into the container to create, in publish, the lists shown above.
Container code:
<div class="az-timeline row">
<section class="small-12 columns">
<section class="wrapper">
<ul class="timeline">
<!-- /* The parsys where all of the timeline tags will be dropped */ -->
<div data-sly-resource="${'par-wrapper' # resourceType='foundation/components/parsys'}" data-sly-unwrap></div>
<li class="clear"></li>
</ul>
</section>
</section>
Tag component which is dragged and dropped into the container parsys above:
<li data-sly-use.timelineTag="TimelineClass" class="event" href="#">
<img style="width: 165px;" data-sly-test="${properties.outerImage}" alt="placeholder" src="${properties.outerImage}"/>
<article>
<h5>${properties.heading || 'Timeline heading'}</h5>
<h4>${properties.subheading || 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt labore molestias perspiciatis reiciendis.'}</h4>
<p>${properties.text || 'Sed molestie, mauris sit amet egestas malesuada, felis magna commodo urna, vel consequat lorem enim ac diam. Aenean eget ex vitae enim cursus facilisis ac feugiat nisl. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.'}</p>
<img style="height: 130px;" data-sly-test="${properties.innerImage}" alt="" src="${properties.innerImage}" />
<a data-sly-test="${properties.link}" class="az-sbButton" href="${properties.link}">${properties.linkText || 'More'}<span class="owi-az-linkIcon internal"></span></a>
</article>
</li>
Several of the tag components are dragged and dropped into the parsys in the container and the result in wcmmode=disabled is the second ul shown above with the first item in the list surrounded by a div tag
I haven't worked with the Sightly stuff yet, but I have had success removing the extra divs by assigning the property "cq:noDecoration" (Boolean set to true) on the component in the JCR. Try that and see if it helps.
if i understand you correctly and you want div.section.timelineTag to be here only in edit mode, then the code would be
<ul>
<div data-sly-test="${wcmmode.edit}" class="section timelineTag">
Use data-sly-unwrap. See this post and the referenced doc from adobe
http://www.aemmastery.com/2015/04/24/remove-div-tags-sightly/
"data-sly-unwrap: Removes the host element from the generated markup while retaining its content."
Another option, set cq:htmlTag to "":
http://dev.day.com/cemblog/en/experiencedelivers/2013/04/modify_the_auto-generateddivs.html
As Rampant suggested but make the timeline ul part of the component and try setting cq:htmlTag to a "ul" and give it a class timeline: and you can still edit the component and it does not mess with the display. http://dev.day.com/cemblog/en/experiencedelivers/2013/04/modify_the_auto-generateddivs.html
Possible workaround for the issue when you need conditional remove of the decoration tags in Sightly on example of edit / preview mode:
Create two child components for your component ("parent-component") - "edit-view" and "preview-view".
For "edit-view" component set cq:noDecoration="{Boolean}false"
For "preview-view" component set cq:noDecoration="{Boolean}true"
In parent-component.html add conditional rendering like:
<sly data-sly-test="${isEditMode}">
<sly data-sly-resource="${'editViewResourceName' # resourceType='yourapp/components/parent-component/edit-view'}"></sly>
</sly>
<sly data-sly-test="${isPreviewMode}">
<sly data-sly-resource="${'editViewResourceName' # resourceType='yourapp/components/parent-component/preview-view'}"></sly>
</sly>
Tips:
Add dialog only for "edit-view" component.
For "preview-view" component you can keep only .content.xml and preview-view.html
To avoid code duplication there is possibility to include "edit-view" into "preview-view" using construction like
<sly data-sly-resource="${currentNode.path # resourceType='yourapp/components/parent-component/edit-view'}"></sly>

tumblr customization - Show post details in modal

I've been modifying my tumblr page to show posts inside a modal.
I have added the modal but when I click on a post, the post details do not show up inside the modal.
I used a free theme that has the masonry grid applied and the blog shows a grid of posts.
Currently I have the modal outside {block:Posts}.
If I have the modal inside {block:Posts} I get 10 modals opening all on top of each other. Although post details do show inside the modal. (10 is the number of posts on current page).
If I have the modal inside {block:Photo} I get all the modals showing up inside the masonry grid.
Current state of my tumblr:
http://cnocle.tumblr.com/
What I want to acheive:
http://fifth-avenue-theme.tumblr.com/
Any help, suggestions, directions would be great!
Please let me know if I should post the code. It's long and I'm not sure if I should post it or not.
Code Below is the top section of the
thank you
<body>
<script type="text/javascript" src="http://static.tumblr.com/ek9ly4s/Yfzmx9hib/jquery.ms.js"></script>
<link href="http://static.tumblr.com/ek9ly4s/0WMmx9ghw/homemade-ii.css" rel="stylesheet">
<div id="header">
<div class="xnav">
{block:ifshowblogtitle} <img src="http://static.tumblr.com/ksc6s4f/dWtnk041m/cnocle-logo.png"/> // {/block:ifshowblogtitle}
{block:ifshowdescription}
{block:Description}<p>{Description}</p> //{/block:Description} {/block:ifshowdescription}
Home /
{block:AskEnabled}{text:Ask Title} /{/block:AskEnabled}
{block:ifLinkOneTitle}
{text:Link One Title} / {/block:ifLinkOneTitle}
{block:ifLinkTwoTitle}
{text:Link Two Title} / {/block:ifLinkTwoTitle}
{block:ifLinkThreeTitle}
{text:Link Three Title} / {/block:ifLinkThreeTitle}
{block:ifLinkFourTitle}
{text:Link Four Title} / {/block:ifLinkFourTitle}
{block:ifLinkFiveTitle}
{text:Link Five Title} / {/block:ifLinkFiveTitle}
{block:HasPages}{block:Pages}{Label} / {/block:Pages} {/block:HasPages}
{block:iftextonlineusercounter}
{text:text online user counter} /
{/block:iftextonlineusercounter}
Archive /
Theme
</div><div class="spacer"> </div></div>
<div id="content">
{block:Posts}
<div class = "autopagerize_page_element" >
<div class="entry">
{block:Photo}
{block:IndexPage}
<div class="photo">
<img src="{PhotoUrl-250}" alt="{PhotoAlt}"/>
</div>
{/block:IndexPage}
{/block:Photo}
{block:PermalinkPage}
<div style="display:block;">
<img src="{PhotoUrl-500}" alt="{PhotoAlt}"/>
{block:NoteCount}{NoteCountWithLabel}
<div style="margin-top:5px;"></div>{/block:NoteCount}
{block:HasTags} · {block:Tags} #{Tag}
<div style="margin-top:5px;"></div>{/block:Tags}{/block:hasTags}
{block:Caption}{Caption}{/block:Caption}{/block:PermalinkPage}
{block:PostNotes}
<div style="width:500px;height:250px;overflow-y:scroll;overflow-x:hidden;margin-left:-5px;">{PostNotes}</div>
{/block:PostNotes}
</div>
</div>
{/block:Posts}
<!--
Start of Modal
-->
<div class="modal-content drop-shadow">
<div class="product-desc">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium adipisci aliquam corporis distinctio ea in incidunt ipsum molestiae molestias mollitia officiis possimus quis quod, ratione veritatis voluptate voluptatibus? A, amet.</div>
<div class="product-image"><img src="" alt="{PhotoAlt}" /></div>
</div>
<div class="modal-overlay"></div>
<!--
End of Modal
-->
<script type="text/javascript">
$(document).ready(function() {
$(".entry").click(function(){
var imgSrc = $(".photo").children("img").attr("src");
$(".product-image img").attr("src",imgSrc);
$(".modal-overlay").addClass("modal-show");
$(".modal-content").addClass("modal-content-show");
});
$(".btn-modal-close").click(function() {
$(".modal-overlay").removeClass("modal-show");
});
$(".modal-overlay").click(function() {
$(".modal-overlay").removeClass("modal-show");
$(".modal-content").removeClass("modal-content-show");
})
});
</script>
</div>

afterAdd binding is not working

I tried to use the afterAdd binding to add some trivial animation to the elements being added to my observableArray but it does not trigger anything.
I tought I had a problem with my animation code so I coded a small alert on the function but still does not work.
Here's some sample code for the div being templated:
<div id="resultList"
data-bind='template: { name: "searchResultTemplate",
afterAdd: function(elem){alert(elem)} }'
runat="server">
</div>
This is the template:
<script type="text/html" id="searchResultTemplate">{{each(i, searchresult) resultCollection()}}
<div class="searchresultwrapper ui-corner-all ui-state-default">
<div class="searchresult">
<img src='${ ImageUrl }' alt='${ Title }' title='${ Title }' class="searchresultpicture" />
<div class="searchresultinformationcontainer">
<span class="searchresulttitle" data-bind="text: Title"></span>
<br />
<div class="searchresultdescription" data-bind="text: Description">
</div>
<span class="searchresultAuthor" data-bind="text: AuthorName"></span> at <span class="searchresultmodule" data-bind="text: ModuleName"></span> on <span class="searchresultdate" data-bind="text: PublicationDate"></span>
<br />
Take me there
</div>
</div>
</div>
<br />{{/each}}
</script>
Any ideas?
You need to qualify the template attributes with foreach like so,
<div id="resultList" data-bind='template: {
name: "searchResultTemplate",
foreach: searchresult,
beforeRemove: function(elem) { $(elem).slideUp() },
afterAdd: function(elem) { $(elem).hide().slideDown() }
}' runat="server">
</div>
and then, not use {{each in the template, just template it for each item stand alone.
Here, foreach attribute helps keep track of changes to the object array