diff --git a/javascript/HtmlEditorField.js b/javascript/HtmlEditorField.js
index e2f4fbc90..6c3b59e14 100644
--- a/javascript/HtmlEditorField.js
+++ b/javascript/HtmlEditorField.js
@@ -171,6 +171,13 @@
*/
moveToBookmark: function(bookmark) {
this.getInstance().selection.moveToBookmark(bookmark);
+ this.getInstance().focus();
+ },
+ /**
+ * Removes any selection & de-focuses this editor
+ */
+ blur: function() {
+ this.getInstance().selection.collapse();
},
/**
* Add new undo point with the current DOM content.
@@ -318,6 +325,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
url: url,
success: function(html) {
dialog.html(html);
+ dialog.trigger('dialogopen');
}
});
}
@@ -325,19 +333,17 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
});
$('.htmleditorfield-dialog').entwine({
- onmatch: function() {
+ onadd: function() {
// Create jQuery dialog
var height = $(window).height() * 0.8;
- var width = $(window).width() * 0.8;
+ var width = $(window).width() * 0.8;
- this.dialog({autoOpen: true, bgiframe: true, modal: true, height: height, width: width, ghost: true});
+ if (!this.is('.ui-dialog-content')) this.dialog({autoOpen: true, bgiframe: true, modal: true, height: height, width: width, ghost: true});
this._super();
},
- onunmatch: function() {
- this._super();
- },
+
getForm: function() {
return this.find('form');
},
@@ -350,13 +356,6 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
toggle: function(bool) {
if(this.is(':visible')) this.close();
else this.open();
- },
- ondialogopen: function(e) {
- this.getForm().updateFromEditor();
- this.getForm().redraw();
- },
- ondialogclose: function(e) {
- this.getForm().resetFields();
}
});
@@ -365,44 +364,69 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
* mostly geared towards modification and insertion of content.
*/
$('form.htmleditorfield-form').entwine({
+ Selection: null,
+ Bookmark: null,
+
+ setSelection: function(node) {
+ return this._super($(node));
+ },
// Wrapper for various HTML editors
Editor: null,
- // TODO Figure out how to keep bookmark reference in entwine, and still be allowed to delete the JS object
- // Bookmark: null,
- onmatch: function() {
+ onadd: function() {
// Move title from headline to (jQuery compatible) title attribute
var titleEl = this.find(':header:first');
this.getDialog().attr('title', titleEl.text());
this._super();
-
- this.redraw();
},
- onunmatch: function() {
+ onremove: function() {
+ this.setSelection(null);
+ this.setBookmark(null);
+ this.setEditor(null);
+
this._super();
},
- redraw: function() {
- },
- resetFields: function() {
- if(typeof window._ss_htmleditorfield_bookmark != 'undefined') window._ss_htmleditorfield_bookmark = null;
- this.getEditor().onclose();
- },
+
getDialog: function() {
// TODO Refactor to listen to form events to remove two-way coupling
return this.closest('.htmleditorfield-dialog');
},
- /**
- * Update the view state based on the current editor selection.
- */
- updateFromEditor: function() {
- this.getEditor().onopen();
- window._ss_htmleditorfield_bookmark = this.getEditor().createBookmark();
+
+ fromDialog: {
+ ondialogopen: function(){
+ var ed = this.getEditor();
+ ed.onopen();
+
+ this.setSelection(ed.getSelectedNode());
+ this.setBookmark(ed.createBookmark());
+
+ ed.blur();
+
+ this.find(':input:not(:submit)[data-skip-autofocus!="true"]').filter(':visible:enabled').eq(0).focus();
+
+ this.updateFromEditor();
+ this.redraw();
+ },
+
+ ondialogclose: function(){
+ var ed = this.getEditor();
+ ed.onclose();
+
+ ed.moveToBookmark(this.getBookmark());
+
+ this.setSelection(null);
+ this.setBookmark(null);
+
+ this.resetFields();
+ }
},
+
createEditor: function(){
return ss.editorWrappers['default']();
},
+
/**
* Get the tinyMCE editor
*/
@@ -412,6 +436,28 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
this.setEditor(val = this.createEditor());
}
return val;
+ },
+
+ modifySelection: function(callback) {
+ var ed = this.getEditor();
+
+ ed.moveToBookmark(this.getBookmark());
+ callback.call(this, ed);
+
+ this.setSelection(ed.getSelectedNode());
+ this.setBookmark(ed.createBookmark());
+
+ ed.blur();
+ },
+
+ updateFromEditor: function() {
+ /* NOP */
+ },
+ redraw: function() {
+ /* NOP */
+ },
+ resetFields: function() {
+ /* NOP */
}
});
@@ -463,7 +509,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
}
},
insertLink: function() {
- var href, target = null, anchor = this.find(':input[name=Anchor]').val(), ed = this.getEditor();
+ var href, target = null, anchor = this.find(':input[name=Anchor]').val();
// Determine target
if(this.find(':input[name=TargetBlank]').is(':checked')) target = '_blank';
@@ -503,17 +549,16 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
title : this.find(':input[name=Description]').val()
};
- // Workaround for browsers losing focus, similar to tinyMCEPopup.restoreSelection
- ed.moveToBookmark(window._ss_htmleditorfield_bookmark);
- window._ss_htmleditorfield_bookmark = null;
+ this.modifySelection(function(ed){
+ ed.insertLink(attributes);
+ })
- // Add the new link
- ed.insertLink(attributes);
- this.trigger('onafterinsert', attributes);
this.updateFromEditor();
},
removeLink: function() {
- this.getEditor().removeLink();
+ this.modifySelection(function(ed){
+ ed.removeLink();
+ })
this.close();
},
addAnchorSelector: function() {
@@ -590,7 +635,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
* form.
*/
getCurrentLink: function() {
- var ed = this.getEditor(), selectedEl = $(ed.getSelectedNode()),
+ var selectedEl = this.getSelection(),
href = "", target = "", title = "", action = "insert", style_class = "";
// We use a separate field for linkDataSource from tinyMCE.linkElement.
@@ -611,7 +656,9 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
linkDataSource = selectedEl = selectedEl.parents('a:first');
}
}
- if(linkDataSource && linkDataSource.length) ed.selectNode(linkDataSource[0]);
+ if(linkDataSource && linkDataSource.length) this.modifySelection(function(ed){
+ ed.selectNode(linkDataSource[0]);
+ });
// Is anchor not a link
if (!linkDataSource.attr('href')) linkDataSource = null;
@@ -621,7 +668,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
target = linkDataSource.attr('target');
title = linkDataSource.attr('title');
style_class = linkDataSource.attr('class');
- href = ed.cleanLink(href, linkDataSource);
+ href = this.getEditor().cleanLink(href, linkDataSource);
action = "update";
}
@@ -699,21 +746,20 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
this.find('.overview .action-delete')[updateExisting ? 'hide' : 'show']();
},
onsubmit: function() {
- var self = this, ed = this.getEditor();
+ this.modifySelection(function(ed){
+ this.find('.ss-htmleditorfield-file').each(function() {
+ $(this).insertHTML(ed);
+ });
+
+ ed.repaint();
+ })
- // HACK: See ondialogopen()
- // jQuery(ed.getContainer()).show();
-
- this.find('.ss-htmleditorfield-file').each(function() {
- $(this).insertHTML();
- });
- ed.repaint();
this.getDialog().close();
-
return false;
},
updateFromEditor: function() {
- var self = this, ed = this.getEditor(), node = $(ed.getSelectedNode());
+ var self = this, node = this.getSelection();
+
// TODO Depends on managed mime type
if(node.is('img')) {
this.showFileView(node.data('url') || node.attr('src'), function() {
@@ -727,7 +773,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
redraw: function() {
this._super();
- var ed = this.getEditor(), node = $(ed.getSelectedNode()),
+ var node = this.getSelection(),
hasItems = Boolean(this.find('.ss-htmleditorfield-file').length),
editingSelected = node.is('img'),
header = this.find('.header-edit');
@@ -750,11 +796,6 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
this.find('.Actions .media-update')[updateExisting ? 'show' : 'hide']();
},
resetFields: function() {
- var ed = this.getEditor(), node = $(ed.getSelectedNode());
-
- // HACK: See ondialogopen()
- // jQuery(ed.getContainer()).show();
-
this.find('.ss-htmleditorfield-file').remove(); // Remove any existing views
this.find('.ss-gridfield-items .ui-selected').removeClass('ui-selected'); // Unselect all items
this.redraw();
@@ -869,13 +910,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
/**
* Insert updated HTML content into the rich text editor
*/
- insertHTML: function() {
- var form = this.closest('form'), ed = form.getEditor();
-
- // Workaround for browsers losing focus, similar to tinyMCEPopup.restoreSelection
- ed.moveToBookmark(window._ss_htmleditorfield_bookmark);
- window._ss_htmleditorfield_bookmark = null;
-
+ insertHTML: function(ed) {
// Insert content
ed.replaceContent(this.getHTML());
},
@@ -959,16 +994,9 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
/**
* Logic similar to TinyMCE 'advimage' plugin, insertAndClose() method.
*/
- insertHTML: function() {
- var form = this.closest('form'), ed = form.getEditor(),
- node = $(ed.getSelectedNode()), captionNode = node.closest('.captionImage');
-
- // Workaround for browsers losing focus, similar to tinyMCEPopup.restoreSelection.
- // TODO In TinyMCE core this is restricted to IE, but leaving it our also
- // breaks Firefox: It doesn't save the selection because it inserts into a temporary TinyMCE
- // marker element rather than the content DOM nodes
- ed.moveToBookmark(window._ss_htmleditorfield_bookmark);
- window._ss_htmleditorfield_bookmark = null;
+ insertHTML: function(ed) {
+ var form = this.closest('form'),
+ node = form.getSelection(), captionNode = node.closest('.captionImage');
if(node && node.is('img')) {
// If the image exists, update it to avoid complications with inserting TinyMCE HTML content