wp-admin-modal-example
wp-admin-modal-example copied to clipboard
Add TinyMCE Plugin to Backbone Example
Extend the backbone plugin to include a sample TinyMCE plugin.
See Issue #5
First, thanks for sharing this on github! It was an amazing help to my latest project.
I've got a tinymce editor working in your backbone modal.
A couple of steps ( note: modal-editor
is the ID of the textarea):
- ensure that
editor
is one of the dependencies for enqueing the modal script - duplicate the HTML markup in your template, some of this is handled via PHP so I had to hard-code some div IDs/classes
<div class="wp-editor-wrap">
<div class="postarea wp-editor-expand">
<div id="wp-modal-editor-wrap" class="wp-core-ui wp-editor-wrap has-dfw">
<div id="wp-modal-editor-editor-tools" class="wp-editor-tools hide-if-no-js">
<div class="wp-media-buttons">
<button type="button" class="button insert-media add_media" data-editor="modal-editor"><span class="wp-media-buttons-icon"></span><?php _e( 'Add Media', 'backbone_modal' );?></button>
</div>
<div class="wp-editor-tabs">
<button type="button" id="content-tmce" class="wp-switch-editor switch-tmce" data-wp-editor-id="modal-editor"><?php _e( 'Visual', 'backbone_modal' ); ?></button>
<button type="button" id="content-html" class="wp-switch-editor switch-html" data-wp-editor-id="modal-editor"><?php _ex( 'Text', 'Name for the Text editor tab (formerly HTML)', 'backbone_modal' ); ?></button>
</div>
</div><!-- .wp-editor-tools -->
<div class="wp-editor-container">
<textarea id="modal-editor" class="wp-editor-area" autocomplete="off" cols="40" name="content">{{{ data.content }}}</textarea>
</div>
</div>
</div>
</div>
- "borrow" the settings from the
tinyMCEPreInit
object. I run this function on the view'sinitialize()
/**
* Merge the default TinyMCE settings
*/
tinyMCEsettings: function() {
// get the #content"s tinyMCE settings or use default
var init_settings = typeof tinyMCEPreInit == "object" && "mceInit" in tinyMCEPreInit && "content" in tinyMCEPreInit.mceInit ? tinyMCEPreInit.mceInit.content : this.tmc_defaults;
// get the #content"s quicktags settings or use default
var qt_settings = typeof tinyMCEPreInit == "object" && "qtInit" in tinyMCEPreInit && "content" in tinyMCEPreInit.qtInit ? tinyMCEPreInit.qtInit.content : this.qt_defaults;
var _this = this;
var custom_settings = {
selector: "#modal-editor"
}
// merge our settings with WordPress" and store for later use
this.tmc_settings = $.extend({}, init_settings, custom_settings);
this.qt_settings = $.extend({}, qt_settings, {
id: "modal-editor"
});
},
- then after the modal and textarea are rendered, run
/**
* Start TinyMCE on the textarea
*/
startTinyMCE: function() {
// add our copy to the collection in the tinyMCEPreInit object because switch editors
if (typeof tinyMCEPreInit == 'object') {
tinyMCEPreInit.mceInit["modal-editor"] = this.tmc_settings;
tinyMCEPreInit.qtInit["modal-editor"] = this.qt_settings;
}
try {
var rich = (typeof tinyMCE != "undefined");
// turn on the quicktags editor
quicktags(this.qt_settings);
// attempt to fix problem of quicktags toolbar with no buttons
QTags._buttonsInit();
if (rich !== false) {
// turn on tinyMCE
tinyMCE.init(this.tmc_settings);
}
} catch (e) {}
},
I think that's pretty much everything I have to get media buttons plus text/visual editor switching working. I have one remaining problem with the "link" plugin not appearing, but otherwise it's all working.
Thanks again!
Thanks @helgatheviking ! This is good stuff and I'm glad my code helped you out -- though I have to apologize for how outdated it is.
I have a working example of a custom modal launching from a tinyMCE plugin/button containing a fully-functioning tinyMCE editor I did for a client I'll share if I can find time to circle back to this repo. I'll need to re-write it to pull out all their domain-specific stuff and I've been overloaded with projects (excuses, excuses, right? ;-)
As for the link-modal, there are a ton of things that could be causing you grief. One easy fix is that that the link-modal will not appear if the body has the modal-open
class, so it might benefit you to create your own version of modal-open
. Doubt that helps in this situation (but it shouldn't hurt either).
Thanks for the info and the follow on twitter.
the link-modal will not appear if the body has the
modal-open
class
WHAAAAAAAAAAAAAT? Stop the presses. I've been struggling with that for days! I just switched the class name in my addClass
and the link plugin appears. You can't type in it yet, but damn, that's a nice improvement. Would love to see your example if you get the time.
Thanks again!
I've discovered that your preserveFocus
function is what is preventing the link plugin from appearing.
Borrowing from this answer I've added an extra if condition:
preserveFocus: function(e) {
"use strict";
// this allows for the tinymce plugins to still work
if ($(e.target).closest(".mce-container").length) {
e.stopImmediatePropagation();
} else if (this.$el[0] !== e.target && !this.$el.has(e.target).length) {
this.$el.focus();
}
},
The link plugin is working! it's generating this error "Uncaught TypeError: Cannot read property 'fire' of undefined" even though everything seems to be working.
Anyway, I've been trying to tweak the modal to copy the media modal's markup so that it inherits the media modal's styles. It seems like I ought to be able to use the media modals's backbone views somehow, but I'm not at that level of backbone badassery yet. Thanks again!!
Just to keep adding on for posterity, the above preserveFocus()
still isn't doing everything I need because it's still blocking the media modal when you click on "Add Media". How much do you think this is really needed?
That method keeps the user's focus on the modal. Without it, user of assistive technology or keyboard-only users can get lost/trapped in the content being covered by the modal.
If your project doesn't need to be accessible (comply with sec.508 or WCAG 2.0) and you don't envision disabled users using the product, then it can be removed.
Another solution is to listen for other modals being opened and suspend the method until the other modals are closed. This is what's recommended by the W3C in their ARIA best practices, and I suspect is being used in WP itself in places.
Hope that helped and sorry I have so little time to update this project.
There's no need to apologize. I'm so grateful that this is even here and that you're willing to bounce this idea around with me. I learned something new about accessibility. I wonder if I let that .closest()
bubble up a little higher to look for the modal frame if that might do the trick.
Another solution is to listen for other modals being opened and suspend the method until the other modals are closed.
If you did that could you not still get trapped in the content behind the modal?
Back to the drawing board!
If you did that could you not still get trapped in the content behind the modal?
Theoretically, no, because the modal opened by your custom modal would also trap keyboard interaction within itself and relinquish it when closed. Obviously, it depends on if the link modal traps focus within itself -- I know the WP media modal traps input focus once opened with a very similar method ( might be where this came from, can't remember).
Another solution would be to add the media modal class to your list of allowed focus targets.
// untested, blind code:
preserveFocus: function(e) {
"use strict";
var $target = $(e.target);
if (e.target !== document &&
$target.closest(".mce-container").length === 0 &&
$target.closest(".media-modal").length === 0 &&
this.$el[0] !== e.target &&
!this.$el.has(e.target).length ) {
this.$el.focus();
}
},
Sorta doubt this is a good direction, but it might be good enough. If you had the time to invest in it, It would probably be better to listen for any of the modals your modal could open and add them to an array of "allowed" parents. if the parent .has()
the active element, allow focus.
Doing more research, I've found that the default media modal doesn't have a preserveFocus
style function that is listening on the focusin
event. It does use something called the focusManager
which restricts the ability to "tab" around only to the modal.
Here's the focusManager
and here it is being used in the media modal.
I don't really know enough about accessibility, but hopefully it's "good enough" if I copy core. :) It should at least get the project done, though I'd love to go back and see if I can't create a modal from exiting WP media views/states.
Thanks again!