<commit_before>
// PKUI 核心模块
define( function ( require ) {
    "use strict";

    require( "isLoading" );
    require( "css/font/font-awesome/4.7.0/font-awesome.css" );
    require( "layer" );
    require( "lib/component/layer/3.0.1.x/skin/default/layer.css" );
    require( "moment-local-zh" );

    var
        $ = require( "jquery" ),

        AOP = require( "meld" ),
        moment = require( "moment" ),

        ns = window[ "www.pkusoft.net" ],

        $doc = $( window.document ),

        PKUI = {
            //

            componentMarkupProp: "pkui-component",

            //

            optionsMarkupProp: "pkui-component-options",

            // CTX路径
            ctxPath: ns.ctxPath,

            // pkui的基本路径
            basePath: ns.pkuiBasePath,

            // 字典路径
            dicPath: ns.ctxPath + "/static/dic/",

            // 时间戳（版本控制）v=2012-1-1
            timestamp: ns.timestamp,

            // 组件容器
            component: {},

            // 载入模块（seajs.use方法的别名）
            load: seajs.use,

            // 渲染
            render: render,

            // 自动渲染标志
            isAutoRender: true,

            // 设置自动渲染（true/false）
            setAutoRender: setAutoRender
        }
        ;

    // 如果是在WebStorm里跑 PKUI项目，则更改 ctxPath 和 dicPath
    if ( location.href.indexOf( "localhost" ) !== -1 && ns.pkuiBasePath.indexOf( "static" ) === -1 ) {
        PKUI.ctxPath = "http://localhost:8080/pkui";
        PKUI.dicPath = "http://localhost:8080/pkui/static/dic/";
    }

    /**
     * 初始化
     * @private
     */
    PKUI._init = function _init() {

        // DOM树构建完毕，执行一次渲染
        $( document ).ready( render );

        // 处理所有Ajax请求
        fmtAjaxUrl();

        // 全局的简单事件处理
        regGlobalEventHandler();

        // 设置自动渲染
        this.setAutoRender( this.isAutoRender );

        // 暴露到全局名称空间
        window.PKUI = PKUI;
    };

    /**
     * 通用功能
     */
    $.extend( PKUI, {
        /**
         * @example
         * public class JsonResult {
         *     private boolean success = false;
         *     private String message = "";
         *     private Object data;
         * }
         */
        handleJsonResult: function ( jsonResult ) {
            if ( typeof jsonResult === "string" ) {
                jsonResult = $.parseJSON( jsonResult );
            }
            // if ( jsonResult.success == false ) {
            //     return false;
            // }
            return jsonResult;
        },
        /**
         * @example
         * public class GridResult {
         *     private boolean success = true;
         *     private int totalRecords = 0;
         *     private List<?> data;
         * }
         */
        handleGridResult: function ( gridResult ) {
            return PKUI.handleJsonResult( gridResult );
        },
        /**
         * 转换树结构
         * @param options {{data: Array, rootId: string, idName: string, parentIdName: string, childrenName: string, filter: Array}}
         * @example
         * PKUI.getTreeList( {
                data: [
                    { menuId: 0, menuName: "系统管理", treeParentId: null },
                    { menuId: 1, menuName: "用户管理", treeParentId: 0 },
                    { menuId: 2, menuName: "单位管理", treeParentId: 0 }
                ],
                rootId: 0,
                idName: "menuId",
                parentIdName: "treeParentId",
                childrenName: "children"
           } );
         返回：
         [
         {
             menuId: 0, menuName: "系统管理", treeParentId: null,
             children: [
                 { menuId: 1, menuName: "用户管理", treeParentId: 0, children: null },
                 { menuId: 2, menuName: "单位管理", treeParentId: 0, children: null }
             ]
         }
         ]
         */
        getTreeList: function getTreeList( options ) {
            var
                data = options.data,
                rootId = options.rootId,
                idName = options.idName || "id",
                parentIdName = options.parentIdName || "parentId",
                childrenName = options.childrenName || "children",
                returnData,
                childrenCollection = {},
                parentId,
                rootList
                ;

            if ( !rootId ) {
                rootId = data[ 0 ][ idName ];
            }

            $.each( data, function ( index, elt ) {
                parentId = elt[ parentIdName ];
                childrenCollection[ parentId ] = childrenCollection[ parentId ] || [];
                childrenCollection[ parentId ].push( elt );
            } );

            rootList = data[ rootId ];

            if ( !$.isArray( rootList ) ) {
                rootList = [ rootList ];
            }

            returnData = fmtData( rootList );

            function fmtData( data ) {
                var list = []
                    ;
                if ( !data || !data.length ) {
                    return null;
                }
                $.each( data, function ( index, elt ) {
                    var record = elt,
                        newRecord
                        ;
                    newRecord = $.extend( {}, record );
                    newRecord[ childrenName ] = fmtData( childrenCollection[ record[ idName ] ] );
                    list.push( newRecord );
                } );
                return list;
            }

            return returnData;

        }
    } );

    /**
     * 渲染。
     *
     * 渲染的目标（在此列出全部可被自动渲染的组件）：
     *
     *

     *

     *

     *
     * 已渲染的标志（添加 isrendered="true"）：
     *
     *

     *
     *      渲染标志的添加由组件自身添加
     */
    function render() {
        var
            $component = $( "[data-" + PKUI.componentMarkupProp + "]" )
                .not('[isrendered]')
                .not( "[notrecognized='not reg']" )
            ;

        $component.each( function () {
            var
                $this = $( this ),
                componentName = $this.data( PKUI.componentMarkupProp ),
                // jQuery自动转为JSON对象了
                componentOptions = $this.data( PKUI.optionsMarkupProp ) || {},
                componentNameList
                ;
            if ( $.trim( componentName ) === "" ) {
                return ;
            }

            if ( componentName.indexOf( "|" ) !== -1 ) {
                componentNameList = componentName.split( "|" );
            } else {
                componentNameList = [ componentName ];
            }

            if ( ! $.isArray( componentOptions ) ) {
                componentOptions = [ componentOptions ];
            }

            $.each( componentNameList, function( index, componentName ) {
                var
                    options = componentOptions[ index ] || {},
                    component = PKUI.component[ $.trim( componentName ) ],
                    moduleId = componentName
                    ;
                // 如果没有注册该组件，则载入，再初始化
                if ( !component ) {
                    switch ( componentName ) {
                        case "datagrid":
                            moduleId = "bootgrid";
                            break;
                        case "drawer":
                            moduleId = "drawer";
                            break;
                        case "form":
                            moduleId = "form";
                            break;
                        case "validator":
                            moduleId = "validator";
                            break;
                        default:
                            console.info();
                            var errorMessage = " 未被注册的组件[" + componentName + "]";
                            console.info( moment().format("YYYY年MM月DD日 HH:MM:SS"), errorMessage );
                            window.layer.msg( errorMessage );
                            $this.attr( "notrecognized", "not reg" );
                            return;
                    }
                    seajs.use( [ moduleId ], function () {
                        PKUI.component[ $.trim( componentName ) ].call( $this, options );
                    } );
                }
                // 如果已注册，则初始化
                else {
                    component.call( $this, options );
                }
            } );

        } );
    }
    /**
     * 开启/关闭 自动渲染。
     *
     * 自动渲染时机：
     *
     *      1. 调用 jquery.html( value ) 方法之后
     *      2. 调用 jquery.append( value ) 方法之后
     *      3. 调用 jquery.appendTo( value ) 方法之后
     *      4. 调用 jquery.prepend( value ) 方法之后
     *      5. 调用 jquery.prependTo( value ) 方法之后
     *
     * @param isAutoRender {boolean} true-开启，false-关闭。
     *
     */
    function setAutoRender ( isAutoRender ) {

        if ( arguments.length === 0 ) {
            console.info( "/(ㄒoㄒ)/~~ 请设置参数。" );
            return;
        }

        PKUI.isAutoRender = Boolean( isAutoRender );

        if ( isAutoRender ) {

            setAutoRender.pointcutHandlerList = [

                // 1. 调用 jquery.html( value ) 方法之后
                AOP.after( $.prototype, "html", render )
                // ,

                // 2. 调用 jquery.append( value ) 方法之后
                //AOP.after( $.prototype, "append", render ),

                // 3. 调用 jquery.appendTo( value ) 方法之后
                //AOP.after( $.prototype, "appendTo", render ),

                // 4. 调用 jquery.prepend( value ) 方法之后
                //AOP.after( $.prototype, "prepend", render ),

                // 5. 调用 jquery.prependTo( value ) 方法之后
                //AOP.after( $.prototype, "prependTo", render )

            ];

        } else {

            $.each( setAutoRender.pointcutHandlerList, function ( index, pointcutHandler ) {
                pointcutHandler.remove();
            } );

        }

    }

    /**
     * 格式化 $.ajax 的 url，如果包含“__CTX__” 则，替换为 PKUI.ctxPath
     */
    function fmtAjaxUrl () {
        AOP.before( $, "ajax", function ( url, options ) {
            // If url is an object, simulate pre-1.5 signature
            if ( typeof url === "object" ) {
                options = url;
                url = undefined;
            }

            if ( options.url.indexOf( "__CTX__" ) !== -1 ) {
                options.url = options.url.replace( "__CTX__", PKUI.ctxPath );
            }
        } );
    }

    /**
     * 全局的事件处理，通过类名。
     * 类名格式：名称空间-事件类型-处理后的结果
     * @example
     *

     */
    function regGlobalEventHandler() {
        var
            eventNs = ".pkui.global"
        ;
        // 点击后，隐藏
        $doc.on( "click" + eventNs, ".pkui-click-hide", function () {
            $( this ).hide();
        } );

    }

    PKUI._init();

} );<commit_msg>【PKUI】记录渲染次数<commit_after>
// PKUI 核心模块
define( function ( require ) {
    "use strict";

    require( "isLoading" );
    require( "css/font/font-awesome/4.7.0/font-awesome.css" );
    require( "layer" );
    require( "lib/component/layer/3.0.1.x/skin/default/layer.css" );
    require( "moment-local-zh" );

    var
        $ = require( "jquery" ),

        AOP = require( "meld" ),
        moment = require( "moment" ),

        ns = window[ "www.pkusoft.net" ],

        $doc = $( window.document ),

        PKUI = {
            //

            componentMarkupProp: "pkui-component",

            //

            optionsMarkupProp: "pkui-component-options",

            // CTX路径
            ctxPath: ns.ctxPath,

            // pkui的基本路径
            basePath: ns.pkuiBasePath,

            // 字典路径
            dicPath: ns.ctxPath + "/static/dic/",

            // 时间戳（版本控制）v=2012-1-1
            timestamp: ns.timestamp,

            // 组件容器
            component: {},

            // 载入模块（seajs.use方法的别名）
            load: seajs.use,

            // 渲染
            render: render,

            // 自动渲染标志
            isAutoRender: true,

            // 设置自动渲染（true/false）
            setAutoRender: setAutoRender,

            __isrendering: false,
            __renderedTimes: 0

        }
        ;

    // 如果是在WebStorm里跑 PKUI项目，则更改 ctxPath 和 dicPath
    if ( location.href.indexOf( "localhost" ) !== -1 && ns.pkuiBasePath.indexOf( "static" ) === -1 ) {
        PKUI.ctxPath = "http://localhost:8080/pkui";
        PKUI.dicPath = "http://localhost:8080/pkui/static/dic/";
    }

    /**
     * 初始化
     * @private
     */
    PKUI._init = function _init() {

        // DOM树构建完毕，执行一次渲染
        $( document ).ready( render );

        // 处理所有Ajax请求
        fmtAjaxUrl();

        // 全局的简单事件处理
        regGlobalEventHandler();

        // 设置自动渲染
        this.setAutoRender( this.isAutoRender );

        // 暴露到全局名称空间
        window.PKUI = PKUI;
    };

    /**
     * 通用功能
     */
    $.extend( PKUI, {
        /**
         * @example
         * public class JsonResult {
         *     private boolean success = false;
         *     private String message = "";
         *     private Object data;
         * }
         */
        handleJsonResult: function ( jsonResult ) {
            if ( typeof jsonResult === "string" ) {
                jsonResult = $.parseJSON( jsonResult );
            }
            // if ( jsonResult.success == false ) {
            //     return false;
            // }
            return jsonResult;
        },
        /**
         * @example
         * public class GridResult {
         *     private boolean success = true;
         *     private int totalRecords = 0;
         *     private List<?> data;
         * }
         */
        handleGridResult: function ( gridResult ) {
            return PKUI.handleJsonResult( gridResult );
        },
        /**
         * 转换树结构
         * @param options {{data: Array, rootId: string, idName: string, parentIdName: string, childrenName: string, filter: Array}}
         * @example
         * PKUI.getTreeList( {
                data: [
                    { menuId: 0, menuName: "系统管理", treeParentId: null },
                    { menuId: 1, menuName: "用户管理", treeParentId: 0 },
                    { menuId: 2, menuName: "单位管理", treeParentId: 0 }
                ],
                rootId: 0,
                idName: "menuId",
                parentIdName: "treeParentId",
                childrenName: "children"
           } );
         返回：
         [
         {
             menuId: 0, menuName: "系统管理", treeParentId: null,
             children: [
                 { menuId: 1, menuName: "用户管理", treeParentId: 0, children: null },
                 { menuId: 2, menuName: "单位管理", treeParentId: 0, children: null }
             ]
         }
         ]
         */
        getTreeList: function getTreeList( options ) {
            var
                data = options.data,
                rootId = options.rootId,
                idName = options.idName || "id",
                parentIdName = options.parentIdName || "parentId",
                childrenName = options.childrenName || "children",
                returnData,
                childrenCollection = {},
                parentId,
                rootList
                ;

            if ( !rootId ) {
                rootId = data[ 0 ][ idName ];
            }

            $.each( data, function ( index, elt ) {
                parentId = elt[ parentIdName ];
                childrenCollection[ parentId ] = childrenCollection[ parentId ] || [];
                childrenCollection[ parentId ].push( elt );
            } );

            rootList = data[ rootId ];

            if ( !$.isArray( rootList ) ) {
                rootList = [ rootList ];
            }

            returnData = fmtData( rootList );

            function fmtData( data ) {
                var list = []
                    ;
                if ( !data || !data.length ) {
                    return null;
                }
                $.each( data, function ( index, elt ) {
                    var record = elt,
                        newRecord
                        ;
                    newRecord = $.extend( {}, record );
                    newRecord[ childrenName ] = fmtData( childrenCollection[ record[ idName ] ] );
                    list.push( newRecord );
                } );
                return list;
            }

            return returnData;

        }
    } );

    /**
     * 渲染。
     *
     * 渲染的目标（在此列出全部可被自动渲染的组件）：
     *
     *

     *

     *

     *
     * 已渲染的标志（添加 isrendered="true"）：
     *
     *

     *
     *      渲染标志的添加由组件自身添加
     */
    function render() {
        var
            $component = $( "[data-" + PKUI.componentMarkupProp + "]" )
                .not('[isrendered]')
                .not( "[notrecognized='not reg']" )

            ;
        if ( PKUI.__isrendering ) {
            console.info( moment().format( "YYYY年MM月DD日 HH:MM:SS" ), "正在渲染..." );
            return;
        }
        PKUI.__renderedTimes++;

        $component.each( function () {
            var
                $this = $( this ),
                componentName = $this.data( PKUI.componentMarkupProp ),
                // jQuery自动转为JSON对象了
                componentOptions = $this.data( PKUI.optionsMarkupProp ) || {},
                componentNameList
                ;
            if ( $.trim( componentName ) === "" ) {
                return ;
            }

            if ( componentName.indexOf( "|" ) !== -1 ) {
                componentNameList = componentName.split( "|" );
            } else {
                componentNameList = [ componentName ];
            }

            if ( ! $.isArray( componentOptions ) ) {
                componentOptions = [ componentOptions ];
            }

            $.each( componentNameList, function( index, componentName ) {
                var
                    options = componentOptions[ index ] || {},
                    component = PKUI.component[ $.trim( componentName ) ],
                    moduleId = componentName
                    ;
                // 如果没有注册该组件，则载入，再初始化
                if ( !component ) {
                    switch ( componentName ) {
                        case "datagrid":
                            moduleId = "bootgrid";
                            break;
                        case "drawer":
                            moduleId = "drawer";
                            break;
                        case "form":
                            moduleId = "form";
                            break;
                        case "validator":
                            moduleId = "validator";
                            break;
                        default:
                            console.info();
                            var errorMessage = " 未被注册的组件[" + componentName + "]";
                            console.info( moment().format("YYYY年MM月DD日 HH:MM:SS"), errorMessage );
                            window.layer.msg( errorMessage );
                            $this.attr( "notrecognized", "not reg" );
                            return;
                    }
                    seajs.use( [ moduleId ], function () {
                        PKUI.component[ $.trim( componentName ) ].call( $this, options );
                    } );
                }
                // 如果已注册，则初始化
                else {
                    component.call( $this, options );
                }
            } );

        } );

        PKUI.__isrendering = false;
    }
    /**
     * 开启/关闭 自动渲染。
     *
     * 自动渲染时机：
     *
     *      1. 调用 jquery.html( value ) 方法之后
     *      2. 调用 jquery.append( value ) 方法之后
     *      3. 调用 jquery.appendTo( value ) 方法之后
     *      4. 调用 jquery.prepend( value ) 方法之后
     *      5. 调用 jquery.prependTo( value ) 方法之后
     *
     * @param isAutoRender {boolean} true-开启，false-关闭。
     *
     */
    function setAutoRender ( isAutoRender ) {

        if ( arguments.length === 0 ) {
            console.info( "/(ㄒoㄒ)/~~ 请设置参数。" );
            return;
        }

        PKUI.isAutoRender = Boolean( isAutoRender );

        if ( isAutoRender ) {

            setAutoRender.pointcutHandlerList = [

                // 1. 调用 jquery.html( value ) 方法之后
                AOP.after( $.prototype, "html", render )
                // ,

                // 2. 调用 jquery.append( value ) 方法之后
                //AOP.after( $.prototype, "append", render ),

                // 3. 调用 jquery.appendTo( value ) 方法之后
                //AOP.after( $.prototype, "appendTo", render ),

                // 4. 调用 jquery.prepend( value ) 方法之后
                //AOP.after( $.prototype, "prepend", render ),

                // 5. 调用 jquery.prependTo( value ) 方法之后
                //AOP.after( $.prototype, "prependTo", render )

            ];

        } else {

            $.each( setAutoRender.pointcutHandlerList, function ( index, pointcutHandler ) {
                pointcutHandler.remove();
            } );

        }

    }

    /**
     * 格式化 $.ajax 的 url，如果包含“__CTX__” 则，替换为 PKUI.ctxPath
     */
    function fmtAjaxUrl () {
        AOP.before( $, "ajax", function ( url, options ) {
            // If url is an object, simulate pre-1.5 signature
            if ( typeof url === "object" ) {
                options = url;
                url = undefined;
            }

            if ( options.url.indexOf( "__CTX__" ) !== -1 ) {
                options.url = options.url.replace( "__CTX__", PKUI.ctxPath );
            }
        } );
    }

    /**
     * 全局的事件处理，通过类名。
     * 类名格式：名称空间-事件类型-处理后的结果
     * @example
     *

     */
    function regGlobalEventHandler() {
        var
            eventNs = ".pkui.global"
        ;
        // 点击后，隐藏
        $doc.on( "click" + eventNs, ".pkui-click-hide", function () {
            $( this ).hide();
        } );

    }

    PKUI._init();

} );<|endoftext|>


<commit_before>var EventType = {
	join            : 1,
	leave           : 2,
	welcome         : 3,
	change_color    : 4,
	change_tool     : 5,
	mouse_move      : 6,
	mouse_up        : 7,
	mouse_down      : 8,
	chat_message    : 9,
	change_nickname : 10
}

function send_event(event){
//    console.log(event, msgpack.pack(event, true).length)
//    console.log(msgpack.unpack(msgpack.pack(event, true)), event)
    if (mySocket.readyState == 1){
//        mySocket.send(JSON.stringify(event))
        var data = msgpack.pack(event)
        var array = new Uint8Array(data.length)
        for (var i = 0; i < data.length; i++) {
          array[i] = data[i]
        }
        mySocket.send(array.buffer)
    }
}

function send_change_color(red, green, blue){
    send_event([
        EventType.change_color,
        red,
        green,
        blue
    ])
}

function send_change_tool(use_pen){
    send_event([
        EventType.change_tool,
        use_pen
    ])
    my_use_pen = use_pen
}

function send_change_nickname(nickname){
    if ((nickname != null) && (nickname.length <= MAX_NICKNAME_LENGTH)){
        send_event([
            EventType.change_nickname,
            nickname
        ])
    }
}

function send_chat_message(msg){
    if (msg != ""){
        send_event([
            EventType.chat_message,
            msg.slice(0, MAX_CHAT_MESSAGE_LENGTH) // truncate if too long
        ])
    }
}

function decode_msgpack(data){
    // Reading a blob is an async operation but we want to keep the messages in
    // order, so we have a queue of incoming messages and we decode them one at
    // a time.
    function decode(){
        is_decoding = true
        var reader = new FileReader()
        reader.onloadend = function(evt) {
            if (evt.target.readyState == FileReader.DONE) {
                var bytes = new Uint8Array(evt.target.result)
                gotmessage(msgpack.unpack(bytes))
                if (incoming_blobs.length > 0){
                    decode()
                } else {
                    is_decoding = false
                }
            }
        }
        reader.readAsArrayBuffer(incoming_blobs.shift());
    }
    incoming_blobs.push(data)
    if (!is_decoding){
        decode()
    }
}

function create_socket(){
    mySocket = new WebSocket(
        'ws' + SECURE + '://' + DOMAIN + ":" + (SECURE ? HTTPS_PORT : HTTP_PORT) + "/ws?u=" + encodeURIComponent(
            document.location.href
        )
    )
    mySocket.onmessage = function(e){decode_msgpack(e.data)}
    mySocket.onclose = function(e){
        set_error_message(e.reason)
        warning_box.style.display = "block"
    }
}

function create_canvas(){
    canvas = create_element("canvas", {
        "position"     : "absolute",
        "left"         : 0,
        "top"          : 0,
        "outline"      : "10px dashed #F30B55"
    })
    mask_canvas = create_element("canvas", {
        "position"     : "absolute",
        "cursor"       : "crosshair",
        "left"         : 0,
        "top"          : 0,
        "z-index"      : 2
    })
    canvas.width = WIDTH
    mask_canvas.width = WIDTH
    canvas.height = HEIGHT
    mask_canvas.height = HEIGHT
    frame_div.appendChild(canvas)
    frame_div.appendChild(mask_canvas)
    ctx = canvas.getContext("2d")
    mask_ctx = mask_canvas.getContext("2d")
    ctx.strokeStyle = "rgb(0,0,0)"
    mask_canvas.onmousedown = mousedown
    mask_canvas.onmouseup   = mouseup
    mask_canvas.onmousemove = mousemove
    mask_canvas.onmouseout  = mouseup
    if (document.body.onwheel === undefined) {
        // chrome
        document.body.onmousewheel = wheel
    } else {
        // firefox
        document.body.onwheel = wheel
    }
//    window.setInterval(mask_redraw, 30)
}

function set_zoom(){
        var center_x = (window.scrollX + (window.innerWidth / 2)) / document.body.scrollWidth
        var center_y = (window.scrollY + (window.innerHeight / 2)) / document.body.scrollHeight
        var zoom_str = zoom.toFixed(1)
        if (frame_div.style.transform === undefined) {
            frame_div.style.webkitTransform = "scale(" + zoom_str + ")"
        } else {
            frame_div.style.transform = "scale(" + zoom_str + ")"
        }
        var new_scrollx = document.body.scrollWidth * center_x - (window.innerWidth / 2)
        var new_scrolly = document.body.scrollHeight * center_y - (window.innerHeight / 2)
        window.scrollTo(new_scrollx, new_scrolly)
}

function wheel(event){
    if (event.altKey){
        var delta = (event.wheelDeltaY || -event.deltaY)
        if ((delta > 0) && (zoom < ZOOM_MAX)){
            zoom *= ZOOM_FACTOR
        } else if ((delta < 0) && (zoom > ZOOM_MIN)){
            zoom /= ZOOM_FACTOR
        }
        zoom_slider.value = logn(zoom, ZOOM_FACTOR)
        set_zoom()
        event.preventDefault()
        return false
    }
}

function mousemove(ev){
//    console.log(ev)
    var duration = time_since_last_time()
    if (duration < MOUSEMOVE_DELAY) return
    // offset for chrome and layer for mozilla
    var mouse_x  = ev.offsetX || ev.layerX,
        mouse_y  = ev.offsetY || ev.layerY,
        my_color
    send_event([
        EventType.mouse_move,
        mouse_x,               // x
        mouse_y,               // y
        duration               // duration
    ])
    if (my_use_pen && my_mouse_is_down && my_last_x != null){
        // anti-lag system
        my_color = get_my_color()
        mask_push([
            my_last_x, my_last_y,                              // origin
            mouse_x, mouse_y,                                  // destination
            duration,                                          // duration
            my_color[0], my_color[1], my_color[2],             // color
            true                                               // pen not eraser
        ])
    }
    my_last_x = mouse_x
    my_last_y = mouse_y
}

function mousedown(ev){
    mousemove(ev)
    send_event([EventType.mouse_down])
    my_mouse_is_down = true
    return false // prevent text selection in chrome
}

function mouseup(ev){
    send_event([EventType.mouse_up])
    my_mouse_is_down = false
    ev.stopPropagation()
}

function gotmessage(event){
    var type = event.shift(),            // event_type
        user_id, user
    if (type != EventType.welcome){
        user_id = event.shift()
        user = users[user_id]
    }
    if (type == EventType.join){
        new User(
            user_id,
            event[0], // position
            event[1], // color
            event[2], // mouse_is_down
            event[3], // you
            event[4], // nickname
            event[5]  // use_pen
        )
        if (event[6] != 0) {
            add_chat_notification("user " + event[4] + " joined ", event[6])
        }
    }else if (type == EventType.leave){
        add_chat_notification("user " + user.nickname + " left ", event[0])
        user.destroy()
    }else if (type == EventType.mouse_up){
        user.mouse_up()
    }else if (type == EventType.mouse_down){
        user.mouse_down()
    }else if (type == EventType.mouse_move){
        user.mouse_move.apply(user, event)
    }else if (type == EventType.change_color){
        user.change_color.apply(user, event)
    }else if (type == EventType.change_tool){
        user.change_tool.apply(user, event)
    }else if (type == EventType.chat_message){
        add_chat_message(user.get_label(), event[0], event[1])
    }else if (type == EventType.welcome){
        load_image("http" + SECURE + "://" + DOMAIN + ":" + (SECURE ? HTTPS_PORT : HTTP_PORT) + "/" + event[0])          // image url
        draw_delta(event[1])                                     // delta
        display_chat_log(event[2])                               // chat history
    }else if (type == EventType.change_nickname){
        user.change_nickname.apply(user, event)
    }
}

<commit_msg>allow zooming with ctrl<commit_after>var EventType = {
	join            : 1,
	leave           : 2,
	welcome         : 3,
	change_color    : 4,
	change_tool     : 5,
	mouse_move      : 6,
	mouse_up        : 7,
	mouse_down      : 8,
	chat_message    : 9,
	change_nickname : 10
}

function send_event(event){
//    console.log(event, msgpack.pack(event, true).length)
//    console.log(msgpack.unpack(msgpack.pack(event, true)), event)
    if (mySocket.readyState == 1){
//        mySocket.send(JSON.stringify(event))
        var data = msgpack.pack(event)
        var array = new Uint8Array(data.length)
        for (var i = 0; i < data.length; i++) {
          array[i] = data[i]
        }
        mySocket.send(array.buffer)
    }
}

function send_change_color(red, green, blue){
    send_event([
        EventType.change_color,
        red,
        green,
        blue
    ])
}

function send_change_tool(use_pen){
    send_event([
        EventType.change_tool,
        use_pen
    ])
    my_use_pen = use_pen
}

function send_change_nickname(nickname){
    if ((nickname != null) && (nickname.length <= MAX_NICKNAME_LENGTH)){
        send_event([
            EventType.change_nickname,
            nickname
        ])
    }
}

function send_chat_message(msg){
    if (msg != ""){
        send_event([
            EventType.chat_message,
            msg.slice(0, MAX_CHAT_MESSAGE_LENGTH) // truncate if too long
        ])
    }
}

function decode_msgpack(data){
    // Reading a blob is an async operation but we want to keep the messages in
    // order, so we have a queue of incoming messages and we decode them one at
    // a time.
    function decode(){
        is_decoding = true
        var reader = new FileReader()
        reader.onloadend = function(evt) {
            if (evt.target.readyState == FileReader.DONE) {
                var bytes = new Uint8Array(evt.target.result)
                gotmessage(msgpack.unpack(bytes))
                if (incoming_blobs.length > 0){
                    decode()
                } else {
                    is_decoding = false
                }
            }
        }
        reader.readAsArrayBuffer(incoming_blobs.shift());
    }
    incoming_blobs.push(data)
    if (!is_decoding){
        decode()
    }
}

function create_socket(){
    mySocket = new WebSocket(
        'ws' + SECURE + '://' + DOMAIN + ":" + (SECURE ? HTTPS_PORT : HTTP_PORT) + "/ws?u=" + encodeURIComponent(
            document.location.href
        )
    )
    mySocket.onmessage = function(e){decode_msgpack(e.data)}
    mySocket.onclose = function(e){
        set_error_message(e.reason)
        warning_box.style.display = "block"
    }
}

function create_canvas(){
    canvas = create_element("canvas", {
        "position"     : "absolute",
        "left"         : 0,
        "top"          : 0,
        "outline"      : "10px dashed #F30B55"
    })
    mask_canvas = create_element("canvas", {
        "position"     : "absolute",
        "cursor"       : "crosshair",
        "left"         : 0,
        "top"          : 0,
        "z-index"      : 2
    })
    canvas.width = WIDTH
    mask_canvas.width = WIDTH
    canvas.height = HEIGHT
    mask_canvas.height = HEIGHT
    frame_div.appendChild(canvas)
    frame_div.appendChild(mask_canvas)
    ctx = canvas.getContext("2d")
    mask_ctx = mask_canvas.getContext("2d")
    ctx.strokeStyle = "rgb(0,0,0)"
    mask_canvas.onmousedown = mousedown
    mask_canvas.onmouseup   = mouseup
    mask_canvas.onmousemove = mousemove
    mask_canvas.onmouseout  = mouseup
    if (document.body.onwheel === undefined) {
        // chrome
        document.body.onmousewheel = wheel
    } else {
        // firefox
        document.body.onwheel = wheel
    }
//    window.setInterval(mask_redraw, 30)
}

function set_zoom(){
        var center_x = (window.scrollX + (window.innerWidth / 2)) / document.body.scrollWidth
        var center_y = (window.scrollY + (window.innerHeight / 2)) / document.body.scrollHeight
        var zoom_str = zoom.toFixed(1)
        if (frame_div.style.transform === undefined) {
            frame_div.style.webkitTransform = "scale(" + zoom_str + ")"
        } else {
            frame_div.style.transform = "scale(" + zoom_str + ")"
        }
        var new_scrollx = document.body.scrollWidth * center_x - (window.innerWidth / 2)
        var new_scrolly = document.body.scrollHeight * center_y - (window.innerHeight / 2)
        window.scrollTo(new_scrollx, new_scrolly)
}

function wheel(event){
    if (event.altKey || event.ctrlKey){
        var delta = (event.wheelDeltaY || -event.deltaY)
        if ((delta > 0) && (zoom < ZOOM_MAX)){
            zoom *= ZOOM_FACTOR
        } else if ((delta < 0) && (zoom > ZOOM_MIN)){
            zoom /= ZOOM_FACTOR
        }
        zoom_slider.value = logn(zoom, ZOOM_FACTOR)
        set_zoom()
        event.preventDefault()
        return false
    }
}

function mousemove(ev){
//    console.log(ev)
    var duration = time_since_last_time()
    if (duration < MOUSEMOVE_DELAY) return
    // offset for chrome and layer for mozilla
    var mouse_x  = ev.offsetX || ev.layerX,
        mouse_y  = ev.offsetY || ev.layerY,
        my_color
    send_event([
        EventType.mouse_move,
        mouse_x,               // x
        mouse_y,               // y
        duration               // duration
    ])
    if (my_use_pen && my_mouse_is_down && my_last_x != null){
        // anti-lag system
        my_color = get_my_color()
        mask_push([
            my_last_x, my_last_y,                              // origin
            mouse_x, mouse_y,                                  // destination
            duration,                                          // duration
            my_color[0], my_color[1], my_color[2],             // color
            true                                               // pen not eraser
        ])
    }
    my_last_x = mouse_x
    my_last_y = mouse_y
}

function mousedown(ev){
    mousemove(ev)
    send_event([EventType.mouse_down])
    my_mouse_is_down = true
    return false // prevent text selection in chrome
}

function mouseup(ev){
    send_event([EventType.mouse_up])
    my_mouse_is_down = false
    ev.stopPropagation()
}

function gotmessage(event){
    var type = event.shift(),            // event_type
        user_id, user
    if (type != EventType.welcome){
        user_id = event.shift()
        user = users[user_id]
    }
    if (type == EventType.join){
        new User(
            user_id,
            event[0], // position
            event[1], // color
            event[2], // mouse_is_down
            event[3], // you
            event[4], // nickname
            event[5]  // use_pen
        )
        if (event[6] != 0) {
            add_chat_notification("user " + event[4] + " joined ", event[6])
        }
    }else if (type == EventType.leave){
        add_chat_notification("user " + user.nickname + " left ", event[0])
        user.destroy()
    }else if (type == EventType.mouse_up){
        user.mouse_up()
    }else if (type == EventType.mouse_down){
        user.mouse_down()
    }else if (type == EventType.mouse_move){
        user.mouse_move.apply(user, event)
    }else if (type == EventType.change_color){
        user.change_color.apply(user, event)
    }else if (type == EventType.change_tool){
        user.change_tool.apply(user, event)
    }else if (type == EventType.chat_message){
        add_chat_message(user.get_label(), event[0], event[1])
    }else if (type == EventType.welcome){
        load_image("http" + SECURE + "://" + DOMAIN + ":" + (SECURE ? HTTPS_PORT : HTTP_PORT) + "/" + event[0])          // image url
        draw_delta(event[1])                                     // delta
        display_chat_log(event[2])                               // chat history
    }else if (type == EventType.change_nickname){
        user.change_nickname.apply(user, event)
    }
}

<|endoftext|>


<commit_before>export {default as DropzoneArea} from './components/DropzoneArea';
export {default as DropzoneAreaBase} from './components/DropzoneAreaBase';
export {default as DropzoneDialog} from './components/DropzoneDialog';
<commit_msg>:sparkles: Add controlled version of 'DropzoneDialog'- exported as 'DropzoneDialogBase'<commit_after>export {default as DropzoneArea} from './components/DropzoneArea';
export {default as DropzoneAreaBase} from './components/DropzoneAreaBase';
export {default as DropzoneDialog} from './components/DropzoneDialog';
export {default as DropzoneDialogBase} from './components/DropzoneDialogBase';
<|endoftext|>


<commit_before>/**
 * Элемент, хранящий специфические для периодических изданий сведения.
 * Для каждого периодического издания вводится ID, позволяющий опознавать вышедшие в его рамках номера.
 *
 * @author dew1983@mail.ru <Suvorov Andrey M.>
 */

Ext.define(
	'FBEditor.view.form.desc.periodical.Periodical',
	{
		extend: 'FBEditor.view.form.desc.AbstractFieldContainer',
		xtype: 'form-desc-periodical',

		translateText: {
			title: 'Заголовок',
			issn: 'ISSN',
			issnError: 'Значение должно соответствовать шаблону \d{4}-\d{3}(\d|X). Например: 1748-7188',
			desc: 'Описание',
			number: 'Номер',
			year: 'Год',
			date: 'Дата'
		},

		initComponent: function ()
		{
			var me = this;

			me.items = [
				{
					xtype: 'fieldcontainer',
					layout: 'hbox',
					hideLabel: true,
					margin: '0 0 0 0',
					defaults: {
						anchor: '100%',
						flex: 1,
						xtype: 'displayfield',
						hideLabel: true,
						margin: '0 2 0 0'
					},
					items: [
						{
							value: me.translateText.title + ':',
							flex: 0,
							width: 300
						},
						{
							value: me.translateText.issn + ':'
						},
						{
							value: me.translateText.desc + ':'
						},
						{
							value: me.translateText.number + ':'
						},
						{
							value: me.translateText.year + ':'
						},
						{
							value: me.translateText.date + ':'
						},
						{
							flex: 0,
							width: 140,
							value: ''
						}
					]
				},
				{
					xtype: 'fieldcontainer',
					layout: 'hbox',
					hideLabel: true,
					combineErrors: true,
					msgTarget: 'side',
					defaults: {
						anchor: '100%',
						flex: 1,
						labelAlign: 'top',
						labelPad: '0',
						xtype: 'textfield',
						msgTarget: 'none',
						hideLabel: true,
						margin: '0 2 0 0'
					},
					plugins: {
						ptype: 'fieldcontainerreplicator',
						groupName: 'periodical',
						btnPos: 'end',
						btnStyle: 'margin: 0 0 0 2px'
					},
					items: [
						{
							xtype: 'form-desc-title',
							flex: 0,
							width: 300,
							layout: 'fit',
							allowBlank: true,
							defaults: {
								labelWidth: 175,
								labelAlign: 'right',
								margin: '0 0 2 0'
							}
						},
						{
							name: 'periodical-issn',
							regex: /^\d{4}-\d{3}(\d|X)$/,
							regexText: me.translateText.issnError,
							fieldLabel: me.translateText.issn
						},
						{
							name: 'periodical-desc',
							allowBlank: false,
							fieldLabel: me.translateText.desc
						},
						{
							xtype: 'numberfield',
							name: 'periodical-number',
							allowBlank: false,
							fieldLabel: me.translateText.number
						},
						{
							xtype: 'numberfield',
							name: 'periodical-year',
							allowBlank: false,
							fieldLabel: me.translateText.year
						},
						{
							xtype: 'datefield',
							name: 'periodical-date',
							allowBlank: false,
							fieldLabel: me.translateText.date
						}
					]
				}
			];
			me.callParent(arguments);
		}
	}
);<commit_msg>Форма описания книги: периодическое издание (убрано клонирование полей)<commit_after>/**
 * Элемент, хранящий специфические для периодических изданий сведения.
 * Для каждого периодического издания вводится ID, позволяющий опознавать вышедшие в его рамках номера.
 *
 * @author dew1983@mail.ru <Suvorov Andrey M.>
 */

Ext.define(
	'FBEditor.view.form.desc.periodical.Periodical',
	{
		extend: 'FBEditor.view.form.desc.AbstractFieldContainer',
		xtype: 'form-desc-periodical',

		translateText: {
			title: 'Заголовок',
			issn: 'ISSN',
			issnError: 'Значение должно соответствовать шаблону \d{4}-\d{3}(\d|X). Например: 1748-7188',
			desc: 'Описание',
			number: 'Номер',
			year: 'Год',
			date: 'Дата'
		},

		initComponent: function ()
		{
			var me = this;

			me.items = [
				{
					xtype: 'fieldcontainer',
					layout: 'hbox',
					hideLabel: true,
					margin: '0 0 0 0',
					defaults: {
						anchor: '100%',
						flex: 1,
						xtype: 'displayfield',
						hideLabel: true,
						margin: '0 2 0 0'
					},
					items: [
						{
							value: me.translateText.title + ':',
							flex: 0,
							width: 300
						},
						{
							value: me.translateText.issn + ':'
						},
						{
							value: me.translateText.desc + ':'
						},
						{
							value: me.translateText.number + ':'
						},
						{
							value: me.translateText.year + ':'
						},
						{
							value: me.translateText.date + ':'
						}
					]
				},
				{
					xtype: 'fieldcontainer',
					layout: 'hbox',
					hideLabel: true,
					combineErrors: true,
					msgTarget: 'side',
					defaults: {
						anchor: '100%',
						flex: 1,
						labelAlign: 'top',
						labelPad: '0',
						xtype: 'textfield',
						msgTarget: 'none',
						hideLabel: true,
						margin: '0 2 0 0'
					},
					items: [
						{
							xtype: 'form-desc-title',
							flex: 0,
							width: 300,
							layout: 'fit',
							allowBlank: true,
							defaults: {
								labelWidth: 175,
								labelAlign: 'right',
								margin: '0 0 2 0'
							}
						},
						{
							name: 'periodical-issn',
							regex: /^\d{4}-\d{3}(\d|X)$/,
							regexText: me.translateText.issnError,
							fieldLabel: me.translateText.issn
						},
						{
							name: 'periodical-desc',
							allowBlank: false,
							fieldLabel: me.translateText.desc
						},
						{
							xtype: 'numberfield',
							name: 'periodical-number',
							allowBlank: false,
							fieldLabel: me.translateText.number
						},
						{
							xtype: 'numberfield',
							name: 'periodical-year',
							allowBlank: false,
							fieldLabel: me.translateText.year
						},
						{
							xtype: 'datefield',
							name: 'periodical-date',
							allowBlank: false,
							fieldLabel: me.translateText.date
						}
					]
				}
			];
			me.callParent(arguments);
		}
	}
);<|endoftext|>


<commit_before>const ejs = require("ejs");
const fs = require("fs");
const path = require("path");
const marked = require("marked");
const hljs = require("highlightjs");
const renderer = new marked.Renderer();

//Render markdown headings.
renderer.heading = function(text, level) {
    var id = text.toLowerCase().replace(/\s/g, '-')
        .match(/[\-0-9a-zA-Z]+/g).join("");
    return `<h${level} id="${id}">

        <svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16">
            <path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path>
        </svg>
    ${text}
</h${level}>\n`;
};

//Render markdown codes to be highlighted.
renderer.code = function(code, lang, escaped) {
    return `

    ${hljs.highlightAuto(code).value}

\n`;
};

/**
 * The Controller give you a common API to return data to the underlying
 * response context, all controllers will be automatically handled by the
 * framework, which will save your work from setting HTTP routes and socket
 * events.
 */
class Controller {
    constructor(options = {}) {
        //ViewPath and defaultView will be auto set properly by the framework
        //when a request event fires.
        this.viewPath = options.viewPath || "App/Views";
        this.defaultView = options.defaultView || "index";

        //If requireAuth true, when calling the controller unauthorized, a 401
        //error will be thrown.
        this.requireAuth = false;
    }

    /**
     * Sends a view file to the response context.
     *
     * @param  {String}  tplName  [optional] The template name. Template files
     *  are stored in `App[.subdomain]/Views/`, if the filename ends with
     *  .html as its extension name, you can pass this argument without an
     *  extension name. If this argument is missing, then the `defaultView`
     *  will be used.
     *
     * @param  {Object}  vars  [optional] Additional variables passed to the
     *  template, these variables will replace the placeholders in the view
     *  file.
     *
     * @return {String} Returns a Promise, and the only argument passed to the
     *  callback of `then()` is the contents of the template with its
     *  placeholders replaced with `vars`.
     */
    view(tplName = "", vars = {}) {
        if (tplName === "" || typeof tplName == "object") {
            vars = tplName || {};
            tplName = this.defaultView;
        }
        tplName = tplName.toString();
        if (path.extname(tplName) === "")
            tplName += ".html";
        return new Promise((resolve, reject) => {
            var file = ROOT + "/" + this.viewPath + "/" + tplName;
            ejs.renderFile(file, vars, {}, (err, content) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(content);
                }
            });
        });
    }

    /**
     * Sends a view file to the response context, and parse it as a markdown
     * file.
     *
     * This method rely on the module `highlightjs`, so when displaying code
     * snippets, you need to include CSS files to the HTML page manually.
     *
     * @param  {String}  tplName  [optional] The template name. Template files
     *  are stored in `App[.subdomain]/Views/`, if the filename ends with
     *  .html as its extension name, you can pass this argument without an
     *  extension name. If this argument is missing, then the `defaultView`
     *  will be used.
     *
     * @return {String} Returns a Promise, and the only argument passed to the
     *  callback of `then()` is the parsed contents of the template.
     */
    viewMarkdown(tplName = "") {
        tplName = tplName || this.defaultView;
        if (path.extname(tplName) === "")
            tplName += ".md";
        return new Promise((resolve, reject) => {
            var file = ROOT + "/" + this.viewPath + "/" + tplName;
            fs.readFile(file, "utf8", (err, content) => {
                if (err) {
                    reject(err);
                } else {
                    content = marked(content, { renderer: renderer });
                    resolve(content);
                }
            });
        });
    }

    /**
     * Sends successful action results to the response context.
     *
     * @param  {Any}  data  The data that needs to be send.
     *
     * @param  {Number}  code  A code represented the status of the action.
     *
     * @return {Object} Returns a Promise, and the only argument passed to the
     *  callback of `then()` is a object which carries these information:
     *  - `success` Indicates if the action is successful, always true.
     *  - `data` The same `data` given above.
     *  - `code` The same `code` given above.
     */
    success(data, code = 0) {
        return new Promise(resolve => {
            resolve({
                success: true,
                data,
                code,
            });
        });
    }

    /**
     * Sends failed action results to the response context.
     *
     * @param  {Any}  msg  A message the indicates the failed reason.
     *
     * @param  {Number}  code  A code represented the status of the action.
     *
     * @return {Object} Returns a Promise, and the only argument passed to the
     *  callback of `then()` is a object which carries these information:
     *  - `success` Indicates if the action is successful, always false.
     *  - `msg` The same `msg` given above.
     *  - `code` The same `code` given above.
     */
    error(msg, code = 0) {
        return new Promise(resolve => {
            resolve({
                success: false,
                msg,
                code,
            });
        });
    }
}

module.exports = Controller;<commit_msg>Update via git.<commit_after>const ejs = require("ejs");
const fs = require("fs");
const path = require("path");
const marked = require("marked");
const hljs = require("highlightjs");
const renderer = new marked.Renderer();

//Render markdown headings.
renderer.heading = function(text, level) {
    var id = text.toLowerCase().replace(/\s/g, '-')
        .match(/[\-0-9a-zA-Z]+/g).join("");
    return `<h${level} id="${id}">

        <svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16">
            <path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path>
        </svg>
    ${text}
</h${level}>\n`;
};

//Render markdown codes to be highlighted.
renderer.code = function(code, lang, escaped) {
    return `

    ${hljs.highlightAuto(code).value}

\n`;
};

/**
 * The Controller give you a common API to return data to the underlying
 * response context, all controllers will be automatically handled by the
 * framework, which will save your work from setting HTTP routes and socket
 * events.
 */
class Controller {
    constructor(options = {}) {
        //ViewPath and defaultView will be auto set properly by the framework
        //when a request event fires.
        this.viewPath = options.viewPath || "App/Views";
        this.defaultView = options.defaultView || "index";

        //If requireAuth true, when calling the controller unauthorized, a 401
        //error will be thrown.
        this.requireAuth = false;
    }

    /**
     * Sends a view file to the response context.
     *
     * @param  {String}  tplName  [optional] The template name. Template files
     *  are stored in `App[.subdomain]/Views/`, if the filename ends with
     *  .html as its extension name, you can pass this argument without an
     *  extension name. If this argument is missing, then the `defaultView`
     *  will be used.
     *
     * @param  {Object}  vars  [optional] Additional variables passed to the
     *  template, these variables will replace the placeholders in the view
     *  file.
     *
     * @return {Promise} Returns a Promise, and the only argument passed to
     *  the callback of `then()` is the contents of the template with its
     *  placeholders replaced with `vars`.
     */
    view(tplName = "", vars = {}) {
        if (tplName === "" || typeof tplName == "object") {
            vars = tplName || {};
            tplName = this.defaultView;
        }
        tplName = tplName.toString();
        if (path.extname(tplName) === "")
            tplName += ".html";
        return new Promise((resolve, reject) => {
            var file = ROOT + "/" + this.viewPath + "/" + tplName;
            ejs.renderFile(file, vars, {}, (err, content) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(content);
                }
            });
        });
    }

    /**
     * Sends a view file to the response context, and parse it as a markdown
     * file.
     *
     * This method rely on the module `highlightjs`, so when displaying code
     * snippets, you need to include CSS files to the HTML page manually.
     *
     * @param  {String}  tplName  [optional] The template name. Template files
     *  are stored in `App[.subdomain]/Views/`, if the filename ends with
     *  .html as its extension name, you can pass this argument without an
     *  extension name. If this argument is missing, then the `defaultView`
     *  will be used.
     *
     * @return {Promise} Returns a Promise, and the only argument passed to
     *  the callback of `then()` is the parsed contents of the template.
     */
    viewMarkdown(tplName = "") {
        tplName = tplName || this.defaultView;
        if (path.extname(tplName) === "")
            tplName += ".md";
        return new Promise((resolve, reject) => {
            var file = ROOT + "/" + this.viewPath + "/" + tplName;
            fs.readFile(file, "utf8", (err, content) => {
                if (err) {
                    reject(err);
                } else {
                    content = marked(content, { renderer: renderer });
                    resolve(content);
                }
            });
        });
    }

    /**
     * Sends successful action results to the response context.
     *
     * @param  {Any}  data  The data that needs to be send.
     *
     * @param  {Number}  code  [optional] A code represented the status of the
     *  action.
     *
     * @return {Promise} Returns a Promise, and the only argument passed to
     *  the callback of `then()` is a object which carries these information:
     *  - `success` Indicates if the action is successful, always true.
     *  - `data` The same `data` given above.
     *  - `code` The same `code` given above.
     */
    success(data, code = 0) {
        return new Promise(resolve => {
            resolve({
                success: true,
                data,
                code,
            });
        });
    }

    /**
     * Sends failed action results to the response context.
     *
     * @param  {String}  msg  A message the indicates the failed reason.
     *
     * @param  {Number}  code  [optional] A code represented the status of the
     *  action.
     *
     * @return {Promise} Returns a Promise, and the only argument passed to
     *  the callback of `then()` is a object which carries these information:
     *  - `success` Indicates if the action is successful, always false.
     *  - `msg` The same `msg` given above.
     *  - `code` The same `code` given above.
     */
    error(msg, code = 0) {
        return new Promise(resolve => {
            resolve({
                success: false,
                msg,
                code,
            });
        });
    }
}

module.exports = Controller;<|endoftext|>


<commit_before>/* jshint expr: true, strict: true */
(function (factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define('bootstrap.wysihtml5', ['jquery', 'wysihtml5', 'bootstrap', 'bootstrap.wysihtml5.templates', 'bootstrap.wysihtml5.commands'], factory);
  } else {
    // Browser globals
    factory(jQuery, wysihtml5); // jshint ignore:line
  }
}(function ($, wysihtml5) {
  'use strict';
  var bsWysihtml5 = function($, wysihtml5) {

    var templates = function(key, locale, options) {
      if(wysihtml5.tpl[key]) {
        return wysihtml5.tpl[key]({locale: locale, options: options});
      }
    };

    var Wysihtml5 = function(el, options) {
      this.el = el;
      var toolbarOpts = $.extend(true, {}, defaultOptions, options);
      for(var t in toolbarOpts.customTemplates) {
        if (toolbarOpts.customTemplates.hasOwnProperty(t)) {
          wysihtml5.tpl[t] = toolbarOpts.customTemplates[t];
        }
      }
      this.toolbar = this.createToolbar(el, toolbarOpts);
      this.editor =  this.createEditor(toolbarOpts);
    };

    Wysihtml5.prototype = {

      constructor: Wysihtml5,

      createEditor: function(options) {
        options = options || {};

        // Add the toolbar to a clone of the options object so multiple instances
        // of the WYISYWG don't break because 'toolbar' is already defined
        options = $.extend(true, {}, options);
        options.toolbar = this.toolbar[0];

        var editor = new wysihtml5.Editor(this.el[0], options);

        // #30 - body is in IE 10 not created by default, which leads to nullpointer
        // 2014/02/13 - adapted to wysihtml5-0.4, does not work in IE
        if(editor.composer.editableArea.contentDocument) {
          this.addMoreShortcuts(editor,
                                editor.composer.editableArea.contentDocument.body || editor.composer.editableArea.contentDocument,
                                options.shortcuts);
        } else {
          this.addMoreShortcuts(editor, editor.composer.editableArea, options.shortcuts);
        }

        if(options && options.events) {
          for(var eventName in options.events) {
            if (options.events.hasOwnProperty(eventName)) {
              editor.on(eventName, options.events[eventName]);
            }
          }
        }

        editor.on('beforeload', this.syncBootstrapDialogEvents);
        return editor;
      },

      //sync wysihtml5 events for dialogs with bootstrap events
      syncBootstrapDialogEvents: function() {
        var editor = this;
        $.map(this.toolbar.commandMapping, function(value) {
          return [value];
        }).filter(function(commandObj) {
          return commandObj.dialog;
        }).map(function(commandObj) {
          return commandObj.dialog;
        }).forEach(function(dialog) {
          dialog.on('show', function() {
            $(this.container).modal('show');
          });
          dialog.on('hide', function() {
            $(this.container).modal('hide');
            editor.composer.focus();
          });
          $(dialog.container).on('shown.bs.modal', function () {
            $(this).find('input, select, textarea').first().focus();
          });
        });
        this.on('change_view', function() {
          $(this.toolbar.container.children).find('a.btn').not('[data-wysihtml5-action="change_view"]').toggleClass('disabled');
        });
      },

      createToolbar: function(el, options) {
        var self = this;
        var toolbar = $('<ul/>', {
          'class' : 'wysihtml5-toolbar',
          'style': 'display:none'
        });
        var culture = options.locale || defaultOptions.locale || 'en';
        if(!locale.hasOwnProperty(culture)) {
          console.debug('Locale \'' + culture + '\' not found. Available locales are: ' + Object.keys(locale) + '. Falling back to \'en\'.');
          culture = 'en';
        }
        var localeObject = $.extend(true, {}, locale.en, locale[culture]);
        for(var key in options.toolbar) {
          if(options.toolbar[key]) {
            toolbar.append(templates(key, localeObject, options));
          }
        }

        toolbar.find('a[data-wysihtml5-command="formatBlock"]').click(function(e) {
          var target = e.delegateTarget || e.target || e.srcElement,
          el = $(target),
          showformat = el.data('wysihtml5-display-format-name'),
          formatname = el.data('wysihtml5-format-name') || el.html();
          if(showformat === undefined || showformat === 'true') {
            self.toolbar.find('.current-font').text(formatname);
          }
        });

        toolbar.find('a[data-wysihtml5-command="foreColor"]').click(function(e) {
          var target = e.target || e.srcElement;
          var el = $(target);
          self.toolbar.find('.current-color').text(el.html());
        });

        this.el.before(toolbar);

        return toolbar;
      },

      addMoreShortcuts: function(editor, el, shortcuts) {
        /* some additional shortcuts */
        wysihtml5.dom.observe(el, 'keydown', function(event) {
          var keyCode  = event.keyCode,
          command  = shortcuts[keyCode];
          if ((event.ctrlKey || event.metaKey || event.altKey) && command && wysihtml5.commands[command]) {
            var commandObj = editor.toolbar.commandMapping[command + ':null'];
            if (commandObj && commandObj.dialog && !commandObj.state) {
              commandObj.dialog.show();
            } else {
              wysihtml5.commands[command].exec(editor.composer, command);
            }
            event.preventDefault();
          }
        });
      }
    };

    // these define our public api
    var methods = {
      resetDefaults: function() {
        $.fn.wysihtml5.defaultOptions = $.extend(true, {}, $.fn.wysihtml5.defaultOptionsCache);
      },
      bypassDefaults: function(options) {
        return this.each(function () {
          var $this = $(this);
          $this.data('wysihtml5', new Wysihtml5($this, options));
        });
      },
      shallowExtend: function (options) {
        var settings = $.extend({}, $.fn.wysihtml5.defaultOptions, options || {}, $(this).data());
        var that = this;
        return methods.bypassDefaults.apply(that, [settings]);
      },
      deepExtend: function(options) {
        var settings = $.extend(true, {}, $.fn.wysihtml5.defaultOptions, options || {});
        var that = this;
        return methods.bypassDefaults.apply(that, [settings]);
      },
      init: function(options) {
        var that = this;
        return methods.shallowExtend.apply(that, [options]);
      }
    };

    $.fn.wysihtml5 = function ( method ) {
      if ( methods[method] ) {
        return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
      } else if ( typeof method === 'object' || ! method ) {
        return methods.init.apply( this, arguments );
      } else {
        $.error( 'Method ' +  method + ' does not exist on jQuery.wysihtml5' );
      }
    };

    $.fn.wysihtml5.Constructor = Wysihtml5;

    var defaultOptions = $.fn.wysihtml5.defaultOptions = {
      toolbar: {
        'font-styles': true,
        'color': false,
        'emphasis': {
          'small': true
        },
        'blockquote': true,
        'lists': true,
        'html': false,
        'link': true,
        'image': true,
        'smallmodals': false
      },
      parserRules: {
        classes: {
          'wysiwyg-color-silver' : 1,
          'wysiwyg-color-gray' : 1,
          'wysiwyg-color-white' : 1,
          'wysiwyg-color-maroon' : 1,
          'wysiwyg-color-red' : 1,
          'wysiwyg-color-purple' : 1,
          'wysiwyg-color-fuchsia' : 1,
          'wysiwyg-color-green' : 1,
          'wysiwyg-color-lime' : 1,
          'wysiwyg-color-olive' : 1,
          'wysiwyg-color-yellow' : 1,
          'wysiwyg-color-navy' : 1,
          'wysiwyg-color-blue' : 1,
          'wysiwyg-color-teal' : 1,
          'wysiwyg-color-aqua' : 1,
          'wysiwyg-color-orange' : 1
        },
        tags: {
          'b':  {},
          'i':  {},
          'strong': {},
          'em': {},
          'p': {},
          'br': {},
          'ol': {},
          'ul': {},
          'li': {},
          'h1': {},
          'h2': {},
          'h3': {},
          'h4': {},
          'h5': {},
          'h6': {},
          'blockquote': {},
          'u': 1,
          'img': {
            'check_attributes': {
              'width': 'numbers',
              'alt': 'alt',
              'src': 'url',
              'height': 'numbers'
            }
          },
          'a':  {
            'check_attributes': {
              'href': 'url' // important to avoid XSS
            },
            'set_attributes': {
              'target': '_blank',
              'rel': 'nofollow'
            }
          },
          'span': 1,
          'div': 1,
          'small': 1,
          // to allow save and edit files with code tag hacks
          'code': 1,
          'pre': 1
        }
      },
      locale: 'en',
      shortcuts: {
        '83': 'small'     // S
      }
    };

    if (typeof $.fn.wysihtml5.defaultOptionsCache === 'undefined') {
      $.fn.wysihtml5.defaultOptionsCache = $.extend(true, {}, $.fn.wysihtml5.defaultOptions);
    }

    var locale = $.fn.wysihtml5.locale = {};
  };
  bsWysihtml5($, wysihtml5);
}));
<commit_msg>JSHINT<commit_after>(function (factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define('bootstrap.wysihtml5', ['jquery', 'wysihtml5', 'bootstrap', 'bootstrap.wysihtml5.templates', 'bootstrap.wysihtml5.commands'], factory);
  } else {
    // Browser globals
    factory(jQuery, wysihtml5); // jshint ignore:line
  }
}(function ($, wysihtml5) {
  'use strict';
  var bsWysihtml5 = function($, wysihtml5) {

    var templates = function(key, locale, options) {
      if(wysihtml5.tpl[key]) {
        return wysihtml5.tpl[key]({locale: locale, options: options});
      }
    };

    var Wysihtml5 = function(el, options) {
      this.el = el;
      var toolbarOpts = $.extend(true, {}, defaultOptions, options);
      for(var t in toolbarOpts.customTemplates) {
        if (toolbarOpts.customTemplates.hasOwnProperty(t)) {
          wysihtml5.tpl[t] = toolbarOpts.customTemplates[t];
        }
      }
      this.toolbar = this.createToolbar(el, toolbarOpts);
      this.editor =  this.createEditor(toolbarOpts);
    };

    Wysihtml5.prototype = {

      constructor: Wysihtml5,

      createEditor: function(options) {
        options = options || {};

        // Add the toolbar to a clone of the options object so multiple instances
        // of the WYISYWG don't break because 'toolbar' is already defined
        options = $.extend(true, {}, options);
        options.toolbar = this.toolbar[0];

        var editor = new wysihtml5.Editor(this.el[0], options);

        // #30 - body is in IE 10 not created by default, which leads to nullpointer
        // 2014/02/13 - adapted to wysihtml5-0.4, does not work in IE
        if(editor.composer.editableArea.contentDocument) {
          this.addMoreShortcuts(editor,
                                editor.composer.editableArea.contentDocument.body || editor.composer.editableArea.contentDocument,
                                options.shortcuts);
        } else {
          this.addMoreShortcuts(editor, editor.composer.editableArea, options.shortcuts);
        }

        if(options && options.events) {
          for(var eventName in options.events) {
            if (options.events.hasOwnProperty(eventName)) {
              editor.on(eventName, options.events[eventName]);
            }
          }
        }

        editor.on('beforeload', this.syncBootstrapDialogEvents);
        return editor;
      },

      //sync wysihtml5 events for dialogs with bootstrap events
      syncBootstrapDialogEvents: function() {
        var editor = this;
        $.map(this.toolbar.commandMapping, function(value) {
          return [value];
        }).filter(function(commandObj) {
          return commandObj.dialog;
        }).map(function(commandObj) {
          return commandObj.dialog;
        }).forEach(function(dialog) {
          dialog.on('show', function() {
            $(this.container).modal('show');
          });
          dialog.on('hide', function() {
            $(this.container).modal('hide');
            editor.composer.focus();
          });
          $(dialog.container).on('shown.bs.modal', function () {
            $(this).find('input, select, textarea').first().focus();
          });
        });
        this.on('change_view', function() {
          $(this.toolbar.container.children).find('a.btn').not('[data-wysihtml5-action="change_view"]').toggleClass('disabled');
        });
      },

      createToolbar: function(el, options) {
        var self = this;
        var toolbar = $('<ul/>', {
          'class' : 'wysihtml5-toolbar',
          'style': 'display:none'
        });
        var culture = options.locale || defaultOptions.locale || 'en';
        if(!locale.hasOwnProperty(culture)) {
          console.debug('Locale \'' + culture + '\' not found. Available locales are: ' + Object.keys(locale) + '. Falling back to \'en\'.');
          culture = 'en';
        }
        var localeObject = $.extend(true, {}, locale.en, locale[culture]);
        for(var key in options.toolbar) {
          if(options.toolbar[key]) {
            toolbar.append(templates(key, localeObject, options));
          }
        }

        toolbar.find('a[data-wysihtml5-command="formatBlock"]').click(function(e) {
          var target = e.delegateTarget || e.target || e.srcElement,
          el = $(target),
          showformat = el.data('wysihtml5-display-format-name'),
          formatname = el.data('wysihtml5-format-name') || el.html();
          if(showformat === undefined || showformat === 'true') {
            self.toolbar.find('.current-font').text(formatname);
          }
        });

        toolbar.find('a[data-wysihtml5-command="foreColor"]').click(function(e) {
          var target = e.target || e.srcElement;
          var el = $(target);
          self.toolbar.find('.current-color').text(el.html());
        });

        this.el.before(toolbar);

        return toolbar;
      },

      addMoreShortcuts: function(editor, el, shortcuts) {
        /* some additional shortcuts */
        wysihtml5.dom.observe(el, 'keydown', function(event) {
          var keyCode  = event.keyCode,
          command  = shortcuts[keyCode];
          if ((event.ctrlKey || event.metaKey || event.altKey) && command && wysihtml5.commands[command]) {
            var commandObj = editor.toolbar.commandMapping[command + ':null'];
            if (commandObj && commandObj.dialog && !commandObj.state) {
              commandObj.dialog.show();
            } else {
              wysihtml5.commands[command].exec(editor.composer, command);
            }
            event.preventDefault();
          }
        });
      }
    };

    // these define our public api
    var methods = {
      resetDefaults: function() {
        $.fn.wysihtml5.defaultOptions = $.extend(true, {}, $.fn.wysihtml5.defaultOptionsCache);
      },
      bypassDefaults: function(options) {
        return this.each(function () {
          var $this = $(this);
          $this.data('wysihtml5', new Wysihtml5($this, options));
        });
      },
      shallowExtend: function (options) {
        var settings = $.extend({}, $.fn.wysihtml5.defaultOptions, options || {}, $(this).data());
        var that = this;
        return methods.bypassDefaults.apply(that, [settings]);
      },
      deepExtend: function(options) {
        var settings = $.extend(true, {}, $.fn.wysihtml5.defaultOptions, options || {});
        var that = this;
        return methods.bypassDefaults.apply(that, [settings]);
      },
      init: function(options) {
        var that = this;
        return methods.shallowExtend.apply(that, [options]);
      }
    };

    $.fn.wysihtml5 = function ( method ) {
      if ( methods[method] ) {
        return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
      } else if ( typeof method === 'object' || ! method ) {
        return methods.init.apply( this, arguments );
      } else {
        $.error( 'Method ' +  method + ' does not exist on jQuery.wysihtml5' );
      }
    };

    $.fn.wysihtml5.Constructor = Wysihtml5;

    var defaultOptions = $.fn.wysihtml5.defaultOptions = {
      toolbar: {
        'font-styles': true,
        'color': false,
        'emphasis': {
          'small': true
        },
        'blockquote': true,
        'lists': true,
        'html': false,
        'link': true,
        'image': true,
        'smallmodals': false
      },
      parserRules: {
        classes: {
          'wysiwyg-color-silver' : 1,
          'wysiwyg-color-gray' : 1,
          'wysiwyg-color-white' : 1,
          'wysiwyg-color-maroon' : 1,
          'wysiwyg-color-red' : 1,
          'wysiwyg-color-purple' : 1,
          'wysiwyg-color-fuchsia' : 1,
          'wysiwyg-color-green' : 1,
          'wysiwyg-color-lime' : 1,
          'wysiwyg-color-olive' : 1,
          'wysiwyg-color-yellow' : 1,
          'wysiwyg-color-navy' : 1,
          'wysiwyg-color-blue' : 1,
          'wysiwyg-color-teal' : 1,
          'wysiwyg-color-aqua' : 1,
          'wysiwyg-color-orange' : 1
        },
        tags: {
          'b':  {},
          'i':  {},
          'strong': {},
          'em': {},
          'p': {},
          'br': {},
          'ol': {},
          'ul': {},
          'li': {},
          'h1': {},
          'h2': {},
          'h3': {},
          'h4': {},
          'h5': {},
          'h6': {},
          'blockquote': {},
          'u': 1,
          'img': {
            'check_attributes': {
              'width': 'numbers',
              'alt': 'alt',
              'src': 'url',
              'height': 'numbers'
            }
          },
          'a':  {
            'check_attributes': {
              'href': 'url' // important to avoid XSS
            },
            'set_attributes': {
              'target': '_blank',
              'rel': 'nofollow'
            }
          },
          'span': 1,
          'div': 1,
          'small': 1,
          // to allow save and edit files with code tag hacks
          'code': 1,
          'pre': 1
        }
      },
      locale: 'en',
      shortcuts: {
        '83': 'small'     // S
      }
    };

    if (typeof $.fn.wysihtml5.defaultOptionsCache === 'undefined') {
      $.fn.wysihtml5.defaultOptionsCache = $.extend(true, {}, $.fn.wysihtml5.defaultOptions);
    }

    var locale = $.fn.wysihtml5.locale = {};
  };
  bsWysihtml5($, wysihtml5);
}));
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define("ace/mode/siddhi_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function (require, exports, module) {

    "use strict";   // JS strict mode

    var oop = require("../lib/oop");
    var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;

    var SiddhiHighlightRules = function () {
        var keywords = "STREAM|DEFINE|FUNCTION|TRIGGER|TABLE|FROM|PARTITION|WINDOW|SELECT|GROUP|BY|" +
            "HAVING|ORDER|LIMIT|INSERT|DELETE|UPDATE|SET|RETURN|EVENTS|INTO|OUTPUT|EXPIRED|CURRENT|SNAPSHOT|" +
            "FOR|RAW|OF|AS|AT|OR|AND|IN|ON|IS|NOT|WITHIN|WITH|BEGIN|END|EVERY|LAST|ALL|FIRST|JOIN|" +
            "INNER|OUTER|RIGHT|LEFT|FULL|UNIDIRECTIONAL|YEAR|YEARS|MONTH|MONTHS|WEEK|WEEKS|DAY|DAYS|HOUR|HOURS|" +
            "MIN|MINUTE|MINUTES|SEC|SECOND|SECONDS|MILLISEC|MILLISECOND|MILLISECONDS|STRING|INT|LONG|FLOAT|DOUBLE|" +
            "BOOL|OBJECT|AGGREGATION|AGGREGATE|PER";

        var builtInConstants = "TRUE|FALSE|NULL";

        var builtInBooleanConstants = "TRUE|FALSE";

        var builtInTypes = "STRING|INT|LONG|FLOAT|DOUBLE|BOOL|OBJECT";

        var keywordMapper = this.createKeywordMapper({
            "keyword": keywords,
            "constant.language": builtInConstants,
            "constant.language.boolean": builtInBooleanConstants,
            "support.type": builtInTypes
        }, "identifier", true);

        this.$rules = {
            "start": [
                {
                    token: ["annotation.plan.start", "keyword.other", "annotation.plan", "keyword.other"],
                    regex: "(@\\s*[Aa][Pp][Pp]\\s*)(:)(\\s*[a-zA-Z_][a-zA-Z_0-9]*\\s*)(\\(\\s*)",
                    next: "annotation"
                },
                {
                    token: ["annotation.common.start", "keyword.other"],
                    regex: "(@\\s*[a-zA-Z_][a-zA-Z_0-9]*\\s*)(\\(\\s*)",
                    next: "annotation"
                },
                {
                    token: "comment.line",
                    regex: "--.*$"
                },
                {
                    token: "comment.block",
                    start: "/\\*",
                    end: "\\*/"
                },
                {
                    token: "string.quoted.double",
                    regex: '".*?"'
                },
                {
                    token: "string.quoted.single",
                    regex: "'.*?'"
                },
                {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                },
                {
                    token: keywordMapper,
                    regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
                },
                {
                    token: "keyword.operator",
                    regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=|->"
                },
                {
                    token: "keyword.other",
                    regex: "\\?|:|;|,|\\.|#|@|\\[|\\]"
                },
                {
                    token: "keyword.other.lparen",
                    regex: "\\("
                },
                {
                    token: "keyword.other.rparen",
                    regex: "\\)"
                },
                {
                    token: "paren.lparen",
                    regex: "{"
                },
                {
                    token: "paren.rparen",
                    regex: "}"
                },
                {
                    token: "whitespace",
                    regex: "\\s+"
                }
            ],
            "annotation": [
                {
                    token: ["annotation.common.start", "keyword.other"],
                    regex: "(@\\s*[a-zA-Z_][a-zA-Z_0-9]*\\s*)(\\(\\s*)"
                },
                {
                    token: "identifier",
                    regex: "([a-zA-Z_][a-zA-Z_0-9]*\\s*)"
                },
                {
                    token: "comment.line",
                    regex: "--.*$"
                },
                {
                    token: "comment.block",
                    start: "/\\*",
                    end: "\\*/"
                },
                {
                    token: "string.quoted.double",
                    regex: '".*?"'
                },
                {
                    token: "string.quoted.single",
                    regex: "'.*?'"
                },
                {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                },
                {
                    token: "keyword.other.annotation.mid.end",
                    regex: "\\)+\\s+,"
                },
                {
                    token: "keyword.other.annotation.full.end",
                    regex: "(\\)+\\s*)+",
                    next: "start"
                },
                {
                    token: "keyword.operator",
                    regex: "="
                },
                {
                    token: "keyword.other",
                    regex: "-|:|,|\\."
                },
                {
                    token: "whitespace",
                    regex: "\\s+"
                }
            ]
        };

        this.normalizeRules();
    };

    oop.inherits(SiddhiHighlightRules, TextHighlightRules);
    exports.SiddhiHighlightRules = SiddhiHighlightRules;
});
<commit_msg>Add triple quotes for highlighting rules<commit_after>/*
 * Copyright (c) 2014, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define("ace/mode/siddhi_highlight_rules", ["require", "exports", "module", "ace/lib/oop", "ace/mode/text_highlight_rules"], function (require, exports, module) {

    "use strict";   // JS strict mode

    var oop = require("../lib/oop");
    var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;

    var SiddhiHighlightRules = function () {
        var keywords = "STREAM|DEFINE|FUNCTION|TRIGGER|TABLE|FROM|PARTITION|WINDOW|SELECT|GROUP|BY|" +
            "HAVING|ORDER|LIMIT|INSERT|DELETE|UPDATE|SET|RETURN|EVENTS|INTO|OUTPUT|EXPIRED|CURRENT|SNAPSHOT|" +
            "FOR|RAW|OF|AS|AT|OR|AND|IN|ON|IS|NOT|WITHIN|WITH|BEGIN|END|EVERY|LAST|ALL|FIRST|JOIN|" +
            "INNER|OUTER|RIGHT|LEFT|FULL|UNIDIRECTIONAL|YEAR|YEARS|MONTH|MONTHS|WEEK|WEEKS|DAY|DAYS|HOUR|HOURS|" +
            "MIN|MINUTE|MINUTES|SEC|SECOND|SECONDS|MILLISEC|MILLISECOND|MILLISECONDS|STRING|INT|LONG|FLOAT|DOUBLE|" +
            "BOOL|OBJECT|AGGREGATION|AGGREGATE|PER";

        var builtInConstants = "TRUE|FALSE|NULL";

        var builtInBooleanConstants = "TRUE|FALSE";

        var builtInTypes = "STRING|INT|LONG|FLOAT|DOUBLE|BOOL|OBJECT";

        var keywordMapper = this.createKeywordMapper({
            "keyword": keywords,
            "constant.language": builtInConstants,
            "constant.language.boolean": builtInBooleanConstants,
            "support.type": builtInTypes
        }, "identifier", true);

        this.$rules = {
            "start": [
                {
                    token: ["annotation.plan.start", "keyword.other", "annotation.plan", "keyword.other"],
                    regex: "(@\\s*[Aa][Pp][Pp]\\s*)(:)(\\s*[a-zA-Z_][a-zA-Z_0-9]*\\s*)(\\(\\s*)",
                    next: "annotation"
                },
                {
                    token: ["annotation.common.start", "keyword.other"],
                    regex: "(@\\s*[a-zA-Z_][a-zA-Z_0-9]*\\s*)(\\(\\s*)",
                    next: "annotation"
                },
                {
                    token: "comment.line",
                    regex: "--.*$"
                },
                {
                    token: "comment.block",
                    start: "/\\*",
                    end: "\\*/"
                },
                {
                    token: "string.quoted.double.thrice",
                    start: '"""',
                    end: '"""'
                },
                {
                    token: "string.quoted.double",
                    regex: '".*?"'
                },
                {
                    token: "string.quoted.single",
                    regex: "'.*?'"
                },
                {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                },
                {
                    token: keywordMapper,
                    regex: "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
                },
                {
                    token: "keyword.operator",
                    regex: "\\+|\\-|\\/|\\/\\/|%|<@>|@>|<@|&|\\^|~|<|>|<=|=>|==|!=|<>|=|->"
                },
                {
                    token: "keyword.other",
                    regex: "\\?|:|;|,|\\.|#|@|\\[|\\]"
                },
                {
                    token: "keyword.other.lparen",
                    regex: "\\("
                },
                {
                    token: "keyword.other.rparen",
                    regex: "\\)"
                },
                {
                    token: "paren.lparen",
                    regex: "{"
                },
                {
                    token: "paren.rparen",
                    regex: "}"
                },
                {
                    token: "whitespace",
                    regex: "\\s+"
                }
            ],
            "annotation": [
                {
                    token: ["annotation.common.start", "keyword.other"],
                    regex: "(@\\s*[a-zA-Z_][a-zA-Z_0-9]*\\s*)(\\(\\s*)"
                },
                {
                    token: "identifier",
                    regex: "([a-zA-Z_][a-zA-Z_0-9]*\\s*)"
                },
                {
                    token: "comment.line",
                    regex: "--.*$"
                },
                {
                    token: "comment.block",
                    start: "/\\*",
                    end: "\\*/"
                },
                {
                    token: "string.quoted.double.thrice",
                    start: '"""',
                    end: '"""'
                },
                {
                    token: "string.quoted.double",
                    regex: '".*?"'
                },
                {
                    token: "string.quoted.single",
                    regex: "'.*?'"
                },
                {
                    token: "constant.numeric",
                    regex: "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b"
                },
                {
                    token: "keyword.other.annotation.mid.end",
                    regex: "\\)+\\s+,"
                },
                {
                    token: "keyword.other.annotation.full.end",
                    regex: "(\\)+\\s*)+",
                    next: "start"
                },
                {
                    token: "keyword.operator",
                    regex: "="
                },
                {
                    token: "keyword.other",
                    regex: "-|:|,|\\."
                },
                {
                    token: "whitespace",
                    regex: "\\s+"
                }
            ]
        };

        this.normalizeRules();
    };

    oop.inherits(SiddhiHighlightRules, TextHighlightRules);
    exports.SiddhiHighlightRules = SiddhiHighlightRules;
});
<|endoftext|>