Closed (fixed)
Project:
Wysiwyg
Version:
5.x-2.x-dev
Component:
Code
Priority:
Normal
Category:
Bug report
Assigned:
Reporter:
Created:
10 Oct 2008 at 02:26 UTC
Updated:
23 Mar 2009 at 05:20 UTC
Jump to comment: Most recent file
The current work in progress in #245799: Update TinyMCE integration to 3.x uncovered some caveats Wysiwyg API needs to handle. Specifically:
| Comment | File | Size | Author |
|---|---|---|---|
| #41 | 319363.patch | 802 bytes | owen barton |
| #40 | wysiwyg-DRUPAL-5--2.rewrite-fixes.patch | 5.79 KB | sun |
| #38 | 319363.patch | 31.3 KB | owen barton |
| #32 | wysiwyg-HEAD.pluginapi.patch | 46.93 KB | sun |
| #32 | img_assist.pluginapi.patch | 11.7 KB | sun |
Comments
Comment #1
sunFirst iteration. Pretty close. Only works in FF due to some leftover Firebug debugging code.
Please note that the Drupal/major version of this issue does not matter, since all the code we touch is our own module/API code, which is almost identical for all Drupal versions.
Hm. After reviewing this patch, I guess it would be helpful to commit some of the structural changes first...? (moved editor function callstacks from Drupal.wysiwyg.* to Drupal.wysiwyg.editor.* to make space for our new Drupal.wysiwyg.invoke callstack)
Comment #2
sunComment #3
sunCommitted the namespace changes separately.
Comment #4
sunThis patch adds the first working editor plugin, provided by a Drupal module.
Comment #5
sunNow supporting TinyMCE 2, YAY!
Comment #6
quicksketchUpdated patch (only for Drupal 6/HEAD version) to include invoke commands for plain textareas ("none.js"). This is rocking!
Comment #7
sunInvoke functions for the none editor are properly updated now, when no editor is attached. Hence, doing
Drupal.wysiwyg.invoke.insert('edit-body', 'FOO!');
and disabling the editor (in various ways) and doing
Drupal.wysiwyg.invoke.insert('edit-body', 'FOO!');
results in the expected action -- insert "FOO!" in the textarea/editor/textarea/editor/textarea/editor/textarea/editor/textarea/editor/textarea/editor/... 8)
However, I think we need to pass some context info to plugins provided by Drupal modules, since they would have, for example, to do Drupal.wysiwyg.invoke.insert('edit-body', '<!--break-->'); for the none editor, and Drupal.wysiwyg.invoke.insert('edit-body', '<img class="wysiwyg-break" ... />'); for an HTML editor.
TinyMCE implemented some nice way to support this, speaking JS:
data = {};
data.content = 'Editor content goes here';
data.format = 'html' | 'raw' (= text) | 'xml';
So instead of passing the content as plain string, we should pass it as object including some meta information for Drupal plugins provided via the proxy plugin.
Comment #8
sunTalk is silver, code is gold -- Practical example, break.js:
So, basically, Drupal.wysiwyg.invoke.insert() is a dumb function. Drupal plugins have to sort out the target format of an inserted/updated content before altering the editor contents. So either we hard-code data.format in the proxy plugin (according to the editor), or might even turn this into a profile/input format setting.
Comment #9
sunAttached patch adds the required data.format for Drupal plugins like Teaser break.
Additionally, the function prepareContent() was added to the invoke functions (for both TinyMCE 2 and 3), which parses the content that is about to be inserted and adds special properties to elements, which need them, because most editors apply internal DOM properties to distinguish whether a content element belongs to an internal editor button (for example, selecting the Teaser break image should not highlight TinyMCE's built-in image button).
Drupal plugin implementations now also support the properties "icon title", which moves the localization of buttons completely into Drupal's localization system.
Comment #10
sunBefore moving ahead and trying to implement Image Assist as new style API plugin, the new API code badly needs a major clean-up. The current PHP part of the implementation is rather a hack. So what happens there:
a) The schema and structure of (editor-specific) plugins provided via hook_wysiwyg_plugin() is different than the one of Drupal plugins.
b) Drupal plugins are stacked into one proxy plugin, internally called "drupal".
c) The new Drupal plugins can be loaded separately. But the old hook_wysiwyg_plugin() plugins cannot, because the defining module is unknown. A plugin "registry" doesn't make sense in terms of D7, but we should gather the defining module names to store them in a Wysiwyg profile, directly invoke the corresponding functions, and finally improve performance.
d) Instead of rebuilding the plugin list, this function should probably rely on wysiwyg_editor_get_plugins().
a) Even the simple Teaser break plugin relies on settings.path, resp. Drupal.settings.wysiwyg.plugins.break.path, which means that plugin settings are actually divided into plugin-specific settings and editor-specific settings. The former must not be overridden.
b) The current plugin settings callback for TinyMCE also adds the JavaScripts of Drupal plugins. But loading external scripts and just adding settings should be clearly separated. (Scripts are required to be loaded in a certain order, and Drupal.settings must come before wysiwyg_editor.js)
c) The plugin settings callback needs to explicitly check for the plugin name "drupal", and has to add different settings for the Drupal plugins provided via the proxy plugins.
d) Because of the missing separation between editor-specific plugins and Drupal plugins, there is also an ugly variable type check in Drupal.wysiwyg.editor.init.tinymce().
a) Again, a hard-coded check for the internal "drupal" plugin name here.
b) Probably most confusing at first glance: The "drupal" proxy plugin is NOT added to the editor initialization settings. Only the buttons are added, since the proxy plugin itself adds itself in tinymce-3.js, for example.
c) If we would not stack Drupal plugins into the 'buttons' array of the proxy plugin, they would not appear on the profile configuration form.
Comment #11
sunCommitted the code clean-up changes separately.
Comment #12
sunCommitted another namespace clean-up separately, changing the JS *settings* namespace from 'wysiwygEditor' to 'wysiwyg'; a prerequisite for this patch.
Comment #13
sunAttached patch eliminates:
3a
4a,b,c,d
by
Drupal.settings.wysiwyg.plugins.tinymce.native: contains native plugins to load.
Drupal.settings.wysiwyg.plugins.tinymce.drupal: contains an array of Drupal plugin settings to process via the proxy plugin.
Drupal.settings.wysiwyg.plugins.drupal: contains settings specific for each Drupal plugin (currently, a 1:1 copy of the 'settings' definition of a Drupal plugin).
So, what's left?
3b) Drupal plugins are stacked into one proxy plugin, internally called "drupal".
5a) Again, a hard-coded check for the internal "drupal" plugin name here.
5b) Probably most confusing at first glance: The "drupal" proxy plugin is NOT added to the editor initialization settings. Only the buttons are added, since the proxy plugin itself adds itself in tinymce-3.js, for example.
5c) If we would not stack Drupal plugins into the 'buttons' array of the proxy plugin, they would not appear on the profile configuration form.
The following are rather a performance issues, and I'd like to defer anything related to performance for later:
3c) The new Drupal plugins can be loaded separately. But the old hook_wysiwyg_plugin() plugins cannot, because the defining module is unknown. A plugin "registry" doesn't make sense in terms of D7, but we should gather the defining module names to store them in a Wysiwyg profile, directly invoke the corresponding functions, and finally improve performance.
3d) Instead of rebuilding the plugin list, this function should probably rely on wysiwyg_editor_get_plugins().
Comment #14
sunLast patch update for today.
Comment #15
smk-ka commentedI do not understand the purpose of this part of Drupal.wysiwygAttach():
Since this function gets executed in a loop, Drupal.wysiwyg.invoke (BTW, using a verb for what's supposed to be an object is a bad choice) and Drupal.wysiwyg.activeId will be overwritten with the last editor instance.
Comment #16
sunRe-roll after #321216: Move wysiwyg_editor into wysiwyg module has landed.
Comment #17
sunQuick braindump after discussing #15 with smk-ka, since I need to work on something different for the next hours:
Comment #18
sunRe-rolled, since #320559: Add confirmation dialog to delete profiles. has landed.
Comment #19
sunRe-rolled, since frickin' awesome #327100: Associate editors/profiles with input formats has landed. 8)
- Changed Drupal.wysiwyg.invoke into Drupal.wysiwyg.instances, as well as Drupal.wysiwyg.editor.invoke.<editor> into Drupal.wysiwyg.editor.instance.<editor>.
Comment #20
sunRe-rolled after a flood of patches went in.
Also contains some overlapping changes for #328052: Switching between input formats conflicts with enable/disable rich-text.
Comment #21
Roi Danton commentedA perfect, conceivable workflow for a module that wants to use editors API is written here. Maybe this could be inspiring for the editors API in one way or another.
Comment #22
sunRe-rolled after another flood of patches went in.
Comment #23
Ryanbach commentedsub
Comment #24
murzsubscribe
Comment #25
PixelClever commentedsubscribing...
Comment #26
owen barton commentedThis looks really promising - is it worth applying and testing the patch, or is there still architectural stuff to be figured out?
Comment #27
sunAside from the points listed in #13, the design is basically fleshed out, I think. The "Teaser break" plugin for core's "<--break-->" teaser splitter inline tag should already work with TinyMCE 3, TinyMCE 2, and the default textarea (well, if you invoke the function to insert it from the console ;).
It also turned out to be good decision to already add support for other editors in the meantime. This revealed that some editors do not support external plugins at all (which would already be covered by the current proxy plugin design), some other editors use a completely different, but very flexible/overengineered way of defining and loading plugins (YUI/markItUp), and some editors do not have built-in support for popups or modal dialogs. The latter is one of the major issues I'm tinkering about, since we have two options for invoking/presenting the UI of Drupal plugins:
Pro: The interface and flow for Drupal plugins (that need an interface) is the same interface as for other, internal plugins of an editor. For example, if TinyMCE is configured to use modal dialogs (the "Inline popups" plugin), Drupal plugins could be presented in the same way as internal plugins by re-using TinyMCE's modal dialog functions. If it is configured to use popup windows, Drupal plugins would use popup windows as well.
Con: Popup/dialog functions are different for all editors, so we need a very solid proxy plugin API to make the required information available at the right time. If the editor uses popup windows, we need to ensure that jQuery and other scripts are properly loaded in the window. To re-use the UI of internal editor plugins, we would also have to create a "proxy dialog template" for Drupal plugins, which would have to provide "Insert"/"Update"/"Cancel" button functionality.
Pro: No overhead with editor-specific popup/dialog functions. We know that jQuery and plugin scripts are already loaded and available on the page.
Con: Drupal plugins would have a different UI than internal editor plugins. We either need to implement own library functions for invoking/displaying/resizing/draggin/closing a modal dialog, or we would have to add a dependency on another module - and I'm unsure whether there is one at all (popups? jQuery UI?).
In either case, dialog contents of Drupal plugins are usually presenting forms, so we have to ensure, resp. implement, methods for validating the form values and presenting error messages in the dialog via AJAX.
Re-rolled.
Comment #28
pillarsdotnet commented"
Comment #29
tstoecklerThe attached patches have been against the D6-dev version for quite a while. Did I miss something or was the Version tag simply outdated?
Comment #30
sunRe-rolled against latest HEAD.
Also fixed wrong instanceId passed to Drupal plugins in TinyMCE 2.
Comment #31
sunThis is a major breakthrough.
Also attached is a patch for Image Assist HEAD, which held off this patch. It's not yet generic, but makes Image Assist compatible to the new plugin API.
To summarize:
- The Teaser break plugin shipped with Wysiwyg API (on behalf of Drupal core) should work both in TinyMCE 3 and TinyMCE 2. It should also work when invoked manually.
- Image Assist should work with TinyMCE 3.x, using Wysiwyg's new plugin API.
Comment #32
sunLAST MINUTE fixes:
- Due to a wrong execution order, editor instance callbacks received the wrong editor field id ('this.field') of the previously attached editor.
- Fixed a bunch of wrong PHPDoc and coding-style flaws.
Note: All issues related to this patch as well as improvements related to @todo statements in this patch should be treated in separate issues. Thanks in advance.
WELCOME to the second generation of content-editing in Drupal!
8)
Comment #33
Roi Danton commentedThanks for providing the patch for img_assist, too! In case someone wonders the 6.x-2.x-dev release can be found here.
As far as I understand it is enough to use hook_wysiwyg_plugin() to add buttons to the supported editors with my module (as img_assist does). The things the plugin array has to contain seems to be quite self-explanatory. The possibility to use own dialogs is really great! Thx (and I shut up now and will write follow ups in separate issues as you requested ;) )!
Comment #34
sunThanks for reminding and pointing that out. 2.x is now displayed on the project page.
Comment #35
quicksketchExciting. Thanks sun!
Comment #36
aread22 commentedIs the teaser break plugin really working? I have the latest 6.x-2.x-dev release and TinyMCE 3.2.1.1 and have enabled the "Teaser Break" plugin in the Buttons area, but I do not see a button in the textarea. Thanks
Comment #37
tstoeckler@aread22:
sun:
Please DO open up a new issue for your problem, I am certain sun is desperately waiting for this issue to be finally closed.
Comment #38
owen barton commentedHere is a patch that backports the rest of these changes to the 5.x version (some were already committed). The break seems to work well, but I haven't tried the dialog code yet.
Comment #39
sunThank you! :)
Committed, erm, that patch + a bit more trickery to DRUPAL-5--2.
Marking as fixed. Please re-open if anything of this was just "mad nuts"... (possible, since untested).
Comment #40
sunCommitted a follow-up fix for the D5-theme-trickery.
Comment #41
owen barton commentedOne more fix to the 2.x dialog code - there is no theme_render_template function in Drupal 5 (this functionality was only moved from the phptemplate engine in Drupal 6).
Comment #42
sunSorry, this fell somehow out of my radar. Committed!