3

for given tag I need to wrap it with quite a few elements. So that user can put

<img src="img.gif" >

but outcome would be

<div class="total">
    <div class="cover">
        <div class="crop">
            <img src="img.gif" alt> 
        </div>
        <div class="hover">
            <div class="peel">
                <div class="links">
                    <a href="#">FB</a>
                </div>

            </div>
        </div>
    </div>
</div>

So i decided to make it into jQuery plugin. And here is piece of it

(function($) {
$.fn.peel = function(options) {
    var defaults = {};
    var settings = $.extend({},defaults, options);

    return this.each(function() {
        $(this).load(function() {
            var image = $(this);
            var total = $('<div />', {'class' : 'total'});
            var cover = $('<div />', {'class' : 'cover'});
            var crop = $('<div />', {'class': 'crop'});
            var hover = $('<div />', {'class' : 'hover'});
            var peel = $('<div />', {'class' : 'peel'});
            var links = $('<div />', {'class' : 'links'});
            var a = $('<a>', {'href' : '#', 'text' : 'FB'});
            //Chaining begins here
            image.wrap(crop);
            crop.after(hover);

        });
    });

};
})(jQuery);

At first i make variables with divs i will use. But i am having hard time making it all together this time.. I left 2 lines which doesnt want to work with chaining. At first i am wrapping image with crop, and then i am adding hover div after crop div. But... 2nd line doesn't work. I tried in numerous ways. No luck so far. Seems like it is impossible to add something that is added with "wrap". Maybe I am doing wrong, so maybe someone of you could help ? :)

Thanks.

3 Answers 3

2

DOM manipulations on elements not inserted in the page might be a little tricky.

after, for example, can only work on an element having a parent. Here is its implementation :

after: function() {
    return this.domManip( arguments, false, function( elem ) {
        if ( this.parentNode ) {
            this.parentNode.insertBefore( elem, this.nextSibling );
        }
    });
},  

Similarly, wrap will call before which has a symmetric implementation.

What works is to build your tree by using append and starting from the most external element :

cover.append(crop);
crop.append(image);
cover.append(hover);
Sign up to request clarification or add additional context in comments.

4 Comments

For me it outputs only <div class="crop"> <img src="img.gif" alt=""/> </div>
but shouldnt it at least give me hover div? Now its only img tag wrapped with crop
@Wish You're right, this didn't work. See edited answer : you'd better only use append, starting from the most external elements.
Ye, this will be the way to go. Also found got something similar just by playing. Wrap probably is just bugged.. But also your argument "hover isn't in the page so after can't insert anything after it." doesnt seem to be valid aswell. I can make hover.append(peel).append(links).append(a) and then image.after(hover) and all the divs are there.
1

you can achieve that in this way:

image.wrap(total).wrap(cover).wrap(crop)
    .closest('.crop')
    .after(a.wrap(hover).wrap(peel).wrap(links).closest('.hover'));

@dystroy's answer is not totally correct: you can insert thing after a node in memory

cover.append(crop).append(hover).appendTo('body');

you'll find all the 3 nodes were appended to DOM

the key point is $.wrap. when you wrap something, not like other operation, jQuery will create a new copy, at this time, the wrapper in the dom is not the same reference with the one created in memory any more.

take the first line as example:

var domCrop = image.wrap(total).wrap(cover).wrap(crop)
    .closest('.crop');
console.log(domCrop.is(crop)); //false, domCrop and the corp in mem not point to the same ref

the last but not least, in actually, I don't like this way to extend the dom node. it made the code hard to write and maintain.

here's my solution:

(function($) {
$.fn.peel = function(options) {
    var defaults = {};
    var settings = $.extend({},defaults, options);
    var html = '<div class="total">'
        + ' <div class="cover">'
        + '   <div class="crop"></div>'
        + '   <div class="hover">'
        + '      <div class="peel">'
        + '         <div class="links">'
        + '            <a href="#">FB</a>'
        + '         </div>'
        + '      </div>'
        + '   </div>'
        + ' </div>'
        + '</div>';

    return this.each(function() {
        $(this).load(function() {
            var $image = $(this);

            //introduced a placeholder. 
            //not to replace the $image directly, just for keeping all the event handler bound to $image.
            var $placeholder = $('<span/>').insertAfter($image);
            $(html).find('.crop').append($image)
                .end()
                .replaceAll($placeholder);
        });
    });

};
})(jQuery);

jsFiddle Demo: http://jsfiddle.net/vF4QH/1/

1 Comment

Now, when i need to add multiple <a> next to each other, i understand why i should use html...
0

Why not simply build a tempalte once and for all like this

var htmlTemplate = '<div class="total">'
    htmlTemplate += ' <div class="cover">';
    htmlTemplate += '   <div class="crop"></div>';
    htmlTemplate += '   <div class="hover">';
    htmlTemplate += '      <div class="peel">';
    htmlTemplate += '         <div class="links">';
    htmlTemplate += '            <a href="#">FB</a>';
    htmlTemplate += '         </div>';
    htmlTemplate += '      </div>';
    htmlTemplate += '   </div>';
    htmlTemplate += ' </div>';
    htmlTemplate += '</div>';

Then when you need it you can do something like the below code to insert the image tag

var selection = $(htmlTemplate);
selection.find('.crop').html('<img src="img.gif" alt>');

and finally append it somewhere in the DOM

//substitute body for where you wish to place the result
$("body").append(selection) 

2 Comments

@wish code should be easy to read. Who cares if it looks lame as long as it's easy to understand and functionally correct. Interestingly enough your accepted answer got updated to this approach too
Cause i understood myself that my approach is pain in the ass.. True dat.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.