wikiTicketDescriptionTemplates

Version 10 (modified by huxy, 5年 ago) (diff)

增加插入代码块的工具栏

Ticket 问题描述模板定义规则

按照下面的格式定义:

  1. 使用== 开头定义模板名字,这个名字会显示在模板选择列表里
  2. 使用{{{、}}}将模板内容包含起来,模板内容可以是任意符合wiki语法的文本
    == 模板名字
    {{{
    模板内容
    }}}
    

补丁申请模板(html)

<!-- html template -->
<style type="text/css">
    tr.panel-row textarea {
        height: 85px;
        padding-right: 0.4em;
    }
    .required-field-label {
        color: red;
    }
    input.date-picker {
        width: 100px;
    }
    #propertyform table.trac-properties {
        table-layout: unset;
    }
    #properties table.trac-properties > tbody > tr > th.col2 {
        border-left: 0px;
    }
    #properties table.trac-properties > tbody > tr > td.col1 {
        width: 28.2%;
    }
    #properties table.trac-properties > tbody > tr > td.col2 {
        width: 15%;
    }
    #propertyform table select {
        width: 99%;
    }
    #content.ticket {
        width: 68em;
    }
    #properties table.trac-properties > tbody > tr > th, #properties table.trac-properties > colgroup > col.th {
        width: 12.5%;
    }
    #propertyform table.trac-properties td input[type="text"], #propertyform table.trac-properties td textarea {
        width: 99%;
    }
    #properties table.trac-properties > tbody > tr > td, #properties table.trac-properties > colgroup > col.td {
        width: 0%;
    }
    .textarea-toolbar {
        margin-top: 0.3em;
        margin-left: 0.2em;
        border: solid #d7d7d7;
        border-width: 1px 1px 1px 0;
        height: 18px;
        width: 52px;
    }
    .textarea-toolbar :link, .textarea-toolbar :visited {
        background: transparent url(raw-attachment/wiki/TicketDescriptionTemplates/toolbar.png) no-repeat;
        border: 1px solid #fff;
        border-left-color: #d7d7d7;
        cursor: default;
        display: block;
        float: left;
        width: 24px;
        height: 16px;
       }
    .textarea-toolbar :link:hover, .textarea-toolbar :visited:hover {
        ckground-color: transparent;
        border: 1px solid #fb2;
    }
    .textarea-toolbar a#em { background-position: 0 0 }
    .textarea-toolbar a#strong { background-position: 0 -16px }
</style>
<script type="text/javascript">
    String.prototype.replaceAll = function(exp, newStr) {
        return this.replace(new RegExp(exp, "gm"), newStr);
    }

    String.prototype.format = function(args) {
        var result = this;
        if (arguments.length < 1)
            return result;
        
        var data = arguments;
        if (arguments.length == 1 && typeof(args) == "object")
            data = args;
        
        for (var key in data) {
            var value = data[key];
            if (undefined != value)
                result = result.replaceAll("\\{" + key + "\\}", value);
        }
        return result;
    }

    function clearDescriptionCookie() {
        $.cookie("description_panel", "");
    }

    function getDescriptionCookie() {
        return $.cookie("description_panel");
    }

    function setDescriptionCookie(value) {
        $.cookie("description_panel", value);
    }

    function createDescriptionPanel() {
        function updateDescriptionForServer(event) {
            var found_empty_field = false;
            var required_elements = $(".required-field");
            for (var i = 0; i < required_elements.length; i++) {
                if ($(required_elements.get(i)).val() == "") {
                    found_empty_field = true;
                    break;
                }
            }
            if (found_empty_field) {
                event.preventDefault();
                alert('有必填项为空,请补充。带 * 的为必填项。');
            }
            var data = populateDescription();
            if (data != null) {
                setDescriptionCookie(data.panel_info);
                $("#field-description").val(data.description);
            }
        }

        if (/msie/.test(navigator.userAgent.toLowerCase())) {
            $("#content").prepend('<div id="browser-warning" class="system-message">检测到浏览器为 IE,由于 IE 浏览器兼容性不好,请使用 Chrome 或 Firefox 浏览器</div>');
            $("#browser-warning").css("background-color", "#ffb");
            $("#browser-warning").css("border", "1px solid #500");
            $("input:submit[name='preview']").remove();
            $("input:submit[name='submit']").remove();
        } else {
            $("input:submit[name='preview']").click(function(event) {
                updateDescriptionForServer(event);
            });

            $("input:submit[name='submit']").click(function(event) {
                updateDescriptionForServer(event);
            });
        }

        var template = $("#panel tbody").html();
        $("#panel").remove();
        var description_row = $("label#field-description-help").parent().parent();
        description_row.css("display", "none");
        description_row.before(template);
        $("#field-summary").parent().attr("colspan", "5");
        $("#field-reporter").parent().attr("colspan", "5");
        $("#properties table th").css("vertical-align", "super");

        var required_fields = [
            'field-summary', 'field-reporter', 'field-type', 'field-component',
            'field-priority', 'field-severity', 'field-version', 'field-chip'
        ];

        for (var i = 0; i < required_fields.length; i++) {
            var element = $("label[for='{0}']".format(required_fields[i]));
            if (element.length != 0) {
                var text = element.html().replace(':', '');
                element.html('{label} <span class="required-field-label">*</span>:'.format({label: text}));
            }
            $('#{0}'.format(required_fields[i])).attr("class", "required-field");
        }

        $(".date-picker").datepicker({
            changeMonth: true,
            changeYear: true,
            onClose: function(date_text, picker) {
                var warning_tip = $(this).parent().find("span.empty-warning");
                if (warning_tip.length != 0)
                    warning_tip.remove();
            }
        });
        $(".date-picker").datepicker("option", "dateFormat", "yy-mm-dd");

        if (window.location.href.split(window.location.host)[1] != $("#propertyform").attr("action")) {
            clearDescriptionCookie();
        }

        $("#developer-resolve-date").val("[=#developer-resolve-date]");

        $(".required-field").blur(function(event) {
            var warning_tip = $(event.target).parent().find("span.empty-warning");
            if ($(event.target).val() == "") {
                if (warning_tip.length == 0)
                    $(event.target).parent().append('<span class="required-field-label empty-warning">内容不能为空</span>');
            } else {
                if (warning_tip.length != 0)
                    warning_tip.remove();
            }
        });

        var description_panel = getDescriptionCookie();
        if (description_panel != undefined && description_panel != "") {
            var panel_info = JSON.parse(description_panel);
            $(".panel-row label").each(function(index, element) {
                var text_element = $(element).parent().next("td").find("input:text")[0];
                if (text_element == undefined) {
                    text_element = $(element).parent().next("td").find("textarea")[0];
                }
                if ($(text_element).attr("class") != undefined && $(text_element).attr("class").match(/date-picker/) != null)
                    $(text_element).datepicker("setDate", panel_info[index]);
                else
                    $(text_element).val(panel_info[index]);
            });
        }

        function addToolbarButton(toolbar, id, title, click_fn) {
            var a = document.createElement("a");
            a.href = "#";
            a.id = id;
            a.title = title;
            a.onclick = function() {
                if ($(toolbar.target_textarea).prop("disabled") === false &&
                    $(toolbar.target_textarea).prop("readonly") === false) {
                    try { click_fn() } catch (e) {}
                }
                return false;
            };
            a.tabIndex = 400;
            toolbar.appendChild(a);
        }

        function encloseSelection(textarea, prefix, suffix) {
            textarea.focus();
            var start, end, sel, scrollPos, subst;
            if (document.selection != undefined) {
                sel = document.selection.createRange().text;
            } else if (textarea.setSelectionRange != undefined) {
                start = textarea.selectionStart;
                end = textarea.selectionEnd;
                scrollPos = textarea.scrollTop;
                sel = textarea.value.substring(start, end);
            }
            if (sel.match(/ $/)) {
                sel = sel.substring(0, sel.length - 1);
                suffix = suffix + " ";
            }
            subst = prefix + sel + suffix;
            if (document.selection != undefined) {
                var range = document.selection.createRange().text = subst;
                textarea.caretPos -= suffix.length;
            } else if (textarea.setSelectionRange != undefined) {
                textarea.value = textarea.value.substring(0, start) + subst + textarea.value.substring(end);
                if (sel) {
                    textarea.setSelectionRange(start + subst.length, start + subst.length);
                } else {
                    textarea.setSelectionRange(start + prefix.length, start + prefix.length);
                }
                textarea.scrollTop = scrollPos;
            }
        }

        $("textarea.toolbar").each(function(index, element) {
            if ($(element).prev('div.textarea-toolbar').length == 0) {
                $(element).before('<div class="textarea-toolbar"></div>');
                var toolbar = $(element).prev('div.textarea-toolbar').get(0);
                toolbar.target_textarea = element;
                addToolbarButton(toolbar, "strong", "插入 C 代码块", function() {encloseSelection(element, "\n{{{#!c\n", "\n}}}\n");});
                addToolbarButton(toolbar, "em", "插入 C++ 代码块", function() {encloseSelection(element, "\n{{{#!cpp\n", "\n}}}\n");});
            }
        });
    }

    function populateDescription() {
        var boundary = "|------";

        var panel_info = [];
        var description = "";
        var exchange_tags = []
        $(".panel-row").each(function(index, element) {
            var labels = $(element).find("th label");
            var row_data = [];
            var title = $(element).attr("title");
            description += "== " + title + "\n";

            if (labels.length == 1) {
                var value = $(element).find("td").children("input:text").val();
                if (value == undefined) {
                    value = $(element).find("td").children("textarea").val();
                }
                if (title == "出错日志")
                    description += "{{{\n" + value + "\n}}}\n";
                else
                    description += value + "\n";
                panel_info.push(value);
            } else {
                var values = $(element).find("td input:text");
                for (var i = 0; i < labels.length; i++) {
                    var label_name = $(labels.get(i)).text();
                    label_name = label_name.replace(/\s*\*/, '');
                    var input_val = $(values.get(i)).val();
                    var label_class = $(labels.get(i)).attr("class");
                    var tag = null;
                    if (label_class != undefined) {
                        var matched = label_class.match(/exchange-\d+/);
                        if (matched != null) {
                            tag = matched[0];
                            exchange_tags.push(tag);
                        }
                    }
                    if (tag != null)
                        description += '- <{tag}>{label_name}{input_val}</{tag}>\n'.format({tag:tag, label_name:label_name, input_val:input_val});
                    else
                        description += '- {label_name}{input_val}\n'.format({label_name:label_name, input_val:input_val});
                    panel_info.push(input_val);
                }
            }
            description += boundary + "\n";
        });

        for (var i = 0; i < exchange_tags.length; i++) {
            var tag = exchange_tags[i];
            var tag_pattern = new RegExp('<{tag}>.*</{tag}>'.format({tag:tag}), 'g');
            var content_pattern = new RegExp('<{tag}>(.*)</{tag}>'.format({tag:tag}));
            var matched = description.match(tag_pattern);
            if (matched != null) {
                description = description.replace(matched[0], matched[1].match(content_pattern)[1]);
                description = description.replace(matched[1], matched[0].match(content_pattern)[1]);
            }
        }
        return {panel_info: JSON.stringify(panel_info), description: description};
    }
</script>
<table id="panel">
    <tbody>
        <tr title="问题描述" class="panel-row">
            <th><label>问题描述 <span class="required-field-label">*</span>:</label></th>
            <td colspan="5"><textarea class="required-field toolbar"></textarea></td>
        </tr>
        <tr title="问题场景" class="panel-row">
            <th><label>问题场景 <span class="required-field-label">*</span>:</label></th>
            <td colspan="5"><textarea class="required-field toolbar"></textarea></td>
        </tr>
        <tr title="复现步骤" class="panel-row">
            <th><label>复现步骤 <span class="required-field-label">*</span>:</label></th>
            <td colspan="5"><textarea class="required-field toolbar"></textarea></td>
        </tr>
        <tr title="出错日志" class="panel-row">
            <th><label>出错日志:</label></th>
            <td colspan="5"><textarea></textarea></td>
        </tr>
        <tr title="初步定位" class="panel-row">
            <th><label>初步定位:</label></th>
            <td colspan="5"><textarea class="toolbar"></textarea></td>
        </tr>
        <tr title="问题处理时间段" class="panel-row">
            <th><label>发现日期 <span class="required-field-label">*</span>:</label></th>
            <td><input type="text" id="issue-occur-date" class="date-picker required-field"></td>
            <th><label class="exchange-1">沟通联系人 <span class="required-field-label">*</span>:</label></th>
            <td><input type="text" class="required-field"></td>
            <th style="display: none"><label>开发人员预期解决日期:</label></th>
            <td style="display: none"><input type="text" id="developer-resolve-date"></td>
        </tr>
        <tr title="联系人信息" class="panel-row">
            <th><label class="exchange-1">期望解决日期 <span class="required-field-label">*</span>:</label></th>
            <td><input type="text" id="issue-resolve-date" class="date-picker required-field"></td>
            <th><label>电话 <span class="required-field-label">*</span>:</label></th>
            <td><input type="text" class="required-field"></td>
            <th style="width: 30px"><label>邮箱:</label></th>
            <td><input type="text" style="width: 96%;"></td>
        </tr>
    </tbody>
</table>

附件 (1)

Download all attachments as: .zip