We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 3749
    • 24,544 Posts
    Has anyone succeeded in using multiple instances of TinyMCE in the front end? I’d like to have a different toolbar for different input sections. So far, I can’t get Tiny to come up at all in any div with a class other than modx-richtext. I’ve duplicated the instantiation and property-setting code, and added a new selector, but nothing is working.

    Actually, what I want is a way to let users update an Image TV in the front end (for NewsPublisher), so I need an image browser/uploader. I figured I’d create a TinyMCE window with just the image icon in the toolbar. I’m open to other suggestions -- hopefully ones that don’t require me to write a bunch of JavaScript. wink
      Did I help you? Buy me a beer
      Get my Book: MODX:The Official Guide
      MODX info for everyone: http://bobsguides.com/modx.html
      My MODX Extras
      Bob's Guides is now hosted at A2 MODX Hosting
      • 4172
      • 5,888 Posts
      could get it run with new property on richtext-TV:

      name: rt_class
      example-value: rt_imagetv


      and this mods in newspublisher.class.php:

      in function init():
                         
      <?php
      
                         $this->modx->regClientStartupScript($tiny->config['assetsUrl'].'tiny.browser.js');
                         //mod by Bruno
      		   //Todo: new NP-scriptProperty: rt_configs
                        $rt_configs='[{"selector":"rt_imagetv", "buttons1":"image", "buttons2":"", "theme_advanced_buttons1":"image", "theme_advanced_buttons2":""}]';
                        $rt_configs=$this->modx->fromJson($rt_configs);
                        foreach($rt_configs as $rt_config){
                             $cfg = '';
                             foreach ($rt_config as $cf_key => $cf_value){
                                 $cfg.='Tiny.config.'.$cf_key.' = "'.$cf_value.'";';
                             }
                             $js.=$cfg.' MODx.loadRTE();';	
                         }
      		   $this->modx->regClientStartupHTMLBlock('<script type="text/javascript">
                             Ext.onReady(function() {
      					   MODx.loadRTE();
                             '.$js.'		   
                             });
                         </script>');
      
      


      in function displayTV():

       
      <?php
      
      
                case 'richtext':
                      $replace['[[+npx.rows]]'] = '200';
                      $replace['[[+npx.cols]]'] = '600';
                      if ($this->props['initrte']) {
                          //mod by Bruno
                          $replace['[[+npx.class]]'] = isset($fields['properties']['rt_class']['value'])?$fields['properties']['rt_class']['value']:'modx-richtext';
                      } else {
                          //$this->setError($this->modx->lexicon('np_no_rte') . $fields['name']);
                          $msg = $this->modx->lexicon('np_no_rte');
                          $this->setError($msg . $fields['name']);
                          $this->setFieldError($fields['name'], $msg);
                          $replace['[[+npx.class]]'] = 'textarea';
                      }


        -------------------------------

        you can buy me a beer, if you like MIGX

        http://webcmsolutions.de/migx.html

        Thanks!
        • 3749
        • 24,544 Posts
        Thanks a million, Bruno.

        I’m very close. The TinyMCE editor appears for the TV and I can insert and upload images with it. The image appears in the editor, but it’s not making it into the $_POST array. The $_POST value for the TV is empty.

        I don’t need the parameter or if statements because every image TV will use the editor. I just put the class in the Tpl chunk:

        <div class="rt_imagetv">
        [[+np.error_[[+npx.fieldName]]]]
            <label for="[[+npx.fieldName]]" title="[[+npx.help]]">[[+npx.caption]]: </label>
                <textarea rows="20" cols="60" name="[[+npx.fieldName]]" class="rt_imagetv" id="[[+npx.fieldName]]" type="text">[[+np.[[+npx.fieldName]]]]</textarea>
        </div>


        Except for the ID, this is the same Tpl I use for the content and introtext fields. The $_POST value is set for them, but not for the TV.
          Did I help you? Buy me a beer
          Get my Book: MODX:The Official Guide
          MODX info for everyone: http://bobsguides.com/modx.html
          My MODX Extras
          Bob's Guides is now hosted at A2 MODX Hosting
          • 4172
          • 5,888 Posts
          Mine is working. Also the $_POST is filled correctly.
          The only difference to mine I can see is, you have: type="text" in your textarea-tag
          Don’t know if that matters.
            -------------------------------

            you can buy me a beer, if you like MIGX

            http://webcmsolutions.de/migx.html

            Thanks!
            • 3749
            • 24,544 Posts
            Quote from: Bruno17 at Feb 23, 2011, 12:30 AM

            Mine is working. Also the $_POST is filled correctly.
            The only difference to mine I can see is, you have: type="text" in your textarea-tag
            Don’t know if that matters.

            Hmmm. I took that out, but the $_POST is still empty (even if I just reload the page, the $_POST for that TV exists and is empty and the image is gone). Don’t know what it could be.

            I notice in your code above, that MODx.loadRTE(); appears twice. Is that intentional?
              Did I help you? Buy me a beer
              Get my Book: MODX:The Official Guide
              MODX info for everyone: http://bobsguides.com/modx.html
              My MODX Extras
              Bob's Guides is now hosted at A2 MODX Hosting
              • 4172
              • 5,888 Posts
              you need to init tinyMCE with different configs to different selectors.

              My code takes the configs and selector from $rt_configs in JSON-format and overrides the js-Tiny-object with them before it inits the next tiny-instance.
              So you can have multiple tiny-instances with different configs for each selector (class).

              MODx.loadRTE() gets the configs from this Tiny-object into the var s and runs tinyMCE.init(s); for each config and selector.
                -------------------------------

                you can buy me a beer, if you like MIGX

                http://webcmsolutions.de/migx.html

                Thanks!
                • 3749
                • 24,544 Posts
                Could you post the whole init() method? I probably have some of your code in the wrong place.
                  Did I help you? Buy me a beer
                  Get my Book: MODX:The Official Guide
                  MODX info for everyone: http://bobsguides.com/modx.html
                  My MODX Extras
                  Bob's Guides is now hosted at A2 MODX Hosting
                  • 4172
                  • 5,888 Posts
                  here is the complete init() method:

                  <?php
                  
                          public function init($context) {
                  
                              switch ($context) {
                                  case 'mgr':
                                      break;
                                  case 'web':
                                  default:
                                      $language = !empty($this->props['language'])
                                              ? $this->props['language'] . ':' : '';
                                      $this->modx->lexicon->load($language . 'newspublisher:default');
                                      break;
                              }
                              $this->prefix =  empty($this->props['prefix']) ? 'np' : $this->props['prefix'];
                              /* see if we're editing an existing doc */
                              $this->existing = false;
                              if (isset($_POST['np_existing']) && $_POST['np_existing'] == 'true') {
                                  $this->existing = is_numeric($_POST['np_doc_id'])
                                          ? $_POST['np_doc_id'] : false;
                              }
                  
                              /* see if it's a repost */
                              $this->setPostback(isset($_POST['hidSubmit']) && $_POST['hidSubmit'] == 'true');
                  
                              if($this->existing) {
                  
                                  $this->resource = $this->modx->getObject('modResource', $this->existing);
                                  if ($this->resource) {
                  
                                      if (!$this->modx->hasPermission('view_document') || !$this->resource->checkPolicy('view') ) {
                                          $this->setError($this->modx->lexicon('np_view_permission_denied'));
                                      }
                                      if ($this->isPostBack) {
                                          /* str_replace to prevent rendering of placeholders */
                                           $fs = array();
                                           foreach($_POST as $k=>$v) {
                                               $fs[$k] = str_replace(array('[',']'),array('[',']'),$v);
                                           }
                                          $this->modx->toPlaceholders($fs,$this->prefix);
                  
                  
                                      } else {
                                          $ph = $this->resource->toArray();
                                          $tags = false;
                                          foreach($ph as $k=>$v) {
                                              if (strstr($v, '[[')) {
                                                  $tags = true;
                                              }
                                              if ($tags && ! $this->modx->hasPermission('allow_modx_tags')) {
                                                  $this->setError($this->modx->lexicon('np_no_modx_tags'));
                                                  return;
                                              }
                                              $fs[$k] = str_replace(array('[',']'),array('[',']'),$v);
                                          }
                                          $ph = $fs;
                                          $this->modx->toPlaceholders($ph,$this->prefix);
                                          unset($ph);
                                      }
                                  } else {
                                     $this->setError($this->modx->lexicon('np_no_resource') . $this->existing);
                                     return;
                  
                                  }
                                  /* need to forward this from $_POST so we know it's an existing doc */
                                  $stuff = '<input type="hidden" name="np_existing" value="true" />' . "\n" .
                                  '<input type="hidden" name="np_doc_id" value="' . $this->resource->get('id') . '" />';
                                  $this->modx->toPlaceholder('post_stuff',$stuff,$this->prefix);
                  
                              } else {
                                  /* new document */
                                  if (!$this->modx->hasPermission('new_document')) {
                                      $this->setError($this->modx->lexicon('np_create_permission_denied'));
                                  }
                                  $this->resource = $this->modx->newObject('modResource');
                                  /* get folder id where we should store articles
                                   else store under current document */
                                   $this->parentId = !empty($this->props['parent']) ? intval($this->props['parent']):$this->modx->resource->get('id');
                  
                                  /* str_replace to prevent rendering of placeholders */
                                   $fs = array();
                                   foreach($_POST as $k=>$v) {
                                       $fs[$k] = str_replace(array('[',']'),array('[',']'),$v);
                                   }
                                   $this->modx->toPlaceholders($fs,$this->prefix);
                  
                  
                                   $this->aliasTitle = $this->props['aliastitle']? true : false;
                                   $this->clearcache = isset($_POST['clearcache'])? $_POST['clearcache'] : $this->props['clearcache'] ? true: false;
                  
                                   $this->hideMenu = isset($_POST['hidemenu'])? $_POST['hidemenu'] : $this->_setDefault('hidemenu',$this->parentId);
                                   $this->resource->set('hidemenu', $this->hideMenu);
                  
                                   $this->cacheable = isset($_POST['cacheable'])? $_POST['cacheable'] : $this->_setDefault('cacheable',$this->parentId);
                                   $this->resource->set('cacheable', $this->cacheable);
                  
                                   $this->searchable = isset($_POST['searchable'])? $_POST['searchable'] : $this->_setDefault('searchable',$this->parentId);
                                   $this->resource->set('searchable', $this->searchable);
                  
                                   $this->published = isset($_POST['published'])? $_POST['published'] : $this->_setDefault('published',$this->parentId);
                                   $this->resource->set('published', $this->published);
                  
                                   $this->richtext = isset($_POST['richtext'])? $_POST['richtext'] : $this->_setDefault('richtext',$this->parentId);
                                   $this->resource->set('richtext', $this->richtext);
                  
                                   if (! empty($this->props['groups'])) {
                                      $this->groups = $this->_setDefault('groups',$this->parentId);
                                   }
                                   $this->header = !empty($this->props['headertpl']) ? $this->modx->getChunk($this->props['headertpl']) : '';
                                   $this->footer = !empty($this->props['footertpl']) ? $this->modx->getChunk($this->props['footertpl']):'';
                  
                                   $this->intMaxlength = !empty($this->props['intmaxlength'])? $this->props['intmaxlength'] : 10;
                                   $this->textMaxlength = !empty($this->props['textmaxlength'])? $this->props['textmaxlength'] : 60;
                  
                  
                  
                              }
                               if( !empty($this->props['badwords'])) {
                                   $this->badwords = str_replace(' ','', $this->props['badwords']);
                                   $this->badwords = "/".str_replace(',','|', $this->badwords)."/i";
                               }
                  
                             $this->modx->lexicon->load('core:resource');
                             $this->template = $this->_getTemplate();
                             if($this->props['initdatepicker']) {
                                  $this->modx->regClientCSS($this->assetsUrl . 'datepicker/css/datepicker.css');
                                  $this->modx->regClientStartupScript($this->assetsUrl . 'datepicker/js/datepicker.js');
                             }
                  
                             /* inject NP CSS file */
                             /* Empty but sent parameter means use no CSS file at all */
                  
                             if (empty($this->props['cssfile'])) { /* nothing sent - use default */
                                 $css = $this->assetsUrl . 'css/newspublisher.css';
                             } elseif (empty($this->props['cssfile']) ) { /* empty param -- no css file */
                                 $css = false;
                             } else {  /* set but not empty -- use it */
                                 $css = $this->assetsUrl . 'components/newspublisher/css/' . $this->props['cssfile'];
                             }
                  
                             if ($css !== false) {
                                 $this->modx->regClientCSS($css);
                             }
                  
                             $this->listboxMax = $this->props['listboxmax']? $this->props['listboxmax'] : 8;
                             $this->MultipleListboxMax = $this->props['multiplelistboxmax']? $this->props['multiplelistboxmax'] : 8;
                  
                  
                             $ph = ! empty($this->props['contentrows'])? $this->props['contentrows'] : '10';
                             $this->modx->toPlaceholder('contentrows',$ph,$this->prefix);
                  
                             $ph = ! empty($this->props['contentcols'])? $this->props['contentcols'] : '60';
                             $this->modx->toPlaceholder('contentcols',$ph, $this->prefix);
                  
                             $ph = ! empty($this->props['summaryrows'])? $this->props['summaryrows'] : '10';
                             $this->modx->toPlaceholder('summaryrows',$ph, $this->prefix);
                  
                             $ph = ! empty($this->props['summarycols'])? $this->props['summarycols'] : '60';
                             $this->modx->toPlaceholder('summarycols',$ph, $this->prefix);
                  
                             /* do rich text stuff */
                              //$ph = ! empty($this->props['rtcontent']) ? 'MODX_RichTextWidget':'content';
                              $ph = ! empty($this->props['rtcontent']) ? 'modx-richtext':'content';
                              $this->modx->toPlaceholder('rt_content_1', $ph, $this->prefix );
                              $ph = ! empty($this->props['rtcontent']) ? 'modx-richtext':'content';
                              $this->modx->toPlaceholder('rt_content_2', $ph, $this->prefix );
                  
                              /* set rich text summary field */
                  
                              $ph = ! empty($this->props['rtsummary']) ? 'modx-richtext':'introtext';
                              $this->modx->toPlaceholder('rt_summary_1', $ph, $this->prefix );
                              $ph = ! empty($this->props['rtsummary']) ? 'modx-richtext':'introtext';
                              $this->modx->toPlaceholder('rt_summary_2', $ph, $this->prefix );
                  
                              unset($ph);
                             if ($this->props['initrte']) {
                                  /* set rich text content placeholders and includes necessary js files */
                                 $tinyPath = $this->modx->getOption('core_path').'components/tinymce/';
                                 $this->modx->regClientStartupScript($this->modx->getOption('manager_url').'assets/ext3/adapter/ext/ext-base.js');
                                 $this->modx->regClientStartupScript($this->modx->getOption('manager_url').'assets/ext3/ext-all.js');
                                 $this->modx->regClientStartupScript($this->modx->getOption('manager_url').'assets/modext/core/modx.js');
                  
                  
                                 $whichEditor = $this->modx->getOption('which_editor',null,'');
                  
                                 $plugin=$this->modx->getObject('modPlugin',array('name'=>$whichEditor));
                                 if ($whichEditor == 'TinyMCE' ) {
                                     //$tinyUrl = $this->modx->getOption('assets_url').'components/tinymcefe/';
                                      $tinyUrl = $this->modx->getOption('assets_url').'components/tinymce/';
                                     /* OnRichTextEditorInit */
                  
                                     $tinyproperties=$plugin->getProperties();
                                     require_once $tinyPath.'tinymce.class.php';
                                     $tiny = new TinyMCE($this->modx,$tinyproperties,$tinyUrl);
                                     if (isset($this->props['forfrontend']) || $this->modx->isFrontend()) {
                                         $def = $this->modx->getOption('cultureKey',null,$this->modx->getOption('manager_language',null,'en'));
                                         $tinyproperties['language'] = $this->modx->getOption('fe_editor_lang',array(),$def);
                                         $tinyproperties['frontend'] = true;
                                         //$tinyproperties['selector'] = 'modx-richtext';
                                         //$tinyproperties['selector'] = 'modx-richtext';//alternative to 'frontend = true' you can use a selector for texareas
                                         unset($def);
                                     }
                                     $tinyproperties['cleanup'] = true; /* prevents "bogus" bug */
                                     $tinyproperties['width'] = empty ($this->props['tinywidth'] )? '95%' : $this->props['tinywidth'];
                                     $tinyproperties['height'] = empty ($this->props['tinyheight'])? '400px' : $this->props['tinyheight'];
                  
                                     //$tinyproperties['tiny.custom_buttons1'] = 'image';
                  				   //$tinyproperties['tiny.custom_buttons2'] = '';
                  
                                     $tiny->setProperties($tinyproperties);
                  
                                     $html = $tiny->initialize();
                  
                                     $this->modx->regClientStartupScript($tiny->config['assetsUrl'].'jscripts/tiny_mce/langs/'.$tiny->properties['language'].'.js');
                                     $this->modx->regClientStartupScript($tiny->config['assetsUrl'].'tiny.browser.js');
                                     //mod by Bruno
                  				   //Todo: new NP-scriptProperty: rt_configs
                  				   $rt_configs='[{"selector":"rt_imagetv", "buttons1":"image", "buttons2":"", "theme_advanced_buttons1":"image", "theme_advanced_buttons2":""}]';
                  				   $rt_configs=$this->modx->fromJson($rt_configs);
                                     foreach($rt_configs as $rt_config){
                                         $cfg = '';
                                         foreach ($rt_config as $cf_key => $cf_value){
                                             $cfg.='Tiny.config.'.$cf_key.' = "'.$cf_value.'";';
                                         }
                                         $js.=$cfg.' MODx.loadRTE();';	
                                     }
                  				   $this->modx->regClientStartupHTMLBlock('<script type="text/javascript">
                                         Ext.onReady(function() {
                  					   MODx.loadRTE();
                                         '.$js.'		   
                                         });
                                     </script>');
                                 } /* end if ($whichEditor == 'TinyMCE') */
                  
                             } /* end if ($richtext) */
                  
                          } /* end init */
                  
                    -------------------------------

                    you can buy me a beer, if you like MIGX

                    http://webcmsolutions.de/migx.html

                    Thanks!