I've had a go at implementing a plugin for CKEditor_Link and I've got much of it working. I'm finding, however, that my revert function is not getting called at all, and when editing links created by CKEditor_Link they do not get recognised as such.

A little debugging has concluded that ckeditor_link_ckeditor_link_menu_revert() is returning FALSE whenever menu_get_item($path) does not return a menu item. Your documentation does not indicate that implementations of this hook should ever return FALSE:

107 * An URL alias, or nothing if the implementing module is not responsible for
108 * the given path.

But what the code in ckeditor_link_revert() currently does is to break out of the hook calls if a non-NULL is returned, and if FALSE is returned then that is passed to the javascript.

My hook implementation correctly gets a chance to try and revert the URL if I remove line 55 from ckeditor_link_menu.inc:

  return FALSE;

Isn't that what should happen?

Patch attached.

CommentFileSizeAuthor
ckeditor_link_menu_inc.patch464 bytesmartin_q

Comments

anrikun’s picture

lines 107,108 are about hook_ckeditor_link_TYPE_url(), not hook_ckeditor_link_TYPE_revert().
The correct lines are 89, 90:

* A title, FALSE if not found, or nothing if the implementing module is not
* responsible for the given path.

Anyway, menu hooks should run in last position as they are kinds of fallbacks.
To solve your problem, implement hook_ckeditor_link_types_alter() and insert your type before the menu type.
This way, your hook_ckeditor_link_TYPE_revert() will be called before ckeditor_link_ckeditor_link_menu_revert().

martin_q’s picture

Category: bug » support

Thanks for the help! Yes, my mistake quoting the wrong lines of the API file.

I still think it's strange to have a hook implementation that will always return FALSE if nothing is found, but your tip works. I implemented hook_ckeditor_link_types_alter like this:

function mymodule_ckeditor_link_types_alter(&$types) {
  // Move 'menu' to the end of the list by copying, unsetting, resetting.
  $entry_for_menu = $types['ckeditor_link.menu'];
  unset($types['ckeditor_link.menu']);
  $types['ckeditor_link.menu'] = $entry_for_menu;
}

Actually, if you are intending for 'menu' always to come last and work as a fallback (and always returning a value or FALSE only makes sense if you do), then IMHO I think you should implement this in your module, rather than have plugin developers implement it in theirs - since your implementation of 'menu' breaks plugins without it.

Thanks again for the workaround, but I would still categorise this as a bug, albeit very minor since there is this workaround.

anrikun’s picture

Hey, I have just remembered one thing.
Actually, ckeditor_link_ckeditor_link_menu_revert() returns FALSE if the given path is not a valid Drupal path or if user has not access to it.
This is the way it has to be: an invalid path cannot be reverted and a path that current user has not access to should not be.
So, unlike I said before (sorry for that!), even if menu hook is not run in last position, everything should work as expected.
So I suggest:
1. You add your implementation without changing order (like you did at the beginning).
2. You make sure your paths are valid paths. Are you sure they are? Does current user has access to them?

Maybe you could give me more information about the paths you want to handle?

martin_q’s picture

Maybe I am misunderstanding how you intended the module to be used. Using hook_ckeditor_link_autocomplete(), I place pseudo-'paths' into the page that only make sense to my module. They look like this: 'mlsp/1234'. Then, in my ..._revert() and ..._url() hook implementations, I know that this link belongs to me, I work out what node it should point to, and I do the checks and either return a full URL or nothing at all.

The way your module works, each plugin module should not care about the internal implementation of the links. Indeed, your own documentation says that the hooks should return "nothing if the implementing module is not responsible for the given path." The 'menu' type is not responsible for my 'mlsp/XXX' paths, so your hook description says it should return nothing. Instead, one could say that it is interfering, and blocking, and not giving my module a chance to return a legitimate path!

I think I preferred your earlier explanation and the idea that the checks in 'menu' should come last of all. In any case, the behaviour you have now is not consistent with the documentation, and I prefer the documentation than the actual behaviour! :)

anrikun’s picture

Version: 6.x-2.1 » 6.x-2.x-dev
Category: support » bug
Priority: Normal » Minor
Status: Active » Fixed

Your further explanations absolutely make sense, especially:

The way your module works, each plugin module should not care about the internal implementation of the links.

When I designed CKEditor Link, I was assuming that any path handled by the module would always be a path that exists in the router table. But your post made me realize that it is not always the case and that it does not have to be a requirement.

So thank you for this issue :) I turn it into a bug... fixed! I have committed a better implementation of the menu hooks.
So please download the latest 6.x-2.x-dev or get it from GIT and confirm me that it works as expected, even without reordering types.

I will then port changes to the D7 version.

martin_q’s picture

Somebody on d.o thinks I'm right about something?

*faints*

Ha, seriously, thanks for looking into that. :) I haven't looked at your code but I can confirm that the fix does work as expected.

anrikun’s picture

Version: 6.x-2.x-dev » 7.x-2.x-dev
Status: Fixed » Closed (fixed)

This is now fixed both in 6.x-2.x-dev and 7.x-2.x-dev :-)