[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/plugins/editors/tinymce/src/PluginTraits/ -> DisplayTrait.php (source)

   1  <?php
   2  
   3  /**
   4   * @package     Joomla.Plugin
   5   * @subpackage  Editors.tinymce
   6   *
   7   * @copyright   (C) 2021 Open Source Matters, Inc. <https://www.joomla.org>
   8   * @license     GNU General Public License version 2 or later; see LICENSE.txt
   9   */
  10  
  11  namespace Joomla\Plugin\Editors\TinyMCE\PluginTraits;
  12  
  13  use Joomla\CMS\Filesystem\Folder;
  14  use Joomla\CMS\Filter\InputFilter;
  15  use Joomla\CMS\HTML\HTMLHelper;
  16  use Joomla\CMS\Language\Text;
  17  use Joomla\CMS\Layout\LayoutHelper;
  18  use Joomla\CMS\Session\Session;
  19  use Joomla\CMS\Uri\Uri;
  20  use Joomla\Registry\Registry;
  21  use stdClass;
  22  
  23  // phpcs:disable PSR1.Files.SideEffects
  24  \defined('_JEXEC') or die;
  25  // phpcs:enable PSR1.Files.SideEffects
  26  
  27  /**
  28   * Handles the onDisplay event for the TinyMCE editor.
  29   *
  30   * @since  4.1.0
  31   */
  32  trait DisplayTrait
  33  {
  34      use GlobalFilters;
  35      use KnownButtons;
  36      use ResolveFiles;
  37      use ToolbarPresets;
  38      use XTDButtons;
  39  
  40      /**
  41       * Display the editor area.
  42       *
  43       * @param   string   $name     The name of the editor area.
  44       * @param   string   $content  The content of the field.
  45       * @param   string   $width    The width of the editor area.
  46       * @param   string   $height   The height of the editor area.
  47       * @param   int      $col      The number of columns for the editor area.
  48       * @param   int      $row      The number of rows for the editor area.
  49       * @param   boolean  $buttons  True and the editor buttons will be displayed.
  50       * @param   string   $id       An optional ID for the textarea. If not supplied the name is used.
  51       * @param   string   $asset    The object asset
  52       * @param   object   $author   The author.
  53       * @param   array    $params   Associative array of editor parameters.
  54       *
  55       * @return  string
  56       */
  57      public function onDisplay(
  58          $name,
  59          $content,
  60          $width,
  61          $height,
  62          $col,
  63          $row,
  64          $buttons = true,
  65          $id = null,
  66          $asset = null,
  67          $author = null,
  68          $params = []
  69      ) {
  70          $id              = empty($id) ? $name : $id;
  71          $user            = $this->app->getIdentity();
  72          $language        = $this->app->getLanguage();
  73          $doc             = $this->app->getDocument();
  74          $id              = preg_replace('/(\s|[^A-Za-z0-9_])+/', '_', $id);
  75          $nameGroup       = explode('[', preg_replace('/\[\]|\]/', '', $name));
  76          $fieldName       = end($nameGroup);
  77          $scriptOptions   = [];
  78          $externalPlugins = [];
  79          $options         = $doc->getScriptOptions('plg_editor_tinymce');
  80          $theme           = 'silver';
  81  
  82          // Data object for the layout
  83          $textarea           = new stdClass();
  84          $textarea->name     = $name;
  85          $textarea->id       = $id;
  86          $textarea->class    = 'mce_editable joomla-editor-tinymce';
  87          $textarea->cols     = $col;
  88          $textarea->rows     = $row;
  89          $textarea->width    = is_numeric($width) ? $width . 'px' : $width;
  90          $textarea->height   = is_numeric($height) ? $height . 'px' : $height;
  91          $textarea->content  = $content;
  92          $textarea->readonly = !empty($params['readonly']);
  93  
  94          // Render Editor markup
  95          $editor = '<div class="js-editor-tinymce">';
  96          $editor .= LayoutHelper::render('joomla.tinymce.textarea', $textarea);
  97          $editor .= !$this->app->client->mobile ? LayoutHelper::render('joomla.tinymce.togglebutton') : '';
  98          $editor .= '</div>';
  99  
 100          // Prepare the instance specific options
 101          if (empty($options['tinyMCE'][$fieldName])) {
 102              $options['tinyMCE'][$fieldName] = [];
 103          }
 104  
 105          // Width and height
 106          if ($width && empty($options['tinyMCE'][$fieldName]['width'])) {
 107              $options['tinyMCE'][$fieldName]['width'] = $width;
 108          }
 109  
 110          if ($height && empty($options['tinyMCE'][$fieldName]['height'])) {
 111              $options['tinyMCE'][$fieldName]['height'] = $height;
 112          }
 113  
 114          // Set editor to readonly mode
 115          if (!empty($params['readonly'])) {
 116              $options['tinyMCE'][$fieldName]['readonly'] = 1;
 117          }
 118  
 119          // The ext-buttons
 120          if (empty($options['tinyMCE'][$fieldName]['joomlaExtButtons'])) {
 121              $btns = $this->tinyButtons($id, $buttons);
 122  
 123              $options['tinyMCE'][$fieldName]['joomlaMergeDefaults'] = true;
 124              $options['tinyMCE'][$fieldName]['joomlaExtButtons']    = $btns;
 125          }
 126  
 127          $doc->addScriptOptions('plg_editor_tinymce', $options, false);
 128          // Setup Default (common) options for the Editor script
 129  
 130          // Check whether we already have them
 131          if (!empty($options['tinyMCE']['default'])) {
 132              return $editor;
 133          }
 134  
 135          $ugroups  = array_combine($user->getAuthorisedGroups(), $user->getAuthorisedGroups());
 136  
 137          // Prepare the parameters
 138          $levelParams      = new Registry();
 139          $extraOptions     = new stdClass();
 140          $toolbarParams    = new stdClass();
 141          $extraOptionsAll  = (array) $this->params->get('configuration.setoptions', []);
 142          $toolbarParamsAll = (array) $this->params->get('configuration.toolbars', []);
 143  
 144          // Sort the array in reverse, so the items with lowest access level goes first
 145          krsort($extraOptionsAll);
 146  
 147          // Get configuration depend from User group
 148          foreach ($extraOptionsAll as $set => $val) {
 149              $val = (object) $val;
 150              $val->access = empty($val->access) ? [] : $val->access;
 151  
 152              // Check whether User in one of allowed group
 153              foreach ($val->access as $group) {
 154                  if (isset($ugroups[$group])) {
 155                      $extraOptions  = $val;
 156                      $toolbarParams = (object) $toolbarParamsAll[$set];
 157                  }
 158              }
 159          }
 160  
 161          // load external plugins
 162          if (isset($extraOptions->external_plugins) && $extraOptions->external_plugins) {
 163              foreach (json_decode(json_encode($extraOptions->external_plugins), true) as $external) {
 164                  // get the path for readability
 165                  $path = $external['path'];
 166  
 167                  // if we have a name and path, add it to the list
 168                  if ($external['name'] != '' && $path != '') {
 169                      $externalPlugins[$external['name']] = substr($path, 0, 1) == '/' ? Uri::root() . substr($path, 1) : $path;
 170                  }
 171              }
 172          }
 173  
 174          // Merge the params
 175          $levelParams->loadObject($toolbarParams);
 176          $levelParams->loadObject($extraOptions);
 177  
 178          // Set the selected skin
 179          $skin = $levelParams->get($this->app->isClient('administrator') ? 'skin_admin' : 'skin', 'oxide');
 180  
 181          // Check that selected skin exists.
 182          $skin = Folder::exists(JPATH_ROOT . '/media/vendor/tinymce/skins/ui/' . $skin) ? $skin : 'oxide';
 183  
 184          if (!$levelParams->get('lang_mode', 1)) {
 185              // Admin selected language
 186              $langPrefix = $levelParams->get('lang_code', 'en');
 187          } else {
 188              // Reflect the current language
 189              if (file_exists(JPATH_ROOT . '/media/vendor/tinymce/langs/' . $language->getTag() . '.js')) {
 190                  $langPrefix = $language->getTag();
 191              } elseif (file_exists(JPATH_ROOT . '/media/vendor/tinymce/langs/' . substr($language->getTag(), 0, strpos($language->getTag(), '-')) . '.js')) {
 192                  $langPrefix = substr($language->getTag(), 0, strpos($language->getTag(), '-'));
 193              } else {
 194                  $langPrefix = 'en';
 195              }
 196          }
 197  
 198          $use_content_css    = $levelParams->get('content_css', 1);
 199          $content_css_custom = $levelParams->get('content_css_custom', '');
 200          $content_css        = null;
 201  
 202          // Loading of css file for 'styles' dropdown
 203          if ($content_css_custom) {
 204              /**
 205               * If URL, just pass it to $content_css
 206               * else, assume it is a file name in the current template folder
 207               */
 208              $content_css = strpos($content_css_custom, 'http') !== false
 209                  ? $content_css_custom
 210                  : $this->includeRelativeFiles('css', $content_css_custom);
 211          } else {
 212              // Process when use_content_css is Yes and no custom file given
 213              $content_css = $use_content_css ? $this->includeRelativeFiles('css', 'editor' . (JDEBUG ? '' : '.min') . '.css') : $content_css;
 214          }
 215  
 216          $ignore_filter = false;
 217  
 218          // Text filtering
 219          if ($levelParams->get('use_config_textfilters', 0)) {
 220              // Use filters from com_config
 221              $filter            = static::getGlobalFilters($user);
 222              $ignore_filter     = $filter === false;
 223              $blockedTags       = !empty($filter->blockedTags) ? $filter->blockedTags : [];
 224              $blockedAttributes = !empty($filter->blockedAttributes) ? $filter->blockedAttributes : [];
 225              $tagArray          = !empty($filter->tagsArray) ? $filter->tagsArray : [];
 226              $attrArray         = !empty($filter->attrArray) ? $filter->attrArray : [];
 227              $invalid_elements  = implode(',', array_merge($blockedTags, $blockedAttributes, $tagArray, $attrArray));
 228  
 229              // Valid elements are all entries listed as allowed in com_config, which are now missing in the filter blocked properties
 230              $default_filter = InputFilter::getInstance();
 231              $valid_elements = implode(',', array_diff($default_filter->blockedTags, $blockedTags));
 232  
 233              $extended_elements = '';
 234          } else {
 235              // Use filters from TinyMCE params
 236              $invalid_elements  = trim($levelParams->get('invalid_elements', 'script,applet,iframe'));
 237              $extended_elements = trim($levelParams->get('extended_elements', ''));
 238              $valid_elements    = trim($levelParams->get('valid_elements', ''));
 239          }
 240  
 241          // The param is true for vertical resizing only, false or both
 242          $resizing          = (bool) $levelParams->get('resizing', true);
 243          $resize_horizontal = (bool) $levelParams->get('resize_horizontal', true);
 244  
 245          if ($resizing && $resize_horizontal) {
 246              $resizing = 'both';
 247          }
 248  
 249          // Set of always available plugins
 250          $plugins  = [
 251              'autolink',
 252              'lists',
 253              'importcss',
 254              'quickbars',
 255          ];
 256  
 257          // Allowed elements
 258          $elements = [
 259              'hr[id|title|alt|class|width|size|noshade]',
 260          ];
 261          $elements = $extended_elements ? array_merge($elements, explode(',', $extended_elements)) : $elements;
 262  
 263          // Prepare the toolbar/menubar
 264          $knownButtons = static::getKnownButtons();
 265  
 266          // Check if there no value at all
 267          if (!$levelParams->get('menu') && !$levelParams->get('toolbar1') && !$levelParams->get('toolbar2')) {
 268              // Get from preset
 269              $presets = static::getToolbarPreset();
 270  
 271              /**
 272               * Predefine group as:
 273               * Set 0: for Administrator, Editor, Super Users (4,7,8)
 274               * Set 1: for Registered, Manager (2,6), all else are public
 275               */
 276              switch (true) {
 277                  case isset($ugroups[4]) || isset($ugroups[7]) || isset($ugroups[8]):
 278                      $preset = $presets['advanced'];
 279                      break;
 280  
 281                  case isset($ugroups[2]) || isset($ugroups[6]):
 282                      $preset = $presets['medium'];
 283                      break;
 284  
 285                  default:
 286                      $preset = $presets['simple'];
 287              }
 288  
 289              $levelParams->loadArray($preset);
 290          }
 291  
 292          $menubar  = (array) $levelParams->get('menu', []);
 293          $toolbar1 = (array) $levelParams->get('toolbar1', []);
 294          $toolbar2 = (array) $levelParams->get('toolbar2', []);
 295  
 296          // Make an easy way to check which button is enabled
 297          $allButtons = array_merge($toolbar1, $toolbar2);
 298          $allButtons = array_combine($allButtons, $allButtons);
 299  
 300          // Check for button-specific plugins
 301          foreach ($allButtons as $btnName) {
 302              if (!empty($knownButtons[$btnName]['plugin'])) {
 303                  $plugins[] = $knownButtons[$btnName]['plugin'];
 304              }
 305          }
 306  
 307          // Template
 308          $templates = [];
 309  
 310          if (!empty($allButtons['template'])) {
 311              // Do we have a custom content_template_path
 312              $template_path = $levelParams->get('content_template_path');
 313              $template_path = $template_path ? '/templates/' . $template_path : '/media/vendor/tinymce/templates';
 314  
 315              $filepaths = Folder::exists(JPATH_ROOT . $template_path)
 316                  ? Folder::files(JPATH_ROOT . $template_path, '\.(html|txt)$', false, true)
 317                  : [];
 318  
 319              foreach ($filepaths as $filepath) {
 320                  $fileinfo      = pathinfo($filepath);
 321                  $filename      = $fileinfo['filename'];
 322                  $full_filename = $fileinfo['basename'];
 323  
 324                  if ($filename === 'index') {
 325                      continue;
 326                  }
 327  
 328                  $title       = $filename;
 329                  $title_upper = strtoupper($filename);
 330                  $description = ' ';
 331  
 332                  if ($language->hasKey('PLG_TINY_TEMPLATE_' . $title_upper . '_TITLE')) {
 333                      $title = Text::_('PLG_TINY_TEMPLATE_' . $title_upper . '_TITLE');
 334                  }
 335  
 336                  if ($language->hasKey('PLG_TINY_TEMPLATE_' . $title_upper . '_DESC')) {
 337                      $description = Text::_('PLG_TINY_TEMPLATE_' . $title_upper . '_DESC');
 338                  }
 339  
 340                  $templates[] = [
 341                      'title'       => $title,
 342                      'description' => $description,
 343                      'url'         => Uri::root(true) . $template_path . '/' . $full_filename,
 344                  ];
 345              }
 346          }
 347  
 348          // Check for extra plugins, from the setoptions form
 349          foreach (['wordcount' => 1, 'advlist' => 1, 'autosave' => 1, 'textpattern' => 0] as $pName => $def) {
 350              if ($levelParams->get($pName, $def)) {
 351                  $plugins[] = $pName;
 352              }
 353          }
 354  
 355          // Use CodeMirror in the code view instead of plain text to provide syntax highlighting
 356          if ($levelParams->get('sourcecode', 1)) {
 357              $externalPlugins['highlightPlus'] = HTMLHelper::_('script', 'plg_editors_tinymce/plugins/highlighter/plugin-es5.min.js', ['relative' => true, 'version' => 'auto', 'pathOnly' => true]);
 358          }
 359  
 360          $dragdrop = $levelParams->get('drag_drop', 1);
 361  
 362          if ($dragdrop && $user->authorise('core.create', 'com_media')) {
 363              $externalPlugins['jdragndrop'] = HTMLHelper::_('script', 'plg_editors_tinymce/plugins/dragdrop/plugin.min.js', ['relative' => true, 'version' => 'auto', 'pathOnly' => true]);
 364              $uploadUrl                     = Uri::base(false) . 'index.php?option=com_media&format=json&url=1&task=api.files';
 365              $uploadUrl                     = $this->app->isClient('site') ? htmlentities($uploadUrl, ENT_NOQUOTES, 'UTF-8', false) : $uploadUrl;
 366  
 367              Text::script('PLG_TINY_ERR_UNSUPPORTEDBROWSER');
 368              Text::script('ERROR');
 369              Text::script('PLG_TINY_DND_ADDITIONALDATA');
 370              Text::script('PLG_TINY_DND_ALTTEXT');
 371              Text::script('PLG_TINY_DND_LAZYLOADED');
 372              Text::script('PLG_TINY_DND_EMPTY_ALT');
 373  
 374              $scriptOptions['parentUploadFolder'] = $levelParams->get('path', '');
 375              $scriptOptions['csrfToken']          = Session::getFormToken();
 376              $scriptOptions['uploadUri']          = $uploadUrl;
 377  
 378              // @TODO have a way to select the adapter, similar to $levelParams->get('path', '');
 379              $scriptOptions['comMediaAdapter']    = 'local-images:';
 380          }
 381  
 382          // Convert pt to px in dropdown
 383          $scriptOptions['fontsize_formats'] = '8px 10px 12px 14px 18px 24px 36px';
 384  
 385          // select the languages for the "language of parts" menu
 386          if (isset($extraOptions->content_languages) && $extraOptions->content_languages) {
 387              foreach (json_decode(json_encode($extraOptions->content_languages), true) as $content_language) {
 388                  // if we have a language name and a language code then add to the menu
 389                  if ($content_language['content_language_name'] != '' && $content_language['content_language_code'] != '') {
 390                      $ctemp[] = array('title' => $content_language['content_language_name'], 'code' => $content_language['content_language_code']);
 391                  }
 392              }
 393              $scriptOptions['content_langs'] = array_merge($ctemp);
 394          }
 395  
 396          // User custom plugins and buttons
 397          $custom_plugin = trim($levelParams->get('custom_plugin', ''));
 398          $custom_button = trim($levelParams->get('custom_button', ''));
 399  
 400          if ($custom_plugin) {
 401              $plugins   = array_merge($plugins, explode(strpos($custom_plugin, ',') !== false ? ',' : ' ', $custom_plugin));
 402          }
 403  
 404          if ($custom_button) {
 405              $toolbar1  = array_merge($toolbar1, explode(strpos($custom_button, ',') !== false ? ',' : ' ', $custom_button));
 406          }
 407  
 408          // Merge the two toolbars for backwards compatibility
 409          $toolbar = array_merge($toolbar1, $toolbar2);
 410  
 411          // Build the final options set
 412          $scriptOptions   = array_merge(
 413              $scriptOptions,
 414              [
 415                  'deprecation_warnings' => JDEBUG ? true : false,
 416                  'suffix'   => JDEBUG ? '' : '.min',
 417                  'baseURL'  => Uri::root(true) . '/media/vendor/tinymce',
 418                  'directionality' => $language->isRtl() ? 'rtl' : 'ltr',
 419                  'language' => $langPrefix,
 420                  'autosave_restore_when_empty' => false,
 421                  'skin'     => $skin,
 422                  'theme'    => $theme,
 423                  'schema'   => 'html5',
 424  
 425                  // Toolbars
 426                  'menubar'  => empty($menubar)  ? false : implode(' ', array_unique($menubar)),
 427                  'toolbar' => empty($toolbar) ? null  : 'jxtdbuttons ' . implode(' ', $toolbar),
 428  
 429                  'plugins'  => implode(',', array_unique($plugins)),
 430  
 431                  // Quickbars
 432                  'quickbars_image_toolbar'     => false,
 433                  'quickbars_insert_toolbar'    => false,
 434                  'quickbars_selection_toolbar' => 'bold italic underline | H2 H3 | link blockquote',
 435  
 436                  // Cleanup/Output
 437                  'browser_spellcheck' => true,
 438                  'entity_encoding'    => $levelParams->get('entity_encoding', 'raw'),
 439                  'verify_html'        => !$ignore_filter,
 440                  'paste_as_text'      => (bool) $levelParams->get('paste_as_text', false),
 441  
 442                  'valid_elements'          => $valid_elements,
 443                  'extended_valid_elements' => implode(',', $elements),
 444                  'invalid_elements'        => $invalid_elements,
 445  
 446                  // URL
 447                  'relative_urls'      => (bool) $levelParams->get('relative_urls', true),
 448                  'remove_script_host' => false,
 449  
 450                  // Drag and drop Images always FALSE, reverting this allows for inlining the images
 451                  'paste_data_images'  => false,
 452  
 453                  // Layout
 454                  'content_css'        => $content_css,
 455                  'document_base_url'  => Uri::root(true) . '/',
 456                  'image_caption'      => true,
 457                  'importcss_append'   => true,
 458                  'height'             => $this->params->get('html_height', '550px'),
 459                  'width'              => $this->params->get('html_width', ''),
 460                  'elementpath'        => (bool) $levelParams->get('element_path', true),
 461                  'resize'             => $resizing,
 462                  'templates'          => $templates,
 463                  'external_plugins'   => empty($externalPlugins) ? null  : $externalPlugins,
 464                  'contextmenu'        => (bool) $levelParams->get('contextmenu', true) ? null : false,
 465                  'toolbar_sticky'     => true,
 466                  'toolbar_mode'       => $levelParams->get('toolbar_mode', 'sliding'),
 467  
 468                  // Image plugin options
 469                  'a11y_advanced_options' => true,
 470                  'image_advtab'          => (bool) $levelParams->get('image_advtab', false),
 471                  'image_title'           => true,
 472  
 473                  // Drag and drop specific
 474                  'dndEnabled' => $dragdrop,
 475  
 476                  // Disable TinyMCE Branding
 477                  'branding'   => false,
 478              ]
 479          );
 480  
 481          if ($levelParams->get('newlines')) {
 482              // Break
 483              $scriptOptions['force_br_newlines'] = true;
 484              $scriptOptions['forced_root_block'] = '';
 485          } else {
 486              // Paragraph
 487              $scriptOptions['force_br_newlines'] = false;
 488              $scriptOptions['forced_root_block'] = 'p';
 489          }
 490  
 491          $scriptOptions['rel_list'] = [
 492              ['title' => 'None', 'value' => ''],
 493              ['title' => 'Alternate', 'value' => 'alternate'],
 494              ['title' => 'Author', 'value' => 'author'],
 495              ['title' => 'Bookmark', 'value' => 'bookmark'],
 496              ['title' => 'Help', 'value' => 'help'],
 497              ['title' => 'License', 'value' => 'license'],
 498              ['title' => 'Lightbox', 'value' => 'lightbox'],
 499              ['title' => 'Next', 'value' => 'next'],
 500              ['title' => 'No Follow', 'value' => 'nofollow'],
 501              ['title' => 'No Referrer', 'value' => 'noreferrer'],
 502              ['title' => 'Prefetch', 'value' => 'prefetch'],
 503              ['title' => 'Prev', 'value' => 'prev'],
 504              ['title' => 'Search', 'value' => 'search'],
 505              ['title' => 'Tag', 'value' => 'tag'],
 506          ];
 507  
 508          $scriptOptions['style_formats'] = [
 509              [
 510                  'title' => Text::_('PLG_TINY_MENU_CONTAINER'),
 511                  'items' => [
 512                      ['title' => 'article', 'block' => 'article', 'wrapper' => true, 'merge_siblings' => false],
 513                      ['title' => 'aside', 'block' => 'aside', 'wrapper' => true, 'merge_siblings' => false],
 514                      ['title' => 'section', 'block' => 'section', 'wrapper' => true, 'merge_siblings' => false],
 515                  ],
 516              ],
 517          ];
 518  
 519          $scriptOptions['style_formats_merge'] = true;
 520          $options['tinyMCE']['default']        = $scriptOptions;
 521  
 522          $doc->addScriptOptions('plg_editor_tinymce', $options);
 523  
 524          return $editor;
 525      }
 526  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer