Im having some trouble in my quest to build a d7 custom node based image gallery module, i've got a lot working already but now I need ajax links to load node content from another node.
Im looking at the example ajax modules & everything I can find on the net but still have some issues. For one I dont understand how to use the drupal menu callback concept in my module, I am new to module building. Below is some explanation and code.
What I'm Doing... I've created a Drupal 7 one image per node image gallery, it uses relationships, EVA and even BBQ for deep linking, when viewing the 'gallery' node, EVA feeds in the thumbs and helpful attributes, ie. url to full image, url to actual node. I have jquery in my gallery node which ajax preloads the full images on thumb click & manipulates them for fast dynamic full screen browsing, it works perfectly! ...even the BBQ deep-linking which was difficult for me to master. Some of my gallery display js code is based on http://manos.malihu.gr/tuts/sideways_jquery_fullscreen_image_gallery.html
Current Status... Now im stumped because I'd like to load other parts of the node via ajax, ie comments etc. I can do this with jquery but I think utilizing the drupal methods may offer better control/performance. Plus when adding a comment one is taken to the node rather than remaining on the gallery page. Dohh!
I've tried many different ways, at present the only thing I can get to work is the following. This loads the whole node or pieces depending on .html bit. This doesnt work all that well, for example my Load-More-Comments Ajax-Pager rarely works. Also sometimes this load results in a WSOD if loading the whole url. Using this to pull in just the pieces based on #id works great, I could change my ajax comments pager thing to work from the gallery context too I suppose... but isnt there a better Drupal way to do all this? Surely I've entirely missed, conflated and/or clusterfucked something here? lol.
(function ($) {
$preloader2=$("#preloader2");
$preloader2.hide();
Drupal.behaviors.aa_website_module = {
attach: function (context) {
$('a.ajax-links:not(.ajax-module-processed)', context)
.addClass('ajax-module-processed').each(function() {
$(this).click(function(e){
$("#preloader2").fadeIn("fast");
// Remove the default click handler.
e.preventDefault();
// Get the URL of the clicked link.
var toLoad = $(this).attr('href');
// Now load the content
xhr = $.ajax({
url: toLoad,
success: function(data) {
// Inject the new content into <div id="ajax-div"></div>
//$('#ajax-div').html($('#comments', data));
$('#ajax-div').html($(data));
$("#preloader2").fadeOut("fast");
// Call attachBehaviors to ensure that any behavious in the
// injected content are fired.
Drupal.attachBehaviors(context);
}
});
});
});
}
}
})(jQuery);
Attempting the Drupal Ajax Link Method... I have also tried this quick hack in my gallery tpl to attempt a drupal ajax link. This does not work, the little ajax loading graphic loads and it seems to try but it returns an ajax http error HTTP Result Code: 200
<?php
$link = array(
'#type' => 'link',
'#title' => t('Work Damn You!'),
'#href' => 'node/216/nojs',
'#ajax' => array(
'callback' => 'aa_website_module_ajax_callback',
'wrapper' => 'ajax-response-goes-here',
'method' => 'replaceWith',
'effect' => 'fade',
),
// Using the onload below is entirely optional; It's just included as
// a reminder of an easy way to add extra simple jQuery tricks.
'#attributes' => array(
'onload' => "jQuery('something-to-hide').hide();",
),
);
print "<div id='ajax-response-goes-here'></div>" . drupal_render($link);
?>
Here is my module code, the referenced js file is the same as the Drupal.behaviors.aa_website_module bit I posted above...
<?php
/**
* @file
* TODO: Enter file description here.
*/
function aa_website_module_init() {
drupal_add_library('system', 'ui');
drupal_add_library('system', 'ui.dialog');
drupal_add_library('system', 'effects.explode');
drupal_add_library('system', 'effects.fade');
//drupal_add_library('system', 'effects.drop');
drupal_add_library('system', 'effects.blind');
drupal_add_library('system', 'jquery-bbq');
drupal_add_js(drupal_get_path('module', 'aa_website_module') .'/aa_website_module.js');
drupal_add_css(drupal_get_path('module', 'aa_website_module') .'/aa_website_module.css');
drupal_add_library('system', 'drupal.ajax');
drupal_add_library('system', 'jquery.form');
}
function aa_website_module_menu() {
$items = array();
$items['node/*/ajax'] = array(
'page callback' => 'aa_website_module_ajax_callback',
'access arguments' => TRUE,
'type' => MENU_CALLBACK,
);
$items['node/*/ajax/%/%'] = array(
'page callback' => 'aa_website_module_ajax_callback',
'page arguments' => array(2, 3),
'access arguments' => TRUE, 'type' => MENU_CALLBACK,
);
return $items;
}
function aa_website_module_ajax_callback($type = 'ajax', $some_argument){
if ($type == 'ajax')
{ $commands[] = ajax_command_replace('#ajax-response-goes-here', 'AJAX content!');
$page = array('#type' => 'ajax', '#commands' => $commands);
ajax_deliver($page);
}
else {
$output = t("Content delivered via a page load."); return $output;
}
}
Demo... I'd like to get a demo up but everything is in my local testing server; that and not all of the setup is in my module. I've cut corners by placing some js and such in my custom tpl's & theme-layer - plus creating views,content-types etc from the admin interface; I want to be sure it all works before taking the next step of my module creating the all that on install... this will be my first time doing that too. lol
The Possible Solution...? I have created another module that places a nodes comments and its comment-form in a block which gets its nid context from the url... It works great, if I could have this block on my gallery page and update its node context with ajax & refresh using my gallery image switcher function (code below), that would be perfect! Once thats sorted, I can work on an ajax sumbit setup for the add comment & get my ajax load-more-comments pager code working in this display.
Here is 'some' of the jquery on my gallery-node page. This is the image switcher function I could update my block from. I have no idea how to do it yet but I suspect its likely the best solution.
$(function(){
// Override the default behavior of all `a.thumb_link` elements so that, when
// clicked, their `href` value is pushed onto the history hash
// instead of being navigated to directly.
// my drupal View adds the needed value as "rel" to leave the thumbs href as
// themed url to full themed imagecache derivative.
$("a.thumb_link").click(function(){
var href = $(this).attr( "rel" );
// Push this URL "state" onto the history hash.
$.bbq.pushState({ image: href });
// Prevent the default click behavior.
return false;
});
// Keep a mapping of url-to-container for caching purposes.
var cache = {
'': $('#gall-default') // If url is '' (no fragment), display this div's content.
};
// Bind a callback that executes when document.location.hash changes.
$(window).bind( "hashchange", function(e) {
// In jQuery 1.4, use e.getState( "url" );
var url = $.bbq.getState( "image" ); //Get State from the above push "image"
// In this example, whenever the event is triggered, iterate over
// all `a.thumb_link` elements, setting the class to "current" if the
// href matches (and removing it otherwise).
$("a.thumb_link").each(function(){
var href = $(this).attr( "rel" );
//Mark the active thumb and launch its content!
if ( href === url ) {
//set context for node loading - my drupal View adds my 'node' attribute for use
var node = $(this).attr( "node" );
$('#top-panel a.node-load').attr('href', node);
//end set context for load node bits
$(this).addClass( "current" );
$("#gall-default").css("display","none");
//event.preventDefault();
var $this=this;
$bgimg.css("display","none");
$preloader.fadeIn("fast"); //show preloader
//style clicked thumbnail
$outer_container_a.each(function() {
$(this).children(".selected").css("display","none");
});
$(this).children(".selected").css("display","block");
//get and store next image and selected thumb
$outer_container.data("selectedThumb",$this);
$bg.data("nextImage",$(this).next().attr("href"));
//get and store new image title attribute
$bg.data("newTitle",$(this).children("img").attr("title"));
itemIndex=getIndex($this); //get clicked item index
lastItemIndex=($outer_container_a.length)-1; //get last item index
$bgimg.attr("src", "").attr("src", $this); //switch image
//Do some magic to my comments block to switch nid context and refresh it
$("#ajax_comments_block").serenity_now();
//$("#ajax-div").empty();
} else { //Un-Mark Thumb & other shtuff
$(this).removeClass( "current" );
}
});
});
// Since the event is only triggered when the hash changes, we need
// to trigger the event now, to handle the hash the page may have
// loaded with.
$(window).trigger( "hashchange" );
});
Conclusion... Well thats where im at... im going to keep digging to see if I can get my proposed solution with the block working... any feedback is welcome!
I suppose I need a little guidance on completing this, that and some php, drupal and jquery classes this winter, i'd love to figure these things out much faster! lol Serenity Now!
PS. I Love your tagging widget! Too cool!