<commit_before>'use strict';

/**
 * @ngdoc function
 * @name wdiApp.controller:IndicatorChartCtrl
 * @description
 * # IndicatorChartCtrl
 * Controller of the wdiApp
 */
angular.module('wdiApp')
  .controller('IndicatorChartCtrl', function ($scope, $attrs, $http, CountryStore, SelectionStore) {
		var ENDPOINT = 'http://api.worldbank.org/countries/{countries}/indicators/{indicator}';

		/* Chart data
		**************************************/

		$scope.countries = SelectionStore.countries();
		$scope.series = [];
		$scope.data = [];
		$scope.labels = [];

		/* Render
		**************************************/

		var update = function () {
			if (_.isEmpty($scope.countries)) {
				$scope.series = $scope.data = $scope.labels = [];
				return;
			}

			var endpoint = ENDPOINT
				.replace('{countries}', _.pluck($scope.countries, 'attributes.key').join(';'))
				.replace('{indicator}', $scope.indicator.get('key'));

			$http.jsonp(endpoint, {
				params: {format: 'jsonp', per_page: 100, prefix: 'JSON_CALLBACK'}
			})
				.then(function (response) {
					var series = _(response.data[1])
						.filter('value')
						.filter(function (row) { return row.date % 5 === 0; })
						.sortBy('date')
						.groupBy('country.id')
						.value();

					$scope.series = _.map(series, function (country, key) {
						return CountryStore.getByIso2Code(key).get('name');
					});
					$scope.data = _.map(series, function (rows) {
						return _.map(_.pluck(rows, 'value'), Number);
					});
					$scope.labels = _.pluck(_.values(series)[0], 'date');
				})
				.catch(console.error.bind(console));
		};

		if (!_.isEmpty(SelectionStore.countries())) {
			update();
		}

		/* Store bindings
		**************************************/

		var tokens = [
			SelectionStore.addListener(function () {
				var aKeys = _.pluck($scope.countries, 'attributes.key'),
					bKeys = _.pluck(SelectionStore.countries(), 'attributes.key');
				if (!_.isEqual(aKeys, bKeys)) {
					$scope.countries = SelectionStore.countries();
					update();
				}
			})
		];

		$scope.$on('$destroy', function () {
			_.forEach(tokens, function (token) {
				token.remove();
			});
		});
  });
<commit_msg>Fix indicator chart clipping<commit_after>'use strict';

/**
 * @ngdoc function
 * @name wdiApp.controller:IndicatorChartCtrl
 * @description
 * # IndicatorChartCtrl
 * Controller of the wdiApp
 */
angular.module('wdiApp')
  .controller('IndicatorChartCtrl', function ($scope, $attrs, $http, CountryStore, SelectionStore) {
		var ENDPOINT = 'http://api.worldbank.org/countries/{countries}/indicators/{indicator}';

		/* Chart data
		**************************************/

		$scope.countries = SelectionStore.countries();
		$scope.series = [];
		$scope.data = [];
		$scope.labels = [];

		/* Render
		**************************************/

		var update = function () {
			if (_.isEmpty($scope.countries)) {
				$scope.series = $scope.data = $scope.labels = [];
				return;
			}

			var endpoint = ENDPOINT
				.replace('{countries}', _.pluck($scope.countries, 'attributes.key').join(';'))
				.replace('{indicator}', $scope.indicator.get('key'));

			$http.jsonp(endpoint, {
				params: {format: 'jsonp', per_page: 1000, prefix: 'JSON_CALLBACK'}
			})
				.then(function (response) {
					if (response.data[0].pages > 1) {
						console.error('API returned incomplete data.');
					}

					var series = _(response.data[1])
						.filter('value')
						.filter(function (row) { return row.date % 5 === 0; })
						.sortBy('date')
						.groupBy('country.id')
						.value();

					$scope.series = _.map(series, function (country, key) {
						return CountryStore.getByIso2Code(key).get('name');
					});
					$scope.data = _.map(series, function (rows) {
						return _.map(_.pluck(rows, 'value'), Number);
					});
					$scope.labels = _.pluck(_.values(series)[0], 'date');
				})
				.catch(console.error.bind(console));
		};

		if (!_.isEmpty(SelectionStore.countries())) {
			update();
		}

		/* Store bindings
		**************************************/

		var tokens = [
			SelectionStore.addListener(function () {
				var aKeys = _.pluck($scope.countries, 'attributes.key'),
					bKeys = _.pluck(SelectionStore.countries(), 'attributes.key');
				if (!_.isEqual(aKeys, bKeys)) {
					$scope.countries = SelectionStore.countries();
					update();
				}
			})
		];

		$scope.$on('$destroy', function () {
			_.forEach(tokens, function (token) {
				token.remove();
			});
		});
  });
<|endoftext|>


<commit_before>(function() {
  'use strict';

  function MinimapController($scope, ol, proj4, sitesservice) {
    var me = this;
    this.sitesservice = sitesservice;

    proj4.defs('EPSG:32633', '+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs');
    proj4.defs('urn:ogc:def:crs:EPSG::32633', proj4.defs('EPSG:32633'));

    var olProjectionCode = 'EPSG:3857';
    var siteProjectionCode = 'EPSG:32633';
    var siteStyle =  new ol.style.Style({
      stroke: new ol.style.Stroke({
        color: 'yellow',
        width: 10
      }),
      fill: new ol.style.Fill({
        color: 'rgba(255, 255, 0, 0.1)'
      })
    });

    function centerOnVisibleSites() {
      map.getView().fitExtent(vectorSource.getExtent(), map.getSize());
    }

    var vectorSource = new ol.source.GeoJSON({
      projection: olProjectionCode
    });

    this.onSitesChanged = function(filtered) {
      var featuresArray = vectorSource.readFeatures(filtered);
      vectorSource.clear();
      vectorSource.addFeatures(featuresArray);
      centerOnVisibleSites();
    };

    $scope.$watch(function() {
      return me.siteservice.filtered;
    }, this.onSitesChanged);

    var vectorLayer = new ol.layer.Vector({
      source: vectorSource,
      style: siteStyle
    });

    var mapType = new ol.source.MapQuest({layer: 'osm'});

    var rasterLayer = new ol.layer.Tile({
      source: mapType
    });

    var map = new ol.Map({
      layers: [rasterLayer, vectorLayer],
      view: new ol.View({
        center: ol.proj.transform([12.5469185, 41.8286509], 'EPSG:4326', 'EPSG:3857'),
        zoom: 17
      })
    });
    this.map = map;
    map.on('rightclick', function(event) {
      event.preventDefault();

      return false;
    });

    // listen on map click
    map.on('click', function(event) {

      // EPSG:3857 (strange internal OpenLayers lat/lon units)
      var lat = event.coordinate[0];
      var lon = event.coordinate[1];
      // EPSG:4326 'normal' lat/long:
      var coord4326 = ol.proj.transform([lat, lon], 'EPSG:3857', 'EPSG:4326');
      var lat4326 = coord4326[0];
      var lon4326 = coord4326[1];
      // EPSG:32633 laz coordinate system:
      var coord32633 = proj4('EPSG:3857', siteProjectionCode, [lat, lon]);
      var lat32633 = coord32633[0];
      var lon32633 = coord32633[1];

      console.log('EPSG:3857 (openlayers)\nx: '+ lat + '\ny: ' + lon +
      '\nESPG:4326 (google)\nx: ' + lat4326 +
      '\ny: ' + lon4326 + '\nEPSG:32633 (drivemap)\nx: ' + lat32633 +
      '\ny: ' + lon32633);
    });
  }

  angular.module('pattyApp.minimap')
  .controller('MinimapController', MinimapController);
})();
<commit_msg>Add TODO for things deleted from original minimap<commit_after>(function() {
  'use strict';

  function MinimapController($scope, ol, proj4, sitesservice) {
    var me = this;
    this.sitesservice = sitesservice;

    proj4.defs('EPSG:32633', '+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs');
    proj4.defs('urn:ogc:def:crs:EPSG::32633', proj4.defs('EPSG:32633'));

    var olProjectionCode = 'EPSG:3857';
    var siteProjectionCode = 'EPSG:32633';
    var siteStyle =  new ol.style.Style({
      stroke: new ol.style.Stroke({
        color: 'yellow',
        width: 10
      }),
      fill: new ol.style.Fill({
        color: 'rgba(255, 255, 0, 0.1)'
      })
    });

    // TODO add function to ceter the map

    function centerOnVisibleSites() {
      map.getView().fitExtent(vectorSource.getExtent(), map.getSize());
    }

    var vectorSource = new ol.source.GeoJSON({
      projection: olProjectionCode
    });

    this.onSitesChanged = function(filtered) {
      var featuresArray = vectorSource.readFeatures(filtered);
      vectorSource.clear();
      vectorSource.addFeatures(featuresArray);
      centerOnVisibleSites();
    };

    $scope.$watch(function() {
      return me.siteservice.filtered;
    }, this.onSitesChanged);

    var vectorLayer = new ol.layer.Vector({
      source: vectorSource,
      style: siteStyle
    });

    var mapType = new ol.source.MapQuest({layer: 'osm'});

    var rasterLayer = new ol.layer.Tile({
      source: mapType
    });

    var map = new ol.Map({
      layers: [rasterLayer, vectorLayer],
      view: new ol.View({
        center: ol.proj.transform([12.5469185, 41.8286509], 'EPSG:4326', 'EPSG:3857'),
        zoom: 17
      })
    });
    this.map = map;
    map.on('rightclick', function(event) {
      event.preventDefault();

      return false;
    });

    // TODO set initial location for the map
    // TODO toggle map on/of

    // listen on map click
    map.on('click', function(event) {

      // EPSG:3857 (strange internal OpenLayers lat/lon units)
      var lat = event.coordinate[0];
      var lon = event.coordinate[1];
      // EPSG:4326 'normal' lat/long:
      var coord4326 = ol.proj.transform([lat, lon], 'EPSG:3857', 'EPSG:4326');
      var lat4326 = coord4326[0];
      var lon4326 = coord4326[1];
      // EPSG:32633 laz coordinate system:
      var coord32633 = proj4('EPSG:3857', siteProjectionCode, [lat, lon]);
      var lat32633 = coord32633[0];
      var lon32633 = coord32633[1];

      console.log('EPSG:3857 (openlayers)\nx: '+ lat + '\ny: ' + lon +
      '\nESPG:4326 (google)\nx: ' + lat4326 +
      '\ny: ' + lon4326 + '\nEPSG:32633 (drivemap)\nx: ' + lat32633 +
      '\ny: ' + lon32633);
    });
  }

  angular.module('pattyApp.minimap')
  .controller('MinimapController', MinimapController);
})();
<|endoftext|>


<commit_before>/* Copyright (c) 2012-2013 Coding Smackdown TV, http://codingsmackdown.tv

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */

'use strict';
// Declare module which depends on filters, and services
angular.module('notificationWidget', [])
    // set up the interceptor
    .config(['$httpProvider', function ($httpProvider) {
        $httpProvider.interceptors.push(function ($q, $injector, $location, $rootScope) {
            var notificationChannel, $http;

            function removeErrors() {
                var $inputs = $(':input');
                $inputs.each(function () {
                    $(this).removeClass("validationerror");
                });
            }

            return {
                request: function (config) {
                    $rootScope.blockUI = true;

                    // get requestNotificationChannel via $injector because of circular dependency problem
                    notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                    // send a notification requests are complete
                    notificationChannel.requestStarted();
                    // do something on success
                    return config || $q.when(config);
                },
                requestError: function (rejection) {
                    $rootScope.blockUI = false;

                    // get $http via $injector because of circular dependency problem
                    $http = $http || $injector.get('$http');
                    // don't send notification until all requests are complete
                    if ($http.pendingRequests.length < 1) {
                        // get requestNotificationChannel via $injector because of circular dependency problem
                        notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                        // send a notification requests are complete
                        notificationChannel.requestEnded();
                    }
                    return $q.reject(rejection);
                },
                response: function (response) {
                    $rootScope.blockUI = false;
                    // clear previous errors for a success request.
                    delete $rootScope.errorStatus;
                    delete $rootScope.errorDetails;

                    removeErrors();

                    //contains the responses successful and failed responses
                    $rootScope.successfulResponses = [];
                    $rootScope.failedResponses = [];

                    //check for batch API errors
                    if (response.config.url.indexOf('batches') > 0) {

                        for (var i = 0; i < response.data.length; i++) {
                            var currResponse = response.data[i];
                            if (currResponse.statusCode == 200) {
                                $rootScope.successfulResponses.push(currResponse);
                            } else {
                                $rootScope.failedResponses.push(currResponse);
                            }
                        }

                        //pass failed responses to error function
                        if ($rootScope.failedResponses.length > 0) {
                            var errResponse = response;
                            errResponse.data = $rootScope.failedResponses;
                            error(errResponse);

                            //set the value of response only to successful responses
                            response.data = $rootScope.successfulResponses;
                        }

                    }

                    // get $http via $injector because of circular dependency problem
                    $http = $http || $injector.get('$http');
                    // don't send notification until all requests are complete
                    if ($http.pendingRequests.length < 1) {
                        // get requestNotificationChannel via $injector because of circular dependency problem
                        notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                        // send a notification requests are complete
                        notificationChannel.requestEnded();
                    }
                    if (response.config && response.config.method == "GET") {
                        return response || $q.when(response);
                    } else {
                        if (response.data && response.data.commandId) {
                            //Maker checker is enabled or performing actions of maker checker
                            if (response.config.url.indexOf('makercheckers/') > 0) {
                                //return response for maker checker actions(approve or delete)
                                return response || $q.when(response);
                            } else {
                                //redirect if maker checker is enabled
                                $location.path('/viewMakerCheckerTask/' + response.data.commandId);
                            }
                        } else {
                            //when no maker checker enabled
                            return response || $q.when(response);
                        }
                    }
                },
                responseError: function (rejection) {
                    $rootScope.blockUI = false;
                    delete $rootScope.errorStatus;
                    delete $rootScope.errorDetails;
                    removeErrors();
                    // get $http via $injector because of circular dependency problem
                    //console.log(response.data);

                    $http = $http || $injector.get('$http');
                    // don't send notification until all requests are complete
                    if ($http.pendingRequests.length < 1) {
                        // get requestNotificationChannel via $injector because of circular dependency problem
                        notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                        // send a notification requests are complete
                        notificationChannel.requestEnded();
                    }

                    $rootScope.errorDetails = [];
                    //works with batch requests as well
                    //now our data array will hold the return response
                    //either it's a batch response or a normal response
                    var data = [];
                    if (rejection.config.url.indexOf('batches') > 0) {
                        data = rejection.data;
                    }
                    else {
                        //just push a single response into data
                        var res = {};
                        res.body = JSON.stringify(rejection.data);
                        data.push(res);
                    }

                    if (rejection.status === 0) {
                        $rootScope.errorStatus = 'No connection. Verify application is running.';
                    } else if (rejection.status == 401) {
                        $rootScope.errorStatus = 'Unauthorized';
                    } else if (rejection.status == 405) {
                        $rootScope.errorStatus = 'HTTP verb not supported [405]';
                    } else if (rejection.status == 500) {
                        $rootScope.errorStatus = 'Internal Server Error [500].';
                    } else {
                        for(var i = 0; i < data.length; i++) {
                            //console.log(data[i]);
                            var jsonErrors = JSON.parse(data[i].body);
                            var valErrors = jsonErrors.errors;
                            var errorArray = new Array();
                            var arrayIndex = 0;
                            if (valErrors) {
                                for (var j in valErrors) {
                                    var temp = valErrors[j];
                                    // add error class to input in dialog
                                    var fieldId = '#' + temp.parameterName;
                                    $(fieldId).addClass("validationerror");

                                    // for views using ui add the classes instead of ids
                                    var fieldClass = "."+temp.parameterName;
                                    $(fieldClass).eq(data[i].requestId).addClass("validationerror");

                                    var errorObj = new Object();
                                    errorObj.field = temp.parameterName;
                                    errorObj.code = temp.userMessageGlobalisationCode;
                                    errorObj.body = jsonErrors;
                                    errorObj.args = {params: []};
                                    for (var k in temp.args) {
                                        errorObj.args.params.push({value: temp.args[k].value});
                                    }
                                    errorArray[arrayIndex] = errorObj;
                                    arrayIndex++;
                                };
                            } else {
                                /***
                                 * Update user password api call won't return errors array,
                                 * if user enters a password which is used previously
                                 */
                                if (jsonErrors.userMessageGlobalisationCode) {
                                    var errorObj = new Object();
                                    errorObj.code = jsonErrors.userMessageGlobalisationCode;
                                    errorArray[arrayIndex] = errorObj;
                                    arrayIndex++;
                                }
                            }
                            $rootScope.errorDetails.push(errorArray);
                            console.log(errorArray);
                        }
                    }
                    return $q.reject(rejection);
                }
            }
        })
    }])
    // declare the notification pub/sub channel
    .factory('requestNotificationChannel', ['$rootScope', function ($rootScope) {
        // private notification messages
        var _START_REQUEST_ = '_START_REQUEST_';
        var _END_REQUEST_ = '_END_REQUEST_';
        // publish start request notification
        var requestStarted = function () {
            $rootScope.$broadcast(_START_REQUEST_);
        };
        // publish end request notification
        var requestEnded = function () {
            $rootScope.$broadcast(_END_REQUEST_);
        };
        // subscribe to start request notification
        var onRequestStarted = function ($scope, handler) {
            $scope.$on(_START_REQUEST_, function (event) {
                handler();
            });
        };
        // subscribe to end request notification
        var onRequestEnded = function ($scope, handler) {
            $scope.$on(_END_REQUEST_, function (event) {
                handler();
            });
        };
        return {
            requestStarted: requestStarted,
            requestEnded: requestEnded,
            onRequestStarted: onRequestStarted,
            onRequestEnded: onRequestEnded
        };
    }]);
<commit_msg>MIFOSX-1987<commit_after>/* Copyright (c) 2012-2013 Coding Smackdown TV, http://codingsmackdown.tv

 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */

'use strict';
// Declare module which depends on filters, and services
angular.module('notificationWidget', [])
    // set up the interceptor
    .config(['$httpProvider', function ($httpProvider) {
        $httpProvider.interceptors.push(function ($q, $injector, $location, $rootScope) {
            var notificationChannel, $http;

            function removeErrors() {
                var $inputs = $(':input');
                $inputs.each(function () {
                    $(this).removeClass("validationerror");
                });
            }

            function error(rejection){
                $rootScope.errorDetails = [];
                //works with batch requests as well
                //now our data array will hold the return response
                //either it's a batch response or a normal response
                var data = [];
                if (rejection.config.url.indexOf('batches') > 0) {
                    data = rejection.data;
                }
                else {
                    //just push a single response into data
                    data.push(rejection.data);
                }

                if (rejection.status === 0) {
                    $rootScope.errorStatus = 'No connection. Verify application is running.';
                } else if (rejection.status === 0) {
                    $rootScope.errorStatus = 'No connection. Verify application is running.';
                } else if (rejection.status == 401) {
                    $rootScope.errorStatus = 'Unauthorized';
                } else if (rejection.status == 405) {
                    $rootScope.errorStatus = 'HTTP verb not supported [405]';
                } else if (rejection.status == 500) {
                    $rootScope.errorStatus = 'Internal Server Error [500].';
                } else {
                    for(var i = 0; i < data.length; i++) {
                        var jsonErrors =data[i];
                        var valErrors = jsonErrors.errors;
                        var errorArray = new Array();
                        var arrayIndex = 0;
                        if (valErrors) {
                            for (var j in valErrors) {
                                var temp = valErrors[j];
                                // add error class to input in dialog
                                var fieldId = '#' + temp.parameterName;
                                $(fieldId).addClass("validationerror");

                                // for views using ui add the classes instead of ids
                                var fieldClass = "."+temp.parameterName;
                                $(fieldClass).eq(data[i].requestId).addClass("validationerror");

                                var errorObj = new Object();
                                errorObj.field = temp.parameterName;
                                errorObj.code = temp.userMessageGlobalisationCode;
                                errorObj.body = jsonErrors;
                                errorObj.args = {params: []};
                                for (var k in temp.args) {
                                    errorObj.args.params.push({value: temp.args[k].value});
                                }
                                errorArray[arrayIndex] = errorObj;
                                arrayIndex++;
                            };
                        } else {
                            /***
                             * Update user password api call won't rh
                             eturn errors array,
                             * if user enters a password which is used previously
                             */
                            if (jsonErrors.userMessageGlobalisationCode) {
                                var errorObj = new Object();
                                errorObj.code = jsonErrors.userMessageGlobalisationCode;
                                errorArray[arrayIndex] = errorObj;
                                arrayIndex++;
                            }
                        }
                        $rootScope.errorDetails.push(errorArray);
                    }
                }
                return $q.reject(rejection);
            }

            return {
                request: function (config) {
                    $rootScope.blockUI = true;

                    // get requestNotificationChannel via $injector because of circular dependency problem
                    notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                    // send a notification requests are complete
                    notificationChannel.requestStarted();
                    // do something on success
                    return config || $q.when(config);
                },
                requestError: function (rejection) {
                    $rootScope.blockUI = false;

                    // get $http via $injector because of circular dependency problem
                    $http = $http || $injector.get('$http');
                    // don't send notification until all requests are complete
                    if ($http.pendingRequests.length < 1) {
                        // get requestNotificationChannel via $injector because of circular dependency problem
                        notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                        // send a notification requests are complete
                        notificationChannel.requestEnded();
                    }
                    return $q.reject(rejection);
                },
                response: function (response) {
                    $rootScope.blockUI = false;
                    // clear previous errors for a success request.
                    delete $rootScope.errorStatus;
                    delete $rootScope.errorDetails;

                    removeErrors();

                    //contains the responses successful and failed responses
                    $rootScope.successfulResponses = [];
                    $rootScope.failedResponses = [];

                    //check for batch API errors
                    if (response.config.url.indexOf('batches') > 0) {

                        for (var i = 0; i < response.data.length; i++) {
                            var currResponse = response.data[i];
                            if (currResponse.statusCode == 200) {
                                $rootScope.successfulResponses.push(currResponse);
                            } else {
                                if($rootScope.failedResponses.length == 0){
                                    $rootScope.failedResponses.push(currResponse.body);
                                } else {
                                    for(var j in currResponse.body.errors){
                                        $rootScope.failedResponses[0].errors.push(currResponse.body.errors[j]);
                                    }
                                }
                            }
                        }

                        //pass failed responses to error function
                        if ($rootScope.failedResponses.length > 0) {
                            var errResponse = response;
                            errResponse.data = $rootScope.failedResponses;
                            error(errResponse);

                            //set the value of response only to successful responses
                            response.data = $rootScope.successfulResponses;
                        }

                    }

                    // get $http via $injector because of circular dependency problem
                    $http = $http || $injector.get('$http');
                    // don't send notification until all requests are complete
                    if ($http.pendingRequests.length < 1) {
                        // get requestNotificationChannel via $injector because of circular dependency problem
                        notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                        // send a notification requests are complete
                        notificationChannel.requestEnded();
                    }
                    if (response.config && response.config.method == "GET") {
                        return response || $q.when(response);
                    } else {
                        if (response.data && response.data.commandId) {
                            //Maker checker is enabled or performing actions of maker checker
                            if (response.config.url.indexOf('makercheckers/') > 0) {
                                //return response for maker checker actions(approve or delete)
                                return response || $q.when(response);
                            } else {
                                //redirect if maker checker is enabled
                                $location.path('/viewMakerCheckerTask/' + response.data.commandId);
                            }
                        } else {
                            //when no maker checker enabled
                            return response || $q.when(response);
                        }
                    }
                },
                responseError: function (rejection) {
                    $rootScope.blockUI = false;
                    delete $rootScope.errorStatus;
                    delete $rootScope.errorDetails;
                    removeErrors();
                    // get $http via $injector because of circular dependency problem
                    //console.log(response.data);

                    $http = $http || $injector.get('$http');
                    // don't send notification until all requests are complete
                    if ($http.pendingRequests.length < 1) {
                        // get requestNotificationChannel via $injector because of circular dependency problem
                        notificationChannel = notificationChannel || $injector.get('requestNotificationChannel');
                        // send a notification requests are complete
                        notificationChannel.requestEnded();
                    }
                    error(rejection);
                }
            }
        })
    }])
    // declare the notification pub/sub channel
    .factory('requestNotificationChannel', ['$rootScope', function ($rootScope) {
        // private notification messages
        var _START_REQUEST_ = '_START_REQUEST_';
        var _END_REQUEST_ = '_END_REQUEST_';
        // publish start request notification
        var requestStarted = function () {
            $rootScope.$broadcast(_START_REQUEST_);
        };
        // publish end request notification
        var requestEnded = function () {
            $rootScope.$broadcast(_END_REQUEST_);
        };
        // subscribe to start request notification
        var onRequestStarted = function ($scope, handler) {
            $scope.$on(_START_REQUEST_, function (event) {
                handler();
            });
        };
        // subscribe to end request notification
        var onRequestEnded = function ($scope, handler) {
            $scope.$on(_END_REQUEST_, function (event) {
                handler();
            });
        };
        return {
            requestStarted: requestStarted,
            requestEnded: requestEnded,
            onRequestStarted: onRequestStarted,
            onRequestEnded: onRequestEnded
        };
    }]);
<|endoftext|>


<commit_before>/* jshint -W003, -W117, -W004 */
(function () {
  'use strict';

  angular
    .module('newplayer.service')
    .service('AssessmentService', AssessmentService);

  /** @ngInject */
  function AssessmentService($log, $rootScope, ConfigService, AssessmentIOService) {
    var assessmentID, pages, questions,
      vm = this,
      isAssessing,
      minPassing = 0,
      io = AssessmentIOService,              // This is the I/O module for saving/restoring assessment stuff
      config = ConfigService.getConfig();

    if (config.hasOwnProperty('assessmentIO') && typeof config.assessmentIO === 'object' && config.assessmentIO.hasOwnProperty('updateFinal')) {
      $log.debug('[Assessment] using assessmentIO from config');
      setIO(config.assessmentIO);
    } else {
      $log.debug('[Assessment] using default assessmentIO');
    }

    // NOTE: this function is run below to initialize this service

    /**
     * Initializes the assessment service back to its 'blank' state.
     */
    function reset() {
      assessmentID = false;
      isAssessing = false;
      minPassing = -1;

      questions = {
        required: 0, total: 0, inventory: {},
        answered: {requiredCorrect: 0, inventory: {}}
      };

      pages = {
        required: 0, total: 0, inventory: {},
        viewed: {required: 0, inventory: {}}
      };
    }

  // NOTE: reset when the IIFE executes after the script is loaded.
    reset();

    /**
     * Begins an assessment session for a given ID and optionally a minimum passing score
     *
     * @param id The unique string for this assessment to identify it to the backend
     * @param newMinPassing A fractional number from 0 to 1 (e.g. 0.75 for 75%)
     */
    function beginFor(id, newMinPassing) {
      //$log.debug('Beginning assessments for ', id, newMinPassing);

      reset();
      assessmentID = id;
      setMinPassing(newMinPassing);

      isAssessing = true;
    }

    /**
     * Mark assessment as complete, whatever that will mean to the end system
     */
    function finalize() {
      if (!isAssessing) {
        //$log.debug('Assessment:finalize | assessment is disabled, ignoring');
        return;
      }

      //$log.debug('NP assessment::finalize | Finalizing assessments for ', assessmentID);

      // TODO - should this wait for a promise?
      io.updateFinal(getAssessment());

      isAssessing = false;
    }

    function getAssessment() {
      return {
        assessmentID: assessmentID,
        isAssessing: isAssessing,
        isPassing: isPassing(),
        minPassing: minPassing,
        pages: pages,
        questions: questions,
        score: getScore()
      };
    }

    /**
     * This sets the mechanism for how the assessment service communicates data
     * to an external data store. See the example in the assessmentio.service.js
     *
     * @see app/scripts/service/assessmentio.service.js
     */
    function setIO(newAssessmentIO) {
      // at some point this may change to validating the plugin
      io = newAssessmentIO;
    }

    // ---------------------------| Scoring

    /**
     * Get the minimum passing score
     * @returns {number} fraction of 1 (e.g. 0.6 for 60%)
     */
    function getMinPassing() {
      return minPassing;
    }

    /**
     * Sets the minimum passing score for this assessment.
     *
     * @param newMinPassing {number} fraction of 1 (e.g. 0.6 for 60%)
     */
    function setMinPassing(newMinPassing) {
      //$log.info('Assessment:setMinPassing', minPassing);

      newMinPassing = parseFloat(newMinPassing);

      if (!isNaN(newMinPassing)) {

        if (newMinPassing > 1) {
          $log.warn('[Assessment::setMinPassing] minPassing should be a fraction of 1. It is unlikely users will pass this assessment.', newMinPassing);
        }

        minPassing = newMinPassing;

      } else if (minPassing === -1 && config.hasOwnProperty('minPassing')) {
        minPassing = config.minPassing;
      } else if( minPassing === -1 ) {
        $log.warn('[Assessment::setMinPassing] no minimum passing score provided to beginFor or in config; any score will pass.');
        minPassing = 0;
      }
    }

    /**
     * Get the user's current score according to page and answer counts
     *
     * @return score from 0..1. Returns 1 if there are no required questions or answers.
     */
    function getScore() {

      if (!isAssessing) {
        return 0;
      }

      /*
       * (# of req. pages viewed + # of correctly answered req. questions) /
       *      (total req. pages + total req. questions)
       */

      var totalRequired = pages.required + questions.required;

      // User scores 100% if there are no requirements...
      if (totalRequired === 0) {
        return 1;
      }

      return Math.min(( pages.viewed.required + questions.answered.requiredCorrect ) / totalRequired, 1);
    }

    /**
     * Determine if the user is passing based on the minPassing score
     *
     * @return bool
     */
    function isPassing() {

      if (!isAssessing) {
        return false;
      }

      if (minPassing === 0) {
        return true;
      }

      return getScore() >= minPassing;
    }

    // ---------------------------| Pages

    function setRequiredPages(newRequiredPages) {

      var requiredPagesInt = parseInt(newRequiredPages);

      if( isNaN(requiredPagesInt)) {
        $log.error('Assessment:setRequiredPages | pages must be a number');
        return;
      }

      pages.required = requiredPagesInt;
    }

    /**
     * Add a potential page to view and whether it is required for score
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param pageIsRequired bool Whether the page was required so it can help user's score.
     */
    function addPage(pageName, pageIsRequired) {

      $log.info('[Assessment::addPage] name, required?', pageName, pageIsRequired);

      // look in the inventory to see if this property already exists
      if (pages.inventory.hasOwnProperty(pageName)) {
        $log.warn('[Assessment::addPage] ignoring duplicate page ' + pageName);
      } else {
        pages.total++;
        pages.inventory[pageName] = pageIsRequired;
        pages.viewed.inventory[pageName] = false;

        // NOTE: commented for now, we're for now declaring the number of required pages directly
        //if (pageIsRequired) {
        //  pages.required++;
        //}
      }
    }

    /**
     * Record that a page was viewed
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     */
    function pageViewed(pageId) {
      //$log.info('[Assessment::pageViewed]  ', pageId);

      if (pages.viewed.inventory[pageId] === false) {
        pages.viewed.inventory[pageId] = new Date();

        if (pages.inventory[pageId] === true) {
          pages.viewed.required++;

          if (isAssessing) {
            io.updatePage(pageId, getAssessment());
          }
        }
      } else {
        $log.warning('Assessment:pageViewed | page already viewed, ', pageId);
      }
    }

    /**
     * Gets all pageview data
     *
     * @return obj of pageview stats
     */
    function getPageStats() {
      return pages;
    }

    /**
     * Gets the count of number of unique pageviews
     * @returns {pages.viewed.total|*}
     */
    function getPageviewsCount() {
      return pages.viewed.total;
    }

    // ---------------------------| Q+A

    function setRequiredQuestions(newRequiredQuestions) {

      var requiredQuestionsInt = parseInt(newRequiredQuestions);

      if( isNaN(requiredQuestionsInt)) {
        $log.error('[Assessment::setRequiredQuestions] questions must be a number');
        return;
      }

      questions.required = requiredQuestionsInt;
      dumpState();
    }

    /**
     * Record that a question was correctly answered and whether it was required
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param pageIsRequired bool Whether the page was required so it can help user's score.
     */
    function addQuestion(questionName, questionIsRequired) {

      $log.info('[Assessment::addQuestion] name, required?', questionName, questionIsRequired);

      // look in the inventory to see if this property already exists
      if (questions.inventory.hasOwnProperty(questionName)) {
        $log.warn('[Assessment::addQuestion] ignoring duplicate page ' + questionName);
      } else {
        questions.total++;
        questions.inventory[questionName] = questionIsRequired;
        questions.answered.inventory[questionName] = {
          isCorrect: null,
          isRequired: questionIsRequired,
          answered: false
        };

        //NOTE: We are setting question required count through setRequiredQuestions()
        //if (questionIsRequired) {
        //  questions.required++;
        //}
      }
    }

    /**
     * Record that a question was correctly answered and whether it was required
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param isCorrect bool Whether the answer provided is correct
     */
    function questionAnswered(questionId, isCorrect) {

      $log.info('[Assessment::questionAnswered] ', questionId, isCorrect);

      if (questions.answered.inventory[questionId].answered === false) {
        questions.answered.inventory[questionId].answered = new Date();
        questions.answered.inventory[questionId].isCorrect = !!isCorrect;

        if (isCorrect && questions.answered.inventory[questionId].isRequired) {
          questions.answered.requiredCorrect++;
        }

        if (isAssessing) {
          io.updateQuestion(questionId, getAssessment());
        }

      } else {
        $log.warning('[Assessment::questionAnswered] question already answered, ', questionId);
      }
    }

    /**
     * Gets all questions stats
     *
     * @return obj of questions stats
     */
    function getQuestionStats() {
      return questions;
    }

    /**
     * DEBUG ONLY
     */
    function dumpState() {
      $log.info('[Assessment:dumpState] ', getAssessment());
    }

    var service = {
      beginFor: beginFor,
      finalize: finalize,
      getAssessment: getAssessment,
      reset: reset,
      setIO: setIO,

      //--- Scoring
      getMinPassing: getMinPassing,
      getScore: getScore,
      isPassing: isPassing,
      setMinPassing: setMinPassing,

      //--- Pages
      addPage: addPage,
      getPageviewsCount: getPageviewsCount,
      getPageStats: getPageStats,
      pageViewed: pageViewed,
      setRequiredPages: setRequiredPages,

      //--- Questions
      addQuestion: addQuestion,
      getQuestionStats: getQuestionStats,
      questionAnswered: questionAnswered,
      setRequiredQuestions: setRequiredQuestions,

      // DEBUG
      dumpState: dumpState
    };

    $log.info('[Assessment] service init');

    return service;
  }
})();
<commit_msg>fix(assessments): register unregistered answers<commit_after>/* jshint -W003, -W117, -W004 */
(function () {
  'use strict';

  angular
    .module('newplayer.service')
    .service('AssessmentService', AssessmentService);

  /** @ngInject */
  function AssessmentService($log, $rootScope, ConfigService, AssessmentIOService) {
    var assessmentID, pages, questions,
      vm = this,
      isAssessing,
      minPassing = 0,
      io = AssessmentIOService,              // This is the I/O module for saving/restoring assessment stuff
      config = ConfigService.getConfig();

    if (config.hasOwnProperty('assessmentIO') && typeof config.assessmentIO === 'object' && config.assessmentIO.hasOwnProperty('updateFinal')) {
      $log.debug('[Assessment] using assessmentIO from config');
      setIO(config.assessmentIO);
    } else {
      $log.debug('[Assessment] using default assessmentIO');
    }

    // NOTE: this function is run below to initialize this service

    /**
     * Initializes the assessment service back to its 'blank' state.
     */
    function reset() {
      assessmentID = false;
      isAssessing = false;
      minPassing = -1;

      questions = {
        required: 0, total: 0, inventory: {},
        answered: {requiredCorrect: 0, inventory: {}}
      };

      pages = {
        required: 0, total: 0, inventory: {},
        viewed: {required: 0, inventory: {}}
      };
    }

  // NOTE: reset when the IIFE executes after the script is loaded.
    reset();

    /**
     * Begins an assessment session for a given ID and optionally a minimum passing score
     *
     * @param id The unique string for this assessment to identify it to the backend
     * @param newMinPassing A fractional number from 0 to 1 (e.g. 0.75 for 75%)
     */
    function beginFor(id, newMinPassing) {
      //$log.debug('Beginning assessments for ', id, newMinPassing);

      reset();
      assessmentID = id;
      setMinPassing(newMinPassing);

      isAssessing = true;
    }

    /**
     * Mark assessment as complete, whatever that will mean to the end system
     */
    function finalize() {
      if (!isAssessing) {
        //$log.debug('Assessment:finalize | assessment is disabled, ignoring');
        return;
      }

      //$log.debug('NP assessment::finalize | Finalizing assessments for ', assessmentID);

      // TODO - should this wait for a promise?
      io.updateFinal(getAssessment());

      isAssessing = false;
    }

    function getAssessment() {
      return {
        assessmentID: assessmentID,
        isAssessing: isAssessing,
        isPassing: isPassing(),
        minPassing: minPassing,
        pages: pages,
        questions: questions,
        score: getScore()
      };
    }

    /**
     * This sets the mechanism for how the assessment service communicates data
     * to an external data store. See the example in the assessmentio.service.js
     *
     * @see app/scripts/service/assessmentio.service.js
     */
    function setIO(newAssessmentIO) {
      // at some point this may change to validating the plugin
      io = newAssessmentIO;
    }

    // ---------------------------| Scoring

    /**
     * Get the minimum passing score
     * @returns {number} fraction of 1 (e.g. 0.6 for 60%)
     */
    function getMinPassing() {
      return minPassing;
    }

    /**
     * Sets the minimum passing score for this assessment.
     *
     * @param newMinPassing {number} fraction of 1 (e.g. 0.6 for 60%)
     */
    function setMinPassing(newMinPassing) {
      //$log.info('Assessment:setMinPassing', minPassing);

      newMinPassing = parseFloat(newMinPassing);

      if (!isNaN(newMinPassing)) {

        if (newMinPassing > 1) {
          $log.warn('[Assessment::setMinPassing] minPassing should be a fraction of 1. It is unlikely users will pass this assessment.', newMinPassing);
        }

        minPassing = newMinPassing;

      } else if (minPassing === -1 && config.hasOwnProperty('minPassing')) {
        minPassing = config.minPassing;
      } else if( minPassing === -1 ) {
        $log.warn('[Assessment::setMinPassing] no minimum passing score provided to beginFor or in config; any score will pass.');
        minPassing = 0;
      }
    }

    /**
     * Get the user's current score according to page and answer counts
     *
     * @return score from 0..1. Returns 1 if there are no required questions or answers.
     */
    function getScore() {

      if (!isAssessing) {
        return 0;
      }

      /*
       * (# of req. pages viewed + # of correctly answered req. questions) /
       *      (total req. pages + total req. questions)
       */

      var totalRequired = pages.required + questions.required;

      // User scores 100% if there are no requirements...
      if (totalRequired === 0) {
        return 1;
      }

      return Math.min(( pages.viewed.required + questions.answered.requiredCorrect ) / totalRequired, 1);
    }

    /**
     * Determine if the user is passing based on the minPassing score
     *
     * @return bool
     */
    function isPassing() {

      if (!isAssessing) {
        return false;
      }

      if (minPassing === 0) {
        return true;
      }

      return getScore() >= minPassing;
    }

    // ---------------------------| Pages

    function setRequiredPages(newRequiredPages) {

      var requiredPagesInt = parseInt(newRequiredPages);

      if( isNaN(requiredPagesInt)) {
        $log.error('Assessment:setRequiredPages | pages must be a number');
        return;
      }

      pages.required = requiredPagesInt;
    }

    /**
     * Add a potential page to view and whether it is required for score
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param pageIsRequired bool Whether the page was required so it can help user's score.
     */
    function addPage(pageName, pageIsRequired) {

      $log.info('[Assessment::addPage] name, required?', pageName, pageIsRequired);

      // look in the inventory to see if this property already exists
      if (pages.inventory.hasOwnProperty(pageName)) {
        $log.warn('[Assessment::addPage] ignoring duplicate page ' + pageName);
      } else {
        pages.total++;
        pages.inventory[pageName] = pageIsRequired;
        pages.viewed.inventory[pageName] = false;

        // NOTE: commented for now, we're for now declaring the number of required pages directly
        //if (pageIsRequired) {
        //  pages.required++;
        //}
      }
    }

    /**
     * Record that a page was viewed
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     */
    function pageViewed(pageId) {
      //$log.info('[Assessment::pageViewed]  ', pageId);

      if (pages.viewed.inventory[pageId] === false) {
        pages.viewed.inventory[pageId] = new Date();

        if (pages.inventory[pageId] === true) {
          pages.viewed.required++;

          if (isAssessing) {
            io.updatePage(pageId, getAssessment());
          }
        }
      } else {
        $log.warning('Assessment:pageViewed | page already viewed, ', pageId);
      }
    }

    /**
     * Gets all pageview data
     *
     * @return obj of pageview stats
     */
    function getPageStats() {
      return pages;
    }

    /**
     * Gets the count of number of unique pageviews
     * @returns {pages.viewed.total|*}
     */
    function getPageviewsCount() {
      return pages.viewed.total;
    }

    // ---------------------------| Q+A

    function setRequiredQuestions(newRequiredQuestions) {

      var requiredQuestionsInt = parseInt(newRequiredQuestions);

      if( isNaN(requiredQuestionsInt)) {
        $log.error('[Assessment::setRequiredQuestions] questions must be a number');
        return;
      }

      questions.required = requiredQuestionsInt;
      dumpState();
    }

    /**
     * Record that a question was correctly answered and whether it was required
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param pageIsRequired bool Whether the page was required so it can help user's score.
     */
    function addQuestion(questionName, questionIsRequired) {

      $log.info('[Assessment::addQuestion] name, required?', questionName, questionIsRequired);

      // look in the inventory to see if this property already exists
      if (questions.inventory.hasOwnProperty(questionName)) {
        $log.warn('[Assessment::addQuestion] ignoring duplicate page ' + questionName);
      } else {
        questions.total++;
        questions.inventory[questionName] = questionIsRequired;
        questions.answered.inventory[questionName] = {
          isCorrect: null,
          isRequired: questionIsRequired,
          answered: false
        };

        //NOTE: We are setting question required count through setRequiredQuestions()
        //if (questionIsRequired) {
        //  questions.required++;
        //}
      }
    }

    /**
     * Record that a question was correctly answered and whether it was required
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param isCorrect bool Whether the answer provided is correct
     */
    function questionAnswered(questionId, isCorrect) {

      $log.info('[Assessment::questionAnswered] ', questionId, isCorrect);

      // double-check this has an entry
      if (!questions.inventory.hasOwnProperty(questionId)) {
        $log.warn('[Assessment::questionAnswered] answered question has no registered question, defaulting to NOT required.', questionId);
        addQuestion(questionId, false);
      }

      if (questions.answered.inventory[questionId].answered === false) {
        questions.answered.inventory[questionId].answered = new Date();
        questions.answered.inventory[questionId].isCorrect = !!isCorrect;

        if (isCorrect && questions.answered.inventory[questionId].isRequired) {
          questions.answered.requiredCorrect++;
        }

        if (isAssessing) {
          io.updateQuestion(questionId, getAssessment());
        }

      } else {
        $log.warning('[Assessment::questionAnswered] question already answered, ', questionId);
      }
    }

    /**
     * Gets all questions stats
     *
     * @return obj of questions stats
     */
    function getQuestionStats() {
      return questions;
    }

    /**
     * DEBUG ONLY
     */
    function dumpState() {
      $log.info('[Assessment:dumpState] ', getAssessment());
    }

    var service = {
      beginFor: beginFor,
      finalize: finalize,
      getAssessment: getAssessment,
      reset: reset,
      setIO: setIO,

      //--- Scoring
      getMinPassing: getMinPassing,
      getScore: getScore,
      isPassing: isPassing,
      setMinPassing: setMinPassing,

      //--- Pages
      addPage: addPage,
      getPageviewsCount: getPageviewsCount,
      getPageStats: getPageStats,
      pageViewed: pageViewed,
      setRequiredPages: setRequiredPages,

      //--- Questions
      addQuestion: addQuestion,
      getQuestionStats: getQuestionStats,
      questionAnswered: questionAnswered,
      setRequiredQuestions: setRequiredQuestions,

      // DEBUG
      dumpState: dumpState
    };

    $log.info('[Assessment] service init');

    return service;
  }
})();
<|endoftext|>


<commit_before>/* jshint -W003, -W117, -W004 */
(function () {
  'use strict';

  angular
    .module('newplayer.service')
    .service('AssessmentService', AssessmentService);

  /** @ngInject */
  function AssessmentService($log, $rootScope, ConfigService, AssessmentIOService) {
    var assessmentID, pages, questions,
      vm = this,
      isAssessing,
      minPassing = 0,
      io = AssessmentIOService,              // This is the I/O module for saving/restoring assessment stuff
      config = ConfigService.getConfig();

    if (config.hasOwnProperty('assessmentIO') && typeof config.assessmentIO === 'object' && config.assessmentIO.hasOwnProperty('updateFinal')) {
      $log.debug('[Assessment] using assessmentIO from config');
      setIO(config.assessmentIO);
    } else {
      $log.debug('[Assessment] using default assessmentIO');
    }

    // NOTE: this function is run below to initialize this service

    /**
     * Initializes the assessment service back to its 'blank' state.
     */
    function reset() {
      assessmentID = false;
      isAssessing = false;
      minPassing = -1;

      questions = {
        required: 0, total: 0, inventory: {},
        answered: {requiredCorrect: 0, inventory: {}}
      };

      pages = {
        required: 0, total: 0, inventory: {},
        viewed: {required: 0, inventory: {}}
      };
    }

  // NOTE: reset when the IIFE executes after the script is loaded.
    reset();

    /**
     * Begins an assessment session for a given ID and optionally a minimum passing score
     *
     * @param id The unique string for this assessment to identify it to the backend
     * @param newMinPassing A fractional number from 0 to 1 (e.g. 0.75 for 75%)
     */
    function beginFor(id, newMinPassing) {
      //$log.debug('Beginning assessments for ', id, newMinPassing);

      reset();
      assessmentID = id;
      setMinPassing(newMinPassing);

      isAssessing = true;
    }

    /**
     * Mark assessment as complete, whatever that will mean to the end system
     */
    function finalize() {
      if (!isAssessing) {
        //$log.debug('Assessment:finalize | assessment is disabled, ignoring');
        return;
      }

      //$log.debug('NP assessment::finalize | Finalizing assessments for ', assessmentID);

      // TODO - should this wait for a promise?
      io.updateFinal(getAssessment());

      isAssessing = false;
    }

    function getAssessment() {
      return {
        assessmentID: assessmentID,
        isAssessing: isAssessing,
        isPassing: isPassing(),
        minPassing: minPassing,
        pages: pages,
        questions: questions,
        score: getScore()
      };
    }

    /**
     * This sets the mechanism for how the assessment service communicates data
     * to an external data store. See the example in the assessmentio.service.js
     *
     * @see app/scripts/service/assessmentio.service.js
     */
    function setIO(newAssessmentIO) {
      // at some point this may change to validating the plugin
      io = newAssessmentIO;
    }

    // ---------------------------| Scoring

    /**
     * Get the minimum passing score
     * @returns {number} fraction of 1 (e.g. 0.6 for 60%)
     */
    function getMinPassing() {
      return minPassing;
    }

    /**
     * Sets the minimum passing score for this assessment.
     *
     * @param newMinPassing {number} fraction of 1 (e.g. 0.6 for 60%)
     */
    function setMinPassing(newMinPassing) {
      //$log.info('Assessment:setMinPassing', minPassing);

      newMinPassing = parseFloat(newMinPassing);

      if (!isNaN(newMinPassing)) {

        if (newMinPassing > 1) {
          $log.warn('[Assessment::setMinPassing] minPassing should be a fraction of 1. It is unlikely users will pass this assessment.', newMinPassing);
        }

        minPassing = newMinPassing;

      } else if (minPassing === -1 && config.hasOwnProperty('minPassing')) {
        minPassing = config.minPassing;
      } else if( minPassing === -1 ) {
        $log.warn('[Assessment::setMinPassing] no minimum passing score provided to beginFor or in config; any score will pass.');
        minPassing = 0;
      }
    }

    /**
     * Get the user's current score according to page and answer counts
     *
     * @return score from 0..1. Returns 1 if there are no required questions or answers.
     */
    function getScore() {

      if (!isAssessing) {
        return 0;
      }

      /*
       * (# of req. pages viewed + # of correctly answered req. questions) /
       *      (total req. pages + total req. questions)
       */

      var totalRequired = pages.required + questions.required;

      // User scores 100% if there are no requirements...
      if (totalRequired === 0) {
        return 1;
      }

      return Math.min(( pages.viewed.required + questions.answered.requiredCorrect ) / totalRequired, 1);
    }

    /**
     * Determine if the user is passing based on the minPassing score
     *
     * @return bool
     */
    function isPassing() {

      if (!isAssessing) {
        return false;
      }

      if (minPassing === 0) {
        return true;
      }

      return getScore() >= minPassing;
    }

    // ---------------------------| Pages

    function setRequiredPages(newRequiredPages) {

      var requiredPagesInt = parseInt(newRequiredPages);

      if( isNaN(requiredPagesInt)) {
        $log.error('Assessment:setRequiredPages | pages must be a number');
        return;
      }

      pages.required = requiredPagesInt;
    }

    /**
     * Add a potential page to view and whether it is required for score
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param pageIsRequired bool Whether the page was required so it can help user's score.
     */
    function addPage(pageName, pageIsRequired) {

      $log.info('[Assessment::addPage] name, required?', pageName, pageIsRequired);

      // look in the inventory to see if this property already exists
      if (pages.inventory.hasOwnProperty(pageName)) {
        $log.warn('[Assessment::addPage] ignoring duplicate page ' + pageName);
      } else {
        pages.total++;
        pages.inventory[pageName] = pageIsRequired;
        pages.viewed.inventory[pageName] = false;

        // NOTE: commented for now, we're for now declaring the number of required pages directly
        //if (pageIsRequired) {
        //  pages.required++;
        //}
      }
    }

    /**
     * Record that a page was viewed
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     */
    function pageViewed(pageId) {
      //$log.info('[Assessment::pageViewed]  ', pageId);

      if (pages.viewed.inventory[pageId] === false) {
        pages.viewed.inventory[pageId] = new Date();

        if (pages.inventory[pageId] === true) {
          pages.viewed.required++;

          if (isAssessing) {
            io.updatePage(pageId, getAssessment());
          }
        }
      } else {
        $log.warning('Assessment:pageViewed | page already viewed, ', pageId);
      }
    }

    /**
     * Gets all pageview data
     *
     * @return obj of pageview stats
     */
    function getPageStats() {
      return pages;
    }

    /**
     * Gets the count of number of unique pageviews
     * @returns {pages.viewed.total|*}
     */
    function getPageviewsCount() {
      return pages.viewed.total;
    }

    // ---------------------------| Q+A

    function setRequiredQuestions(newRequiredQuestions) {

      var requiredQuestionsInt = parseInt(newRequiredQuestions);

      if( isNaN(requiredQuestionsInt)) {
        $log.error('[Assessment::setRequiredQuestions] questions must be a number');
        return;
      }

      questions.required = requiredQuestionsInt;
      dumpState();
    }

    /**
     * Record that a question was correctly answered and whether it was required
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param pageIsRequired bool Whether the page was required so it can help user's score.
     */
    function addQuestion(questionName, questionIsRequired) {

      $log.info('[Assessment::addQuestion] name, required?', questionName, questionIsRequired);

      // look in the inventory to see if this property already exists
      if (questions.inventory.hasOwnProperty(questionName)) {
        $log.warn('[Assessment::addQuestion] ignoring duplicate page ' + questionName);
      } else {
        questions.total++;
        questions.inventory[questionName] = questionIsRequired;
        questions.answered.inventory[questionName] = {
          isCorrect: null,
          isRequired: questionIsRequired,
          answered: false
        };

        //NOTE: We are setting question required count through setRequiredQuestions()
        //if (questionIsRequired) {
        //  questions.required++;
        //}
      }
    }

    /**
     * Record that a question was correctly answered and whether it was required
     *
     * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
     * @param isCorrect bool Whether the answer provided is correct
     */
    function questionAnswered(questionId, isCorrect) {

      $log.info('[Assessment::questionAnswered] ', questionId, isCorrect);

      // double-check this has an entry
      if (!questions.inventory.hasOwnProperty(questionId)) {
        $log.warn('[Assessment::questionAnswered] answered question has no registered question, defaulting to NOT required.', questionId);
        addQuestion(questionId, false);
      }

      if (questions.answered.inventory[questionId].answered === false) {
        questions.answered.inventory[questionId].answered = new Date();
        questions.answered.inventory[questionId].isCorrect = !!isCorrect;

        if (isCorrect && questions.answered.inventory[questionId].isRequired) {
          questions.answered.requiredCorrect++;
        }

        if (isAssessing) {
          io.updateQuestion(questionId, getAssessment());
        }

      } else {
        $log.warn('[Assessment::questionAnswered] question already answered, ', questionId);
      }
    }

    /**
     * Gets all questions stats
     *
     * @return obj of questions stats
     */
    function getQuestionStats() {
      return questions;
    }

    /**
     * DEBUG ONLY
     */
    function dumpState() {
      $log.info('[Assessment:dumpState] ', getAssessment());
    }

    var service = {
      beginFor: beginFor,
      finalize: finalize,
      getAssessment: getAssessment,
      reset: reset,
      setIO: setIO,

      //--- Scoring
      getMinPassing: getMinPassing,
      getScore: getScore,
      isPassing: isPassing,
      setMinPassing: setMinPassing,

      //--- Pages
      addPage: addPage,
      getPageviewsCount: getPageviewsCount,
      getPageStats: getPageStats,
      pageViewed: pageViewed,
      setRequiredPages: setRequiredPages,

      //--- Questions
      addQuestion: addQuestion,
      getQuestionStats: getQuestionStats,
      questionAnswered: questionAnswered,
      setRequiredQuestions: setRequiredQuestions,

      // DEBUG
      dumpState: dumpState
    };

    $log.info('[Assessment] service init');

    return service;
  }
})();
<commit_msg>Drag and Select scoring<commit_after>/* jshint -W003, -W117, -W004 */
(function () {
    'use strict';
    angular
            .module('newplayer.service')
            .service('AssessmentService', AssessmentService);

    /** @ngInject */
    function AssessmentService($log, $rootScope, ConfigService, AssessmentIOService) {
        var assessmentID, pages, questions,
                vm = this,
                isAssessing,
                minPassing = 0,
                io = AssessmentIOService, // This is the I/O module for saving/restoring assessment stuff
                config = ConfigService.getConfig();
        if (config.hasOwnProperty('assessmentIO') && typeof config.assessmentIO === 'object' && config.assessmentIO.hasOwnProperty('updateFinal')) {
            $log.debug('[Assessment] using assessmentIO from config');
            setIO(config.assessmentIO);
        } else {
            $log.debug('[Assessment] using default assessmentIO');
        }
        // NOTE: this function is run below to initialize this service

        /**
         * Initializes the assessment service back to its 'blank' state.
         */
        function reset() {
            assessmentID = false;
            isAssessing = false;
            minPassing = -1;
            questions = {
                required: 0, total: 0, inventory: {},
                answered: {requiredCorrect: 0, inventory: {}}
            };
            pages = {
                required: 0, total: 0, inventory: {},
                viewed: {required: 0, inventory: {}}
            };
        }
        // NOTE: reset when the IIFE executes after the script is loaded.
        reset();

        /**
         * Begins an assessment session for a given ID and optionally a minimum passing score
         *
         * @param id The unique string for this assessment to identify it to the backend
         * @param newMinPassing A fractional number from 0 to 1 (e.g. 0.75 for 75%)
         */
        function beginFor(id, newMinPassing) {
            //$log.debug('Beginning assessments for ', id, newMinPassing);
            reset();
            assessmentID = id;
            setMinPassing(newMinPassing);
            isAssessing = true;
        }

        /**
         * Mark assessment as complete, whatever that will mean to the end system
         */
        function finalize() {
            if (!isAssessing) {
                //$log.debug('Assessment:finalize | assessment is disabled, ignoring');
                return;
            }
            //$log.debug('NP assessment::finalize | Finalizing assessments for ', assessmentID);
            // TODO - should this wait for a promise?
            io.updateFinal(getAssessment());
            isAssessing = false;
        }
        function getAssessment() {
            return {
                assessmentID: assessmentID,
                isAssessing: isAssessing,
                isPassing: isPassing(),
                minPassing: minPassing,
                pages: pages,
                questions: questions,
                score: getScore()
            };
        }

        /**
         * This sets the mechanism for how the assessment service communicates data
         * to an external data store. See the example in the assessmentio.service.js
         *
         * @see app/scripts/service/assessmentio.service.js
         */
        function setIO(newAssessmentIO) {
            // at some point this may change to validating the plugin
            io = newAssessmentIO;
        }

        // ---------------------------| Scoring
        /**
         * Get the minimum passing score
         * @returns {number} fraction of 1 (e.g. 0.6 for 60%)
         */
        function getMinPassing() {
            return minPassing;
        }

        /**
         * Sets the minimum passing score for this assessment.
         *
         * @param newMinPassing {number} fraction of 1 (e.g. 0.6 for 60%)
         */
        function setMinPassing(newMinPassing) {
            //$log.info('Assessment:setMinPassing', minPassing);
            newMinPassing = parseFloat(newMinPassing);
            if (!isNaN(newMinPassing)) {
                if (newMinPassing > 1) {
                    $log.warn('[Assessment::setMinPassing] minPassing should be a fraction of 1. It is unlikely users will pass this assessment.', newMinPassing);
                }
                minPassing = newMinPassing;
            } else if (minPassing === -1 && config.hasOwnProperty('minPassing')) {
                minPassing = config.minPassing;
            } else if (minPassing === -1) {
                $log.warn('[Assessment::setMinPassing] no minimum passing score provided to beginFor or in config; any score will pass.');
                minPassing = 0;
            }
        }

        /**
         * Get the user's current score according to page and answer counts
         *
         * @return score from 0..1. Returns 1 if there are no required questions or answers.
         */
        function getScore() {
            if (!isAssessing) {
                return 0;
            }
            /*
             * (# of req. pages viewed + # of correctly answered req. questions) /
             *      (total req. pages + total req. questions)
             */
            var totalRequired = pages.required + questions.required;
            // User scores 100% if there are no requirements...
            if (totalRequired === 0) {
                return 1;
            }
            return Math.min((pages.viewed.required + questions.answered.requiredCorrect) / totalRequired, 1);
        }

        /**
         * Determine if the user is passing based on the minPassing score
         *
         * @return bool
         */
        function isPassing() {
            if (!isAssessing) {
                return false;
            }
            if (minPassing === 0) {
                return true;
            }
            return getScore() >= minPassing;
        }

        // ---------------------------| Pages
        function setRequiredPages(newRequiredPages) {
            var requiredPagesInt = parseInt(newRequiredPages);
            if (isNaN(requiredPagesInt)) {
                $log.error('Assessment:setRequiredPages | pages must be a number');
                return;
            }
            pages.required = requiredPagesInt;
        }

        /**
         * Add a potential page to view and whether it is required for score
         *
         * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
         * @param pageIsRequired bool Whether the page was required so it can help user's score.
         */
        function addPage(pageName, pageIsRequired) {
            $log.info('[Assessment::addPage] name, required?', pageName, pageIsRequired);
            // look in the inventory to see if this property already exists
            if (pages.inventory.hasOwnProperty(pageName)) {
                $log.warn('[Assessment::addPage] ignoring duplicate page ' + pageName);
            } else {
                pages.total++;
                pages.inventory[pageName] = pageIsRequired;
                pages.viewed.inventory[pageName] = false;
                // NOTE: commented for now, we're for now declaring the number of required pages directly
                //if (pageIsRequired) {
                //  pages.required++;
                //}
            }
        }

        /**
         * Record that a page was viewed
         *
         * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
         */
        function pageViewed(pageId) {
            //$log.info('[Assessment::pageViewed]  ', pageId);
            if (pages.viewed.inventory[pageId] === false) {
                pages.viewed.inventory[pageId] = new Date();
                if (pages.inventory[pageId] === true) {
                    pages.viewed.required++;
                    if (isAssessing) {
                        io.updatePage(pageId, getAssessment());
                    }
                }
            } else {
                $log.warning('Assessment:pageViewed | page already viewed, ', pageId);
            }
        }

        /**
         * Gets all pageview data
         *
         * @return obj of pageview stats
         */
        function getPageStats() {
            return pages;
        }

        /**
         * Gets the count of number of unique pageviews
         * @returns {pages.viewed.total|*}
         */
        function getPageviewsCount() {
            return pages.viewed.total;
        }
        // ---------------------------| Q+A
        function setRequiredQuestions(newRequiredQuestions) {
            var requiredQuestionsInt = parseInt(newRequiredQuestions);
            if (isNaN(requiredQuestionsInt)) {
                $log.error('[Assessment::setRequiredQuestions] questions must be a number');
                return;
            }
            questions.required = requiredQuestionsInt;
            dumpState();
        }

        /**
         * Record that a question was correctly answered and whether it was required
         *
         * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
         * @param pageIsRequired bool Whether the page was required so it can help user's score.
         */
        function addQuestion(questionName, questionIsRequired) {
            $log.info('[Assessment::addQuestion] name, required?', questionName, questionIsRequired);
            // look in the inventory to see if this property already exists
            if (questions.inventory.hasOwnProperty(questionName)) {
                $log.warn('[Assessment::addQuestion] ignoring duplicate page ' + questionName);
            } else {
                questions.total++;
                questions.inventory[questionName] = questionIsRequired;
                questions.answered.inventory[questionName] = {
                    isCorrect: null,
                    isRequired: questionIsRequired,
                    answered: false
                };
                //NOTE: We are setting question required count through setRequiredQuestions()
                //if (questionIsRequired) {
                //  questions.required++;
                //}
            }
        }

        /**
         * Record that a question was correctly answered and whether it was required
         *
         * @param pageNamed string The name or ID of the page (we'll keep a stack of it)
         * @param isCorrect bool Whether the answer provided is correct
         */
        function questionAnswered(questionId, isCorrect) {
            $log.info('[Assessment::questionAnswered] ', questionId, isCorrect);
            // double-check this has an entry
            if (!questions.inventory.hasOwnProperty(questionId)) {
                $log.warn('[Assessment::questionAnswered] answered question has no registered question, defaulting to NOT required.', questionId);
                addQuestion(questionId, false);
            }
            if (questions.answered.inventory[questionId].answered === false) {
                questions.answered.inventory[questionId].answered = new Date();
                questions.answered.inventory[questionId].isCorrect = !!isCorrect;
                if (isCorrect && questions.answered.inventory[questionId].isRequired) {
                    questions.answered.requiredCorrect++;
                }
                if (isAssessing) {
                    io.updateQuestion(questionId, getAssessment());
                }
            } else {
                $log.warn('[Assessment::questionAnswered] question already answered, ', questionId);
            }
        }

        /**
         * Gets all questions stats
         *
         * @return obj of questions stats
         */
        function getQuestionStats() {
            return questions;
        }

        /**
         * DEBUG ONLY
         */
        function dumpState() {
            $log.info('[Assessment:dumpState] ', getAssessment());
        }
        var service = {
            beginFor: beginFor,
            finalize: finalize,
            getAssessment: getAssessment,
            reset: reset,
            setIO: setIO,
            //--- Scoring
            getMinPassing: getMinPassing,
            getScore: getScore,
            isPassing: isPassing,
            setMinPassing: setMinPassing,
            //--- Pages
            addPage: addPage,
            getPageviewsCount: getPageviewsCount,
            getPageStats: getPageStats,
            pageViewed: pageViewed,
            setRequiredPages: setRequiredPages,
            //--- Questions
            addQuestion: addQuestion,
            getQuestionStats: getQuestionStats,
            questionAnswered: questionAnswered,
            setRequiredQuestions: setRequiredQuestions,
            // DEBUG
            dumpState: dumpState
        };
        $log.info('[Assessment] service init');
        return service;
    }
})();
<|endoftext|>


<commit_before>/**
 * @file Percent component
 * @author chao(chao.zhang@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

export default class Percent extends Component {

    static propTypes = {

        className: PropTypes.string,
        style: PropTypes.object,

        endNum: PropTypes.number,
        move: PropTypes.bool

    };
    static defaultProps = {

        className: null,
        style: null,

        endNum: 100,
        move: false

    };

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            percent: 0
        };

    }

    /**
     * 百分比数字递增
     */
    numberChange() {
        if (this.state.percent < 100) {
            if (this.state.percent < this.props.endNum) {
                this.setState({
                    percent: this.state.percent + 1
                });
                const time = 300 / (this.props.endNum - this.state.percent);
                this.timer = setTimeout(() => this.numberChange(), time);
                return;
            }
            this.timer = setTimeout(() => this.numberChange(), 30);
        }
    }

    componentDidMount() {
        this.timer = setTimeout(() => this.numberChange(), 30);
    }

    componentWillUnmount() {
        clearTimeout(this.timer);
    }

    render() {

        const {className, style, move, endNum} = this.props,
            {percent} = this.state,

            wrapperClassName = (className ? ' ' + className : ''),
            wrapperStyle = move === true ?
                {
                    width: endNum + '%',
                    textAlign: 'right',
                    ...style
                }
                :
                {...style};

        return (

                {
                    React.Children.map(this.props.children, child => (
                        {child}
                    ))
                }

                {percent}%

        );

    }
};<commit_msg>update Percent<commit_after>/**
 * @file Percent component
 * @author chao(chao.zhang@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

class Percent extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            percent: 0
        };

    }

    /**
     * 百分比数字递增
     */
    numberChange() {
        if (this.state.percent < 100) {
            if (this.state.percent < this.props.endNum) {
                this.setState({
                    percent: this.state.percent + 1
                });
                const time = 300 / (this.props.endNum - this.state.percent);
                this.timer = setTimeout(() => this.numberChange(), time);
                return;
            }
            this.timer = setTimeout(() => this.numberChange(), 30);
        }
    }

    componentDidMount() {
        this.timer = setTimeout(() => this.numberChange(), 30);
    }

    componentWillUnmount() {
        clearTimeout(this.timer);
    }

    render() {

        const {className, style, move, endNum} = this.props,
            {percent} = this.state,

            wrapperClassName = (className ? ' ' + className : ''),
            wrapperStyle = move === true ?
                {
                    width: endNum + '%',
                    textAlign: 'right',
                    ...style
                }
                :
                {...style};

        return (

                {
                    React.Children.map(this.props.children, child => (
                        {child}
                    ))
                }

                {percent}%

        );

    }
};

Percent.propTypes = {

    className: PropTypes.string,
    style: PropTypes.object,

    endNum: PropTypes.number,
    move: PropTypes.bool

};

Percent.defaultProps = {

    className: null,
    style: null,

    endNum: 100,
    move: false

};

export default Percent;<|endoftext|>


<commit_before>define([
    'jquery',
    'angular',
    'moment'
], function($, angular, moment) {
    'use strict';

    angular.module('superdesk.items.directives', []).
        filter('reldate', function() {
            return function(date) {
                return moment(date).fromNow();
            };
        }).
        directive('sdSearchbar', function($location, $routeParams) {
            return {
                link: function($scope, element, attrs) {
                    element.attr('name', 'searchbar');
                    element.attr('autofocus', 'autofocus');
                    element.addClass('searchbar-container');

                    if ('q' in $routeParams) {
                        element.val($routeParams.q);
                    }

                    $(element).change(function() {
                        $scope.$apply(function() {
                            var query = element.val();
                            if (query && query.length > 2) {
                                $location.search('q', query);
                                $location.search('skip', null);
                            } else if (query.length === 0) {
                                $location.search('q', null);
                                $location.search('skip', null);
                            }
                        });
                    });
                }
            };
        }).
        directive('sdPagination', function($location, $routeParams) {
            function getCurrentSkip() {
                return 'skip' in $routeParams ? parseInt($routeParams.skip, 10) : 0;
            }

            function getPrevSkip($scope) {
                var skip = getCurrentSkip() - $scope.limit;
                if (skip < 0) {
                    skip = 0;
                }

                return skip === 0 ? null : skip;
            }

            function getNextSkip($scope) {
                return getCurrentSkip() + $scope.limit;
            }

            return {
                templateUrl: 'scripts/superdesk/items/views/pagination.html',
                require: '?ngModel',
                scope: false,
                link: function($scope, element, attrs, ngModel) {
                    element.addClass('btn-group').addClass('pull-right');

                    $scope.links = {};
                    $scope.limit = 25;

                    $scope.prev = function() {
                        if (!$scope.links.hasPrev) {
                            return false;
                        }
                        $location.search('skip', getPrevSkip($scope));
                    };

                    $scope.next = function() {
                        if (!$scope.links.hasNext) {
                            return false;
                        }
                        $location.search('skip', getNextSkip($scope));
                    };

                    $scope.go = function(link) {
                        console.log('go', link);
                    };

                    ngModel.$render = function() {
                        var items = ngModel.$viewValue;
                        $scope.links = items.links;
                    };
                }
            };
        }).
        directive('sdHtml', function($sce) {
            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.prepend(ngModel.$viewValue);
                    };
                }
            };
        }).
        directive('sdContent', function() {
            function getText(content) {
                var lines = $(content);
                var texts = [];
                for (var i = 0; i < lines.length; i++) {
                    var el = $(lines[i]);
                    if (el.is('p')) {
                        texts.push(el[0].outerHTML);
                    }
                }

                return texts.join('\n');
            }

            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.html(getText(ngModel.$viewValue.content));
                    };
                }
            };
        }).
        directive('sdContenteditable', function() {
            return {
                require: 'ngModel',
                link: function($scope, element, attrs, ngModel) {
                    element.attr('contenteditable', 'true');

                    $(element).keyup(function(e) {
                        $scope.$apply(function() {
                            ngModel.$setViewValue(element.html());
                        });
                    });

                    ngModel.$render = function() {
                        var model = ngModel.$viewValue;
                        if (angular.isString(model)) {
                            element.html(model);
                        } else {
                            switch (model.contenttype) {
                            case 'application/xhtml+html':
                            case 'application/xhtml+xml':
                                element.html(model.content);
                                break;

                            case 'image/jpeg':
                                if (model.rendition !== 'rend:viewImage') {
                                    break;
                                }

                                $('<img />').
                                    attr('src', model.href).
                                    appendTo(element);
                                break;

                            case 'audio/mpeg':
                                $('<audio controls>').
                                    attr('src', model.href).
                                    appendTo(element);
                                break;

                            case 'video/mpeg':
                                if (model.rendition !== 'rend:stream:700:16x9:mp4') {
                                    break;
                                }

                                $('<video controls>').
                                    attr('src', model.href).
                                    appendTo(element);
                                break;

                            default:
                                console.log(model);
                            }
                        }
                    };
                }
            };
        });
});<commit_msg>Remove temporary method.<commit_after>define([
    'jquery',
    'angular',
    'moment'
], function($, angular, moment) {
    'use strict';

    angular.module('superdesk.items.directives', []).
        filter('reldate', function() {
            return function(date) {
                return moment(date).fromNow();
            };
        }).
        directive('sdSearchbar', function($location, $routeParams) {
            return {
                link: function($scope, element, attrs) {
                    element.attr('name', 'searchbar');
                    element.attr('autofocus', 'autofocus');
                    element.addClass('searchbar-container');

                    if ('q' in $routeParams) {
                        element.val($routeParams.q);
                    }

                    $(element).change(function() {
                        $scope.$apply(function() {
                            var query = element.val();
                            if (query && query.length > 2) {
                                $location.search('q', query);
                                $location.search('skip', null);
                            } else if (query.length === 0) {
                                $location.search('q', null);
                                $location.search('skip', null);
                            }
                        });
                    });
                }
            };
        }).
        directive('sdPagination', function($location, $routeParams) {
            function getCurrentSkip() {
                return 'skip' in $routeParams ? parseInt($routeParams.skip, 10) : 0;
            }

            function getPrevSkip($scope) {
                var skip = getCurrentSkip() - $scope.limit;
                if (skip < 0) {
                    skip = 0;
                }

                return skip === 0 ? null : skip;
            }

            function getNextSkip($scope) {
                return getCurrentSkip() + $scope.limit;
            }

            return {
                templateUrl: 'scripts/superdesk/items/views/pagination.html',
                require: '?ngModel',
                scope: false,
                link: function($scope, element, attrs, ngModel) {
                    element.addClass('btn-group').addClass('pull-right');

                    $scope.links = {};
                    $scope.limit = 25;

                    $scope.prev = function() {
                        if (!$scope.links.hasPrev) {
                            return false;
                        }
                        $location.search('skip', getPrevSkip($scope));
                    };

                    $scope.next = function() {
                        if (!$scope.links.hasNext) {
                            return false;
                        }
                        $location.search('skip', getNextSkip($scope));
                    };

                    ngModel.$render = function() {
                        var items = ngModel.$viewValue;
                        $scope.links = items.links;
                    };
                }
            };
        }).
        directive('sdHtml', function($sce) {
            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.prepend(ngModel.$viewValue);
                    };
                }
            };
        }).
        directive('sdContent', function() {
            function getText(content) {
                var lines = $(content);
                var texts = [];
                for (var i = 0; i < lines.length; i++) {
                    var el = $(lines[i]);
                    if (el.is('p')) {
                        texts.push(el[0].outerHTML);
                    }
                }

                return texts.join('\n');
            }

            return {
                require: '?ngModel',
                link: function($scope, element, attrs, ngModel) {
                    ngModel.$render = function() {
                        element.html(getText(ngModel.$viewValue.content));
                    };
                }
            };
        }).
        directive('sdContenteditable', function() {
            return {
                require: 'ngModel',
                link: function($scope, element, attrs, ngModel) {
                    element.attr('contenteditable', 'true');

                    $(element).keyup(function(e) {
                        $scope.$apply(function() {
                            ngModel.$setViewValue(element.html());
                        });
                    });

                    ngModel.$render = function() {
                        var model = ngModel.$viewValue;
                        if (angular.isString(model)) {
                            element.html(model);
                        } else {
                            switch (model.contenttype) {
                            case 'application/xhtml+html':
                            case 'application/xhtml+xml':
                                element.html(model.content);
                                break;

                            case 'image/jpeg':
                                if (model.rendition !== 'rend:viewImage') {
                                    break;
                                }

                                $('<img />').
                                    attr('src', model.href).
                                    appendTo(element);
                                break;

                            case 'audio/mpeg':
                                $('<audio controls>').
                                    attr('src', model.href).
                                    appendTo(element);
                                break;

                            case 'video/mpeg':
                                if (model.rendition !== 'rend:stream:700:16x9:mp4') {
                                    break;
                                }

                                $('<video controls>').
                                    attr('src', model.href).
                                    appendTo(element);
                                break;

                            default:
                                console.log(model);
                            }
                        }
                    };
                }
            };
        });
});<|endoftext|>