<commit_before>angular.module('app.controllers', [])
    // Controller for Tag View
    .controller('TagCtrl', function ($scope, $rootScope, $cordovaBluetoothLE, Log, settings) {
        $scope.devices = {};
        $scope.scanDevice = false;
        $scope.noDevice = true;
        $scope.dev1Connected = false;
        $scope.dev2Connected = false;
        $scope.currentDevice1 = null;
        $scope.currentDevice2 = null;
        $scope.firstScan = true;
        $scope.barometer = {
            temperatureDev1: "FREEZING HELL", pressureDev1: "Inside of Jupiter",
            temperatureDev2: "FREEZING HELL", pressureDev2: "Inside of Jupiter"
        };
        var barometer = {
            service: "F000AA40-0451-4000-B000-000000000000",
            data: "F000AA41-0451-4000-B000-000000000000",
            notification: "F0002902-0451-4000-B000-000000000000",
            configuration: "F000AA42-0451-4000-B000-000000000000",
            period: "F000AA43-0451-4000-B000-000000000000"
        };

        function getLastCon() {
            return localStorage.getItem("lastCon");
        }

        function setLastCon(deviceId) {
            localStorage.setItem("lastCon", deviceId);
        }

        $scope.startScan = function () {
            var params = {
                services: [],
                allowDuplicates: false,
                scanTimeout: settings.settings.duration * 1000
            };

            if (window.cordova) {
                params.scanMode = bluetoothle.SCAN_MODE_LOW_POWER;
                params.matchMode = bluetoothle.MATCH_MODE_STICKY;
                params.matchNum = bluetoothle.MATCH_NUM_ONE_ADVERTISEMENT;
                //params.callbackType = bluetoothle.CALLBACK_TYPE_FIRST_MATCH;
            }

            function startScan() {
                $cordovaBluetoothLE.startScan(params).then(function (obj) {
                    Log.add("Start Scan Auto Stop : " + JSON.stringify(obj));
                    $scope.firstScan = false;
                    $scope.scanDevice = false;
                }, function (obj) {
                    Log.add("Start Scan Error : " + JSON.stringify(obj));
                }, function (device) {
                    Log.add("Start Scan Success : " + JSON.stringify(device));

                    if (device.status == "scanStarted") {
                         $scope.scanDevice = true;
                         return;
                    }

                    $scope.noDevice = false;
                    $scope.devices[device.address] = device;
                    $scope.devices[device.address].services = {};
                    console.log(JSON.stringify($scope.devices));

                    if (device.address == getLastCon() && $scope.firstScan) {
                        $scope.connect(device);
                        $scope.firstScan = false;
                    }
                })
            };
            Log.add("Start Scan : " + JSON.stringify(params));

            $cordovaBluetoothLE.isLocationEnabled().then(function (obj) {
                console.log(JSON.stringify(obj));
                if(obj.isLocationEnabled)
                {
                    startScan();
                }
                else
                {
                    $cordovaBluetoothLE.requestLocation().then(function (obj) {
                        console.log(JSON.stringify(obj));
                        if(obj.requestLocation)
                        {
                            startScan();
                        }
                        else
                        {
                            navigator.notification.alert("Sorry. Scanning only works with location services enabled.", null);
                        }
                    }, null);

                }
            }, null);

        };

        $scope.connect = function (device) {

            var onConnect = function (obj) {

                if ($scope.dev1Connected && $scope.dev2Connected) {
                    navigator.notification.alert("Sorry. You cannot connect to more than two devices!", function () { });
                    return;
                }

                Log.add("Connect Success : " + JSON.stringify(obj));
                // Save deviceId as last connected one
                setLastCon(device.address);

                if ($scope.dev1Connected == false) {
                    $scope.dev1Connected = true;
                    $scope.currentDevice1 = device;
                    $scope.barometer.temperatureDev1 = "FREEZING HELL";
                    $scope.barometer.pressureDev1 = "Inside of Jupiter";
                } else {
                    $scope.dev2Connected = true;
                    $scope.currentDevice2 = device;
                    $scope.barometer.temperatureDev2 = "FREEZING HELL";
                    $scope.barometer.pressureDev2 = "Inside of Jupiter";
                }

                //Subscribe to barometer service
                var params = {
                    address: device.address,
                    service: barometer.service,
                    characteristic: barometer.data,
                    timeout: 5000
                };

                Log.add("Subscribe : " + JSON.stringify(params));

                $cordovaBluetoothLE.subscribe(params).then(function (obj) {
                    Log.add("Subscribe Auto Unsubscribe : " + JSON.stringify(obj));
                }, function (obj) {
                    Log.add("Subscribe Error : " + JSON.stringify(obj));
                }, function (obj) {
                    //Log.add("Subscribe Success : " + JSON.stringify(obj));

                    if (obj.status == "subscribedResult") {
                        //Log.add("Subscribed Result");
                        onBarometerData(obj, device);
                        var bytes = $cordovaBluetoothLE.encodedStringToBytes(obj.value);
                        Log.add("Subscribe Success ASCII (" + bytes.length + "): " + $cordovaBluetoothLE.bytesToString(bytes));
                        Log.add("HEX (" + bytes.length + "): " + $cordovaBluetoothLE.bytesToHex(bytes));
                    } else if (obj.status == "subscribed") {
                        Log.add("Subscribed");
                        //Turn on barometer
                        var barometerConfig = new Uint8Array(1);
                        barometerConfig[0] = 0x01;
                        var params = {
                            address: device.address,
                            service: barometer.service,
                            characteristic: barometer.configuration,
                            value: $cordovaBluetoothLE.bytesToEncodedString(barometerConfig),
                            timeout: 5000
                        };

                        Log.add("Write : " + JSON.stringify(params));

                        $cordovaBluetoothLE.write(params).then(function (obj) {
                            Log.add("Write Success : " + JSON.stringify(obj));
                        }, function (obj) {
                            Log.add("Write Error : " + JSON.stringify(obj));
                        });
                    } else {
                        Log.add("Unexpected Subscribe Status");
                    }
                });

            };
            var params = { address: device.address, timeout: 10000 };

            Log.add("Connect : " + JSON.stringify(params));

            $cordovaBluetoothLE.connect(params).then(null, function (obj) {
                Log.add("Connect Error : " + JSON.stringify(obj));
                $scope.close(params.address); //Best practice is to close on connection error
            }, function () {
                $scope.discover(device.address, onConnect);
            });

        };

        $rootScope.$on("bleEnabledEvent", function () {
            $scope.startScan();
        })

        $scope.refreshSensortags = function () {
            $scope.devices = {};
            $scope.startScan();
            $scope.noDevice = true;
        }

        $scope.stopScan = function () {
            $scope.scanDevice = false;
            $scope.firstScan = false;
            $cordovaBluetoothLE.stopScan().then(function (obj) {
                Log.add("Stop Scan Success : " + JSON.stringify(obj));
            }, function (obj) {
                Log.add("Stop Scan Error : " + JSON.stringify(obj));
            });
        }

        $scope.close = function (address) {
            var params = { address: address };

            Log.add("Close : " + JSON.stringify(params));

            $cordovaBluetoothLE.close(params).then(function (obj) {
                Log.add("Close Success : " + JSON.stringify(obj));
            }, function (obj) {
                Log.add("Close Error : " + JSON.stringify(obj));
            });

            var device = $scope.devices[address];
            device.services = {};
        };

        function onBarometerData(obj, device) {
            var a = $cordovaBluetoothLE.encodedStringToBytes(obj.value);

            function sensorBarometerConvert(data) {
                return (data / 100);
            }

            if ($scope.currentDevice1.address == device.address) {
                $scope.barometer.temperatureDev1 = sensorBarometerConvert(a[0] | (a[1] << 8) | (a[2] << 16)) + "°C";
                $scope.barometer.pressureDev1 = sensorBarometerConvert(a[3] | (a[4] << 8) | (a[5] << 16)) + "hPa";
            } else if ($scope.currentDevice2.address == device.address) {
                $scope.barometer.temperatureDev2 = sensorBarometerConvert(a[0] | (a[1] << 8) | (a[2] << 16)) + "°C";
                $scope.barometer.pressureDev2 = sensorBarometerConvert(a[3] | (a[4] << 8) | (a[5] << 16)) + "hPa";
            } else {
                Log.add("onBarometerData: no matching device" + JSON.stringify(device.address));
            }
        }

        $scope.disconnect = function (device) {
            if ($scope.dev1Connected && $scope.currentDevice1.address == device.address) {
                $scope.dev1Connected = false;
                $scope.close($scope.currentDevice1.address);
            } else if ($scope.dev2Connected && $scope.currentDevice2.address == device.address) {
                $scope.dev2Connected = false;
                $scope.close($scope.currentDevice2.address);
            }
        }

        $scope.isConnected = function (device) {
            if ($scope.dev1Connected && $scope.currentDevice1.address == device.address) {
                return true;
            } else if ($scope.dev2Connected && $scope.currentDevice2.address == device.address) {
                return true;
            } else {
                return false;
            }
        }

        $scope.discover = function (address, afterFunction) {
            var params = {
                address: address,
                timeout: 10000
            };

            Log.add("Discover : " + JSON.stringify(params));

            $cordovaBluetoothLE.discover(params).then(function (obj) {
                Log.add("Discover Success : " + JSON.stringify(obj));

                var device = $scope.devices[obj.address];

                var services = obj.services;

                for (var i = 0; i < services.length; i++) {
                    var service = services[i];

                    addService(service, device);

                    var serviceNew = device.services[service.uuid];

                    var characteristics = service.characteristics;

                    for (var j = 0; j < characteristics.length; j++) {
                        var characteristic = characteristics[j];

                        addCharacteristic(characteristic, serviceNew);

                        var characteristicNew = serviceNew.characteristics[characteristic.uuid];

                        var descriptors = characteristic.descriptors;

                        for (var k = 0; k < descriptors.length; k++) {
                            var descriptor = descriptors[k];

                            addDescriptor(descriptor, characteristicNew);
                        }

                    }
                }
                if (afterFunction != undefined) {
                    afterFunction();
                }
            }, function (obj) {
                Log.add("Discover Error : " + JSON.stringify(obj));
            });
        };
        function addService(service, device) {
            if (device.services[service.uuid] !== undefined) {
                return;
            }
            device.services[service.uuid] = { uuid: service.uuid, characteristics: {} };
        }

        function addCharacteristic(characteristic, service) {
            if (service.characteristics[characteristic.uuid] !== undefined) {
                return;
            }
            service.characteristics[characteristic.uuid] = { uuid: characteristic.uuid, descriptors: {}, properties: characteristic.properties };
        }

        function addDescriptor(descriptor, characteristic) {
            if (characteristic.descriptors[descriptor.uuid] !== undefined) {
                return;
            }
            characteristic.descriptors[descriptor.uuid] = { uuid: descriptor.uuid };
        }

        $scope.firstScan = false;
        if (settings.settings.reconnect == "true" || settings.settings.reconnect === true) {
            $scope.firstScan = true;

        }

        $rootScope.$on("bleEnabledEvent", function () {
            $scope.startScan();
        });

    })

    // Controller for Settings
    .controller('SettingsCtrl', function ($scope, Log, settings) {

        // Link the scope settings to the settings service
        $scope.settings = settings.settings;

        // Scope update function is the settings service persist function
        $scope.update = settings.persistSettings;

        $scope.newVolumeProfileName = "";

        $scope.changedVolume = function () {
            $scope.settings.currentVolumeProfile = false;
            $scope.settings.mute = false;
            $scope.update();
        }

        $scope.addVolumeProfile = function (name) {
            // TODO: no duplicates!
            var newProfile = { name: name, volume: $scope.settings.volume };
            $scope.settings.volumeProfiles.push(newProfile);
            $scope.settings.currentVolumeProfile = newProfile;
            $scope.newVolumeProfileName = "";  // TODO: has no effect!
        }

        $scope.removeVolumeProfile = function (volumeProfile) {  // TODO
            console.log("removing volume profile " + volumeProfile.name);
            $scope.settings.volumeProfiles = $scope.settings.volumeProfiles.filter(function (item) {
                return item.name !== volumeProfile.name;
            });
        }

        $scope.changeVolumeProfile = function () {
            $scope.settings.volume = JSON.parse($scope.settings.currentVolumeProfile).volume;
            $scope.update();
        }

        //called when mute was toggled by pressing the button
        $scope.muteToggle = function () {
            if (settings.settings.mute) {
                settings.settings.volBeforeMute = settings.settings.volume;
                settings.settings.volume = parseInt(0);
            } else {
                settings.settings.volume = parseInt(settings.settings.volBeforeMute);
            }
            //persist settings
            $scope.update();
        }

        $scope.$on('volumeupbutton', function () {
            $scope.$apply(function () {									// angular doesn't fire $apply on the events so if $broadcast is called outside angular's context, you are going to need to $apply by hand.

                // Update Volume + checks for valid values (0 to 100)
                if (settings.settings.mute) {
                    var vol = parseInt(settings.settings.volBeforeMute);
                } else {
                    // parse to Int or otherwise it is not if changed per GUI
                    var vol = parseInt(settings.settings.volume);
                }
                var up = 10;

                // Catch if volume 91 to 100, update to max 100
                if (vol > 90)
                    up = 100 - vol;
                vol = vol + up;

                settings.settings.volume = vol;
                //unmute as the user changed the volume and persist
                $scope.changedVolume();

            });
        });

        $scope.$on('volumedownbutton', function () {
            $scope.$apply(function () {									// angular doesn't fire $apply on the events so if $broadcast is called outside angular's context, you are going to need to $apply by hand.

                // Update Volume + checks for valid values (0 to 100)
                if (settings.settings.mute) {
                    var vol = parseInt(settings.settings.volBeforeMute);
                } else {
                    // parse to Int or otherwise it is not if changed per GUI
                    var vol = parseInt(settings.settings.volume);
                }
                var down = 10;

                // Catch if volume 9 to 0, update to min 0
                if (vol < 10)
                    down = vol;
                vol = vol - down;

                settings.settings.volume = vol;
                //unmute as the user changed the volume and persist
                $scope.changedVolume();

            });
        });
    });
<commit_msg>Removed duplicate onBleEnabled Event handler<commit_after>angular.module('app.controllers', [])
    // Controller for Tag View
    .controller('TagCtrl', function ($scope, $rootScope, $cordovaBluetoothLE, Log, settings) {
        $scope.devices = {};
        $scope.scanDevice = false;
        $scope.noDevice = true;
        $scope.dev1Connected = false;
        $scope.dev2Connected = false;
        $scope.currentDevice1 = null;
        $scope.currentDevice2 = null;
        $scope.firstScan = true;
        $scope.barometer = {
            temperatureDev1: "FREEZING HELL", pressureDev1: "Inside of Jupiter",
            temperatureDev2: "FREEZING HELL", pressureDev2: "Inside of Jupiter"
        };
        var barometer = {
            service: "F000AA40-0451-4000-B000-000000000000",
            data: "F000AA41-0451-4000-B000-000000000000",
            notification: "F0002902-0451-4000-B000-000000000000",
            configuration: "F000AA42-0451-4000-B000-000000000000",
            period: "F000AA43-0451-4000-B000-000000000000"
        };

        function getLastCon() {
            return localStorage.getItem("lastCon");
        }

        function setLastCon(deviceId) {
            localStorage.setItem("lastCon", deviceId);
        }

        $scope.startScan = function () {
            var params = {
                services: [],
                allowDuplicates: false,
                scanTimeout: settings.settings.duration * 1000
            };

            if (window.cordova) {
                params.scanMode = bluetoothle.SCAN_MODE_LOW_POWER;
                params.matchMode = bluetoothle.MATCH_MODE_STICKY;
                params.matchNum = bluetoothle.MATCH_NUM_ONE_ADVERTISEMENT;
                //params.callbackType = bluetoothle.CALLBACK_TYPE_FIRST_MATCH;
            }

            function startScan() {
                $cordovaBluetoothLE.startScan(params).then(function (obj) {
                    Log.add("Start Scan Auto Stop : " + JSON.stringify(obj));
                    $scope.firstScan = false;
                    $scope.scanDevice = false;
                }, function (obj) {
                    Log.add("Start Scan Error : " + JSON.stringify(obj));
                }, function (device) {
                    Log.add("Start Scan Success : " + JSON.stringify(device));

                    if (device.status == "scanStarted") {
                         $scope.scanDevice = true;
                         return;
                    }

                    $scope.noDevice = false;
                    $scope.devices[device.address] = device;
                    $scope.devices[device.address].services = {};
                    console.log(JSON.stringify($scope.devices));

                    if (device.address == getLastCon() && $scope.firstScan) {
                        $scope.connect(device);
                        $scope.firstScan = false;
                    }
                })
            };
            Log.add("Start Scan : " + JSON.stringify(params));

            $cordovaBluetoothLE.isLocationEnabled().then(function (obj) {
                console.log(JSON.stringify(obj));
                if(obj.isLocationEnabled)
                {
                    startScan();
                }
                else
                {
                    $cordovaBluetoothLE.requestLocation().then(function (obj) {
                        console.log(JSON.stringify(obj));
                        if(obj.requestLocation)
                        {
                            startScan();
                        }
                        else
                        {
                            navigator.notification.alert("Sorry. Scanning only works with location services enabled.", null);
                        }
                    }, null);

                }
            }, null);

        };

        $scope.connect = function (device) {

            var onConnect = function (obj) {

                if ($scope.dev1Connected && $scope.dev2Connected) {
                    navigator.notification.alert("Sorry. You cannot connect to more than two devices!", function () { });
                    return;
                }

                Log.add("Connect Success : " + JSON.stringify(obj));
                // Save deviceId as last connected one
                setLastCon(device.address);

                if ($scope.dev1Connected == false) {
                    $scope.dev1Connected = true;
                    $scope.currentDevice1 = device;
                    $scope.barometer.temperatureDev1 = "FREEZING HELL";
                    $scope.barometer.pressureDev1 = "Inside of Jupiter";
                } else {
                    $scope.dev2Connected = true;
                    $scope.currentDevice2 = device;
                    $scope.barometer.temperatureDev2 = "FREEZING HELL";
                    $scope.barometer.pressureDev2 = "Inside of Jupiter";
                }

                //Subscribe to barometer service
                var params = {
                    address: device.address,
                    service: barometer.service,
                    characteristic: barometer.data,
                    timeout: 5000
                };

                Log.add("Subscribe : " + JSON.stringify(params));

                $cordovaBluetoothLE.subscribe(params).then(function (obj) {
                    Log.add("Subscribe Auto Unsubscribe : " + JSON.stringify(obj));
                }, function (obj) {
                    Log.add("Subscribe Error : " + JSON.stringify(obj));
                }, function (obj) {
                    //Log.add("Subscribe Success : " + JSON.stringify(obj));

                    if (obj.status == "subscribedResult") {
                        //Log.add("Subscribed Result");
                        onBarometerData(obj, device);
                        var bytes = $cordovaBluetoothLE.encodedStringToBytes(obj.value);
                        Log.add("Subscribe Success ASCII (" + bytes.length + "): " + $cordovaBluetoothLE.bytesToString(bytes));
                        Log.add("HEX (" + bytes.length + "): " + $cordovaBluetoothLE.bytesToHex(bytes));
                    } else if (obj.status == "subscribed") {
                        Log.add("Subscribed");
                        //Turn on barometer
                        var barometerConfig = new Uint8Array(1);
                        barometerConfig[0] = 0x01;
                        var params = {
                            address: device.address,
                            service: barometer.service,
                            characteristic: barometer.configuration,
                            value: $cordovaBluetoothLE.bytesToEncodedString(barometerConfig),
                            timeout: 5000
                        };

                        Log.add("Write : " + JSON.stringify(params));

                        $cordovaBluetoothLE.write(params).then(function (obj) {
                            Log.add("Write Success : " + JSON.stringify(obj));
                        }, function (obj) {
                            Log.add("Write Error : " + JSON.stringify(obj));
                        });
                    } else {
                        Log.add("Unexpected Subscribe Status");
                    }
                });

            };
            var params = { address: device.address, timeout: 10000 };

            Log.add("Connect : " + JSON.stringify(params));

            $cordovaBluetoothLE.connect(params).then(null, function (obj) {
                Log.add("Connect Error : " + JSON.stringify(obj));
                $scope.close(params.address); //Best practice is to close on connection error
            }, function () {
                $scope.discover(device.address, onConnect);
            });

        };

        $scope.refreshSensortags = function () {
            $scope.devices = {};
            $scope.startScan();
            $scope.noDevice = true;
        }

        $scope.stopScan = function () {
            $scope.scanDevice = false;
            $scope.firstScan = false;
            $cordovaBluetoothLE.stopScan().then(function (obj) {
                Log.add("Stop Scan Success : " + JSON.stringify(obj));
            }, function (obj) {
                Log.add("Stop Scan Error : " + JSON.stringify(obj));
            });
        }

        $scope.close = function (address) {
            var params = { address: address };

            Log.add("Close : " + JSON.stringify(params));

            $cordovaBluetoothLE.close(params).then(function (obj) {
                Log.add("Close Success : " + JSON.stringify(obj));
            }, function (obj) {
                Log.add("Close Error : " + JSON.stringify(obj));
            });

            var device = $scope.devices[address];
            device.services = {};
        };

        function onBarometerData(obj, device) {
            var a = $cordovaBluetoothLE.encodedStringToBytes(obj.value);

            function sensorBarometerConvert(data) {
                return (data / 100);
            }

            if ($scope.currentDevice1.address == device.address) {
                $scope.barometer.temperatureDev1 = sensorBarometerConvert(a[0] | (a[1] << 8) | (a[2] << 16)) + "°C";
                $scope.barometer.pressureDev1 = sensorBarometerConvert(a[3] | (a[4] << 8) | (a[5] << 16)) + "hPa";
            } else if ($scope.currentDevice2.address == device.address) {
                $scope.barometer.temperatureDev2 = sensorBarometerConvert(a[0] | (a[1] << 8) | (a[2] << 16)) + "°C";
                $scope.barometer.pressureDev2 = sensorBarometerConvert(a[3] | (a[4] << 8) | (a[5] << 16)) + "hPa";
            } else {
                Log.add("onBarometerData: no matching device" + JSON.stringify(device.address));
            }
        }

        $scope.disconnect = function (device) {
            if ($scope.dev1Connected && $scope.currentDevice1.address == device.address) {
                $scope.dev1Connected = false;
                $scope.close($scope.currentDevice1.address);
            } else if ($scope.dev2Connected && $scope.currentDevice2.address == device.address) {
                $scope.dev2Connected = false;
                $scope.close($scope.currentDevice2.address);
            }
        }

        $scope.isConnected = function (device) {
            if ($scope.dev1Connected && $scope.currentDevice1.address == device.address) {
                return true;
            } else if ($scope.dev2Connected && $scope.currentDevice2.address == device.address) {
                return true;
            } else {
                return false;
            }
        }

        $scope.discover = function (address, afterFunction) {
            var params = {
                address: address,
                timeout: 10000
            };

            Log.add("Discover : " + JSON.stringify(params));

            $cordovaBluetoothLE.discover(params).then(function (obj) {
                Log.add("Discover Success : " + JSON.stringify(obj));

                var device = $scope.devices[obj.address];

                var services = obj.services;

                for (var i = 0; i < services.length; i++) {
                    var service = services[i];

                    addService(service, device);

                    var serviceNew = device.services[service.uuid];

                    var characteristics = service.characteristics;

                    for (var j = 0; j < characteristics.length; j++) {
                        var characteristic = characteristics[j];

                        addCharacteristic(characteristic, serviceNew);

                        var characteristicNew = serviceNew.characteristics[characteristic.uuid];

                        var descriptors = characteristic.descriptors;

                        for (var k = 0; k < descriptors.length; k++) {
                            var descriptor = descriptors[k];

                            addDescriptor(descriptor, characteristicNew);
                        }

                    }
                }
                if (afterFunction != undefined) {
                    afterFunction();
                }
            }, function (obj) {
                Log.add("Discover Error : " + JSON.stringify(obj));
            });
        };
        function addService(service, device) {
            if (device.services[service.uuid] !== undefined) {
                return;
            }
            device.services[service.uuid] = { uuid: service.uuid, characteristics: {} };
        }

        function addCharacteristic(characteristic, service) {
            if (service.characteristics[characteristic.uuid] !== undefined) {
                return;
            }
            service.characteristics[characteristic.uuid] = { uuid: characteristic.uuid, descriptors: {}, properties: characteristic.properties };
        }

        function addDescriptor(descriptor, characteristic) {
            if (characteristic.descriptors[descriptor.uuid] !== undefined) {
                return;
            }
            characteristic.descriptors[descriptor.uuid] = { uuid: descriptor.uuid };
        }

        $scope.firstScan = false;
        if (settings.settings.reconnect == "true" || settings.settings.reconnect === true) {
            $scope.firstScan = true;

        }

        $rootScope.$on("bleEnabledEvent", function () {
            console.log("BLE Enabled Event");
            $scope.startScan();
        });

    })

    // Controller for Settings
    .controller('SettingsCtrl', function ($scope, Log, settings) {

        // Link the scope settings to the settings service
        $scope.settings = settings.settings;

        // Scope update function is the settings service persist function
        $scope.update = settings.persistSettings;

        $scope.newVolumeProfileName = "";

        $scope.changedVolume = function () {
            $scope.settings.currentVolumeProfile = false;
            $scope.settings.mute = false;
            $scope.update();
        }

        $scope.addVolumeProfile = function (name) {
            // TODO: no duplicates!
            var newProfile = { name: name, volume: $scope.settings.volume };
            $scope.settings.volumeProfiles.push(newProfile);
            $scope.settings.currentVolumeProfile = newProfile;
            $scope.newVolumeProfileName = "";  // TODO: has no effect!
        }

        $scope.removeVolumeProfile = function (volumeProfile) {  // TODO
            console.log("removing volume profile " + volumeProfile.name);
            $scope.settings.volumeProfiles = $scope.settings.volumeProfiles.filter(function (item) {
                return item.name !== volumeProfile.name;
            });
        }

        $scope.changeVolumeProfile = function () {
            $scope.settings.volume = JSON.parse($scope.settings.currentVolumeProfile).volume;
            $scope.update();
        }

        //called when mute was toggled by pressing the button
        $scope.muteToggle = function () {
            if (settings.settings.mute) {
                settings.settings.volBeforeMute = settings.settings.volume;
                settings.settings.volume = parseInt(0);
            } else {
                settings.settings.volume = parseInt(settings.settings.volBeforeMute);
            }
            //persist settings
            $scope.update();
        }

        $scope.$on('volumeupbutton', function () {
            $scope.$apply(function () {									// angular doesn't fire $apply on the events so if $broadcast is called outside angular's context, you are going to need to $apply by hand.

                // Update Volume + checks for valid values (0 to 100)
                if (settings.settings.mute) {
                    var vol = parseInt(settings.settings.volBeforeMute);
                } else {
                    // parse to Int or otherwise it is not if changed per GUI
                    var vol = parseInt(settings.settings.volume);
                }
                var up = 10;

                // Catch if volume 91 to 100, update to max 100
                if (vol > 90)
                    up = 100 - vol;
                vol = vol + up;

                settings.settings.volume = vol;
                //unmute as the user changed the volume and persist
                $scope.changedVolume();

            });
        });

        $scope.$on('volumedownbutton', function () {
            $scope.$apply(function () {									// angular doesn't fire $apply on the events so if $broadcast is called outside angular's context, you are going to need to $apply by hand.

                // Update Volume + checks for valid values (0 to 100)
                if (settings.settings.mute) {
                    var vol = parseInt(settings.settings.volBeforeMute);
                } else {
                    // parse to Int or otherwise it is not if changed per GUI
                    var vol = parseInt(settings.settings.volume);
                }
                var down = 10;

                // Catch if volume 9 to 0, update to min 0
                if (vol < 10)
                    down = vol;
                vol = vol - down;

                settings.settings.volume = vol;
                //unmute as the user changed the volume and persist
                $scope.changedVolume();

            });
        });
    });
<|endoftext|>


<commit_before>import xmlService from 'xml';

import data from '../data/wrapper';

/**
 * setCommonResponseHeaders - Set HTTP response headers
 * @param {object} headers - key and value of new headers to add
 * @param {object} response - http response object
 * @param {object} log - Werelogs logger
 * @return {object} response - response object with additional headers
 */
function setCommonResponseHeaders(headers, response, log) {
    if (headers && typeof headers === 'object') {
        log.trace('setting response headers', { headers });
        Object.keys(headers).forEach(key => {
            if (headers[key]) {
                response.setHeader(key, headers[key]);
            }
        });
    }
    response.setHeader('server', 'AmazonS3');
    // to be expanded in further implementation of logging of requests
    response.setHeader('x-amz-id-2', log.getSerializedUids());
    response.setHeader('x-amz-request-id', log.getSerializedUids());
    return response;
}
/**
 * okHeaderResponse - Response with only headers, no body
 * @param {object} headers - key and value of new headers to add
 * @param {object} response - http response object
 * @param {number} httpCode -- http response code
 * @param {object} log - Werelogs logger
 * @return {object} response - response object with additional headers
 */
function okHeaderResponse(headers, response, httpCode, log) {
    log.trace('sending success header response');
    setCommonResponseHeaders(headers, response, log);
    log.debug('response http code', { httpCode });
    response.writeHead(httpCode);
    return response.end(() => {
        log.end().info('responded to request', {
            httpCode: response.statusCode,
        });
    });
}

/**
 * okXMLResponse - Response with XML body
 * @param {string} xml - XML body as string
 * @param {object} response - http response object
 * @param {object} log - Werelogs logger
 * @return {object} response - response object with additional headers
 */
function okXMLResponse(xml, response, log) {
    log.trace('sending success xml response');
    setCommonResponseHeaders(null, response, log);
    response.writeHead(200, { 'Content-type': 'application/xml' });
    log.debug('response http code', { httpCode: 200 });
    log.trace('xml response', { xml });
    return response.end(xml, 'utf8', () => {
        log.end().info('responded with XML', {
            httpCode: response.statusCode,
        });
    });
}

function errorXMLResponse(errCode, response, log) {
    log.trace('sending error xml response', { errCode });
    const result = { xml: '', httpCode: 500 };
    /*
    <?xml version="1.0" encoding="UTF-8"?>
     <Error>
     NoSuchKey
     <Message>The resource you requested does not exist</Message>
     <Resource>/mybucket/myfoto.jpg</Resource>
     <RequestId>4442587FB7D0A2F9</RequestId>
     </Error>
     */

    const errXMLObj = [{
        Error: [
            { Code: errCode.message },
            { Message: errCode.description },
            { Resource: '' },
            { RequestId: '' },
        ],
    }];
    result.xml = xmlService(errXMLObj, { declaration: { encoding: 'UTF-8' } });
    log.trace('error xml', { xml: result.xml });
    setCommonResponseHeaders(null, response, log);
    response.writeHead(errCode.code, { 'Content-type': 'application/xml' });
    log.debug('response http code', { httpCode: errCode.code });
    return response.end(result.xml, 'utf8', () => {
        log.end().info('responded with error XML', {
            httpCode: response.statusCode,
        });
    });
}

/**
 * Modify response headers for an objectGet or objectHead request
 * @param {object} overrideHeaders - headers in this object override common
 * headers. These are extracted from the request object
 * @param {object} resHeaders - object with common response headers
 * @param {object} response - router's response object
 * @param {object} log - Werelogs logger
 * @return {object} response - modified response object
 */
function okContentHeadersResponse(overrideHeaders, resHeaders, response, log) {
    const addHeaders = {};
    Object.assign(addHeaders, resHeaders);

    if (overrideHeaders['response-content-type']) {
        addHeaders['Content-Type'] = overrideHeaders['response-content-type'];
    }
    if (overrideHeaders['response-content-language']) {
        addHeaders['Content-Language'] =
            overrideHeaders['response-content-language'];
    }
    if (overrideHeaders['response-expires']) {
        addHeaders.Expires = overrideHeaders['response-expires'];
    }
    if (overrideHeaders['response-cache-control']) {
        addHeaders['Cache-Control'] = overrideHeaders['response-cache-control'];
    }
    if (overrideHeaders['response-content-disposition']) {
        addHeaders['Content-Disposition'] =
        overrideHeaders['response-content-disposition'];
    }
    if (overrideHeaders['response-content-encoding']) {
        addHeaders['Content-Encoding'] =
            overrideHeaders['response-content-encoding'];
    }

    setCommonResponseHeaders(addHeaders, response, log);
    log.debug('response http code', { httpCode: 200 });
    response.writeHead(200);
    return response;
}

const routesUtils = {
    /**
     * @param {string} errCode - S3 error Code
     * @param {string} xml - xml body as string conforming to S3's spec.
     * @param {object} response - router's response object
     * @param {object} log - Werelogs logger
     * @return {function} - error or success response utility
     */
    responseXMLBody(errCode, xml, response, log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            return okXMLResponse(xml, response, log);
        }
    },

    /**
     * @param {string} errCode - S3 error Code
     * @param {string} resHeaders - headers to be set for the response
     * @param {object} response - router's response object
     * @param {number} httpCode - httpCode to set in response
     *   If none provided, defaults to 200.
     * @param {object} log - Werelogs logger
     * @return {function} - error or success response utility
     */
    responseNoBody(errCode, resHeaders, response, httpCode = 200, log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            return okHeaderResponse(resHeaders, response, httpCode, log);
        }
    },

    /**
     * @param {string} errCode - S3 error Code
     * @param {object} overrideHeaders - headers in this object override common
     * headers. These are extracted from the request object
     * @param {string} resHeaders - headers to be set for the response
     * @param {object} response - router's response object
     * @param {object} log - Werelogs logger
     * @return {object} - router's response object
     */
    responseContentHeaders(errCode, overrideHeaders, resHeaders, response,
        log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            okContentHeadersResponse(overrideHeaders, resHeaders, response,
                log);
        }
        return response.end(() => {
            log.end().info('responded with content headers', {
                httpCode: response.statusCode,
            });
        });
    },

    /**
     * @param {string} errCode - S3 error Code
     * @param {object} overrideHeaders - headers in this object override common
     * headers. These are extracted from the request object
     * @param {string} resHeaders - headers to be set for the response
     * @param {array | null} dataLocations --
     *   - array of locations to get streams from sproxyd
     *   - null if no data for object and only metadata
     * @param {http.ServerResponse} response - response sent to the client
     * @param {object} log - Werelogs logger
     * @return {undefined}
     */
    responseStreamData(errCode, overrideHeaders,
            resHeaders, dataLocations, response, log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            okContentHeadersResponse(overrideHeaders, resHeaders, response,
                log);
        }
        if (dataLocations === null) {
            return response.end(() => {
                log.end().info('responded with only metadata', {
                    httpCode: response.statusCode,
                });
            });
        }
        return routesUtils.responseStreamDataArray(dataLocations,
            response, log);
    },

    /**
     * @param {string[]} array - keys related to the object
     * @param {http.ServerResponse} response - response sent to the client
     * @param {object} log - Werelogs logger
     * @return {undefined}
     */
    responseStreamDataArray(array, response, log) {
        function finish(msg) {
            // Having the nulls here prevent the mock response object
            // in the test from interpreting the callback as data to write
            response.end(null, null, () => {
                log.end().info(msg, {
                    httpCode: response.statusCode,
                });
            });
        }

        function getPart(array, partNumber) {
            if (partNumber >= array.length) {
                return finish('responded with multi-part streamed content');
            }

            const key = array[partNumber];
            data.get(key, log, (err, readStream) => {
                const info = { partNumber, key };
                if (err) {
                    info.errorMessage = err.message;
                    log.error('unable to get object part', info);
                    return finish('unable to get object part');
                }

                readStream.on('end', () => {
                    log.debug('finished forwarding part', info);
                    process.nextTick(getPart, array, partNumber + 1);
                });

                readStream.on('data', (chunk) => {
                    info.chunkSize = chunk.length;
                    log.trace('forwarding chunk', info);
                    response.write(chunk);
                });
            });
        }

        getPart(array, 0);
    },
};

export default routesUtils;
<commit_msg>cleanup: routeUtils - remove dep. for xml generation<commit_after>import data from '../data/wrapper';

/**
 * setCommonResponseHeaders - Set HTTP response headers
 * @param {object} headers - key and value of new headers to add
 * @param {object} response - http response object
 * @param {object} log - Werelogs logger
 * @return {object} response - response object with additional headers
 */
function setCommonResponseHeaders(headers, response, log) {
    if (headers && typeof headers === 'object') {
        log.trace('setting response headers', { headers });
        Object.keys(headers).forEach(key => {
            if (headers[key]) {
                response.setHeader(key, headers[key]);
            }
        });
    }
    response.setHeader('server', 'AmazonS3');
    // to be expanded in further implementation of logging of requests
    response.setHeader('x-amz-id-2', log.getSerializedUids());
    response.setHeader('x-amz-request-id', log.getSerializedUids());
    return response;
}
/**
 * okHeaderResponse - Response with only headers, no body
 * @param {object} headers - key and value of new headers to add
 * @param {object} response - http response object
 * @param {number} httpCode -- http response code
 * @param {object} log - Werelogs logger
 * @return {object} response - response object with additional headers
 */
function okHeaderResponse(headers, response, httpCode, log) {
    log.trace('sending success header response');
    setCommonResponseHeaders(headers, response, log);
    log.debug('response http code', { httpCode });
    response.writeHead(httpCode);
    return response.end(() => {
        log.end().info('responded to request', {
            httpCode: response.statusCode,
        });
    });
}

/**
 * okXMLResponse - Response with XML body
 * @param {string} xml - XML body as string
 * @param {object} response - http response object
 * @param {object} log - Werelogs logger
 * @return {object} response - response object with additional headers
 */
function okXMLResponse(xml, response, log) {
    log.trace('sending success xml response');
    setCommonResponseHeaders(null, response, log);
    response.writeHead(200, { 'Content-type': 'application/xml' });
    log.debug('response http code', { httpCode: 200 });
    log.trace('xml response', { xml });
    return response.end(xml, 'utf8', () => {
        log.end().info('responded with XML', {
            httpCode: response.statusCode,
        });
    });
}

function errorXMLResponse(errCode, response, log) {
    log.trace('sending error xml response', { errCode });
    /*
    <?xml version="1.0" encoding="UTF-8"?>
     <Error>
     NoSuchKey
     <Message>The resource you requested does not exist</Message>
     <Resource>/mybucket/myfoto.jpg</Resource>
     <RequestId>4442587FB7D0A2F9</RequestId>
     </Error>
     */
    const xml = [];
    xml.push(
        '<?xml version="1.0" encoding="UTF-8"?>',
        '<Error>',
        `<Code>${errCode.message}</Code>`,
        `<Message>${errCode.description}</Message>`,
        '<Resource></Resource>',
        `<RequestId>${log.getSerializedUids()}</RequestId>`,
        '</Error>'
    );
    setCommonResponseHeaders(null, response, log);
    response.writeHead(errCode.code, { 'Content-type': 'application/xml' });
    return response.end(xml.join(''), 'utf8', () => {
        log.end().info('responded with error XML', {
            httpCode: response.statusCode,
        });
    });
}

/**
 * Modify response headers for an objectGet or objectHead request
 * @param {object} overrideHeaders - headers in this object override common
 * headers. These are extracted from the request object
 * @param {object} resHeaders - object with common response headers
 * @param {object} response - router's response object
 * @param {object} log - Werelogs logger
 * @return {object} response - modified response object
 */
function okContentHeadersResponse(overrideHeaders, resHeaders, response, log) {
    const addHeaders = {};
    Object.assign(addHeaders, resHeaders);

    if (overrideHeaders['response-content-type']) {
        addHeaders['Content-Type'] = overrideHeaders['response-content-type'];
    }
    if (overrideHeaders['response-content-language']) {
        addHeaders['Content-Language'] =
            overrideHeaders['response-content-language'];
    }
    if (overrideHeaders['response-expires']) {
        addHeaders.Expires = overrideHeaders['response-expires'];
    }
    if (overrideHeaders['response-cache-control']) {
        addHeaders['Cache-Control'] = overrideHeaders['response-cache-control'];
    }
    if (overrideHeaders['response-content-disposition']) {
        addHeaders['Content-Disposition'] =
        overrideHeaders['response-content-disposition'];
    }
    if (overrideHeaders['response-content-encoding']) {
        addHeaders['Content-Encoding'] =
            overrideHeaders['response-content-encoding'];
    }

    setCommonResponseHeaders(addHeaders, response, log);
    log.debug('response http code', { httpCode: 200 });
    response.writeHead(200);
    return response;
}

const routesUtils = {
    /**
     * @param {string} errCode - S3 error Code
     * @param {string} xml - xml body as string conforming to S3's spec.
     * @param {object} response - router's response object
     * @param {object} log - Werelogs logger
     * @return {function} - error or success response utility
     */
    responseXMLBody(errCode, xml, response, log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            return okXMLResponse(xml, response, log);
        }
    },

    /**
     * @param {string} errCode - S3 error Code
     * @param {string} resHeaders - headers to be set for the response
     * @param {object} response - router's response object
     * @param {number} httpCode - httpCode to set in response
     *   If none provided, defaults to 200.
     * @param {object} log - Werelogs logger
     * @return {function} - error or success response utility
     */
    responseNoBody(errCode, resHeaders, response, httpCode = 200, log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            return okHeaderResponse(resHeaders, response, httpCode, log);
        }
    },

    /**
     * @param {string} errCode - S3 error Code
     * @param {object} overrideHeaders - headers in this object override common
     * headers. These are extracted from the request object
     * @param {string} resHeaders - headers to be set for the response
     * @param {object} response - router's response object
     * @param {object} log - Werelogs logger
     * @return {object} - router's response object
     */
    responseContentHeaders(errCode, overrideHeaders, resHeaders, response,
        log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            okContentHeadersResponse(overrideHeaders, resHeaders, response,
                log);
        }
        return response.end(() => {
            log.end().info('responded with content headers', {
                httpCode: response.statusCode,
            });
        });
    },

    /**
     * @param {string} errCode - S3 error Code
     * @param {object} overrideHeaders - headers in this object override common
     * headers. These are extracted from the request object
     * @param {string} resHeaders - headers to be set for the response
     * @param {array | null} dataLocations --
     *   - array of locations to get streams from sproxyd
     *   - null if no data for object and only metadata
     * @param {http.ServerResponse} response - response sent to the client
     * @param {object} log - Werelogs logger
     * @return {undefined}
     */
    responseStreamData(errCode, overrideHeaders,
            resHeaders, dataLocations, response, log) {
        if (errCode && !response.headersSent) {
            return errorXMLResponse(errCode, response, log);
        }
        if (!response.headersSent) {
            okContentHeadersResponse(overrideHeaders, resHeaders, response,
                log);
        }
        if (dataLocations === null) {
            return response.end(() => {
                log.end().info('responded with only metadata', {
                    httpCode: response.statusCode,
                });
            });
        }
        return routesUtils.responseStreamDataArray(dataLocations,
            response, log);
    },

    /**
     * @param {string[]} array - keys related to the object
     * @param {http.ServerResponse} response - response sent to the client
     * @param {object} log - Werelogs logger
     * @return {undefined}
     */
    responseStreamDataArray(array, response, log) {
        function finish(msg) {
            // Having the nulls here prevent the mock response object
            // in the test from interpreting the callback as data to write
            response.end(null, null, () => {
                log.end().info(msg, {
                    httpCode: response.statusCode,
                });
            });
        }

        function getPart(array, partNumber) {
            if (partNumber >= array.length) {
                return finish('responded with multi-part streamed content');
            }

            const key = array[partNumber];
            data.get(key, log, (err, readStream) => {
                const info = { partNumber, key };
                if (err) {
                    info.errorMessage = err.message;
                    log.error('unable to get object part', info);
                    return finish('unable to get object part');
                }

                readStream.on('end', () => {
                    log.debug('finished forwarding part', info);
                    process.nextTick(getPart, array, partNumber + 1);
                });

                readStream.on('data', (chunk) => {
                    info.chunkSize = chunk.length;
                    log.trace('forwarding chunk', info);
                    response.write(chunk);
                });
            });
        }

        getPart(array, 0);
    },
};

export default routesUtils;
<|endoftext|>


<commit_before>/**
* Auteur :  DWAPS Formation - Michael Cornillon
* Mail :    contact@dwaps.fr
* Tel :     0651279211
* Site :    http://dwaps.fr
* Date :    12/03/2017
**/

angular
	.module('controllers', [])
	.controller('homeCtrl', homeCtrl)
;

function homeCtrl($scope, $rootScope, $filter, dwapsLog)
{
    $rootScope.type = {
        ARRAY: "tab",
        OBJECT: "obj",
        STRING: "str",
        INTEGER: "nb",
        BOOLEAN: "y/n",

        PROPRIETE: "Propriété",
        VALEUR: "Valeur"
    };

	$scope.dataType = $rootScope.type.PROPRIETE;
	$scope.currentType = "";
	$scope.currentProp = "";

	var isRootArray = true;
	$scope.jsonStart = true;

    $scope.setTypeAndData = function( data, type )
    {
    	var tmp = "";

        if( $scope.jsonStart ) // 1er appel à la fonction : initialisation de l'objet JSON
        {
    		$scope.jsonStart = false;
        	isRootArray = type;

	        if(isRootArray)
    			$rootScope.json = [];
	        else
    			$rootScope.json = {};
        }
        else if(data) // Si les données sont renseignées
        {
        	// SAISIE PROPRIETE
        	if( type ) // Si type est renseigné, la saisie est une propriété
        	{
        		// Mise à jour du type de la valeur à venir : (array, boolean...)
        		$scope.currentType = type;
        		$scope.currentProp = $filter("slugify")(data, data);

        		tmp = '{"'+$scope.currentProp+'":""}';
        		var toJson = JSON.parse(tmp);

				if(isRootArray) $rootScope.json.push(toJson);
				else
				{
					if(Object.keys($rootScope.json).length === 0)
						$rootScope.json = toJson;
					else
						$rootScope.json[$scope.currentProp] = "";
				}
				// else
				// 	if($rootScope.json == {}) $rootScope.json = toJson;
				// 	else $rootScope.json += toJson;
    			$scope.dataType = $rootScope.type.VALEUR; // Prochaine donnée => valeur
        	}

        	// SAISIE VALEUR
        	else
        	{
	        	switch( $scope.currentType )
	        	{
	        		case $rootScope.type.ARRAY:
	        			break;
	        		case $rootScope.type.OBJECT:
	        			break;
	        		case $rootScope.type.STRING:
	        			if( isRootArray ) // Si le JSON est un tableau d'objet
	        			{
	        				$rootScope.json.forEach(
	        					function( o )
	        					{
        							for(var p in o )
        							{
        								if( p == $scope.currentProp )
        									o[p] = data;
        							}
	        					}
	        				);
	        			}
	        			else
	        			{
							for(var p in $rootScope.json )
							{
								if( p == $scope.currentProp )
									$rootScope.json[p] = data;
							}
	        			}
	        			break;
	        		case $rootScope.type.INTEGER:
	        			break;
	        		case $rootScope.type.BOOLEAN:
	        			break;
	        	}

	        	// Si l'utilisateur a fini de renseigner la valeur,
	        	// il faut repasser en mode "saisir une nouvelle propriété"
	        	$scope.dataType = $rootScope.type.PROPRIETE;
        	}

    		dwapsLog.show(JSON.stringify($rootScope.json));
    		// dwapsLog.show($rootScope.json);
        }
    };
}<commit_msg>Gestion valeur integer ok<commit_after>/**
* Auteur :  DWAPS Formation - Michael Cornillon
* Mail :    contact@dwaps.fr
* Tel :     0651279211
* Site :    http://dwaps.fr
* Date :    12/03/2017
**/

angular
	.module('controllers', [])
	.controller('homeCtrl', homeCtrl)
;

function homeCtrl($scope, $rootScope, $filter, dwapsLog)
{
    $rootScope.type = {
        ARRAY: "tab",
        OBJECT: "obj",
        STRING: "str",
        INTEGER: "nb",
        BOOLEAN: "y/n",

        PROPRIETE: "Propriété",
        VALEUR: "Valeur"
    };

	$scope.dataType = $rootScope.type.PROPRIETE;
	$scope.currentType = "";
	$scope.currentProp = "";

	var isRootArray = true;
	$scope.jsonStart = true;

    $scope.setTypeAndData = function( data, type )
    {
    	var tmp = "";

        if( $scope.jsonStart ) // 1er appel à la fonction : initialisation de l'objet JSON
        {
    		$scope.jsonStart = false;
        	isRootArray = type;

	        if(isRootArray)
    			$rootScope.json = [];
	        else
    			$rootScope.json = {};
        }
        else if(data) // Si les données sont renseignées
        {
        	// SAISIE PROPRIETE
        	if( type ) // Si type est renseigné, la saisie est une propriété
        	{
        		// Mise à jour du type de la valeur à venir : (array, boolean...)
        		$scope.currentType = type;
        		$scope.currentProp = $filter("slugify")(data, data);

        		tmp = '{"'+$scope.currentProp+'":""}';
        		var toJson = JSON.parse(tmp);

				if(isRootArray) $rootScope.json.push(toJson);
				else
				{
					if(Object.keys($rootScope.json).length === 0)
						$rootScope.json = toJson;
					else
						$rootScope.json[$scope.currentProp] = "";
				}
				// else
				// 	if($rootScope.json == {}) $rootScope.json = toJson;
				// 	else $rootScope.json += toJson;
    			$scope.dataType = $rootScope.type.VALEUR; // Prochaine donnée => valeur
        	}

        	// SAISIE VALEUR
        	else
        	{
	        	switch( $scope.currentType )
	        	{
	        		case $rootScope.type.ARRAY:
	        			break;
	        		case $rootScope.type.OBJECT:
	        			break;
	        		case $rootScope.type.STRING:
	        			if( isRootArray ) // Si le JSON est un tableau d'objet
	        			{
	        				$rootScope.json.forEach(
	        					function( o )
	        					{
        							for(var p in o )
        							{
        								if( p == $scope.currentProp )
        									o[p] = data;
        							}
	        					}
	        				);
	        			}
	        			else
	        			{
							for(var p in $rootScope.json )
							{
								if( p == $scope.currentProp )
									$rootScope.json[p] = data;
							}
	        			}
	        			break;
	        		case $rootScope.type.INTEGER:
	        			if( isRootArray ) // Si le JSON est un tableau d'objet
	        			{
	        				$rootScope.json.forEach(
	        					function( o )
	        					{
        							for(var p in o )
        							{
        								if( p == $scope.currentProp )
        									o[p] = parseInt(data);
        							}
	        					}
	        				);
	        			}
	        			else
	        			{
							for(var p in $rootScope.json )
							{
								if( p == $scope.currentProp )
									$rootScope.json[p] = parseInt(data);
							}
	        			}
	        			break;
	        		case $rootScope.type.BOOLEAN:
	        			break;
	        	}

	        	// Si l'utilisateur a fini de renseigner la valeur,
	        	// il faut repasser en mode "saisir une nouvelle propriété"
	        	$scope.dataType = $rootScope.type.PROPRIETE;
        	}

    		dwapsLog.show(JSON.stringify($rootScope.json));
    		// dwapsLog.show($rootScope.json);
        }
    };
}<|endoftext|>


<commit_before>(function(){
    'use strict';
    var app = require('express').createServer();
    var io = require('socket.io').listen(app);

    //Setup logging to file and couchdb
    var winston = require('winston');
    var winstonCouch = require('winston-couchdb').Couchdb;

    winston.add(winston.transports.File, { filename: 'wifi-device.log' });
    winston.add(winstonCouch, {
        host: 'localhost',
        port: 5984,
        db: 'presence'
    });

    app.listen(3030);

    var DeviceMonitor = require('./lib/monitor.js');

    var monitor = new DeviceMonitor('http://192.168.1.254/xslt?PAGE=C_2_0');
    monitor.start();

    monitor.on(DeviceMonitor.START, function onDeviceStart(devices){
        winston.info('device monitoring starting', devices);
        io.sockets.emit('start', devices);
    });

    monitor.on(DeviceMonitor.END, function onMonitroEnd(){
        winston.info('device monitoring ending');
    });

    monitor.on(DeviceMonitor.ADD, function onDeviceAdd(device){
        winston.info('add', device);
        io.sockets.emit('add', device);
    });

    monitor.on(DeviceMonitor.REMOVE, function onDeviceRemove(device){
        winston.info('remove', device);
        io.sockets.emit('remove', device);
    });

    monitor.on(DeviceMonitor.ERROR, function onMonitorError(error){
        winston.error(error);
    });

    app.get('/devices', function(req, res){
        res.send(monitor.connectedDevices);
    });
})();
<commit_msg>updated express and socket.io implementation.<commit_after>(function(){
    'use strict';
    var express = require('express');
    var app = express();
    var httpSer= app.listen(3030);

    var io = require('socket.io').listen(httpSer);

    //Setup logging to file and couchdb
    var winston = require('winston');
    var winstonCouch = require('winston-couchdb').Couchdb;

    winston.add(winston.transports.File, { filename: 'wifi-device.log' });
    winston.add(winstonCouch, {
        host: 'localhost',
        port: 5984,
        db: 'presence'
    });

    var DeviceMonitor = require('./lib/monitor.js');

    var monitor = new DeviceMonitor('http://192.168.1.254/xslt?PAGE=C_2_0');
    monitor.start();

    monitor.on(DeviceMonitor.START, function onDeviceStart(devices){
        winston.info('device monitoring starting', devices);
        io.sockets.emit('start', devices);
    });

    monitor.on(DeviceMonitor.END, function onMonitroEnd(){
        winston.info('device monitoring ending');
    });

    monitor.on(DeviceMonitor.ADD, function onDeviceAdd(device){
        winston.info('add', device);
        io.sockets.emit('add', device);
    });

    monitor.on(DeviceMonitor.REMOVE, function onDeviceRemove(device){
        winston.info('remove', device);
        io.sockets.emit('remove', device);
    });

    monitor.on(DeviceMonitor.ERROR, function onMonitorError(error){
        winston.error(error);
    });

    app.get('/devices', function(req, res){
        res.send(monitor.connectedDevices);
    });
})();
<|endoftext|>


<commit_before>(function(window) {
	"use strict";

	var Fn        = window.Fn;
	var Sparky    = window.Sparky;
	var isDefined = Fn.isDefined;

	function groupBy(name, array) {
		return array.reduce(function(groups, object) {
			var group = groups[groups.length - 1];

			if (!group) {
				groups.push([object]);
				return groups;
			}

			var prev = group[group.length - 1];

			if (object[name] === prev[name]) {
				group.push(object);
			}
			else {
				groups.push([object]);
			}

			return groups;
		}, []);
	}

	function collectionToPath(collection, x, y, textToX) {
		var state = 0;

		collection.sort(Fn.by(x));

		var groups = groupBy(x, collection);
console.log('G', groups);
		return groups.reduce(function(string, group) {
			var agregate = group.reduce(function(agregate, object) {
				agregate[y] = (agregate[y] || 0) + object[y];
				agregate[x] = object[x];
				return agregate;
			}, {});

console.log(agregate, x, y);

			//if (!isDefined(object[x]) || !isDefined(object[y])) {
			//	state = 0;
			//	return string;
			//}

			var xpos = typeof agregate[x] === 'string' ?
				textToX(agregate[x]) :
				agregate[x] ;

			var ypos = agregate[y];

			return string + ((state++ === 0) ? 'M' : 'L') + xpos + ',' + ypos;
		}, '');
	}

	function same(a, b) {
		return a === b && a ;
	}

	function lower(a, b) {
		return a.localeCompare(b) > 0 ? b : a ;
	}

	function higher(a, b) {
		return a.localeCompare(b) > 0 ? a : b ;
	}

	function unique(array, value) {
		if (array.indexOf(value) === -1) {
			array.push(value);
		}

		return array;
	}

	var fns = {
		'chart-path': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var collection;
console.log(data);
			function update() {
				node.setAttribute('d', collectionToPath(collection, x, y, function textToX(text) {
					var index = data['x-labels'].map(Fn.get('text')).indexOf(text);
					var label = data['x-labels'][index];
					return label.x;
				}));
			}

			var throttle = Fn.Throttle(update);

			function observe(collection, object) {
				Sparky.observe(object, x, throttle);
				Sparky.observe(object, y, throttle);
			}

			function unobserve(collection, object) {
				Sparky.unobserve(object, x, throttle);
				Sparky.unobserve(object, y, throttle);
			}

			this.on('scope', function(sparky, scope) {
				if (!scope) { return; }

				if (collection) {
					collection
					.off('add', observe)
					.off('remove', unobserve);
				}

				collection = scope;

				collection
				.on('add', observe)
				.on('remove', unobserve)
				.forEach(function(object, i, collection) {
					observe(collection, object);
				});

				throttle();
			});
		},

		'chart-bar': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var point;

			// We have to do it in a fn, because scope problems...
			// Todo: sort out scope problems

			function update() {
				var index = data['x-labels'].map(Fn.get('text')).indexOf(point[x]);
				var label = data['x-labels'][index];
				node.setAttribute('x', label.x);
			}

			var throttle = Fn.Throttle(update);

			this.on('scope', function(sparky, scope) {
				if (!scope) { return; }
				point = scope;
				throttle();
			});
		},

		'x-axis': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var axis = {
				labels: Collection(),
				ticks:  Collection(),
				lines:  Collection()
			};

			function update() {
				if (data['x-labels']) {
					axis.labels = data['x-labels'];
					return;
				}

				axis.labels.length = 0;

				var min    = data['x-min'];
				var range  = data['x-range'];
				var step   = data['x-label-step'];
				var max    = min + range;
				var x      = Math.ceil(min / step) * step;

				while (x <= max) {
					axis.labels.push({ x: x,  text: '' + x });
					x += step;
				}
			}

			Sparky.observe(data, 'x-range', update);
			Sparky.observe(data, 'x-min',   update);
			update();
			return axis;
		},

		'y-axis': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var axis = {
				labels: Collection(),
				ticks: Collection(),
				lines: Collection()
			};

			function update() {
				var labels = axis.labels;
				var min    = data['y-min'];
				var range  = data['y-range'];
				var step   = data['y-label-step'];
				var max    = min + range;
				var y      = Math.ceil(min / step) * step;

				labels.length = 0;

				while (y <= max) {
					labels.push({ y: y,  text: '' + y });
					y += step;
				}

				var ticks  = axis.ticks;
				var step   = data['y-tick-step'];
				var y      = Math.ceil(min / step) * step;

				ticks.length = 0;

				while (y <= max) {
					ticks.push({ y: y });
					y += step;
				}

				var lines  = axis.lines;
				var step   = data['y-line-step'];
				var y      = Math.ceil(min / step) * step;

				lines.length = 0;

				while (y <= max) {
					lines.push({ y: y });
					y += step;
				}
			}

			Sparky.observe(data, 'y-range', update);
			Sparky.observe(data, 'y-min',   update);
			update();
			return axis;
		}
	};

	Sparky.fn['series-chart'] = function(node) {
		var x = node.getAttribute('data-chart-x') || 'x';
		var y = node.getAttribute('data-chart-y') || 'y';
		var data = this.data = {
			'x': x,
			'x-min': 0,
			'x-range': 100,
			'x-label-step': 10,
			'x-line-step': 10,
			'x-tick-step': 10,
			'y': y,
			'y-min': 0,
			'y-range': 50,
			'y-label-step': 10,
			'y-line-step': 10,
			'y-tick-step': 10,
			'y-headroom': 10
		};

		Object.assign(this.fn, fns);

		var series = Sparky.data.stats;
		data.series = series;

window.s = series;
window.d = data;

		//data['series-2'] = Sparky.data.series2;

		// Propogate changes to min and range to child datas

		function updateXMax() {
			var xMax = data['x-min'] + data['x-range'];
			data['x-max'] = xMax;
		}

		function updateYMax() {
			var yMax = data['y-min'] + data['y-range'];
			data['y-max'] = yMax;
		}

		Sparky.observe(data, 'x-range', updateXMax);
		Sparky.observe(data, 'y-range', updateYMax);
		Sparky.observe(data, 'x-min',   updateXMax);
		//Sparky.observe(data, 'y-min',   updateYMax);

		var scaleX = Fn.multiply(8);

		function update() {
			var xType = series.map(Fn.compose(Fn.toStringType, Fn.get(x))).reduce(same) || 'string';

			if (xType === 'number') {
				data['x-min']   = series.map(Fn.get(x)).reduce(Fn.min, Infinity);
				data['x-range'] = series.map(Fn.get(x)).reduce(Fn.max, 0) - data['x-min'];
			}
			else if (xType === 'date') {
				data['x-labels'] = Collection(series.map(Fn.get(x)).reduce(unique, []).sort(Fn.byGreater).map(function createLabel(text, i) {
					return { x: scaleX(i), text: text } ;
				}));
				data['x-min'] = scaleX(0);
				data['x-range'] = scaleX(data['x-labels'].length);
			}
			else {
				data['x-labels'] = Collection(series.map(Fn.get(x)).reduce(unique, []).sort(Fn.byAlphabet).map(function createLabel(text, i) {
					return { x: scaleX(i), text: text } ;
				}));
				data['x-min'] = scaleX(0);
				data['x-range'] = scaleX(data['x-labels'].length);
			}

			//data['y-min'] = series.map(Fn.get(y)).reduce(Fn.min, Infinity);
			data['y-range'] = series.map(Fn.get(y)).reduce(Fn.max, 0) - data['y-min'] + data['y-headroom'];
		}

		function observe(collection, object) {
			Sparky.observe(object, x, update);
			Sparky.observe(object, y, update);
		}

		function unobserve(collection, object) {
			Sparky.unobserve(object, x, update);
			Sparky.unobserve(object, y, update);
		}

		series
		.on('add', observe)
		.on('remove', unobserve)
		.forEach(function(object, i, collection) {
			observe(collection, object);
		});

		this.on('destroy', function() {
			Sparky.unobserve(data, 'x-range', updateXMax);
			Sparky.unobserve(data, 'y-range', updateYMax);
			Sparky.unobserve(data, 'x-min',   updateXMax);
			Sparky.unobserve(data, 'y-min',   updateYMax);

			Sparky.unobserve(data, 'x-range', updateXAxis);
			Sparky.unobserve(data, 'y-range', updateYAxis);
			Sparky.unobserve(data, 'x-min',   updateXAxis);
			Sparky.unobserve(data, 'y-min',   updateYAxis);

			series
			.forEach(function(object, i, collection) {
				unobserve(collection, object);
			});
		});

		// Initilise the data
		update();

		return data;
	};
})(this);
<commit_msg>Damn graphs<commit_after>(function(window) {
	"use strict";

	var Fn        = window.Fn;
	var Sparky    = window.Sparky;
	var isDefined = Fn.isDefined;

	function groupBy(name, array) {
		return array.reduce(function(groups, object) {
			var group = groups[groups.length - 1];

			if (!group) {
				groups.push([object]);
				return groups;
			}

			var prev = group[group.length - 1];

			if (object[name] === prev[name]) {
				group.push(object);
			}
			else {
				groups.push([object]);
			}

			return groups;
		}, []);
	}

	function collectionToPath(collection, x, y, textToX) {
		var state = 0;

		collection.sort(Fn.by(x));

		var groups = groupBy(x, collection);
console.log('G', groups);
		return groups.reduce(function(string, group) {
			var agregate = group.reduce(function(agregate, object) {
				agregate[y] = (agregate[y] || 0) + object[y];
				agregate[x] = object[x];
				return agregate;
			}, {});

console.log(agregate, x, y);

			//if (!isDefined(object[x]) || !isDefined(object[y])) {
			//	state = 0;
			//	return string;
			//}

			var xpos = typeof agregate[x] === 'string' ?
				textToX(agregate[x]) :
				agregate[x] ;

			var ypos = agregate[y];

			return string + ((state++ === 0) ? 'M' : 'L') + xpos + ',' + ypos;
		}, '');
	}

	function same(a, b) {
		return a === b && a ;
	}

	function lower(a, b) {
		return a.localeCompare(b) > 0 ? b : a ;
	}

	function higher(a, b) {
		return a.localeCompare(b) > 0 ? a : b ;
	}

	function unique(array, value) {
		if (array.indexOf(value) === -1) {
			array.push(value);
		}

		return array;
	}

	var fns = {
		'chart-path': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var collection;

			function update() {
				node.setAttribute('d', collectionToPath(collection, x, y, function textToX(text) {
					var index = data['x-labels'].map(Fn.get('text')).indexOf(text);
					var label = data['x-labels'][index];
					return label.x;
				}));
			}

			var throttle = Fn.Throttle(update);

			function observe(collection, object) {
				Sparky.observe(object, x, throttle);
				Sparky.observe(object, y, throttle);
			}

			function unobserve(collection, object) {
				Sparky.unobserve(object, x, throttle);
				Sparky.unobserve(object, y, throttle);
			}

			this.on('scope', function(sparky, scope) {
				if (!scope) { return; }

				if (collection) {
					collection
					.off('add', observe)
					.off('remove', unobserve);
				}

				collection = scope;

				collection
				.on('add', observe)
				.on('remove', unobserve)
				.forEach(function(object, i, collection) {
					observe(collection, object);
				});

				throttle();
			});
		},

		'chart-bar': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var point;

			// We have to do it in a fn, because scope problems...
			// Todo: sort out scope problems

			function update() {
				var index = data['x-labels'].map(Fn.get('text')).indexOf(point[x]);
				var label = data['x-labels'][index];
				node.setAttribute('x', label.x);
			}

			var throttle = Fn.Throttle(update);

			this.on('scope', function(sparky, scope) {
				if (!scope) { return; }
				point = scope;
				throttle();
			});
		},

		'x-axis': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var axis = {
				labels: Collection(),
				ticks:  Collection(),
				lines:  Collection()
			};

			function update() {
				if (data['x-labels']) {
					axis.labels = data['x-labels'];
					return;
				}

				axis.labels.length = 0;

				var min    = data['x-min'];
				var range  = data['x-range'];
				var step   = data['x-label-step'];
				var max    = min + range;
				var x      = Math.ceil(min / step) * step;

				while (x <= max) {
					axis.labels.push({ x: x,  text: '' + x });
					x += step;
				}
			}

			Sparky.observe(data, 'x-range', update);
			Sparky.observe(data, 'x-min',   update);
			update();
			return axis;
		},

		'y-axis': function(node) {
			var data = this.data;
			var x    = data.x || 'x';
			var y    = data.y || 'y';
			var axis = {
				labels: Collection(),
				ticks: Collection(),
				lines: Collection()
			};

			function update() {
				var labels = axis.labels;
				var min    = data['y-min'];
				var range  = data['y-range'];
				var step   = data['y-label-step'];
				var max    = min + range;
				var y      = Math.ceil(min / step) * step;

				labels.length = 0;

				while (y <= max) {
					labels.push({ y: y,  text: '' + y });
					y += step;
				}

				var ticks  = axis.ticks;
				var step   = data['y-tick-step'];
				var y      = Math.ceil(min / step) * step;

				ticks.length = 0;

				while (y <= max) {
					ticks.push({ y: y });
					y += step;
				}

				var lines  = axis.lines;
				var step   = data['y-line-step'];
				var y      = Math.ceil(min / step) * step;

				lines.length = 0;

				while (y <= max) {
					lines.push({ y: y });
					y += step;
				}
			}

			Sparky.observe(data, 'y-range', update);
			Sparky.observe(data, 'y-min',   update);
			update();
			return axis;
		}
	};

	Sparky.fn['series-chart'] = function(node) {
		var x = node.getAttribute('data-chart-x') || 'x';
		var y = node.getAttribute('data-chart-y') || 'y';
		var data = this.data = {
			'x': x,
			'x-min': 0,
			'x-range': 100,
			'x-label-step': 10,
			'x-line-step': 10,
			'x-tick-step': 10,
			'y': y,
			'y-min': 0,
			'y-range': 50,
			'y-label-step': 10,
			'y-line-step': 10,
			'y-tick-step': 10,
			'y-headroom': 10
		};

		Object.assign(this.fn, fns);

		var series;// = Sparky.data.stats;
		//data.series = series;

window.s = series;
window.d = data;

		//data['series-2'] = Sparky.data.series2;

		// Propogate changes to min and range to child datas

		function updateXMax() {
			var xMax = data['x-min'] + data['x-range'];
			data['x-max'] = xMax;
		}

		function updateYMax() {
			var yMax = data['y-min'] + data['y-range'];
			data['y-max'] = yMax;
		}

		Sparky.observe(data, 'x-range', updateXMax);
		Sparky.observe(data, 'y-range', updateYMax);
		Sparky.observe(data, 'x-min',   updateXMax);
		//Sparky.observe(data, 'y-min',   updateYMax);

		var scaleX = Fn.multiply(8);

		function update() {
			var xType = series.map(Fn.compose(Fn.toStringType, Fn.get(x))).reduce(same) || 'string';

			if (xType === 'number') {
				data['x-min']   = series.map(Fn.get(x)).reduce(Fn.min, Infinity);
				data['x-range'] = series.map(Fn.get(x)).reduce(Fn.max, 0) - data['x-min'];
			}
			else if (xType === 'date') {
				data['x-labels'] = Collection(series.map(Fn.get(x)).reduce(unique, []).sort(Fn.byGreater).map(function createLabel(text, i) {
					return { x: scaleX(i), text: text } ;
				}));
				data['x-min'] = scaleX(0);
				data['x-range'] = scaleX(data['x-labels'].length);
			}
			else {
				data['x-labels'] = Collection(series.map(Fn.get(x)).reduce(unique, []).sort(Fn.byAlphabet).map(function createLabel(text, i) {
					return { x: scaleX(i), text: text } ;
				}));
				data['x-min'] = scaleX(0);
				data['x-range'] = scaleX(data['x-labels'].length);
			}

			//data['y-min'] = series.map(Fn.get(y)).reduce(Fn.min, Infinity);
			data['y-range'] = series.map(Fn.get(y)).reduce(Fn.max, 0) - data['y-min'] + data['y-headroom'];
		}

		function observe(collection, object) {
			Sparky.observe(object, x, update);
			Sparky.observe(object, y, update);
		}

		function unobserve(collection, object) {
			Sparky.unobserve(object, x, update);
			Sparky.unobserve(object, y, update);
		}

		this
		.on('scope', function(sparky, scope) {
			series = scope;

			if (!series) { return; }
console.log('SERIES', series);
			series
			.on('add', observe)
			.on('remove', unobserve)
			.forEach(function(object, i, collection) {
				observe(collection, object);
			});

			data.series = series;
			update();
		})
		.on('destroy', function() {
			Sparky.unobserve(data, 'x-range', updateXMax);
			Sparky.unobserve(data, 'y-range', updateYMax);
			Sparky.unobserve(data, 'x-min',   updateXMax);
			Sparky.unobserve(data, 'y-min',   updateYMax);
			Sparky.unobserve(data, 'x-range', updateXAxis);
			Sparky.unobserve(data, 'y-range', updateYAxis);
			Sparky.unobserve(data, 'x-min',   updateXAxis);
			Sparky.unobserve(data, 'y-min',   updateYAxis);

			series
			.forEach(function(object, i, collection) {
				unobserve(collection, object);
			});
		});

		// Initilise the data
		//update();
	};
})(this);
<|endoftext|>


<commit_before>
import { XMLExporter, isString } from 'substance'
import converters from './_converters'

/**
 * A factory the creates an exporter instance that can be used to convert a full document to JATS
 * but also for converting single nodes.
 *
 * @param {DOMElement} jatsDom
 * @param {InternalArticleDocument} doc
 */
export default function createJatsExporter (jatsDom, doc) {
  // ATTENTION: in this case it is different to the importer
  // not the first matching converter is used, but the last one which is
  // registered for a specific nody type, i.e. a later converter overrides a previous one
  let exporter = new Internal2JATSExporter({
    converters,
    elementFactory: {
      createElement: jatsDom.createElement.bind(jatsDom)
    }
  })
  exporter.state.doc = doc
  return exporter
}

class Internal2JATSExporter extends XMLExporter {
  getNodeConverter (node) {
    let type = node.type
    if (node.isInstanceOf('reference')) {
      type = 'reference'
    }
    return this.converters.get(type)
  }

  // TODO: try to improve the core implementation to allow disabling of defaultBlockConverter
  convertNode (node) {
    if (isString(node)) {
      // Assuming this.state.doc has been set by convertDocument
      node = this.state.doc.get(node)
    } else {
      this.state.doc = node.getDocument()
    }
    var converter = this.getNodeConverter(node)
    // special treatment for annotations, i.e. if someone calls
    // `exporter.convertNode(anno)`
    if (node.isPropertyAnnotation() && (!converter || !converter.export)) {
      return this._convertPropertyAnnotation(node)
    }
    if (!converter) {
      throw new Error(`No converter found for node type '${node.type}'`)
    }
    var el
    if (converter.tagName) {
      el = this.$$(converter.tagName)
    } else {
      el = this.$$('div')
    }
    el.attr(this.config.idAttribute, node.id)
    if (converter.export) {
      el = converter.export(node, el, this) || el
    } else {
      throw new Error('Converter must define a function export(node, el, exporter)')
    }
    return el
  }
}
<commit_msg>Allow for simple exporters.<commit_after>
import { XMLExporter, isString } from 'substance'
import converters from './_converters'

/**
 * A factory the creates an exporter instance that can be used to convert a full document to JATS
 * but also for converting single nodes.
 *
 * @param {DOMElement} jatsDom
 * @param {InternalArticleDocument} doc
 */
export default function createJatsExporter (jatsDom, doc) {
  // ATTENTION: in this case it is different to the importer
  // not the first matching converter is used, but the last one which is
  // registered for a specific nody type, i.e. a later converter overrides a previous one
  let exporter = new Internal2JATSExporter({
    converters,
    elementFactory: {
      createElement: jatsDom.createElement.bind(jatsDom)
    }
  })
  exporter.state.doc = doc
  return exporter
}

class Internal2JATSExporter extends XMLExporter {
  getNodeConverter (node) {
    let type = node.type
    if (node.isInstanceOf('reference')) {
      type = 'reference'
    }
    return this.converters.get(type)
  }

  // TODO: try to improve the core implementation to allow disabling of defaultBlockConverter
  convertNode (node) {
    if (isString(node)) {
      // Assuming this.state.doc has been set by convertDocument
      node = this.state.doc.get(node)
    } else {
      this.state.doc = node.getDocument()
    }
    var converter = this.getNodeConverter(node)
    // special treatment for annotations, i.e. if someone calls
    // `exporter.convertNode(anno)`
    if (node.isPropertyAnnotation() && (!converter || !converter.export)) {
      return this._convertPropertyAnnotation(node)
    }
    if (!converter) {
      throw new Error(`No converter found for node type '${node.type}'`)
    }
    var el
    if (converter.tagName) {
      el = this.$$(converter.tagName)
    } else {
      el = this.$$('div')
    }
    el.attr(this.config.idAttribute, node.id)
    if (converter.export) {
      el = converter.export(node, el, this) || el
    }
    return el
  }
}
<|endoftext|>


<commit_before>/*!
 * ${copyright}
 */
sap.ui.define(["sap/base/strings/toHex"], function(toHex) {
	"use strict";

	/**
	 * RegExp and escape function for URL escaping
	 */
	var rURL = /[\x00-\x2c\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\uffff]/g,
		mURLLookup = {};

	var fnURL = function(sChar) {
		var sEncoded = mURLLookup[sChar];
		if (!sEncoded) {
			var iChar = sChar.charCodeAt(0);
			if (iChar < 128) {
				sEncoded = "%" + toHex(iChar, 2);
			} else if (iChar < 2048) {
				sEncoded = "%" + toHex((iChar >> 6) | 192, 2) +
					"%" + toHex((iChar & 63) | 128, 2);
			} else {
				sEncoded = "%" + toHex((iChar >> 12) | 224, 2) +
					"%" + toHex(((iChar >> 6) & 63) | 128, 2) +
					"%" + toHex((iChar & 63) | 128, 2);
			}
			mURLLookup[sChar] = sEncoded;
		}
		return sEncoded;
	};

	/*
	 * Encoding according to the Secure Programming Guide
	 * <SAPWIKI>/wiki/display/NWCUIAMSIM/XSS+Secure+Programming+Guide
	 */

	/**
	 * Encode the string for inclusion into a URL parameter.
	 *
	 * Unescaped characters: alphabetic, decimal digits, -_. (dash, underscore, point)
	 *
	 * @function
	 * @since 1.58
	 * @alias module:sap/base/security/encodeURL
	 * @param {string} sString The string to be escaped
	 * @returns {string} The encoded string
	 * @SecValidate {0|return|XSS} validates the given string for a URL context
	 * @public
	 */
	var fnEncodeURL = function(sString) {
		return sString.replace(rURL, fnURL);
	};
	return fnEncodeURL;
});<commit_msg>[INTERNAL] base/security/encodeURL: documentation example<commit_after>/*!
 * ${copyright}
 */
sap.ui.define(["sap/base/strings/toHex"], function(toHex) {
	"use strict";

	/**
	 * RegExp and escape function for URL escaping
	 */
	var rURL = /[\x00-\x2c\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\uffff]/g,
		mURLLookup = {};

	var fnURL = function(sChar) {
		var sEncoded = mURLLookup[sChar];
		if (!sEncoded) {
			var iChar = sChar.charCodeAt(0);
			if (iChar < 128) {
				sEncoded = "%" + toHex(iChar, 2);
			} else if (iChar < 2048) {
				sEncoded = "%" + toHex((iChar >> 6) | 192, 2) +
					"%" + toHex((iChar & 63) | 128, 2);
			} else {
				sEncoded = "%" + toHex((iChar >> 12) | 224, 2) +
					"%" + toHex(((iChar >> 6) & 63) | 128, 2) +
					"%" + toHex((iChar & 63) | 128, 2);
			}
			mURLLookup[sChar] = sEncoded;
		}
		return sEncoded;
	};

	/*
	 * Encoding according to the Secure Programming Guide
	 * <SAPWIKI>/wiki/display/NWCUIAMSIM/XSS+Secure+Programming+Guide
	 */

	/**
	 * Encode the string for inclusion into a URL parameter.
	 *
	 * Unescaped characters: alphabetic, decimal digits, -_. (dash, underscore, point)
	 *
	 * @example
	 * sap.ui.require(['sap/base/security/encodeURL'], function(encodeURL) {
	 *      var sEncoded = encodeURL('a/b?c=d&e');
	 *      console.log(sEncoded); // a%2fb%3fc%3dd%26e
	 * });
	 *
	 * @function
	 * @since 1.58
	 * @alias module:sap/base/security/encodeURL
	 * @param {string} sString The string to be escaped
	 * @returns {string} The encoded string
	 * @SecValidate {0|return|XSS} validates the given string for a URL context
	 * @public
	 */
	var fnEncodeURL = function(sString) {
		return sString.replace(rURL, fnURL);
	};
	return fnEncodeURL;
});<|endoftext|>