Dynamically pulling in blocks and/or areas from other pages

Permalink
I've been chewing on this one for a while and I think it's time to call in the cavalry.

I have two idea's I've been entertaining that center around the ability to dynamically pull in instances of a block from another page. One is for a c5 jquery mobile integration and the other is to create a sort of iGoogle page where blocks can be handy widgets, but for page load purposes, only load the widgets you click on.

The core technology both these projects rely on is being able to pull in the header/footer items of a block and the HTML markup in a way that doesn't break the JS and will look exactly like they do on the page they originate from. This has been more tricky than I expected and I'm hoping that i'm just overlooking something.

I decided to start with was the iGoogle-like thing. I've got an area defined that loads the area, but doesn't display it, but prints a clickable div with the bID as the div's rel tag. OnClick, the page calls out to an ajax tool to try and grab the HTML of the block. This works great for the content block, but breaks if the block's view ever references $c (like autonav) because the collection ID is not defined. If i moved it to another singlepage it'd still be the wrong page. Somehow I need to trick the instance of that block what the current pageID is.

Once I get this sorted out and move on to the jquery mobile integration, I'll need to pull in header items. Easily enough done in the page's controller, but many of those scripts run on pageload. It's almost like I'll need a way of re-triggering the onpageload event of certain libraries... Naturally, i'll also need to parse the HTML in this case and rewrite the links or intercept the $('a').click() event, but I can handle that.


Here's the tiny test case for the iGoogle-like idea
Single Page:
<? defined('C5_EXECUTE') or die(_("Access Denied."));
?>
<div id="widgetArray">
  <?php 
    $a = new Area('Widget Area');
    foreach($a->getAreaBlocksArray($c) as $block){
      echo '<div class="widget" rel="'.$block->bID.'">'.$block->btHandle.'</div>' . '<br>';
    }
  ?>
</div>
<script type="text/javascript">
$('#widgetArray .widget').click(function(){
  console.log('clicked icon for bID:'+$(this).attr('rel'));
  $.getJSON("/tools/required/getBlock", { bID: $(this).attr('rel')}, function(json) {
    console.log(json);


tool
<?php defined('C5_EXECUTE') or die(_("Access Denied."));
  $response = new stdClass;
  $response->status = false; // err on the side of error
  $response->bID = (int)$_GET['bID'];
  $block = Block::getById($response->bID); // grab the block by ID passed in the GET string
  if($block){ // capture HTML output
    ob_start();
    $block->display();
    $response->html = ob_get_clean();
    $response->status = true;
  }
  echo json_encode($response);

PerryGovier
 
JohntheFish replied on at Permalink Best Answer Reply
JohntheFish
PerryGovier replied on at Permalink Reply
PerryGovier
Amazing job, I'll probably just play around with the Ajax blocks for the iGoogle-like deal.

Have you looked in to a jQuery mobile plugin? You should be able to make a package where you create a subsection of your site where content from other areas of the site map directly to the jquery mobile page.

How well do these work when pulling content in from other pages? Does autonav display the right info?
JohntheFish replied on at Permalink Reply
JohntheFish
I have not looked at jQuery Mobile yet.

Global Areas and Parent Area both work with autonav. I have not even looked at making an autonav template for Blocks By Ajax (I concentrated on blocks with a more obvious use case). It should be easy enough to give it a go from inside a stack.
PerryGovier replied on at Permalink Reply
PerryGovier
I got the dynamic content loading perfectly by modifying your blocks by ajax product.

In the op_script() method at the bottom of the helper, set $load_method to 'on_event', either by what's passed to it, or an override in the method itself, and then this to get the click event working.
$('.blocks_by_ajax').click(function(){
    $(this).trigger('blocks_by_ajax');
  });


At this point, clicking on a spinner will cause the block to load. Still to do is changing the template to be a representative icon rather than the spinner, but the functionality is done. Amazing work, thanks!
JohntheFish replied on at Permalink Reply
JohntheFish
One of the (very) longer term projects I am mulling over is to create a 'Blocks by AJAX behaviours' package that will provide a range of behaviours other than the standard load when visible. Obviously it will be impossible to do that for all blocks, so I was thinking of just a few commonly used blocks, the global areas block and stacks.

For the actual behaviours, I am thinking on click, on hover, periodic, toggling and reloading with a click, maybe some others, not sure yet. The Quick Log View addon already has a toggling reload behaviour. Other users have implemented hover and timer behaviours.

With your code, I think you could achieve the same by putting the script in the custom template rather than inside op_script in the helper. However, that would mean a new custom template for each block type, whereas your method has changed the behaviour globally for any block that uses a blocks by ajax template.

Maybe when I look at the behaviours package, I should also look at some sort of plugin mechanism to facilitate new behaviours, making it easier to apply them globally.
JohntheFish replied on at Permalink Reply
JohntheFish
I was making some updates to Blocks by AJAX and thought of your mods. v1.1 now has an extended developer interface that makes it easier to change behaviours globally.

The constant for the throbber will now accept HTML fragments, so you could use it to inject both your javascript and alternate throbber markup or icon.

There is also a new constant you can set to globally redefine the default load method.

My intention is that you can set these constants in site config to achieve what you want without having to modify the helper, thus preserving forward compatibility.

Details are on the documentation page.

(For others, the addon now includes both the original starter template and a package starter template that addon developers can use to ship Blocks by AJAX templates with their addons)