CKEditor inline instance fails to reload after it's destroyed - plugins

For the app I'm working on, users can edit text inline using CKEditor. Recently, I've included 2 extra plugins that I modified: stylescombo and bidi. For both of these, I just gave it a new name and modified what happens when text is clicked.
When a user clicks on a block of text to edit, I would dynamically load CKEditor onto it like this:
HTML: <div id="text-content">sample text</div>
JS: var $text = $("#text-content");
$text.attr("contenteditable", true);
CKEDITOR.disableAutoInline = true;
...
// toolbarOptions is an array of toolbar options
var editor = CKEDITOR.inline("text-content", {toolbar: toolbarOptions});
When user clicks away from the CKEditor, I would destroy the editor like this:
editor.destroy(true);
editor = null;
$("#text-content").removeAttr("contenteditable");
Now all of this works fine the first time, but when I attempt to edit the text-content again, the CKEditor fails to load without any error whatsoever. I console log the "editor" variable and I see the status of the editor being "unloaded". After some debugging, I found that if I don't load one of the 2 customized plugins above, the editor can reload after being destroyed. Any ideas why those 2 plugins are affecting the reloading of the inline CKEditor?
Demo: http://jsfiddle.net/22A6F/

Related

Why does document.execCommand('undo') not work in TinyMCE?

I am working on a chrome extension that lets users pre-configure action sequences.
I noticed that document.execCommand('undo') doesn't work in TinyMCE.
However tinyMCE.execCommand('undo') works fine.
Is there a way to make document.execCommand('undo') work directly in TinyMCE?
Any text or images or other items added to the editor creates an event in the separate, TinyMCE DOM. This is why document.exeCommand('undo'); won't affect added content and returns 'false' in the console.
To see this in action, I contrasted TinyMCE with a standard textarea and content editable section, and tried out the commands in the console: the document.execCommand returns 'true' when run in the console for undoing content in the textarea and contenteditable. But it does return 'false' for TinyMCE.
(As for a way to make document.execCommand run in TinyMCE, I'm not sure it is possible.)

Showing TinyMCE code plugin into the editor, not in popup

I am designing an HTML editor for Windows Forms. I use Geckofx 60.64 and TinyMCE 5.2.0 for this. When everything runs smoothly, this will be a usercontrol.
Here is the screenshot:
And I don't want anything that pops up as a popup in this usercontrol. However, TinyMCE's code plugin opens as a popup.
As in the TinyMCE editor in Wordpress, I want the contents of the HTML code to be displayed in the editor when you click on the code icon and return it when you click the code icon again. But I have no idea how I can do it.
In order to better explain what I want, I also designed a simple image in Photoshop.
The code view in WordPress is not actually using the TinyMCE code view plugin. Rather it extracts the editor contents, loads it into a textarea, allows you to edit, and then it re-invokes TinyMCE and reloads the updated HTML.
If you want a similar experience to WordPress you will have to create the code view behavior yourself.
If you want to use the code viewer that TinyMCE provides it works as a dialog.
I had a similar request (displaying html source in editor) and achieved a pretty simple and (for me) sufficient solution by modifying the initial (open source) code plugin:
var e = tinymce.util.Tools.resolve("tinymce.PluginManager"),
p = tinymce.util.Tools.resolve("tinymce.dom.DOMUtils"),
o = function (o) {
var e = o.getContent({source_view: !0});
var b = o.getBody();
if (b.getAttribute("code") === "true") {
b.setAttribute("code", "false");
b.style.backgroundColor = "white";
b.style.color = "black";
b.style.fontFamily = "Helvetica";
o.setContent(p.DOM.decode(e));
} else {
b.setAttribute("code", "true");
b.style.backgroundColor = "black";
b.style.color = "white";
b.style.fontFamily = "Monaco";
o.setContent(p.DOM.encode(e));
}
};
Instead of opening a new window, it just changes the css of the editor (background, color, font) and sets a data-attribute (enables toggling between the initial view and the code view). The p.DOM.encode(e) then allows to display the html tags.
I'm not very experienced in javascript, but it works good so far. Anyway, feel free to correct / improve things.

Wicket AjaxLink javascript handler shows strange behaviour

I have a ListView that displays a list of Panels, one below the other. Every panel features a button (implemented via AjaxLink) that closes the panel and removes it from the list.
This is how the ListView is initalized and how the panels are created:
panelsList = new ArrayList<MyPanel>();
pnlContainer = new WebMarkupContainer("pnlContainer");
ListView<MyPanel> pnlItems = new ListView<MyPanel>("pnlItems", panelsList) {
#Override
protected void populateItem(final ListItem<MyPanel> item) {
item.add(item.getModelObject());
item.add(new AjaxLink<Void>("pnlClose") {
#Override
public void onClick(AjaxRequestTarget target) {
panelsList.remove(item.getModelObject());
target.add(pnlContainer); // repaint panel container
}
});
}
};
pnlContainer.setOutputMarkupId(true);
pnlContainer.add(pnlItems);
add(pnlContainer);
This works so far - the actions that trigger adding new panels (usually also AjaxLinks) do what they should and the new panel is added and displayed correctly. But I have problems getting the close button to fully work.
Please see the following steps:
1) I start the server and navigate to the main page. The ListView is initially populated with one panel.
Close-button-code of this panel:
<a wicket:id="pnlClose" id="pnlClose7" href="javascript:;">Close</a>
Searching the page code for pnlClose7 finds the following javascript code that makes the button work as expected:
Wicket.Ajax.ajax({"u":"./?0-1.IBehaviorListener.0-pnlContainer-pnlItems-0-pnlClose","e":"click","c":"pnlClose7"});;
Note: I do not press the button now, if i would, it would work as expected (thoroughly tested).
2) I trigger an action that opens a second panel. The panel is displayed below the first one as expected.
Close-button of the first panel:
<a wicket:id="pnlClose" id="pnlClosef" href="javascript:;">X</i></a>
Close-button of the second panel:
<a wicket:id="pnlClose" id="pnlClose10" href="javascript:;">X</i></a>
But now, neither searching for pnlClosef nor pnlClose10 finds some javascript code. The buttons (both!) do not work. I can still find the javascript code for pnlClose7.
3) I reload the page via pressing F5.
The button IDs change to pnlClose1a and pnlClose1b. Both IDs have javascript counterparts and work.
4) I press the first button (upper panel, ID pnlClose1a). The panel is closed as expected.
The remaining button's ID changes to pnlClose1c, again without a javascript counterpart. Javascript code for pnlClose1a and pnlClose1b is still present.
To make a long story short, the javascript handlers for my AjaxLinks seem to have shyness issues and only appear after I press F5 or reload the whole page in any other manner. I guess thats because repainting the pnlContainer changes the IDs of the current panels - but why is the linked javascript not updated at the same time? Is there anything I can change in my code to update the whole page without completely reloading it?
Wierd thing is that I am pretty sure this worked before... But I checked the whole class history and can't find any major change that would have triggered that. The ListView-code is mainly static since I added it.
I was had similiar problem. if you have any hardcoded javascript code in your page or panels html file (using <script> tag) remove it and set that js code in renderHead of your panel.

Google Closure add onclick to button after adding this button with custom editor plugin

I am making a custom plugin for the editor provided by Google Closure. The plugin makes it able to add a button.
I am having problems by setting an onclick on the button, the other values are nicely set.
button.innerHTML = event.label;
button.className = event.initialClass;
var extraClasses = event.extraClasses;
if (extraClasses)
{
button.className += ' ' + extraClasses
}
button.onclick = function() { event.onclick };
Does anyone know what I am doing wrong and how I can fix this?
After creating a button it is added to the editors SeamlessField. A second problem that I currently have is that after creating the button, my pointer is inside the button and I can't seem to get it out of there.
I've got the follow piece of code for handling this at the moment. The var button is the created button. button contains: <button class="orange">test</button>
// We want to insert the button in place of the user's selection.
// So we restore it first, and then use it for insertion.
this.restoreOriginalSelection();
var range = this.fieldObject.getRange();
button = range.replaceContentsWithNode(button);
// Done making changes, notify the editor.
this.fieldObject.dispatchChange();
// Put the user's selection right after the newly inserted button.
goog.editor.range.placeCursorNextTo(button, false);
// Dispatch selection change event because we just moved the selection.
this.fieldObject.dispatchSelectionChangeEvent();
Any ideas about how I could fix this second problem aswell?
For the first, it does not look like you have begun using Google Closure event code. Wiring up the button to the 'click' event in Google Closure would be as follows:
goog.events.listen(button, goog.events.EventType.CLICK, event.onclick)
You should also be investigating the goog.dom and goog.dom.classes namespaces if you'd like to use Google Closure's wrappers around standard CSS class and text DOM manipulation.
For the second, were you testing in Chrome? If so, you might have ran into a range issue in Webkit, documented within the Closure code itself:
https://code.google.com/p/closure-library/source/browse/closure/goog/editor/range.js#174
I have gotten around this in the past by inserting an empty <span> element as a sibling after the offending element (the button, in your case), and placing the cursor next to the <span> instead. However, there's nothing stopping the user from moving the cursor back inside your button. You'll have to add more logic to prevent a user from placing the cursor within the button's text.

TinyMCE content not being updated when using hide

First of all, this is not about the tinyMCE.triggerSave();
Sometimes when editing content, I switch to the textarea mode with the following
$('#id').tinymce().hide(); // from the official example
which temporarily hides the rich editor from view so I can see the HTML codes.
But if I submit the form right after editing without switching back to rich editor [ using .show() ], the content will not be updated.
My question is how can I save the content of textarea to iframe?
Please do not offer me the "use the code window" option, I have a customized show/hide button outside of TinyMCE.
Switching by mceAddControl/mceRemoveControl will solve the problem. But when submitting, the content inside the textarea will not be formatted.
Well, I just figured out a way to update content
$('#id').blur(function() {
$('#id').html(document.getElementById('id').value);
});
UPDATE
this might be even better, for all instances
$('textarea.tinymce').blur(function() {
var this_id = $(this).attr('id');
$('#' + this_id).html(document.getElementById(this_id).value);
});
Any other solutions are really appreciated.