Called if $type === 'edit_link'
976929
protected function render_edit_link(): string
    {
        if (!\current_user_can(
            $this->post->type()->cap->edit_post,
            $this->post->get()->ID
        )) {
            return '';
        }

        return '<a class="edit-post-link" href="'.
            \get_edit_post_link($this->post->get()->ID).
            '"  itemprop="url">'.\esc_html__('Edit', 'grotto-wp-posts').'</a>';
    }
500940
def choose_type(cls, content_type):
        """"""
        return cls.type_cls.SUBDIR if content_type in cls.subdir_types \
            else cls.type_cls.FILE
187395
@SuppressWarnings("deprecation")
    private boolean isRedirectType(int typeId) {

        try {
            return typeId == OpenCms.getResourceManager().getResourceType(RECOURCE_TYPE_NAME_REDIRECT).getTypeId();
        } catch (Exception e) {
            return false;
        }
    }
1043173
def check_edit_tab(self, tab: str, md_type: str):
        
        # check parameters types
        if not isinstance(tab, str):
            raise TypeError("'tab' expected a str value.")
        else:
            pass
        if not isinstance(md_type, str):
            raise TypeError("'md_type' expected a str value.")
        else:
            pass
        # check parameters values
        if tab not in EDIT_TABS:
            raise ValueError(
                "'{}' isn't a valid edition tab. "
                "Available values: {}".format(tab, " | ".join(EDIT_TABS))
            )
        else:
            pass
        if md_type not in FILTER_TYPES:
            if md_type in FILTER_TYPES.values():
                md_type = self._convert_md_type(md_type)
            else:
                raise ValueError(
                    "'{}' isn't a valid metadata type. "
                    "Available values: {}".format(md_type, " | ".join(FILTER_TYPES))
                )
        else:
            pass
        # check adequation tab/md_type
        if md_type not in EDIT_TABS.get(tab):
            raise ValueError(
                "'{}'  isn't a valid tab for a '{}'' metadata."
                " Only for these types: {}.".format(tab, md_type, EDIT_TABS.get(tab))
            )
        else:
            return True
172212
public function assertEditNodeOfType($type)
    {
        $node = (object) array(
        'type' => $type,
        'title' => "Test $type",
        );
        $saved = $this->nodeCreate($node);

        // Set internal browser on the node edit page.
        $this->getSession()->visit($this->locatePath('/node/' . $saved->nid . '/edit'));

        // Test status.
        $this->assertSession()->statusCodeEquals('200');
    }
56320
public function control($type, $href, $custom = array())
    {
        $s = '';
        switch ($type)
        {
            case 'add':
                $control = array(
                    'image' => Eresus_CMS::getLegacyKernel()->root .
                    'admin/themes/default/img/medium/item-add.png',
                    'title' => strAdd,
                    'alt' => '+',
                );
                break;
            case 'edit':
                $control = array(
                    'image' => Eresus_CMS::getLegacyKernel()->root .
                    'admin/themes/default/img/medium/item-edit.png',
                    'title' => strEdit,
                    'alt' => '&plusmn;',
                );
                break;
            case 'delete':
                $control = array(
                    'image' => Eresus_CMS::getLegacyKernel()->root .
                    'admin/themes/default/img/medium/item-delete.png',
                    'title' => strDelete,
                    'alt' => 'X',
                    'onclick' => 'return askdel(this)',
                );
                break;
            case 'setup':
                $control = array(
                    'image' => Eresus_CMS::getLegacyKernel()->root .
                    'admin/themes/default/img/medium/item-config.png',
                    'title' => strProperties,
                    'alt' => '*',
                );
                break;
            case 'move':
                $control = array(
                    'image' => Eresus_CMS::getLegacyKernel()->root .
                    'admin/themes/default/img/medium/item-move.png',
                    'title' => strMove,
                    'alt' => '-&gt;',
                );
                break;
            case 'position':
                $control = array(
                    'image' => Eresus_CMS::getLegacyKernel()->root .
                    'admin/themes/default/img/medium/move-up.png',
                    'title' => ADM_UP,
                    'alt' => '&uarr;',
                );
                $s = array_pop($href);
                $href = $href[0];
                break;
            case 'position_down':
                $control = array(
                    'image' => Eresus_CMS::getLegacyKernel()->root .
                    'admin/themes/default/img/medium/move-down.png',
                    'title' => ADM_DOWN,
                    'alt' => '&darr;',
                );
                break;
            default:
                $control = array(
                    'image' => '',
                    'title' => '',
                    'alt' => '',
                );
                break;
        }
        foreach ($custom as $key => $value)
        {
            $control[$key] = $value;
        }
        $result = '<a href="'.$href.'"'.(isset($control['onclick'])?' onclick="'.
                $control['onclick'].'"':'').'><img src="'.$control['image'].'" alt="'.$control['alt'].
            '" title="'.$control['title'].'" /></a>';
        if ($type == 'position')
        {
            $result .= ' '.$this->control('position_down', $s, $custom);
        }
        return $result;
    }
834458
function at_type() {
  match(/@type/);
  add_tag("type");
  skip_horiz_white();
  if (look(/\{/)) {
    var tdf = typedef();
    current_tag["type"] = tdf["type"];
    current_tag["optional"] = tdf["optional"] ? true : false;
  }
  else if (look(/\S/)) {
    current_tag["type"] = match(/\S+/);
  }
  skip_white();
}
573643
function remove_type($type=null)
    {
        if (!isset($type)) {
            $this->mime_types = array();
            return;
        }
        $slash_pos = strpos($type, '/');
        if (!$slash_pos) return;

        $type_info = array('last_match'=>false, 'wildcard'=>false, 'type'=>$type);
        if (substr($type, $slash_pos) == '/*') {
            $type_info['wildcard'] = true;
            $type_info['type'] = substr($type, 0, $slash_pos);
        }
        $this->scan(array(&$this, '_remove_type_callback'), $type_info);
    }
589021
public function bindValue(string $param, $value, int $type = null)
    {
        if (is_null($type)) {
            switch (true) {
                case is_int($value):
                    $type = \PDO::PARAM_INT;
                    break;
                case is_bool($value):
                    $type = \PDO::PARAM_BOOL;
                    break;
                case is_null($value):
                    $type = \PDO::PARAM_NULL;
                    break;
                default:
                    $type = \PDO::PARAM_STR;
            }
        }
        
        if (is_array($value)) {
            $value = implode(', ', $value);
        }
        
        $this->stmt->bindValue($param, $value, $type);
    }
778549
function (settings) {
        var self = this, editor = getActiveEditor(), editorSettings = editor.settings;
        var actionCallback, fileBrowserCallback, fileBrowserCallbackTypes;
        var fileType = settings.filetype;

        settings.spellcheck = false;

        fileBrowserCallbackTypes = editorSettings.file_picker_types || editorSettings.file_browser_callback_types;
        if (fileBrowserCallbackTypes) {
          fileBrowserCallbackTypes = Tools.makeMap(fileBrowserCallbackTypes, /[, ]/);
        }

        if (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType]) {
          fileBrowserCallback = editorSettings.file_picker_callback;
          if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
            actionCallback = function () {
              var meta = self.fire('beforecall').meta;

              meta = Tools.extend({ filetype: fileType }, meta);

              // file_picker_callback(callback, currentValue, metaData)
              fileBrowserCallback.call(
                editor,
                function (value, meta) {
                  self.value(value).fire('change', { meta: meta });
                },
                self.value(),
                meta
              );
            };
          } else {
            // Legacy callback: file_picker_callback(id, currentValue, filetype, window)
            fileBrowserCallback = editorSettings.file_browser_callback;
            if (fileBrowserCallback && (!fileBrowserCallbackTypes || fileBrowserCallbackTypes[fileType])) {
              actionCallback = function () {
                fileBrowserCallback(
                  self.getEl('inp').id,
                  self.value(),
                  fileType,
                  window
                );
              };
            }
          }
        }

        if (actionCallback) {
          settings.icon = 'browse';
          settings.onaction = actionCallback;
        }

        self._super(settings);

        setupAutoCompleteHandler(self, editorSettings, editor.getBody(), fileType);
        setupLinkValidatorHandler(self, editorSettings, fileType);
      }
746079
private function checkType(Request $request)
    {
        $type = 'view';
        if ($request->is('*/create')) {
            $type = 'create';
        } elseif ($request->is('*/edit/*') || $request->is('*/update/*')) {
            $type = 'update';
        } elseif ($request->is('*/delete/*')) {
            $type = 'delete';
        } elseif ($request->is('*/store') && $request->isMethod('post')) {
            if ($request->has('id')) {
                $type = 'update';
            } else {
                $type = 'create';
            }
        }
        
        return $type;
    }
42591
protected static function addTypedURL(&$array, $url, $type=null) {
		if( !$type ) {
			$type = self::LINK_TYPE_CUSTOM;
		}
		if( !isset($array[$type]) ) {
			$array[$type] = array();
		}
		$array[$type][] = $url;
	}
1122197
function(rel, href, mimetype) {
            if (_.isObject(rel)) {
                _.each(rel, function(value, name) {
                    this.link(name, value);
                }, this);
                return;
            }

            var mt =  this.$('link[rel="'+rel+'"]');
            if (mt.length === 0) {
                mt =  $("<link>", {}).attr("rel", rel).appendTo(this.$el);
            }
            if (mimetype != null) mt.attr("type", mimetype);
            if (href != null) {
                mt.attr('href', href);
            } else {
                return mt.attr('href');
            }
        }
935049
protected void processLink(Tag tag, String attr, CmsRelationType type) {

        if (tag.getAttribute(attr) == null) {
            return;
        }
        CmsLink link = null;
        switch (m_mode) {
            case PROCESS_LINKS:
                // macros are replaced with links
                link = m_linkTable.getLink(CmsMacroResolver.stripMacro(tag.getAttribute(attr)));
                if (link != null) {
                    // link management check
                    String l = link.getLink(m_cms);
                    if (TAG_PARAM.equals(tag.getTagName())) {
                        // HACK: to distinguish link parameters the link itself has to end with '&' or '?'
                        // another solution should be a kind of macro...
                        if (!l.endsWith(CmsRequestUtil.URL_DELIMITER)
                            && !l.endsWith(CmsRequestUtil.PARAMETER_DELIMITER)) {
                            if (l.indexOf(CmsRequestUtil.URL_DELIMITER) > 0) {
                                l += CmsRequestUtil.PARAMETER_DELIMITER;
                            } else {
                                l += CmsRequestUtil.URL_DELIMITER;
                            }
                        }
                    }
                    // set the real target
                    tag.setAttribute(attr, CmsEncoder.escapeXml(l));
                }
                break;
            case REPLACE_LINKS:
                // links are replaced with macros
                String targetUri = tag.getAttribute(attr);
                if (CmsStringUtil.isNotEmpty(targetUri)) {
                    String internalUri = null;
                    if (!CmsMacroResolver.isMacro(targetUri)) {
                        m_cms.getRequestContext().setAttribute(
                            CmsDefaultLinkSubstitutionHandler.DONT_USE_CURRENT_SITE_FOR_WORKPLACE_REQUESTS,
                            "true");
                        internalUri = OpenCms.getLinkManager().getRootPath(m_cms, targetUri, m_relativePath);
                    }
                    // HACK: to distinguish link parameters the link itself has to end with '&' or '?'
                    // another solution should be a kind of macro...
                    if (!TAG_PARAM.equals(tag.getTagName())
                        || targetUri.endsWith(CmsRequestUtil.URL_DELIMITER)
                        || targetUri.endsWith(CmsRequestUtil.PARAMETER_DELIMITER)) {
                        if (internalUri != null) {
                            internalUri = rewriteUri(internalUri);
                            // this is an internal link
                            link = m_linkTable.addLink(type, internalUri, true);
                            // link management check
                            link.checkConsistency(m_cms);

                            if ("IMG".equals(tag.getTagName()) || TAG_AREA.equals(tag.getTagName())) {
                                // now ensure the image has the "alt" attribute set
                                setAltAttributeFromTitle(tag, internalUri);
                            }
                        } else {
                            // this is an external link
                            link = m_linkTable.addLink(type, targetUri, false);
                        }
                    }
                    if (link != null) {
                        tag.setAttribute(attr, CmsMacroResolver.formatMacro(link.getName()));
                    }
                }
                break;
            default: // empty
        }
    }
211028
function getType (str, typeLinks) {
  if (str in typeLinks) {
    return dom.create('a').class('qm-api-type-link').attr('href', typeLinks[str]).text(str)
  } else {
    return str
  }
}
1140498
function()
		{
			var linkType = this.getContentElement( 'info', 'linkType' ),
					urlField;
			if ( linkType && linkType.getValue() == 'url' )
			{
				urlField = this.getContentElement( 'info', 'url' );
				urlField.select();
			}
		}
983474
function( $textarea, classes, placeholder, toolbar_position, toolbar_buttons, toolbar_submit, label_selectImage,
                                  placeholder_url, placeholder_embed, max_imagesize, filter_imageType, on_imageupload, force_imageupload, video_from_url,
                                  on_keydown, on_keypress, on_keyup, on_autocomplete )
    {
        // Content: Insert link
        var wysiwygeditor_insertLink = function( wysiwygeditor, url )
        {
            if( ! url )
                ;
            else if( wysiwygeditor.getSelectedHTML() )
                wysiwygeditor.insertLink( url );
            else
                wysiwygeditor.insertHTML( '<a href="' + html_encode(url) + '">' + html_encode(url) + '</a>' );
            wysiwygeditor.closePopup().collapseSelection();
        };
        var content_insertlink = function(wysiwygeditor, $modify_link)
        {
            var $inputurl = $('<input type="text" value="">').val( $modify_link ? $modify_link.attr('href') : '' )  // prop('href') does not reflect real value
                                .addClass('wysiwyg-input')
                                .keypress(function(event){
                                    if( event.which != 10 && event.which != 13 )
                                        return ;
                                    if( $modify_link )
                                    {
                                        $modify_link.prop( 'href', $inputurl.val() );
                                        wysiwygeditor.closePopup().collapseSelection();
                                    }
                                    else
                                        wysiwygeditor_insertLink( wysiwygeditor,$inputurl.val() );
                                });
            if( placeholder_url )
                $inputurl.prop( 'placeholder', placeholder_url );
            var $okaybutton = $();
            if( toolbar_submit )
                $okaybutton = toolbar_button(toolbar_submit).click(function(event){
                                    if( $modify_link )
                                    {
                                        $modify_link.prop( 'href', $inputurl.val() );
                                        wysiwygeditor.closePopup().collapseSelection();
                                    }
                                    else
                                        wysiwygeditor_insertLink( wysiwygeditor, $inputurl.val() );
                                    event.stopPropagation();
                                    event.preventDefault();
                                    return false;
                                });
            var $content = $('<div/>').addClass('wysiwyg-toolbar-form')
                                      .prop('unselectable','on');
            $content.append($inputurl).append($okaybutton);
            return $content;
        };

        // Content: Insert image
        var content_insertimage = function(wysiwygeditor)
        {
            // Add image to editor
            var insert_image_wysiwyg = function( url, filename )
            {
                var html = '<img id="wysiwyg-insert-image" src="" alt=""' + (filename ? ' title="'+html_encode(filename)+'"' : '') + '>';
                wysiwygeditor.insertHTML( html ).closePopup().collapseSelection();
                var $image = $('#wysiwyg-insert-image').removeAttr('id');
                if( max_imagesize )
                {
                    $image.css({maxWidth: max_imagesize[0]+'px',
                                maxHeight: max_imagesize[1]+'px'})
                          .load( function() {
                                $image.css({maxWidth: '',
                                            maxHeight: ''});
                                // Resize $image to fit "clip-image"
                                var image_width = $image.width(),
                                    image_height = $image.height();
                                if( image_width > max_imagesize[0] || image_height > max_imagesize[1] )
                                {
                                    if( (image_width/image_height) > (max_imagesize[0]/max_imagesize[1]) )
                                    {
                                        image_height = parseInt(image_height / image_width * max_imagesize[0]);
                                        image_width = max_imagesize[0];
                                    }
                                    else
                                    {
                                        image_width = parseInt(image_width / image_height * max_imagesize[1]);
                                        image_height = max_imagesize[1];
                                    }
                                    $image.prop('width',image_width)
                                          .prop('height',image_height);
                                }
                            });
                }
                $image.prop('src', url);
            };
            // Create popup
            var $content = $('<div/>').addClass('wysiwyg-toolbar-form')
                                      .prop('unselectable','on');
            // Add image via 'Browse...'
            var $fileuploader = null,
                $fileuploader_input = $('<input type="file">')
                                        .css({position: 'absolute',
                                              left: 0,
                                              top: 0,
                                              width: '100%',
                                              height: '100%',
                                              opacity: 0,
                                              cursor: 'pointer'});
            if( ! force_imageupload && window.File && window.FileReader && window.FileList )
            {
                // File-API
                var loadImageFromFile = function( file )
                {
                    // Only process image files
                    if( typeof(filter_imageType) === 'function' && ! filter_imageType(file) )
                        return;
                    else if( ! file.type.match(filter_imageType) )
                        return;
                    var reader = new FileReader();
                    reader.onload = function(event) {
                        var dataurl = event.target.result;
                        insert_image_wysiwyg( dataurl, file.name );
                    };
                    // Read in the image file as a data URL
                    reader.readAsDataURL( file );
                };
                $fileuploader = $fileuploader_input
                                    .prop('draggable','true')
                                    .change(function(event){
                                        var files = event.target.files; // FileList object
                                        for(var i=0; i < files.length; ++i)
                                            loadImageFromFile( files[i] );
                                    })
                                    .on('dragover',function(event){
                                        event.originalEvent.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
                                        event.stopPropagation();
                                        event.preventDefault();
                                        return false;
                                    })
                                    .on('drop', function(event){
                                        var files = event.originalEvent.dataTransfer.files; // FileList object.
                                        for(var i=0; i < files.length; ++i)
                                            loadImageFromFile( files[i] );
                                        event.stopPropagation();
                                        event.preventDefault();
                                        return false;
                                    });
            }
            else if( on_imageupload )
            {
                // Upload image to a server
                var $input = $fileuploader_input
                                    .change(function(event){
                                        on_imageupload.call( this, insert_image_wysiwyg );
                                    });
                $fileuploader = $('<form/>').append($input);
            }
            if( $fileuploader )
                $('<div/>').addClass( 'wysiwyg-browse' )
                           .html( label_selectImage )
                           .append( $fileuploader )
                           .appendTo( $content );
            // Add image via 'URL'
            var $inputurl = $('<input type="text" value="">').addClass('wysiwyg-input')
                                .keypress(function(event){
                                    if( event.which == 10 || event.which == 13 )
                                        insert_image_wysiwyg( $inputurl.val() );
                                });
            if( placeholder_url )
                $inputurl.prop( 'placeholder', placeholder_url );
            var $okaybutton = $();
            if( toolbar_submit )
                $okaybutton = toolbar_button(toolbar_submit).click(function(event){
                                    insert_image_wysiwyg( $inputurl.val() );
                                    event.stopPropagation();
                                    event.preventDefault();
                                    return false;
                                });
            $content.append( $('<div/>').append($inputurl).append($okaybutton) );
            return $content;
        };

        // Content: Insert video
        var content_insertvideo = function(wysiwygeditor)
        {
            // Add video to editor
            var insert_video_wysiwyg = function( url, html )
            {
                url = $.trim(url||'');
                html = $.trim(html||'');
                var website_url = false;
                if( url.length && ! html.length )
                    website_url = url;
                else if( html.indexOf('<') == -1 && html.indexOf('>') == -1 &&
                         html.match(/^(?:https?:\/)?\/?(?:[^:\/\s]+)(?:(?:\/\w+)*\/)(?:[\w\-\.]+[^#?\s]+)(?:.*)?(?:#[\w\-]+)?$/) )
                    website_url = html;
                if( website_url && video_from_url )
                    html = video_from_url( website_url ) || '';
                if( ! html.length && website_url )
                    html = '<video src="' + html_encode(website_url) + '">';
                wysiwygeditor.insertHTML( html ).closePopup().collapseSelection();
            };
            // Create popup
            var $content = $('<div/>').addClass('wysiwyg-toolbar-form')
                                      .prop('unselectable','on');
            // Add video via '<embed/>'
            var $textareaembed = $('<textarea>').addClass('wysiwyg-input wysiwyg-inputtextarea');
            if( placeholder_embed )
                $textareaembed.prop( 'placeholder', placeholder_embed );
            $('<div/>').addClass( 'wysiwyg-embedcode' )
                       .append( $textareaembed )
                       .appendTo( $content );
            // Add video via 'URL'
            var $inputurl = $('<input type="text" value="">').addClass('wysiwyg-input')
                                .keypress(function(event){
                                    if( event.which == 10 || event.which == 13 )
                                        insert_video_wysiwyg( $inputurl.val() );
                                });
            if( placeholder_url )
                $inputurl.prop( 'placeholder', placeholder_url );
            var $okaybutton = $();
            if( toolbar_submit )
                $okaybutton = toolbar_button(toolbar_submit).click(function(event){
                                    insert_video_wysiwyg( $inputurl.val(), $textareaembed.val() );
                                    event.stopPropagation();
                                    event.preventDefault();
                                    return false;
                                });
            $content.append( $('<div/>').append($inputurl).append($okaybutton) );
            return $content;
        };

        // Content: Color palette
        var content_colorpalette = function( wysiwygeditor, forecolor )
        {
            var $content = $('<table/>')
                            .prop('cellpadding','0')
                            .prop('cellspacing','0')
                            .prop('unselectable','on');
            for( var row=1; row < 15; ++row ) // should be '16' - but last line looks so dark
            {
                var $rows = $('<tr/>');
                for( var col=0; col < 25; ++col ) // last column is grayscale
                {
                    var color;
                    if( col == 24 )
                    {
                        var gray = Math.floor(255 / 13 * (14 - row)).toString(16);
                        var hexg = (gray.length < 2 ? '0' : '') + gray;
                        color = '#' + hexg + hexg + hexg;
                    }
                    else
                    {
                        var hue        = col / 24;
                        var saturation = row <= 8 ? row     /8 : 1;
                        var value      = row  > 8 ? (16-row)/8 : 1;
                        color = HSVtoRGB( hue, saturation, value );
                    }
                    $('<td/>').addClass('wysiwyg-toolbar-color')
                              .prop('title', color)
                              .prop('unselectable','on')
                              .css({backgroundColor: color})
                              .click(function(){
                                  var color = this.title;
                                  if( forecolor )
                                      wysiwygeditor.forecolor( color ).closePopup().collapseSelection();
                                  else
                                      wysiwygeditor.highlight( color ).closePopup().collapseSelection();
                                  return false;
                              })
                              .appendTo( $rows );
                }
                $content.append( $rows );
            }
            return $content;
        };

        // Handlers
        var get_toolbar_handler = function( name, popup_callback )
        {
            switch( name )
            {
                case 'insertimage':
                    if( ! popup_callback )
                        return null;
                    return function( target ) {
                        popup_callback( content_insertimage(wysiwygeditor), target );
                    };
                case 'insertvideo':
                    if( ! popup_callback )
                        return null;
                    return function( target ) {
                        popup_callback( content_insertvideo(wysiwygeditor), target );
                    };
                case 'insertlink':
                    if( ! popup_callback )
                        return null;
                    return function( target ) {
                        popup_callback( content_insertlink(wysiwygeditor), target );
                    };
                case 'bold':
                    return function() {
                        wysiwygeditor.bold(); // .closePopup().collapseSelection()
                    };
                case 'italic':
                    return function() {
                        wysiwygeditor.italic(); // .closePopup().collapseSelection()
                    };
                case 'underline':
                    return function() {
                        wysiwygeditor.underline(); // .closePopup().collapseSelection()
                    };
                case 'strikethrough':
                    return function() {
                        wysiwygeditor.strikethrough(); // .closePopup().collapseSelection()
                    };
                case 'forecolor':
                    if( ! popup_callback )
                        return null;
                    return function( target ) {
                        popup_callback( content_colorpalette(wysiwygeditor,true), target );
                    };
                case 'highlight':
                    if( ! popup_callback )
                        return null;
                    return function( target ) {
                        popup_callback( content_colorpalette(wysiwygeditor,false), target );
                    };
                case 'alignleft':
                    return function() {
                        wysiwygeditor.align('left'); // .closePopup().collapseSelection()
                    };
                case 'aligncenter':
                    return function() {
                        wysiwygeditor.align('center'); // .closePopup().collapseSelection()
                    };
                case 'alignright':
                    return function() {
                        wysiwygeditor.align('right'); // .closePopup().collapseSelection()
                    };
                case 'alignjustify':
                    return function() {
                        wysiwygeditor.align('justify'); // .closePopup().collapseSelection()
                    };
                case 'subscript':
                    return function() {
                        wysiwygeditor.subscript(); // .closePopup().collapseSelection()
                    };
                case 'superscript':
                    return function() {
                        wysiwygeditor.superscript(); // .closePopup().collapseSelection()
                    };
                case 'indent':
                    return function() {
                        wysiwygeditor.indent(); // .closePopup().collapseSelection()
                    };
                case 'outdent':
                    return function() {
                        wysiwygeditor.indent(true); // .closePopup().collapseSelection()
                    };
                case 'orderedList':
                    return function() {
                        wysiwygeditor.insertList(true); // .closePopup().collapseSelection()
                    };
                case 'unorderedList':
                    return function() {
                        wysiwygeditor.insertList(); // .closePopup().collapseSelection()
                    };
                case 'removeformat':
                    return function() {
                        wysiwygeditor.removeFormat().closePopup().collapseSelection();
                    };
            }
            return null;
        }

        // Create the toolbar
        var toolbar_button = function( button ) {
            var $element = $('<a/>').addClass( 'wysiwyg-toolbar-icon' )
                                    .prop('href','#')
                                    .prop('unselectable','on')
                                    .append(button.image);
            // pass other properties as "prop()"
            $.each( button, function( name, value )
            {
                switch( name )
                {
                    // classes
                    case 'class':
                        $element.addClass( value );
                        break;
                    // special meaning
                    case 'image':
                    case 'html':
                    case 'popup':
                    case 'click':
                    case 'showstatic':
                    case 'showselection':
                        break;
                    default: // button.title, ...
                        $element.attr( name, value );
                        break;
                }
            });
            return $element;
        };
        var add_buttons_to_toolbar = function( $toolbar, selection, popup_open_callback, popup_position_callback )
        {
            $.each( toolbar_buttons, function(key, value) {
                if( ! value )
                    return ;
                // Skip buttons on the toolbar
                if( selection === false && 'showstatic' in value && ! value.showstatic )
                    return ;
                // Skip buttons on selection
                if( selection === true && 'showselection' in value && ! value.showselection )
                    return ;
                // Click handler
                var toolbar_handler;
                if( 'click' in value )
                    toolbar_handler = function( target ) {
                        value.click( $(target) );
                    };
                else if( 'popup' in value )
                    toolbar_handler = function( target ) {
                        var $popup = popup_open_callback();
                        var overwrite_offset = value.popup( $popup, $(target) );
                        popup_position_callback( $popup, target, overwrite_offset );
                    };
                else
                    toolbar_handler = get_toolbar_handler( key, function( $content, target ) {
                        var $popup = popup_open_callback();
                        $popup.append( $content );
                        popup_position_callback( $popup, target );
                        $popup.find('input[type=text]:first').focus();
                    });
                // Create the toolbar button
                var $button;
                if( toolbar_handler )
                    $button = toolbar_button( value ).click( function(event) {
                        toolbar_handler( event.currentTarget );
                        // Give the focus back to the editor. Technically not necessary
                        if( get_toolbar_handler(key) ) // only if not a popup-handler
                            wysiwygeditor.getElement().focus();
                        event.stopPropagation();
                        event.preventDefault();
                        return false;
                    });
                else if( value.html )
                    $button = $(value.html);
                if( $button )
                    $toolbar.append( $button );
            });
        };
        var popup_position = function( $popup, $container, left, top )  // left+top relative to $container
        {
            // Test parents
            var container_node = $container.get(0),
                offsetparent = container_node.offsetParent,
                offsetparent_left = 0,
                offsetparent_top = 0,
                offsetparent_break = false,
                offsetparent_window_left = 0,     //$.offset() does not work with Safari 3 and 'position:fixed'
                offsetparent_window_top = 0,
                offsetparent_fixed = false,
                offsetparent_overflow = false,
                popup_width = $popup.width(),
                node = offsetparent;
            while( node )
            {
                offsetparent_window_left += node.offsetLeft;
                offsetparent_window_top += node.offsetTop;
                var $node = $(node),
                    node_position = $node.css('position');
                if( node_position != 'static' )
                    offsetparent_break = true;
                else if( ! offsetparent_break )
                {
                    offsetparent_left += node.offsetLeft;
                    offsetparent_top += node.offsetTop;
                }
                if( node_position == 'fixed' )
                    offsetparent_fixed = true;
                if( $node.css('overflow') != 'visible' )
                    offsetparent_overflow = true;
                node = node.offsetParent;
            }
            // Move $popup as high as possible in the DOM tree: offsetParent of $container
            var $offsetparent = $(offsetparent || document.body);
            $offsetparent.append( $popup );
            left += offsetparent_left + container_node.offsetLeft; // $container.position() does not work with Safari 3
            top += offsetparent_top + container_node.offsetTop;
            // Trim to offset-parent
            if( offsetparent_fixed || offsetparent_overflow )
            {
                if( left + popup_width > $offsetparent.width() - 1 )
                    left = $offsetparent.width() - popup_width - 1;
                if( left < 1 )
                    left = 1;
            }
            // Trim to viewport
            var viewport_width = $(window).width();
            if( offsetparent_window_left + left + popup_width > viewport_width - 1 )
                left = viewport_width - offsetparent_window_left - popup_width - 1;
            var scroll_left = offsetparent_fixed ? 0 : $(window).scrollLeft();
            if( offsetparent_window_left + left < scroll_left + 1 )
                left = scroll_left - offsetparent_window_left + 1;
            // Set offset
            $popup.css({ left: parseInt(left) + 'px',
                         top: parseInt(top) + 'px' });
        };


        // Transform the textarea to contenteditable
        var hotkeys = {},
            autocomplete = null;
        var create_wysiwyg = function( $textarea, $editor, $container, $placeholder )
        {
            var handle_autocomplete = function( keypress, key, character, shiftKey, altKey, ctrlKey, metaKey )
            {
                if( ! on_autocomplete )
                    return ;
                var typed = autocomplete || '';
                switch( key )
                {
                    case  8: // backspace
                        typed = typed.substring( 0, typed.length - 1 );
                        // fall through
                    case 13: // enter
                    case 27: // escape
                    case 33: // pageUp
                    case 34: // pageDown
                    case 35: // end
                    case 36: // home
                    case 37: // left
                    case 38: // up
                    case 39: // right
                    case 40: // down
                        if( keypress )
                            return ;
                        character = false;
                        break;
                    default:
                        if( ! keypress )
                            return ;
                        typed += character;
                        break;
                }
                var rc = on_autocomplete( typed, key, character, shiftKey, altKey, ctrlKey, metaKey );
                if( typeof(rc) == 'object' && rc.length )
                {
                    // Show autocomplete
                    var $popup = $(wysiwygeditor.openPopup());
                    $popup.hide().addClass( 'wysiwyg-popup wysiwyg-popuphover' ) // show later
                          .empty().append( rc );
                    autocomplete = typed;
                }
                else
                {
                    // Hide autocomplete
                    wysiwygeditor.closePopup();
                    autocomplete = null;
                    return rc; // swallow key if 'false'
                }
            };

            // Options to wysiwyg.js
            var option = {
                element: $textarea.get(0),
                contenteditable: $editor ? $editor.get(0) : null,
                onKeyDown: function( key, character, shiftKey, altKey, ctrlKey, metaKey )
                    {
                        // Ask master
                        if( on_keydown && on_keydown(key, character, shiftKey, altKey, ctrlKey, metaKey) === false )
                            return false; // swallow key
                        // Exec hotkey (onkeydown because e.g. CTRL+B would oben the bookmarks)
                        if( character && !shiftKey && !altKey && ctrlKey && !metaKey )
                        {
                            var hotkey = character.toLowerCase();
                            if( ! hotkeys[hotkey] )
                                return ;
                            hotkeys[hotkey]();
                            return false; // prevent default
                        }
                        // Handle autocomplete
                        return handle_autocomplete( false, key, character, shiftKey, altKey, ctrlKey, metaKey );
                    },
                onKeyPress: function( key, character, shiftKey, altKey, ctrlKey, metaKey )
                    {
                        // Ask master
                        if( on_keypress && on_keypress(key, character, shiftKey, altKey, ctrlKey, metaKey) === false )
                            return false; // swallow key
                        // Handle autocomplete
                        return handle_autocomplete( true, key, character, shiftKey, altKey, ctrlKey, metaKey );
                    },
                onKeyUp: function( key, character, shiftKey, altKey, ctrlKey, metaKey )
                    {
                        // Ask master
                        if( on_keyup && on_keyup(key, character, shiftKey, altKey, ctrlKey, metaKey) === false )
                            return false; // swallow key
                    },
                onSelection: function( collapsed, rect, nodes, rightclick )
                    {
                        var show_popup = true,
                            $special_popup = null;
                        // Click on a link opens the link-popup
                        if( collapsed )
                            $.each( nodes, function(index, node) {
                                var $link = $(node).closest('a');
                                if( $link.length != 0 ) { // only clicks on text-nodes
                                    $special_popup = content_insertlink( wysiwygeditor, $link )
                                    return false; // break
                                }
                            });
                        // Read-Only?
                        if( wysiwygeditor.readOnly() )
                            show_popup = false;
                        // Fix type error - https://github.com/wysiwygjs/wysiwyg.js/issues/4
                        else if( ! rect )
                            show_popup = false;
                        // Force a special popup?
                        else if( $special_popup )
                            ;
                        // A right-click always opens the popup
                        else if( rightclick )
                            ;
                        // Autocomplete popup?
                        else if( autocomplete )
                            ;
                        // No selection-popup wanted?
                        else if( $.inArray('selection',toolbar_position.split('-')) == -1 )
                            show_popup = false;
                        // Selected popup wanted, but nothing selected (=selection collapsed)
                        else if( collapsed )
                            show_popup = false;
                        // Only one image? Better: Display a special image-popup
                        else if( nodes.length == 1 && nodes[0].nodeName == 'IMG' ) // nodes is not a sparse array
                            show_popup = false;
                        if( ! show_popup )
                        {
                            wysiwygeditor.closePopup();
                            return ;
                        }
                        // Popup position
                        var $popup;
                        var apply_popup_position = function()
                        {
                            var popup_width = $popup.outerWidth();
                            // Point is the center of the selection - relative to $parent not the element
                            var $parent = $textarea.parent(),
                                container_offset = $parent.offset(),
                                editor_offset = $(wysiwygeditor.getElement()).offset();
                            var left = rect.left + parseInt(rect.width / 2) - parseInt(popup_width / 2) + editor_offset.left - container_offset.left;
                            var top = rect.top + rect.height + editor_offset.top - container_offset.top;
                            popup_position( $popup, $parent, left, top );
                        };
                        // Open popup
                        $popup = $(wysiwygeditor.openPopup());
                        // if wrong popup -> close and open a new one
                        if( ! $popup.hasClass('wysiwyg-popuphover') || (!$popup.data('wysiwygjs-special')) != (!$special_popup) )
                            $popup = $(wysiwygeditor.closePopup().openPopup());
                        if( autocomplete )
                            $popup.show();
                        else if( ! $popup.hasClass('wysiwyg-popup') )
                        {
                            // add classes + buttons
                            $popup.addClass( 'wysiwyg-popup wysiwyg-popuphover' );
                            if( $special_popup )
                                $popup.empty().append( $special_popup ).data('wysiwygjs-special',true);
                            else
                                add_buttons_to_toolbar( $popup, true,
                                    function() {
                                        return $popup.empty();
                                    },
                                    apply_popup_position );
                        }
                        // Apply position
                        apply_popup_position();
                    },
                onOpenpopup: function() {
                        add_class_active();
                    },
                onClosepopup: function() {
                        autocomplete = null;
                        remove_class_active();
                    },
                hijackContextmenu: (toolbar_position == 'selection'),
                readOnly: !!$textarea.prop( 'readonly' )
            };
            if( $placeholder )
            {
                option.onPlaceholder = function( visible ) {
                    if( visible )
                        $placeholder.show();
                    else
                        $placeholder.hide();
                };
            }

            var wysiwygeditor = wysiwyg( option );
            return wysiwygeditor;
        }


        // Create a container if it does not exist yet
        var $container = $textarea.closest( '.wysiwyg-container' );
        if( $container.length == 0 )
        {
            $container = $('<div/>').addClass('wysiwyg-container');
            if( classes )
                $container.addClass( classes );
            $textarea.wrap( $container );
            $container = $textarea.closest( '.wysiwyg-container' );
        }

        // Create the placeholder if it does not exist yet and we want one
        var $wrapper = $textarea.closest( '.wysiwyg-wrapper' );
        if( placeholder && $wrapper.length == 0 )
        {
            $wrapper = $('<div/>').addClass('wysiwyg-wrapper');
            $textarea.wrap( $wrapper );
            $wrapper = $textarea.closest( '.wysiwyg-wrapper' );
        }
        var $placeholder = null;
        if( $wrapper.length != 0 )
            $placeholder = $wrapper.find( '.wysiwyg-placeholder' );
        if( placeholder && (! $placeholder || $placeholder.length == 0) )
        {
            $placeholder = $('<div/>').addClass( 'wysiwyg-placeholder' )
                                      .html( placeholder )
                                      .hide();
            $wrapper.prepend( $placeholder );
        }

        // Create the WYSIWYG Editor
        var $editor = $container.find( '.wysiwyg-editor' );
        if( $editor.length == 0 )
            $editor = null;
        var wysiwygeditor = create_wysiwyg( $textarea, $editor, $container, $placeholder );
        if( wysiwygeditor.legacy )
        {
            if( $editor )
                $editor.hide();
            if( $placeholder )
                $placeholder.hide();
            var $textarea = $(wysiwygeditor.getElement());
            $textarea.show().addClass( 'wysiwyg-textarea' );
            if( $textarea.is(':visible') ) // inside the DOM
                $textarea.width( $container.width() - ($textarea.outerWidth() - $textarea.width()) );
        }
        else
        {
            if( ! $editor )
                $(wysiwygeditor.getElement()).addClass( 'wysiwyg-editor' );

            // Clicking the placeholder -> focus editor - fixes IE6-IE8
            $wrapper.click(function(){
                wysiwygeditor.getElement().focus();
            });

            // Support ':active'-class
            var remove_active_timeout = null,
                initialize_toolbar = null;
            var add_class_active = function() {
                if( remove_active_timeout )
                    clearTimeout( remove_active_timeout );
                remove_active_timeout = null;
                if( initialize_toolbar )
                {
                    initialize_toolbar();
                    initialize_toolbar = null;
                }
                $container.addClass( 'wysiwyg-active' );
                $container.find( '.wysiwyg-toolbar-focus' ).slideDown(200);
            };
            var remove_class_active = function() {
                if( remove_active_timeout || document.activeElement == wysiwygeditor.getElement() )
                    return ;
                remove_active_timeout = setTimeout( function() {
                    remove_active_timeout = null;
                    $container.removeClass( 'wysiwyg-active' );
                    if( $.trim(wysiwygeditor.getHTML().replace(/<br\s*[\/]?>/gi,'')).length == 0 )
                        $container.find( '.wysiwyg-toolbar-focus' ).slideUp(200);
                }, 100 );
            };
            $(wysiwygeditor.getElement()).focus( add_class_active ).blur( remove_class_active );
            $textarea.closest( 'form' ).on( 'reset', remove_class_active );

            // Hotkey+Commands-List
            var commands = {};
            $.each( toolbar_buttons, function(key, value) {
                if( ! value || ! value.hotkey )
                    return ;
                var toolbar_handler = get_toolbar_handler( key );
                if( ! toolbar_handler )
                    return ;
                hotkeys[value.hotkey.toLowerCase()] = toolbar_handler;
                commands[key] = toolbar_handler;
            });

            // Toolbar on top or bottom
            if( ! $.isEmptyObject(toolbar_buttons) && toolbar_position != 'selection' )
            {
                var toolbar_top = $.inArray( 'top', toolbar_position.split('-') ) != -1;
                var toolbar_focus = $.inArray( 'focus', toolbar_position.split('-') ) != -1;
                // Callback to create toolbar on demand
                var create_toolbar = function()
                {
                    var $toolbar = $('<div/>').addClass( 'wysiwyg-toolbar' ).addClass( toolbar_top ? 'wysiwyg-toolbar-top' : 'wysiwyg-toolbar-bottom' );
                    if( toolbar_focus )
                        $toolbar.hide().addClass( 'wysiwyg-toolbar-focus' );
                    // Add buttons to the toolbar
                    add_buttons_to_toolbar( $toolbar, false,
                        function() {
                            // Open a popup from the toolbar
                            var $popup = $(wysiwygeditor.openPopup());
                            // if wrong popup -> create a new one
                            if( $popup.hasClass('wysiwyg-popup') && $popup.hasClass('wysiwyg-popuphover') )
                                $popup = $(wysiwygeditor.closePopup().openPopup());
                            if( ! $popup.hasClass('wysiwyg-popup') )
                                // add classes + content
                                $popup.addClass( 'wysiwyg-popup' );
                            return $popup;
                        },
                        function( $popup, target, overwrite_offset ) {
                            // Popup position
                            var $button = $(target);
                            var popup_width = $popup.outerWidth();
                            // Point is the top/bottom-center of the button
                            var left = $button.offset().left - $container.offset().left + parseInt($button.width() / 2) - parseInt(popup_width / 2);
                            var top = $button.offset().top - $container.offset().top;
                            if( toolbar_top )
                                top += $button.outerHeight();
                            else
                                top -= $popup.outerHeight();
                            if( overwrite_offset )
                            {
                                left = overwrite_offset.left;
                                top = overwrite_offset.top;
                            }
                            popup_position( $popup, $container, left, top );
                        });
                    if( toolbar_top )
                        $container.prepend( $toolbar );
                    else
                        $container.append( $toolbar );
                };
                if( ! toolbar_focus )
                    create_toolbar();
                else
                    initialize_toolbar = create_toolbar;
            }
        }

        // Export userdata
        return {
            wysiwygeditor: wysiwygeditor,
            $container: $container
        };
    }