tags:

views:

179

answers:

3

I have some HTML that I need to toggle between two structures - one nested, and one un-nested - to make it easier for users to sort page components in a cms.

Here's the before html...

<p><a href="#" id="restructure">Toggle Structure</a></p>
<div id="modules">
  <div class="two_column_box">
    <div class="column_left">
      <p>Some text</p>
    </div>
    <div class="column_right">
      <p>Some text</p>
    </div>
  </div>
  <div class="two_column_box">
    <div class="column_left">
      <p>Some text</p>
    </div>
    <div class="column_right">
      <p>Some text</p>
    </div> 
  </div> 
</div>

and after html...

<p><a href="#" id="restructure">Toggle Structure</a></p>
<div id="modules">
  <div class="column_left">
    <p>Some text</p>
  </div>
  <div class="column_right">
    <p>Some text</p>
  </div>
  <div class="column_left">
    <p>Some text</p>
  </div>
  <div class="column_right">
    <p>Some text</p>
  </div>
</div>

I can strip out the extra divs, no trouble, but putting them back afterwards - I just don't get how to build up html from plain text and existing DOM elements. Here's the code I have so far...

  <script type="text/javascript" charset="utf-8">
  $(document).ready(function(){  
    $('#restructure').toggle(
      function() {
        alert('removing structure');
        var module_list = $("#modules > div > div");
        $("#modules").html(module_list);
      },
      function() {
        alert('replacing structure');
        var idx = 1;
        var next;
        var structure = $("");
        while((next = $('#modules > div:nth-child(' + idx++ + ')')).length) {
          var element = next.clone();
          if(idx%2==1) {
            $(structure).append('<div class="two_column_box">').append(element);
          } else {
            $(structure).append(element).append('</div>');
          }
        }
        $("#modules").html(structure);
      }
    );
  });
  </script>

Any help in getting the second function of the toggle to work (or in a more idiomatic version of the working code) would be much appreciated...

+3  A: 

Give this a try:

  $(document).ready(function(){  
    $('#restructure').toggle(
      function() {
        alert('removing structure');
        $("#modules .column_left, #modules .column_right").moveToGrandparent();
        $(".two_column_box").remove(); 
      },
      function() {
        alert('replacing structure');

        var next = $('#modules > .column_left:first, #modules > .column_right:first');
        while (next.length > 0)
        { 
            var wrapper = $("<div />").addClass("two_column_box");
            next.wrapAll(wrapper);
            next = $('#modules > .column_left:first, #modules > .column_right:first');
        }
      }
    );
  });


  (function($) {

    $.fn.moveToGrandparent = function() {
     return $(this).each(function() {
      $(this).parent().parent().append($(this));
     });
    };     

  })(jQuery);

Although you're removing structure code worked, I re-wrote it to use a plugin. As for the replacing structure, I'm using the jQuery wrapAll method with a loop that gets the first elements until there aren't any elements remaining.

HTH, Ben

bendewey
Thanks Ben; actually I think that gradbot's code is more concise, but I'll purloin your moveToGrandparent plugin for something else I need ! ;-)
Dycey
+4  A: 

You should use wrapAll in your case since your wrapping multiple elements at once into the same element.

  <script type="text/javascript" charset="utf-8">
  $(document).ready(function(){  
    $('#restructure').toggle(
      function() {
        alert('removing structure');
        var module_list = $("#modules > div > div");
        $("#modules").html(module_list);
      },
      function() {
        alert('replacing structure');
        var next;
        while((next = $('#modules > div.column_left:first, #modules > div.column_right:first')).length)
        {
          next.wrapAll('<div class="two_column_box"></div>');
        }
      }
    );
  });
  </script>
gradbot
I really like how concise your code is. I didn't know that you can pass jQuery element list to html method. Working demo for your code:http://jsbin.com/apake
SolutionYogi
Thanks gradbot - jQuery - always another function to learn!
Dycey
A: 

Once slight addendum to gradbot's suggestion: the point is that the elements will be sorted using UI sortable, so I needed to re-class the items depending on where they were in the list - odd being lefthand side, even being righthand side. There's probably a quicker way to do it but...

  <script type="text/javascript" charset="utf-8">
    $(document).ready(function(){  
      $('#restructure').toggle(
        function() {
          alert('removing structure');
          var module_list = $("#modules > div > div");
          $("#modules").html(module_list);
        },
        function() {
            alert('replacing structure');
            $('#modules > div').removeClass();
            $("#modules > div:odd").addClass('column_left');
            $("#modules > div:even").addClass('column_right');
            while((next = $('#modules > div.column_left:first, #modules > div.column_right:first')).length) {  
              next.wrapAll('<div class="two_column_box"></div>');
            }
        }
      );
    });
    </script>
Dycey
This makes sense when the class was removed during the removing structure toggle path.This might be redundant since it's working fine without the two new lines?
Jimmy Chandra
Sorry Jimmy - perhaps I wasn't being clear: between the restructure link being clicked the first and second time, the user may have REORDERED the divs (using jQuery UI sortable) - so the classes used to fetch the pairs will be wrong... hence the need to reset them using :odd and "even.That said, there may be a simpler way.
Dycey