%3 ::xowiki::formfield::richtext::ckeditor4 ::xowiki::formfield::richtext::ckeditor4 initialize js_image_helper pathNames render_input ::xowiki::formfield::richtext ::xowiki::formfield::richtext check=safe_html editor initialize pretty_value render_richtext_as_div ::xowiki::formfield::richtext::ckeditor4->::xowiki::formfield::richtext ::xowiki::formfield::richtext::wym ::xowiki::formfield::richtext::wym initialize render_input ::xowiki::formfield::richtext::wym->::xowiki::formfield::richtext ::xowiki::formfield::richtext::xinha ::xowiki::formfield::richtext::xinha initialize render_input ::xowiki::formfield::richtext::xinha->::xowiki::formfield::richtext ::xowiki::formfield::form ::xowiki::formfield::form check=form initialize ::xowiki::formfield::form->::xowiki::formfield::richtext ::xowiki::formfield::localized_richtext ::xowiki::formfield::localized_richtext ::xowiki::formfield::localized_richtext->::xowiki::formfield::richtext ::xowiki::formfield::localized_text ::xowiki::formfield::localized_text ::xowiki::formfield::localized_richtext->::xowiki::formfield::localized_text ::xowiki::formfield::textarea ::xowiki::formfield::textarea add_statistics clear_editor_mixins initialize render_input set_feedback ::xowiki::formfield::richtext->::xowiki::formfield::textarea ::xowiki::formfield::FormField ::xowiki::formfield::FormField ::xowiki::formfield::textarea->::xowiki::formfield::FormField

Class ::xowiki::formfield::richtext::ckeditor4

::xowiki::formfield::richtext::ckeditor4[i] create ... \
           [ -CSSclass (default "xowiki-ckeditor") ] \
           [ -CSSclass (default "xowiki-ckeditor") ] \
           [ -additionalConfigOptions (default "") ] \
           [ -allowedContent (default "") ] \
           [ -callback (default "/* callback code */") ] \
           [ -ck_package (default "standard") ] \
           [ -contentsCss (default "/resources/xowiki/ck_contents.css") ] \
           [ -customConfig (default "config.js") ] \
           [ -destroy_callback (default "/* callback code */") ] \
           [ -extraAllowedContent (default "*(*)") ] \
           [ -extraPlugins (default "") ] \
           [ -imageSelectorDialog (default "/xowiki/ckeditor-images/") ] \
           [ -mode (default "wysiwyg") ] \
           [ -skin (default "bootstrapck,/resources/xowiki/ckeditor4/skins/bootstrapck/") ] \
           [ -submit_callback (default "") ] \
           [ -templates (default "") ] \
           [ -templatesFiles (default "") ] \
           [ -toolbar (default "Full") ] \
           [ -uiColor (default "") ]

Class Relations

  • class: ::xotcl::Class[i]
  • superclass: ::xowiki::formfield::richtext[i]
::xotcl::Class create ::xowiki::formfield::richtext::ckeditor4 \
     -superclass ::xowiki::formfield::richtext

Methods (to be applied on instances)

  • CSSclass (setter)

  • additionalConfigOptions (setter)

  • allowedContent (setter)

  • callback (setter)

  • ck_package (setter)

  • contentsCss (setter)

  • customConfig (setter)

  • destroy_callback (setter)

  • extraAllowedContent (setter)

  • extraPlugins (setter)

  • imageSelectorDialog (setter)

  • initialize (scripted)

    switch -- ${:displayMode} {
      inplace { append :help_text " #xowiki.ckeip_help#" }
    }
    next
    set :widget_type richtext
    # Mangle the id to make it compatible with jQuery; most probably
    # not optimal and just a temporary solution
    regsub -all -- {[.:-]} ${:id} "" id
    :id $id
  • js_image_helper (scripted)

    set path [${:object} pretty_link]
    append js  [subst -novariables {
          function xowiki_image_callback(editor) {
            if (typeof editor != "undefined") {
              $(editor.element.$.form).submit(function(e) {
                calc_image_tags_to_wiki_image_links(this);
              });
              editor.setData(calc_wiki_image_links_to_image_tags('[set path]',editor.getData()));
            }
          }
        }] {
          function calc_image_tags_to_wiki_image_links(form) {
            var calc = function() {
              var wiki_link = $(this).attr('alt');
              $(this).replaceWith('[['+wiki_link+']]');
            }
            $(form).find('iframe').each(function() {
              $(this).contents().find('img[type="wikilink"]').each(calc);
            });
    
            $(form).find('textarea.ckeip').each(function() {
              var contents = $('<div>'+this.value+'</div>');
              contents.find('img[type="wikilink"]').each(calc);
              this.value = contents.html();
            });
            return true;
          }
    
          function calc_image_tags_to_wiki_image_links_inline(e) {
            var data = $('<div>'+CKEDITOR.instances[e].getData()+'</div>');
            data.find('img[type="wikilink"]').each( function() {
              var wiki_link = $(this).attr('alt');
              $(this).replaceWith('[['+wiki_link+']]');
            });
            CKEDITOR.instances[e].setData(data.html());
            CKEDITOR.instances[e].updateElement();
          }
    
          function calc_wiki_image_links_to_image_tags(path, text) {
            // console.log('path = <' + path + '>');
            var regex_wikilink = new RegExp('(\\[\\[.SELF./image:)(.*?)(\\]\\])', 'g');
            text = text.replace(regex_wikilink,'<img src="'+path+'/file:$2?m=download"  alt=".SELF./image:$2" type="wikilink"  />');
            return text;
          }
        }
    ::xo::Page requireJS $js
  • mode (setter)

  • pathNames (scripted)

    set result [list]
    foreach fn $fileNames {
      if {[regexp {^[./]} $fn]} {
        append result $fn
      } else {
        append result "/resources/xowiki/$fn"
      }
    }
    return $result
  • render_input (scripted)

    set disabled [:is_disabled]
    set is_repeat_template [:is_repeat_template_p]
    
    # :msg "${:id} ${:name} - $is_repeat_template"
    
    if {$is_repeat_template} {
      set :data-repeat-template-id ${:id}
    }
    
    # if value is empty, we need something to be clickable for display mode inplace
    if {[:value] eq "" && ${:displayMode} eq "inplace"} {
      :value "&nbsp;"
    }
    
    if {![:istype ::xowiki::formfield::richtext] || ($disabled && !$is_repeat_template)} {
      :render_richtext_as_div
    } else {
    
      template::head::add_javascript -src urn:ad:js:jquery
      try {
        #
        # Try to use the ckeditor from the richtext-ckeditor4
        # installation.
        #
        # There seems to be something broken on 4.9.2 version on the
        # CDN. If we do not use standard-all, then we see an error
        # about a missing
        # ".../4.9.2/full/plugins/iframedialog/plugin.js". There
        # exists a default "iframe" and a "iframedialog" plugin for
        # ckeditor4, the latter is not included in the standard builds
        # (only in "-all").
        #
        # UPDATE July 2021: The "*-all" ckpackages are gone for newer
        # versions of CKEditor (e.g. 4.16.*) and it is unlikely that
        # it will be revived for the standard packages. One can
        # download the "iframedialog" plugin still from the addons
        #
        #    https://ckeditor.com/cke4/addon/iframedialog
        #
        # and add it manually to the downloaded tree in e.g.
        #
        #   richtext-ckeditor4/www/resources/4.16.1/standard/plugins/
        #
        # For the time being, we remove the "xowikiimage" plugin from
        # the extraPlugins to make it working out of the box. This
        # plugin should be rewritten using the current dialogs of
        # ckeditor.
        #
        ::richtext::ckeditor4::add_editor  -order 90  -ck_package ${:ck_package}  -adapters "jquery.js"
    
      } trap {TCL LOOKUP COMMAND} {errorMsg} {
        #
        # If for whatever reason, richtext-ckeditor4 is not available,
        # bail out and tell the user to install.
        #
    
        error "Please install the package: richtext-ckeditor4"
      }
    
      #
      # In contrary to the documentation, ckeditor4 names instances
      # after the id, not the name.
      #
      set id ${:id}
      set name ${:name}
      set package_id [${:object} package_id]
    
      # Earlier versions required the plugin "sourcedialog" in
      # "inline" mode. Not sure why. This plugin was removed from
      # CKEditor.
      #if {${:displayMode} eq "inline"} {
      #  lappend :extraPlugins sourcedialog
      #}
    
      if {"xowikiimage" in ${:extraPlugins}} {
        :js_image_helper
        set ready_callback "xowiki_image_callback(CKEDITOR.instances\['$id'\]);"
        set ready_callback2 {xowiki_image_callback(e.editor);}
      } else {
        set ready_callback "/*none*/;"
        set ready_callback2 $ready_callback
        set submit_callback "/*none*/;"
      }
    
      #
      # Append dimensions (when available) in JSON notation.
      #
      set dimensions {}
      if {[info exists :height]} {
        lappend dimensions [subst {"height""${:height}"}]
      }
      if {[info exists :width]} {
        lappend dimensions [subst {"width""${:width}"}]
      }
      if {[llength $dimensions] > 0} {
        set dimensions [join $dimensions ,],
      }
    
      set options [subst {
        $dimensions
        ${:additionalConfigOptions}
        toolbar : '${:toolbar}',
        uiColor: '${:uiColor}',
        language: '[::xo::cc lang]',
        skin: '${:skin}',
        startupMode: '${:mode}',
        disableNativeSpellChecker: false,
        parent_id: '[${:object} item_id]',
        package_url: '[::$package_id package_url]',
        extraPlugins: '[join ${:extraPlugins} ,]',
        extraAllowedContent: '${:extraAllowedContent}',
        contentsCss: '${:contentsCss}',
        imageSelectorDialog: '[:imageSelectorDialog]?parent_id=[${:object} item_id]',
        ready_callback: '$ready_callback2',
        customConfig: '${:customConfig}',
        textarea_id: id
      }]
      if {${:allowedContent} ne ""} {
        #
        # Syntax rules:
        # https://ckeditor.com/docs/ckeditor4/latest/guide/dev_allowed_content_rules.html#string-format
        #
        if {${:allowedContent} in {true false}} {
          append options "  , allowedContent: ${:allowedContent}\n"
        } else {
          append options "  , allowedContent: '${:allowedContent}'\n"
        }
      }
      if {${:templatesFiles} ne ""} {
        append options "  , templates_files: \['[join [:pathNames ${:templatesFiles}] ',' ]' \]\n"
      }
      if {${:templates} ne ""} {
        append options "  , templates: '${:templates}'\n"
      }
    
      #set parent [[${:object} package_id] get_page_from_item_or_revision_id [${:object} parent_id]];# ???
    
      if {${:displayMode} eq "inplace"} {
    
        lappend :CSSclass ckeip
        ::xo::Page requireJS "/resources/xowiki/ckeip.js"
    
        ::xo::Page requireJS [subst -nocommands {
          function load_$id (id) {
            // must use id provided as argument
            \$('#' + id).ckeip(function() { ${:callback}}, {
              name: '$name',
              ckeditor_config: {
                $options,
                destroy_callback: function() { ${:destroy_callback} }
              }
            });
          }
        }]
        if {!$is_repeat_template} {
          ::xo::Page requireJS [subst -nocommands {
            \$(document).ready(function() {
              CKEDITOR.plugins.addExternal( 'xowikiimage', '/resources/xowiki/ckeditor4/plugins/xowikiimage/', 'plugin.js' );
              if (\$('#$id').parents('.repeatable').length != 0) {
                if (\$('#$id').is(':visible')) {
                  load_$id ('$id');
                }
              } else {
                //this is not inside a repeatable container, load normally
                load_$id ('$id');
              }
            } );
          }]
        }
        :render_richtext_as_div
      } elseif {${:displayMode} eq "inline"} {
        if {"xowikiimage" in ${:extraPlugins}} {
          set ready_callback "xowiki_image_callback(CKEDITOR.instances\['$id'\]);"
          set submit_callback "calc_image_tags_to_wiki_image_links_inline('$id');"
        }
    
        set submit_callback "$submit_callback ${:submit_callback}"
        ::xo::Page requireJS [subst {
          function load_$id (id) {
            CKEDITOR.inline(id, {
              on: {
                instanceReady: function(e) {
                  \$(e.editor.element.\$).attr('title', '${:label}');
                  \$(e.editor.element.\$.form).submit(function(e) {
                    $submit_callback
                  });
                }
              },
              $options
            });
          }
        }]
        if {!$is_repeat_template} {
          ::xo::Page requireJS [subst {
            \$(document).ready(function() {
              CKEDITOR.plugins.addExternal( 'xowikiimage', '/resources/xowiki/ckeditor4/plugins/xowikiimage/', 'plugin.js' );
              if (\$('#$id').parents('.repeatable').length != 0) {
                if (\$('#$id').is(':visible')) {
                  load_$id ('$id');
                }
              } else {
                //this is not inside a repeatable container, load normally
                load_$id ('$id');
              }
              $ready_callback
            });
          }]
        }
        next
      } else {
        ::xo::Page requireJS [subst -nocommands {
          function load_$id (id) {
            // must use id provided as argument
            \$('#' + id).ckeditor(function() { ${:callback} }, {$options});
          }
        }]
        if {!$is_repeat_template} {
          ::xo::Page requireJS [subst -nocommands {
            \$(document).ready(function() {
              CKEDITOR.plugins.addExternal( 'xowikiimage', '/resources/xowiki/ckeditor4/plugins/xowikiimage/', 'plugin.js' );
              load_$id ('$id');
              $ready_callback
              //CKEDITOR.instances['$id'].on('instanceReady',function(e) {$ready_callback});
            });
          }]
        }
        next
      }
    }
  • skin (setter)

  • submit_callback (setter)

  • templates (setter)

  • templatesFiles (setter)

  • toolbar (setter)

  • uiColor (setter)