2

I have some HTML inside of a Magento Theme that I am not allowed to edit however I need to come up with some JavaScript to target a really hard to target item and change it's content.

Below is the basic structure of the area I have to work with, I remove all the Siblings and only the relevant code is shown now.

This line <label for="options_2074">None</label> will always have a ID Number so I cannot use that to target my elements.

But I need to Change the text on that line from None to Black and also add

<span id="backingBlackTooltip"><img src="https://www.neonandmore.com/tooltips/question_mark.png"></span> Right after the closing </label> tag on that line as well.

I need some help building the JavaScript selector code to achieve this.

Also to note, I cannot use jQuery on this project =(

This is the main stuff I can use... #product-options-wrapper .input-box:first .options-list + .label label

Any help appreciate. There is a JSFiddle set up here.... http://jsfiddle.net/jasondavis/0b61L398/

<div class="product-options" id="product-options-wrapper">

    <dl class="last">

        <dt><label>Backing</label></dt>
        <dd>
            <div class="input-box">
                <ul id="options-2074-list" class="options-list">
                    <li>
                        <input type="radio" id="options_2074" class="radio product-custom-option" name="options[2074]">
                        <span class="label">
                            <label for="options_2074">None</label>
                        </span>
                    </li>
                </ul>
            </div>
        </dd>

    </dl>


</div>
JasonDavis
  • 48,204
  • 100
  • 318
  • 537
  • I achieved this using `jQuery` but I don't think it would be helpful: http://jsfiddle.net/0b61L398/6/. By the way, you can target the `label` with the `for` attribute using `label[for]`. – Fahad Hasan Oct 21 '14 at 00:27
  • Can you use [this](http://stackoverflow.com/questions/285522/find-html-label-associated-with-a-given-input) approach? – PM 77-1 Oct 21 '14 at 00:27
  • Not sure if this is to generic but it works if I assume your html wont change (though it is ugly). var myEls=document.querySelectorAll('label'); myEls[1].innerHTML = 'Black'. The cleaner solution would probably be to use the Fahad's suggestion of label[for] and play with pseudo selectors. – Blue Oct 21 '14 at 00:34
  • Something like this: http://jsfiddle.net/0b61L398/11/ – PM 77-1 Oct 21 '14 at 00:48

2 Answers2

3

This should do it. Make sure not to run this code until the document has loaded:

var alreadyFound=false;
[].forEach.call(document.getElementsByTagName('label'),function(curElt){
    if(!alreadyFound&&curElt.getAttribute('for') && curElt.getAttribute('for').indexOf('options_') === 0 && curElt.textContent === 'None'){
        alreadyFound=true;
        curElt.textContent='Black';
        var newSpan=document.createElement('span');
        newSpan.setAttribute('id','backingBlackTooltip');
        var newImg=new Image();
        newImg.setAttribute('src','https://www.neonandmore.com/tooltips/question_mark.png');
        newSpan.appendChild(newImg);
        curElt.parentNode.appendChild(newSpan);
    }
});

Working example: http://jsfiddle.net/0b61L398/12/

What I'm doing:

  1. Get all <label> element and start iterating through them
  2. For each one, check if the following work: it has a for attribute, the for attribute starts with options_, and the content of the <label> is None
  3. If those conditions are all met, set the content of the <label> to Black
  4. Create a new <span>, and set it's id attribute to backingBlackTooltip
  5. Create a new <img>, set it's src to the url you provided, then add it as a child of the <span> we just created
  6. Append the span (and it's child <img>) to the parent of the <label>, effectively the same as adding it "right after the closing </label> tag"

Also, it has been edited so that it stops after finding the first <label> that matches all criterion. jsfiddle link has been updated to reflect this change

markasoftware
  • 12,292
  • 8
  • 41
  • 69
  • This works, thanks this seemed like a tricky one, I usually have better HTML to work with but I am unable to make any HTML changes in this case, i'm glad you came up with a non-jQuery solution! – JasonDavis Oct 22 '14 at 01:04
  • This is amazing code you share with me a few weeks ago but I have now discovered it is causing a problem on some of the pages it is ran on. The problem is on some page, this ends up matching 2 separate times and changing them both when it should, or better said, it needs to only change the first matching element that is found on the page and then abort or disregard others. Would you happen to know of an easy fix for this? – JasonDavis Nov 12 '14 at 06:04
2

You will need to do something like the following:

var labelElement = document.getElementById("product-options-wrapper").  //#product-options-wrapper
                    getElementsByClassName("input-box")[0].     //.input-box:first
                    getElementsByClassName("options-list")[0].  //.options-list
                    getElementsByClassName("label")[0].         //.label
                    getElementsByTagName("label")[0];           //label

// Change the label content
labelElement.textContent = 'Black';

// Create the image and set its src
var img = new Image();
img.src = 'https://www.neonandmore.com/tooltips/question_mark.png'; 

// Create the span to wrapper the image
var span = document.createElement("span")
span.id = "backingBlackTooltip";
span.appendChild(img);

// Append it to the label parent element
labelElement.parentNode.appendChild(span);
Rafael Maiolla
  • 373
  • 1
  • 3
  • 13