Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically updating a TinyMCE 4 ListBox

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?

like image 947
spud Avatar asked Sep 14 '13 20:09

spud


People also ask

How to upgrade TinyMCE to the latest version?

How to upgrade TinyMCE via TinyMCE Cloud, package manager options, Self-hosted, and custom build options. The procedure for upgrading to the latest version of TinyMCE 5 depends on the deployment type. Upgrading Tiny Cloud. Upgrading TinyMCE Self-hosted using a package manager. Upgrading TinyMCE Self-hosted manually.

How do I move TinyMCE customizations from one directory to another?

Copy customizations to the new tinymce/ directory. Ensure that only custom changes are added the new tinymce/ directory, such as: Delete the existing tinymce/ directory and replace with the new tinymce/. Note: To simplify the upgrade process to future versions of TinyMCE: Host the TinyMCE customizations outside of the tinymce/ directory.

Where are TinyMCE customizations stored?

Customizations for TinyMCE are typically stored in the following directories: Download the latest version of TinyMCE. For the TinyMCE Community Version, download tinymce_<VERSION>.zip from Get TinyMCE - Self-hosted releases, where <VERSION> is the latest version of TinyMCE.

How do I download the TinyMCE Enterprise bundle?

For the TinyMCE Enterprise Version, download the TinyMCE Enterprise Bundle from Tiny Account > Downloads. The downloaded file will be named enterprise_latest.zip. Extract the downloaded .zip file to a temporary location. (If required) Install the latest language packs from Get TinyMCE - Language Packages.


3 Answers

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
like image 90
Moeri Avatar answered Dec 05 '22 04:12

Moeri


I tried the solution from TinyMCE forum, but I found it buggy. For example, when I tried to alter the first ListBox multiple times, only the first time took effect. Also first change to that box right after dialogue popped up didn't take any effect.

But to the solution:

Do not call button.menu.remove();

Also, the "hack" for getting button reference is quite unnecessary. Your job can be done simply using:

var button = win.find("#button")[0]; 

With these modification, my ListBoxes work just right.

Whole dialogue function:

function ShowDialog() {
  var val;
  win = editor.windowManager.open({
          title: 'title',
          body: {type: 'form', 
          items: [
          {type: 'listbox', 
          name: 'categorybox', 
          text: 'pick one', 
          value: 0,
          label: 'Section: ', 
          values: categories,
          onselect: setValuebox(this.value())        
          },
          {type: 'listbox', 
          name: 'valuebox', 
          text:'pick one', 
          value: '',
          label: 'Page: ', 
          values: pagelist[0],
            onselect: function(e) {
              val = this.value();
            }
          }
          ]
        },
                onsubmit: function(e) {
                    //do whatever
                }
            });

      var valbox = win.find("#valuebox")[0]; 

      function setValuebox(i){
      //feel free to call ajax
      valbox.value(null);              
      valbox.menu = null;
      valbox.settings.menu = pagelist[i]; 
      // you can also set a value from pagelist[i]["values"][0]
      }
  }

categories and pagelist are JSONs generated from DB before TinyMCE load. pagelist[category] = data for ListBox for selected category. category=0 means all.

Hope I helped somebody, because I've been struggling this for hours.

like image 24
Vitexikora Avatar answered Dec 05 '22 03:12

Vitexikora


It looks like the tinyMCE version that is included in wordpress 4.3 changed some things, and added a state object that caches the initial menu, so changing the menu is not enough anymore.

One will probably have to update the state object as well. Here is an example of updating the menu with data coming from an ajax request:

editor.addButton('shortcodes', {
        icon: 'icon_shortcodes',
        tooltip: 'Your tooltip',
        type: 'menubutton',
        onPostRender: function() {
            var ctrl = this;
            $.getJSON( ajaxurl , function( menu) {
                // menu is the array containing your menu items
                ctrl.state.data.menu = ctrl.settings.menu = menu;
            });
        }
    });
like image 21
Harris Konstantourakis Avatar answered Dec 05 '22 04:12

Harris Konstantourakis