The 1.x version of the asset module directly adds javascript calls at the asset when it adds an asset to a page. This is in place because the assets are added with a filter and filters are cached. So, the first time the asset is displayed something like drupal_add_js would work. Each time after that it wouldn't because of a cached result for the filter.

I consider this to be a bug because it's an external call to the same javascript file each time a page adds a media asset.

My first gut instinct was to use something like the actions module to do the dirty work. Upon a litter further digging this did not seem like the best approach.

A better approach seem to be to tie into hook_nodeapi on the view op. At this point the assets are loaded and attached to the node object. What about cycling through the assets and using drupal_add_js to add the relevant javascript here?

This would be happening completely separately from use of hook_filter which renders the html in the node but it should work.

Thoughts? I'm going to roll a patch in the next few days and take it for a spin if there are no objections.

CommentFileSizeAuthor
#21 asset_254346_20.patch5.04 KBmfer
#19 asset_254346_19.patch2.5 KBmfer

Comments

wmostrey’s picture

Category: task » bug

I'm putting my blogplost up as a reference: hook_filter versus drupal_add_js.

If there is any alternative, I will do a lot of QA on the patch and it will get published if it works. Currently there are two ways that work, but that are not perfect:

  • Cache hook_filter and put the javascript inline, this works but some people might run into this nasty IE bug.
  • Don't cache hook_filter and use drupal_add_js, this works for everyone but the filter is no longer cached, which is not something we would prefer.

So a working alternative is really appreciated. Thanks for your input and work on this Matt.

mfer’s picture

My current direction of thinking is to add a theme function called by the view op on hook_nodeapi that adds noncachable page elements to the viewing of assets. Initially it would include things like drupal_add_js calls though it could be extended to other areas.

I'm working on a project this coming week that could really benefit from this so I'll roll a patch when I get to that point in the project and take it for a test spin.

mfer’s picture

It's going to be another week. My development machine is in the shop.. doh.

wmostrey’s picture

Category: bug » task
mfer’s picture

@wmostrey - here's my proposed solution.

First, add another op to hook_asset_formatter called nocache. This is where operations that can't be cached can be placed.

Then, in hook_nodeapi with the op view we call something like

  module_invoke($module, 'asset_formatter', 'nocache', $asset, $attr);

This would allow other modules to extend and work on assets in a non-cached manner. In that op there could be a theme call that can be attached to the rendered node and then displayed. There could be a call to drupal_add_js or drupal_add_css.

Plus, other modules can extend what is already there. I would use it to implement thickbox. It could be used to move lightbox support into a separate module.

Thoughts before I start coding this?

wmostrey’s picture

Category: bug » task

Hey Matt,

I like the idea. This allows us to use "no cache" which we need to implement drupal_add_js(), without completely uncaching the complete asset_filter(). Passing the necessary arguments around should be done as elegant as possible of course. I think it's a great idea!

Be sure to work from the latest dev or from beta4, it got released today.

wmostrey’s picture

I ran into this issue today: http://drupal.org/node/260596

We should also try to view an flv asset from within a block and see if that works as well.

mfer’s picture

So, assets can be attached to nodes and blocks. I'm guessing this applies to any textfield we can have in the system, right? Anywhere?

mfer’s picture

I have a feeling this is frowned upon but what about doing something like http://www.php.net/manual/en/function.override-function.php#50821 on check_markup and somehow detecting what assets are thrown and acting on them. It would be nice if check_markup allowed a partially cached mode.

This would then work on every text field in the system that accepted input formats. Any thoughts on other ways to expand this beyond just nodes? Even if there was an easy way to detect when check_markup is fired and getting it's input parameters.

mfer’s picture

The more I look into this the more we may not be able to do it for every textfield. For nodes and comments it wouldn't be to hard. We may even be able to get it into blocks. But, input formats can be used everywhere and we would end up leaving it off somewhere in some custom module.

Maybe we need to look at different approach. Something in the javascript. Time to go brush up on that. I'm open to any ideas at all. No matter how crazy. I've had some weird issues because of this problem.

mfer’s picture

Alternate thought. Let's try and do something that works for filtered locations. What about a design pattern that we could reuse for the filters. For example, let's take the swfobject include code for flv videos. What if we include a short script that checks if swfobject is loaded and if it isn't loads it. This would have it loaded only once. Thoughts?

This same pattern could be used for other things and even jquery.js/drupal.js.

wmostrey’s picture

I'm not sure if that's going to work since we need to call the swfobject code to replace the "Media placeholder" div with the correct flvplayer.swf per asset. For Drupal 6 this would be doable using preprocess functions. You can use it pass the asset id to the template from within your module. Zen 5.x-1.1 implements its own MODULE_preprocess_HOOK function, which emulates the Drupal 6 functionality of preprocessing. So adopting this looks to me like a very good way to tackle this issue. I will be looking into this myself the next two weeks.

mfer’s picture

@wmostrey - What I was thinking was instead of:

<script src="/sites/all/modules/asset/asset_bonus/swfobject/swfobject.js" type="text/javascript"/>

We insert javascript with the filter that looks something like:

var scripts = table.getElementsByTagName("script");
var swfswitch = false;
for (var i = 0; i < scripts.length; i++) {
  if (scripts[i].src == "/sites/all/modules/asset/asset_bonus/swfobject/swfobject.js") {
    swfswitch = true;
  }
}
if (swfswitch == false) {
  var newjs=document.createElement('script');
  newjs.type='text/javascript';
  newjs.src='/sites/all/modules/asset/asset_bonus/swfobject/swfobject.js';
  document.getElementsByTagName('head')[0].appendChild(newjs);
}

This would check for the swfobject file and only include it if it isn't already included.

This pattern of checking and only including if not there could be extended to any javascript, including core. We could include something like:

<script type="text/javascript"/>
var corejs = <?php print drupal_get_js(); ?>
var scripts = table.getElementsByTagName("script");
var swfswitch = false;
for (var i = 0; i < scripts.length; i++) {
  if (scripts[i].src == "/misc/jquery.js") {
    swfswitch = true;
  }
}
if (swfswitch == false) {
  document.getElementsByTagName('head')[0].appendChild(corejs);
}
</script>

Thoughts? It's a little extra javascript to parse through but it does conditionally including. And, it could all be done inside the same theme function that is now inserting the javascript.

wmostrey’s picture

Interesting. We do need to remember that somehow we need to add the var oSwf = new SWFObject code right before the </body> as well. How would you go to implement this, keeping in mind that somehow the asset id or move filename would need to be passed through?

mfer’s picture

In the filters code we add something like:

document.getElementsByTagName('body')[0].appendChild('what we want to insert');

This would put what we add as the last thing before the closing of the body tag. We could use this javascript to add javascript as the end of the page.

I have a feeling it's not going to be quite that easy but this is the general concept. I'll try to write something and test out this theory over the next few days.

wmostrey’s picture

I'm not sure if that wil work: any javascript that alerts the html needs to be at the bottom of the page, so I don't think it will work to write it from within the filter. Maybe it does because you're not replacing the content in a div, but you're appending extra code. Be sure to start testing in IE, that will probably tell you fast enough if the method isn't working. I'm looking forward to your rapport on this, thanks so much for your effort and input, it's highly appreciated.

mfer’s picture

An update... I'm partially there with this fix. I've got it working and tested in IE6 and Firefox on both PC and Mac. My trouble browser is safari. The current code works for blocks in garland, too. I want to do more browser testing and work out the Safari bug. Not using a js library has really brought out the quirks between browsers with JavaScript :(.

wmostrey’s picture

Thanks so much for all your work on this. Could you provide a patch for what you have so far so that I can start testing this as well? What exactly are you experiencing in safari? Does it just not display the video?

mfer’s picture

Status: Active » Needs review
StatusFileSize
new2.5 KB

Here is a patch tested in IE6, Firefox (mac and pc), and Safari 3 that works for video in the node area and a sidebar block in garland.

Writing this is really giving me an appreciation for javascript libraries that deal with browser issues.

In some browsers when you add something to the DOM with javascript there is a slight delay before it's added and some browsers have javascript as a single thread so I used setTimeout to deal with that. It lets items be loaded in the interval.

Feedback here is much appreciated. I'm sure this can be improved upon.

mfer’s picture

This takes the same technique and applies it to asset bonus audio as well as video players. The idea is to only load the external javascript files once. This works in blocks and in body content.

Thoughts?

With this I'm not getting incorrectly shaped or odd issues with the objects anymore.

mfer’s picture

StatusFileSize
new5.04 KB

Let's try attaching that patch again.

wmostrey’s picture

Status: Needs review » Closed (won't fix)

I'm going to mark this as "wontfix". I don't think there's a cleaner solution for Drupal 5 as is currently implemented. I hope to have a cleaner solution for Drupal 6.