 /*********************************************************************
 **
 **   server/appx-client-widget.js - Client Widget processing
 **
 **   This module contains code to process Appx Widget screen elements.
 **
 *********************************************************************/

// what_str =  "@(#)Appx $Header: /src/cvs/appxHtml5/server/appx-client-widget.js,v 1.287 2016/06/17 19:50:52 jnelson Exp $";

//Need to Remove the default styles and set CUSTOM.css - !!!

"use strict"; // Commented this out as IE11 takes strict much more seriously than other browsers, breaks the client.
function addClientId( appxId, clientId ) {
    if (clientId && clientId != appxId) {
	appx_session.clientIds[appxId] = clientId;
	appx_session.clientIds[clientId] = appxId;
    }
    else {
	appx_session.clientIds[appxId] = appxId;
    }
    return appx_session.clientIds[appxId];
}

function getClientId( appxId ) {
    return appx_session.clientIds[appxId];
}

function clearClientIds() {
    appx_session.clientIds = {};
}

//prevent default browser behavior on drops (e.g. navigating to contents)
function eventCatcher(e) {
    e = e || e.originalEvent || window.event;
    if (e.preventDefault) e.preventDefault();
    if (e.stopPropagation) e.stopPropagation();
    return false;
}
window.ondragover = function (e) {
    return eventCatcher(e);
};
window.ondrop = function (e) {
    return eventCatcher(e);
};


// this function is bound to a widget button's click event at the time the widget is created
function appxwidgetcallback2(option) {
    if( appx_session.mouseX ) {
	var row = Math.floor(appx_session.mouseY / appx_session.rowHeightPx);
	var col = Math.floor(appx_session.mouseX / appx_session.colWidthPx);
	appxPutCursor(col,row);
    }
    appxwidgetcallback(option);
}

function appxwidgetcallback(option) {
    /*if option is supposed to be handled by the client then change client preferences
     *and reset option to just redraw screen*/ 
    appx_session.lastOption = option;
    if ((parseInt(option) >= 20101 && parseInt(option) <= 20106) ||
        (parseInt(option) >= 20030 && parseInt(option) <= 20032)){
	var optionParsed = parseInt(option);
	var propValue = null;
	var propName = null;
	switch (optionParsed){
	     case 20101:
		 /*propName = "guiInterface";
		   propValue = !appx_session.getProp(propName);
		   appx_session.setProp(propName, propValue.toString());*/
		 showPopup(false);
		 return;
		 break;
	     case 20102:
		 propName = "showOptionNumbers";
		 propValue = !appx_session.getProp(propName);
		 appx_session.setProp(propName, propValue.toString());
		 break;
	     case 20103:
		 propName = "autoTabOut";
		 propValue = !appx_session.getProp(propName);
		 appx_session.setProp(propName, propValue.toString());
		 break;
	     case 20104:
		 propName = "autoSelect";
		 propValue = !appx_session.getProp(propName);
		 appx_session.setProp(propName, propValue.toString());
		 break;
	     case 20105:
		 propName = "dockingScrollbar";
		 propValue = !appx_session.getProp(propName);
		 appx_session.setProp(propName, propValue.toString());
		 break;
	     case 20106:
		 propName = "showGridlines";
		 /*
		 **When image editor gets included uncomment this code and 
		 **remove showPopup & return statement
		 **
		 propValue = !appx_session.getProp(propName);
		 appx_session.setProp(propName, propValue.toString());
		 */
		 showPopup(false);
		 return;
		 break;
	     case 20030:
		 //print setup
		 showPopup(false);
		 return;
		 break;
	     case 20031:
		 //about
		 showPopup(true);
		 return;
		 break;
	     case 20032:
		 appx_session.showPreferences();
		 return;
		 break;
	}
    }
    
    logca("appxwidgetcallback: " + option);

    if( parseInt(option) == 21005 ) {
	var sessionflags = {};
	sendappxnewsession(appx_session.host, appx_session.port, appx_session.user, appx_session.password, appx_session.screenrows, appx_session.screencols, sessionflags);
	return;
    }

    $(".cke").each(function () {
	var editor = CKEDITOR.instances[$(this).attr("id").substring(4)];
	$(this).val(editor.getData());
	if (editor && editor.checkDirty()) {
	    $(this).addClass("appxitem dirty");
	    $(this).attr("id", $(this).attr("id").substring(4));
	}
    });

    var data = [];
    $("#appx_main_container").focus();
    $(".appxitem.dirty").each(function () {
        data.push(this);
    });
    if (appx_session.processhelp == true){
	appx_session.processhelpoption = option;
	console.log("option: " + option);
	console.log("processhelpoption: " + appx_session.processhelpoption);
	option = OPT_HELP_OPT;
    }

    sendappxshow(option, data);
}

function appxwidgetdimensions(wori, $tag, box) { //Widget or Item
    try {
        var x = 0,
            y = 0,
            w = 0,
            h = 0;
        var wx = wori,
            wt = wx.wWidgetType;
        var colW = appx_session.colWidthPx;
        var rowH = appx_session.rowHeightPx;

	if (wx.hasOwnProperty("widget")){
	    wt = wx.widget.wWidgetType;
	}
        if (box) { //translate items to box coordinates too
            x = box.begin_column - 1;
            y = box.begin_row;
            if (!appxIsScrollReg(box)) y--;
            //TODO: scanrecords not showing yet
        }

        //TODO/FIXME: Check this logic.  Tried to find a way to set negative 
        //-w and -h with the value from the size_cols and size_rows sent from 
        //the connector. Before this lines with negative values wouldn't always
        //work, as all widgets depended on purely widget @SSZ data for size. 
        //Lines don't always include the @SSZ data parameter we need for the 
        //neg width and height see WIDGET_TYPE_LINE
        var css = null;
        if (!wx.hasOwnProperty("wWidgetId")) { //Item
            if (wori.hasOwnProperty("widget") && wori.widget != null && wori.widget.wPositionX != null) {
                wx = wori.widget;
                if (wt != WIDGET_TYPE_PROGRESS_BAR && wt != WIDGET_TYPE_SLIDER) {
                    if (!wx.wSizeW) {
			wx.wSizeW = wori.size_col || wori.size_cols; //sometimes 0
		    }
		    if (!wx.wSizeH) {
			wx.wSizeH = wori.size_row || wori.size_rows;
		    }
                }
            }
            else {
                x = (wx.pos_col - x) * colW;
                y = (wx.pos_row - y) * rowH;
                w = (wx.size_cols || wx.size_col) * colW;
                h = (wx.size_rows || wx.size_row) * rowH;
            }
        }

        //widget positioning is relative to the parent box (appxshowhandler)
        var css = null;
        if (wx.hasOwnProperty("wWidgetId")) { //instanceof Widget
            var offX = 0,
                offY = 0,
                offW = 0,
                offH = 0;

            // The java client truncates, not rounds, the double NOT (~~) is
            // a fast and negative value safe way to truncation a float to an int.
            if (wx.wOffsetX) offX = ~~((wx.wOffsetX * colW) / 100);
            if (wx.wOffsetY) offY = ~~((wx.wOffsetY * rowH) / 100);
            if (wx.wOffsetW) offW = ~~((wx.wOffsetW * colW) / 100);
            if (wx.wOffsetH) offH = ~~((wx.wOffsetH * rowH) / 100);

	    if (wx.wPositionX != null){
		x = (wx.wPositionX ? ((wx.wPositionX - x) * colW) + offX : 0);
		y = (wx.wPositionY ? ((wx.wPositionY - y) * rowH) + offY : 0);
		w = (wx.wSizeW ? (wx.wSizeW * colW) + offW : 0);
		h = (wx.wSizeH ? (wx.wSizeH * rowH) + offH : 0);
	    }
        }

        if ($tag) {
            $tag.css({
                "position": "absolute",
                "left": x,
                "top": y
            });
	    if (h === 0 || w === 0){
		$tag.hide();
	    }
	    if ( wt == WIDGET_TYPE_HTML_VIEWER ) h-=2;
	    $tag.css("height", h);
            if (wt != WIDGET_TYPE_CHECK_BOX) {
                // The java client adds an extra 5 pixel to the widget of input fields
                // to make room for the decorations
                if (wt != WIDGET_TYPE_TABLE && wt != WIDGET_TYPE_BOX && wt != WIDGET_TYPE_BUTTON && wt != WIDGET_TYPE_LABEL && wt != WIDGET_TYPE_PICTURE && wt != WIDGET_TYPE_LISTBOX){
		    w += 5;
		}
                if (wt == WIDGET_TYPE_LISTBOX){
		    var pad = colW * 3.96; //Added width to accomodate drop down arrow
		    $tag.attr("data-padWidth", pad);//Attach added width to data tag
		    w += pad;
		}
                $tag.css("width", w);
            }
        }
    }
    catch (ex) {
        console.log("appxwidgetdimensions: " + ex);
	console.log(ex.stack);
    }
    return {
        "x": x,
        "y": y,
        "w": w,
        "h": h,
        "cw": colW,
        "rh": rowH
    };
}

//Widgets Message Handler
//Display.addField(MFld)
function appxwidgetshandler(x) {
    var wdgts = x.data;
    var i = 1;
    var defaultButtonSet = false;
    while (wdgts.length > 0) {
        var wdata = wdgts.shift();
        var wx = new Widget(wdata[0], "", wdata[1], wdata[2], wdata[3]);
        var wt = parseInt(wx.wWidgetType);
        //console.log("widget row=%d, col=%d label=%s, box=%d %s",wx.wPositionY,wx.wPositionX,wx.wLabel,wdata[0],ab2str(wdata[1]));

        if (wx.wDefaultButton) {
            if (defaultButtonSet)
                wx.wDefaultButton = null;
            else
                defaultButtonSet = true;
        }

        if (wt == WIDGET_TYPE_ROWTEXT) {
            var rowtxt = new RowTextStruct();
            rowtxt.type = ROWTEXT_TYPE_WIDGET;
            rowtxt.boxid = wdata[0];
	    rowtxt.isTitle = wx.wInvert;
            rowtxt.pos_row = wx.wPositionY;
            rowtxt.pos_col = wx.wPositionX;
            rowtxt.size_rows = wx.wSizeH;
            rowtxt.size_cols = wx.wSizeW;
            rowtxt.string = wx.wLabel;
            appx_session.rowtext.push(rowtxt);
            continue;
        }

        var $tag = null;
        switch (wt) {
             case WIDGET_TYPE_BUTTON:
                 $tag = $("<button type='button'>").css({
                     "margin": "0",
                     "padding": "0"
                 });

                 $tag.addClass("button")
                     .data("row", wx.wPositionY)
                     .data("col", wx.wPositionX);

                 if (wx.wCommand != null) {
                     $tag.attr("id", addClientId("widget_sac_" + wx.wCommand,wx.wClientId));
                     $tag.click(function () {
			 var opt = parseInt(getClientId(this.id).substring(11));
			 if( opt >= 250 && opt <= 255 ) {
			     var col = $(this).data("col");
			     var row = $(this).data("row");
			     if (col && row) {
				 appxPutCursor(col, row);
			     }
			 }
			 appxwidgetcallback(getClientId(this.id).substring(11));
                     });
                 }
                 if (!wx.wBorder) wx.wBorder = BORDER_BEVEL_RAISED;
                 break;
             case WIDGET_TYPE_LABEL:
                 $tag = $("<div>");
                 $tag.addClass("label");
                 $tag.attr("id", addClientId("widget_sac_" + i.toString(),wx.wClientId));
                 break;
             case WIDGET_TYPE_PICTURE:
                 $tag = $("<div>");
                 break;
             case WIDGET_TYPE_BOX:
                 $tag = $("<fieldset>").css({
                     "margin": "0",
                     "text-align": "left"
                 });
                 break;
             case WIDGET_TYPE_LINE:
                 $tag = $("<div>");
                 break;
             case WIDGET_TYPE_SLIDER:
                 $tag.css({
                     "height": $tag.height() + 50,
                     "width": $tag.width() + 15
                 });
                 break;
             case WIDGET_TYPE_PROGRESS_BAR:
                 break;
             case WIDGET_TYPE_PASSWORD:
                 break;
             case WIDGET_TYPE_FLASH_PLAYER:
                 //can also use <embed></embed> see http://www.w3schools.com/html/html_object.asp
                 $tag = $("<object data='http://www.w3schools.com/html/bookmark.swf'></object>");
                 break;
             case WIDGET_TYPE_MEDIA_PLAYER:
                 if (wx.type == "video") {
                     $tag = $('<video><source src="http://www.w3schools.com/tags/movie.mp4" type="video/mp4">Your browser does not support the video tag.</video>');
                 }
                 if (wx.type == "audio") {
                     $tag = $('<audio controls><source src="http://www.w3schools.com/tags/horse.mp3" type="audio/mpeg">Your browser does not support the audio element.</audio>');
                 }
                 break;
             case WIDGET_TYPE_DATE_CHOOSER:
                 $tag = $("<input type='text'>");
                 $tag.val(item.data);
                 $tag.addClass("appxdatefield");
                 //need mask from server
                 $tag.mask('0000/00/00');
                 break;
             case WIDGET_TYPE_TABLE:
                 wx.wSizeH -= 1;
                 $tag = $("<div>")
                     .addClass("appxtablewidget")
                     .attr("id", addClientId( "appxitem_" + wx.wPositionX + "_" + wx.wPositionY, wx.wClientId))
                     .data("action", {
                         "command": wx.wCommand,
                         "command2": wx.wCommand2
                     })
                     .data("row", wx.wPositionY)
                     .data("col", wx.wPositionX);
                 break;
             case WIDGET_TYPE_ROWTEXT:
                 if (wx.wPositionY > 1) {
                     wx.wLabel = "<pre>" + wx.wLabel + "</pre>";
                     wx.wColorFg = "black";
                     wx.wFont = "Dialog";
                     $tag = $("<div>");
                     $tag.addClass("rowtext");
                     if (wx.wLabel.length > 1 && wx.wLabel[0] == '=')
                         $tag.addClass("ColHdgSep");
                     $tag.attr("id", addClientId("widget_sac_" + i.toString(),wx.wClientId));
                 }
                 break;
        }

        if ($tag != null) {
            var dim = appxwidgetdimensions(wx, $tag);
            appxwidgetshandlerprops(wx, $tag);
            $tag.addClass("appxwidget");
	    if (wt == WIDGET_TYPE_BOX) {
                if (wx.wLabel && wx.wLabel.length > 0) {
                    $tag.css({
                        "width": dim.w - (2 * dim.cw) - 2 + 14,
                        "height": dim.h - dim.rh + 5 + 14,
                        "left": dim.x + 2
                    });
                }
                else {
                    $tag.css({
                        "width": dim.w - (2 * dim.cw) + 2 + 14,
                        "height": dim.h - dim.rh + 5 + 2 + 14
                    });
                }
                //TODO: overrules html set in appxwidgethandlerprops
                //color is black in ie(11) without inherit
                if (wx.wLabel) $tag.html("<legend style='color:inherit'><span>" + wx.wLabel + "</span></legend>");
            }else if ($tag.hasClass("defaultBorder") && $tag.is("button") && wx.wBorder != BORDER_NONE){
		$tag.css({
		    "top": (dim.y +1 ),
		    "left": (dim.x +1 ),
		    "height": (dim.h - 2),
		    "width": (dim.w - 2)
		});
	    }
	    
	
            $tag.css("z-index", 1000 + wx.wLayer * -1);
            appx_session.widgets.push([wx, $tag]);
        }

        i++;
    } //end while widgets
}


/*
**Function to attach blur event to HTML element if we have there is lost
**focus event, DLU event, or both attached to the item or widget being 
**processed
**
**@param $tag: HTML element to append blur function to.
**@param mCmd: command to send to appx engine on blur
**
*/
function appxAttachBlur($tag, mCmd){
    if ($tag.find(".appxdatevalue").length > 0) {
	$tag = $tag.find(".appxdatevalue");
    }
    
    $tag.blur(function () {
	if (appx_session.activeDatepicker == null && !appxIsLocked()) {
	    appx_session.valueTimerStop(); //CA: key pause
	    appxPutTabOut();			
	    logca("wx.blur");
	    //without timeout tab can switch back to the current field and 
	    //make it hard to end the function
	    
	    setTimeout(function (cmd) {
		logca("CommandLostFocus to: " + cmd);
		if (!appxIsLocked()){
		    appxwidgetcallback(cmd);
		}
		else logca("(locked)");
	    }, 100, mCmd);
	}
	else {
	    logca("wx.blur: locked");
	}
    });
}

function appxwidgetshandlerprops(wori, $tag) {
    appxwidgetshandlerpropsex(wori, $tag, false);
}

function appxwidgetshandlerpropsex(wori, $tag, bTitlebar) {
    var wx = wori;
    var isWidget = true;
    if (wori.hasOwnProperty("widget")) { //Item
        if (wori.widget != null) {
	    wx = wori.widget;
	    isWidget = false;
	}
        else { 
	    if ($tag && appxIsDLUonTabOut(wori)){
		appxAttachBlur($tag, OPT_DLU_ON_TABOUT);
	    }
	    return;
	}
    }
    if (wx == null || $tag == null) return;

    var wt = parseInt(wx.wWidgetType);
    var bInput = ($tag.is("input") || $tag.is("select") || $tag.is("textarea"));
    if (!bTitlebar) {
	
	if($tag.html() && wt != WIDGET_TYPE_DATE_CHOOSER) {
	    var itemdata = $tag.html();
	    $tag.html("");
	}
	
        switch (wt) {
		 //TODO? maybe merge with box, item and widgetshandler and return html tag
             case WIDGET_TYPE_LINE:
		 if( !wx.wSizeH ) wx.wSizeH = wx.size_row;
		 if( !wx.wSizeW ) wx.wSizeW = wx.size_col;
		 
		 var bounds = { "height": wx.wSizeH, "width": wx.wSizeW, "x": wx.wPositionX, "y": wx.wPositionY };
		 var offset = { "height": wx.wOffsetH, "width": wx.wOffsetW, "x": wx.wOffsetX, "y": wx.wOffsetY };
		 var unitbase = appx_session.rowHeightPx;
		 
		 if( wx.wLineUnitBase ) {
		     switch(wx.wLineUnitBase.toLowerCase()) {
		          case "w": unitbase = appx_session.colWidthPx;  break;
		          case "h": unitbase = appx_session.rowHeightPx; break;
		          default:  unitbase = parseInt(wx.wLineUnitBase);
		     }
		 }
		 
		 var lineweightpct = -1;
		 var lineweight = -1.0;
		 if( wx.wSetLineWeight ) {
		     lineweightpct = wx.wSetLineWeight;
		 }
		 if( lineweightpct < 0 ) lineweight = 0.32 * unitbase;
		 if( lineweight    < 0 ) lineweight = lineweightpct / 100.0 * unitbase;
		 if( lineweight    < 1 ) lineweight = 1.0;
		 var lineweightwhole = ~~( lineweight ); //~~ removes decimals
		 
		 var insets = {"top": lineweightwhole+1, "left": lineweightwhole+1, "bottom": lineweightwhole + 1, "right": lineweightwhole + 1};
		 var ow = bounds.width  == 1 && offset.width  < 0 ? (offset.width  * -1)/100 : offset.width/100;
		 var oh = bounds.height == 1 && offset.height < 0 ? (offset.height * -1)/100 : offset.height/100;
		 var dim = {"width": (Math.abs(bounds.width ) * appx_session.colWidthPx) + (ow * appx_session.colWidthPx) + insets.left + insets.right  - appx_session.colWidthPx, 
			    "height":(Math.abs(bounds.height) * appx_session.rowHeightPx) + (oh * appx_session.rowHeightPx) + insets.top  + insets.bottom - appx_session.rowHeightPx };
		 var beg = {"x": 0, "y":0};
		 var end = {"x": 0, "y":0};
		 beg.x = bounds.width  > 0 
		     ? bounds.width  == 1 && offset.width  < 0 ? insets.left - offset.width : insets.left 
		 : dim.width  - insets.right;
		 beg.y = bounds.height > 0 
		     ? bounds.height == 1 && offset.height < 0 ? insets.top  - offset.height : insets.top  
		 : dim.height - insets.bottom;
		 end.x = bounds.width  > 0 
		     ? bounds.width  == 1 && offset.width  < 0 ? insets.left : dim.width - insets.right   
		 : insets.left;
		 end.y = bounds.height > 0 
		     ? bounds.height == 1 && offset.height < 0 ? insets.top : dim.height - insets.bottom 
		 : insets.top;
		 
		 var x  = bounds.width  > 0 ? bounds.x : bounds.x + bounds.width  + 1;
		 var y  = bounds.height > 0 ? bounds.y : bounds.y + bounds.height + 1;
		 var ox = bounds.width  > 0 
		     ? bounds.width  == 1 && offset.width  < 0 ? offset.x + offset.width  : offset.x 
		     : offset.x - offset.width;
		 var oy = bounds.height > 0 
		     ? bounds.height == 1 && offset.height < 0 ? offset.y + offset.height : offset.y 
		     : offset.y - offset.height;
		 var loc = { "x": (x * appx_session.colWidthPx) + (((ox * appx_session.colWidthPx) / 100) - insets.left), "y": roundAwayFromZero((y * appx_session.rowHeightPx) + (((oy * appx_session.rowHeightPx) / 100) - insets.top))};
		 
                 $tag.css({"background": "transparent"});
		 
                 var $svg = $("<svg>").width("100%").height("100%");
                 var $line = $("<line x1="+beg.x+" y1="+beg.y+" x2="+end.x+" y2="+end.y+" style='stroke: rgb(0,0,0); stroke-width:"+lineweightwhole+"'>");
		 $tag.width(dim.width);
		 $tag.height(dim.height);
		 $tag.css("top", loc.y+"px");
		 $tag.css("left", loc.x+"px");
		 
                 if (wx.wColorFgDisabled) {
                     $line.css({"stroke": wx.wColorFgDisabled});
                 }
		 
                 switch (wx.wEndcapType) {
                      case 2:  $line.css({"stroke-linecap": "square"}); break;
                      case 1:  $line.css({"stroke-linecap": "round"  }); break;
                      case 0:  $line.css({"stroke-linecap": "none"  }); break;
                      default: $line.css({"stroke-linecap": "round" }); break;
                 }
		 
                 if (wx.wStrokePattern) {
                     var adjPattern = wx.wStrokePattern.split(",");
                     var p2 = [];
                     $.each(adjPattern, function (a, b) {
                         p2.push(parseInt(b) * lineweightwhole);
                     });
                     $line.css({"stroke-dasharray": p2.toString()});
                 }
		 
                 if (wx.wStrokePatternOffset) {
                     $line.css({"stroke-dashoffset": wx.wStrokePatternOffset * lineweightwhole});
                 }
		 
                 $svg.html($line[0].outerHTML);
                 $tag.append($svg[0].outerHTML);
		 
                 break;
	     case WIDGET_TYPE_PICTURE:
		 $tag.addClass("picture");
		 if (wx.wIconDisabled){
		     $tag.addClass(AppxResource.load(wx.wIconDisabled) + "_pic"); 
		 } else if (wx.wIconWallpaper){
		     $tag.addClass(AppxResource.load(wx.wIconWallpaper) + "_pic"); 
		 }
		 var clsPic = appxGetClassIcon(wx, bTitlebar);
		 $tag.addClass(clsPic);
		 var tagCSS = ""; 
		 if (wx.wSetImageScale){
		     var scale = wx.wSetImageScale + "%";
		     if (wx.wSetImageScale != 100){
			 tagCSS = scale;
		     }else{
			 tagCSS = "contain";
		     }
		 }
		 $tag.css({
		     "background-size" : tagCSS,
		     "background-position" : wx.wSetHorizAlign + " " + wx.wSetVertAlign
		 });
		 break;
	     case WIDGET_TYPE_SLIDER:
                 $tag.css({
                     "height": $tag.height() + 50,
                     "width": $tag.width() + 15
                 });
                 break;
             case WIDGET_TYPE_PROGRESS_BAR:
                 break;
             case WIDGET_TYPE_LISTBOX:
                 var opt = wx.wCommand;
                 $tag.change(function () {
                     if (opt) {
                         appxwidgetcallback(opt);
                     }
                 });
                 break;
             case WIDGET_TYPE_CHECK_BOX:
                 break;
             case WIDGET_TYPE_PASSWORD:
                 $tag.prop("type", "password");
                 break;
             case WIDGET_TYPE_FILE_CHOOSER:
                 $tag.on('click', function (e) {
                     if (localos_session && localos_session.ws.readyState == 1) {
                         var randclass = "awaiting_filepath";
                         $(this).addClass(randclass);
                         var ms = {
                             cmd: 'file-dialog-nw',
                             args: [],
                             handler: '',
                             data: {
                                 dbg: false, //show devtools, don't close window
				 wDnD: wx.wDragAndDrop,
                                 wgtid: randclass,
                                 wPosX: wx.wPositionX + 1,
                                 wPosY: wx.wPositionY + 1
                             }
                         };
                         localos_session.ws.send(JSON.stringify(ms));
                         return false;
                     }
                 });
                 break;
             case WIDGET_TYPE_TABLE:
                 if (wx.widgetExtraData.widget_extra_reuse == true) {
                     var tablespecs = appx_session.gridcache[wx.tableHashKey];
                 }
                 else {
		     var tablespecs = wx.widgetExtraData.widget_extra_data;
		     if (wx.tableShowRowNumbers !== null){
			 tablespecs.showRowNumbers = wx.tableShowRowNumbers;
		     }else{
			 tablespecs.showRowNumbers = appx_session.getProp("gridShowRowNumbers");
		     }
		     if (wx.tableShowFooterBar !== null){
			 tablespecs.showFooterBar = wx.tableShowFooterBar;
		     }else{
			 tablespecs.showFooterBar = appx_session.getProp("gridShowFooterBar");
		     }
                     appx_session.gridcache[wx.tableHashKey] = tablespecs;
		     if( appx_session.gridpropscache && appx_session.gridpropscache[wx.tableHashKey]) {
			 var gridprops = appx_session.gridpropscache[wx.tableHashKey];
			 if( gridprops.records == tablespecs.rowCount ) {
			     appx_session.gridpropscache[wx.tableHashKey].selrows = [];
			 }
			 else {
			     delete appx_session.gridpropscache[wx.tableHashKey];
			 }
		     }
                 }
                 appx_session.currenttabledata[getClientId("appxitem_" + wx.wPositionX + "_" + wx.wPositionY)] = tablespecs;
                 $tag.data("tableHashKey", wx.tableHashKey);
                 break;
        }
    }
    
    if (wx.wBorder) {
        $tag.addClass("appx-border");
        switch (wx.wBorder) {
             case BORDER_NONE:
                 $tag.addClass("appx-border-none");
                 break;
             case BORDER_BEVEL_RAISED:
                 $tag.addClass("appx-border-bevel-raised");
                 break;
             case BORDER_SOFT_BEVEL_RAISED:
                 $tag.addClass("appx-border-soft-bevel-raised");
                 break;
             case BORDER_BEVEL_SUNKEN:
                 $tag.addClass("appx-border-bevel-sunken");
                 break;
             case BORDER_SOFT_BEVEL_SUNKEN:
                 $tag.addClass("appx-border-soft-bevel-sunken");
                 break;
             case BORDER_ETCHED_SUNKEN:
                 $tag.addClass("appx-border-etched-sunken");
                 break;
             case BORDER_ETCHED_RAISED:
                 $tag.addClass("appx-border-etched-raised");
                 break;
             case BORDER_IMAGE_EDITOR:
                 $tag.addClass("appx-border-image-editor");
                 break;
             case BORDER_SIMPLE_LINE:
                 $tag.addClass("appx-border-simple-line");
                 break;
             case BORDER_SIMPLE_LINE_WIDER:
                 $tag.addClass("appx-border-simple-line-wider");
                 break;
        }
        // because of styling on input[type=text], !important flags are needed on border classes and this inline style
        if (wx.wColorFgDisabled) {
            $tag.attr('style', $tag.attr('style') + ';' + 'border-color:' + wx.wColorFgDisabled + ' !important');
        }
    }

    if (wx.wColorBgWallpaper && !bTitlebar) {
        $tag.css("background-color", wx.wColorBgWallpaper);
        if (wx.wColorBgWallpaperNL) $tag.css("opacity", wx.wColorBgWallpaperNL);
    }
    else {

	if ( (wx.wContentAreaFilled === null && wt === WIDGET_TYPE_LABEL)  ||
	     (wx.wContentAreaFilled != null && (!wx.wContentAreaFilled) &&
	      (!bTitlebar)) ) {
            wx.wColorBg = "transparent";
	}
        if (wx.wColorBg) {
	    $tag.css("background-color", wx.wColorBg);
	}
        if (wx.wColorBgNL) {
	    $tag.css("opacity", wx.wColorBgNL);
	}
    }
    if (wx.wColorFg) {
	//only attach foreground color if item hasn't been disabled
	if (!((!bInput) && (wx.wEnabled != null && wx.wEnabled == false) && wx.wColorBgDisabled)){
	    $tag.css("color", wx.wColorFg);
            if (wx.wColorFgNL) $tag.css("opacity", wx.wColorFgNL);
	}
    }
    if ((!bInput) && (wx.wEnabled != null && wx.wEnabled == false) && wx.wColorBgDisabled){
        $tag.css("background-color", wx.wColorBgDisabled);
	$tag.css("-webkit-filter", "grayscale(0%)"); //remove grayscale if item has disabled bg color
    }
    
    if (appx_session.getProp("showOptionNumbers") && wx.wCommand && wx.wCommand < 256) {
        $("<span>").addClass("appx-option").html(wx.wCommand).appendTo($tag);
    }
    
    //TODO? add events only to items in active box
    if (wx.wCommandGotFocus) {
	if ($tag.find(".appxdatevalue").length > 0) {
	    $tag.find(".appxdatevalue").focus(function () { 
		appx_session.valueTimerStop();
		if (!appxIsLocked()) {
                    logca("wx.focus " + wx.wCommandGotFocus);
                    appxwidgetcallback(wx.wCommandGotFocus);
		}
		else {
                    logca("wx.focus: locked");
		}
		
	    });
	}else{
	    $tag.focus(function () { //AppxField.focusGained
		if (appx_session.lastOption && appx_session.lastOption !== "333"){
		    this.selectionStart = this.selectionEnd = this.value.length;
		}
		appx_session.valueTimerStop();
		if (!appxIsLocked()) {
                    logca("wx.focus " + wx.wCommandGotFocus);
                    appxwidgetcallback(wx.wCommandGotFocus);
		}
		else {
                    logca("wx.focus: locked");
		}
            });
	}
    }
    
    if (wx.wCommand >= 20101 && wx.wCommand <= 20106){
	appxWidgetCheckSelected(wx);
    }
    
    if (wx.wLocalList && $tag.is("select")) {
	var delim = wx.wLocalList.charAt(0);
	var st2 = wx.wLocalList.split(delim);
	var arrayLength = st2.length;
	if ($tag.hasClass("appx-nullok"))
	    $tag.append("<option></option>");
	for (var i = 1; i < arrayLength; i++) {
	    var frag = $('<option></option>').val(st2[i]).html(st2[i]);
	    $tag.append(frag);
	}
	$tag.val($tag.attr("data"));
	$tag.addClass("appx-local-list");
    }
    
    if (wx.wCommandLostFocus || ((!isWidget) && appxIsDLUonTabOut(wori))) {
	if (wx.wCommandLostFocus && ((!isWidget) && appxIsDLUonTabOut(wori))){
	    appxAttachBlur($tag, OPT_DLU_AND_TABOUT);
	}else if (wx.wCommandLostFocus){
	    appxAttachBlur($tag, OPT_TAB_OUT);
	}else {
	    appxAttachBlur($tag, OPT_DLU_ON_TABOUT);
	}
    }

    //bind Enter keydown to default button
    if (wx.wDefaultButton && wt == WIDGET_TYPE_BUTTON){
        $tag.addClass("default"); //TODO? should this be an id instead? (unique)
	if ( wx.wBorder != BORDER_NONE ){
	    $tag.addClass("defaultBorder")
	}
    }
    
    //<dnd>
    if (wx.wDragAndDrop) {
        //click has screenX/Y, drag events don't, nw has position: mouse
        //don't need dragover/leave/drop, processed by nw popup
        $tag.on('dragenter', function (e) {
            //console.log('dragenter');
            if (localos_session && localos_session.ws.readyState == 1) {
                eventCatcher(e);
                var ms = {
                    cmd: 'dnd',
                    args: [],
                    handler: '',
                    data: {
                        dbg: false, //show devtools, don't close window
                        wDnD: wx.wDragAndDrop,
                        wPrnt: WIDGET_PRNT_TYPE_WIDGET, //TODO: could be ITEM
                        wPosX: wx.wPositionX + 1,
                        wPosY: wx.wPositionY + 1,
                    }
                };
                localos_session.ws.send(JSON.stringify(ms));
                return false;
            }
        });
    }
    //</dnd>
    if (wx.wEnabled != null && wx.wEnabled == false){
        $tag.prop("disabled", true);
	if (!(wx.wColorBgDisabled != null || wx.wContentAreaFilled == false)){
	    $tag.addClass("no-disabled-data");
	}
    }
    
    //<font>
    if (!wx.wFont && wx.wWidgetType == WIDGET_TYPE_LABEL) wx.wFont = "helvetica";
    if (wx.wFont) {
        //Remove the default font and set CUSTOM.css
        var ff = null;
        switch (wx.wFont) {
             case "helvetica":    ff = (bInput ? "default-input" : "default"); break;
	     case "Courier":      ff = "courier"; break;
	     case "Helvetica":    ff = "arial"; break;
	     case "TimesRoman":   ff = "times-roman"; break;
	     case "Dialog":       ff = "fixed-sys"; break;
	     case "DialogInput":  ff = "terminal"; break;
	     case "ZapfDingbats": ff = "wingdings"; break;
	     case "SanSerif":     ff = "ms-sans-serif"; break;
	     case "Serif":        ff = "ms-serif"; break;
	     case "Monospaced":   ff = "fixed-sys"; break;
        }
        if (ff != null) 
            $tag.addClass("appx-font-"+ff);
	else
	    $tag.css("font-family", wx.wFont);
        
    }
    
    if (wt == WIDGET_TYPE_TABLE) {
        if (wx.wFontSize) {
            $tag.css("line-height", (wx.wFontSize * 1.67) + "px");
        }
        else {
            $tag.css("line-height", (appx_session.basefontsize * 1.5) + "px");
        }
    }

    if (wx.wFontSize && !wx.isBox){
	$tag.css("font-size", wx.wFontSize);
    } else if (wt == WIDGET_TYPE_BUTTON || wt == WIDGET_TYPE_TABLE || bTitlebar){
        $tag.css("font-size", (appx_session.colWidthPx * 1.50));
    } else { //CA20140328: made size smaller to fit full process names in design and also fit rowtext under buttons
        $tag.css("font-size", (appx_session.colWidthPx * 1.67));
    }
    
    if (wx.wFontStyle) {
        switch (wx.wFontStyle) {
             case "bold":
                 $tag.css("font-weight", "bold");
                 break;
             case "italic":
                 $tag.css("font-style", "italic");
                 break;
             case "bolditalic":
                 $tag.css({
                     "font-weight": "bold",
                     "font-style": "italic"
                 });
                 break;
        }
    }
    //</font>

    if (wx.wWidgetType == WIDGET_TYPE_LABEL) {
        if (wx.wSizeH < 2) {
            $tag.css("white-space", "pre");
	    if (wx.wFontSizePercent){
		var tagHeight = parseInt($tag.css("height").substring(0, $tag.css("height").indexOf("px")));
		$tag.css("line-height", (wx.wFontSizePercent * .01 * tagHeight) + "px");
	    }else{
		$tag.css("line-height", $tag.css("height"));
	    }
	}else{
	    if (checkBrowser() == "IE"){
		$tag.css("line-height", "normal");
	    }else{
		$tag.css("line-height", "initial");
	    }
	}
    }
    
    if (wx.wHtmlViewerType == "autoedit") {
        $tag.addClass("ckeditor"); //add class to call in applystyles()
    }

    //<icons> further processing below
    var $img = null;
    var clsIconProp = null;

    if ( (wx.wIconEnabled || wx.wIconDisabled || wx.IconRollover ) && !wx.isBox && wt != WIDGET_TYPE_PICTURE ) {
        $img = $("<img>");

        if ((wx.wEnabled == null || wx.wEnabled == true || wx.wIconDisabled == null) && wx.wIconEnabled){
	    
	    clsIconProp = AppxResource.load(wx.wIconEnabled);
	    $img.addClass(clsIconProp + "_img");
	    
	}
	
	else if (wx.wEnabled == false && wx.wIconDisabled){
            $img.addClass(AppxResource.load(wx.wIconDisabled) + "_img");
	}
	else if (wx.wIconWallpaper){
	    $img.addClass(AppxResource.load(wx.wIconWallpaper) + "_img");
	}
    }
    //if (wx.wIconRollover)//:BELOW
    if ((wx.wIconWallpaper && wt != WIDGET_TYPE_PICTURE) && !bTitlebar) {
        $tag.addClass(AppxResource.load(wx.wIconWallpaper));
        if (!wx.wTilingMode) wx.wTilingMode = MODE_TILE;
        else if (wx.wTilingMode != MODE_TILE) $tag.css("background-repeat", "no-repeat no-repeat");
        switch (wx.wTilingMode) {
             case MODE_TILE:
                 $tag.css("background-repeat", "repeat repeat");
                 break;
             case MODE_EXPAND:
                 $tag.css("background-size", "100% 100%");
                 break;
             case MODE_CENTER:
                 $tag.css("background-position", "center center");
                 break;
             case MODE_N:
                 $tag.css("background-position", "center top");
                 break;
             case MODE_E:
                 $tag.css("background-position", "right center");
                 break;
             case MODE_S:
                 $tag.css("background-position", "center bottom");
                 break;
             case MODE_W:
                 $tag.css("background-position", "left center");
                 break;
             case MODE_NE:
                 $tag.css("background-position", "right top");
                 break;
             case MODE_NW:
                 $tag.css("background-position", "left top");
                 break;
             case MODE_SE:
                 $tag.css("background-position", "right bottom");
                 break;
             case MODE_SW:
                 $tag.css("background-position", "left bottom");
                 break;
        }
    }
    //</icons>
    
    if (wx.wJscript) {
        $tag.bind(wx.wJevent, function () {
            eval(wx.wJscript);
        });
    }

    //<margin> TODO: test if this works like it should
    var cel = appxGetCellSize();
    if (wx.wMarginB)
        $tag.css("padding-bottom", ((wx.wMarginB * cel.h) / 100));
    if (wx.wMarginL)
        $tag.css("padding-left", ((wx.wMarginL * cel.w) / 100));
    if (wx.wMarginR)
        $tag.css("padding-right", ((wx.wMarginR * cel.w) / 100));
    if (!wx.wMarginT && wt == WIDGET_TYPE_TEXT_AREA) wx.wMarginT = 10;
    if (wx.wMarginT)
        $tag.css("padding-top", ((wx.wMarginT * cel.h) / 100));
    
    if (wx.wSetDropShadow) {
        //default values in parseAndSetShadow
        var factor = .01 * ((appx_session.rowHeightPx + appx_session.colWidthPx) / 2);
        var distance = wx.wSetDropShadowDistance * factor;
        var size = Math.round(wx.wSetDropShadowSize * factor);
        var angle = wx.wSetDropShadowAngle * ((Math.PI) / 180);
        var opacity = wx.wSetDropShadowOpacity;
        var color = appxColorXlate(wx.wSetDropShadowColor, opacity);
	
        var horx = Math.round(distance * Math.cos(angle));
        var very = Math.round(distance * Math.sin(angle));
        var blur = size;
        var spread = size / 100;
	
        if (wx.wContentAreaFilled != null && !wx.wContentAreaFilled) {
            var shade = horx + 'px ' + very + 'px ' + blur + 'px ' + color;
            $tag.css("text-shadow", shade);
        }
        else {
            var shade = horx + 'px ' + very + 'px ' + blur + 'px ' + spread + 'px ' + color;
            $tag.css("box-shadow", shade);
        }
    }
    
    //alignment usually handled by container classes :BELOW
    if (wx.wSetHorizTextPos && bInput) {
        switch (wx.wSetHorizTextPos) {
             case "CENTER":
                 $tag.css("text-align", "center");
                 break;
             case "LEFT":
                 $tag.css("text-align", "left");
                 break;
             case "RIGHT":
                 $tag.css("text-align", "right");
                 break;
        }
    }
    
    if (wx.wTooltip) {
        $tag.data('title', wx.wTooltip); // <-- does not support HTML tags in tooltip
        $tag.addClass("appx-tooltip");
        $tag.tooltip({
            fade: 250,
            show: { delay: 600 },
            hide: { delay: 200 },
            open: function (event, ui) {
                setTimeout(function () {
                    $(ui.tooltip).hide('fade');
                }, 3000);
            },
            items: ".appx-tooltip",
            content: function () {
		return $(this).data('title');
            }
        }).on("focusin",function(){ 
            $(this).tooltip("close"); 
        });
    }
    
    //TODO: maybe previous work is not needed when not visible?
    if (wx.wVisible != null && wx.wVisible == false){
	$tag.css("display", "none");
    }
    
    /*==============================================================================
      :BELOW - Start building our label/icon container and rollover events
      ------------------------------------------------------------------------------*/
    
    //<boxLabelIcon>
    if (bInput || wt == WIDGET_TYPE_ROWTEXT) {
        if (wx.wLabel && wt != WIDGET_TYPE_FILE_CHOOSER) {
            if (bInput) { 
		$tag.val(wx.wLabel); //input or textarea without child elements
	    }
            else { 
		$tag.html(wx.wLabel); //has <pre> tag, don't surround with container
	    }
        }
	else {
	    if (itemdata) {
		$tag.html(itemdata); //has <pre> tag, don't surround with container
	    }
	}
    }
    else {
        var $box = $("<div>").addClass("appx--box"); //container
        $box.css({
            "width": "100%"
        });
	
	// If this is a real Appx region box then don't apply justification.
	if( wori.isBox && $tag.hasClass("appxbox") ) {
	    $box.appendTo($tag);
	}
	else {
	    var clsText = appxGetClassText(wx);
	    $box.addClass(clsText).appendTo($tag);
	}
        var $div = $("<div>").addClass("appx-data");
        //keyboard shortcut combinations (Alt+char) wt == WIDGET_TYPE_BUTTON
        //TODO: should we recommend using Alt+Shift or Alt+Ctrl?
        if (wx.wLabel != null && wx.wLabel.substr(0, 6) == "<html>"){
	    wx.wLabel = wx.wLabel.substr(6);
	}
        if (wx.wShortcut && $tag.is("button")) {
            var sc = wx.wShortcut.toUpperCase(); //keyhandler sees uppercase
            if (sc != "D" && sc != "C") { //these don't work nicely (IE)
                $tag.addClass("appx-shortcut-" + sc.charCodeAt(0));
                if (wx.wLabel) {
                    if (wx.wLabel.indexOf("<") == -1) {
			$div.attr("accesskey", sc);
			var lbl = wx.wLabel;
                        var pos = lbl.indexOf(sc);
                        if (pos == -1) pos = lbl.indexOf(sc.toLowerCase());
                        if (pos != -1) {
                            wx.wLabel = (
                                lbl.substr(0, pos) + '<span class="accesskeyunderline">' +
                                    lbl.substr(pos, 1) + "</span>" +
                                    lbl.substr(pos + 1)
                            );
                        }
                    }
                }
            }
        }
	if (wt === WIDGET_TYPE_PROGRESS_BAR){
	    if (wx.wColorBg !== null){
		$div.css({
		    "background-color":wx.wColorBg
		});
	    }
	}
        if ((wx.wLabel && !wx.isBox) && wt != WIDGET_TYPE_LINE) {
            $div.html(wx.wLabel);
	    
            if (bTitlebar)
                $div.width("100%");
        }
	else if( itemdata ) {
            $div.html(itemdata);
	}
        if ($img == null) {
            if (wx.wLabel || itemdata) $box.append($div);
        } else{
	    $box.addClass(ICON);
	    
            if (wx.wSetImageScale && wx.wTilingMode != MODE_EXPAND && wx.wTilingMode != MODE_TILE) { //CharView.loadImage > scaleImage
		var height;
		if (wx.wFontSize){
		    height = (wx.wFontSize * (wx.wSetImageScale / 100)) * .66;
		}else{
		    height = (basefontsize * (wx.wSetImageScale / 100)) * .66;
		}
		$img.height(height);
            }
            var clsIcon = appxGetClassIcon(wx, bTitlebar);
            $box.addClass(clsIcon);
	    /*Only append $img tag if we are not using expand proportional, 
	    **else we add class to attach image to background of main div 
	    **and use css for sizing and placement*/
	    if (clsIcon != "appx-icon-expand-prop"){
		if (clsIcon == ICON_ABOVE_TEXT) {
                    $box.append($img);
                    $box.append($div);
		}
		else if (clsIcon.indexOf("leading") != -1) {
                    $box.addClass(ICON_LEADING);
                    $box.append($img);
                    $box.append($div);
		}
		else {
                    if (clsIcon.indexOf("trailing") != -1)
			$box.addClass(ICON_TRAILING);
                    else if (clsIcon == ICON_BEHIND_TEXT)
			$div.css("text-align", "center");
                    $box.append($div);
                    $box.append($img);
		}
	    }else{
		$box.append($div);
		$box.addClass(clsIconProp + "_ico");
		var bgPos = "center";
		if (wx.wSetHorizAlign != null && wx.wSetVertAlign != null){
		    bgPos = wx.wSetHorizAlign + " " + wx.wSetVertAlign
		}else if (wx.wSetHorizAlign != null){
		    bgPos = wx.wSetHorizAlign + " center";
		    
		}else if(wx.wSetVertAlign != null){
		    bgPos = "center " + wx.wSetVertAlign;
		}
		$box.css({
		    "background-size" : "contain",
		    "background-position" : bgPos,
		    "background-repeat" : "no-repeat"
		});
	    }
        }
    }
    //</boxLabelIcon>
    
    //<rollover>
    if (
	(wx.wColorBgRollover || wx.wColorBgRolloverNL ||
         wx.wColorFgRollover || wx.wColorFgRolloverNL ||
         wx.wIconRollover) && $tag.prop("disabled") === false
    ) { //hover
        if (wx.wIconRollover) {
            $tag.addClass(AppxResource.load(wx.wIconRollover) + "_imgRO");
            var iconRollover = function () {
                var src = $img.attr("src"),
                    srcRO = $tag.attr("srcRO");
                if (src != undefined && srcRO != undefined) {
                    $tag.attr("srcRO", src);
                    $img.attr("src", srcRO);
                }
            };
        }
        $tag.mouseenter(function () {
            //TODO: test if we should pass the wx data as an argument
            if (wx.wColorBgRollover)
                $tag.css("background-color", wx.wColorBgRollover);
            if (wx.wColorBgRolloverNL)
                $tag.css("opacity", wx.wColorBgRolloverNL);
            if (wx.wColorFgRollover)
                $div.css("color", wx.wColorFgRollover);
            if (wx.wColorFgRolloverNL)
                $div.css("opacity", wx.wColorFgRolloverNL);
            if (wx.wIconRollover)
                iconRollover();
        }).mouseleave(function () {
            //container
            if (wx.wColorBgRollover)
                $tag.css("background-color", (wx.wColorBg ? wx.wColorBg : ""));
            if (wx.wColorBgRolloverNL)
                $tag.css("opacity", (wx.wColorBgNL ? wx.wColorBgNL : 1.0));
            //labeltext
            if (wx.wColorFgRollover)
                $div.css("color", (wx.wColorFg ? wx.wColorFg : ""));
            if (wx.wColorFgRolloverNL)
                $div.css("opacity", (wx.wColorFgNL ? wx.wColorFgNL : 1.0));
            if (wx.wIconRollover)
                iconRollover();
        });
    }
    //</rollover>
    
    //<titlebarButtons> had to move this down here
    if (bTitlebar) {
        var $boxTitle = $("<span>").addClass("appx-title-buttons").appendTo($tag);
	if (checkBrowser() !== "Firefox" && checkBrowser() !== "IE"){
	    $boxTitle.addClass("right-padding-only");
	}
        var titleBarButton = function (opt) {
            var $btnTitle = $("<button type='button'>").css({ //addClass titlebutton
                "font-size": ~~((appx_session.colWidthPx) * 1.40) + "px",
                "height": (appx_session.rowHeightPx - 4) + "px",
                "width": (appx_session.rowHeightPx - 4) + "px"
            });
            switch (opt) {
                 case OPT_END:
                     $btnTitle.addClass("appx-title-button-close").html("X");
                     break;
                 case OPT_ENTER:
                     $btnTitle.addClass("appx-title-button-ok").html("&#10004;");
                     break;
                 case OPT_WHATS_THIS:
                     $btnTitle.addClass("appx-title-button-help").html("?");
                     break;
            }
            $btnTitle.appendTo($boxTitle);
        };
        if (wx.wShowHelp == null || wx.wShowHelp == true) {
            titleBarButton(OPT_WHATS_THIS);
        }
        //TODO: add wShowOk & wShowClose to tab order if active box
        if (wx.wShowOk == null || wx.wShowOk == true) {
            titleBarButton(OPT_ENTER);
        }
        if (wx.wShowClose == null || wx.wShowClose == true) {
            titleBarButton(OPT_END);
        }
    }
    //</titlebarButtons>
    if (wx.wClasses) {
	$tag.addClass(wx.wClasses);
    }
    
    if (wx.wExtraAttrs) {
	for( var i=0; i<wx.wExtraAttrs.length; i++ ) {
	    if( wx.wExtraAttrs[i].length == 2 ) {
		$tag.attr(wx.wExtraAttrs[i][0],wx.wExtraAttrs[i][1]);
	    }
	}
    }
    
    if( $tag.hasClass("ckeditor") && wx.wEditorConfig != null ) {
	if( !appx_session.editorConfigs.hasOwnProperty(wx.wEditorConfig) ) {
	    var temp = wx.wEditorConfig.split(".");
	    var cacheid = cleanClassName(appx_session.server + "_" + appx_session.port + "_" + temp[0].substring(1) + "_" + temp[1] + "_" + temp[2]);
	    appx_session.editorConfigs[cacheid] = null;
	    AppxResource.load(wx.wEditorConfig);
	}
	$tag.data("editorConfig",cacheid);
    }
}

function GridCacheProps() {
    var self = this;
    self.lastSortName = null;
    self.lastSortOrder = null;
    self.scrollTop = null;
    self.scrollLeft = null;
    self.selrows = [];
}

//MWidget Object
Widget.prototype.self = null;

function appxWidgetCheckSelected(wx){
    var propName = null;
    var propValue = null;
    switch (wx.wCommand){
	 case 20101:
	     propName = "guiInterface";
	     propValue = appx_session.getProp(propName);
	     break;
	 case 20102:
	     propName = "showOptionNumbers";
	     propValue = appx_session.getProp(propName);
	     break;
	 case 20103:
	     propName = "autoTabOut";
	     propValue = appx_session.getProp(propName);
	     break;
	 case 20104:
	     propName = "autoSelect";
	     propValue = appx_session.getProp(propName);
	     break;
	 case 20105:
	     propName = "dockingScrollbar";
	     propValue = appx_session.getProp(propName);
	     break;
	 case 20106:
	     propName = "showGridlines";
	     propValue = appx_session.getProp(propName);
	     break;
    }
    wx.wSelected = propValue;
}

function Widget(boxid, html, widgetData, widgetExtraData, fullWidget) {

    //current object alias
    var self = this; //http://javascript.about.com/od/objectorientedjavascript/a/oop12.htm

    self.boxid = boxid;
    self.html = html;

    self.forceAntiAlias = -1;
    self.forceMultiLine = -1;
    self.forceMovable = -1;

    self.wClientId = null;
    self.wWidgetId = null;
    self.wLayer = null;
    self.wLabel = null;
    self.wShortLabel = null;
    self.wTooltip = null;
    self.wGroupName = null;
    self.wShortcut = null;
    self.wMovableCommand = null;
    self.wCommand = null;
    self.wCommand2 = null;
    self.wCommandGotFocus = null; //OPT_NULL
    self.wCommandLostFocus = null; //OPT_NULL
    self.wCommandValueAdjusted = null; //OPT_NULL
    self.wLocalList = null;
    self.wEnabled = null;
    self.wUsageMenu = false;
    self.wUsageToolbar = false;
    self.wUsagePopup = false;
    self.wSepBefore = null;
    self.wSepAfter = null;
    self.wRolloverEnabled = null;
    self.wBorderPainted = null;
    self.wContentAreaFilled = null;
    self.wSelected = null;
    self.wFocusPainted = null;
    self.wVisible = null;
    self.wRequiresSelection = null;
    self.wInvert = null;
    self.wPaintTicks = null;
    self.wPaintTickLabels = null;
    self.wSnapToTicks = null;
    self.wShowHelp = null;
    self.wShowClose = null;
    self.wShowOk = null;
    self.wShowMax = null;
    self.wShowMin = null;
    self.wMovable = null;
    self.wResizable = null;
    self.wDockable = null;
    self.wDefaultButton = null;
    self.wTabable = null;
    self.wColorFg = null;
    self.wColorFgNL = null;
    self.wColorBg = null;
    self.wColorBgNL = null;
    self.wColorFgDisabled = null;
    self.wColorFgDisabledNL = null;
    self.wColorBgDisabled = null;
    self.wColorBgDisabledNL = null;
    self.wColorFgRollover = null;
    self.wColorFgRolloverNL = null;
    self.wColorBgRollover = null;
    self.wColorBgRolloverNL = null;
    self.wColorBgWallpaper = null;
    self.wColorBgWallpaperNL = null;
    //self.wColorBorder = null;
    //self.wColorBorderNL = null;
    self.wFileFilter = null;
    // <---

    // not implemented yet.

    self.wMinValue = null;
    self.wMaxValue = null;
    self.wTickMajor = null;
    self.wTickMinor = null;
    self.wTilingMode = null;
    self.wBorder = null;
    self.wWidgetType = null;
    self.wMarginT = null;
    self.wMarginB = null;
    self.wMarginL = null;
    self.wMarginR = null;
    self.wPositionX = null;
    self.wPositionY = null;
    self.wSizeW = null;
    self.wSizeH = null;
    self.wOffsetX = null;
    self.wOffsetY = null;
    self.wOffsetW = null;
    self.wOffsetH = null;
    self.wTabGroup = null;
    self.wFileChooserMode = null;
    self.wEndcapType = null;

    //    var  wPictureLocation = null;

    self.wBoxNumber = null;
    self.wTabSubGroupId = null;
    self.wIconEnabled = null;
    self.wIconDisabled = null;
    self.wIconPressed = null;
    self.wIconSelected = null;
    self.wIconRollover = null;
    self.wIconRolloverSelected = null;
    self.wIconWallpaper = null;
    self.wSetHorizTextPos = null;
    self.wSetVertTextPos = null;
    self.wSetHorizAlign = null;
    self.wSetVertAlign = null;
    self.wOrientation = null;
    self.wFont = null;
    //added these two instead of wFont = {name}-{style}-{size}
    self.wFontSize = null;
    self.wFontSizePercent = null;
    self.wFontStyle = null;
    self.wSetFormSize = null;
    self.wSetProcessType = null;
    self.wSetFrameClass = null;
    self.wSetImageScale = null;
    self.wSetLineWeight = null;
    self.wSetStrokeWeight = null;
    self.wSetBorderArc = null;
    self.wSetAntiAlias = null;
    self.wSetDropShadow = null;
    self.wSetDropShadowSize = null;
    self.wSetDropShadowOpacity = null;
    self.wSetDropShadowColor = null;
    self.wSetDropShadowDistance = null;
    self.wSetDropShadowAngle = null;
    self.wSetScroller = null;
    self.wForceWidget = null;
    self.wStrokePattern = null;
    self.wStrokePatternOffset = null;
    self.wLineUnitBase = null;
    self.wHtmlViewerType = null; //chris@praclox.nl_20120418_R47_AppxHtmlControl
    self.wDragAndDrop = null; //chris@praclox.nl_20120427_R83_DragAndDrop
    self.wResFont = null;
    self.wResBundle = null;
    self.wEditorConfig = null;
    self.wPcbId = null;
    self.wFrameImageKey = null;
    self.wHashSig = null;
    self.wMenuNo = null; //MMenu()
    self.wMenuUse = null; //MMenu()

    self.delimiter = '\t';
    self.delimiterStr = "" + self.delimiter;
    self.widgetLen = 0;
    self.widgetData = widgetData; //null;
    self.widgetExtraData = widgetExtraData;
    self.widgetExtraLen = 0;
    self.wJscript = null;
    self.wJevent = null;
    self.bytesInCount = 0;
    self.tableHashKey = null;
    self.tableShowRowNumbers = null;
    self.tableShowFooterBar = null;

    if (fullWidget) {
        self.size_row = fullWidget.size_row;
        self.size_col = fullWidget.size_col;
    }

    self.parseData();
}

/* <position> icon & text */

//icon align [sub 0ad widget(extend)(button)]
//TH = WIDGET TEXT POS HORIZ
//TV = WIDGET TEXT POS VERT
//TM = WIDGET TILING MODE

// ICON_NULL             0 TH = _   & TV = _   & TM = _
// ICON_BEHIND_TEXT      1 TH = C   & TV = _|C
// ICON_ABOVE_TEXT       2 TH = C   & TV = B
// ICON_TRAILING_TEXT    3 TH = L   & TV = _|C
// ICON_BELOW_TEXT       4 TH = C   & TV = T
// ICON_LEADING_TEXT     5 TH = _|R & TV = _|C
// ICON_TRAILING_BOTTOM  6 TH = L   & TV = B
// ICON_LEADING_BOTTOM   7 TH = _|R & TV = B
// ICON_TRAILING_TOP     8 TH = L   & TV = T
// ICON_LEADING_TOP      9 TH = _|R & TV = T
// ICON_EXPAND_FILL     10 TH = _   & TV = _   & TM = EXPAND
// ICON_EXPAND_PROP     11 TH = _   & TV = _   & TM = TILE

var ICON = "appx-icon";
var ICON_LEADING = "appx-icon-leading"; //extra class for all leading forms
var ICON_TRAILING = "appx-icon-trailing"; //extra class for all trailing forms
var ICON_NULL = "appx-icon-null";
var ICON_BEHIND_TEXT = "appx-icon-behind-text";
var ICON_ABOVE_TEXT = "appx-icon-above-text";
var ICON_TRAILING_TEXT = "appx-icon-trailing-text";
var ICON_BELOW_TEXT = "appx-icon-below-text";
var ICON_LEADING_TEXT = "appx-icon-leading-text";
var ICON_TRAILING_BOTTOM = "appx-icon-trailing-bottom";
var ICON_LEADING_BOTTOM = "appx-icon-leading-bottom";
var ICON_TRAILING_TOP = "appx-icon-trailing-top";
var ICON_LEADING_TOP = "appx-icon-leading-top";
var ICON_EXPAND_FILL = "appx-icon-expand-fill";
var ICON_EXPAND_PROP = "appx-icon-expand-prop";

var appxGetClassIcon = function (wx, mTitlebar) {
    var wt = parseInt(wx.wWidgetType);
    var cls = wt == WIDGET_TYPE_LABEL ? ICON_TRAILING_TEXT : ICON_LEADING_TEXT;
    if ((wx.wTilingMode == MODE_EXPAND || wx.wTilingMode == MODE_TILE) && !mTitlebar ) {
        switch (wx.wTilingMode) {
             case MODE_EXPAND:
                 cls = ICON_EXPAND_FILL;
                 break;
             case MODE_TILE:
                 cls = ICON_EXPAND_PROP;
                 break;
             default:
                 console.log("appxGetClassIcon: unhandled tiling " + wx.wTilingMode);
        }
    }
    else {
        switch (wx.wSetHorizTextPos) {
             case 'LEFT':
                 switch (wx.wSetVertTextPos) {
                      case 'BOTTOM':
                          cls = ICON_TRAILING_BOTTOM;
                          break;
                      case 'TOP':
                          cls = ICON_TRAILING_TOP;
                          break;
                      default: //null,'','CENTER'
                          cls = ICON_TRAILING_TEXT;
                          break;
                 }
                 break;
             case 'CENTER':
                 switch (wx.wSetVertTextPos) {
                      case 'BOTTOM':
                          cls = ICON_ABOVE_TEXT;
                          break;
                      case 'TOP':
                          cls = ICON_BELOW_TEXT;
                          break;
                      default: //null,'','CENTER'
                          cls = ICON_BEHIND_TEXT;
                          break;
                 }
                 break;
             default: //null,'','RIGHT'
                 switch (wx.wSetVertTextPos) {
                      case 'BOTTOM':
                          cls = ICON_LEADING_BOTTOM;
                          break;
                      case 'TOP':
                          cls = ICON_LEADING_TOP;
                          break;
                      default: //null,'','CENTER'
                          cls = ICON_LEADING_TEXT;
                          break;
                 }
                 break;
        }
    }
    return cls;
};

//widget text align
//AH = WIDGET ALIGN HORIZ
//AV = WIDGET ALIGN VERT
// TEXT_NULL          0 AH = _   & AV = _
// TEXT_CENTER        1 AH = _|C & AV = _|C
// TEXT_TOP           2 AH = _|C & AV = T
// TEXT_RIGHT         3 AH = R   & AV = _|C
// TEXT_BOTTOM        4 AH = _|C & AV = B
// TEXT_LEFT          5 AH = L   & AV = _|C
// TEXT_UPPER_RIGHT   6 AH = R   & AV = T
// TEXT_UPPER_LEFT    7 AH = L   & AV = T
// TEXT_LOWER_RIGHT   8 AH = R   & AV = B
// TEXT_LOWER_LEFT    9 AH = L   & AV = B

var TEXT_NULL = "appx-text-null";
var TEXT_CENTER = "appx-text-center";
var TEXT_TOP = "appx-text-top";
var TEXT_RIGHT = "appx-text-right";
var TEXT_BOTTOM = "appx-text-bottom";
var TEXT_LEFT = "appx-text-left";
var TEXT_UPPER_RIGHT = "appx-text-upper-right";
var TEXT_UPPER_LEFT = "appx-text-upper-left";
var TEXT_LOWER_RIGHT = "appx-text-lower-right";
var TEXT_LOWER_LEFT = "appx-text-lower-left";

var appxGetClassText = function (wx) {
    var cls = TEXT_LEFT; //TEXT_NULL

    if( wx.wSizeH && wx.wSizeH > 1 ) {
	if( wx.wWidgetType == WIDGET_TYPE_RAW_TEXT )
	    cls = TEXT_UPPER_LEFT;
	else
	    cls = TEXT_LEFT;
    }

    if( wx.wWidgetType == WIDGET_TYPE_HTML_VIEWER )
	cls = TEXT_UPPER_LEFT;

    if (wx.wWidgetType == WIDGET_TYPE_BUTTON )
        cls = TEXT_CENTER;

    if  ((wx.wWidgetType == WIDGET_TYPE_LABEL) && (wx.wSizeH > 1)){
	var browser = checkBrowser();
	if (browser == "Edge" || browser == "IE"){
	    cls = TEXT_NULL;
	}
    }
    
    if (wx.wSetHorizAlign || wx.wSetVertAlign) {
        switch (wx.wSetHorizAlign) {
             case 'LEFT':
                 switch (wx.wSetVertAlign) {
                      case 'BOTTOM':
                          cls = TEXT_LOWER_LEFT;
                          break;
                      case 'TOP':
                          cls = TEXT_UPPER_LEFT;
                          break;
                      default: //null,'','CENTER'
                          cls = TEXT_LEFT;
                          break;
                 }
                 break;
             case 'RIGHT':
                 switch (wx.wSetVertAlign) {
                      case 'BOTTOM':
                          cls = TEXT_LOWER_RIGHT;
                          break;
                      case 'TOP':
                          cls = TEXT_UPPER_RIGHT;
                          break;
                      default: //null,'','CENTER'
                          cls = TEXT_RIGHT;
                          break;
                 }
                 break;
             default: //null,'','CENTER'
                 switch (wx.wSetVertAlign) {
                      case 'BOTTOM':
                          cls = TEXT_BOTTOM;
                          break;
                      case 'TOP':
                          cls = TEXT_TOP;
                          break;
                      default: //null,'','CENTER'
                          cls = TEXT_CENTER;
                          break;
                 }
                 break;
        }
    }
    return cls;
};
/* </position> */

//comm.msg.MWidget
//Set Drop Shadow - @SDS={visible},{distance},{size},{angle},{opacity},{color} 
//SDS: T,250,500,50,45,green
Widget.prototype.parseAndSetShadow = function (token) {
    try {
        var tokens = token.split(",");
        if (tokens.length > 0 && tokens[0].toUpperCase() == "F")
            this.wSetDropShadow = false;
        else
            this.wSetDropShadow = true;

        if (tokens.length > 1 && tokens[1].length > 0)
            this.wSetDropShadowDistance = parseInt(tokens[1]);
        else
            this.wSetDropShadowDistance = 25;

        if (tokens.length > 2 && tokens[2].length > 0)
            this.wSetDropShadowSize = parseInt(tokens[2]);
        else
            this.wSetDropShadowSize = this.wSetDropShadowDistance;

        if (tokens.length > 3 && tokens[3].length > 0)
            this.wSetDropShadowAngle = parseInt(tokens[3]);
        else
            this.wSetDropShadowAngle = 45.0;

        if (tokens.length > 4 && tokens[4].length > 0)
            this.wSetDropShadowOpacity = parseInt(tokens[4]) * .01;
        else
            this.wSetDropShadowOpacity = 0.5;

        if (tokens.length > 5 && tokens[5].length > 0)
            this.wSetDropShadowColor = tokens[5];
        else
            this.wSetDropShadowColor = "#000000";
    }
    catch (e) {
        console.log("MWidget - bad setDropShadow " + e + "," + token);
	console.log(e.stack);
    }
}

Widget.prototype.parseData = function () { //CreateFromJSON(widgetparams)
    try {
        if (this.widgetData) {
            var st2 = null;
            var widgetparams = this.parseDataIntoPairs();
            for (var ct = 0; ct < widgetparams.length; ct++) {
                var key = widgetparams[ct].key;
                var val = widgetparams[ct].value.replace(/ *$/,"").replace(/##\'\'##/g, '\"');
                switch (key) {
                     case "XA":
			 var attrs = val.split(";");
			 var p2 = [];
			 $.each(attrs, function (idx, obj) {
			     var p1 = obj.split(":");
			     p2.push(p1);
			 });
			 this.wExtraAttrs = p2;
                         break;
                     case "CLSS":
                         this.wClasses = val;
                         break;
                     case "CLID":
                         this.wClientId = val;
                         break;
		     case "SAA": // Set Anti Aliasing, not needed
		         break;
                     case "SAC":
                         this.wCommand = parseInt(val);
                         break;
                     case "SAC2":
                         this.wCommand2 = parseInt(val);
                         break;
                     case "SGFC":
                         this.wCommandGotFocus = parseInt(val);
                         break;
                     case "SLFC":
                         this.wCommandLostFocus = parseInt(val);
                         break;			
                     case "SB":
                         this.wBorder = parseInt(val);
                         break;
                         //?case "SBF": break;
                     case "SBN":
                         this.wBoxNumber = parseInt(val);
                         break;
                     case "SBP":
                         if (val == 'F') this.wBorder = BORDER_NONE;
                         break;
                     case "SCAF":
                         this.wContentAreaFilled = (val != 'F');
                         break;
                     case "SCT":
                         this.wEndcapType = parseInt(val);
                         break;
                     case "SDB":
                         this.wDefaultButton = (val != 'F');
                         break;
                     case "SDBC":
                         if (val.length > 7) {
                             this.wColorBgDisabled = val.substr(0, 7);
                             this.wColorBgDisabledNL = parseInt("0x"+val.substr(7)) / 255;
                         }
                         else {
                             this.wColorBgDisabled = val;
                         }
                         break;
                     case "SDFC":
                         if (val.length > 7) {
                             this.wColorFgDisabled = val.substr(0, 7);
                             this.wColorFgDisabledNL = parseInt("0x"+val.substr(7)) / 255;
                         }
                         else {
                             this.wColorFgDisabled = val;
                         }
                         break;
                     case "SDI":
                         this.wIconDisabled = val;
                         break;
                     case "SDND": //chris@praclox.nl_20120427_R83_DragAndDrop
                         this.wDragAndDrop = val;
                         break;
                     case "SDS":
                         this.parseAndSetShadow(val);
                         break;
                     case "SE":
                         this.wEnabled = (val != 'F');
                         break;
                     case "SEBC":
                     case "SBC":
                         if (val.length > 7) {
                             this.wColorBg = val.substr(0, 7);
                             this.wColorBgNL = parseInt("0x"+val.substr(7)) / 255;
                         }
                         else {
                             this.wColorBg = val;
                             this.wColorBgNL = null;
                         }
                         break;
                     case "SEFC":
                     case "SFC":
                         if (val.length > 7) {
                             this.wColorFg = val.substr(0, 7);
                             this.wColorFgNL = parseInt("0x"+val.substr(7)) / 255;
                         }
                         else {
                             this.wColorFg = val;
                             this.wColorFgNL = null;
                         }
                         break;
                     case "SF":
                         st2 = val.split(",");
                         if (st2.length > 0) {
                             this.wFont = st2[0];
                         }
                         if (st2.length > 1) {
                             this.wFontStyle = st2[1].toLowerCase();
                             if (this.wFontStyle == "bold+italic" || this.wFontStyle == "bold + italic")
                                 this.wFontStyle = "bolditalic";
                         }
                         if (st2.length > 2) {
                             this.wFontSize = parseInt(st2[2]);
                             // Sanity Check
                             if (this.wFontSize >= presetFontSizes.length)
                                 this.wFontSize = 0;
                             // Convert to percentage from preset list
                             this.wFontSize = presetFontSizes[this.wFontSize];
			     this.wFontSizePercent = this.wFontSize;
                             // Convert percentage to real size
			     if( this.wWidgetType == WIDGET_TYPE_TABLE ) {
				 this.wFontSize = (this.wFontSize * .01 * (appx_session.colWidthPx) * 1.50);
			     } else {
				 this.wFontSize = (this.wFontSize * .01 * (appx_session.colWidthPx) * 1.70);
			     }
                         }
                         break;
                     case "SFCM":
                         this.wFileChooserMode = val;
                         break;
                     case "SFIK":
                         this.wFrameImageKey = val;
                         break;
                     case "SGN":
                         this.wGroupName = val;
                         break;
                     case "SHA":
                         this.wSetHorizAlign = val;
                         break;
                     case "SHCL":
                         this.wShowClose = (val != 'F');
                         break;
                     case "SHHL":
                         this.wShowHelp = (val != 'F');
                         break;
                     case "SHOK":
                         this.wShowOk = (val != 'F');
                         break;
                     case "SHS":
                         this.wHashSig = parseInt(val);
                         break;
                     case "SHTM":
                         this.wHtmlViewerType = val;
                         break;
                     case "SHTP":
                         this.wSetHorizTextPos = val;
                         break;
                     case "SI":
                         this.wIconEnabled = val;
                         break;
		     case "SINV":
			 this.wInvert = (val != 'F');
			 break;
		     case "SIS":
                         var iSize = parseInt(val);
                         if (iSize >= presetFontSizes.length) iSize = 0;
                         // Convert to percentage from preset list
                         if (iSize > 0)
                             this.wSetImageScale = parseInt(presetFontSizes[iSize]);
                         else
                             console.log("MWidget.parseData() Invalid Widget Image Scale = " + val + "for widget = " + this.widgetData.toString());
                         break;
                     case "SJE":
                         this.wJevent = val;
                         break;
                     case "SJS":
                         this.wJscript = val;
                         break;
                     case "SL":
                         st2 = val.split(",");
                         this.wPositionY = parseInt(st2[1]);
                         this.wPositionX = parseInt(st2[0]);
                         break;
                     case "SLL":
			 this.wLocalList = val;
                         break;
                     case "SLN":
                         this.wLayer = parseInt(val);
                         break;
                     case "SLUB":
                         this.wLineUnitBase = val;
                         break;
                     case "SLW":
                         this.wSetLineWeight = parseInt(val);
                         break;
                     case "SM":
                         st2 = val.split(",");
                         if (st2.length > 0) this.wMarginT = parseInt(st2[0]);
                         if (st2.length > 1) this.wMarginL = parseInt(st2[1]);
                         if (st2.length > 2) this.wMarginB = parseInt(st2[2]);
                         if (st2.length > 3) this.wMarginR = parseInt(st2[3]);
                         break;
                     case "SMATS":
                         this.wTickMajor = parseInt(val);
                         break;;
                     case "SMAX":
                         this.wMaxValue = parseInt(val);
                         break;
                     case "SMIN":
                         this.wMinValue = parseInt(val);
                         break;
                     case "SMITS":
                         this.wTickMinor = parseInt(val);
                         break;
                     case "SMN": //MMenu()
                         this.wShortcut = val;
                         break;
                     case "SMT": //MMenu()
                         this.wMenuNo = parseInt(val);
                         break;
                     case "SMV":
                         this.wMovable = true;
                         this.wMovableCommand = val;
                         break;
		     case "SO":
			 if (val === "VERTICAL"){
			     this.wOrientation = "vertical";
			 }else{
			     this.wOrientation = "horizontal";
			 }
			 break;
                     case "SOFF": //micro positioning (percentages)
                         st2 = val.split(",");
                         if (st2.length > 0) {
                             this.wOffsetY = parseInt(st2[0]);
                             if (this.wOffsetY > 127) {
                                 this.wOffsetY = this.wOffsetY - 256;
                             }
                         }
                         if (st2.length > 1) {
                             this.wOffsetX = parseInt(st2[1]);
                             if (this.wOffsetX > 127) {
                                 this.wOffsetX = this.wOffsetX - 256;
                             }
                         }
                         if (st2.length > 2) {
                             this.wOffsetW = parseInt(st2[2]);
                             if (this.wOffsetW > 127) {
                                 this.wOffsetW = this.wOffsetW - 256;
                             }
                         }
                         if (st2.length > 3) {
                             this.wOffsetH = parseInt(st2[3]);
                             if (this.wOffsetH > 127) {
                                 this.wOffsetH = this.wOffsetH - 256;
                             }
                         }
                         break;
                     case "SPCB":
                         this.wPcbId = parseInt(val);
                         break;
                     case "SPT":
                         this.wPaintTicks = (val != 'F');
                         break;
                     case "SPTL":
                         this.wPaintTickLabels = (val != 'F');
                         break;
                     case "SRBC":
                         //turn on alpha color bit
                         //check length of string
                         //if greater 6, last two is alpha
                         //use rgbs(0,0,0,0)
                         //20140328 chris@praclox.nl: aye
                         if (val.length > 7) {
                             this.wColorBgRollover = val.substr(0, 7);
                             this.wColorBgRolloverNL = parseInt("0x"+val.substr(7)) / 255;
                         }
                         else {
                             this.wColorBgRollover = val;
                         }
                         break;
                     case "SRE":
                         this.wRolloverEnabled = (val != 'F');
                         break;
                     case "SREC":
                         this.wEditorConfig = val;
                         break;
                     case "SRFC":
                         if (val.length > 7) {
                             this.wColorFgRollover = val.substr(0, 7);
                             this.wColorFgRolloverNL = parseInt("0x"+val.substr(7)) / 255;
                         }
                         else {
                             this.wColorFgRollover = val;
                         }
                         break;
                     case "SRI":
                         this.wIconRollover = val;
                         break;
                     case "SSP":
                         this.wStrokePattern = val;
                         break;
                     case "SSPO":
                         this.wStrokePatternOffset = val;
                         break;
                     case "SST":
                         this.wShortLabel = val;
                         break;
		     case "SSTT":
			 this.wSnapToTicks = (val != 'F');
			 break;
                     case "SSU":
                         var mask = parseInt(val);
                         if ((mask & WIDGET_SEP_BEFORE) == WIDGET_SEP_BEFORE)
                             this.wSepBefore = true;
                         if ((mask & WIDGET_SEP_AFTER) == WIDGET_SEP_AFTER)
                             this.wSepAfter = true;
                         break;
                     case "SSZ":
                         st2 = val.split(",");
                         this.wSizeW = parseInt(st2[0]);
                         this.wSizeH = parseInt(st2[1]);
                         break;
                     case "ST": //MMenu()
                         this.wLabel = val;
                         break;
                     case "STG": //MMenu()
                         this.wTabGroup = parseInt(val);
                         break;
                     case "STM":
                         this.wTilingMode = parseInt(val);
                         break;
                     case "STSG":
                         this.wTabSubGroupId = val;
                         break;
                     case "STTT":
                         this.wTooltip = val;
                         break;
                     case "SV":
                         this.wVisible = (val != 'F');
                         break;
                     case "SVA":
                         this.wSetVertAlign = val;
                         break;
                     case "SVAC":
                         //for listbox change event
                         //CA20141118:#3183 Key pause
                         this.wCommandValueAdjusted = val;
                         break;
                     case "SVTP":
                         this.wSetVertTextPos = val;
                         break;
                     case "SWBC":
                         if (val.length > 7) {
                             this.wColorBgWallpaper = val.substr(0, 7);
                             this.wColorBgWallpaperNL = parseInt("0x"+val.substr(7)) / 255;
                         }
                         else {
                             this.wColorBgWallpaper = val;
                         }
                         break;
                     case "SWI":
                         this.wIconWallpaper = val;
                         break;
                     case "SWID":
                         this.wWidgetId = val;
                         break;
                     case "SWT":
                         this.wWidgetType = parseInt(val);
                         break;
                     case "SWU":
                         var mask = parseInt(val);
                         if ((mask & WIDGET_USAGE_MENU) == WIDGET_USAGE_MENU)
                             this.wUsageMenu = true;
                         if ((mask & WIDGET_USAGE_TOOLBAR) == WIDGET_USAGE_TOOLBAR)
                             this.wUsageToolbar = true;
                         if ((mask & WIDGET_USAGE_POPUP) == WIDGET_USAGE_POPUP)
                             this.wUsagePopup = true;
                         break;
                     case "TSRN": //Table Show Row Numbers
                         this.tableShowRowNumbers = (val == 'T');
                         break;
                     case "TSFB": //Table Show Footer Bar
                         this.tableShowFooterBar = (val == 'T');
                         break;
                     case "USE": //MMenu()
                         this.wMenuUse = (val == 'T');
                         break;
                     default:
                         console.log("WP: unhandled " + key + "=" + val);
                         break;
                }
            }
        }

        if (this.wWidgetType == WIDGET_TYPE_TABLE)
            this.tableHashKey = "pcb" + this.wPcbId + "fik" + this.wFrameImageKey + "sig" + this.wHashSig + "r" + this.wPositionY + "c" + this.wPositionX + "h" + this.wSizeH + "w" + this.wSizeW;

        if (this.wLayer == null) {
            this.wLayer = 10;
            if (this.wWidgetType != null) {
                switch (parseInt(this.wWidgetType)) {
                     case WIDGET_TYPE_LABEL:
                     case WIDGET_TYPE_PICTURE:
                     case WIDGET_TYPE_LINE:
                         this.wLayer = 20; //button overlay issues, off for now
                         break;
                     case WIDGET_TYPE_TABLE:
                         this.wLayer = 9; //button overlay issues, off for now
                         break;
                     case WIDGET_TYPE_BOX:
                         this.wLayer = 30; //button overlay issues, off for now
                         break;
                     case WIDGET_TYPE_ROWTEXT:
                         this.wLayer = 25; //put beneath buttons
                         break;
                }
            }
        }
    }
    catch (ex) {
        console.log("Widget.parseData: " + ex);
	console.log(ex.stack);
    }
};

Widget.prototype.parseDataIntoPairs = function () {
    try {
        var widgetparams = {};
        var cnt = 0,
            pos;
        var widgetparam = "[";

        // We must preprcess the string so we don't accidentally split on an @ cahracter in the data, like in an email address
        var blockStart = -1;
        var blockEnd = -1;
        var offsetSave = -1;
        var parserStr = this.widgetData.replace(/\n/g,"").replace(/\r/g,"");
        var mywidgetrawdata = [];
        for (var i = 0; i < parserStr.length; i++) {
            if (parserStr.charAt(i) == '@') {
                offsetSave = i;
            }
            if (parserStr.charAt(i) == '=' && offsetSave >= 0) {
                if (blockStart >= 0) {
                    mywidgetrawdata.push(parserStr.substring(blockStart, offsetSave));
                }
                blockStart = offsetSave + 1;
                offsetSave = -1;
            }
        }

        if (blockStart >= 0 && blockStart < parserStr.length) {
            mywidgetrawdata.push(parserStr.substring(blockStart));
        }

        while (mywidgetrawdata.length > 0) {
            var kvpair = mywidgetrawdata.shift();
            if (kvpair.trim().length > 0 && kvpair != " ") {
                var pos = kvpair.indexOf("=");
                if (pos > 0) {
                    var kp0 = kvpair.substr(0, pos);
                    var kp1 = kvpair.substr(pos + 1).replace(/\"/g, '##\'\'##');
                    if (kp0.trim().length > 0) {
                        if (cnt > 0) widgetparam += ", ";
                        widgetparam += '{ "key": "' + kp0 + '", "value": "' + kp1 + '"}';
                    }
                }
                else {
                    logactivity("kvpair length not > 1: " + kvpair);
                }
                cnt++;
            }
        }
        widgetparam = widgetparam.replace(/\\/g, "\\\\");
        widgetparams = JSON.parse("" + widgetparam + "]");
    }
    catch (ex) {
        console.log("WIDGET PARSE ERROR:\n\n" + widgetparam);
	console.log(ex.stack);
    }
    return widgetparams;
};

//we may need to make this generic and put in utils lib
function parseTableData(tabledata) {
    try {
        // Convert buffer to string
        var newstring = "";
        newstring += '["';
        for (var i = 0; i < tabledata.length; i++) {
            switch (tabledata[i].charCodeAt(0)) {
                 case 0x01:
                     newstring += '"],["';
                     break;
                 case 0x02:
                     newstring += '","';
                     break;
                 case 0x03:
                     newstring += '||';
                     break;
                 case 0x00: // null
                 case 0x0A: // linefeed
                 case 0x08: // backspace
                 case 0x0C: // formfeed
                 case 0x0D: // cr
                 case 0x09: // tab
                     newstring += ' ';
                     break;
                 case 0x5C: // backslash
                 case 0x22: // double quote
                     newstring += '\\';
                     newstring += tabledata[i];
                     break;
                 default:
                     newstring += tabledata[i];
                     break;
            }
        }
        newstring += '"]';
        return JSON.parse('{"tabledata": [' + newstring + ']}');
    }
    catch (ex) {
        console.log("parseTableData() failed: " + ex);
	console.log(ex.stack);
        return "";
    }
}

function scrollSwitch(gridName,pagerName,coldata,elid) {
    $("#"+gridName).jqGrid('GridUnload');
    $('#'+pagerName).remove();
    $('#'+gridName).remove();

    var scroll =appx_session.getProp("gridVirtualScroll");
    appx_session.setProp("gridVirtualScroll", ""+!scroll);
    createGridMongo(coldata, elid);
    catchEnterKeyInGridPager();
}

function createGridMongo(coldata, elid) {
    try {
	var dbgcnt = 0;
        var id = elid;
	var elem = $("#" + id);
	var fontSize = elem.css("font-size");
	var lineHeight = elem.css("line-height");
        var numrows = coldata.rowCount;
        var numcols = coldata.colCount;
        var expand = coldata.expand;
	var colmodel = coldata.colModel;
	var collist = coldata.collist;
	var floatcol = coldata.floatcol >= 0 ? true : false;
	var selectedRows = coldata.selectedRows;
	var selectedKeys = coldata.selectedKeys;
	var widthpx = $(elem).width();
	var widthcur = coldata.widthcur;
	var tableSize = null;
	var pagerName = "pager_"+id;
	var gridName = "newtablewidget_" + id;
	var rowsPerPage = 50;
	var navPage = 1;
	var sortName = "initialSort";
	var sortOrder = "asc";
	var sortColumns = coldata.lastSortColumns;
	var showRowNumbers = coldata.showRowNumbers;
	var showFooterBar = coldata.showFooterBar;
	var filters = null;
	var vertScrollbar = 18;
	var height = (parseInt($(elem).height())) + 1;
        var pnav = $('<div id="'+pagerName+'" style="height: '+appx_session.rowHeightPx+'px"></div>').appendTo(elem);
        var table = $('<table id="'+gridName+'">');

	if (!showFooterBar){
	    pnav.css({
		"display": "none"
	    });
	}

	/*18px for scroll bar + 2px to fit inside our table div */
	tableSize = widthpx - 20;
	
        $(elem).append(table);
        $(elem).append(pnav);

	if ( appx_session.getProp("gridFilterToolbar") == true){
	    height -= parseInt(pnav.height()) - appx_session.rowHeightPx;
	}else{
	    if (showFooterBar){
		height -= parseInt(pnav.height());
	    }
	    
	}

	if( coldata.height )
	    height = coldata.height;

	coldata.height = height;
	

	if ((numrows * appx_session.rowHeightPx) < height){
	    vertScrollbar = 0;
	    tableSize += 18; /*Add scrollbar width back in*/
	}
	
	/*If table has float column set width to resize to remaining table space*/
	if (floatcol){
	    for (var i = 0; i < coldata.colModel.length; i++){
		if (coldata.colModel[i].hidden !== true){
		    if (coldata.colModel[i].fixed !== true){
			coldata.colModel[i].width = tableSize - widthcur;
		    }
		}
	    }
	}




	// Create the grid
	if( coldata["lastPage"] )
	    navPage = coldata.lastPage;

	if( coldata["lastSortName"] ){
	    sortName = coldata.lastSortName[coldata.lastSortName.length-1];
	}else {
	    //If records are initially selected navigate to correct page
	    if( selectedRows.length > 0 && navPage == 1 ) {
		navPage = Math.ceil(selectedRows[0] / rowsPerPage);
	    }
	}

	if( coldata["lastSortOrder"] )
	    sortOrder = coldata.lastSortOrder[coldata.lastSortOrder.length-1];

	if( coldata["filters"] )
	    filters = coldata.filters;
/* This flicker reducing code seems to break the scrollback rows in a table, so turning it off (1 of 2)
	if( numrows > 0 )
	    appx_session.pendingResources.length++;
*/
	var search = false;
	var postData = null;
	if (coldata.datalookupid != "BlankTable"){
	    postData = { "collection": coldata.collection, "datalookupid": coldata.datalookupid, "collist": collist, "lastSortName[]": coldata.lastSortName, "lastSortOrder[]": coldata.lastSortOrder };
	    if( filters && filters.length > 0 ) {
		search = true;
		postData["filters"] = filters;
	    }
	}
	var gridConfig = {
	    "search": search,
	    "width": tableSize,
	    "scrollOffset": vertScrollbar,
	    "caption": "",
	    "colModel": colmodel,
	    "datatype": "json",
	    "height": height,
	    "hidegrid": false,
	    "multiselect": true,
	    "postData": postData,
	    "rowList": [10,20,30,40,50],
	    "scroll": 1,
	    "pager": "#"+pagerName,
	    "page": navPage,
	    "sortname": sortName,
	    "sortorder": sortOrder,
	    "viewrecords": true,
	    "gridview":true,
	    "loadonce": false,
	    "rowNum": rowsPerPage,
	    "rownumbers":showRowNumbers,
	    "scrollrows": false,
	    "url": appx_session.appxDataCacheUrl,
	    "sortable": function (perm){
		coldata.lastSortColumns = perm;
	    },
	    "loadComplete": function () {
		var browser = checkBrowser();
		if (browser == "Edge" || browser == "IE"){
		    //Do nothing for these browsers, their disabled checkboxes look ok.
		}
		else {
		    $.each($("input[type=checkbox][disabled]"), function (k, el0) {
			    $(el0).removeAttr('disabled')
			    .addClass('disabled')
			    .keypress(function(event) {
				    event.preventDefault();
				})   
			    .click(function (event) {
				    event.preventDefault();
				});
			});
		}
/* This flicker reducing code seems to break the scrollback rows in a table, so turning it off (2 of 2)
		if( numrows > 0 && appx_session.pendingResources.length > 0) {
		    appx_session.pendingResources.length--;
		    if (appx_session.pendingResources.length == 0) {
			appxSetStatusStateText(APPX_STATE_READY);
			if (!screenflipped){
			    appxshowscreen();
			}
		    }
		}
*/
		if (sortColumns){
		    $(this).jqGrid("remapColumns",sortColumns, true);
		}
		coldata.lastPage = $(this).jqGrid("getGridParam", "page");

		var self = this;
		/*Set last sort order data*/
		    var gridSortN = $(self).jqGrid("getGridParam", "sortname");
		    var gridSortO = $(self).jqGrid("getGridParam", "sortorder");
		    if( coldata["lastSortName"] ){
			var inColdata = false;
			for ( var i = 0; i < coldata.lastSortName.length; i++){
			    if (coldata.lastSortName[i] === gridSortN){
				if ( (gridSortN !== "initialSort") &&
				     (i === coldata.lastSortName.length -1)){

				    coldata.lastSortOrder[i] = gridSortO
				}
				inColdata = true;
			    }
			}
			if (!inColdata){
			    coldata.lastSortName.push(gridSortN);
			    coldata.lastSortOrder.push(gridSortO);
			}
			
		    }else {
			coldata.lastSortName = [gridSortN];
			coldata.lastSortOrder = [gridSortO];
		    }
		    
		    var curPostData = $(self).jqGrid("getGridParam", "postData");
		    
		    delete curPostData.lastSortName;
		    delete curPostData.lastSortOrder;
		    curPostData.lastSortName = coldata.lastSortName;
		    curPostData.lastSortOrder = coldata.lastSortOrder;
		    curPostData.showFooterBar = showFooterBar;
		    curPostData.rowCount = numrows;
		    curPostData.colCount = numcols;
		    curPostData.colModel = colmodel;

		    //Only toggle selection if screen has finished repainting.
		    if( coldata.selectedKeys && coldata.selectedKeys.length > 0 ) {
			var a = function(){
			    $(self).jqGrid("resetSelection");
			    for( var i = 0; i<coldata.selectedKeys.length; i++ ) {
				$(self).jqGrid("setSelection",coldata.selectedKeys[i], false);
			    }
			}
			if (!appxIsLocked()){
			    a.call();
			}else{
			    appx_session.runOnUnlock.push(a);
			}
		    }

		if( coldata && (coldata.scrollTop > 0 || coldata.scrollLeft > 0 )) {
		    $(this).closest(".ui-jqgrid-bdiv").scrollTop(coldata.scrollTop);
		    $(this).closest(".ui-jqgrid-bdiv").scrollLeft(coldata.scrollLeft);
		    coldata.scrollTop = 0;
		    coldata.scrollLeft = 0;
		}
	    },
	    "onSelectRow": function (id) {
		if (!($(this).closest(".appxbox").hasClass("appx-not-modifiable") || appxIsLocked())) {
		    var cmd = $(this).closest(".appxtablewidget").data("action").command;
		    $(this).closest(".appxtablewidget").data("selkeys", coldata.selectedKeys);
		    
		    coldata.selectedKeys = $(this).jqGrid('getGridParam', 'selarrrow');
		    
		    appx_session.tablerowcleartimeout = setTimeout(function () {
			if (cmd && appx_session.tablerowcleartimeout) {
			    appxwidgetcallback(cmd);
			}
		    }, 500);
		}
	    },
	    "ondblClickRow": function (rowid, iRow, iCol, e) {
		if (appx_session.tablerowcleartimeout) {
		    clearTimeout(appx_session.tablerowcleartimeout);
		    appx_session.tablerowcleartimeout = null;
		}
		
		if (!($(this).closest(".appxbox").hasClass("appx-not-modifiable") || appxIsLocked())) {
		    var cmd = $(this).closest(".appxtablewidget").data("action").command2;
		    
		    coldata.selectedKeys = $(this).jqGrid('getGridParam', 'selarrrow');
		    
		    $(this).closest(".appxtablewidget").data("selkeys", coldata.selectedKeys);
		    
		    if (cmd) {
			appxwidgetcallback(cmd);
		    }
		}
	    },
	    "beforeSelectRow": function (rowid, e) {
		if (!e.ctrlKey && !e.metaKey && !e.shiftKey) {
		    $(this).jqGrid('resetSelection');
		}
		else if (e.shiftKey) {
		    var initialRowSelect = $(this).jqGrid('getGridParam', 'selrow');
		    $(this).jqGrid('resetSelection');
		    
		    var CurrentSelectIndex = $(this).jqGrid('getInd', rowid);
		    var InitialSelectIndex = $(this).jqGrid('getInd', initialRowSelect);
		    
		    if (CurrentSelectIndex > InitialSelectIndex) {
			var startID = initialRowSelect;
			var endID = rowid;
		    }
		    else {
			var startID = rowid;
			var endID = initialRowSelect;
		    }
		    
		    var shouldSelectRow = false;
		    var mytableid = $(this);
		    $.each($(this).jqGrid("getDataIDs"), function (_, id) {
			if ((shouldSelectRow = id == startID || shouldSelectRow) && (id != rowid)) {
			    $(mytableid).jqGrid('setSelection', id, false);
			}
			return id != endID;
		    });
		}
		return true;
	    }
	};
	
	if (appx_session.getProp("gridVirtualScroll") != true) {
	    gridConfig.scroll = false;
	}

	if (!showFooterBar){
	    $("#"+pagerName).hide();
	}
	setTimeout(function(){
	
	    $("#newtablewidget_" + id).jqGrid(gridConfig);

            // if the parent box is not active then block the UI for the grid
            if ($("#newtablewidget_" + id).closest(".appxbox").hasClass("appx-not-modifiable")) {
		$("#newtablewidget_" + id).closest(".ui-jqgrid").block({
                    "message": null,
                    "overlayCSS": {
			"backgroundColor": '#000',
			"opacity": 0.0,
			"cursor": null
                    }
		});
            }

	    for( var i=0; i<colmodel.length; i++ ) {
		if( colmodel[i].align ) {
		    $("#"+gridName).jqGrid("setLabel",colmodel[i].name,"",{"text-align":colmodel[i].align});
		}
	    }


            $("#newtablewidget_" + id).jqGrid('hideCol', 'cb');

	    $("#newtablewidget_" + id).setGridWidth(widthpx - 2, false);
	    
	    $('#'+$("#newtablewidget_" + id).jqGrid('getGridParam','selrow')).focus();

	    if (appx_session.getProp("gridFilterToolbar") == true){
		$("#newtablewidget_" + id).jqGrid("filterToolbar", {stringResult: true, searchOnEnter : false, defaultSearch: "cn"});
	    }
	    
            $("#newtablewidget_" + id).jqGrid('navGrid',"#"+pagerName,{edit:false,add:false,del:false},{},{},{},{multipleSearch: true, closeAfterSearch: true })
		.jqGrid('navButtonAdd',"#"+pagerName,{
		    caption:"",
		    buttonicon:"ui-icon-newwin",
		    onClickButton: function() {scrollSwitch(gridName, pagerName, coldata, elid)},
		    position: "last",
		    title:"Toggle grid view between scrolling and paging",
		    cursor: "pointer"
		});
	    
	    $("#"+pagerName+"_left"  ).addClass("appx-grid-pager-left");
	    $("#"+pagerName+"_center").addClass("appx-grid-pager-center");
	    $("#"+pagerName+"_right" ).addClass("appx-grid-pager-right");

	    $("#gview_"+gridName + " div").css({
		"font-size": fontSize,
		"line-height": (parseFloat(lineHeight.substring(0,4))).toFixed(2)+"px"
	    });
	},0);
	
	
	
    } catch (e) {
        console.log("widget.createGrid: " + e);
	console.log(e.stack);
    }
}

var presetFontSizes = [100, 25, 33, 50, 66, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 140, 150, 175, 200, 300, 400, 500, 600, 700, 800, 900, 1000];

//Document
var BORDER_NONE = 5;
var BORDER_SIMPLE_LINE = 10;
var BORDER_SIMPLE_LINE_WIDER = 20;
var BORDER_ETCHED_SUNKEN = 30;
var BORDER_ETCHED_RAISED = 40;
var BORDER_BEVEL_SUNKEN = 50;
var BORDER_BEVEL_RAISED = 60;
var BORDER_SOFT_BEVEL_SUNKEN = 70;
var BORDER_SOFT_BEVEL_RAISED = 80;
var BORDER_IMAGE_EDITOR = 90;
var BORDER_MAX = BORDER_IMAGE_EDITOR;

//CharView
var MODE_TILE = 1;
var MODE_EXPAND = 2;
var MODE_CENTER = 3;
var MODE_N = 4;
var MODE_E = 5;
var MODE_S = 6;
var MODE_W = 7;
var MODE_NE = 8;
var MODE_NW = 9;
var MODE_SE = 10;
var MODE_SW = 11;
/*var MODE_EXPAND_PROP         = 12;
  var MODE_MENU_ITEM           = 13;
  var MODE_TOOL_BUTTON         = 14;
  var MODE_WINDOW_TITLE        = 15;*/

var TOKENIZE_WIDGET_TYPE_BUTTON = 1;
var TOKENIZE_WIDGET_TYPE_MENU = 2;
var TOKENIZE_WIDGET_TYPE_MENUHDR = 3;
var TOKENIZE_WIDGET_TYPE_BOX = 4;
var TOKENIZE_WIDGET_TYPE_ITM = 5;

var WIDGET_PRNT_TYPE_FRAME = 2;
var WIDGET_PRNT_TYPE_IMAGE = 3;
var WIDGET_PRNT_TYPE_ITEM = 5;
var WIDGET_PRNT_TYPE_WIDGET = 6;
var WIDGET_PRNT_TYPE_CHILD = 8;

var WIDGET_SEP_BEFORE = 1;
var WIDGET_SEP_AFTER = 2;

var WIDGET_TYPE_NONE = 0;
var WIDGET_TYPE_BUTTON = 1;
var WIDGET_TYPE_LABEL = 2;
var WIDGET_TYPE_PICTURE = 3;
var WIDGET_TYPE_BOX = 4;
var WIDGET_TYPE_LINE = 5;
var WIDGET_TYPE_RAW_TEXT = 20;
var X_WIDGET_TYPE_SPINNER = 30;
var WIDGET_TYPE_SLIDER = 31;
var X_WIDGET_TYPE_RADIO_DIAL = 32;
var WIDGET_TYPE_PROGRESS_BAR = 33;
var X_WIDGET_TYPE_SCROLL_BAR = 34;
var WIDGET_TYPE_CHECK_BOX = 40;
var X_WIDGET_TYPE_RADIO_BUTTON = 41;
var WIDGET_TYPE_LISTBOX = 42;
var X_WIDGET_TYPE_TOGGLE_BUTTON = 43;
var WIDGET_TYPE_PASSWORD = 50;
var WIDGET_TYPE_FILE_CHOOSER = 51;
var WIDGET_TYPE_COLOR_CHOOSER = 52;
var WIDGET_TYPE_TEXT_AREA = 59;
var WIDGET_TYPE_HTML_VIEWER = 60;
var X_WIDGET_TYPE_RTF_VIEWER = 61;
var X_WIDGET_TYPE_CODE_VIEWER = 62;
var WIDGET_TYPE_HTML_EDITOR = 63;
var WIDGET_TYPE_FLASH_PLAYER = 64;
var WIDGET_TYPE_MEDIA_PLAYER = 65;
var X_WIDGET_TYPE_WEB_BROWSER = 66;
var X_WIDGET_TYPE_BUTTON_GROUP = 70;
var WIDGET_TYPE_DATE_CHOOSER = 80;
var WIDGET_TYPE_TABLE = 90;
var WIDGET_TYPE_ROWTEXT = 91;
var WIDGET_TYPE_IMG_EDITOR_FRAME = 200;
var WIDGET_TYPE_ILF_EDITOR_FRAME = 201;
var WIDGET_TYPE_PRT_ON_SCR_FRAME = 202;

var WIDGET_USAGE_MENU = 1;
var WIDGET_USAGE_TOOLBAR = 2;
var WIDGET_USAGE_POPUP = 4;

