Let's discuss possibilities for turning hook_nodeapi into hook_filter in inline.module in this issue.

Background info

Alterations of a node through hook_nodeapi are not cached, thus performed each time a node is displayed.

  • Node id should be stored in a hidden tag
    • - Would need to be extended for other Drupal objects, such as blocks or comments, which at least would need a block id or comment id to refer to additional object information.
    • - Would probably lead to inconsistent Inline tags, if multiple Inline tags in a content would refer to additional object information of different objects (f.e. a comment with an inlined file uploaded to the commented node and an inlined image uploaded with the comment using comment_upload module).
    • + Would simplify the tag filtering, since only tags referencing to other objects would contain an additional id.
    • - Requires a database update to inject the hidden tags in all Inline-enabled nodes.
  • Node id should be stored in each Inline tag
    • + Would be appropriate for a completely customizable plugin system (hook_inline) to allow integration of other modules with Inline.
    • - Looks awful for content authors, if the tag is not immediately replaced by a placeholder (see integration of Img_Assist in TinyMCE f.e.).
    • + Node id info could be added upon save and removed upon view.
  • CCK (text)field name might need to be stored in a hidden tag
    • - Why do we need to know the name of a field while processing the contents of it?
  • Since hook_filter caches filtered contents, Inline needs to add a hidden timestamp to each content to have the content filtered again, f.e. if only attachments are altered but not the content
    • + Although adding an internal tag to all contents upon save and removing it upon view is not very Drupalish, it seems to be the only solution to force hook_filter again.
    • + Those internal tags could be removed via (not yet existing) inline_uninstall().

Some related issues

I would like to limit the scope of this issue solely to usage of hook_filter. However, there are some other issues involved, f.e. New Inline filter syntax, CCK textfield support and perhaps more.

Recommendation

  • Upon saving of a content (node, block, comment, …)
    • preceed the content with an internal [inline-info] tag, that includes the current timestamp and object id.

    ending up with one [inline-info|timestamp=123456789|nid=123] tag and [inline:file.pdf] tags.

  • Upon editing a content
    • remove the internal [inline-info] tag.

    ending up with [inline:file.pdf] tags.

  • Upon viewing a content
    • replace Inline tag by injecting corresponding HTML to download file.pdf, which is attached to node 123, using hook_filter().

Since we already need to alter existing Inline tags and add the new internal tag to existing contents through a database update, we might consider to directly alter the syntax of Inline tags to:

[inline|file=file.pdf]

or even better for future Inline API compatibility and CCK support:

[inline|upload=file.pdf]
[inline|cck_filefield_name=file.pdf]

whereas "upload" references to an attachment uploaded via core upload.module and "cck_filefield_name" references to an attachment provided through a custom CCK File field with the name 'cck_filefield_name'.

CommentFileSizeAuthor
#14 inline.filter.2.patch25.26 KBsun
#13 inline.filter.1.patch16.21 KBsun
#1 inline_7.patch8 KBsun

Comments

sun’s picture

Status: Active » Needs work
StatusFileSize
new8 KB

First try. Node preview and initial node save not working. Heavy comments on that.
Also won't work with old nodes not containing the new (& required) Inline info tag.

smk-ka’s picture

Some question arising:

  • How is cross-referencing handled? There exists a timestamp if the current node changes, but what about the current node referencing an image in another node and that image changes? How can you make sure the cached filter output is invalidated? Or will referencing foreign data not be supported?
  • "check_markup() does not activ(at)e the filter" seems to be not true. Is this a Contemplate specific issue?
smk-ka’s picture

Will this work?
[inline|cck_filefield_name=file.pdf]
Don't we need a fixed 'provider' identifier on the left side of the equal sign, to know which module provides the actual data replacement? That is, sort of
[inline|cck=filefield_name|item=file.pdf]

smk-ka’s picture

A quick review of the patch:

  • _inline_filter_info() should have the $op as first argument, as everywhere else in Drupal.
  • We should try to exchange the hardcoded file related code and replace them with generic API hooks. However, this requires us to define a tag format that is suitable for work with plug-ins. Note that I am aware of the fact this is actually a separate issue, but since it is critical for the final filtering results, I'm recommending to do it first. Otherwise we risk to end with a working filtering solution, but a tag format not suitable for plug-in extendibility.
sun’s picture

@smk-ka: Thanks for reviewing!

How is cross-referencing handled? {...} How can you make sure the cached filter output is invalidated? Or will referencing foreign data not be supported?

AFAIK, we only have 2 options here:

  1. Store cross-referencing information in a database table, as already suggested by benshell. Based on that information, we could somehow invalidate the referencing/referenced node's filter cache and would probably benefit from the cross-reference information to validate user actions (e.g. deletion of an image that is referenced in another node).
  2. Completely disable the filter cache for all input formats that include Inline filter. See hook_filter.

Don't we need a fixed 'provider' identifier on the left side of the equal sign, to know which module provides the actual data replacement? That is, sort of
[inline|cck=filefield_name|item=file.pdf] {...} We should try to exchange the hardcoded file related code and replace them with generic API hooks. However, this requires us to define a tag format that is suitable for work with plug-ins.

I'm all with you on this one. This is basically, what Inline API is about.
Since Inline shouldn't be limited to CCK, the argument would rather be "plugin", "field" or "module", so f.e.:
[inline|field=cck-filefield-name|item=file.pdf]
or
[inline|module=filefield|my_fieldname=file.pdf]
If we assume that all contents are stored in Drupal objects, like nodes, we may stick to the field name only. Otherwise, we would have to assign the module name and the field name, whereas the argument "module" would be processed by Inline core and any following parameters would have to be processed by the corresponding Inline implementation of that module.
However, I'm a bit afraid that Inline tags would become cumbersome without any additional javascript supplying user-friendly widgets to automatically insert Inline tags.

_inline_filter_info() should have the $op as first argument, as everywhere else in Drupal.

Please, let's not hold up this task with such details. We can definitely alter function signatures later on. Certainly there are also possible performance optimizations, but for now we should concentrate on getting the main implementation to work...

...so last but not least:

Node preview and initial node save not working. Heavy comments on that.

After troubleshooting this issue last night, I'm a bit sceptic if using hook_filter() for Inline is really the right solution. We definitely should have a look on other modules, such as Image Assist, which AFAIK has successfully implemented CCK support and filtering of other Drupal objects like blocks.

smk-ka’s picture

Completely disable the filter cache for all input formats that include Inline filter.

Sorry if I sound slightly confused, but: wasn't the main reason for the switch to hook_filter() the ability to cache the filtered output (vs. hook_nodeapi() which has to process the node on every page view)?

Store cross-referencing information in a database table, as already suggested by benshell.

This approach actually looks interesting. IMO to be able to efficiently resolve cross-references we always need to store some information in the database, without taking into account the actual implementation we'll choose.

However, I'm a bit afraid that Inline tags would become cumbersome without any additional javascript supplying user-friendly widgets to automatically insert Inline tags.

Don't care for a moment about how cumbersome the result will be &emdash; this module should 1. work flawlessly and 2. its API serve as a powerful base for other modules to extend it. A TinyMCE extension would be purely for convenience and is not the topic of this issue.

smk-ka’s picture

such as Image Assist, which AFAIK has successfully implemented CCK support

From a quick peek I can say there is no CCK support. And filtering doesn't seem to take changed images into account.

While we're shaping the new features of Inline it seems like a good idea to point Ben to this issue and talk with him about his ideas since the mentioned post is already a year old :s.

Moonshine’s picture

Well I'm certainly late to the party here. :) A few comments first on background info:

Node id should be stored in a hidden tag:

- Would need to be extended for other Drupal objects, such as blocks or comments, which at least would need a block id or comment id to refer to additional object information.

Would it matter if the info was in visible tags? Seems that they would also need to be "extended" to include any necessary info also for things like comments or blocks.

Node id should be stored in a hidden tag:

- Would probably lead to inconsistent Inline tags, if multiple Inline tags in a content would refer to additional object information of different objects (f.e. a comment with an inlined file uploaded to the commented node and an inlined image uploaded with the comment using comment_upload module).

I'm not really clear on this one, but it seems that what is considered "inconsistancy" is just tags that only reference the relevant information.

Node id should be stored in each Inline tag:

+ Would be appropriate for a completely customizable plugin system (hook_inline) to allow integration of other modules with Inline.

I'm not sure why the info wouldn't be available to plugins either way. hook_inline would just get at the hidden tag info and pass it along to the module.

Node id should be stored in each Inline tag:
+ Node id info could be added upon save and removed upon view.

So the advantage is that it could be made into a redundant version the hidden tag approach? Sorry I couldn't resist. :)

Anyways, more importantly...

I see some references to fieldnames. Personally I think the fieldname should be included in the hidden tag as it's required for any intellegent processing of inline tags. (ie. user wants inlined images in teasers to be smaller, or wants large inlined images in a certain cck field) That's the reason it's included in my nodeinfo tags, it allows for processing flexibilty which is really necessary. There were 3 parameters in the hidden nodeinfo tag: NID, fieldname and timestamp. Also you don't want to let an author tell the filter what fieldname it is.

As for hook_inline capability, I see references to adding another tag parameter to indicate the module being used. Personally I think that's pretty sloppy. Hook inline should just base the hook_inline module to used based on the initial key in the tag: [inline=1] uses a module for older compatibility code, [image=1] use inline image module, [file=1] use inline file module, [audio=1] use the inline audio module etc. Much cleaner and more professional IMO. If it can't find a module match than it just leaves the tag alone (for another filter to possibly hit) I had already started some code for this but another project has come up. It's certainly doable though.

As for using content from other nodes, another table would seem to be the cleanest approach. Personally I think there are a lot of things to consider security wise when offering to include content from other nodes, which is a whole other topic.

As for filtering CCK field, I don't entirely understand what's being questioned. If you get a chance to go through my code you'll see they are being filtered and it is using hook_filter.

Node preview and initial node save not working.

I'm sure this just has to do with the hook_nodeapi implementation (and potentially issues with imagecache preview, imagefield preview or thickbox preview depending on what you're using) . If you walk through my code you'll see how these cases are handled via nodeapi though.

Really in the end I think it might be a lot easier process to just take my hook_filter and hook_nodeinfo code, rename "nodeinfo" to "inline-info", and question whatever you don't like during walkthoughs. There shouldn't be much (other then auto add code) in those two functions that you won't need in the end I think.

niklp’s picture

Subscribing.

Also, would it be useful to implement support for imagefield, whilst we're about this? It's something I've been thinking about, but given the present company, I'm pretty out of my depth.

sun’s picture

Version: 6.x-2.x-dev » 5.x-2.x-dev
Status: Needs work » Active

Inline API has quite evolved and implements the former Inline v1 (now inline_upload) module as input filter.

the fieldname should be included in the hidden tag as it's required for any intellegent processing of inline tags. (ie. user wants inlined images in teasers to be smaller, or wants large inlined images in a certain cck field)

I understand the point here. However, besides images I can't think of other hook_inline implementations that could use this field information in an intelligent fashion. Because of that, I would it leave it up to the implementation to add or alter each macro according upon node submit/update.

sun’s picture

See http://drupal.org/node/184112 for an possible use-case of #10 in Image Assist. hook_inline implementations should indicate if they need a field name for optional processing, and if they do, Inline API should automatically add (and ensure) the field name to the macro.

guillaumeduveau’s picture

I was just about posting an issue asking why we use hook_filter instead of hook_nodeapi after reading http://drupal.org/node/106249#comment-184886 :)

I found my answer in the fact that alterations of a node through hook_nodeapi are not cached. On the one hand, no cache, on the other hand, no context like $node. Is there a general issue for D7 on this ?

sun’s picture

Status: Active » Needs review
StatusFileSize
new16.21 KB

The Real Fu.

sun’s picture

Title: Use hook_filter instead of nodeapi for Inline » Inline API: Solve all problems.
Status: Needs review » Reviewed & tested by the community
StatusFileSize
new25.26 KB

Better title. ;)

sun’s picture

Version: 5.x-2.x-dev » 6.x-2.x-dev

Better version.

sun’s picture

Status: Reviewed & tested by the community » Fixed

Committed. Yay!

I'll probably use this #issue for some clean-up and follow-up commits.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.