Dynamically updating a TinyMCE 4 ListBox

spud picture spud · Sep 14, 2013 · Viewed 11k times · Source

I'm trying to modify the TinyMCE 4 "link" plugin to allow users to select content from ListBox elements that are dynamically updated by AJAX requests.

I'm creating the ListBox elements in advance of editor.windowManager.open(), so they are initially rendered properly. I have an onselect handler that performs the AJAX request, and gets a response in JSON format.

What I need to do with the JSON response is to have it update another ListBox element, replacing the existing items with the new results.

I'm baffled, and the documentation is terribly unclear. I don't know if I should replace the entire control, or delete items and then add new ones. I don't know if I need to instantiate a new ListBox control, or render it to HTML, etc.

Basically, I have access to the original rendered ListBox (name: "module"} with

win.find('#module');

I have the new values from the AJAX request:

var data = tinymce.util.JSON.parse(text).data;

And I've tried creating a new Control configuration object, like

newCtrlconfig = {
    type: 'listbox',
    label: 'Class',
    values: data
};

but I wouldn't know how to render it, much less have it replace the existing one.

I tried

var newList = tinymce.ui.Factory.create(newCtrlconfig);

and then

newList.renderHtml()

but even then, the rendered HTML did not contain any markup for the items. And examining these objects is just frustrating: there are "settings", "values", "_values", "items" all of which will happily store my values, but it isn't even clear which of them will work.

Since it's a ListBox and not a simple SELECT menu, I can't even easily use the DOM to manipulate the values.

Has anyone conquered the TinyMCE ListBox in 4.x?

Answer

Moeri picture Moeri · Nov 8, 2013

I found this on the TinyMCE forum and I have confirmed that it works:

tinymce.PluginManager.add('myexample', function(editor, url) {
   var self = this, button;

   function getValues() {
      return editor.settings.myKeyValueList;
   }
   // Add a button that opens a window
   editor.addButton('myexample', {
      type: 'listbox',
      text: 'My Example',
      values: getValues(),
      onselect: function() {
         //insert key
         editor.insertContent(this.value());

         //reset selected value
         this.value(null);
      },
      onPostRender: function() {
         //this is a hack to get button refrence.
         //there may be a better way to do this
         button = this;
      },
   });

   self.refresh = function() {
      //remove existing menu if it is already rendered
      if(button.menu){
         button.menu.remove();
         button.menu = null;
      }

      button.settings.values = button.settings.menu = getValues();
   };
});


Call following code block from ajax success method
//Set new values to myKeyValueList 
tinyMCE.activeEditor.settings.myKeyValueList = [{text: 'newtext', value: 'newvalue'}];
//Call plugin method to reload the dropdown
tinyMCE.activeEditor.plugins.myexample.refresh();

The key here is that you need to do the following:

  1. Get the 'button' reference by taking it from 'this' in the onPostRender method
  2. Update the button.settings.values and button.settings.menu with the values you want
  3. To update the existing list, call button.menu.remove() and button.menu = null