<commit_before>/*globals define, _, $*/
/*jshint browser: true, camelcase: false*/

/**
 * @author rkereskenyi / https://github.com/rkereskenyi
 * @author <NAME> / https://github.com/VictorCoder123
 */

define([
    'epiceditor',
    'js/Constants',
    'js/Utils/ComponentSettings',
    'js/NodePropertyNames',
    'js/Utils/DisplayFormat',
    'js/Widgets/DiagramDesigner/DiagramDesignerWidget.DecoratorBase',
    '../Core/DocumentDecorator.Core',
    './DocumentEditorDialog',
    'text!./DocumentDecorator.DiagramDesignerWidget.html',
    'css!./DocumentDecorator.DiagramDesignerWidget.css'
], function (marked,
             CONSTANTS,
             ComponentSettings,
             nodePropertyNames,
             displayFormat,
             DiagramDesignerWidgetDecoratorBase,
             DocumentDecoratorCore,
             DocumentEditorDialog,
             DocumentDecoratorTemplate) {

    'use strict';

    var DocumentDecorator,
        DECORATOR_ID = 'DocumentDecorator',
        TEXT_META_EDIT_BTN_BASE = $('<i class="glyphicon glyphicon-cog text-meta no-print" ' +
            'title="Edit documentation" />');

    DocumentDecorator = function (options) {
        var opts = _.extend({}, options);

        DiagramDesignerWidgetDecoratorBase.apply(this, [opts]);
        DocumentDecoratorCore.apply(this, [opts]);

        this._config = DocumentDecorator.getDefaultConfig();
        ComponentSettings.resolveWithWebGMEGlobal(this._config, DocumentDecorator.getComponentId());

        this.name = '';

        this._skinParts = {};

        this.$doc = this.$el.find('.doc').first();

        // Use default marked options
        marked.setOptions(this._config.parserOptions);

        this.logger.debug('DocumentDecorator ctor');
    };

    DocumentDecorator.getDefaultConfig = function () {
        return {
            parserOptions: {
                // See https://github.com/chjj/marked
                gfm: true,
                tables: true,
                breaks: false,
                pedantic: false,
                sanitize: true, // Set to false if you want to enable html.
                smartLists: true,
                smartypants: false
            }
        };
    };

    DocumentDecorator.getComponentId = function () {
        return 'GenericUIDocumentDecorator';
    };

    _.extend(DocumentDecorator.prototype, DiagramDesignerWidgetDecoratorBase.prototype);
    _.extend(DocumentDecorator.prototype, DocumentDecoratorCore.prototype);

    DocumentDecorator.prototype.DECORATORID = DECORATOR_ID;

    /*********************** OVERRIDE DiagramDesignerWidgetDecoratorBase MEMBERS **************************/

    DocumentDecorator.prototype.$DOMBase = $(DocumentDecoratorTemplate);

    DocumentDecorator.prototype.on_addTo = function () {
        var self = this;
        var client = this._control._client;
        var nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]);
        this._renderName();

        //render text-editor based META editing UI piece
        this._skinParts.$EditorBtn = TEXT_META_EDIT_BTN_BASE.clone();
        this.$el.append(this._skinParts.$EditorBtn);

        // Load EpicEditor on click
        this._skinParts.$EditorBtn.on('click', function (event) {
            if (self.hostDesignerItem.canvas.getIsReadOnlyMode() !== true &&
                nodeObj.getAttribute('documentation') !== undefined) {
                self._showEditorDialog();
            }

            event.stopPropagation();
            event.preventDefault();
        });

        // Set title editable on double-click 
        this.skinParts.$name.on('dblclick.editOnDblClick', null, function (event) {
            if (self.hostDesignerItem.canvas.getIsReadOnlyMode() !== true) {
                $(this).editInPlace({
                    class: '',
                    onChange: function (oldValue, newValue) {
                        self._onNodeTitleChanged(oldValue, newValue);
                    }
                });
            }
            event.stopPropagation();
            event.preventDefault();
        });

        // Show Popover when click on name
        this.skinParts.$name.on('click', function (event) {
            self.skinParts.$name.popover({});
            self.skinParts.$name.popover('show');
            self.logger.debug(self.skinParts.$name.popover);
            event.stopPropagation();
            event.preventDefault();
        });

        // Let the parent decorator class do its job.
        DiagramDesignerWidgetDecoratorBase.prototype.on_addTo.apply(this, arguments);

        // Finally invoke the update too.
        self.update();
    };

    DocumentDecorator.prototype._renderName = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]);
        //render GME-ID in the DOM, for debugging

        this.$el.attr({'data-id': this._metaInfo[CONSTANTS.GME_ID]});
        if (nodeObj) {
            this.name = displayFormat.resolve(nodeObj);
        }
        //find name placeholder
        this.skinParts.$name = this.$el.find('.name');
        this.skinParts.$name.text(this.name);

        if (this.name) {
            this.skinParts.$name.show();
        } else {
            this.skinParts.$name.hide();
        }
    };

    DocumentDecorator.prototype.update = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]),
            newDoc = '',
            renderedEl;

        if (nodeObj) {
            newDoc = nodeObj.getAttribute('documentation');
            // Update docs on node when attribute "documentation" changes
            this.$doc.empty();
            // Show error message if documentation attribute is not defined
            if (newDoc === undefined) {
                this.$doc.append('Editor is disabled because attribute "documentation" is not found in Meta-Model');
                this._skinParts.$EditorBtn.addClass('not-activated');
            } else {
                if (this.hostDesignerItem.canvas.getIsReadOnlyMode() === false) {
                    this._skinParts.$EditorBtn.removeClass('not-activated');
                } else {
                    this._skinParts.$EditorBtn.addClass('not-activated');
                }

                try {
                    renderedEl = $(marked(newDoc));
                    this.$doc.append(renderedEl);
                } catch (e) {
                    this.logger.error('Markdown parsing failed html', e);
                    this.logger.error('Stored text:', newDoc);
                    this.$doc.empty();
                    this.$doc.append('Stored markdown is invalid!');
                }
            }

            this._renderName();
        }

        this._updateColors();
    };<commit_msg>DocumentDecorator has more flexible width to avoid overflows (#1653)<commit_after>/*globals define, _, $*/
/*jshint browser: true, camelcase: false*/

/**
 * @author rkereskenyi / https://github.com/rkereskenyi
 * @author <NAME> / https://github.com/VictorCoder123
 */

define([
    'epiceditor',
    'js/Constants',
    'js/Utils/ComponentSettings',
    'js/NodePropertyNames',
    'js/Utils/DisplayFormat',
    'js/Widgets/DiagramDesigner/DiagramDesignerWidget.DecoratorBase',
    '../Core/DocumentDecorator.Core',
    './DocumentEditorDialog',
    'text!./DocumentDecorator.DiagramDesignerWidget.html',
    'css!./DocumentDecorator.DiagramDesignerWidget.css'
], function (marked,
             CONSTANTS,
             ComponentSettings,
             nodePropertyNames,
             displayFormat,
             DiagramDesignerWidgetDecoratorBase,
             DocumentDecoratorCore,
             DocumentEditorDialog,
             DocumentDecoratorTemplate) {

    'use strict';

    var DocumentDecorator,
        INNER_MAX_WIDTH = 373,
        PADDING_AND_MARGINS = 27,
        DECORATOR_ID = 'DocumentDecorator',
        TEXT_META_EDIT_BTN_BASE = $('<i class="glyphicon glyphicon-cog text-meta no-print" ' +
            'title="Edit documentation" />');

    DocumentDecorator = function (options) {
        var opts = _.extend({}, options);

        DiagramDesignerWidgetDecoratorBase.apply(this, [opts]);
        DocumentDecoratorCore.apply(this, [opts]);

        this._config = DocumentDecorator.getDefaultConfig();
        ComponentSettings.resolveWithWebGMEGlobal(this._config, DocumentDecorator.getComponentId());

        this.name = '';

        this._skinParts = {};

        this.$doc = this.$el.find('.doc').first();
        this._docString = '';

        // Use default marked options
        marked.setOptions(this._config.parserOptions);

        this.logger.debug('DocumentDecorator ctor');
    };

    DocumentDecorator.getDefaultConfig = function () {
        return {
            parserOptions: {
                // See https://github.com/chjj/marked
                gfm: true,
                tables: true,
                breaks: false,
                pedantic: false,
                sanitize: true, // Set to false if you want to enable html.
                smartLists: true,
                smartypants: false
            }
        };
    };

    DocumentDecorator.getComponentId = function () {
        return 'GenericUIDocumentDecorator';
    };

    _.extend(DocumentDecorator.prototype, DiagramDesignerWidgetDecoratorBase.prototype);
    _.extend(DocumentDecorator.prototype, DocumentDecoratorCore.prototype);

    DocumentDecorator.prototype.DECORATORID = DECORATOR_ID;

    /*********************** OVERRIDE DiagramDesignerWidgetDecoratorBase MEMBERS **************************/

    DocumentDecorator.prototype.$DOMBase = $(DocumentDecoratorTemplate);

    DocumentDecorator.prototype.on_addTo = function () {
        var self = this;
        var client = this._control._client;
        var nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]);
        this._renderName();

        //render text-editor based META editing UI piece
        this._skinParts.$EditorBtn = TEXT_META_EDIT_BTN_BASE.clone();
        this.$el.append(this._skinParts.$EditorBtn);

        // Load EpicEditor on click
        this._skinParts.$EditorBtn.on('click', function (event) {
            if (self.hostDesignerItem.canvas.getIsReadOnlyMode() !== true &&
                nodeObj.getAttribute('documentation') !== undefined) {
                self._showEditorDialog();
            }

            event.stopPropagation();
            event.preventDefault();
        });

        // Set title editable on double-click 
        this.skinParts.$name.on('dblclick.editOnDblClick', null, function (event) {
            if (self.hostDesignerItem.canvas.getIsReadOnlyMode() !== true) {
                $(this).editInPlace({
                    class: '',
                    onChange: function (oldValue, newValue) {
                        self._onNodeTitleChanged(oldValue, newValue);
                    }
                });
            }
            event.stopPropagation();
            event.preventDefault();
        });

        // Show Popover when click on name
        this.skinParts.$name.on('click', function (event) {
            self.skinParts.$name.popover({});
            self.skinParts.$name.popover('show');
            self.logger.debug(self.skinParts.$name.popover);
            event.stopPropagation();
            event.preventDefault();
        });

        // Let the parent decorator class do its job.
        DiagramDesignerWidgetDecoratorBase.prototype.on_addTo.apply(this, arguments);

        // Finally invoke the update too.
        self.update();
    };

    DocumentDecorator.prototype.onRenderGetLayoutInfo = function () {
        // At this point all elements are inserted in the DOM - adjust the max-width
        // based on the widest contained child (if using a bunch of custom css style this
        // approach probably wont work).
        var maxWidth = 0;

        this.$doc.find('*')
            .each(function () {
                var elWidth = $(this).outerWidth(true);
                maxWidth = elWidth > maxWidth ? elWidth : maxWidth;
            });

        if (maxWidth > INNER_MAX_WIDTH) {
            this.$el.css('maxWidth', maxWidth + PADDING_AND_MARGINS);
        } else {
            // Remove and fall back to css defined (400px)
            this.$el.css('maxWidth', undefined);
        }

        DiagramDesignerWidgetDecoratorBase.prototype.onRenderGetLayoutInfo.apply(this);
    };

    DocumentDecorator.prototype._renderName = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]);
        //render GME-ID in the DOM, for debugging

        this.$el.attr({'data-id': this._metaInfo[CONSTANTS.GME_ID]});
        if (nodeObj) {
            this.name = displayFormat.resolve(nodeObj);
        }
        //find name placeholder
        this.skinParts.$name = this.$el.find('.name');
        this.skinParts.$name.text(this.name);

        if (this.name) {
            this.skinParts.$name.show();
        } else {
            this.skinParts.$name.hide();
        }
    };

    DocumentDecorator.prototype.update = function () {
        var client = this._control._client,
            nodeObj = client.getNode(this._metaInfo[CONSTANTS.GME_ID]),
            newDoc = '',
            renderedEl;

        if (nodeObj) {
            newDoc = nodeObj.getAttribute('documentation');
            // Show error message if documentation attribute is not defined
            if (newDoc === undefined) {
                this.$doc.empty();
                this.$doc.append('Editor is disabled because attribute "documentation" is not found in Meta-Model');
                this._skinParts.$EditorBtn.addClass('not-activated');
            } else {
                if (this.hostDesignerItem.canvas.getIsReadOnlyMode() === false) {
                    this._skinParts.$EditorBtn.removeClass('not-activated');
                } else {
                    this._skinParts.$EditorBtn.addClass('not-activated');
                }

                if (this._docString !== newDoc) {
                    this.$doc.empty();
                    this._docString = newDoc;
                    try {
                        renderedEl = $(marked(newDoc));
                        this.$doc.append(renderedEl);
                    } catch (e) {
                        this.logger.error('Markdown parsing failed html', e);
                        this.logger.error('Stored text:', newDoc);
                        this.$doc.empty();
                        this.$doc.append('Stored markdown is invalid!');
                    }
                }
            }

            this._renderName();
        }

        this._updateColors();
    };
{'fraction_non_alphanumeric': 0.12144353585186186, 'fraction_numerical': 0.0012840440629857403, 'mean_word_length': 1.9720827475396665, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4675164', 'n_tokens_mistral': 4044, 'n_tokens_neox': 3876, 'n_words': 700}