<commit_before>define([
    'dojo/_base/declare',
    'dijit/_WidgetBase',
    'dijit/_TemplatedMixin',
    'dijit/_WidgetsInTemplateMixin',

    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/topic',
    'dojo/dom-style',
    'dojo/dom-construct',
    'dojo/number',
    'dojo/aspect',

    'esri/geometry/Point',

    'proj4js/proj4',

    'dojo/text!./OpenExternalMap/templates/OpenExternalMap.html',

    'dojo/i18n!./OpenExternalMap/nls/resource',

    'gis/plugins/Google',

    'dijit/form/Button',
    'dijit/form/ToggleButton',

    'xstyle/css!./OpenExternalMap/css/OpenExternalMap.css'
], function (
    declare,
    _WidgetBase,
    _TemplatedMixin,
    _WidgetsInTemplateMixin,

    lang,
    array,
    topic,
    domStyle,
    domConstruct,
    number,
    aspect,

    Point,

    proj4,

    template,

    i18n,

    GoogleMapsLoader,

    Button
) {
    var google;
    return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
        widgetsInTemplate: true,
        templateString: template,
        i18n: i18n,
        mapClickMode: null,

        // the map providers and buttons  to include
        mapProviders: [
            {
                name: 'Google Maps',
                buttons: [
                    {
                        label: 'Hybrid Map',
                        iconClass: 'fa fa-google fa-fw',
                        url: 'https://www.google.com/maps/place/@{lat},{lng},{zoom}z/data=!3m1!1e3' //https://www.google.com/maps/@{lat},{lng},1000a,20y,0t/data=!3m1!1e3'
                    },
                    {
                        label: 'StreetView',
                        iconClass: 'fa fa-street-view fa-fw',
                        isStreetView: true,
                        url: 'https://maps.google.com/maps?q=&layer=c&cbll={lat},{lng}'
                    }
                ]
            },
            {
                name: 'Bing Maps',
                buttons: [
                    {
                        label: 'Hybrid Map',
                        iconClass: 'fa fa-windows fa-fw',
                        url: 'https://www.bing.com/maps?cp={lat}~{lng}&lvl={zoom}&sstyle=h'
                    },
                    {
                        label: 'Bird\'s Eye',
                        iconClass: 'fa fa-building fa-fw',
                        url: 'https://bing.com/maps/?cp={lat}~{lng}&style=o'
                    },
                    {
                        label: 'Streetside',
                        iconClass: 'fa fa-street-view fa-fw',
                        url: 'https://bing.com/maps/?cp={lat}~{lng}&lvl=19&dir=113.8911&pi=-0.284&style=x&v=2&sV=1'
                    }
                ]
            },
            {
                name: 'Other Maps',
                buttons: [
                    {
                        label: 'MapQuest',
                        iconClass: 'fa fa-globe fa-fw',
                        url: 'https://www.mapquest.com/map?q={lat},{lng}&zoom={zoom}&maptype=hybrid'
                    },
                    {
                        label: 'OpenStreetMap',
                        iconClass: 'fa fa-globe fa-fw',
                        url: 'http://www.openstreetmap.org/?lat={lat}&lon={lng}&zoom={zoom}'
                    }
                ]
            }
        ],

        // group the providers by their name, otherwise group all buttons together
        groupProviders: true,

        // set the Lat/Lng from the map's center point when the map's extent is updated
        useMapCenter: true,

        // Show coordinate in Degrees, Minutes and Seconds
        showDMS: true,

        // conversion factor for DMS
        unitScale: 2,

        // is street view available at the coordinates
        streetViewAvailable: false,

        // not currently implemented
        useEmbeddedWindow: false,

        // in case this changes some day
        proj4BaseURL: 'https://epsg.io/',

        //  options are ESRI, EPSG and SR-ORG
        // See http://spatialreference.org/ for more information
        proj4Catalog: 'EPSG',

        // if desired, you can load a projection file from your server
        // instead of using one from spatialreference.org
        // i.e., http://server/projections/102642.js
        projCustomURL: null,

        _mapButtons: [],

        postCreate: function () {
            this.inherited(arguments);

            this.own(topic.subscribe('mapClickMode/currentSet', lang.hitch(this, 'setMapClickMode')));

            if (this.parentWidget) {
                if (this.parentWidget.toggleable) {
                    this.own(aspect.after(this.parentWidget, 'toggle', lang.hitch(this, function () {
                        this.onLayoutChange(this.parentWidget.open);
                    })));
                }
            }

            //load the google api asynchronously
            GoogleMapsLoader.load(lang.hitch(this, function (g) {
                //store a reference to google
                google = g;
            }));

            var wkid = this.map.spatialReference.wkid;
            if (wkid === 102100) { // ESRI --> EPSG
                wkid = 3857;
            }
            var key = this.proj4Catalog + ':' + String(wkid);
            if (!proj4.defs[key]) {
                var url = this.proj4BaseURL + String(wkid) + '.js';
                require([url]);
            }

            this.addProviders();

            this.map.on('click', lang.hitch(this, 'onMapPoint'));
            if (this.useMapCenter) {
                this.map.on('extent-change', lang.hitch(this, 'onMapCenter'));
                if (this.map.extent) {
                    this.onMapCenter({
                        extent: this.map.extent
                    });
                }
            }
        },

        addProviders: function () {
            var btnContainer, btn, providerClass, buttonsClass, buttonClass;
            if (!this.groupProviders) {
                btnContainer = domConstruct.create('div', {
                    class: 'externalMapButtons'
                }, this.providerContainer);
            }
            array.forEach(this.mapProviders, lang.hitch(this, function (provider) {
                if (this.groupProviders) {
                    if (provider.name) {
                        providerClass = 'mapLabel-' + provider.name.replace(' ', '-').toLowerCase();
                        domConstruct.create('div', {
                            class: 'mapLabel ' + providerClass,
                            innerHTML: provider.name
                        }, this.providerContainer);
                    }

                    buttonsClass = 'mapButtons-' + provider.name.replace(' ', '-').toLowerCase();
                    btnContainer = domConstruct.create('div', {
                        class: 'mapButtons ' + buttonsClass
                    }, this.providerContainer);
                }

                array.forEach(provider.buttons, lang.hitch(this, function (button) {
                    providerClass = (provider.name) ? 'mapButton-' + provider.name.replace(' ', '-').toLowerCase() : '';
                    buttonClass = ((providerClass.length > 0) ? providerClass : 'mapButton') + '-' + button.label.replace(' ', '-').toLowerCase();
                    btn = new Button({
                        label: button.label,
                        class: 'mapButton ' + buttonClass + ' ' + providerClass,
                        iconClass: button.iconClass
                    });
                    btn.on('click', lang.hitch(this, 'openMap', button));
                    btn.startup();
                    btn.set('disabled', true);
                    btn.placeAt(btnContainer, 'last');
                    this._mapButtons.push(btn);
                }));
            }));
        },

        onMapPoint: function (evt) {
            if (this.mapClickMode === 'externalmap') {
                var mapPoint = evt.mapPoint;
                if (!mapPoint) {
                    return;
                }
                this.processPoint(mapPoint);
            }
        },

        onMapCenter: function (opts) {
            var extent = opts.extent;
            var centerPoint = extent.getCenter();
            this.processPoint(centerPoint);
        },

        onClose: function () {
            if (this.mapClickMode === 'externalmap') {
                this.connectMapClick();
            }
        },

        onLayoutChange: function (open) {
            if (!open) {
                this.onClose();
            }
        },

        placePoint: function () {
            if (this.OEMapButtonDijit.get('checked')) {
                this.disconnectMapClick();
            } else {
                this.connectMapClick();
            }
        },

        disconnectMapClick: function () {
            this.OEMapButtonDijit.set('checked', true);
            this.map.setMapCursor('crosshair');
            topic.publish('mapClickMode/setCurrent', 'externalmap');
        },

        connectMapClick: function () {
            this.OEMapButtonDijit.set('checked', false);
            this.map.setMapCursor('auto');
            topic.publish('mapClickMode/setDefault');
        },

        processPoint: function (point) {
            var latLng = this.convertCoordinates(point);
            this.checkStreetView(latLng);

            this.OEMapLatitudeDijit.set('value', latLng[1].toFixed(6));
            this.OEMapLongitudeDijit.set('value', latLng[0].toFixed(6));
            window.setTimeout(lang.hitch(this, 'connectMapClick'), 100);

            this.checkButtons();
        },

        openMap: function (button) {
            if (!this.checkCoordinates(button)) {
                return;
            }
            var lat = this.OEMapLatitudeDijit.get('value');
            var lng = this.OEMapLongitudeDijit.get('value');
            var zoom = '';
            if (this.map.spatialReference.wkid === 102100) {
                zoom = this.map.getLevel();
            }
            var url = lang.replace(button.url, {
                lat: lat,
                lng: lng,
                zoom: zoom
            });

            if (this.useEmbeddedWindow) {
                // do something here with floating window
            } else {
                window.open(url);
            }
        },

        checkCoordinates: function (button) {
            if (!this.validateCoordinates('lat')) {
                topic.publish('growler/growl', {
                    title: button.label,
                    message: i18n.latitudeInvalid,
                    level: 'error',
                    timeout: 3000
                });
                return false;
            }

            if (!this.validateCoordinates('lng')) {
                topic.publish('growler/growl', {
                    title: button.label,
                    message: i18n.longitudeInvalid,
                    level: 'error',
                    timeout: 3000
                });
                return false;
            }

            if (button.isStreetView && !this.streetViewAvailable) {
                topic.publish('growler/growl', {
                    title: button.label,
                    message: i18n.streetViewNotAvailable,
                    level: 'error',
                    timeout: 3000
                });
                return false;
            }

            return true;

        },

        validateCoordinates: function (checkOne) {
            var lat = this.OEMapLatitudeDijit.get('value');
            if (checkOne === 'lat' || !checkOne) {
                if (lat === '' || isNaN(lat) || lat < -85.05 || lat > 85.05) {
                    return false;
                }
            }

            var lng = this.OEMapLongitudeDijit.get('value');
            if (checkOne === 'lng' || !checkOne) {
                if (lng === '' || isNaN(lng) || lng < -180 || lng > 180) {
                    return false;
                }
            }

            return true;
        },

        checkStreetView: function (latLng) {
            /*
                Only check for availability of street view if a key is provided.
                Currently, there is not a reliable method to check that the key is valid.
            */
            if (!GoogleMapsLoader.KEY || !google) {
                this.streetViewAvailable = true;
                return;
            }

            this.streetViewAvailable = false;
            if (!this.panoramaService) {
                this.panoramaService = new google.maps.StreetViewService();
            }
            if (google) {
                var googlePt = new google.maps.LatLng(latLng[1], latLng[0]);
                this.panoramaService.getPanoramaByLocation(googlePt, 50, lang.hitch(this, function (geoPt, res) {
                    this.streetViewAvailable = (res === google.maps.StreetViewStatus.OK);
                }));
            }
        },

        checkButtons: function () {
            var valid = this.validateCoordinates();
            array.forEach(this._mapButtons, function (button) {
                button.set('disabled', !valid);
            });
        },

        latitudeChanged: function () {
            var valid = this.validateCoordinates('lat'), dms = '';
            if (valid && this.showDMS) {
                var val = this.OEMapLatitudeDijit.get('value');
                dms = this.decToDMS(val, true);
            }
            this.OEMapLatitudeDMSDijit.innerHTML = dms;
            this.checkButtons();
        },

        longitudeChanged: function () {
            var valid = this.validateCoordinates('lng'), dms = '';
            if (valid && this.showDMS) {
                var val = this.OEMapLongitudeDijit.get('value');
                dms = this.decToDMS(val, false);
            }
            this.OEMapLongitudeDMSDijit.innerHTML = dms;
            this.checkButtons();
        },

        decToDMS: function (l, lat) {
            var dir = '?',
                abs = Math.abs(l),
                deg = parseInt(abs, 10),
                min = (abs - deg) * 60,
                minInt = parseInt(min, 10),
                sec = number.round((min - minInt) * 60, this.unitScale),
                minIntTxt = (minInt < 10) ? '0' + minInt : minInt,
                secTxt = (sec < 10) ? '0' + sec : sec;

            if (lat) {
                dir = (l > 0) ? 'N' : 'S';
            } else {
                dir = (l > 0) ? 'E' : 'W';
            }

            return deg + '° ' + minIntTxt + '\' ' + secTxt + '" ' + dir;
        },

        convertCoordinates: function (mapPoint) {
            // convert the map point's coordinate system into lat/long
            var wkid = this.map.spatialReference.wkid;
            if (wkid === 102100) { // ESRI --> EPSG
                wkid = 3857;
            }
            var key = this.proj4Catalog + ':' + String(wkid);
            return proj4(proj4.defs[key]).inverse([mapPoint.x, mapPoint.y]);
        },

        setMapClickMode: function (mode) {
            this.mapClickMode = mode;
        }
    });
});<commit_msg>fix potential conflict with mouse click in OpenExternalMap widget<commit_after>define([
    'dojo/_base/declare',
    'dijit/_WidgetBase',
    'dijit/_TemplatedMixin',
    'dijit/_WidgetsInTemplateMixin',

    'dojo/_base/lang',
    'dojo/_base/array',
    'dojo/topic',
    'dojo/dom-style',
    'dojo/dom-construct',
    'dojo/number',
    'dojo/aspect',

    'esri/geometry/Point',

    'proj4js/proj4',

    'dojo/text!./OpenExternalMap/templates/OpenExternalMap.html',

    'dojo/i18n!./OpenExternalMap/nls/resource',

    'gis/plugins/Google',

    'dijit/form/Button',
    'dijit/form/ToggleButton',

    'xstyle/css!./OpenExternalMap/css/OpenExternalMap.css'
], function (
    declare,
    _WidgetBase,
    _TemplatedMixin,
    _WidgetsInTemplateMixin,

    lang,
    array,
    topic,
    domStyle,
    domConstruct,
    number,
    aspect,

    Point,

    proj4,

    template,

    i18n,

    GoogleMapsLoader,

    Button
) {
    var google;
    return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
        widgetsInTemplate: true,
        templateString: template,
        i18n: i18n,
        mapClickMode: null,

        // the map providers and buttons  to include
        mapProviders: [
            {
                name: 'Google Maps',
                buttons: [
                    {
                        label: 'Hybrid Map',
                        iconClass: 'fa fa-google fa-fw',
                        url: 'https://www.google.com/maps/place/@{lat},{lng},{zoom}z/data=!3m1!1e3' //https://www.google.com/maps/@{lat},{lng},1000a,20y,0t/data=!3m1!1e3'
                    },
                    {
                        label: 'StreetView',
                        iconClass: 'fa fa-street-view fa-fw',
                        isStreetView: true,
                        url: 'https://maps.google.com/maps?q=&layer=c&cbll={lat},{lng}'
                    }
                ]
            },
            {
                name: 'Bing Maps',
                buttons: [
                    {
                        label: 'Hybrid Map',
                        iconClass: 'fa fa-windows fa-fw',
                        url: 'https://www.bing.com/maps?cp={lat}~{lng}&lvl={zoom}&sstyle=h'
                    },
                    {
                        label: 'Bird\'s Eye',
                        iconClass: 'fa fa-building fa-fw',
                        url: 'https://bing.com/maps/?cp={lat}~{lng}&style=o'
                    },
                    {
                        label: 'Streetside',
                        iconClass: 'fa fa-street-view fa-fw',
                        url: 'https://bing.com/maps/?cp={lat}~{lng}&lvl=19&dir=113.8911&pi=-0.284&style=x&v=2&sV=1'
                    }
                ]
            },
            {
                name: 'Other Maps',
                buttons: [
                    {
                        label: 'MapQuest',
                        iconClass: 'fa fa-globe fa-fw',
                        url: 'https://www.mapquest.com/map?q={lat},{lng}&zoom={zoom}&maptype=hybrid'
                    },
                    {
                        label: 'OpenStreetMap',
                        iconClass: 'fa fa-globe fa-fw',
                        url: 'http://www.openstreetmap.org/?lat={lat}&lon={lng}&zoom={zoom}'
                    }
                ]
            }
        ],

        // group the providers by their name, otherwise group all buttons together
        groupProviders: true,

        // set the Lat/Lng from the map's center point when the map's extent is updated
        useMapCenter: true,

        // Show coordinate in Degrees, Minutes and Seconds
        showDMS: true,

        // conversion factor for DMS
        unitScale: 2,

        // is street view available at the coordinates
        streetViewAvailable: false,

        // not currently implemented
        useEmbeddedWindow: false,

        // in case this changes some day
        proj4BaseURL: 'https://epsg.io/',

        //  options are ESRI, EPSG and SR-ORG
        // See http://spatialreference.org/ for more information
        proj4Catalog: 'EPSG',

        // if desired, you can load a projection file from your server
        // instead of using one from spatialreference.org
        // i.e., http://server/projections/102642.js
        projCustomURL: null,

        _mapButtons: [],

        postCreate: function () {
            this.inherited(arguments);

            this.own(topic.subscribe('mapClickMode/currentSet', lang.hitch(this, 'setMapClickMode')));

            if (this.parentWidget) {
                if (this.parentWidget.toggleable) {
                    this.own(aspect.after(this.parentWidget, 'toggle', lang.hitch(this, function () {
                        this.onLayoutChange(this.parentWidget.open);
                    })));
                }
            }

            //load the google api asynchronously
            GoogleMapsLoader.load(lang.hitch(this, function (g) {
                //store a reference to google
                google = g;
            }));

            var wkid = this.map.spatialReference.wkid;
            if (wkid === 102100) { // ESRI --> EPSG
                wkid = 3857;
            }
            var key = this.proj4Catalog + ':' + String(wkid);
            if (!proj4.defs[key]) {
                var url = this.proj4BaseURL + String(wkid) + '.js';
                require([url]);
            }

            this.addProviders();

            this.map.on('click', lang.hitch(this, 'onMapPoint'));
            if (this.useMapCenter) {
                this.map.on('extent-change', lang.hitch(this, 'onMapCenter'));
                if (this.map.extent) {
                    this.onMapCenter({
                        extent: this.map.extent
                    });
                }
            }
        },

        addProviders: function () {
            var btnContainer, btn, providerClass, buttonsClass, buttonClass;
            if (!this.groupProviders) {
                btnContainer = domConstruct.create('div', {
                    class: 'externalMapButtons'
                }, this.providerContainer);
            }
            array.forEach(this.mapProviders, lang.hitch(this, function (provider) {
                if (this.groupProviders) {
                    if (provider.name) {
                        providerClass = 'mapLabel-' + provider.name.replace(' ', '-').toLowerCase();
                        domConstruct.create('div', {
                            class: 'mapLabel ' + providerClass,
                            innerHTML: provider.name
                        }, this.providerContainer);
                    }

                    buttonsClass = 'mapButtons-' + provider.name.replace(' ', '-').toLowerCase();
                    btnContainer = domConstruct.create('div', {
                        class: 'mapButtons ' + buttonsClass
                    }, this.providerContainer);
                }

                array.forEach(provider.buttons, lang.hitch(this, function (button) {
                    providerClass = (provider.name) ? 'mapButton-' + provider.name.replace(' ', '-').toLowerCase() : '';
                    buttonClass = ((providerClass.length > 0) ? providerClass : 'mapButton') + '-' + button.label.replace(' ', '-').toLowerCase();
                    btn = new Button({
                        label: button.label,
                        class: 'mapButton ' + buttonClass + ' ' + providerClass,
                        iconClass: button.iconClass
                    });
                    btn.on('click', lang.hitch(this, 'openMap', button));
                    btn.startup();
                    btn.set('disabled', true);
                    btn.placeAt(btnContainer, 'last');
                    this._mapButtons.push(btn);
                }));
            }));
        },

        onMapPoint: function (evt) {
            if (this.mapClickMode === 'externalmap') {
                var mapPoint = evt.mapPoint;
                if (!mapPoint) {
                    return;
                }
                this.processPoint(mapPoint);
            }
        },

        onMapCenter: function (opts) {
            var extent = opts.extent;
            var centerPoint = extent.getCenter();
            this.processPoint(centerPoint);
        },

        onClose: function () {
            if (this.mapClickMode === 'externalmap') {
                this.connectMapClick();
            }
        },

        onLayoutChange: function (open) {
            if (!open) {
                this.onClose();
            }
        },

        placePoint: function () {
            if (this.OEMapButtonDijit.get('checked')) {
                this.disconnectMapClick();
            } else {
                this.connectMapClick();
            }
        },

        disconnectMapClick: function () {
            this.OEMapButtonDijit.set('checked', true);
            this.map.setMapCursor('crosshair');
            topic.publish('mapClickMode/setCurrent', 'externalmap');
        },

        connectMapClick: function () {
            this.OEMapButtonDijit.set('checked', false);
            if (this.mapClickMode === 'externalmap') {
                this.map.setMapCursor('auto');
                topic.publish('mapClickMode/setDefault');
            }
        },

        processPoint: function (point) {
            var latLng = this.convertCoordinates(point);
            this.checkStreetView(latLng);

            this.OEMapLatitudeDijit.set('value', latLng[1].toFixed(6));
            this.OEMapLongitudeDijit.set('value', latLng[0].toFixed(6));
            window.setTimeout(lang.hitch(this, 'connectMapClick'), 100);

            this.checkButtons();
        },

        openMap: function (button) {
            if (!this.checkCoordinates(button)) {
                return;
            }
            var lat = this.OEMapLatitudeDijit.get('value');
            var lng = this.OEMapLongitudeDijit.get('value');
            var zoom = '';
            if (this.map.spatialReference.wkid === 102100) {
                zoom = this.map.getLevel();
            }
            var url = lang.replace(button.url, {
                lat: lat,
                lng: lng,
                zoom: zoom
            });

            if (this.useEmbeddedWindow) {
                // do something here with floating window
            } else {
                window.open(url);
            }
        },

        checkCoordinates: function (button) {
            if (!this.validateCoordinates('lat')) {
                topic.publish('growler/growl', {
                    title: button.label,
                    message: i18n.latitudeInvalid,
                    level: 'error',
                    timeout: 3000
                });
                return false;
            }

            if (!this.validateCoordinates('lng')) {
                topic.publish('growler/growl', {
                    title: button.label,
                    message: i18n.longitudeInvalid,
                    level: 'error',
                    timeout: 3000
                });
                return false;
            }

            if (button.isStreetView && !this.streetViewAvailable) {
                topic.publish('growler/growl', {
                    title: button.label,
                    message: i18n.streetViewNotAvailable,
                    level: 'error',
                    timeout: 3000
                });
                return false;
            }

            return true;

        },

        validateCoordinates: function (checkOne) {
            var lat = this.OEMapLatitudeDijit.get('value');
            if (checkOne === 'lat' || !checkOne) {
                if (lat === '' || isNaN(lat) || lat < -85.05 || lat > 85.05) {
                    return false;
                }
            }

            var lng = this.OEMapLongitudeDijit.get('value');
            if (checkOne === 'lng' || !checkOne) {
                if (lng === '' || isNaN(lng) || lng < -180 || lng > 180) {
                    return false;
                }
            }

            return true;
        },

        checkStreetView: function (latLng) {
            /*
                Only check for availability of street view if a key is provided.
                Currently, there is not a reliable method to check that the key is valid.
            */
            if (!GoogleMapsLoader.KEY || !google) {
                this.streetViewAvailable = true;
                return;
            }

            this.streetViewAvailable = false;
            if (!this.panoramaService) {
                this.panoramaService = new google.maps.StreetViewService();
            }
            if (google) {
                var googlePt = new google.maps.LatLng(latLng[1], latLng[0]);
                this.panoramaService.getPanoramaByLocation(googlePt, 50, lang.hitch(this, function (geoPt, res) {
                    this.streetViewAvailable = (res === google.maps.StreetViewStatus.OK);
                }));
            }
        },

        checkButtons: function () {
            var valid = this.validateCoordinates();
            array.forEach(this._mapButtons, function (button) {
                button.set('disabled', !valid);
            });
        },

        latitudeChanged: function () {
            var valid = this.validateCoordinates('lat'), dms = '';
            if (valid && this.showDMS) {
                var val = this.OEMapLatitudeDijit.get('value');
                dms = this.decToDMS(val, true);
            }
            this.OEMapLatitudeDMSDijit.innerHTML = dms;
            this.checkButtons();
        },

        longitudeChanged: function () {
            var valid = this.validateCoordinates('lng'), dms = '';
            if (valid && this.showDMS) {
                var val = this.OEMapLongitudeDijit.get('value');
                dms = this.decToDMS(val, false);
            }
            this.OEMapLongitudeDMSDijit.innerHTML = dms;
            this.checkButtons();
        },

        decToDMS: function (l, lat) {
            var dir = '?',
                abs = Math.abs(l),
                deg = parseInt(abs, 10),
                min = (abs - deg) * 60,
                minInt = parseInt(min, 10),
                sec = number.round((min - minInt) * 60, this.unitScale),
                minIntTxt = (minInt < 10) ? '0' + minInt : minInt,
                secTxt = (sec < 10) ? '0' + sec : sec;

            if (lat) {
                dir = (l > 0) ? 'N' : 'S';
            } else {
                dir = (l > 0) ? 'E' : 'W';
            }

            return deg + '° ' + minIntTxt + '\' ' + secTxt + '" ' + dir;
        },

        convertCoordinates: function (mapPoint) {
            // convert the map point's coordinate system into lat/long
            var wkid = this.map.spatialReference.wkid;
            if (wkid === 102100) { // ESRI --> EPSG
                wkid = 3857;
            }
            var key = this.proj4Catalog + ':' + String(wkid);
            return proj4(proj4.defs[key]).inverse([mapPoint.x, mapPoint.y]);
        },

        setMapClickMode: function (mode) {
            this.mapClickMode = mode;
        }
    });
});<|endoftext|>


<commit_before>/*
Copyright 2006-2007, Open Source Applications Foundation

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

//Functionality that works for every browser
//Mozilla specific functionality abstracted to mozcontroller.js
//Safari specific functionality abstracted to safcontroller.js
//IE specific functionality abstracted to iecontroller.js
//The reason for this is that the start page only includes the one corresponding
//to the current browser, this means that the functionality in the controller
//object is only for the current browser, and there is only one copy of the code being
//loaded into the browser for performance.
windmill.xhr = new function() {

    //Keep track of the loop state, running or paused
    this.loopState = false;
    this.timeoutId = null;

    //If the are variables passed we need to do our lex and replace
    this.processVar = function(str){
      if ((str.indexOf('{$') != -1) && (windmill.runTests == true)) {
        str = handleVariable(str);
      }
      return str;
    }

    //action callback
    this.actionHandler = function(str) {
        //Process variables but not for the execJS or execIDEJS
        str = unescape(str);
        if ((str.indexOf('execJsInTestWindow') == -1) && (str.indexOf('execArbTestWinJS') == -1) && (str.indexOf('execIDEJS') == -1)){
          str = windmill.xhr.processVar(str);
        }

        //cleanup, apparently json parsers don't like \"
        //str = str.replace(/\\"/g, "\'")

        //Eval
        try {
          if (typeof(JSON) != "undefined"){
            windmill.xhr.xhrResponse = JSON.parse(str);
          }
          else {
            windmill.xhr.xhrResponse = fleegix.json.parse(str);
          }
        } catch (err){
            windmill.out("\""+err + "\". (Did you escape all double quotes?)")
            jQuery('#tabs').tabs("select", 1);
            windmill.err(err);
            windmill.xhr.getNext();
            return;
        }

        var resp = windmill.xhr.xhrResponse;
        var method = resp.result.method;
        var params = resp.result.params;

        //If there was a legit json response
        if (resp.error) {
            windmill.err("There was a JSON syntax error: '" +
            resp.error + "'");
        }
        else {
            if (method != 'defer') {
                windmill.serviceDelay = windmill.serviceDelayRunning;
                windmill.stat("Running " + method + "...");
                windmill.ui.playback.setPlaying();
            }
            else {
                windmill.serviceDelay = windmill.serviceDelayDefer;
                windmill.ui.playback.resetPlayBack();
                windmill.stat("Ready, Waiting for tests...");
            }

            //Init and start performance but not if the protocol defer
            if (method != 'defer') {

                //Put on windmill main page that we are running something
                windmill.xhr.action_timer = new TimeObj();
                windmill.xhr.action_timer.setName(method);

                //If the action already exists in the UI, skip all the creating suite stuff
                if ($(params.uuid) != null) {
                    var action = $(params.uuid);
                    action.style.background = 'lightyellow';
                }
                //If its a command we don't want to build any UI
                else if (method.split(".")[0] != 'commands') {
                  var action = windmill.xhr.createActionFromSuite(resp.result.suite_name, resp.result);
                }

                //default to true
                var result = true;
                var info = null;
                var output;

                //Forgotten case; If the windmill.runTests is false, but we are trying to change it back to true with a command
                //This fix runs all commands regardless
                //Run the action
                //If it's a user extension.. run it
                if ((windmill.runTests == true) || (method.split(".")[0] == 'commands')) {

                    //split the action up
                    var mArray = method.split(".");

                    //try running the actions
                    try {
                      //Start the action running timer
                        windmill.xhr.action_timer.startTime();
                        //Wait/open needs to not grab the next action immediately
                        if ((method.split(".")[0] == 'waits')) {
                            windmill.pauseLoop();
                            params.aid = action.id;
                        }
                        if (method.indexOf('.') != -1) {
                            //if asserts.assertNotSomething we need to set the result to !result
                            if (method.indexOf('asserts.assertNot') != -1) {
                                var m = mArray[1].replace('Not', '');
                                  try {
                                    //windmill.controller[mArray[0]][m](params);
                                    output = windmill.controller[mArray[0]][m](params);
                                  } catch(err){
                                    var assertNotErr = true;
                                  }
                                  //If the not call didn't error, it's an error
                                  if (!assertNotErr){
                                    throw "returned true.";
                                  }
                            }
                            //Normal asserts and waits
                            else {
                                //windmill.controller[mArray[0]][mArray[1]](params, resp.result);
                                output = windmill.controller[mArray[0]][mArray[1]](params, resp.result);
                            }
                        }
                        //Every other action that isn't namespaced
                        else { output = windmill.controller[method](params); }

                        //End the timer
                        windmill.xhr.action_timer.endTime();
                        //Report all bug commands on success
                        if (method.split(".")[0] != 'commands'){
                          params.aid = action.id;
                          windmill.actOut(method, params, result);
                        }
                    }
                    catch(error) {
                        //End the timer if something broke
                        windmill.xhr.action_timer.endTime();
                        info = error;
                        result = false;

                        //Sometimes this is a huge dom exception which can't be serialized
                        //so what we want to use is the message property
                        if (error.message){
                          params.error = error.message;
                        }
                        else { params.error = error; }

                        windmill.actOut(method, params, result);
                        // var newParams = copyObj(params);
                        // delete newParams.uuid;
                        //
                        // windmill.out("" +
                        // method + ": " + error + "");
                        //
                        // windmill.out("
Action: " + method +
                        // "
Parameters: " + fleegix.json.serialize(newParams) +
                        // "
Test Result: " + result + '');

                        //If the option to throw errors is set
                        if ($('throwDebug').checked == true) {
                            if (console.log) { console.log(error); }
                            else { throw (error); }
                        }
                        else {
                            if (!$('toggleBreak').checked) {
                                windmill.continueLoop();
                            }
                        }
                    }
                }
                else {
                  //we must be loading, change the status to reflect that
                  windmill.stat("Loading " + method + "...");
                }
                var m = method.split(".");
                //Send the report if it's not in the commands namespace, we only call report for test actions
                if ((m[0] != 'commands') && (m[0] != 'waits') && (windmill.runTests == true)) {
                    var newParams = copyObj(params);
                    delete newParams.uuid;
                    //End timer and store
                    //windmill.xhr.action_timer.endTime();
                    //windmill.xhr.sendReport(method, result, windmill.xhr.action_timer, info);
                    windmill.xhr.sendReport(method, result, windmill.xhr.action_timer, info, output);
                    windmill.xhr.setActionBackground(action, result, resp.result);
                    //Do the timer write
                    windmill.xhr.action_timer.write(newParams);
                }
            }
        }
        //Get the next action from the service
        setTimeout("windmill.xhr.getNext()", windmill.serviceDelay);

    };

    //Send the report
    this.sendReport = function(method, result, timer, info, output) {
        //if no info was specified
        if (typeof(info) == "undefined"){
          var info = "";
        }
        //handle the response
        var reportHandler = function(str) {
            response = eval('(' + str + ')');
            if (!response.result == 200) {
                windmill.err('Error: Report receiving non 200 response.');
            }
        };

        //send the report
        var result_string = fleegix.json.serialize(windmill.xhr.xhrResponse.result);
        var test_obj = {
            "result": result,
            "output": escape(output),
            "debug": escape(info),
            "uuid": windmill.xhr.xhrResponse.result.params.uuid,
            "starttime": timer.getStart(),
            "endtime": timer.getEnd()
        };
        var json_object = new json_call('1.1', 'report');
        json_object.params = test_obj;
        var json_string = fleegix.json.serialize(json_object);
        //Actually send the report
        fleegix.xhr.doPost(reportHandler, '/windmill-jsonrpc/', json_string);
    };

    //Get the next action from the server
    this.getNext = function() {

        //write to the output tab what is going on
        var handleTimeout = function() {
            windmill.err('One of the XHR requests to the server timed out.');
        }
        //var handleErr = function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); }

        if (windmill.xhr.loopState) {
            var jsonObject = new json_call('1.1', 'next_action');
            var jsonString = fleegix.json.serialize(jsonObject);

            //Execute the post to get the next action
            //Set the xhr timeout to be really high
            //handle the timeout manually
            //Prevent caching
            fleegix.xhr.doReq({
                method: 'POST',
                handleSuccess: this.actionHandler,
                handleErr: function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); },
                responseFormat: 'text',
                url: '/windmill-jsonrpc/',
                timeoutSeconds: windmill.xhrTimeout,
                handleTimeout: handleTimeout,
                preventCache: true,
                dataPayload: jsonString
            });

        }

    };

    this.clearQueue = function() {
        var h = function(str) {
            windmill.out('Cleared backend queue, ' + str);
        }
        var test_obj = {};
        var json_object = new json_call('1.1', 'clear_queue');
        var json_string = fleegix.json.serialize(json_object);
        //Actually send the report
        fleegix.xhr.doPost(h, '/windmill-jsonrpc/', json_string);

    };

    this.createActionFromSuite = function(suiteName, actionObj) {
        //If the suite name is null, set it to default
        if (suiteName == null) {
            suiteName = 'Default';
        }
        windmill.ui.currentSuite = suiteName;
        var suite = windmill.ui.remote.getSuite(suiteName);

        //Add the action to the suite
        var action = windmill.ui.remote.buildAction(actionObj.method, actionObj.params);
        //var suite = $(result);
        suite.appendChild(action);
        //IE Hack
        if (windmill.browser.isIE) {
            $(action.id).innerHTML = action.innerHTML;
        }
        var ide = $('ideForm');

        //If the settings box is checked, scroll to the bottom
        if ($('autoScroll').checked == true) {
            ide.scrollTop = ide.scrollHeight;
        }
        return action;
    };

    this.setActionBackground = function(action, result, obj) {

        if (result != true) {
            if (typeof(action) != 'undefined') {
                action.style.background = '#FF9692';
                action.parentNode.style.border.borderTop = "1px solid red";
                action.parentNode.style.border.borderBottom = "1px solid red";
            }
            // windmill.out("
Action: " + obj.method +
            //      "
Parameters: " + fleegix.json.serialize(obj.params) +
            //      "
Test Result: " + result + '');
            //
            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
        else {
            //Write to the result tab
            // windmill.out("
Action: " + obj.method +
            // "
Parameters: " + fleegix.json.serialize(obj.params) +
            // "
Test Result: " + result + '');

            if ((typeof(action) != 'undefined') && (windmill.runTests == true)) {
                action.style.background = '#C7FFCC';
                if (action.parentNode.style.borderTop.indexOf("red") != -1){
                  action.parentNode.style.borderTop = "1px solid green";
                  action.parentNode.style.borderBottom = "1px solid green";
                }
            }
        }
    };
    this.setWaitBgAndReport = function(aid, result, obj) {
        if (!obj) { return false; }

        var action = $(aid);
        var output = $(aid+"result");
        windmill.xhr.action_timer.endTime();

        if (result != true) {
            if (action != null) { action.style.background = '#FF9692'; }
            if (output != null) { output.style.background = '#FF9692'; }

            // windmill.out("
Action: " + obj.method +
            // "
Parameters: " + fleegix.json.serialize(obj.params) +
            // "
Test Result: " + result + '');

            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
        else {
            //Write to the result tab
            // windmill.out("
Action: " + obj.method +
            // "
Parameters: " + fleegix.json.serialize(obj.params) +
            // "
Test Result: " + result + '');

            try {
                if ((typeof(action) != 'undefined') && (windmill.runTests == true)) {
                    action.style.background = '#C7FFCC';
                }
                if ((typeof(output) != 'undefined') && (windmill.runTests == true)) {
                    output.style.background = '#C7FFCC';
                }
            }
            catch(err) {}
        }
        //Send the report
        windmill.xhr.xhrResponse.result = obj;
        //Don't report if we are running js tests
        if (obj.params.orig != 'js'){
          //windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer);
          windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer, undefined);
        }
        windmill.xhr.action_timer.write(obj.params);
    };

};
<commit_msg>Report output doesn't need to be URL encoded, hard to read<commit_after>/*
Copyright 2006-2007, Open Source Applications Foundation

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

//Functionality that works for every browser
//Mozilla specific functionality abstracted to mozcontroller.js
//Safari specific functionality abstracted to safcontroller.js
//IE specific functionality abstracted to iecontroller.js
//The reason for this is that the start page only includes the one corresponding
//to the current browser, this means that the functionality in the controller
//object is only for the current browser, and there is only one copy of the code being
//loaded into the browser for performance.
windmill.xhr = new function() {

    //Keep track of the loop state, running or paused
    this.loopState = false;
    this.timeoutId = null;

    //If the are variables passed we need to do our lex and replace
    this.processVar = function(str){
      if ((str.indexOf('{$') != -1) && (windmill.runTests == true)) {
        str = handleVariable(str);
      }
      return str;
    }

    //action callback
    this.actionHandler = function(str) {
        //Process variables but not for the execJS or execIDEJS
        str = unescape(str);
        if ((str.indexOf('execJsInTestWindow') == -1) && (str.indexOf('execArbTestWinJS') == -1) && (str.indexOf('execIDEJS') == -1)){
          str = windmill.xhr.processVar(str);
        }

        //cleanup, apparently json parsers don't like \"
        //str = str.replace(/\\"/g, "\'")

        //Eval
        try {
          if (typeof(JSON) != "undefined"){
            windmill.xhr.xhrResponse = JSON.parse(str);
          }
          else {
            windmill.xhr.xhrResponse = fleegix.json.parse(str);
          }
        } catch (err){
            windmill.out("\""+err + "\". (Did you escape all double quotes?)")
            jQuery('#tabs').tabs("select", 1);
            windmill.err(err);
            windmill.xhr.getNext();
            return;
        }

        var resp = windmill.xhr.xhrResponse;
        var method = resp.result.method;
        var params = resp.result.params;

        //If there was a legit json response
        if (resp.error) {
            windmill.err("There was a JSON syntax error: '" +
            resp.error + "'");
        }
        else {
            if (method != 'defer') {
                windmill.serviceDelay = windmill.serviceDelayRunning;
                windmill.stat("Running " + method + "...");
                windmill.ui.playback.setPlaying();
            }
            else {
                windmill.serviceDelay = windmill.serviceDelayDefer;
                windmill.ui.playback.resetPlayBack();
                windmill.stat("Ready, Waiting for tests...");
            }

            //Init and start performance but not if the protocol defer
            if (method != 'defer') {

                //Put on windmill main page that we are running something
                windmill.xhr.action_timer = new TimeObj();
                windmill.xhr.action_timer.setName(method);

                //If the action already exists in the UI, skip all the creating suite stuff
                if ($(params.uuid) != null) {
                    var action = $(params.uuid);
                    action.style.background = 'lightyellow';
                }
                //If its a command we don't want to build any UI
                else if (method.split(".")[0] != 'commands') {
                  var action = windmill.xhr.createActionFromSuite(resp.result.suite_name, resp.result);
                }

                //default to true
                var result = true;
                var info = null;
                var output;

                //Forgotten case; If the windmill.runTests is false, but we are trying to change it back to true with a command
                //This fix runs all commands regardless
                //Run the action
                //If it's a user extension.. run it
                if ((windmill.runTests == true) || (method.split(".")[0] == 'commands')) {

                    //split the action up
                    var mArray = method.split(".");

                    //try running the actions
                    try {
                      //Start the action running timer
                        windmill.xhr.action_timer.startTime();
                        //Wait/open needs to not grab the next action immediately
                        if ((method.split(".")[0] == 'waits')) {
                            windmill.pauseLoop();
                            params.aid = action.id;
                        }
                        if (method.indexOf('.') != -1) {
                            //if asserts.assertNotSomething we need to set the result to !result
                            if (method.indexOf('asserts.assertNot') != -1) {
                                var m = mArray[1].replace('Not', '');
                                  try {
                                    //windmill.controller[mArray[0]][m](params);
                                    output = windmill.controller[mArray[0]][m](params);
                                  } catch(err){
                                    var assertNotErr = true;
                                  }
                                  //If the not call didn't error, it's an error
                                  if (!assertNotErr){
                                    throw "returned true.";
                                  }
                            }
                            //Normal asserts and waits
                            else {
                                //windmill.controller[mArray[0]][mArray[1]](params, resp.result);
                                output = windmill.controller[mArray[0]][mArray[1]](params, resp.result);
                            }
                        }
                        //Every other action that isn't namespaced
                        else { output = windmill.controller[method](params); }

                        //End the timer
                        windmill.xhr.action_timer.endTime();
                        //Report all bug commands on success
                        if (method.split(".")[0] != 'commands'){
                          params.aid = action.id;
                          windmill.actOut(method, params, result);
                        }
                    }
                    catch(error) {
                        //End the timer if something broke
                        windmill.xhr.action_timer.endTime();
                        info = error;
                        result = false;

                        //Sometimes this is a huge dom exception which can't be serialized
                        //so what we want to use is the message property
                        if (error.message){
                          params.error = error.message;
                        }
                        else { params.error = error; }

                        windmill.actOut(method, params, result);
                        // var newParams = copyObj(params);
                        // delete newParams.uuid;
                        //
                        // windmill.out("" +
                        // method + ": " + error + "");
                        //
                        // windmill.out("
Action: " + method +
                        // "
Parameters: " + fleegix.json.serialize(newParams) +
                        // "
Test Result: " + result + '');

                        //If the option to throw errors is set
                        if ($('throwDebug').checked == true) {
                            if (console.log) { console.log(error); }
                            else { throw (error); }
                        }
                        else {
                            if (!$('toggleBreak').checked) {
                                windmill.continueLoop();
                            }
                        }
                    }
                }
                else {
                  //we must be loading, change the status to reflect that
                  windmill.stat("Loading " + method + "...");
                }
                var m = method.split(".");
                //Send the report if it's not in the commands namespace, we only call report for test actions
                if ((m[0] != 'commands') && (m[0] != 'waits') && (windmill.runTests == true)) {
                    var newParams = copyObj(params);
                    delete newParams.uuid;
                    //End timer and store
                    //windmill.xhr.action_timer.endTime();
                    //windmill.xhr.sendReport(method, result, windmill.xhr.action_timer, info);
                    windmill.xhr.sendReport(method, result, windmill.xhr.action_timer, info, output);
                    windmill.xhr.setActionBackground(action, result, resp.result);
                    //Do the timer write
                    windmill.xhr.action_timer.write(newParams);
                }
            }
        }
        //Get the next action from the service
        setTimeout("windmill.xhr.getNext()", windmill.serviceDelay);

    };

    //Send the report
    this.sendReport = function(method, result, timer, info, output) {
        //if no info was specified
        if (typeof(info) == "undefined"){
          var info = "";
        }
        //handle the response
        var reportHandler = function(str) {
            response = eval('(' + str + ')');
            if (!response.result == 200) {
                windmill.err('Error: Report receiving non 200 response.');
            }
        };

        //send the report
        var result_string = fleegix.json.serialize(windmill.xhr.xhrResponse.result);
        var test_obj = {
            "result": result,
            "output": typeof(output) !== "undefined" ? output : null,
            "debug": typeof(info) !== "undefined" ? info : null,
            "uuid": windmill.xhr.xhrResponse.result.params.uuid,
            "starttime": timer.getStart(),
            "endtime": timer.getEnd()
        };
        var json_object = new json_call('1.1', 'report');
        json_object.params = test_obj;
        var json_string = fleegix.json.serialize(json_object);
        //Actually send the report
        fleegix.xhr.doPost(reportHandler, '/windmill-jsonrpc/', json_string);
    };

    //Get the next action from the server
    this.getNext = function() {

        //write to the output tab what is going on
        var handleTimeout = function() {
            windmill.err('One of the XHR requests to the server timed out.');
        }
        //var handleErr = function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); }

        if (windmill.xhr.loopState) {
            var jsonObject = new json_call('1.1', 'next_action');
            var jsonString = fleegix.json.serialize(jsonObject);

            //Execute the post to get the next action
            //Set the xhr timeout to be really high
            //handle the timeout manually
            //Prevent caching
            fleegix.xhr.doReq({
                method: 'POST',
                handleSuccess: this.actionHandler,
                handleErr: function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); },
                responseFormat: 'text',
                url: '/windmill-jsonrpc/',
                timeoutSeconds: windmill.xhrTimeout,
                handleTimeout: handleTimeout,
                preventCache: true,
                dataPayload: jsonString
            });

        }

    };

    this.clearQueue = function() {
        var h = function(str) {
            windmill.out('Cleared backend queue, ' + str);
        }
        var test_obj = {};
        var json_object = new json_call('1.1', 'clear_queue');
        var json_string = fleegix.json.serialize(json_object);
        //Actually send the report
        fleegix.xhr.doPost(h, '/windmill-jsonrpc/', json_string);

    };

    this.createActionFromSuite = function(suiteName, actionObj) {
        //If the suite name is null, set it to default
        if (suiteName == null) {
            suiteName = 'Default';
        }
        windmill.ui.currentSuite = suiteName;
        var suite = windmill.ui.remote.getSuite(suiteName);

        //Add the action to the suite
        var action = windmill.ui.remote.buildAction(actionObj.method, actionObj.params);
        //var suite = $(result);
        suite.appendChild(action);
        //IE Hack
        if (windmill.browser.isIE) {
            $(action.id).innerHTML = action.innerHTML;
        }
        var ide = $('ideForm');

        //If the settings box is checked, scroll to the bottom
        if ($('autoScroll').checked == true) {
            ide.scrollTop = ide.scrollHeight;
        }
        return action;
    };

    this.setActionBackground = function(action, result, obj) {

        if (result != true) {
            if (typeof(action) != 'undefined') {
                action.style.background = '#FF9692';
                action.parentNode.style.border.borderTop = "1px solid red";
                action.parentNode.style.border.borderBottom = "1px solid red";
            }
            // windmill.out("
Action: " + obj.method +
            //      "
Parameters: " + fleegix.json.serialize(obj.params) +
            //      "
Test Result: " + result + '');
            //
            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
        else {
            //Write to the result tab
            // windmill.out("
Action: " + obj.method +
            // "
Parameters: " + fleegix.json.serialize(obj.params) +
            // "
Test Result: " + result + '');

            if ((typeof(action) != 'undefined') && (windmill.runTests == true)) {
                action.style.background = '#C7FFCC';
                if (action.parentNode.style.borderTop.indexOf("red") != -1){
                  action.parentNode.style.borderTop = "1px solid green";
                  action.parentNode.style.borderBottom = "1px solid green";
                }
            }
        }
    };
    this.setWaitBgAndReport = function(aid, result, obj) {
        if (!obj) { return false; }

        var action = $(aid);
        var output = $(aid+"result");
        windmill.xhr.action_timer.endTime();

        if (result != true) {
            if (action != null) { action.style.background = '#FF9692'; }
            if (output != null) { output.style.background = '#FF9692'; }

            // windmill.out("
Action: " + obj.method +
            // "
Parameters: " + fleegix.json.serialize(obj.params) +
            // "
Test Result: " + result + '');

            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
        else {
            //Write to the result tab
            // windmill.out("
Action: " + obj.method +
            // "
Parameters: " + fleegix.json.serialize(obj.params) +
            // "
Test Result: " + result + '');

            try {
                if ((typeof(action) != 'undefined') && (windmill.runTests == true)) {
                    action.style.background = '#C7FFCC';
                }
                if ((typeof(output) != 'undefined') && (windmill.runTests == true)) {
                    output.style.background = '#C7FFCC';
                }
            }
            catch(err) {}
        }
        //Send the report
        windmill.xhr.xhrResponse.result = obj;
        //Don't report if we are running js tests
        if (obj.params.orig != 'js'){
          //windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer);
          windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer, undefined);
        }
        windmill.xhr.action_timer.write(obj.params);
    };

};
<|endoftext|>


<commit_before>/*
Copyright 2006-2007, Open Source Applications Foundation

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

//Functionality that works for every browser
//Mozilla specific functionality abstracted to mozcontroller.js
//Safari specific functionality abstracted to safcontroller.js
//IE specific functionality abstracted to iecontroller.js
//The reason for this is that the start page only includes the one corresponding
//to the current browser, this means that the functionality in the controller
//object is only for the current browser, and there is only one copy of the code being
//loaded into the browser for performance.
windmill.xhr = new function() {

    //Keep track of the loop state, running or paused
    this.loopState = false;
    this.actionQueued = false;

    //If the are variables passed we need to do our lex and replace
    this.processVar = function(str){
      //only process if it's no an exec method
      if ((str.indexOf('"method": "exec') == -1)
        && (str.indexOf('{$') != -1)
        && (windmill.runTests)) {
        str = handleVariable(str);
      }
      return str;
    }

    this.goWait = function(){
      windmill.xhr.actionQueued = true;
      windmill.controller.waits.forElement(windmill.xhr.action.params, windmill.xhr.action);
    };

    this.runAction = function(){
      var _this = windmill.xhr;

      //setup state
      //windmill.serviceDelay = windmill.serviceDelayRunning;
      windmill.stat("Running " + _this.action.method + "...");
      windmill.ui.playback.setPlaying();
      //Put on windmill main page that we are running something
      _this.action_timer = new TimeObj();
      _this.action_timer.setName(_this.action.method);

      //If the action already exists in the UI, skip all the creating suite stuff
      if ($(_this.action.params.uuid) != null) {
          var action = $(_this.action.params.uuid);
          action.style.background = 'lightyellow';
      }
      //If it's a command we don't want to build any UI
      else if (_this.methodArr[0] != 'commands') {
        var action = _this.createActionFromSuite(_this.action.suite_name, _this.action);
      }

      //default to true
      var result = true;
      var info = null;
      var output;

      //Forgotten case; If the windmill.runTests is false, but we are trying to change it back to true with a command
      //This fix runs all commands regardless
      //Run the action
      //If it's a user extension.. run it
      if ((windmill.runTests) ||
        (_this.methodArr[0] == 'commands')) {

          //try running the actions
          try {
            //Start the action running timer
              windmill.xhr.action_timer.startTime();

              //Get access to the function according to the method array
              //not's don't actually exist
              try {
                var func = stringToFunc(arrayToJSPath(_this.methodArr));
              } catch(err){ windmill.err(err); }

              //waits and nodes that have a lookup that isn't returning
              //if there is no node, this will be false
              //if there is a node, but it doesn't return it will throw
              //else we have a node
              try {
                _this.node = lookupNode(_this.action.params);
              } catch(err){
                _this.node = null;
              }

              //auto wait for only UI actions
              //where the lookup fails.
              if ((_this.node == null) &&
                  (_this.methodArr[0] != 'waits') &&
                  (_this.methodArr[0] != 'asserts')){

                windmill.pauseLoop();
                _this.action.params.aid = action.id;
                _this.goWait();
                return;
              }

              //Wait/open needs to not grab the next action immediately
              if (_this.action.method.indexOf('waits') != -1) {
                  windmill.pauseLoop();
                  _this.action.params.aid = action.id;
              }

              //asserts., waits.
              if (_this.methodArr.length > 1){

                  //if asserts.assertNotSomething we need to set the result to !result
                  if (_this.action.method.indexOf('asserts.assertNot') != -1) {
                      _this.methodArr[1] = _this.methodArr[1].replace('Not', '');
					            var assertNotErr = false;

                      try {
                        var func = stringToFunc(arrayToJSPath(_this.methodArr));
                        output = func(_this.action.params);
                      } catch(err){
                        assertNotErr = true;
                      }
                      //If the not call didn't error, it's an error
                      if (!assertNotErr){
                        throw "AssertNot returned true, thus a fail.";
                      }
                  }
                  //Normal asserts and waits
                  else {
                    output = func(_this.action.params, _this.action);
                  }
              }
              //Every other action that isn't namespaced
              else {
                output = func(_this.action.params);
              }

              //End the timer
              _this.action_timer.endTime();
              //Report all bug commands on success
              if (_this.methodArr[0] != 'commands'){
                _this.action.params.aid = action.id;
                //serialize and send output to the UI
                //if it isn't undefined
                var serOutput = JSON.stringify(output);
                if (serOutput != undefined){
                  _this.action.params.output = serOutput;
                }
                windmill.actOut(_this.action.method, _this.action.params, result);
              }
          }
          catch(error) {
              //End the timer if something broke
              _this.action_timer.endTime();
              info = error;
              result = false;

              //Sometimes this is a huge dom exception which can't be serialized
              //so what we want to use is the message property
              if (error.message){
                _this.action.params.error = error.message;
								if (error.lineNumber){
									error.message += "" + error.lineNumber;
								}
              } else {
                _this.action.params.error = error;
              }

              windmill.actOut(_this.action.method, _this.action.params, result);

              //If the option to throw errors is set
              if ($('throwDebug').checked == true) {
                  if (console.log) { console.log(error); }
                  else { throw (error); }
              } else {
                  if (!$('toggleBreak').checked) {
                    windmill.continueLoop();
                  }
              }
          }
      }
      else {
        //we must be loading, change the status to reflect that
        windmill.stat("Loading " + _this.action.method + "...");
      }

      //Send the report if it's not in the commands namespace, we only call report for test actions
      if ((_this.methodArr[0] != 'commands')
        && (_this.action.method.indexOf('waits') == -1)
        && (windmill.runTests == true)) {

          var newParams = copyObj(_this.action.params);
          delete newParams.uuid;

          _this.sendReport(_this.action.method, result, _this.action_timer, info, output);
          _this.setActionBackground(action, result, _this.action);
          //Do the timer write
          _this.action_timer.write(newParams);
      }
    };

    //action callback
    this.actionHandler = function(str) {
        var _this = windmill.xhr;

        //Eval
        try {
          _this.dataObj = JSON.parse(_this.processVar(str));
        } catch (err){ return; }

        _this.action = _this.dataObj.result;
        _this.methodArr = _this.action.method.split(".");

        //If there was a legit json response
        if (_this.dataObj.error) {
            windmill.err("There was a JSON syntax error: '" +
              _this.dataObj.error + "'");
        }
        else {
            //Init and start performance but not if the protocol defer
            if (_this.action.method != 'defer') {
              _this.runAction();
            } else {
              //windmill.serviceDelay = windmill.serviceDelayDefer;
              windmill.ui.playback.resetPlayBack();
              windmill.stat("Ready, Waiting for tests...");
            }
        }
        //Get the next action from the service
        setTimeout("windmill.xhr.getNext()", windmill.serviceDelay);
    };

    //Send the report
    this.sendReport = function(method, result, timer, info, output) {

        //handle the response
        var reportHandler = function(str) {
            response = eval('(' + str + ')');
            if (!response.result == 200) {
                windmill.err('Error: Report receiving non 200 response.');
            }
        };

        //send the report
        var result_string = JSON.stringify(windmill.xhr.action);
        var test_obj = {
            "result": result,
            "output": typeof(output) !== "undefined" ? output : null,
            "debug": typeof(info) !== "undefined" ? info : null,
            "uuid": windmill.xhr.action.params.uuid,
            "starttime": timer.getStart(),
            "endtime": timer.getEnd()
        };
        var jsonObject = new jsonCall('1.1', 'report');
        jsonObject.params = test_obj;
        var jsonString = JSON.stringify(jsonObject);
        //Actually send the report
        fleegix.xhr.doPost(reportHandler, '/windmill-jsonrpc/', jsonString);
    };

    //Get the next action from the server
    this.getNext = function() {

        //write to the output tab what is going on
        var handleTimeout = function() {
            windmill.err('One of the XHR requests to the server timed out.');
            setTimeout("windmill.xhr.getNext()", windmill.serviceDelay);
        }
        //var handleErr = function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); }

        if (windmill.xhr.loopState) {
            var jsonObject = new jsonCall('1.1', 'next_action');
            var jsonString = JSON.stringify(jsonObject);

            //Execute the post to get the next action
            //Set the xhr timeout to be really high
            //handle the timeout manually
            //Prevent caching
            fleegix.xhr.doReq({
                method: 'POST',
                handleSuccess: this.actionHandler,
                handleErr: function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); },
                responseFormat: 'text',
                url: '/windmill-jsonrpc/',
                timeoutSeconds: windmill.xhrTimeout,
                handleTimeout: handleTimeout,
                preventCache: true,
                dataPayload: jsonString
            });
        }
    };

    this.clearQueue = function() {
        var h = function(str) {
            windmill.out('Cleared backend queue, ' + str);
        }
        var test_obj = {};
        var jsonObject = new jsonCall('1.1', 'clear_queue');
        var jsonString = JSON.stringify(jsonObject);
        //Actually send the report
        fleegix.xhr.doPost(h, '/windmill-jsonrpc/', jsonString);

    };

    this.createActionFromSuite = function(suiteName, actionObj) {
        //If the suite name is null, set it to default
        if (suiteName == null) {
            suiteName = 'Default';
        }
        windmill.ui.currentSuite = suiteName;
        var suite = windmill.ui.remote.getSuite(suiteName);

        //Add the action to the suite
        var action = windmill.ui.remote.buildAction(actionObj.method, actionObj.params);
        //var suite = $(result);
        suite.appendChild(action);
        //IE Hack
        if (windmill.browser.isIE) {
            $(action.id).innerHTML = action.innerHTML;
        }
        var ide = $('ideForm');

        //If the settings box is checked, scroll to the bottom
        if ($('autoScroll').checked == true) {
            ide.scrollTop = ide.scrollHeight;
        }
        return action;
    };

    this.setActionBackground = function(action, result, obj) {

        if (result != true) {
            if (typeof(action) != 'undefined') {
                action.style.background = '#FF9692';
                action.parentNode.style.border.borderTop = "1px solid red";
                action.parentNode.style.border.borderBottom = "1px solid red";
            }
            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
        else {
            //Write to the result tab
            if ((typeof(action) != 'undefined') && (windmill.runTests == true)) {
                action.style.background = '#C7FFCC';
                if (action.parentNode.style.borderTop.indexOf("red") != -1){
                  action.parentNode.style.borderTop = "1px solid green";
                  action.parentNode.style.borderBottom = "1px solid green";
                }
            }
        }
    };
    this.setWaitBgAndReport = function(aid, result, obj) {

        //Access the action UI and output UI
		var action = $(aid);
        var output = $(aid+"result");

		//If we are in an auto-wait state
		if (windmill.xhr.actionQueued){
			//No longer in a waiting state after this if
			windmill.xhr.actionQueued = false;
			//Update the results
			windmill.actOut(windmill.xhr.action.method, windmill.xhr.action.params, result);
			//We want to add a new output line instead of accessing the old one
			output = null;
        }

        //If no object was provided then we just restart the loop and bail
		if (!obj) {
          windmill.continueLoop();
          return false;
        }

		//End any timing that is happening
        windmill.xhr.action_timer.endTime();

        //Failed action case
		if (!result) {
            if (action != null) { action.style.background = '#FF9692'; }
            if (output != null) { //output.style.background = '#FF9692';
              output.removeAttribute('class');
              output.removeAttribute('style');
              output.className = "ui-state-error ui-corner-all outputEntry";
              output.style.height = "13px";
            }

            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
				//Passing action case
        else {
            //Write to the result tab
            try {
                if ((typeof(action) != 'undefined') && (windmill.runTests)) {
                    action.style.background = '#C7FFCC';
                }
                if ((typeof(output) != 'undefined') && (windmill.runTests)) {
                    output.style.background = '#C7FFCC';
                }
            }
            catch(err) {}
        }
        //Send the report
        windmill.xhr.action = obj;
        //Don't report if we are running js tests
        if (obj.params.orig != 'js'){
          //windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer);
          windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer, undefined);
        }
        windmill.xhr.action_timer.write(obj.params);
        windmill.continueLoop();
    };
};
<commit_msg>Applied onblur fix<commit_after>/*
Copyright 2006-2007, Open Source Applications Foundation

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

//Functionality that works for every browser
//Mozilla specific functionality abstracted to mozcontroller.js
//Safari specific functionality abstracted to safcontroller.js
//IE specific functionality abstracted to iecontroller.js
//The reason for this is that the start page only includes the one corresponding
//to the current browser, this means that the functionality in the controller
//object is only for the current browser, and there is only one copy of the code being
//loaded into the browser for performance.
windmill.xhr = new function() {

    //Keep track of the loop state, running or paused
    this.loopState = false;
    this.actionQueued = false;

    //If the are variables passed we need to do our lex and replace
    this.processVar = function(str){
      //only process if it's no an exec method
      if ((str.indexOf('"method": "exec') == -1)
        && (str.indexOf('{$') != -1)
        && (windmill.runTests)) {
        str = handleVariable(str);
      }
      return str;
    }

    this.goWait = function(){
      windmill.xhr.actionQueued = true;
      windmill.controller.waits.forElement(windmill.xhr.action.params, windmill.xhr.action);
    };

    this.runAction = function(){
      var _this = windmill.xhr;

      //setup state
      //windmill.serviceDelay = windmill.serviceDelayRunning;
      windmill.stat("Running " + _this.action.method + "...");
      windmill.ui.playback.setPlaying();
      //Put on windmill main page that we are running something
      _this.action_timer = new TimeObj();
      _this.action_timer.setName(_this.action.method);

      //If the action already exists in the UI, skip all the creating suite stuff
      if ($(_this.action.params.uuid) != null) {
          var action = $(_this.action.params.uuid);
          action.style.background = 'lightyellow';
      }
      //If it's a command we don't want to build any UI
      else if (_this.methodArr[0] != 'commands') {
        var action = _this.createActionFromSuite(_this.action.suite_name, _this.action);
      }

      //default to true
      var result = true;
      var info = null;
      var output;

      //Forgotten case; If the windmill.runTests is false, but we are trying to change it back to true with a command
      //This fix runs all commands regardless
      //Run the action
      //If it's a user extension.. run it
      if ((windmill.runTests) ||
        (_this.methodArr[0] == 'commands')) {

          //try running the actions
          try {
            //Start the action running timer
              windmill.xhr.action_timer.startTime();

              //Get access to the function according to the method array
              //not's don't actually exist
              try {
                var func = stringToFunc(arrayToJSPath(_this.methodArr));
              } catch(err){ windmill.err(err); }

              //waits and nodes that have a lookup that isn't returning
              //if there is no node, this will be false
              //if there is a node, but it doesn't return it will throw
              //else we have a node
              if (_this.node) { var tempNode = _this.node; }
              try {
                _this.node = lookupNode(_this.action.params);
                } catch(err){
                _this.node = null;
              }
              if (tempNode) {
                if (tempNode != _this.node) {
                    windmill.events.triggerEvent(tempNode, 'blur', false);
                }
              }

              //auto wait for only UI actions
              //where the lookup fails.
              if ((_this.node == null) &&
                  (_this.methodArr[0] != 'waits') &&
                  (_this.methodArr[0] != 'asserts')){

                windmill.pauseLoop();
                _this.action.params.aid = action.id;
                _this.goWait();
                return;
              }

              //Wait/open needs to not grab the next action immediately
              if (_this.action.method.indexOf('waits') != -1) {
                  windmill.pauseLoop();
                  _this.action.params.aid = action.id;
              }

              //asserts., waits.
              if (_this.methodArr.length > 1){

                  //if asserts.assertNotSomething we need to set the result to !result
                  if (_this.action.method.indexOf('asserts.assertNot') != -1) {
                      _this.methodArr[1] = _this.methodArr[1].replace('Not', '');
					            var assertNotErr = false;

                      try {
                        var func = stringToFunc(arrayToJSPath(_this.methodArr));
                        output = func(_this.action.params);
                      } catch(err){
                        assertNotErr = true;
                      }
                      //If the not call didn't error, it's an error
                      if (!assertNotErr){
                        throw "AssertNot returned true, thus a fail.";
                      }
                  }
                  //Normal asserts and waits
                  else {
                    output = func(_this.action.params, _this.action);
                  }
              }
              //Every other action that isn't namespaced
              else {
                output = func(_this.action.params);
              }

              //End the timer
              _this.action_timer.endTime();
              //Report all bug commands on success
              if (_this.methodArr[0] != 'commands'){
                _this.action.params.aid = action.id;
                //serialize and send output to the UI
                //if it isn't undefined
                var serOutput = JSON.stringify(output);
                if (serOutput != undefined){
                  _this.action.params.output = serOutput;
                }
                windmill.actOut(_this.action.method, _this.action.params, result);
              }
          }
          catch(error) {
              //End the timer if something broke
              _this.action_timer.endTime();
              info = error;
              result = false;

              //Sometimes this is a huge dom exception which can't be serialized
              //so what we want to use is the message property
              if (error.message){
                _this.action.params.error = error.message;
								if (error.lineNumber){
									error.message += "" + error.lineNumber;
								}
              } else {
                _this.action.params.error = error;
              }

              windmill.actOut(_this.action.method, _this.action.params, result);

              //If the option to throw errors is set
              if ($('throwDebug').checked == true) {
                  if (console.log) { console.log(error); }
                  else { throw (error); }
              } else {
                  if (!$('toggleBreak').checked) {
                    windmill.continueLoop();
                  }
              }
          }
      }
      else {
        //we must be loading, change the status to reflect that
        windmill.stat("Loading " + _this.action.method + "...");
      }

      //Send the report if it's not in the commands namespace, we only call report for test actions
      if ((_this.methodArr[0] != 'commands')
        && (_this.action.method.indexOf('waits') == -1)
        && (windmill.runTests == true)) {

          var newParams = copyObj(_this.action.params);
          delete newParams.uuid;

          _this.sendReport(_this.action.method, result, _this.action_timer, info, output);
          _this.setActionBackground(action, result, _this.action);
          //Do the timer write
          _this.action_timer.write(newParams);
      }
    };

    //action callback
    this.actionHandler = function(str) {
        var _this = windmill.xhr;

        //Eval
        try {
          _this.dataObj = JSON.parse(_this.processVar(str));
        } catch (err){ return; }

        _this.action = _this.dataObj.result;
        _this.methodArr = _this.action.method.split(".");

        //If there was a legit json response
        if (_this.dataObj.error) {
            windmill.err("There was a JSON syntax error: '" +
              _this.dataObj.error + "'");
        }
        else {
            //Init and start performance but not if the protocol defer
            if (_this.action.method != 'defer') {
              _this.runAction();
            } else {
              //windmill.serviceDelay = windmill.serviceDelayDefer;
              windmill.ui.playback.resetPlayBack();
              windmill.stat("Ready, Waiting for tests...");
            }
        }
        //Get the next action from the service
        setTimeout("windmill.xhr.getNext()", windmill.serviceDelay);
    };

    //Send the report
    this.sendReport = function(method, result, timer, info, output) {

        //handle the response
        var reportHandler = function(str) {
            response = eval('(' + str + ')');
            if (!response.result == 200) {
                windmill.err('Error: Report receiving non 200 response.');
            }
        };

        //send the report
        var result_string = JSON.stringify(windmill.xhr.action);
        var test_obj = {
            "result": result,
            "output": typeof(output) !== "undefined" ? output : null,
            "debug": typeof(info) !== "undefined" ? info : null,
            "uuid": windmill.xhr.action.params.uuid,
            "starttime": timer.getStart(),
            "endtime": timer.getEnd()
        };
        var jsonObject = new jsonCall('1.1', 'report');
        jsonObject.params = test_obj;
        var jsonString = JSON.stringify(jsonObject);
        //Actually send the report
        fleegix.xhr.doPost(reportHandler, '/windmill-jsonrpc/', jsonString);
    };

    //Get the next action from the server
    this.getNext = function() {

        //write to the output tab what is going on
        var handleTimeout = function() {
            windmill.err('One of the XHR requests to the server timed out.');
            setTimeout("windmill.xhr.getNext()", windmill.serviceDelay);
        }
        //var handleErr = function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); }

        if (windmill.xhr.loopState) {
            var jsonObject = new jsonCall('1.1', 'next_action');
            var jsonString = JSON.stringify(jsonObject);

            //Execute the post to get the next action
            //Set the xhr timeout to be really high
            //handle the timeout manually
            //Prevent caching
            fleegix.xhr.doReq({
                method: 'POST',
                handleSuccess: this.actionHandler,
                handleErr: function(){ setTimeout("windmill.xhr.getNext()", windmill.serviceDelay); },
                responseFormat: 'text',
                url: '/windmill-jsonrpc/',
                timeoutSeconds: windmill.xhrTimeout,
                handleTimeout: handleTimeout,
                preventCache: true,
                dataPayload: jsonString
            });
        }
    };

    this.clearQueue = function() {
        var h = function(str) {
            windmill.out('Cleared backend queue, ' + str);
        }
        var test_obj = {};
        var jsonObject = new jsonCall('1.1', 'clear_queue');
        var jsonString = JSON.stringify(jsonObject);
        //Actually send the report
        fleegix.xhr.doPost(h, '/windmill-jsonrpc/', jsonString);

    };

    this.createActionFromSuite = function(suiteName, actionObj) {
        //If the suite name is null, set it to default
        if (suiteName == null) {
            suiteName = 'Default';
        }
        windmill.ui.currentSuite = suiteName;
        var suite = windmill.ui.remote.getSuite(suiteName);

        //Add the action to the suite
        var action = windmill.ui.remote.buildAction(actionObj.method, actionObj.params);
        //var suite = $(result);
        suite.appendChild(action);
        //IE Hack
        if (windmill.browser.isIE) {
            $(action.id).innerHTML = action.innerHTML;
        }
        var ide = $('ideForm');

        //If the settings box is checked, scroll to the bottom
        if ($('autoScroll').checked == true) {
            ide.scrollTop = ide.scrollHeight;
        }
        return action;
    };

    this.setActionBackground = function(action, result, obj) {

        if (result != true) {
            if (typeof(action) != 'undefined') {
                action.style.background = '#FF9692';
                action.parentNode.style.border.borderTop = "1px solid red";
                action.parentNode.style.border.borderBottom = "1px solid red";
            }
            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
        else {
            //Write to the result tab
            if ((typeof(action) != 'undefined') && (windmill.runTests == true)) {
                action.style.background = '#C7FFCC';
                if (action.parentNode.style.borderTop.indexOf("red") != -1){
                  action.parentNode.style.borderTop = "1px solid green";
                  action.parentNode.style.borderBottom = "1px solid green";
                }
            }
        }
    };
    this.setWaitBgAndReport = function(aid, result, obj) {

        //Access the action UI and output UI
		var action = $(aid);
        var output = $(aid+"result");

		//If we are in an auto-wait state
		if (windmill.xhr.actionQueued){
			//No longer in a waiting state after this if
			windmill.xhr.actionQueued = false;
			//Update the results
			windmill.actOut(windmill.xhr.action.method, windmill.xhr.action.params, result);
			//We want to add a new output line instead of accessing the old one
			output = null;
        }

        //If no object was provided then we just restart the loop and bail
		if (!obj) {
          windmill.continueLoop();
          return false;
        }

		//End any timing that is happening
        windmill.xhr.action_timer.endTime();

        //Failed action case
		if (!result) {
            if (action != null) { action.style.background = '#FF9692'; }
            if (output != null) { //output.style.background = '#FF9692';
              output.removeAttribute('class');
              output.removeAttribute('style');
              output.className = "ui-state-error ui-corner-all outputEntry";
              output.style.height = "13px";
            }

            //if the continue on error flag has been set by the shell.. then we just keep on going
            if (windmill.stopOnFailure == true) {
                windmill.xhr.loopState = false;
                windmill.stat("Paused, error?...");
            }
        }
				//Passing action case
        else {
            //Write to the result tab
            try {
                if ((typeof(action) != 'undefined') && (windmill.runTests)) {
                    action.style.background = '#C7FFCC';
                }
                if ((typeof(output) != 'undefined') && (windmill.runTests)) {
                    output.style.background = '#C7FFCC';
                }
            }
            catch(err) {}
        }
        //Send the report
        windmill.xhr.action = obj;
        //Don't report if we are running js tests
        if (obj.params.orig != 'js'){
          //windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer);
          windmill.xhr.sendReport(obj.method, result, windmill.xhr.action_timer, undefined);
        }
        windmill.xhr.action_timer.write(obj.params);
        windmill.continueLoop();
    };
};
<|endoftext|>