<commit_before>//	'ws' is a URL with a handler for all chat messages
var pathArray = window.location.pathname.split( '/' );
var ws = new WebSocket( 'ws://' + window.location.host + '/chat/' + pathArray[2] + '/send/' );

ws.onopen = function() {
	ws.send( JSON.stringify({
		type: "name",
		name: $( '#name' ).val(),
	}));
};

//	Starts off as the active window
var isActive = true;

//	Set as active window when focused
window.onfocus = function () {
  isActive = true;
};

//	Unset as active window when unfocused
window.onblur = function () {
  isActive = false;
};

//Function to derive the rand & nick hue from the randString
function hueCalc( randString ) {
	var hueNum = 0;
	if ( randString ) {
		hueNum = Math.floor( randString.slice( 3, 6 ) * 359/999 );
	}
	return hueNum;
}
function colorStringCalc( randString ) {
	return 'hsl(' + hueCalc( randString ) + ',60%,40%)';
}

//	when ws recieves a message, append some html with the contents of the message
ws.onmessage = function ( event ) {
	//Date calculation into local time
	var serverTimeString = JSON.parse(event.data).time + " GMT";
	var serverTime = new Date(serverTimeString);
	var localTimeString = serverTime.toLocaleTimeString( );

	//	When a message is recieved, check the type of the message, and handle it accordingly
	switch ( JSON.parse(event.data).type ) {
		//	Server message format
		case "server":
			$( '#chatLog' ).append([
				'
',
					'[Server]: ' +
					'' + JSON.parse(event.data).text + '' ,
					'' + localTimeString + '',
				'
',
			].join( "\n" ));

			//	Play notification sound
			if ( !isActive && !!$('#notificationSounds').val() ) {
				document.getElementById('notificationTone').play();
			};
		break;

		//	User message format
		case "user":
			//Generate an HSL color from the randstring of this message
			var colorString = colorStringCalc( JSON.parse( event.data ).rand );

			//	If the user left their name blank:
			if ( JSON.parse(event.data).name === "" ) {
				$( '#chatLog' ).append([
					'
',
						'' + JSON.parse(event.data).rand + '' +
						'' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			//	If the user has a name:
			} else {
				$( '#chatLog' ).append([
					'
',
						''  + JSON.parse(event.data).rand + '' +
						''  + '[' + JSON.parse(event.data).name + ']: ' + '' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			};

			//	Play notification sound
			if ( !isActive && !!$('#notificationSounds').val() ) {
				document.getElementById('notificationTone').play();
			};
		break;
		case "userList":
			//	Remove all current entries from the user list.
			$( "#nameList>ul").empty();
			//	Split the received JSON into an array of lines.
			nameArray = JSON.parse(event.data).users.split("\n");
			//	Count the number of lines [number of users] and update the user counter to match
			$( "#userCounter" ).html(nameArray.length.toString());
			//	Add each line to the names list as an li
			for (var i = 0; i < nameArray.length; i++) {
				var colorString = colorStringCalc(nameArray[i]);
				$( "#nameList>ul").append("
" + nameArray[i] + "
");
			}
		break;
		case "keepalive":
			//	do nothing
		break;
		default:
			//	do nothing
		break;
	};

	//	this makes #chatLog scroll to the bottom after each new message is received.
	$( '#chatLog' ).scrollTop( $( '#chatLog' )[0].scrollHeight );
};

function websockSend(message) {

	//	If the outgoing message is blank, don't send anything.
	if ( message == "" ) {
		return;
	};

	//	get a new date
	var date = new Date();
	//	send a JSON of name, text, and time (date) to ws
	ws.send( JSON.stringify({
		name: $( '#name' ).val(),
		text: message,
		time: date.toString(),
		type: "message",
	}));
	// Add the sent message to your message history array so you can access it via arrow keys
	sentMessages.unshift( $( '#outgoing' ).val() );

	//	blank the outgoing message field
	$( '#outgoing' ).val( "" );
}

function getBacklog() {

}

//For up-down picking of previous messages
var sentMessages = [];
var messageInProgress = [];
var sentMessagesIndex = -1;

//Function to cycle through message history
function changeMessageIndex(increment) {
	sentMessages[sentMessagesIndex] = $( '#outgoing' ).val();
	sentMessagesIndex += increment;
	if (sentMessagesIndex >= (sentMessages.length-1)) {
		sentMessagesIndex = sentMessages.length-1;
	}
	if (sentMessagesIndex <= -1) {
		sentMessagesIndex = -1;
	}
};

$( document ).ready(function() {
	$( '#outgoing' ).keyup( function( e ) {
		// Process keystrokes in the chat input box
		switch (e.which) {
			//If it's an enter keystroke, send the message and return to the default message index.
			case 13:
				websockSend( $( '#outgoing' ).val() );
				sentMessagesIndex = -1;
				break;
			// If it's an up keystroke, try to increase the message index, and show the corresponding message in the chat box.
			case 38:
				changeMessageIndex(1);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
			// If it's a down keystroke, try to decrease the message index, and show the corresponding message in the chat box.
			case 40:
				changeMessageIndex(-1);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
		}
	});
	// Show/hide the list of users when you click the users counter.
	$( '#toggleNameList' ).click(function() {
		$( "#chatLog" ).toggleClass("chatLogShrunk");
		$( '#toggleNameList' ).toggleClass("active");
	});
	//	Every time #name changes, send a name message to the server so it can update user lists with the new name.
	$( '#name' ).change( function() {
		ws.send( JSON.stringify({
			type: "name",
			name: $( '#name' ).val(),
		}));
	});

	//	Check if the server is alive every second (all clientside)
	var serverStatusCheck = setInterval( function() {
		if ( ws.readyState === undefined || ws.readyState > 1 ) {
			$( '#disconnectOverlay' ).fadeIn( 350 );
			clearInterval( serverStatusCheck );
			clearInterval( keepalivePing );
		}
	}, 1000 );

	//	Ping the server to keep your WS alive every 20 seconds
	var keepalivePing = setInterval( function() {
		ws.send(JSON.stringify({
			type: "keepalive",
		}));
	}, 20000 );
});
<commit_msg>Moved name updating code to a function.  Added a new function for requesting backlogs that also runs on initial websocket connect.<commit_after>//	'ws' is a URL with a handler for all chat messages
var pathArray = window.location.pathname.split( '/' );
var ws = new WebSocket( 'ws://' + window.location.host + '/chat/' + pathArray[2] + '/send/' );

ws.onopen = function() {
	//Send a name packet to the server with the current name.
	nameUpdate( $( '#name' ).val() );
	//Send a backlogRequest packet to the server
	backlogRequest(128);
};

//	Starts off as the active window
var isActive = true;

//	Set as active window when focused
window.onfocus = function () {
  isActive = true;
};

//	Unset as active window when unfocused
window.onblur = function () {
  isActive = false;
};

function nameUpdate(name) {
	ws.send( JSON.stringify({
		type: "name",
		name: name,
	}));
}
function backlogRequest(amount) {
	ws.send( JSON.stringify({
		type: "backlog",
		amount: amount,
	}));
}

//Function to derive the rand & nick hue from the randString
function hueCalc( randString ) {
	var hueNum = 0;
	if ( randString ) {
		hueNum = Math.floor( randString.slice( 3, 6 ) * 359/999 );
	}
	return hueNum;
}
function colorStringCalc( randString ) {
	return 'hsl(' + hueCalc( randString ) + ',60%,40%)';
}

//	when ws recieves a message, append some html with the contents of the message
ws.onmessage = function ( event ) {
	//Date calculation into local time
	var serverTimeString = JSON.parse(event.data).time + " GMT";
	var serverTime = new Date(serverTimeString);
	var localTimeString = serverTime.toLocaleTimeString( );

	//	When a message is recieved, check the type of the message, and handle it accordingly
	switch ( JSON.parse(event.data).type ) {
		//	Server message format
		case "server":
			$( '#chatLog' ).append([
				'
',
					'[Server]: ' +
					'' + JSON.parse(event.data).text + '' ,
					'' + localTimeString + '',
				'
',
			].join( "\n" ));

			//	Play notification sound
			if ( !isActive && !!$('#notificationSounds').val() ) {
				document.getElementById('notificationTone').play();
			};
		break;

		//	User message format
		case "user":
			//Generate an HSL color from the randstring of this message
			var colorString = colorStringCalc( JSON.parse( event.data ).rand );

			//	If the user left their name blank:
			if ( JSON.parse(event.data).name === "" ) {
				$( '#chatLog' ).append([
					'
',
						'' + JSON.parse(event.data).rand + '' +
						'' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			//	If the user has a name:
			} else {
				$( '#chatLog' ).append([
					'
',
						''  + JSON.parse(event.data).rand + '' +
						''  + '[' + JSON.parse(event.data).name + ']: ' + '' +
						'' + JSON.parse(event.data).text + '' +
						'' + localTimeString + '',
					'
',
				].join( "\n" ));
			};

			//	Play notification sound
			if ( !isActive && !!$('#notificationSounds').val() ) {
				document.getElementById('notificationTone').play();
			};
		break;
		case "userList":
			//	Remove all current entries from the user list.
			$( "#nameList>ul").empty();
			//	Split the received JSON into an array of lines.
			nameArray = JSON.parse(event.data).users.split("\n");
			//	Count the number of lines [number of users] and update the user counter to match
			$( "#userCounter" ).html(nameArray.length.toString());
			//	Add each line to the names list as an li
			for (var i = 0; i < nameArray.length; i++) {
				var colorString = colorStringCalc(nameArray[i]);
				$( "#nameList>ul").append("
" + nameArray[i] + "
");
			}
		break;
		case "keepalive":
			//	do nothing
		break;
		default:
			//	do nothing
		break;
	};

	//	this makes #chatLog scroll to the bottom after each new message is received.
	$( '#chatLog' ).scrollTop( $( '#chatLog' )[0].scrollHeight );
};

function websockSend(message) {

	//	If the outgoing message is blank, don't send anything.
	if ( message == "" ) {
		return;
	};

	//	get a new date
	var date = new Date();
	//	send a JSON of name, text, and time (date) to ws
	ws.send( JSON.stringify({
		name: $( '#name' ).val(),
		text: message,
		time: date.toString(),
		type: "message",
	}));
	// Add the sent message to your message history array so you can access it via arrow keys
	sentMessages.unshift( $( '#outgoing' ).val() );

	//	blank the outgoing message field
	$( '#outgoing' ).val( "" );
}

function getBacklog() {

}

//For up-down picking of previous messages
var sentMessages = [];
var messageInProgress = [];
var sentMessagesIndex = -1;

//Function to cycle through message history
function changeMessageIndex(increment) {
	sentMessages[sentMessagesIndex] = $( '#outgoing' ).val();
	sentMessagesIndex += increment;
	if (sentMessagesIndex >= (sentMessages.length-1)) {
		sentMessagesIndex = sentMessages.length-1;
	}
	if (sentMessagesIndex <= -1) {
		sentMessagesIndex = -1;
	}
};

$( document ).ready(function() {
	$( '#outgoing' ).keyup( function( e ) {
		// Process keystrokes in the chat input box
		switch (e.which) {
			//If it's an enter keystroke, send the message and return to the default message index.
			case 13:
				websockSend( $( '#outgoing' ).val() );
				sentMessagesIndex = -1;
				break;
			// If it's an up keystroke, try to increase the message index, and show the corresponding message in the chat box.
			case 38:
				changeMessageIndex(1);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
			// If it's a down keystroke, try to decrease the message index, and show the corresponding message in the chat box.
			case 40:
				changeMessageIndex(-1);
				$( '#outgoing' ).val( sentMessages[sentMessagesIndex] );
				break;
		}
	});
	// Show/hide the list of users when you click the users counter.
	$( '#toggleNameList' ).click(function() {
		$( "#chatLog" ).toggleClass("chatLogShrunk");
		$( '#toggleNameList' ).toggleClass("active");
	});
	//	Every time #name changes, send a name message to the server so it can update user lists with the new name.
	$( '#name' ).change( function() {
		ws.send( JSON.stringify({
			type: "name",
			name: $( '#name' ).val(),
		}));
	});

	//	Check if the server is alive every second (all clientside)
	var serverStatusCheck = setInterval( function() {
		if ( ws.readyState === undefined || ws.readyState > 1 ) {
			$( '#disconnectOverlay' ).fadeIn( 350 );
			clearInterval( serverStatusCheck );
			clearInterval( keepalivePing );
		}
	}, 1000 );

	//	Ping the server to keep your WS alive every 20 seconds
	var keepalivePing = setInterval( function() {
		ws.send(JSON.stringify({
			type: "keepalive",
		}));
	}, 20000 );
});
<|endoftext|>


<commit_before>/**
 * ------------------------------------------
 * 桌面接口实现文件
 * @version  1.0
 * @author   yuqijun(yuqijun@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _   = NEJ.P,
        _o  = NEJ.O,
        _e  = _('nej.e'),
        _u  = _('nej.u'),
        _v  = _('nej.v'),
        _n  = _('nej.n'),
        _t  = _('nej.ut'),
        _p  = _('nej.cef'),
        _nt = _('nej.cef.ut');
    /**
     * 配置窗体信息
     * @see    {nej.cef._$configWindowPosition}
     * @see    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息，其他参数详情见@see指定接口配置信息
     * @return {Void}
     */
    _p._$configWindow = function(_options){
        _p._$configWindowSizeLimit(_options);
        _p._$configWindowPosition(_options);
    };
    /**
     * 配置窗体位置，对齐方式定义如下

     * 水平对齐方式：
     * [ntb]
     *   名称            |  描述
     *   ----------------------
     *   left   |  左侧对齐
     *   center |  中间对齐
     *   right  |  右侧对齐
     * [/ntb]
     *
     * 垂直对齐方式：
     * [ntb]
     *   名称              |  描述
     *   ---------------------
     *   top     |  顶部对齐
     *   center  |  中间对齐
     *   bottom  |  底部对齐
     * [/ntb]
     * @api    {nej.cef._$configWindowPosition}
     * @param  {Object} 配置信息
     * @config {String}  name     窗体名称
     * @config {Number}  width    窗体宽度
     * @config {Number}  height   窗体高度
     * @config {Boolean} topmost  窗体是否置顶
     * @config {String}  align    对齐方式，格式定义：水平对齐方式+空格+垂直对齐方式，如 left top
     * @return {Void}
     */
    _p._$configWindowPosition = (function(){
        var _reg0 = /\s+/,
            _fmap = {
                left:function(_mbox,_total){
                    return 0;
                },
                center:function(_mbox,_total){
                    return Math.floor((_total-_mbox)/2);
                },
                right:function(_mbox,_total){
                    return _total;
                }
            };
        _fmap.top = _fmap.left;
        _fmap.bottom = _fmap.right;
        return function(_options){
            _options = _options||_o;
            // set window position
            var _aligns = (_options.align||'').trim().split(_reg0),
                _position = NEJ.EX({width:0,height:0,topmost:!1},_options),
                _wkarea = (_n._$exec('os.getSystemInfo','desktop')||_o).workArea||_o;
            _position.x = (_fmap[_aligns[0]]||_fmap.center)(_position.width,_wkarea.width);
            _position.y = (_fmap[_aligns[1]]||_fmap.center)(_position.height,_wkarea.height);
            if (!_options.name){
                _n._$exec('winhelper.setWindowPosition',_position);
            }else{
                _position.name = _options.name;
                _n._$exec('winhelper.setNativeWindowRect',_position);
            }
        };
    })();
    /**
     * 配置窗体大小限制
     * @api    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     */
    _p._$configWindowSizeLimit = (function(){
        // parse min/max - width/height
        var _doParseBox = function(_width,_height){
            _width = parseInt(_width);
            _height = parseInt(_height);
            var _result;
            if (!isNaN(_width)){
                _result = _result||{};
                _result.x = _width;
            }
            if (!isNaN(_height)){
                _result = _result||{};
                _result.y = _height;
            }
            return _result;
        };
        return function(_options){
            _options = _options||_o;
            _n._$exec(
                'winhelper.setWindowSizeLimit',
                _doParseBox(_options.minWidth,_options.minHeight),
                _doParseBox(_options.maxWidth,_options.maxHeight)
            );
        };
    })();
    /**
     * 显示窗体,但窗体不会放在最上层
     * @api    {nej.cef._$showWindow}
     * @return {Void}
     */
    _p._$showWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','show');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!0);
        }
    };
    /**
     * 隐藏窗体
     * @api    {nej.cef._$hideWindow}
     * @return {Void}
     */
    _p._$hideWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','hide');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!1);
        }
    };
    /**
     * 窗口前置
     * @return {Void}
     */
    _p._$topWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.bringWindowToTop');
        }
    };
    /**
     * 打开新窗体
     * @param  {String} 新窗口地址，参数通过查询形式输入，如?width=1000&height=200
     * @return {Void}
     */
    _p._$open = (function(){
        var _doParseInt = function(_value,_key,_map){
            var _int = parseInt(_value);
            if (!isNaN(_int)){
                _map[_key] = _int;
            }else if(_value=='true'||_value=='false'){
                _map[_key] = _value=='true';
            }
        };
        return function(_url){
            // TODO parse param
            var _param = _u._$query2object(_url.split('?')[1]||'');
            _u._$forIn(_param,_doParseInt);
            _n._$exec('winhelper.launchWindow',_url,_param,_param);
        };
    })();
    /**
     * 退出应用
     * @return {Void}
     */
    _p._$exit = function(){
        _nt._$$Tray._$getInstance()._$hide();
        _n._$exec('app.exit');
    };
    /**
     * 弹出菜单
     * @param  {Array} 菜单项列表
     * @return {Void}
     */
    _p._$popMenu = (function(){
        var _xmap = {
            exit:{text:'退出',menu_id:1005,menu:!0,separator:!1,enable:!0,children:null}
        };
        var _doCheckMenu = function(_item,_index,_list){
            var _xitm = _xmap[_item];
            if (!!_xitm){
                _item = _xitm;
                _list[_index] = _item;
            }
            if (!!_item.children){
                _doCompleteMenu(_item.children);
            }
        };
        var _doCompleteMenu = function(_list){
            _u._$forEach(_list,_doCheckMenu);
        };
        return function(_menu){
            _doCompleteMenu(_menu);
            _n._$exec(
                'winhelper.popupMenu',
                JSON.stringify(_menu)
            );
        };
    })();
    // init document.onmenuacton
    _('window.winhelper').onMenuClick = function(_id){
        _v._$dispatchEvent(
            document,'menuacton',{
                mid:_id
            }
        );
    };
    _t._$$CustomEvent._$allocate({
        element:document,
        event:'menuacton'
    });
};
NEJ.define('{lib}native/cef/api.js',
          ['{lib}base/util.js'
          ,'{lib}base/element.js'
          ,'{lib}native/command.js'
          ,'{lib}util/event/event.js'
          ,'{lib}native/cef/util/tray.js'],f);<commit_msg>cef menu<commit_after>/**
 * ------------------------------------------
 * 桌面接口实现文件
 * @version  1.0
 * @author   yuqijun(yuqijun@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _   = NEJ.P,
        _o  = NEJ.O,
        _e  = _('nej.e'),
        _u  = _('nej.u'),
        _v  = _('nej.v'),
        _n  = _('nej.n'),
        _t  = _('nej.ut'),
        _p  = _('nej.cef'),
        _nt = _('nej.cef.ut');
    /**
     * 配置窗体信息
     * @see    {nej.cef._$configWindowPosition}
     * @see    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息，其他参数详情见@see指定接口配置信息
     * @return {Void}
     */
    _p._$configWindow = function(_options){
        _p._$configWindowSizeLimit(_options);
        _p._$configWindowPosition(_options);
    };
    /**
     * 配置窗体位置，对齐方式定义如下

     * 水平对齐方式：
     * [ntb]
     *   名称            |  描述
     *   ----------------------
     *   left   |  左侧对齐
     *   center |  中间对齐
     *   right  |  右侧对齐
     * [/ntb]
     *
     * 垂直对齐方式：
     * [ntb]
     *   名称              |  描述
     *   ---------------------
     *   top     |  顶部对齐
     *   center  |  中间对齐
     *   bottom  |  底部对齐
     * [/ntb]
     * @api    {nej.cef._$configWindowPosition}
     * @param  {Object} 配置信息
     * @config {String}  name     窗体名称
     * @config {Number}  width    窗体宽度
     * @config {Number}  height   窗体高度
     * @config {Boolean} topmost  窗体是否置顶
     * @config {String}  align    对齐方式，格式定义：水平对齐方式+空格+垂直对齐方式，如 left top
     * @return {Void}
     */
    _p._$configWindowPosition = (function(){
        var _reg0 = /\s+/,
            _fmap = {
                left:function(_mbox,_total){
                    return 0;
                },
                center:function(_mbox,_total){
                    return Math.floor((_total-_mbox)/2);
                },
                right:function(_mbox,_total){
                    return _total;
                }
            };
        _fmap.top = _fmap.left;
        _fmap.bottom = _fmap.right;
        return function(_options){
            _options = _options||_o;
            // set window position
            var _aligns = (_options.align||'').trim().split(_reg0),
                _position = NEJ.EX({width:0,height:0,topmost:!1},_options),
                _wkarea = (_n._$exec('os.getSystemInfo','desktop')||_o).workArea||_o;
            _position.x = (_fmap[_aligns[0]]||_fmap.center)(_position.width,_wkarea.width);
            _position.y = (_fmap[_aligns[1]]||_fmap.center)(_position.height,_wkarea.height);
            if (!_options.name){
                _n._$exec('winhelper.setWindowPosition',_position);
            }else{
                _position.name = _options.name;
                _n._$exec('winhelper.setNativeWindowRect',_position);
            }
        };
    })();
    /**
     * 配置窗体大小限制
     * @api    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     */
    _p._$configWindowSizeLimit = (function(){
        // parse min/max - width/height
        var _doParseBox = function(_width,_height){
            _width = parseInt(_width);
            _height = parseInt(_height);
            var _result;
            if (!isNaN(_width)){
                _result = _result||{};
                _result.x = _width;
            }
            if (!isNaN(_height)){
                _result = _result||{};
                _result.y = _height;
            }
            return _result;
        };
        return function(_options){
            _options = _options||_o;
            _n._$exec(
                'winhelper.setWindowSizeLimit',
                _doParseBox(_options.minWidth,_options.minHeight),
                _doParseBox(_options.maxWidth,_options.maxHeight)
            );
        };
    })();
    /**
     * 显示窗体,但窗体不会放在最上层
     * @api    {nej.cef._$showWindow}
     * @return {Void}
     */
    _p._$showWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','show');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!0);
        }
    };
    /**
     * 隐藏窗体
     * @api    {nej.cef._$hideWindow}
     * @return {Void}
     */
    _p._$hideWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.showWindow','hide');
        }else{
            _n._$exec('winhelper.setNativeWindowShow',_name,!1);
        }
    };
    /**
     * 窗口前置
     * @return {Void}
     */
    _p._$topWindow = function(_name){
        if (!_name){
            _n._$exec('winhelper.bringWindowToTop');
        }
    };
    /**
     * 打开新窗体
     * @param  {String} 新窗口地址，参数通过查询形式输入，如?width=1000&height=200
     * @return {Void}
     */
    _p._$open = (function(){
        var _doParseInt = function(_value,_key,_map){
            var _int = parseInt(_value);
            if (!isNaN(_int)){
                _map[_key] = _int;
            }else if(_value=='true'||_value=='false'){
                _map[_key] = _value=='true';
            }
        };
        return function(_url){
            // TODO parse param
            var _param = _u._$query2object(_url.split('?')[1]||'');
            _u._$forIn(_param,_doParseInt);
            _n._$exec('winhelper.launchWindow',_url,_param,_param);
        };
    })();
    /**
     * 退出应用
     * @return {Void}
     */
    _p._$exit = function(){
        _nt._$$Tray._$getInstance()._$hide();
        _n._$exec('app.exit');
    };
    /**
     * 取菜单项
     * @param  {Object} 菜单配置
     * @return {Object} 菜单项信息
     */
    _p._$getMenuItem = function(_options){
        return NEJ.X({
            text:'菜单项',
            menu:!0,
            menu_id:0,
            enable:!0,
            separator:!1,
            children:null
        },_options);
    };
    /**
     * 弹出菜单
     * @param  {Array} 菜单项列表
     * @return {Void}
     */
    _p._$popMenu = (function(){
        var _xmap = {
            exit:_p._$getMenuItem({text:'退出',menu_id:1005}),
            setting:_p._$getMenuItem({text:'设置',menu_id:1006})
        };
        var _doCheckMenu = function(_item,_index,_list){
            var _xitm = _xmap[_item];
            if (!!_xitm){
                _item = _xitm;
                _list[_index] = _item;
            }
            if (!!_item.children){
                _doCompleteMenu(_item.children);
            }
        };
        var _doCompleteMenu = function(_list){
            _u._$forEach(_list,_doCheckMenu);
        };
        return function(_menu){
            _doCompleteMenu(_menu);
            _n._$exec(
                'winhelper.popupMenu',
                JSON.stringify(_menu)
            );
        };
    })();
    // init document.onmenuacton
    _('window.winhelper').onmenuclick = function(_id){
        _v._$dispatchEvent(
            document,'menuaction',{
                id:_id
            }
        );
    };
    _t._$$CustomEvent._$allocate({
        element:document,
        event:'menuaction'
    });
};
NEJ.define('{lib}native/cef/api.js',
          ['{lib}base/util.js'
          ,'{lib}base/element.js'
          ,'{lib}native/command.js'
          ,'{lib}util/event/event.js'
          ,'{lib}native/cef/util/tray.js'],f);<|endoftext|>


<commit_before>/**
 * ------------------------------------------
 * 桌面接口实现文件
 * @version  1.0
 * @author   yuqijun(yuqijun@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _ = NEJ.P,
        _o = NEJ.O,
        _e = _('nej.e'),
        _u = _('nej.u'),
        _v = _('nej.v'),
        _n = _('nej.n'),
        _p = _('nej.cef');
    /**
     * 配置窗体信息
     * @see    {nej.cef._$configWindowPosition}
     * @see    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息，详情见@see指定接口配置信息
     * @return {Void}
     */
    _p._$configWindow = function(_options){
        _p._$configWindowSizeLimit(_options);
        _p._$configWindowPosition(_options);
    };
    /**
     * 配置窗体位置，对齐方式定义如下

     * 水平对齐方式：
     * [ntb]
     *   名称            |  描述
     *   ----------------------
     *   left   |  左侧对齐
     *   center |  中间对齐
     *   right  |  右侧对齐
     * [/ntb]
     *
     * 垂直对齐方式：
     * [ntb]
     *   名称              |  描述
     *   ---------------------
     *   top     |  顶部对齐
     *   center  |  中间对齐
     *   bottom  |  底部对齐
     * [/ntb]
     * @api    {nej.cef._$configWindowPosition}
     * @param  {Object} 配置信息
     * @config {Number}  width     窗体宽度
     * @config {Number}  height    窗体高度
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     * @config {Boolean} topmost   窗体是否置顶
     * @config {String}  align     对齐方式，格式定义：水平对齐方式+空格+垂直对齐方式，如 left top
     * @return {Void}
     */
    _p._$configWindowPosition = (function(){
        var _reg0 = /\s+/,
            _fmap = {
                left:function(_mbox,_total){
                    return 0;
                },
                center:function(_mbox,_total){
                    return Math.floor((_total-_mbox)/2);
                },
                right:function(_mbox,_total){
                    return _total;
                }
            };
        _fmap.top = _fmap.left;
        _fmap.bottom = _fmap.right;
        return function(_options){
            _options = _options||_o;
            // set window position
            var _aligns = (_options.align||'').trim().split(_reg0),
                _wkarea = (_n._$exec('os.getSystemInfo','desktop')||_o).workArea,
                _position = NEJ.EX({width:0,height:0,topmost:!1},_options);
            _position.x = (_fmap[_aligns[0]]||_fmap.center)
                          (_position.width,_wkarea.width);
            _position.y = (_fmap[_aligns[1]]||_fmap.center)
                          (_position.height,_wkarea.height);
            _n._$exec('winhelper.setWindowPosition',_position);
        };
    })();
    /**
     * 配置窗体大小限制
     * @api    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     */
    _p._$configWindowSizeLimit = (function(){
        // parse min/max - width/height
        var _doParseBox = function(_width,_height){
            _width = parseInt(_width);
            _height = parseInt(_height);
            var _result;
            if (!isNaN(_width)){
                _result = _result||{};
                _result.x = _width;
            }
            if (!isNaN(_height)){
                _result = _result||{};
                _result.y = _height;
            }
            return _result;
        };
        return function(_options){
            _options = _options||_o;
            // set window size limit
            _n._$exec(
                'winhelper.setWindowSizeLimit',
                _doParseBox(_options.minWidth,_options.minHeight),
                _doParseBox(_options.maxWidth,_options.maxHeight)
            );
        };
    })();
    /**
     * 显示窗体,但窗体不会放在最上层
     * @api    {nej.cef._$showWindow}
     * @return {Void}
     */
    _p._$showWindow = function(){
        _n._$exec('winhelper.showWindow','show');
    };

    // /**
     // * 将窗体置于最前
     // */
    // _p._$bringToTop = function() {
        // _n._$exec('winhelper.bringWindowToTop');
    // };
    // /**
     // * 隐藏窗体
     // */
    // _p._$hideWindow = function(){
        // _n._$exec('winhelper.showWindow','hide');
    // };
    // /**
     // * 程序退出
     // */
    // _p._$appExit = function(){
        // var _trayIcon = _n._$exec('app.getTrayIcon');
        // if (!!_trayIcon)
          // _trayIcon.uninstall();
        // _n._$exec('app.exit');
    // };
    // /**
     // * 获取托盘对象
     // * @return {Object}        托盘对象
     // */
    // _p._$getTrayIcon = function(){
        // return _n._$exec('app.getTrayIcon');
    // };
    // /**
     // * 程序退出
     // * @param    {Array}        菜单列表结构如下：
     // *                         [{menu:true,separator:false,text:'播放',enable:true,menu_id:1000,children:null}]
     // */
    // _p._$popMenu = function(_menu){
        // _n._$exec('winhelper.popUpMenu',JSON.stringify(_menu));
    // };
    // /**
     // * 气泡
     // * @param    {Object}    _balloonInfo
     // *                                         title        气泡标题
     // *                                         cnt            气泡内容
     // *                                         hasSound    是否播放声音
     // *                                         delay        延时多少时间
     // *                                         icon        气泡图标
     // */
    // _p._$popBalloon = function(_balloonInfo){
        // var _trayIcon = _n._$exec('app.getTrayIcon');
        // _trayIcon.popBalloon({
            // title : _balloonInfo.title,
            // text : _balloonInfo.cnt,
            // icon : _trayIcon.icon,
            // hasSound : _balloonInfo.hasSound,
            // delayTime : _balloonInfo.delay
        // });
    // };
    // /**
     // * 设置任务栏图标和任务栏title
     // * @param    _iconInfo
     // *                     url        任务栏图标地址，如果没有icon从托盘里取icon地址
     // *                     title    任务栏标题
     // */
    // _p._$setTaskIcon = function(_iconInfo){
        // if(!_iconInfo.url){
            // var _trayIcon = _n._$exec('app.getTrayIcon');
            // _n._$exec('winhelper.setWindowIconFromLocalFile', _trayIcon.icon);
        // }
        // else
            // _n._$exec('winhelper.setWindowIconFromLocalFile', _iconInfo.url);
        // _n._$exec('winhelper.setWindowTitle', _iconInfo.title||'');
    // };
    // /**
     // * 在浏览器中打开url
     // * @param    {String}    _url    网页地址,必须是网页上地址http：//开头
     // * @return    {Void}
     // */
    // _p._$openInNavigate = function(_url) {
        // _n._$exec('os.navigateExternal', _url);
    // };
    // /**
     // * 在新窗体中打开页面
     // *
     // * @param {String}
     // *            _url 页面地址
     // * @param {Object}
     // *            _info
     // *                    x         x坐标
     // *                    y         y坐标
     // *                    width     窗体宽度
     // *                    height     窗体高度
     // * @param {Object}
     // *            _setting
     // *                    visible                 打开窗体后是否可见
     // *                    resizable                 窗体是否可缩放
     // *                    taskbarButton           窗体是否要在任务栏显示
     // * @param {Boolean}
     // *            _openInNewWindow 强制在新窗体中打开
     // * @return {Obejct} 新开窗的引用
     // */
    // _p._$open = (function() {
            // var _windowHander = {};
            // return function(_url, _info, _setting, _openInNewWindow){
                // var _absoluteUrl = _u._$absolute(_url,location.href);
                // if (!!_info.center) {
                    // var _pos = _p._$getWindowPos(_info);
                    // _info.x = _pos.x;
                    // _info.y = _pos.y;
                // }
                // if (!!_openInNewWindow) {
                    // return _n._$exec('winhelper.launchWindow', _absoluteUrl, _info,
                            // _setting);
                // } else {
                    // var _page = _absoluteUrl;
                    // if (!_windowHander[_page])
                        // _windowHander[_page] = _n._$exec('winhelper.launchWindow',
                                // _absoluteUrl, _info, _setting);
                    // else if (!!_windowHander[_page] && !_windowHander[_page].location)
                        // _windowHander[_page] = _n._$exec('winhelper.launchWindow',
                                // _absoluteUrl, _info, _setting);
                    // else
                        // _windowHander[_page].location.href = _absoluteUrl;
                    // return _windowHander[_page];
                // }
        // };
    // })();
    // /**
     // * 设置开机启动
     // * @param    {String}    程序代号
     // * @param    {String}    开机启动时参数
     // * 设置后开机启动会是　xxx-startup=auto  xxx是程序名
     // */
    // _p._$setAutoRun = function(){
        // _n._$exec('app.setAutoRun', _name, _param);
    // };
    // /**
     // * 取消开机启动
     // * @return {String}    _name    程序代号
     // */
    // _p._$cancelAutoRun = function(_name){
        // _n._$exec('app.cancelAutoRun', _name);
    // };
    // /**
     // * 获取是否设置了开机启动
     // *
     // * @param {String}
     // *            _name 程序名字
     // * @param {Boolean}
     // *            是否已设置
     // */
    // _p._$getAutoRunState = function(_name) {
        // return _n._$exec('app.getAutoRunState', _name);
    // };
    // /**
     // * 移除指定域上的cookie
     // *
     // * @param {String}
     // *            _url 指定域 例：http://163.com
     // * @param {String}
     // *            _cookieName cookie名
     // */
    // _p._$removeCookie = function(_url, _cookieName) {
        // _n._$exec('browser.removeCookie', _url, _cookieName);
    // };
    // /**
     // * 移动cookie
     // *
     // * @param {String}
     // *            _fromDomain 源域 例：163.com
     // * @param {String}
     // *            _targetDomain 目标域 例：126.com
     // * @param {String}
     // *            _cookieName cookie名
     // */
    // _p._$moveCookie = function(_fromDomain, _targetDomain, _cookieName) {
        // _n._$exec('browser.moveCookie', _fromDomain, _targetDomain,
                // _cookieName);
    // };
    // /**
     // * 设置指定域上的cookie
     // *
     // * @param {String}
     // *            _url 指定域 例：http://.163.com
     // * @param {String
     // *            _cookieName cookie名
     // * @param {String}
     // *            _cookie cookie值
     // */
    // _p._$setCookie = function(_url, _cookieName, _cookie) {
        // _n._$exec('browser.setCookie', _url, _cookieName, _cookie);
    // };
    // /**
     // * 点击节点移动窗体
     // * 由于native的drag是鼠标按下时进行拖动
     // * 但native又没要在mouseup时形成一个完整的鼠标click事件，所以普通的click事件在这些节点上都是无效的
     // * 有多少个节点可以拖动，就添加多少个节点，只有事件源是这些节点的会触发拖动，事件源是他的子节点触发的不会拖动
     // * @param {Element}
     // *            _elm 节点
     // */
    // _p._$onDragWindow = (function() {
        // var _dragElm =[];
        // return function(_elm){
            // var _elm = _e._$get(_elm);
            // _dragElm.push(_elm);
            // _v._$addEvent(_elm, 'mousedown', function(_event){
                // var _elm = _v._$getElement(_event);
                // var _index = _u._$indexOf(_dragElm, _elm);
                // if (_event.which == 1 && _index != -1)
                    // _n._$exec('winhelper.dragWindow');
            // });
        // };
    // })();
    // /**
     // * 获取桌面的大小
     // *
     // * @return {Object} 桌面大小
     // */
    // _p._$geDesktopSize = function() {
        // var _position = _n._$exec('os.getSystemInfo', 'desktop');
        // if(!!_position)
            // return;
        // else
            // return _position.workArea;
    // };
    // /**
     // * 获取当前窗体的位置信息
     // *
     // * @returns {Object} _info height 窗体高度 width 窗体宽度 x 窗体x坐标 y 窗体y坐标
     // */
    // _p._$getWindowInfo = function() {
        // var _info = _n._$exec('winhelper.getWindowPosition');
        // return _info;
    // };
};
NEJ.define('{lib}native/cef/api.js', ['{lib}native/command.js','{lib}base/util.js','{lib}base/element.js'], f);<commit_msg>set default workarea<commit_after>/**
 * ------------------------------------------
 * 桌面接口实现文件
 * @version  1.0
 * @author   yuqijun(yuqijun@corp.netease.com)
 * ------------------------------------------
 */
var f = function() {
    // variable declaration
    var _ = NEJ.P,
        _o = NEJ.O,
        _e = _('nej.e'),
        _u = _('nej.u'),
        _v = _('nej.v'),
        _n = _('nej.n'),
        _p = _('nej.cef');
    /**
     * 配置窗体信息
     * @see    {nej.cef._$configWindowPosition}
     * @see    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息，详情见@see指定接口配置信息
     * @return {Void}
     */
    _p._$configWindow = function(_options){
        _p._$configWindowSizeLimit(_options);
        _p._$configWindowPosition(_options);
    };
    /**
     * 配置窗体位置，对齐方式定义如下

     * 水平对齐方式：
     * [ntb]
     *   名称            |  描述
     *   ----------------------
     *   left   |  左侧对齐
     *   center |  中间对齐
     *   right  |  右侧对齐
     * [/ntb]
     *
     * 垂直对齐方式：
     * [ntb]
     *   名称              |  描述
     *   ---------------------
     *   top     |  顶部对齐
     *   center  |  中间对齐
     *   bottom  |  底部对齐
     * [/ntb]
     * @api    {nej.cef._$configWindowPosition}
     * @param  {Object} 配置信息
     * @config {Number}  width     窗体宽度
     * @config {Number}  height    窗体高度
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     * @config {Boolean} topmost   窗体是否置顶
     * @config {String}  align     对齐方式，格式定义：水平对齐方式+空格+垂直对齐方式，如 left top
     * @return {Void}
     */
    _p._$configWindowPosition = (function(){
        var _reg0 = /\s+/,
            _fmap = {
                left:function(_mbox,_total){
                    return 0;
                },
                center:function(_mbox,_total){
                    return Math.floor((_total-_mbox)/2);
                },
                right:function(_mbox,_total){
                    return _total;
                }
            };
        _fmap.top = _fmap.left;
        _fmap.bottom = _fmap.right;
        return function(_options){
            _options = _options||_o;
            // set window position
            var _aligns = (_options.align||'').trim().split(_reg0),
                _position = NEJ.EX({width:0,height:0,topmost:!1},_options),
                _wkarea = (_n._$exec('os.getSystemInfo','desktop')||_o).workArea||_o;
            _position.x = (_fmap[_aligns[0]]||_fmap.center)
                          (_position.width,_wkarea.width);
            _position.y = (_fmap[_aligns[1]]||_fmap.center)
                          (_position.height,_wkarea.height);
            _n._$exec('winhelper.setWindowPosition',_position);
        };
    })();
    /**
     * 配置窗体大小限制
     * @api    {nej.cef._$configWindowSizeLimit}
     * @param  {Object} 配置信息
     * @config {Number}  minWidth  窗体最小宽度
     * @config {Number}  maxWidth  窗体最大宽度
     * @config {Number}  minHeight 窗体最小高度
     * @config {Number}  maxHeight 窗体最大高度
     */
    _p._$configWindowSizeLimit = (function(){
        // parse min/max - width/height
        var _doParseBox = function(_width,_height){
            _width = parseInt(_width);
            _height = parseInt(_height);
            var _result;
            if (!isNaN(_width)){
                _result = _result||{};
                _result.x = _width;
            }
            if (!isNaN(_height)){
                _result = _result||{};
                _result.y = _height;
            }
            return _result;
        };
        return function(_options){
            _options = _options||_o;
            // set window size limit
            _n._$exec(
                'winhelper.setWindowSizeLimit',
                _doParseBox(_options.minWidth,_options.minHeight),
                _doParseBox(_options.maxWidth,_options.maxHeight)
            );
        };
    })();
    /**
     * 显示窗体,但窗体不会放在最上层
     * @api    {nej.cef._$showWindow}
     * @return {Void}
     */
    _p._$showWindow = function(){
        _n._$exec('winhelper.showWindow','show');
    };

    // /**
     // * 将窗体置于最前
     // */
    // _p._$bringToTop = function() {
        // _n._$exec('winhelper.bringWindowToTop');
    // };
    // /**
     // * 隐藏窗体
     // */
    // _p._$hideWindow = function(){
        // _n._$exec('winhelper.showWindow','hide');
    // };
    // /**
     // * 程序退出
     // */
    // _p._$appExit = function(){
        // var _trayIcon = _n._$exec('app.getTrayIcon');
        // if (!!_trayIcon)
          // _trayIcon.uninstall();
        // _n._$exec('app.exit');
    // };
    // /**
     // * 获取托盘对象
     // * @return {Object}        托盘对象
     // */
    // _p._$getTrayIcon = function(){
        // return _n._$exec('app.getTrayIcon');
    // };
    // /**
     // * 程序退出
     // * @param    {Array}        菜单列表结构如下：
     // *                         [{menu:true,separator:false,text:'播放',enable:true,menu_id:1000,children:null}]
     // */
    // _p._$popMenu = function(_menu){
        // _n._$exec('winhelper.popUpMenu',JSON.stringify(_menu));
    // };
    // /**
     // * 气泡
     // * @param    {Object}    _balloonInfo
     // *                                         title        气泡标题
     // *                                         cnt            气泡内容
     // *                                         hasSound    是否播放声音
     // *                                         delay        延时多少时间
     // *                                         icon        气泡图标
     // */
    // _p._$popBalloon = function(_balloonInfo){
        // var _trayIcon = _n._$exec('app.getTrayIcon');
        // _trayIcon.popBalloon({
            // title : _balloonInfo.title,
            // text : _balloonInfo.cnt,
            // icon : _trayIcon.icon,
            // hasSound : _balloonInfo.hasSound,
            // delayTime : _balloonInfo.delay
        // });
    // };
    // /**
     // * 设置任务栏图标和任务栏title
     // * @param    _iconInfo
     // *                     url        任务栏图标地址，如果没有icon从托盘里取icon地址
     // *                     title    任务栏标题
     // */
    // _p._$setTaskIcon = function(_iconInfo){
        // if(!_iconInfo.url){
            // var _trayIcon = _n._$exec('app.getTrayIcon');
            // _n._$exec('winhelper.setWindowIconFromLocalFile', _trayIcon.icon);
        // }
        // else
            // _n._$exec('winhelper.setWindowIconFromLocalFile', _iconInfo.url);
        // _n._$exec('winhelper.setWindowTitle', _iconInfo.title||'');
    // };
    // /**
     // * 在浏览器中打开url
     // * @param    {String}    _url    网页地址,必须是网页上地址http：//开头
     // * @return    {Void}
     // */
    // _p._$openInNavigate = function(_url) {
        // _n._$exec('os.navigateExternal', _url);
    // };
    // /**
     // * 在新窗体中打开页面
     // *
     // * @param {String}
     // *            _url 页面地址
     // * @param {Object}
     // *            _info
     // *                    x         x坐标
     // *                    y         y坐标
     // *                    width     窗体宽度
     // *                    height     窗体高度
     // * @param {Object}
     // *            _setting
     // *                    visible                 打开窗体后是否可见
     // *                    resizable                 窗体是否可缩放
     // *                    taskbarButton           窗体是否要在任务栏显示
     // * @param {Boolean}
     // *            _openInNewWindow 强制在新窗体中打开
     // * @return {Obejct} 新开窗的引用
     // */
    // _p._$open = (function() {
            // var _windowHander = {};
            // return function(_url, _info, _setting, _openInNewWindow){
                // var _absoluteUrl = _u._$absolute(_url,location.href);
                // if (!!_info.center) {
                    // var _pos = _p._$getWindowPos(_info);
                    // _info.x = _pos.x;
                    // _info.y = _pos.y;
                // }
                // if (!!_openInNewWindow) {
                    // return _n._$exec('winhelper.launchWindow', _absoluteUrl, _info,
                            // _setting);
                // } else {
                    // var _page = _absoluteUrl;
                    // if (!_windowHander[_page])
                        // _windowHander[_page] = _n._$exec('winhelper.launchWindow',
                                // _absoluteUrl, _info, _setting);
                    // else if (!!_windowHander[_page] && !_windowHander[_page].location)
                        // _windowHander[_page] = _n._$exec('winhelper.launchWindow',
                                // _absoluteUrl, _info, _setting);
                    // else
                        // _windowHander[_page].location.href = _absoluteUrl;
                    // return _windowHander[_page];
                // }
        // };
    // })();
    // /**
     // * 设置开机启动
     // * @param    {String}    程序代号
     // * @param    {String}    开机启动时参数
     // * 设置后开机启动会是　xxx-startup=auto  xxx是程序名
     // */
    // _p._$setAutoRun = function(){
        // _n._$exec('app.setAutoRun', _name, _param);
    // };
    // /**
     // * 取消开机启动
     // * @return {String}    _name    程序代号
     // */
    // _p._$cancelAutoRun = function(_name){
        // _n._$exec('app.cancelAutoRun', _name);
    // };
    // /**
     // * 获取是否设置了开机启动
     // *
     // * @param {String}
     // *            _name 程序名字
     // * @param {Boolean}
     // *            是否已设置
     // */
    // _p._$getAutoRunState = function(_name) {
        // return _n._$exec('app.getAutoRunState', _name);
    // };
    // /**
     // * 移除指定域上的cookie
     // *
     // * @param {String}
     // *            _url 指定域 例：http://163.com
     // * @param {String}
     // *            _cookieName cookie名
     // */
    // _p._$removeCookie = function(_url, _cookieName) {
        // _n._$exec('browser.removeCookie', _url, _cookieName);
    // };
    // /**
     // * 移动cookie
     // *
     // * @param {String}
     // *            _fromDomain 源域 例：163.com
     // * @param {String}
     // *            _targetDomain 目标域 例：126.com
     // * @param {String}
     // *            _cookieName cookie名
     // */
    // _p._$moveCookie = function(_fromDomain, _targetDomain, _cookieName) {
        // _n._$exec('browser.moveCookie', _fromDomain, _targetDomain,
                // _cookieName);
    // };
    // /**
     // * 设置指定域上的cookie
     // *
     // * @param {String}
     // *            _url 指定域 例：http://.163.com
     // * @param {String
     // *            _cookieName cookie名
     // * @param {String}
     // *            _cookie cookie值
     // */
    // _p._$setCookie = function(_url, _cookieName, _cookie) {
        // _n._$exec('browser.setCookie', _url, _cookieName, _cookie);
    // };
    // /**
     // * 点击节点移动窗体
     // * 由于native的drag是鼠标按下时进行拖动
     // * 但native又没要在mouseup时形成一个完整的鼠标click事件，所以普通的click事件在这些节点上都是无效的
     // * 有多少个节点可以拖动，就添加多少个节点，只有事件源是这些节点的会触发拖动，事件源是他的子节点触发的不会拖动
     // * @param {Element}
     // *            _elm 节点
     // */
    // _p._$onDragWindow = (function() {
        // var _dragElm =[];
        // return function(_elm){
            // var _elm = _e._$get(_elm);
            // _dragElm.push(_elm);
            // _v._$addEvent(_elm, 'mousedown', function(_event){
                // var _elm = _v._$getElement(_event);
                // var _index = _u._$indexOf(_dragElm, _elm);
                // if (_event.which == 1 && _index != -1)
                    // _n._$exec('winhelper.dragWindow');
            // });
        // };
    // })();
    // /**
     // * 获取桌面的大小
     // *
     // * @return {Object} 桌面大小
     // */
    // _p._$geDesktopSize = function() {
        // var _position = _n._$exec('os.getSystemInfo', 'desktop');
        // if(!!_position)
            // return;
        // else
            // return _position.workArea;
    // };
    // /**
     // * 获取当前窗体的位置信息
     // *
     // * @returns {Object} _info height 窗体高度 width 窗体宽度 x 窗体x坐标 y 窗体y坐标
     // */
    // _p._$getWindowInfo = function() {
        // var _info = _n._$exec('winhelper.getWindowPosition');
        // return _info;
    // };
};
NEJ.define('{lib}native/cef/api.js', ['{lib}native/command.js','{lib}base/util.js','{lib}base/element.js'], f);<|endoftext|>


<commit_before>Template.stevia.helpers({
    'service': function(){
        // var currentUserId = Meteor.userId();
        // but I think is not needed because the data is already filtered for the logged user
        return ServicesList.find({}, {sort: {dueDateService: -1, serviceName: 1}});
    },
   'selectedClass': function(){
   	   var serviceId = this._id;
   	   // console.log(serviceId);
   	   var selectedService = Session.get('selectedService');
   	   if(serviceId == selectedService){
   	   return "selected" }
   } ,
   'numberOfServices': function(){
   return ServicesList.find().count();
   },
   'showSelectedService': function(){
   	   var selectedService = Session.get('selectedService');
   	   return ServicesList.findOne(selectedService)
}
  });

  Template.stevia.events({
    'click .service': function(){
        var serviceId = this._id;
        Session.set('selectedService', serviceId);
        // console.log(serviceId);
    },
       'dblclick .service': function(){
      console.log("You DOUBLE clicked a .service element");
    },
    //   'mouseover .player': function(){
    //  console.log("The mouse is over a .player element");
    // }
    'click .increment': function(){
    	var selectedPlayer = Session.get('selectedPlayer');
    	// PlayersList.update(selectedPlayer, {$inc: {score: 5} });
    	Meteor.call('modifyPlayerScore', selectedPlayer, 5);
    },
       'click .decrement': function(){
    	var selectedPlayer = Session.get('selectedPlayer');
    	//PlayersList.update(selectedPlayer, {$inc: {score: -5} });
    	Meteor.call('modifyPlayerScore', selectedPlayer, -5);
    },
    'click .remove': function(){
    	var selectedService = Session.get('selectedService');

    	if (confirm('Are you sure?')) {
 	//PlayersList.remove(selectedPlayer);
 	Meteor.call('removeService', selectedService);
 		}
    }

  });
  Template.addServiceForm.events({
  'submit form': function(event){
  	  event.preventDefault();
  	  var typeOfServiceVar = event.target.typeOfService.value;
  	  console.log(typeOfServiceVar);
  	  var serviceNameVar = event.target.serviceName.value;
  	  var dueDateServiceVar = event.target.dueDateService.value;
  	  var customerNameVar = event.target.customerName.value;
  	  var customerEmailVar = event.target.customerEmail.value;
  	  var customerPhoneVar = event.target.customerPhone.value;
  	  var customerMobilePhoneVar = event.target.customerMobilePhone.value;

  	 Meteor.call('insertService', typeOfService, serviceName, dueDateService, customerName, customerEmail, customerPhone, customerMobilePhone);
  	 event.target.typeOfService.value = '';
  	 event.target.serviceName.value = '';
  	 event.target.dueDateService.value = '';
  	 event.target.customerName.value = '';
  	 event.target.customerEmail.value = '';
  	 event.target.customerPhone.value = 0;
  	 event.target.customerMobilePhone.value = 0;
  	}
  });

  Meteor.subscribe('theServices');<commit_msg>Fixed the adding of new record!<commit_after>Template.stevia.helpers({
    'service': function(){
        // var currentUserId = Meteor.userId();
        // but I think is not needed because the data is already filtered for the logged user
        return ServicesList.find({}, {sort: {dueDateService: -1, serviceName: 1}});
    },
   'selectedClass': function(){
   	   var serviceId = this._id;
   	   // console.log(serviceId);
   	   var selectedService = Session.get('selectedService');
   	   if(serviceId == selectedService){
   	   return "selected" }
   } ,
   'numberOfServices': function(){
   return ServicesList.find().count();
   },
   'showSelectedService': function(){
   	   var selectedService = Session.get('selectedService');
   	   return ServicesList.findOne(selectedService)
}
  });

  Template.stevia.events({
    'click .service': function(){
        var serviceId = this._id;
        Session.set('selectedService', serviceId);
        // console.log(serviceId);
    },
       'dblclick .service': function(){
      console.log("You DOUBLE clicked a .service element");
    },
    //   'mouseover .player': function(){
    //  console.log("The mouse is over a .player element");
    // }
    'click .increment': function(){
    	var selectedPlayer = Session.get('selectedPlayer');
    	// PlayersList.update(selectedPlayer, {$inc: {score: 5} });
    	Meteor.call('modifyPlayerScore', selectedPlayer, 5);
    },
       'click .decrement': function(){
    	var selectedPlayer = Session.get('selectedPlayer');
    	//PlayersList.update(selectedPlayer, {$inc: {score: -5} });
    	Meteor.call('modifyPlayerScore', selectedPlayer, -5);
    },
    'click .remove': function(){
    	var selectedService = Session.get('selectedService');

    	if (confirm('Are you sure?')) {
 	//PlayersList.remove(selectedPlayer);
 	Meteor.call('removeService', selectedService);
 		}
    }

  });
  Template.addServiceForm.events({
  'submit form': function(event){
  	  event.preventDefault();
  	  var typeOfServiceVar = event.target.typeOfService.value;
  	  var serviceNameVar = event.target.serviceName.value;
  	  var dueDateServiceVar = event.target.dueDateService.value;
  	  var customerNameVar = event.target.customerName.value;
  	  var customerEmailVar = event.target.customerEmail.value;
  	  var customerPhoneVar = event.target.customerPhone.value;
  	  var customerMobilePhoneVar = event.target.customerMobilePhone.value;

  	 Meteor.call('insertService', typeOfServiceVar, serviceNameVar, dueDateServiceVar, customerNameVar, customerEmailVar, customerPhoneVar, customerMobilePhoneVar);
  	 event.target.typeOfService.value = '';
  	 event.target.serviceName.value = '';
  	 event.target.dueDateService.value = '';
  	 event.target.customerName.value = '';
  	 event.target.customerEmail.value = '';
  	 event.target.customerPhone.value = 0;
  	 event.target.customerMobilePhone.value = 0;
  	}
  });

  Meteor.subscribe('theServices');<|endoftext|>


<commit_before>/* @flow strict-local */
import React, { PureComponent } from 'react';
import { View } from 'react-native';

import type { Context } from '../types';
import { Label, Touchable } from '../common';
import Icon from '../common/Icons';

type Props = {
  name: string,
  icon: string,
  onPress: () => void,
};

export default class SidebarRow extends PureComponent<Props> {
  context: Context;
  props: Props;

  static contextTypes = {
    styles: () => null,
  };

  render() {
    const { styles } = this.context;
    const { onPress, name, icon } = this.props;

    return (
      <Touchable onPress={onPress}>
        <View style={styles.item}>
          <Icon style={styles.icon} name={icon} />
          <Label text={name} />
        </View>
      </Touchable>
    );
  }
}
<commit_msg>nav: Remove unused component SidebarRow.<commit_after><|endoftext|>


<commit_before>'use strict';

var execall = require('regexp.execall');

module.exports = function (text) {
  return execall(/ \w{1,2} /g, text).map(function (match) {
    return match.index + match[0].length - 1;
  });
};
<commit_msg>Skip groups of more than one space<commit_after>'use strict';

var execall = require('regexp.execall');

module.exports = function (text) {
  return execall(/ \w{1,2} [^ ]/g, text).map(function (match) {
    return match.index + match[0].length - 2;
  });
};
<|endoftext|>


<commit_before>import { reject } from './helpers/array-helpers';

function trimQueryPartFromURL(url) {
  const queryIndex = url.indexOf('?');
  return queryIndex >= 0 ? url.slice(0, queryIndex) : url;
}

/*
 * The network bridge is a way for the mock websocket object to 'communicate' with
 * all available servers. This is a singleton object so it is important that you
 * clean up urlMap whenever you are finished.
 */
class NetworkBridge {
  constructor() {
    this.urlMap = {};
  }

  /*
   * Attaches a websocket object to the urlMap hash so that it can find the server
   * it is connected to and the server in turn can find it.
   *
   * @param {object} websocket - websocket object to add to the urlMap hash
   * @param {string} url
   */
  attachWebSocket(websocket, url) {
    const serverURL = trimQueryPartFromURL(url);
    const connectionLookup = this.urlMap[serverURL];

    if (connectionLookup && connectionLookup.server && connectionLookup.websockets.indexOf(websocket) === -1) {
      connectionLookup.websockets.push(websocket);
      return connectionLookup.server;
    }
  }

  /*
   * Attaches a websocket to a room
   */
  addMembershipToRoom(websocket, room) {
    const connectionLookup = this.urlMap[trimQueryPartFromURL(websocket.url)];

    if (connectionLookup && connectionLookup.server && connectionLookup.websockets.indexOf(websocket) !== -1) {
      if (!connectionLookup.roomMemberships[room]) {
        connectionLookup.roomMemberships[room] = [];
      }

      connectionLookup.roomMemberships[room].push(websocket);
    }
  }

  /*
   * Attaches a server object to the urlMap hash so that it can find a websockets
   * which are connected to it and so that websockets can in turn can find it.
   *
   * @param {object} server - server object to add to the urlMap hash
   * @param {string} url
   */
  attachServer(server, url) {
    const connectionLookup = this.urlMap[url];

    if (!connectionLookup) {
      this.urlMap[url] = {
        server,
        websockets: [],
        roomMemberships: {}
      };

      return server;
    }
  }

  /*
   * Finds the server which is 'running' on the given url.
   *
   * @param {string} url - the url to use to find which server is running on it
   */
  serverLookup(url) {
    const serverURL = trimQueryPartFromURL(url);
    const connectionLookup = this.urlMap[serverURL];

    if (connectionLookup) {
      return connectionLookup.server;
    }
  }

  /*
   * Finds all websockets which is 'listening' on the given url.
   *
   * @param {string} url - the url to use to find all websockets which are associated with it
   * @param {string} room - if a room is provided, will only return sockets in this room
   * @param {class} broadcaster - socket that is broadcasting and is to be excluded from the lookup
   */
  websocketsLookup(url, room, broadcaster) {
    const serverURL = trimQueryPartFromURL(url);
    let websockets;
    const connectionLookup = this.urlMap[serverURL];

    websockets = connectionLookup ? connectionLookup.websockets : [];

    if (room) {
      const members = connectionLookup.roomMemberships[room];
      websockets = members || [];
    }

    return broadcaster ? websockets.filter(websocket => websocket !== broadcaster) : websockets;
  }

  /*
   * Removes the entry associated with the url.
   *
   * @param {string} url
   */
  removeServer(url) {
    delete this.urlMap[trimQueryPartFromURL(url)];
  }

  /*
   * Removes the individual websocket from the map of associated websockets.
   *
   * @param {object} websocket - websocket object to remove from the url map
   * @param {string} url
   */
  removeWebSocket(websocket, url) {
    const serverURL = trimQueryPartFromURL(url);
    const connectionLookup = this.urlMap[serverURL];

    if (connectionLookup) {
      connectionLookup.websockets = reject(connectionLookup.websockets, socket => socket === websocket);
    }
  }

  /*
   * Removes a websocket from a room
   */
  removeMembershipFromRoom(websocket, room) {
    const connectionLookup = this.urlMap[trimQueryPartFromURL(websocket.url)];
    const memberships = connectionLookup.roomMemberships[room];

    if (connectionLookup && memberships !== null) {
      connectionLookup.roomMemberships[room] = reject(memberships, socket => socket === websocket);
    }
  }
}

export default new NetworkBridge(); // Note: this is a singleton
<commit_msg>trim query params for attachServer method lookup<commit_after>import { reject } from './helpers/array-helpers';

function trimQueryPartFromURL(url) {
  const queryIndex = url.indexOf('?');
  return queryIndex >= 0 ? url.slice(0, queryIndex) : url;
}

/*
 * The network bridge is a way for the mock websocket object to 'communicate' with
 * all available servers. This is a singleton object so it is important that you
 * clean up urlMap whenever you are finished.
 */
class NetworkBridge {
  constructor() {
    this.urlMap = {};
  }

  /*
   * Attaches a websocket object to the urlMap hash so that it can find the server
   * it is connected to and the server in turn can find it.
   *
   * @param {object} websocket - websocket object to add to the urlMap hash
   * @param {string} url
   */
  attachWebSocket(websocket, url) {
    const serverURL = trimQueryPartFromURL(url);
    const connectionLookup = this.urlMap[serverURL];

    if (connectionLookup && connectionLookup.server && connectionLookup.websockets.indexOf(websocket) === -1) {
      connectionLookup.websockets.push(websocket);
      return connectionLookup.server;
    }
  }

  /*
   * Attaches a websocket to a room
   */
  addMembershipToRoom(websocket, room) {
    const connectionLookup = this.urlMap[trimQueryPartFromURL(websocket.url)];

    if (connectionLookup && connectionLookup.server && connectionLookup.websockets.indexOf(websocket) !== -1) {
      if (!connectionLookup.roomMemberships[room]) {
        connectionLookup.roomMemberships[room] = [];
      }

      connectionLookup.roomMemberships[room].push(websocket);
    }
  }

  /*
   * Attaches a server object to the urlMap hash so that it can find a websockets
   * which are connected to it and so that websockets can in turn can find it.
   *
   * @param {object} server - server object to add to the urlMap hash
   * @param {string} url
   */
  attachServer(server, url) {
    const serverUrl = trimQueryPartFromURL(url);
    const connectionLookup = this.urlMap[serverUrl];

    if (!connectionLookup) {
      this.urlMap[serverUrl] = {
        server,
        websockets: [],
        roomMemberships: {}
      };

      return server;
    }
  }

  /*
   * Finds the server which is 'running' on the given url.
   *
   * @param {string} url - the url to use to find which server is running on it
   */
  serverLookup(url) {
    const serverURL = trimQueryPartFromURL(url);
    const connectionLookup = this.urlMap[serverURL];

    if (connectionLookup) {
      return connectionLookup.server;
    }
  }

  /*
   * Finds all websockets which is 'listening' on the given url.
   *
   * @param {string} url - the url to use to find all websockets which are associated with it
   * @param {string} room - if a room is provided, will only return sockets in this room
   * @param {class} broadcaster - socket that is broadcasting and is to be excluded from the lookup
   */
  websocketsLookup(url, room, broadcaster) {
    const serverURL = trimQueryPartFromURL(url);
    let websockets;
    const connectionLookup = this.urlMap[serverURL];

    websockets = connectionLookup ? connectionLookup.websockets : [];

    if (room) {
      const members = connectionLookup.roomMemberships[room];
      websockets = members || [];
    }

    return broadcaster ? websockets.filter(websocket => websocket !== broadcaster) : websockets;
  }

  /*
   * Removes the entry associated with the url.
   *
   * @param {string} url
   */
  removeServer(url) {
    delete this.urlMap[trimQueryPartFromURL(url)];
  }

  /*
   * Removes the individual websocket from the map of associated websockets.
   *
   * @param {object} websocket - websocket object to remove from the url map
   * @param {string} url
   */
  removeWebSocket(websocket, url) {
    const serverURL = trimQueryPartFromURL(url);
    const connectionLookup = this.urlMap[serverURL];

    if (connectionLookup) {
      connectionLookup.websockets = reject(connectionLookup.websockets, socket => socket === websocket);
    }
  }

  /*
   * Removes a websocket from a room
   */
  removeMembershipFromRoom(websocket, room) {
    const connectionLookup = this.urlMap[trimQueryPartFromURL(websocket.url)];
    const memberships = connectionLookup.roomMemberships[room];

    if (connectionLookup && memberships !== null) {
      connectionLookup.roomMemberships[room] = reject(memberships, socket => socket === websocket);
    }
  }
}

export default new NetworkBridge(); // Note: this is a singleton
<|endoftext|>


<commit_before>var request = require('request'),

  os = require('os'),

  path = require('path'),

  fs = require('fs'),

  events = require('events'),

  util = require('util'),

  targz = require('tar.gz'),

  AdmZip = require('adm-zip'),

  localPackJson = require('../../package.json'),

  UPDATE_CONFIG = require('./updateConfig'),

  remotePackJson,

  releaseURL = UPDATE_CONFIG.releaseURL,

  downloadedPath,

  EXEC_PATH,

  // Output stream instance
  write,

  callbackDownloadFn,

  rmdir = function (dir) {
    var list = fs.readdirSync(dir);

  	for(var i = 0; i < list.length; i++) {
  		var filename = path.join(dir, list[i]);
  		var stat = fs.statSync(filename);

  		if(filename == "." || filename == "..") {
  			// pass these files
  		} else if(stat.isDirectory()) {
  			// rmdir recursively
  			rmdir(filename);
  		} else {
  			// rm fiilename
  			fs.unlinkSync(filename);
  		}
  	}

  	fs.rmdirSync(dir);
  },

  getExecPath = function () {
    var reverse = process.execPath.split('').reverse().join(''),
      reversedPath,
      path;

    reversedPath = reverse.substr(reverse.indexOf('/'));
    path = reversedPath.split('').reverse().join('');

    return path;
  };

function Updater () {
  this.updating = false;

  EXEC_PATH = getExecPath();
}

util.inherits(Updater, events.EventEmitter);

Updater.prototype.checkAvailableUpdate = function () {

  request(UPDATE_CONFIG.remotePackJsonURL, function (error, response, body) {
    remotePackJson = JSON.parse(body);

    if (localPackJson.version != remotePackJson.version) {
      this.emit('availableUpdate', remotePackJson);
    }

  }.bind(this));
};

Updater.prototype.update = function () {

  if (!this.updating) {
    this.updating = true;

    releaseURL = releaseURL.concat('v').concat(remotePackJson.version).concat('/');

    console.log(os.platform());
    console.log(os.arch());
    console.log(os.tmpdir());

    switch (os.platform()) {
      case 'linux':
        write = targz().createWriteStream(os.tmpdir());

        if (os.arch() == 'x64') {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.linux64);
          downloadedPath = 'linux64';
        } else {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.linux32);
          downloadedPath = 'linux32';
        }

        callbackDownloadFn = function () {

          try {
            rmdir(EXEC_PATH);
          } catch (err) {
            // IGNORE ERROR
          }

          fs.rename( path.join(os.tmpdir(), downloadedPath), EXEC_PATH, function (err) {

            if (err) {
              console.error(err);
              alert(err);
              this.emit('updateerror');
            } else {
              this.emit('updated');
            }
          }.bind(this));

        }.bind(this);

        break;

      case 'win':

        if (os.arch() == 'x64') {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.win64);
          downloadedPath = 'win64';
        } else {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.win32);
          downloadedPath = 'win32';
        }

        write = fs.createWriteStream( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );

        callbackDownloadFn = function () {
          var zip = new AdmZip( path.join(os.tmpdir(), downloadedPath.concat('.zip')) ),
            zipEntries = zip.getEntries();

          zip.extractAllTo( path.join(os.tmpdir(), 'pie') , true);

          fs.rename( path.join(os.tmpdir(), 'pie', downloadedPath), EXEC_PATH, function () {
            fs.unlinkSync( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );
            rmdir( path.join(os.tmpdir(), 'pie') );

            this.emit('updated');

          }.bind(this));
        }.bind(this);

        break;

        case 'osx':

          if (os.arch() == 'x64') {
            releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.osx64);
            downloadedPath = 'osx64';
          } else {
            releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.osx32);
            downloadedPath = 'osx32';
          }

          write = fs.createWriteStream( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );

          callbackDownloadFn = function () {
            var zip = new AdmZip( path.join(os.tmpdir(), downloadedPath.concat('.zip')) ),
              zipEntries = zip.getEntries();

            zip.extractAllTo( path.join(os.tmpdir(), 'pie') , true);

            fs.rename( path.join(os.tmpdir(), 'pie', downloadedPath) , '/home/matheus/Documentos/Projetos/teste-updater-module/GitPie' , function () {
              fs.unlinkSync( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );
              rmdir( path.join(os.tmpdir(), 'pie') );

              this.emit('updated');

            }.bind(this));
          }.bind(this);

          break;

      default:
        throw new Error('Operation system '.concat(os.platform()).concat(' not supported'));
    }

    //Streams
    var read = request.get(releaseURL);

    this.emit('downloadingfiles');

    read
      .pipe(write)
      .on('close', function () {
        this.emit('installing');

        callbackDownloadFn.call(this);
      }.bind(this));
  }
};

module.exports = Updater;
<commit_msg>Fixed path separator to get the real exec path<commit_after>var request = require('request'),

  os = require('os'),

  path = require('path'),

  fs = require('fs'),

  events = require('events'),

  util = require('util'),

  targz = require('tar.gz'),

  AdmZip = require('adm-zip'),

  localPackJson = require('../../package.json'),

  UPDATE_CONFIG = require('./updateConfig'),

  remotePackJson,

  releaseURL = UPDATE_CONFIG.releaseURL,

  downloadedPath,

  EXEC_PATH,

  // Output stream instance
  write,

  callbackDownloadFn,

  rmdir = function (dir) {
    var list = fs.readdirSync(dir);

  	for(var i = 0; i < list.length; i++) {
  		var filename = path.join(dir, list[i]);
  		var stat = fs.statSync(filename);

  		if(filename == "." || filename == "..") {
  			// pass these files
  		} else if(stat.isDirectory()) {
  			// rmdir recursively
  			rmdir(filename);
  		} else {
  			// rm fiilename
  			fs.unlinkSync(filename);
  		}
  	}

  	fs.rmdirSync(dir);
  },

  getExecPath = function () {
    var reverse = process.execPath.split('').reverse().join(''),
      reversedPath,
      execPath;

    console.log(path.sep);

    reversedPath = reverse.substr(reverse.indexOf(path.sep));
    execPath = reversedPath.split('').reverse().join('');

    return execPath;
  };

function Updater () {
  this.updating = false;

  EXEC_PATH = getExecPath();
}

util.inherits(Updater, events.EventEmitter);

Updater.prototype.checkAvailableUpdate = function () {

  request(UPDATE_CONFIG.remotePackJsonURL, function (error, response, body) {
    remotePackJson = JSON.parse(body);

    if (localPackJson.version != remotePackJson.version) {
      this.emit('availableUpdate', remotePackJson);
    }

  }.bind(this));
};

Updater.prototype.update = function () {

  if (!this.updating) {
    this.updating = true;

    releaseURL = releaseURL.concat('v').concat(remotePackJson.version).concat('/');

    console.log('os', os.platform());
    console.log('arch', os.arch());
    console.log('EXEC_PATH', EXEC_PATH);

    switch (os.platform()) {
      case 'linux':
        write = targz().createWriteStream(os.tmpdir());

        if (os.arch() == 'x64') {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.linux64);
          downloadedPath = 'linux64';
        } else {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.linux32);
          downloadedPath = 'linux32';
        }

        callbackDownloadFn = function () {
          rmdir(EXEC_PATH);

          fs.rename( path.join(os.tmpdir(), downloadedPath), EXEC_PATH, function (err) {

            if (err) {
              console.error(err);
              alert(err);
              this.emit('updateerror');
            } else {
              this.emit('updated');
            }
          }.bind(this));

        }.bind(this);

        break;

      case 'win32':

        if (os.arch() == 'x64') {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.win64);
          downloadedPath = 'win64';
        } else {
          releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.win32);
          downloadedPath = 'win32';
        }

        write = fs.createWriteStream( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );

        callbackDownloadFn = function () {
          var zip = new AdmZip( path.join(os.tmpdir(), downloadedPath.concat('.zip')) ),
            zipEntries = zip.getEntries();

          fs.mkdirSync(path.join(os.tmpdir(), 'pie'));

          zip.extractAllTo( path.join(os.tmpdir(), 'pie') , true);

          fs.rename( path.join(os.tmpdir(), 'pie', downloadedPath), EXEC_PATH, function (err) {
            console.log(err);
            fs.unlinkSync( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );
            rmdir( path.join(os.tmpdir(), 'pie') );

            this.emit('updated');

          }.bind(this));
        }.bind(this);

        break;

        case 'osx':

          if (os.arch() == 'x64') {
            releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.osx64);
            downloadedPath = 'osx64';
          } else {
            releaseURL = releaseURL.concat(UPDATE_CONFIG.fileName.osx32);
            downloadedPath = 'osx32';
          }

          write = fs.createWriteStream( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );

          callbackDownloadFn = function () {
            var zip = new AdmZip( path.join(os.tmpdir(), downloadedPath.concat('.zip')) ),
              zipEntries = zip.getEntries();

            fs.mkdirSync(path.join(os.tmpdir(), 'pie'));

            zip.extractAllTo( path.join(os.tmpdir(), 'pie') , true);

            fs.rename( path.join(os.tmpdir(), 'pie', downloadedPath), EXEC_PATH, function () {
              fs.unlinkSync( path.join(os.tmpdir(), downloadedPath.concat('.zip')) );
              rmdir( path.join(os.tmpdir(), 'pie') );

              this.emit('updated');

            }.bind(this));
          }.bind(this);

          break;

      default:
        throw new Error('Operation system '.concat(os.platform()).concat(' not supported'));
    }

    //Streams
    var read = request.get(releaseURL);

    this.emit('downloadingfiles');

    read
      .pipe(write)
      .on('close', function () {
        this.emit('installing');

        callbackDownloadFn.call(this);
      }.bind(this));
  }
};

module.exports = Updater;
<|endoftext|>


<commit_before>

/**
 * The calendar events list service
 */

/**
 * Get regular event by applying the date filter
 * And rrule events by calling the expand on the events
 *
 * @param {listItemsService} service
 * @param {array} params      query parameters if called by controller
 *
 * @return {Query}
 */
function getEventsQuery(service, params)
{
    'use strict';

    var find = service.app.db.models.CalendarEvent.find();

    if (params.calendar) {
        if (params.calendar instanceof Array) {
            find.where('calendar').in(params.calendar);
        } else {
            find.where('calendar').equals(params.calendar);
        }
    }

    if (params.user) {
        find.where('user.id').equals(params.user);
    }

    find.or([
        { rrule: { $exists: true } },
        { $and:
            [
                { rrule: { $exists: false } },
                { dtend: { $gt: params.dtstart } },
                { dtstart: { $lt: params.dtend } }
            ]
        }
    ]);

    return find;
}

/**
 * @return {Promise} resolve to schedule calendar object
 */
function getScheduleCalendar(service, calendar)
{
    'use strict';

    var find = service.app.db.models.CalendarEvent.findOne(calendar);
    return find.exec();
}

function getNonWorkingDaysCalendar(service)
{
    'use strict';

    var find = service.app.db.models.Calendar.find();
    find.where('type', 'nonworkingday');
    return find.exec();
}

/**
 * Create the service
 * @param   {Object} services
 * @param   {Object} app
 * @returns {listItemsService}
 */
exports = module.exports = function(services, app) {

    'use strict';

    var service = new services.list(app);

    /**
     * Call the calendar events list service
     * the result events will be intersected with the serach interval
     *
     * @param {Object} params
     *                      params.dtstart                  search interval start
     *                      params.dtend                    serach interval end
     *                      params.calendar                 carlendar ID to search in
     *                      params.substractNonWorkingDays  substract non working days periods
     *                      params.substractPersonalEvents  substract personal events
     *                      params.substractException       Array of personal event ID to ignore in the personal events to substract
     *                      params.user                     User ID for personal events
     *
     *
     * @return {Promise}
     */
    service.getResultPromise = function(params) {

        var jurassic = require('jurassic');

        /**
         * Create period from event
         * @param {Object}  obj     expanded event
         * @return {Period}
         */
        function createPeriod(obj)
        {
            var period = new jurassic.Period();
            for(var prop in obj) {
                if (obj.hasOwnProperty(prop)) {
                    period[prop] = obj[prop];
                }
            }
            return period;
        }

        /**
         * Get Era from a list onf events documents
         * events will be expanded according to RRULE if any
         * @param {Array} docs
         * @return {Era}
         */
        function getExpandedEra(docs)
        {

            var events = new jurassic.Era();
            var expanded;

            // it seam that the expand method is based on the event start date
            // we get one more day to get the event overlapping with start search date
            var expandStart = new Date(params.dtstart);
            expandStart.setDate(expandStart.getDate() -1);

            for(var i =0; i<docs.length; i++) {
                expanded = docs[i].expand(expandStart, params.dtend);

                // expand event if RRULE
                for(var e =0; e<expanded.length; e++) {

                    // copy properties of expanded event to the jurassic period
                    events.addPeriod(createPeriod(expanded[e]));
                }
            }
            return events;
        }

        /**
         * get personal events to substract
         * @return {Promise} Era
         */
        function getPersonalEvents()
        {
            var Q = require('q');
            var deferred = Q.defer();

            if (undefined === params.user) {
                deferred.reject('the user param is mandatory if substractPersonalEvents is used');
            } else {

                var filter = {
                    dtstart: params.dtstart,
                    dtend: params.dtend,
                    user: params.user,
                    status: { $in: ['TENTATIVE', 'CONFIRMED'] }
                };

                if (undefined !== params.substractException) {
                    // Do not substract those personnal events
                    // because this is the events to update with selection
                    // the others personal events will be substracted from working hours
                    filter._id = { $not: { $in: params.substractException } };
                }

                getEventsQuery(service, filter).exec(function(err, docs) {
                    if (err) {
                        return deferred.reject(err);
                    }

                    deferred.resolve(getExpandedEra(docs));
                });
            }

            return deferred.promise;
        }

        var checkParams = require('../../../../modules/requestdateparams');

        if (!checkParams(service, params)) {
            return service.deferred.promise;
        }

        getScheduleCalendar(service, params.calendar).then(function(scheduleCalendar) {

            getEventsQuery(service, {
                dtstart: params.dtstart,
                dtend: params.dtend,
                calendar: params.calendar
            }).exec(function(err, docs) {

                var searchPeriod = new jurassic.Period();
                searchPeriod.dtstart = params.dtstart;
                searchPeriod.dtend = params.dtend;

                var events = getExpandedEra(docs);
                var era = events.intersectPeriod(searchPeriod);

                for(var j =0; j<era.periods.length; j++) {

                    // we add the duration in days in a new property for json output
                    era.periods[j].businessDays = era.periods[j].getBusinessDays(scheduleCalendar.halfDayHour);
                }

                if (undefined === params.substractNonWorkingDays || false === params.substractNonWorkingDays) {
                    return service.mongOutcome(err, era.periods);
                }

                getNonWorkingDaysCalendar(service).then(function(nwdCalendars) {
                    var nwdCalId = nwdCalendars.map(function(cal) {
                        return cal._id;
                    });

                    getEventsQuery(service, {
                        dtstart: params.dtstart,
                        dtend: params.dtend,
                        calendar: nwdCalId
                    }).exec(function(err, docs) {

                        var nonWorkingDays = getExpandedEra(docs);
                        var NWera = nonWorkingDays.intersectPeriod(searchPeriod);
                        var substracted = era.substractEra(NWera);

                        if (undefined === params.substractPersonalEvents || false === params.substractPersonalEvents) {
                            return service.mongOutcome(err, substracted.periods);
                        }

                        getPersonalEvents().then(function(personalEra) {
                            substracted = substracted.substractEra(personalEra);
                            service.mongOutcome(err, substracted.periods);
                        });

                    });
                }, service.error);

            });

        }, service.error);

        return service.deferred.promise;
    };

    return service;
};

<commit_msg>Use nin instead of not in<commit_after>

/**
 * The calendar events list service
 */

/**
 * Get regular event by applying the date filter
 * And rrule events by calling the expand on the events
 *
 * @param {listItemsService} service
 * @param {array} params      query parameters if called by controller
 *
 * @return {Query}
 */
function getEventsQuery(service, params)
{
    'use strict';

    var find = service.app.db.models.CalendarEvent.find();

    if (params.calendar) {
        if (params.calendar instanceof Array) {
            find.where('calendar').in(params.calendar);
        } else {
            find.where('calendar').equals(params.calendar);
        }
    }

    if (params.user) {
        find.where('user.id').equals(params.user);
    }

    find.or([
        { rrule: { $exists: true } },
        { $and:
            [
                { rrule: { $exists: false } },
                { dtend: { $gt: params.dtstart } },
                { dtstart: { $lt: params.dtend } }
            ]
        }
    ]);

    return find;
}

/**
 * @return {Promise} resolve to schedule calendar object
 */
function getScheduleCalendar(service, calendar)
{
    'use strict';

    var find = service.app.db.models.CalendarEvent.findOne(calendar);
    return find.exec();
}

function getNonWorkingDaysCalendar(service)
{
    'use strict';

    var find = service.app.db.models.Calendar.find();
    find.where('type', 'nonworkingday');
    return find.exec();
}

/**
 * Create the service
 * @param   {Object} services
 * @param   {Object} app
 * @returns {listItemsService}
 */
exports = module.exports = function(services, app) {

    'use strict';

    var service = new services.list(app);

    /**
     * Call the calendar events list service
     * the result events will be intersected with the serach interval
     *
     * @param {Object} params
     *                      params.dtstart                  search interval start
     *                      params.dtend                    serach interval end
     *                      params.calendar                 carlendar ID to search in
     *                      params.substractNonWorkingDays  substract non working days periods
     *                      params.substractPersonalEvents  substract personal events
     *                      params.substractException       Array of personal event ID to ignore in the personal events to substract
     *                      params.user                     User ID for personal events
     *
     *
     * @return {Promise}
     */
    service.getResultPromise = function(params) {

        var jurassic = require('jurassic');

        /**
         * Create period from event
         * @param {Object}  obj     expanded event
         * @return {Period}
         */
        function createPeriod(obj)
        {
            var period = new jurassic.Period();
            for(var prop in obj) {
                if (obj.hasOwnProperty(prop)) {
                    period[prop] = obj[prop];
                }
            }
            return period;
        }

        /**
         * Get Era from a list onf events documents
         * events will be expanded according to RRULE if any
         * @param {Array} docs
         * @return {Era}
         */
        function getExpandedEra(docs)
        {

            var events = new jurassic.Era();
            var expanded;

            // it seam that the expand method is based on the event start date
            // we get one more day to get the event overlapping with start search date
            var expandStart = new Date(params.dtstart);
            expandStart.setDate(expandStart.getDate() -1);

            for(var i =0; i<docs.length; i++) {
                expanded = docs[i].expand(expandStart, params.dtend);

                // expand event if RRULE
                for(var e =0; e<expanded.length; e++) {

                    // copy properties of expanded event to the jurassic period
                    events.addPeriod(createPeriod(expanded[e]));
                }
            }
            return events;
        }

        /**
         * get personal events to substract
         * @return {Promise} Era
         */
        function getPersonalEvents()
        {
            var Q = require('q');
            var deferred = Q.defer();

            if (undefined === params.user) {
                deferred.reject('the user param is mandatory if substractPersonalEvents is used');
            } else {

                var filter = {
                    dtstart: params.dtstart,
                    dtend: params.dtend,
                    user: params.user,
                    status: { $in: ['TENTATIVE', 'CONFIRMED'] }
                };

                if (undefined !== params.substractException) {
                    // Do not substract those personnal events
                    // because this is the events to update with selection
                    // the others personal events will be substracted from working hours
                    filter._id = { $nin: params.substractException };
                }

                getEventsQuery(service, filter).exec(function(err, docs) {
                    if (err) {
                        return deferred.reject(err);
                    }

                    deferred.resolve(getExpandedEra(docs));
                });
            }

            return deferred.promise;
        }

        var checkParams = require('../../../../modules/requestdateparams');

        if (!checkParams(service, params)) {
            return service.deferred.promise;
        }

        getScheduleCalendar(service, params.calendar).then(function(scheduleCalendar) {

            getEventsQuery(service, {
                dtstart: params.dtstart,
                dtend: params.dtend,
                calendar: params.calendar
            }).exec(function(err, docs) {

                var searchPeriod = new jurassic.Period();
                searchPeriod.dtstart = params.dtstart;
                searchPeriod.dtend = params.dtend;

                var events = getExpandedEra(docs);
                var era = events.intersectPeriod(searchPeriod);

                for(var j =0; j<era.periods.length; j++) {

                    // we add the duration in days in a new property for json output
                    era.periods[j].businessDays = era.periods[j].getBusinessDays(scheduleCalendar.halfDayHour);
                }

                if (undefined === params.substractNonWorkingDays || false === params.substractNonWorkingDays) {
                    return service.mongOutcome(err, era.periods);
                }

                getNonWorkingDaysCalendar(service).then(function(nwdCalendars) {
                    var nwdCalId = nwdCalendars.map(function(cal) {
                        return cal._id;
                    });

                    getEventsQuery(service, {
                        dtstart: params.dtstart,
                        dtend: params.dtend,
                        calendar: nwdCalId
                    }).exec(function(err, docs) {

                        var nonWorkingDays = getExpandedEra(docs);
                        var NWera = nonWorkingDays.intersectPeriod(searchPeriod);
                        var substracted = era.substractEra(NWera);

                        if (undefined === params.substractPersonalEvents || false === params.substractPersonalEvents) {
                            return service.mongOutcome(err, substracted.periods);
                        }

                        getPersonalEvents().then(function(personalEra) {
                            substracted = substracted.substractEra(personalEra);
                            service.mongOutcome(err, substracted.periods);
                        });

                    });
                }, service.error);

            });

        }, service.error);

        return service.deferred.promise;
    };

    return service;
};

<|endoftext|>


<commit_before>module.exports = {
  encode: require('./nsnjson.encoder').encode,
  decode: require('./nsnjson.decoder').decode
};
<commit_msg>Refactor { nsnjson.driver }<commit_after>module.exports = {
  encode: require('./nsnjson.encoder').encode,
  decode: require('./nsnjson.decoder').decode
};<|endoftext|>