Re: [Xsltforms-support] custom buttons in TinyMCE (4.3.12) with XSLTForms (638)
Brought to you by:
alain-couthures
From: C. M. Sperberg-M. <cm...@bl...> - 2017-02-06 21:31:21
|
> On Feb 6, 2017, at 1:30 PM, Alain Couthures <ala...@ag...> wrote: > > Customizing TinyMCE with XSLTForms is based on the definition of a data > type with corresponding parameters. > > Please have a look at http://www.agencexml.com/xsltforms/tinymce.xml I have studied it in some detail, thank you! It was where I started my current attempt to use TinyMCE. > <schema xmlns="http://www.w3.org/2001/XMLSchema" > targetNamespace="http://www.agencexml.com/xsltforms/rte"> > <simpleType name="standardHTML"> > <restriction base="xforms:HTMLFragment" xsltforms:rte="TinyMCE"/> > <annotation> > <appinfo> > { > plugins: [ > "advlist autolink lists link image charmap > print preview anchor", > "searchreplace visualblocks code fullscreen", > "insertdatetime media table contextmenu paste" > ], > toolbar: "insertfile undo redo | styleselect | bold > italic | alignleft aligncenter alignright alignjustify | bullist numlist > outdent indent | link image" > } > </appinfo> > </annotation> > </simpleType> > </schema> > … > As you can guess, the appinfo content is copied with the following > instruction in the initInput method: eval("initinfo = " + (type.appinfo > ? type.appinfo.replace(/(\r\n|\n|\r)/gm, " ") : "{}")); > > Is it what you are looking for? Thank you for your feedback! It’s close, but the problem is that it does not quite do what I need. Consider the following appinfo element: <xsd:appinfo> { /* These customizations all work as expected … */ plugins: [ "code" ], toolbar: 'undo redo | insertperson insertprocedure italic | bullist', content_css: 'test-mce.css', custom_elements: "charge,~person,~procedure,en", valid_elements: "charge,p,i,person[pid],procedure[pid],en”, /* The following customization does not work as expected */ setup: function(editor) { function insertPerson () { insertElem('person'); } function insertProc () { insertElem('procedure'); } function insertElem(gi) { var s = '&lt;' + gi + '>' + editor.selection.getContent() + '&lt;/' + gi + '>'; editor.insertContent(s); } editor.addButton('insertperson', { text: "Person", onclick: insertPerson, tooltip: "Insert person element" }); editor.addButton('insertprocedure', { text: "Procedure", onclick: insertProc, tooltip: "Insert procedure element" }); } }</xsd:appinfo> This appinfo defines an object to be passed to the TinyMCE init() function; it customizes the selection of plugins, adjusts the toolbar, gives a stylesheet for elements within the TinyMCE editor, and declares a few custom elements, using the properties ‘plugins’, ’toolbar’, etc. These properties all work here in the same way as they do when TinyMCE is used directly (without XSLTForms). But the appinfo above also attempts to customize the editor by providing a ’setup’ property, whose value is a function. TinyMCE calls the setup() function during initialization, passing the editor object as an argument, so the setup function can do things like adding buttons (as shown above). The setup() function shown above has the expected effect (it adds buttons labeled ‘Person’ and ‘Procedure’ to the toolbar) in a native TinyMCE example [1]. But it does not have the desired effect with XSLTForms 638 [2], because the function XsltForms_input.prototype.initInput overwrites the ‘setup’ property with a different function. The user-specified ‘setup’ function is lost. [1] http://tlrr.blackmesatech.com/2017/02/tests/tinymce.xhtml [2] http://tlrr.blackmesatech.com/2017/02/tests/xsltforms.xhtml If the user’s appinfo element cannot specify a setup() function, then (as far as I can tell from the TinyMCE documentation) the user cannot add custom buttons to the editor. The code changes shown below illustrate one possible modification to xsltforms.js, to allow the user to specify setup code. We want to execute both the user’s setup code and XSLTForms’ setup code (which sets functions for events KeyUp, Change, Undo, and Redo). So we make the setup() function we supply to TinyMCE call a user callback function (placed in property Xsltforms_usersetup) and then run the XSLTForms setup code. For TinyMCE 4.*.*, the setup() function will look like this: initinfo.setup = function(ed) { initinfo.Xsltforms_usersetup(ed); ed.on("KeyUp", function() { XsltForms_control.getXFElement(document.getElementById(this.id)).valueChanged(this.getContent() || ""); }); ed.on("Change", function(ed) { XsltForms_control.getXFElement(document.getElementById(this.id)).valueChanged(ed.target.getContent() || ""); }); ed.on("Undo", function(ed) { XsltForms_control.getXFElement(document.getElementById(this.id)).valueChanged(ed.target.getContent() || ""); }); ed.on("Redo", function(ed) { XsltForms_control.getXFElement(document.getElementById(this.id)).valueChanged(ed.target.getContent() || ""); }); }; The only change here vis-a-vis XSLTForms 638 is the insertion of the first line: initinfo.Xsltforms_usersetup(ed); If the user supplies a function as the value of property Xsltforms_usersetup, then it's executed when setup() is executed. Otherwise, we need to supply a default function. So before the setup() function is defined, we insert the assignment initinfo.Xsltforms_usersetup = (initinfo.Xsltforms_usersetup ? initinfo.Xsltforms_usersetup : function (ed) {} ); So that if the user does NOT supply a value for the property, a vacuous function is called instead. There may be better ways to allow the user to specify code to be executed at setup time, and if you find one I'll be happy. I have modified xsltforms.js (version 638) on my server in the way described above (and below), and can confirm that the resulting form functions as expected [3], provided that in the appinfo element the property name ‘setup’ is replaced by the name ‘Xsltforms_usersetup’. [3] http://tlrr.blackmesatech.com/2017/02/tests/xsltforms.userexit.xhtml I hope this helps clarify my proposal. —Michael p.s. Working through the code again now, it occurs to me that it might be less surprising for users if the user’s appinfo element could use the name ‘setup’ instead of a different name. Then the user who reads the description of setup() in the TinyMCE documentation would not have to learn a different name for it. If after the line 'initinfo.mode = "none”;’ the default user exit were defined not as shown above but in the following way, the user could suppy a ‘setup’ property and things would work as the user might expect. initinfo.Xsltforms_usersetup = (initinfo.setup ? initinfo.setup : function (ed) {} ); > > --Alain > > Le 2/6/2017 à 8:18 PM, C. M. Sperberg-McQueen a écrit : >>> On Feb 6, 2017, at 9:15 AM, C. M. Sperberg-McQueen <cm...@bl...> wrote: >>> >>> >>>> On Feb 5, 2017, at 2:38 PM, C. M. Sperberg-McQueen <cm...@bl...> wrote: >>>> >>>> Short description: I don't seem to be having any luck making custom >>>> buttons work with TinyMCE in XSLTForms. Can anyone help? >>> ... >>> It might be cleaner to add a user hook to the default setup() >>> function. That is, if the user supplies a property named (say) >>> ‘Xsltforms_usersetup’ in the TinyMCE initialization object, then >>> the default setup function calls that user-supplied function. >> A preliminary test suggests that this modification will work. >> >> I made the following changes to xsltforms.js, all to the function >> XsltForms_input.prototype.initinput. >> >> 1 After the line reading 'initinfo.mode = “none”;’, I inserted >> >> /* MSM 20170206 add initinfo.Xsltforms_usersetup property to allow user contributions to setup() */ >> initinfo.Xsltforms_usersetup = (initinfo.Xsltforms_usersetup ? initinfo.Xsltforms_usersetup : function (ed) {} ); >> >> 2 In each of the two versions of initinfo.setup I added a call to >> initinfo.xsltforms_usersetup(), so the first lines of the assignment >> read >> >> initinfo.setup = function(ed) { >> /* MSM 20170206 user exit for setup() */ >> initinfo.Xsltforms_usersetup(ed); >> >> In addition, in the XForm itself, I changed the content of >> the xsd:appinfo element for simple type ‘standardHTML’, >> so that instead of supplying a setup property, it supplies >> a property named Xsltforms_usersetup. >> >> The result can be seen at [1]. There is a great deal of room >> for improvement, but the buttons are showing up, and the >> functions associated with them are executing. (I have not >> attempted any thorough testing.) >> >> [1] http://tlrr.blackmesatech.com/2017/02/tests/xsltforms.userexit.xhtml >> >> Alain, is it feasible to integrate this (or a better) way of allowing >> user input to the TinyMCE setup() function in the production version >> of XSLTForms? What do you think? ******************************************** C. M. Sperberg-McQueen Black Mesa Technologies LLC cm...@bl... http://www.blackmesatech.com ******************************************** |