<commit_before>(function() {

  var degreesToRadians = fabric.util.degreesToRadians,
      //jscs:disable requireCamelCaseOrUpperCaseIdentifiers
      isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; };
  //jscs:enable requireCamelCaseOrUpperCaseIdentifiers

  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {

    /**
     * The object interactivity controls.
     * @private
     */
    _controlsVisibility: null,

    /**
     * Determines which corner has been clicked
     * @private
     * @param {Object} pointer The pointer indicating the mouse position
     * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found
     */
    _findTargetCorner: function(pointer) {
      if (!this.hasControls || !this.active) {
        return false;
      }

      var ex = pointer.x,
          ey = pointer.y,
          xPoints,
          lines;

      for (var i in this.oCoords) {

        if (!this.isControlVisible(i)) {
          continue;
        }

        if (i === 'mtr' && !this.hasRotatingPoint) {
          continue;
        }

        if (this.get('lockUniScaling') &&
           (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {
          continue;
        }

        lines = this._getImageLines(this.oCoords[i].corner);

        // debugging

        // canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);

        // canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);

        // canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);

        // canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);

        xPoints = this._findCrossPoints({ x: ex, y: ey }, lines);
        if (xPoints !== 0 && xPoints % 2 === 1) {
          this.__corner = i;
          return i;
        }
      }
      return false;
    },

    /**
     * Sets the coordinates of the draggable boxes in the corners of
     * the image used to scale/rotate it.
     * @private
     */
    _setCornerCoords: function() {
      var coords = this.oCoords,
          newTheta = degreesToRadians(45 - this.angle),
          /* Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2, */
          /* 0.707106 stands for sqrt(2)/2 */
          cornerHypotenuse = this.cornerSize * 0.707106,
          cosHalfOffset = cornerHypotenuse * Math.cos(newTheta),
          sinHalfOffset = cornerHypotenuse * Math.sin(newTheta),
          x, y;

      for (var point in coords) {
        x = coords[point].x;
        y = coords[point].y;
        coords[point].corner = {
          tl: {
            x: x - sinHalfOffset,
            y: y - cosHalfOffset
          },
          tr: {
            x: x + cosHalfOffset,
            y: y - sinHalfOffset
          },
          bl: {
            x: x - cosHalfOffset,
            y: y + sinHalfOffset
          },
          br: {
            x: x + sinHalfOffset,
            y: y + cosHalfOffset
          }
        };
      }
    },

    /*
     * Calculate object dimensions from its properties
     * @private
     */
    _getNonTransformedDimensions: function() {
      var strokeWidth = this.strokeWidth,
          w = this.width,
          h = this.height,
          capped = this.strokeLineCap === 'round' || this.strokeLineCap === 'square',
          vLine = this.type === 'line' && this.width === 0,
          hLine = this.type === 'line' && this.height === 0,
          sLine = vLine || hLine,
          strokeW = (capped && hLine) || !sLine,
          strokeH = (capped && vLine) || !sLine;

      if (vLine) {
        w = strokeWidth;
      }
      else if (hLine) {
        h = strokeWidth;
      }
      if (strokeW) {
        w += (w < 0 ? -strokeWidth : strokeWidth);
      }
      if (strokeH) {
        h += (h < 0 ? -strokeWidth : strokeWidth);
      }
      return { x: w, y: h };
    },

    /*
     * @private
     */
    _getTransformedDimensions: function(dimensions) {
      if (!dimensions) {
        dimensions = this._getNonTransformedDimensions();
      }
      var transformMatrix = this._calcDimensionsTransformMatrix();
      return fabric.util.transformPoint(dimensions, transformMatrix, true);
    },

    /*
     * private
     */
    _calculateCurrentDimensions: function(shouldTransform)  {
      var vpt = this.getViewportTransform(),
          dim = this._getTransformedDimensions(),
          w = dim.x, h = dim.y;

      w += 2 * this.padding;
      h += 2 * this.padding;

      if (shouldTransform) {
        return fabric.util.transformPoint(new fabric.Point(w, h), vpt, true);
      }
      return { x: w, y: h };
    },

    /**
     * Draws borders of an object's bounding box.
     * Requires public properties: width, height
     * Requires public options: padding, borderColor
     * @param {CanvasRenderingContext2D} ctx Context to draw on
     * @return {fabric.Object} thisArg
     * @chainable
     */
    drawBorders: function(ctx) {
      if (!this.hasBorders) {
        return this;
      }

      ctx.save();

      ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
      ctx.strokeStyle = this.borderColor;
      ctx.lineWidth = 1 / this.borderScaleFactor;

      var wh = this._calculateCurrentDimensions(true),
          width = wh.x,
          height = wh.y;
      if (this.group) {
        width = width * this.group.scaleX;
        height = height * this.group.scaleY;
      }

      ctx.strokeRect(
        ~~(-(width / 2)) - 0.5, // offset needed to make lines look sharper
        ~~(-(height / 2)) - 0.5,
        ~~(width) + 1, // double offset needed to make lines look sharper
        ~~(height) + 1
      );

      if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) {

        var rotateHeight = -height / 2;

        ctx.beginPath();
        ctx.moveTo(0, rotateHeight);
        ctx.lineTo(0, rotateHeight - this.rotatingPointOffset);
        ctx.closePath();
        ctx.stroke();
      }

      ctx.restore();
      return this;
    },

    /**
     * Draws corners of an object's bounding box.
     * Requires public properties: width, height
     * Requires public options: cornerSize, padding
     * @param {CanvasRenderingContext2D} ctx Context to draw on
     * @return {fabric.Object} thisArg
     * @chainable
     */
    drawControls: function(ctx) {
      if (!this.hasControls) {
        return this;
      }

      var wh = this._calculateCurrentDimensions(true),
          width = wh.x,
          height = wh.y,
          left = -(width / 2),
          top = -(height / 2),
          scaleOffset = this.cornerSize / 2,
          methodName = this.transparentCorners ? 'strokeRect' : 'fillRect';

      ctx.save();

      ctx.lineWidth = 1;

      ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
      ctx.strokeStyle = ctx.fillStyle = this.cornerColor;

      // top-left
      this._drawControl('tl', ctx, methodName,
        left - scaleOffset,
        top - scaleOffset);

      // top-right
      this._drawControl('tr', ctx, methodName,
        left + width - scaleOffset,
        top - scaleOffset);

      // bottom-left
      this._drawControl('bl', ctx, methodName,
        left - scaleOffset,
        top + height - scaleOffset);

      // bottom-right
      this._drawControl('br', ctx, methodName,
        left + width - scaleOffset,
        top + height - scaleOffset);

      if (!this.get('lockUniScaling')) {

        // middle-top
        this._drawControl('mt', ctx, methodName,
          left + width/2 - scaleOffset,
          top - scaleOffset);

        // middle-bottom
        this._drawControl('mb', ctx, methodName,
          left + width/2 - scaleOffset,
          top + height - scaleOffset);

        // middle-right
        this._drawControl('mr', ctx, methodName,
          left + width - scaleOffset,
          top + height/2 - scaleOffset);

        // middle-left
        this._drawControl('ml', ctx, methodName,
          left - scaleOffset,
          top + height/2 - scaleOffset);
      }

      // middle-top-rotate
      if (this.hasRotatingPoint) {
        this._drawControl('mtr', ctx, methodName,
          left + width/2 - scaleOffset,
          top - this.rotatingPointOffset - scaleOffset);
      }

      ctx.restore();

      return this;
    },

    /**
     * @private
     */
    _drawControl: function(control, ctx, methodName, left, top) {
      if (!this.isControlVisible(control)) {
        return;
      }
      var size = this.cornerSize;
      isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size);
      ctx[methodName](left, top, size, size);
    },

    /**
     * Returns true if the specified control is visible, false otherwise.
     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.
     * @returns {Boolean} true if the specified control is visible, false otherwise
     */
    isControlVisible: function(controlName) {
      return this._getControlsVisibility()[controlName];
    },

    /**
     * Sets the visibility of the specified control.
     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.
     * @param {Boolean} visible true to set the specified control visible, false otherwise
     * @return {fabric.Object} thisArg
     * @chainable
     */
    setControlVisible: function(controlName, visible) {
      this._getControlsVisibility()[controlName] = visible;
      return this;
    },

    /**
     * Sets the visibility state of object controls.
     * @param {Object} [options] Options object
     * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it
     * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it
     * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it
     * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it
     * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it
     * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it
     * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it
     * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it
     * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it
     * @return {fabric.Object} thisArg
     * @chainable
     */
    setControlsVisibility: function(options) {
      options || (options = { });

      for (var p in options) {
        this.setControlVisible(p, options[p]);
      }
      return this;
    },

    /**
     * Returns the instance of the control visibility set for this object.
     * @private
     * @returns {Object}
     */
    _getControlsVisibility: function() {
      if (!this._controlsVisibility) {
        this._controlsVisibility = {
          tl: true,
          tr: true,
          br: true,
          bl: true,
          ml: true,
          mt: true,
          mr: true,
          mb: true,
          mtr: true
        };
      }
      return this._controlsVisibility;
    }
  });
})();
<commit_msg>Update object_interactivity.mixin.js<commit_after>(function() {

  var degreesToRadians = fabric.util.degreesToRadians,
      //jscs:disable requireCamelCaseOrUpperCaseIdentifiers
      isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; };
  //jscs:enable requireCamelCaseOrUpperCaseIdentifiers

  fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {

    /**
     * The object interactivity controls.
     * @private
     */
    _controlsVisibility: null,

    /**
     * Determines which corner has been clicked
     * @private
     * @param {Object} pointer The pointer indicating the mouse position
     * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found
     */
    _findTargetCorner: function(pointer) {
      if (!this.hasControls || !this.active) {
        return false;
      }

      var ex = pointer.x,
          ey = pointer.y,
          xPoints,
          lines;
      this.__corner = 0;
      for (var i in this.oCoords) {

        if (!this.isControlVisible(i)) {
          continue;
        }

        if (i === 'mtr' && !this.hasRotatingPoint) {
          continue;
        }

        if (this.get('lockUniScaling') &&
           (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) {
          continue;
        }

        lines = this._getImageLines(this.oCoords[i].corner);

        // debugging

        // canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);

        // canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);

        // canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);

        // canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);
        // canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);

        xPoints = this._findCrossPoints({ x: ex, y: ey }, lines);
        if (xPoints !== 0 && xPoints % 2 === 1) {
          this.__corner = i;
          return i;
        }
      }
      return false;
    },

    /**
     * Sets the coordinates of the draggable boxes in the corners of
     * the image used to scale/rotate it.
     * @private
     */
    _setCornerCoords: function() {
      var coords = this.oCoords,
          newTheta = degreesToRadians(45 - this.angle),
          /* Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2, */
          /* 0.707106 stands for sqrt(2)/2 */
          cornerHypotenuse = this.cornerSize * 0.707106,
          cosHalfOffset = cornerHypotenuse * Math.cos(newTheta),
          sinHalfOffset = cornerHypotenuse * Math.sin(newTheta),
          x, y;

      for (var point in coords) {
        x = coords[point].x;
        y = coords[point].y;
        coords[point].corner = {
          tl: {
            x: x - sinHalfOffset,
            y: y - cosHalfOffset
          },
          tr: {
            x: x + cosHalfOffset,
            y: y - sinHalfOffset
          },
          bl: {
            x: x - cosHalfOffset,
            y: y + sinHalfOffset
          },
          br: {
            x: x + sinHalfOffset,
            y: y + cosHalfOffset
          }
        };
      }
    },

    /*
     * Calculate object dimensions from its properties
     * @private
     */
    _getNonTransformedDimensions: function() {
      var strokeWidth = this.strokeWidth,
          w = this.width,
          h = this.height,
          capped = this.strokeLineCap === 'round' || this.strokeLineCap === 'square',
          vLine = this.type === 'line' && this.width === 0,
          hLine = this.type === 'line' && this.height === 0,
          sLine = vLine || hLine,
          strokeW = (capped && hLine) || !sLine,
          strokeH = (capped && vLine) || !sLine;

      if (vLine) {
        w = strokeWidth;
      }
      else if (hLine) {
        h = strokeWidth;
      }
      if (strokeW) {
        w += (w < 0 ? -strokeWidth : strokeWidth);
      }
      if (strokeH) {
        h += (h < 0 ? -strokeWidth : strokeWidth);
      }
      return { x: w, y: h };
    },

    /*
     * @private
     */
    _getTransformedDimensions: function(dimensions) {
      if (!dimensions) {
        dimensions = this._getNonTransformedDimensions();
      }
      var transformMatrix = this._calcDimensionsTransformMatrix();
      return fabric.util.transformPoint(dimensions, transformMatrix, true);
    },

    /*
     * private
     */
    _calculateCurrentDimensions: function(shouldTransform)  {
      var vpt = this.getViewportTransform(),
          dim = this._getTransformedDimensions(),
          w = dim.x, h = dim.y;

      w += 2 * this.padding;
      h += 2 * this.padding;

      if (shouldTransform) {
        return fabric.util.transformPoint(new fabric.Point(w, h), vpt, true);
      }
      return { x: w, y: h };
    },

    /**
     * Draws borders of an object's bounding box.
     * Requires public properties: width, height
     * Requires public options: padding, borderColor
     * @param {CanvasRenderingContext2D} ctx Context to draw on
     * @return {fabric.Object} thisArg
     * @chainable
     */
    drawBorders: function(ctx) {
      if (!this.hasBorders) {
        return this;
      }

      ctx.save();

      ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
      ctx.strokeStyle = this.borderColor;
      ctx.lineWidth = 1 / this.borderScaleFactor;

      var wh = this._calculateCurrentDimensions(true),
          width = wh.x,
          height = wh.y;
      if (this.group) {
        width = width * this.group.scaleX;
        height = height * this.group.scaleY;
      }

      ctx.strokeRect(
        ~~(-(width / 2)) - 0.5, // offset needed to make lines look sharper
        ~~(-(height / 2)) - 0.5,
        ~~(width) + 1, // double offset needed to make lines look sharper
        ~~(height) + 1
      );

      if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) {

        var rotateHeight = -height / 2;

        ctx.beginPath();
        ctx.moveTo(0, rotateHeight);
        ctx.lineTo(0, rotateHeight - this.rotatingPointOffset);
        ctx.closePath();
        ctx.stroke();
      }

      ctx.restore();
      return this;
    },

    /**
     * Draws corners of an object's bounding box.
     * Requires public properties: width, height
     * Requires public options: cornerSize, padding
     * @param {CanvasRenderingContext2D} ctx Context to draw on
     * @return {fabric.Object} thisArg
     * @chainable
     */
    drawControls: function(ctx) {
      if (!this.hasControls) {
        return this;
      }

      var wh = this._calculateCurrentDimensions(true),
          width = wh.x,
          height = wh.y,
          left = -(width / 2),
          top = -(height / 2),
          scaleOffset = this.cornerSize / 2,
          methodName = this.transparentCorners ? 'strokeRect' : 'fillRect';

      ctx.save();

      ctx.lineWidth = 1;

      ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;
      ctx.strokeStyle = ctx.fillStyle = this.cornerColor;

      // top-left
      this._drawControl('tl', ctx, methodName,
        left - scaleOffset,
        top - scaleOffset);

      // top-right
      this._drawControl('tr', ctx, methodName,
        left + width - scaleOffset,
        top - scaleOffset);

      // bottom-left
      this._drawControl('bl', ctx, methodName,
        left - scaleOffset,
        top + height - scaleOffset);

      // bottom-right
      this._drawControl('br', ctx, methodName,
        left + width - scaleOffset,
        top + height - scaleOffset);

      if (!this.get('lockUniScaling')) {

        // middle-top
        this._drawControl('mt', ctx, methodName,
          left + width/2 - scaleOffset,
          top - scaleOffset);

        // middle-bottom
        this._drawControl('mb', ctx, methodName,
          left + width/2 - scaleOffset,
          top + height - scaleOffset);

        // middle-right
        this._drawControl('mr', ctx, methodName,
          left + width - scaleOffset,
          top + height/2 - scaleOffset);

        // middle-left
        this._drawControl('ml', ctx, methodName,
          left - scaleOffset,
          top + height/2 - scaleOffset);
      }

      // middle-top-rotate
      if (this.hasRotatingPoint) {
        this._drawControl('mtr', ctx, methodName,
          left + width/2 - scaleOffset,
          top - this.rotatingPointOffset - scaleOffset);
      }

      ctx.restore();

      return this;
    },

    /**
     * @private
     */
    _drawControl: function(control, ctx, methodName, left, top) {
      if (!this.isControlVisible(control)) {
        return;
      }
      var size = this.cornerSize;
      isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size);
      ctx[methodName](left, top, size, size);
    },

    /**
     * Returns true if the specified control is visible, false otherwise.
     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.
     * @returns {Boolean} true if the specified control is visible, false otherwise
     */
    isControlVisible: function(controlName) {
      return this._getControlsVisibility()[controlName];
    },

    /**
     * Sets the visibility of the specified control.
     * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.
     * @param {Boolean} visible true to set the specified control visible, false otherwise
     * @return {fabric.Object} thisArg
     * @chainable
     */
    setControlVisible: function(controlName, visible) {
      this._getControlsVisibility()[controlName] = visible;
      return this;
    },

    /**
     * Sets the visibility state of object controls.
     * @param {Object} [options] Options object
     * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it
     * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it
     * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it
     * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it
     * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it
     * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it
     * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it
     * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it
     * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it
     * @return {fabric.Object} thisArg
     * @chainable
     */
    setControlsVisibility: function(options) {
      options || (options = { });

      for (var p in options) {
        this.setControlVisible(p, options[p]);
      }
      return this;
    },

    /**
     * Returns the instance of the control visibility set for this object.
     * @private
     * @returns {Object}
     */
    _getControlsVisibility: function() {
      if (!this._controlsVisibility) {
        this._controlsVisibility = {
          tl: true,
          tr: true,
          br: true,
          bl: true,
          ml: true,
          mt: true,
          mr: true,
          mb: true,
          mtr: true
        };
      }
      return this._controlsVisibility;
    }
  });
})();
<|endoftext|>


<commit_before>(function(angular, _ , toastr){
    "use strict";

    /**
     * @ngdoc module
     *
     * @name mfl.chul.controllers
     *
     * @description
     * Contains the controller used in CHU views
     */
    angular.module("mfl.chul.controllers", [
        "mfl.chul.services",
        "mfl.rating.services",
        "mfl.facility_filter.services"
    ])

    /**
     * @ngdoc controller
     *
     * @name mfl.chul.controllers.view
     *
     * @description
     * Controller for the CHU detail view
     */
    .controller("mfl.chul.controllers.view", ["$scope","mfl.chul.services.wrappers","$stateParams",
        "gisAdminUnitsApi","leafletData", "mfl.rating.services.rating", "$window", "$state",
        "api.auth",
        function ($scope,wrappers,$stateParams,gisAdminUnitsApi,leafletData,
            ratingService, $window, $state, auth) {
            $scope.tooltip = {
                "title": "",
                "checked": false
            };
            $scope.spinner = true;
            /*Setup for map data*/
            angular.extend($scope, {
                defaults: {
                    scrollWheelZoom: false
                },
                layers:{},
                tiles:{
                    openstreetmap: {
                        url: "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                        options: {
                            opacity: 0.7,
                            attribution: "© OpenStreetMap contributors"
                        }
                    }
                }
            });

            /*CHU rating*/
            $scope.rating = [
                {
                    current: 0,
                    max: 5
                }
            ];
            $scope.getSelectedRating = function (rating, id) {
                $scope.cu_rating = {
                    cu_id : id,
                    rating : rating
                };
            };
            $scope.getUnitRating = function () {
                wrappers.chul.get($stateParams.unit_id,
                    {"fields" : "avg_rating,number_of_ratings"})
                .success(function (data) {
                    $scope.unit.avg_rating = data.avg_rating;
                    $scope.unit.number_of_ratings = data.number_of_ratings;
                })
                .error(function (data) {
                    $scope.alert = data;
                });
            };
            $scope.rateCU = function (unit) {
                $scope.chu_rating = {
                    chu : unit.id,
                    rating : unit.ratings[0].current,
                    comment : unit.ratings[0].comment
                };
                $scope.unit.spinner = true;
                wrappers.chul_ratings.create($scope.chu_rating)
                .success(function (data) {
                    //save rating in localStorage
                    var rating_val = [];
                    rating_val[0] = data.rating;
                    rating_val[1] = data.comment;
                    $scope.unit.spinner = false;
                    ratingService.storeRating(unit.id, rating_val);
                    $scope.getUnitRating();
                    toastr.success("Successfully rated");
                    $state.go("chul_view", {unit_id : unit.id},{reload: true});
                })
                .error(function () {
                    $scope.unit.spinner = false;
                    $scope.alert = "CHU can only be rated once a day";
                    toastr.error($scope.alert);
                });
            };
            $scope.printCU = function (unit_id) {
                var download_params = {
                    "format": "pdf",
                    "access_token": auth.getToken().access_token
                };
                $scope.file_url = wrappers.helpers.joinUrl([
                    wrappers.chul_pdf.makeUrl(wrappers.chul_pdf.apiBaseUrl),
                    unit_id, "/",
                    wrappers.helpers.makeGetParam(
                        wrappers.helpers.makeParams(download_params)
                    )
                ]);
            };
            $scope.unit_id = $stateParams.unit_id;
            $scope.printCU($scope.unit_id);
            wrappers.chul.get($stateParams.unit_id)
            .success(function (unit) {
                $scope.spinner = false;
                $scope.unit = unit;
                var current_rate = "";
                current_rate = ratingService.getRating($stateParams.unit_id);
                $scope.unit.ratings = [
                    {
                        current: current_rate ? current_rate[0] : 0,
                        max: 5
                    }
                ];
                /*ward coordinates*/
                gisAdminUnitsApi.ward.get(unit.ward_code)
                .success(function(data){
                    $scope.spinner = false;
                    $scope.ward_gis = data;
                    leafletData.getMap("wardmap")
                        .then(function (map) {
                            var coords = data.properties.bound.coordinates[0];
                            var bounds = _.map(coords, function(c) {
                                return [c[1], c[0]];
                            });
                            map.fitBounds(bounds);
                        });
                    var gis = data;
                    angular.extend($scope, {
                        markers: {
                            mainMarker: {
                                layer:"facility",
                                lat: unit.geo_features.geometry.coordinates[1],
                                lng: unit.geo_features.geometry.coordinates[0],
                                message: "Facility location"
                            }
                        },
                        geojson: {
                            data: gis,
                            style: {
                                fillColor: "rgb(255, 135, 32)",
                                weight: 2,
                                opacity: 1,
                                color: "rgba(0, 0, 0, 0.52)",
                                dashArray: "3",
                                fillOpacity: 0.8
                            }
                        },
                        layers:{
                            baselayers:{
                                ward: {
                                    name: "Ward",
                                    url: "/assets/img/transparent.png",
                                    type:"group"
                                }
                            },
                            overlays:{
                                facility:{
                                    name:"Facility Location",
                                    type:"group",
                                    visible: true
                                }
                            }
                        }
                    });
                })
                .error(function(error){
                    console.error(error);
                });
            })
            .error(function (error) {
                $scope.spinner = false;
                $scope.alert = error;
            });
        }
    ])

    /**
     * @ngdoc controller
     *
     * @name mfl.chul.controllers.search_form
     *
     * @description
     * Controller for the search form in CHU advanced search
     */
    .controller("mfl.chul.controllers.search_form",
        ["$stateParams", "$scope", "$state", "$location",
        "mfl.chul.services.wrappers", "CHU_SEARCH_PARAMS",
        function ($stateParams, $scope, $state, $location, wrappers, CHU_SEARCH_PARAMS) {
            $scope.filters = {
                single: {
                    name: "",
                    code: "",
                    search: ""
                },
                multiple: {
                    county: [],
                    constituency: [],
                    ward: [],
                    status: []
                }
            };

            var updateSingleFilters = function (params) {
                // update single inputs
                _.each(_.keys($scope.filters.single), function (a) {
                    $scope.filters.single[a] = params[a] || "";
                });
            };
            updateSingleFilters($stateParams);
            var updateMultipleFilters = function (params, filter_summaries) {
                // update ui-select inputs
                _.each(_.keys($scope.filters.multiple),function (a) {
                    var val = params[a];
                    if (val) {
                        $scope.filters.multiple[a] = _.filter(
                            filter_summaries[a],
                            function (b) {
                                return val.indexOf(b.id) !== -1;
                            }
                        );
                    }
                });

                // update ui-select with relationships
                var relationships = [
                    {child: "ward", parent: "constituency"},
                    {child: "constituency", parent: "county"}
                ];
                _.each(relationships, function (r) {
                    _.each($scope.filters.multiple[r.child], function (w) {
                        var x = _.findWhere(filter_summaries[r.parent], {"id": w[r.parent]});
                        if (!_.isUndefined(x)) {
                            $scope.filters.multiple[r.parent].push(x);
                        }
                    });
                });

                // remove duplicates in ui-select repeat sources
                _.each(_.keys($scope.filters.multiple), function (a) {
                    $scope.filters.multiple[a] = _.uniq($scope.filters.multiple[a]);
                });
            };

            $scope.filterFxns = {
                constFilter: function (a) {
                    var county_ids = _.pluck($scope.filters.multiple.county, "id");
                    return _.contains(county_ids, a.county);
                },
                wardFilter: function (a) {
                    var const_ids = _.pluck($scope.filters.multiple.constituency, "id");
                    return _.contains(const_ids, a.constituency);
                }
            };

            wrappers.filters.filter({"fields": ["county", "constituency", "ward", "chu_status"]})
            .success(function (data) {
                $scope.filter_summaries = data;
                $scope.filter_summaries.status = $scope.filter_summaries.chu_status;
                updateMultipleFilters($stateParams, data);
            });

            var dumpMultipleFilters = function (src) {
                return _.reduce(_.keys(src), function (memo, b) {
                    memo[b] = _.pluck(src[b], "id").join(",");
                    return memo;
                }, {});
            };

            var dumpSingleFilters = function (src) {
                var k = _.keys(src);
                return _.reduce(k, function (memo, b) {
                    memo[b] = src[b];
                    return memo;
                }, {});
            };

            $scope.filterCHUs = function () {
                var multiple = dumpMultipleFilters($scope.filters.multiple);
                var single = dumpSingleFilters($scope.filters.single);
                var params = _.extend(single, multiple);
                params.page = undefined;
                params.page_size = undefined;
                $state.go("chul_filter.results", params);
            };

            $scope.clearFilters = function () {
                var params = {};
                _.each(CHU_SEARCH_PARAMS, function (a) {
                    params[a] = undefined;
                });
                $state.go("chul_filter", params);
            };
        }]
    )

    /**
     * @ngdoc controller
     *
     * @name mfl.chul.controllers.search_results
     *
     * @description
     * Controller for the results part of CHU advanced search
     */
    .controller("mfl.chul.controllers.search_results",
        ["$scope", "$state", "$window", "filterParams",
        "mfl.chul.services.wrappers", "api.auth",
        function ($scope, $state, $window, filterParams, wrappers, auth) {
            var filter_keys = _.keys(filterParams);
            var params = _.reduce(filter_keys, function (memo, b) {
                if (filterParams[b]) {
                    memo[b] = filterParams[b];
                }
                return memo;
            }, {
                "fields": "id,code,name,status_name,date_established,facility,facility_name," +
                          "facility_county,facility_subcounty,facility_ward"
            });

            // transform search param into a query DSL
            if (params.search) {
                var dsl = {
                    "query": { }
                };
                if (_.isNaN(parseInt(params.search, 10))) {
                    dsl.query.query_string = {
                        "default_field": "name",
                        "query": params.search
                    };
                } else {
                    dsl.query.term = {
                        "code": params.search
                    };
                }
                params.search = JSON.stringify(dsl);
            }

            $scope.spinner = true;
            $scope.filter_promise = wrappers.chul.filter(params)
            .success(function (data) {
                $scope.spinner = false;
                $scope.results = data;
            })
            .error(function (e) {
                $scope.alert = e.detail ||
                               "Sorry, a server connection error occured.";
                $scope.spinner = false;
            });

            $scope.excelExport = function () {
                var download_params = {
                    "format": "excel",
                    "access_token": auth.getToken().access_token,
                    "page_size": $scope.results.count
                };
                _.extend(download_params, _.omit(params, "page"));

                var helpers = wrappers.helpers;
                var url = helpers.joinUrl([
                    wrappers.chul.makeUrl(wrappers.chul.apiBaseUrl),
                    helpers.makeGetParam(helpers.makeParams(download_params))
                ]);

                $window.location.href = url;
            };

            $scope.nextPage = function () {
                if ($scope.results.total_pages === $scope.results.current_page) {
                    return;
                }
                params.page = $scope.results.current_page + 1 ;
                $state.go("chul_filter.results", params);
            };

            $scope.prevPage = function () {
                if ($scope.results.current_page === 1) {
                    return;
                }
                params.page = $scope.results.current_page - 1;
                $state.go("chul_filter.results", params);
            };
        }]
    );
})(window.angular,window._, window.toastr);
<commit_msg>Fix coordinates for linked facility<commit_after>(function(angular, _ , toastr){
    "use strict";

    /**
     * @ngdoc module
     *
     * @name mfl.chul.controllers
     *
     * @description
     * Contains the controller used in CHU views
     */
    angular.module("mfl.chul.controllers", [
        "mfl.chul.services",
        "mfl.rating.services",
        "mfl.facility_filter.services"
    ])

    /**
     * @ngdoc controller
     *
     * @name mfl.chul.controllers.view
     *
     * @description
     * Controller for the CHU detail view
     */
    .controller("mfl.chul.controllers.view", ["$scope","mfl.chul.services.wrappers","$stateParams",
        "gisAdminUnitsApi","leafletData", "mfl.rating.services.rating", "$window", "$state",
        "api.auth",
        function ($scope,wrappers,$stateParams,gisAdminUnitsApi,leafletData,
            ratingService, $window, $state, auth) {
            $scope.tooltip = {
                "title": "",
                "checked": false
            };
            $scope.spinner = true;
            /*Setup for map data*/
            angular.extend($scope, {
                defaults: {
                    scrollWheelZoom: false
                },
                layers:{},
                tiles:{
                    openstreetmap: {
                        url: "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
                        options: {
                            opacity: 0.7,
                            attribution: "© OpenStreetMap contributors"
                        }
                    }
                }
            });

            /*CHU rating*/
            $scope.rating = [
                {
                    current: 0,
                    max: 5
                }
            ];
            $scope.getSelectedRating = function (rating, id) {
                $scope.cu_rating = {
                    cu_id : id,
                    rating : rating
                };
            };
            $scope.getUnitRating = function () {
                wrappers.chul.get($stateParams.unit_id,
                    {"fields" : "avg_rating,number_of_ratings"})
                .success(function (data) {
                    $scope.unit.avg_rating = data.avg_rating;
                    $scope.unit.number_of_ratings = data.number_of_ratings;
                })
                .error(function (data) {
                    $scope.alert = data;
                });
            };
            $scope.rateCU = function (unit) {
                $scope.chu_rating = {
                    chu : unit.id,
                    rating : unit.ratings[0].current,
                    comment : unit.ratings[0].comment
                };
                $scope.unit.spinner = true;
                wrappers.chul_ratings.create($scope.chu_rating)
                .success(function (data) {
                    //save rating in localStorage
                    var rating_val = [];
                    rating_val[0] = data.rating;
                    rating_val[1] = data.comment;
                    $scope.unit.spinner = false;
                    ratingService.storeRating(unit.id, rating_val);
                    $scope.getUnitRating();
                    toastr.success("Successfully rated");
                    $state.go("chul_view", {unit_id : unit.id},{reload: true});
                })
                .error(function () {
                    $scope.unit.spinner = false;
                    $scope.alert = "CHU can only be rated once a day";
                    toastr.error($scope.alert);
                });
            };
            $scope.printCU = function (unit_id) {
                var download_params = {
                    "format": "pdf",
                    "access_token": auth.getToken().access_token
                };
                $scope.file_url = wrappers.helpers.joinUrl([
                    wrappers.chul_pdf.makeUrl(wrappers.chul_pdf.apiBaseUrl),
                    unit_id, "/",
                    wrappers.helpers.makeGetParam(
                        wrappers.helpers.makeParams(download_params)
                    )
                ]);
            };
            $scope.unit_id = $stateParams.unit_id;
            $scope.printCU($scope.unit_id);
            wrappers.chul.get($stateParams.unit_id)
            .success(function (unit) {
                $scope.spinner = false;
                $scope.unit = unit;
                var current_rate = "";
                current_rate = ratingService.getRating($stateParams.unit_id);
                $scope.unit.ratings = [
                    {
                        current: current_rate ? current_rate[0] : 0,
                        max: 5
                    }
                ];
                /*ward coordinates*/
                gisAdminUnitsApi.ward.get(unit.ward_code)
                .success(function(data){
                    $scope.spinner = false;
                    $scope.ward_gis = data;
                    leafletData.getMap("wardmap")
                        .then(function (map) {
                            var coords = data.properties.bound.coordinates[0];
                            var bounds = _.map(coords, function(c) {
                                return [c[1], c[0]];
                            });
                            map.fitBounds(bounds);
                        });
                    var gis = data;
                    angular.extend($scope, {
                        markers: {
                            mainMarker: {
                                layer:"facility",
                                lat: unit.lat_long[0],
                                lng: unit.lat_long[1],
                                message: "Facility location"
                            }
                        },
                        geojson: {
                            data: gis,
                            style: {
                                fillColor: "rgb(255, 135, 32)",
                                weight: 2,
                                opacity: 1,
                                color: "rgba(0, 0, 0, 0.52)",
                                dashArray: "3",
                                fillOpacity: 0.8
                            }
                        },
                        layers:{
                            baselayers:{
                                ward: {
                                    name: "Ward",
                                    url: "/assets/img/transparent.png",
                                    type:"group"
                                }
                            },
                            overlays:{
                                facility:{
                                    name:"Facility Location",
                                    type:"group",
                                    visible: true
                                }
                            }
                        }
                    });
                })
                .error(function(error){
                    console.error(error);
                });
            })
            .error(function (error) {
                $scope.spinner = false;
                $scope.alert = error;
            });
        }
    ])

    /**
     * @ngdoc controller
     *
     * @name mfl.chul.controllers.search_form
     *
     * @description
     * Controller for the search form in CHU advanced search
     */
    .controller("mfl.chul.controllers.search_form",
        ["$stateParams", "$scope", "$state", "$location",
        "mfl.chul.services.wrappers", "CHU_SEARCH_PARAMS",
        function ($stateParams, $scope, $state, $location, wrappers, CHU_SEARCH_PARAMS) {
            $scope.filters = {
                single: {
                    name: "",
                    code: "",
                    search: ""
                },
                multiple: {
                    county: [],
                    constituency: [],
                    ward: [],
                    status: []
                }
            };

            var updateSingleFilters = function (params) {
                // update single inputs
                _.each(_.keys($scope.filters.single), function (a) {
                    $scope.filters.single[a] = params[a] || "";
                });
            };
            updateSingleFilters($stateParams);
            var updateMultipleFilters = function (params, filter_summaries) {
                // update ui-select inputs
                _.each(_.keys($scope.filters.multiple),function (a) {
                    var val = params[a];
                    if (val) {
                        $scope.filters.multiple[a] = _.filter(
                            filter_summaries[a],
                            function (b) {
                                return val.indexOf(b.id) !== -1;
                            }
                        );
                    }
                });

                // update ui-select with relationships
                var relationships = [
                    {child: "ward", parent: "constituency"},
                    {child: "constituency", parent: "county"}
                ];
                _.each(relationships, function (r) {
                    _.each($scope.filters.multiple[r.child], function (w) {
                        var x = _.findWhere(filter_summaries[r.parent], {"id": w[r.parent]});
                        if (!_.isUndefined(x)) {
                            $scope.filters.multiple[r.parent].push(x);
                        }
                    });
                });

                // remove duplicates in ui-select repeat sources
                _.each(_.keys($scope.filters.multiple), function (a) {
                    $scope.filters.multiple[a] = _.uniq($scope.filters.multiple[a]);
                });
            };

            $scope.filterFxns = {
                constFilter: function (a) {
                    var county_ids = _.pluck($scope.filters.multiple.county, "id");
                    return _.contains(county_ids, a.county);
                },
                wardFilter: function (a) {
                    var const_ids = _.pluck($scope.filters.multiple.constituency, "id");
                    return _.contains(const_ids, a.constituency);
                }
            };

            wrappers.filters.filter({"fields": ["county", "constituency", "ward", "chu_status"]})
            .success(function (data) {
                $scope.filter_summaries = data;
                $scope.filter_summaries.status = $scope.filter_summaries.chu_status;
                updateMultipleFilters($stateParams, data);
            });

            var dumpMultipleFilters = function (src) {
                return _.reduce(_.keys(src), function (memo, b) {
                    memo[b] = _.pluck(src[b], "id").join(",");
                    return memo;
                }, {});
            };

            var dumpSingleFilters = function (src) {
                var k = _.keys(src);
                return _.reduce(k, function (memo, b) {
                    memo[b] = src[b];
                    return memo;
                }, {});
            };

            $scope.filterCHUs = function () {
                var multiple = dumpMultipleFilters($scope.filters.multiple);
                var single = dumpSingleFilters($scope.filters.single);
                var params = _.extend(single, multiple);
                params.page = undefined;
                params.page_size = undefined;
                $state.go("chul_filter.results", params);
            };

            $scope.clearFilters = function () {
                var params = {};
                _.each(CHU_SEARCH_PARAMS, function (a) {
                    params[a] = undefined;
                });
                $state.go("chul_filter", params);
            };
        }]
    )

    /**
     * @ngdoc controller
     *
     * @name mfl.chul.controllers.search_results
     *
     * @description
     * Controller for the results part of CHU advanced search
     */
    .controller("mfl.chul.controllers.search_results",
        ["$scope", "$state", "$window", "filterParams",
        "mfl.chul.services.wrappers", "api.auth",
        function ($scope, $state, $window, filterParams, wrappers, auth) {
            var filter_keys = _.keys(filterParams);
            var params = _.reduce(filter_keys, function (memo, b) {
                if (filterParams[b]) {
                    memo[b] = filterParams[b];
                }
                return memo;
            }, {
                "fields": "id,code,name,status_name,date_established,facility,facility_name," +
                          "facility_county,facility_subcounty,facility_ward"
            });

            // transform search param into a query DSL
            if (params.search) {
                var dsl = {
                    "query": { }
                };
                if (_.isNaN(parseInt(params.search, 10))) {
                    dsl.query.query_string = {
                        "default_field": "name",
                        "query": params.search
                    };
                } else {
                    dsl.query.term = {
                        "code": params.search
                    };
                }
                params.search = JSON.stringify(dsl);
            }

            $scope.spinner = true;
            $scope.filter_promise = wrappers.chul.filter(params)
            .success(function (data) {
                $scope.spinner = false;
                $scope.results = data;
            })
            .error(function (e) {
                $scope.alert = e.detail ||
                               "Sorry, a server connection error occured.";
                $scope.spinner = false;
            });

            $scope.excelExport = function () {
                var download_params = {
                    "format": "excel",
                    "access_token": auth.getToken().access_token,
                    "page_size": $scope.results.count
                };
                _.extend(download_params, _.omit(params, "page"));

                var helpers = wrappers.helpers;
                var url = helpers.joinUrl([
                    wrappers.chul.makeUrl(wrappers.chul.apiBaseUrl),
                    helpers.makeGetParam(helpers.makeParams(download_params))
                ]);

                $window.location.href = url;
            };

            $scope.nextPage = function () {
                if ($scope.results.total_pages === $scope.results.current_page) {
                    return;
                }
                params.page = $scope.results.current_page + 1 ;
                $state.go("chul_filter.results", params);
            };

            $scope.prevPage = function () {
                if ($scope.results.current_page === 1) {
                    return;
                }
                params.page = $scope.results.current_page - 1;
                $state.go("chul_filter.results", params);
            };
        }]
    );
})(window.angular,window._, window.toastr);
<|endoftext|>


<commit_before>'use strict';

var mongoose = require('mongoose'),
    extend   = require('util')._extend;

module.exports = exports = function (schema, options) {
    if (!options || !options.languages || !Array.isArray(options.languages) || !options.languages.length) {
        throw new mongoose.Error('Required languages array is missing');
    }

    var pluginOptions = {};
    pluginOptions.languages = options.languages.slice(0);

    // the first available language will be used as default if it's not set or unknown value passed
    if (!options.defaultLanguage || pluginOptions.languages.indexOf(options.defaultLanguage) === -1) {
        pluginOptions.defaultLanguage = pluginOptions.languages[0];
    } else {
        pluginOptions.defaultLanguage = options.defaultLanguage.slice(0);
    }

    schema.eachPath(function (path, schemaType) {
        if (!schemaType.options.intl) {
            return;
        }

        if (!(schemaType instanceof mongoose.Schema.Types.String)) {
            throw new mongoose.Error('Mongoose-intl plugin can be used with String type only');
        }

        var pathArray = path.split('.'),
            key       = pathArray.pop(),
            prefix    = pathArray.join('.');

        if (prefix) prefix += '.';

        // removing real path, it will be changed to virtual later
        schema.remove(path);

        // schema.remove removes path from paths object only, but doesn't update tree
        // sounds like a bug, removing item from the tree manually
        var tree = pathArray.reduce(function (mem, part) {
            return mem[part];
        }, schema.tree);
        delete tree[key];

        schema.virtual(path)
            .get(function (param) {
                return param[pluginOptions.defaultLanguage];
            })
            .set(function (value) {
                this.set(path + '.' + pluginOptions.defaultLanguage, value);
            });

        schema.virtual(path + '.all')
            .get(function () {
                return this.getValue(path);
            })
            .set(function (value) {
                pluginOptions.languages.forEach(function (lang) {
                    if (!value[lang]) { return; }
                    this.set(path + '.' + lang, value[lang]);
                }, this);
            });

        // intl option is not needed for the current path any more,
        // and is unwanted for all child lang-properties
        delete schemaType.options.intl;

        var intlObject = {};
        intlObject[key] = {};
        pluginOptions.languages.forEach(function (lang) {
            var langOptions = extend({}, schemaType.options);
            if (lang !== options.defaultLanguage) {
                delete langOptions.default;
                delete langOptions.required;
            }

            if (schemaType.options.defaultAll) {
                langOptions.default = schemaType.options.defaultAll;
            }

            if (schemaType.options.requiredAll) {
                langOptions.required = schemaType.options.requiredAll;
            }
            this[lang] = langOptions;
        }, intlObject[key]);

        // intlObject example:
        // { fieldName: {
        //     en: '',
        //     de: ''
        // }}
        schema.add(intlObject, prefix);
    });

    schema.method({
        getLanguages: function () {
            return pluginOptions.languages;
        },
        getDefaultLanguage: function () {
            return pluginOptions.defaultLanguage;
        },
        setDefaultLanguage: function (lang) {
            if (lang && pluginOptions.languages.indexOf(lang) !== -1) {
                pluginOptions.defaultLanguage = lang.slice(0);
            }
        }
    });
};
<commit_msg>plugin propagation to sub-documents schemas<commit_after>'use strict';

var mongoose = require('mongoose'),
    extend   = require('util')._extend;

module.exports = exports = function mongooseIntl(schema, options) {
    if (!options || !options.languages || !Array.isArray(options.languages) || !options.languages.length) {
        throw new mongoose.Error('Required languages array is missing');
    }

    // plugin options to be set under schema options
    schema.options.mongooseIntl = {};
    var pluginOptions = schema.options.mongooseIntl;

    pluginOptions.languages = options.languages.slice(0);

    // the first available language will be used as default if it's not set or unknown value passed
    if (!options.defaultLanguage || pluginOptions.languages.indexOf(options.defaultLanguage) === -1) {
        pluginOptions.defaultLanguage = pluginOptions.languages[0];
    } else {
        pluginOptions.defaultLanguage = options.defaultLanguage.slice(0);
    }

    schema.eachPath(function (path, schemaType) {
        if (schemaType.schema) { // propagate plugin initialization for sub-documents schemas
            schemaType.schema.plugin(mongooseIntl, pluginOptions);
            return;
        }

        if (!schemaType.options.intl) {
            return;
        }

        if (!(schemaType instanceof mongoose.Schema.Types.String)) {
            throw new mongoose.Error('Mongoose-intl plugin can be used with String type only');
        }

        var pathArray = path.split('.'),
            key       = pathArray.pop(),
            prefix    = pathArray.join('.');

        if (prefix) prefix += '.';

        // removing real path, it will be changed to virtual later
        schema.remove(path);

        // schema.remove removes path from paths object only, but doesn't update tree
        // sounds like a bug, removing item from the tree manually
        var tree = pathArray.reduce(function (mem, part) {
            return mem[part];
        }, schema.tree);
        delete tree[key];

        schema.virtual(path)
            .get(function (param) {
                return param[pluginOptions.defaultLanguage];
            })
            .set(function (value) {
                this.set(path + '.' + pluginOptions.defaultLanguage, value);
            });

        schema.virtual(path + '.all')
            .get(function () {
                return this.getValue(path);
            })
            .set(function (value) {
                pluginOptions.languages.forEach(function (lang) {
                    if (!value[lang]) { return; }
                    this.set(path + '.' + lang, value[lang]);
                }, this);
            });

        // intl option is not needed for the current path any more,
        // and is unwanted for all child lang-properties
        delete schemaType.options.intl;

        var intlObject = {};
        intlObject[key] = {};
        pluginOptions.languages.forEach(function (lang) {
            var langOptions = extend({}, schemaType.options);
            if (lang !== options.defaultLanguage) {
                delete langOptions.default;
                delete langOptions.required;
            }

            if (schemaType.options.defaultAll) {
                langOptions.default = schemaType.options.defaultAll;
            }

            if (schemaType.options.requiredAll) {
                langOptions.required = schemaType.options.requiredAll;
            }
            this[lang] = langOptions;
        }, intlObject[key]);

        // intlObject example:
        // { fieldName: {
        //     en: '',
        //     de: ''
        // }}
        schema.add(intlObject, prefix);
    });

    schema.method({
        getLanguages: function () {
            return this.schema.options.mongooseIntl.languages;
        },
        getDefaultLanguage: function () {
            return this.schema.options.mongooseIntl.defaultLanguage;
        },
        setDefaultLanguage: function (lang) {

            function updateLanguage(schema, lang) {
                schema.options.mongooseIntl.defaultLanguage = lang.slice(0);

                // default language change for sub-documents schemas
                schema.eachPath(function (path, schemaType) {
                    if (schemaType.schema) {
                        updateLanguage(schemaType.schema, lang);
                    }
                });

            }
            if (lang && this.schema.options.mongooseIntl.languages.indexOf(lang) !== -1) {
                updateLanguage(this.schema, lang);
            }
        }
    });
};
<|endoftext|>


<commit_before>const { resolve } = require('path')

const { test, tearDown } = require('tap')
const proxyquire = require('proxyquire').noCallThru()

const jobPath = resolve.bind(null, __dirname, '../../jobs')

test('worker throws away unimplemented job', async t => {
  t.plan(2)

  const worker = require('../../lib/worker')

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'unimplemented-job' }))
    }
  )
})

test('worker throws away unimplemented job action', async t => {
  t.plan(2)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('unimplemented-job')]: () => {
      throw new Error('not implemented')
    }
  })

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'unimplemented-job' }))
    }
  )
})

test('worker requeues job on error, then throws away', async t => {
  t.plan(3)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('failing-job')]: () => {
      throw new Error('something went wrong')
    }
  })

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: t.pass
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-job' })),
      fields: {}
    }
  )

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-job' })),
      fields: {
        redelivered: true
      }
    }
  )
})

test('worker acks job on success w/o further work', async t => {
  t.plan(1)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('successful-job')]: () => {}
  })

  await worker(
    t.fail,
    {
      ack: t.pass,
      nack: t.fail
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'successful-job' }))
    }
  )
})

test('worker schedules further jobs on success', async t => {
  t.plan(4)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('successful-job')]: () => [
      {
        data: true,
        plan: 'free'
      },
      {
        data: true,
        plan: 'supporter'
      },
      {
        data: true
      },
      {
        data: false
      }
    ]
  })

  await worker(
    t.pass,
    {
      ack: t.pass,
      nack: t.fail
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'successful-job' }))
    }
  )
})

test('worker requeues job on scheduling error, then throws away', async t => {
  t.plan(3)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('failing-schedule')]: () => [
      {
        data: true
      },
      {
        data: true
      }
    ]
  })

  await worker(
    () => {
      throw new Error('scheduling fail')
    },
    {
      ack: t.fail,
      nack: t.pass
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-schedule' })),
      fields: {}
    }
  )

  await worker(
    () => {
      throw new Error('scheduling fail')
    },
    {
      ack: t.pass,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-schedule' })),
      fields: {
        redelivered: true
      }
    }
  )
})

tearDown(() => require('../../lib/statsd').close())
<commit_msg>test(worker): add accountId to job data<commit_after>const { resolve } = require('path')

const { test, tearDown } = require('tap')
const proxyquire = require('proxyquire').noCallThru()

const jobPath = resolve.bind(null, __dirname, '../../jobs')

test('worker throws away unimplemented job', async t => {
  t.plan(2)

  const worker = require('../../lib/worker')

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'unimplemented-job' }))
    }
  )
})

test('worker throws away unimplemented job action', async t => {
  t.plan(2)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('unimplemented-job')]: () => {
      throw new Error('not implemented')
    }
  })

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'unimplemented-job', accountId: 123 }))
    }
  )
})

test('worker requeues job on error, then throws away', async t => {
  t.plan(3)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('failing-job')]: () => {
      throw new Error('something went wrong')
    }
  })

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: t.pass
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-job', accountId: 123 })),
      fields: {}
    }
  )

  await worker(
    t.fail,
    {
      ack: t.fail,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-job', accountId: 123 })),
      fields: {
        redelivered: true
      }
    }
  )
})

test('worker acks job on success w/o further work', async t => {
  t.plan(1)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('successful-job')]: () => {}
  })

  await worker(
    t.fail,
    {
      ack: t.pass,
      nack: t.fail
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'successful-job', repository: { owner: { id: 111 }, full_name: 'testOrg/testRepo' } }))
    }
  )
})

test('worker schedules further jobs on success', async t => {
  t.plan(4)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('successful-job')]: () => [
      {
        data: true,
        plan: 'free'
      },
      {
        data: true,
        plan: 'supporter'
      },
      {
        data: true
      },
      {
        data: false
      }
    ]
  })

  await worker(
    t.pass,
    {
      ack: t.pass,
      nack: t.fail
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'successful-job', accountId: 234 }))
    }
  )
})

test('worker requeues job on scheduling error, then throws away', async t => {
  t.plan(3)

  const worker = proxyquire('../../lib/worker', {
    [jobPath('failing-schedule')]: () => [
      {
        data: true
      },
      {
        data: true
      }
    ]
  })

  await worker(
    () => {
      throw new Error('scheduling fail')
    },
    {
      ack: t.fail,
      nack: t.pass
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-schedule', accountId: 233 })),
      fields: {}
    }
  )

  await worker(
    () => {
      throw new Error('scheduling fail')
    },
    {
      ack: t.pass,
      nack: (job, allUpTo, requeue) => {
        t.notOk(allUpTo)
        t.notOk(requeue)
      }
    },
    {
      content: Buffer.from(JSON.stringify({ name: 'failing-schedule', accountId: 344 })),
      fields: {
        redelivered: true
      }
    }
  )
})

tearDown(() => require('../../lib/statsd').close())
<|endoftext|>


<commit_before>// web analytics configuration
module.exports = {
  //ANALYTICS SETTINGS
  google: {
    enabled: true,
    key: 'UA-48605964-17'
  },
  piwik: {
    enabled: false,
    host: '',
    key: ''
  }
};
<commit_msg>Added DAP configuration option values.<commit_after>// web analytics configuration
module.exports = {
  //ANALYTICS SETTINGS
  google: {
    enabled: true,
    key: 'UA-48605964-17'
  },
  piwik: {
    enabled: false,
    host: '',
    key: ''
  },
  dap: {
    enabled: true,
    source: 'https://dvs6mwdoj87wa.cloudfront.net/dap.min.js'
  }
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule RichTextEditorUtil
 * @typechecks
 * @flow
 */

'use strict';

import type ContentState from 'ContentState';
import type {DraftBlockType} from 'DraftBlockType';
import type {DraftEditorCommand} from 'DraftEditorCommand';
import type URI from 'URI';

const DraftModifier = require('DraftModifier');
const EditorState = require('EditorState');
const SelectionState = require('SelectionState');

const adjustBlockDepthForContentState = require('adjustBlockDepthForContentState');
const nullthrows = require('nullthrows');

const RichTextEditorUtil = {
  currentBlockContainsLink: function(
    editorState: EditorState,
  ): boolean {
    var selection = editorState.getSelection();
    const contentState = editorState.getCurrentContent();
    const entityMap = contentState.getEntityMap();
    return contentState
      .getBlockForKey(selection.getAnchorKey())
      .getCharacterList()
      .slice(selection.getStartOffset(), selection.getEndOffset())
      .some(v => {
        var entity = v.getEntity();
        return !!entity && entityMap.__get(entity).getType() === 'LINK';
      });
  },

  getCurrentBlockType: function(editorState: EditorState): DraftBlockType {
    var selection = editorState.getSelection();
    return editorState.getCurrentContent()
      .getBlockForKey(selection.getStartKey())
      .getType();
  },

  getDataObjectForLinkURL: function(uri: URI): Object {
    return {url: uri.toString()};
  },

  handleKeyCommand: function(
    editorState: EditorState,
    command: DraftEditorCommand | string,
  ): ?EditorState {
    switch (command) {
      case 'bold':
        return RichTextEditorUtil.toggleInlineStyle(editorState, 'BOLD');
      case 'italic':
        return RichTextEditorUtil.toggleInlineStyle(editorState, 'ITALIC');
      case 'underline':
        return RichTextEditorUtil.toggleInlineStyle(editorState, 'UNDERLINE');
      case 'code':
        return RichTextEditorUtil.toggleCode(editorState);
      case 'backspace':
      case 'backspace-word':
      case 'backspace-to-start-of-line':
        return RichTextEditorUtil.onBackspace(editorState);
      case 'delete':
      case 'delete-word':
      case 'delete-to-end-of-block':
        return RichTextEditorUtil.onDelete(editorState);
      default: // they may have custom editor commands; ignore those
        return null;
    }
  },

  insertSoftNewline: function(editorState: EditorState): EditorState {
    var contentState = DraftModifier.insertText(
      editorState.getCurrentContent(),
      editorState.getSelection(),
      '\n',
      editorState.getCurrentInlineStyle(),
      null,
    );

    var newEditorState = EditorState.push(
      editorState,
      contentState,
      'insert-characters',
    );

    return EditorState.forceSelection(
      newEditorState,
      contentState.getSelectionAfter(),
    );
  },

  /**
   * For collapsed selections at the start of styled blocks, backspace should
   * just remove the existing style.
   */
  onBackspace: function(editorState: EditorState): ?EditorState {
    var selection = editorState.getSelection();
    if (
      !selection.isCollapsed() ||
      selection.getAnchorOffset() ||
      selection.getFocusOffset()
    ) {
      return null;
    }

    // First, try to remove a preceding atomic block.
    var content = editorState.getCurrentContent();
    var startKey = selection.getStartKey();
    var blockBefore = content.getBlockBefore(startKey);

    if (blockBefore && blockBefore.getType() === 'atomic') {
      const blockMap = content.getBlockMap().delete(blockBefore.getKey());
      var withoutAtomicBlock = content.merge(
        {blockMap, selectionAfter: selection},
      );
      if (withoutAtomicBlock !== content) {
        return EditorState.push(
          editorState,
          withoutAtomicBlock,
          'remove-range',
        );
      }
    }

    // If that doesn't succeed, try to remove the current block style.
    var withoutBlockStyle = RichTextEditorUtil.tryToRemoveBlockStyle(
      editorState,
    );

    if (withoutBlockStyle) {
      return EditorState.push(
        editorState,
        withoutBlockStyle,
        'change-block-type',
      );
    }

    return null;
  },

  onDelete: function(editorState: EditorState): ?EditorState {
    const selection = editorState.getSelection();
    if (!selection.isCollapsed()) {
      return null;
    }

    const content = editorState.getCurrentContent();
    const startKey = selection.getStartKey();
    const block = content.getBlockForKey(startKey);
    const length = block.getLength();

    // The cursor is somewhere within the text. Behave normally.
    if (selection.getStartOffset() < length) {
      return null;
    }

    const blockAfter = content.getBlockAfter(startKey);

    if (!blockAfter || blockAfter.getType() !== 'atomic') {
      return null;
    }

    const atomicBlockTarget = selection.merge({
      focusKey: blockAfter.getKey(),
      focusOffset: blockAfter.getLength(),
    });

    const withoutAtomicBlock = DraftModifier.removeRange(
      content,
      atomicBlockTarget,
      'forward',
    );

    if (withoutAtomicBlock !== content) {
      return EditorState.push(
        editorState,
        withoutAtomicBlock,
        'remove-range',
      );
    }

    return null;
  },

  onTab: function(
    event: SyntheticKeyboardEvent,
    editorState: EditorState,
    maxDepth: number,
  ): EditorState {
    var selection = editorState.getSelection();
    var key = selection.getAnchorKey();
    if (key !== selection.getFocusKey()) {
      return editorState;
    }

    var content = editorState.getCurrentContent();
    var block = content.getBlockForKey(key);
    var type = block.getType();
    if (type !== 'unordered-list-item' && type !== 'ordered-list-item') {
      return editorState;
    }

    event.preventDefault();

    // Only allow indenting one level beyond the block above, and only if
    // the block above is a list item as well.
    var blockAbove = content.getBlockBefore(key);
    if (!blockAbove) {
      return editorState;
    }

    var typeAbove = blockAbove.getType();
    if (
      typeAbove !== 'unordered-list-item' &&
      typeAbove !== 'ordered-list-item'
    ) {
      return editorState;
    }

    var depth = block.getDepth();
    if (!event.shiftKey && depth === maxDepth) {
      return editorState;
    }

    maxDepth = Math.min(blockAbove.getDepth() + 1, maxDepth);

    var withAdjustment = adjustBlockDepthForContentState(
      content,
      selection,
      event.shiftKey ? -1 : 1,
      maxDepth,
    );

    return EditorState.push(
      editorState,
      withAdjustment,
      'adjust-depth',
    );
  },

  toggleBlockType: function(
    editorState: EditorState,
    blockType: DraftBlockType,
  ): EditorState {
    var selection = editorState.getSelection();
    var startKey = selection.getStartKey();
    var endKey = selection.getEndKey();
    var content = editorState.getCurrentContent();
    var target = selection;

    // Triple-click can lead to a selection that includes offset 0 of the
    // following block. The `SelectionState` for this case is accurate, but
    // we should avoid toggling block type for the trailing block because it
    // is a confusing interaction.
    if (startKey !== endKey && selection.getEndOffset() === 0) {
      var blockBefore = nullthrows(content.getBlockBefore(endKey));
      endKey = blockBefore.getKey();
      target = target.merge({
        anchorKey: startKey,
        anchorOffset: selection.getStartOffset(),
        focusKey: endKey,
        focusOffset: blockBefore.getLength(),
        isBackward: false,
      });
    }

    var hasAtomicBlock = content.getBlockMap()
      .skipWhile((_, k) => k !== startKey)
      .reverse()
      .skipWhile((_, k) => k !== endKey)
      .some(v => v.getType() === 'atomic');

    if (hasAtomicBlock) {
      return editorState;
    }

    var typeToSet = content.getBlockForKey(startKey).getType() === blockType ?
      'unstyled' :
      blockType;

    return EditorState.push(
      editorState,
      DraftModifier.setBlockType(content, target, typeToSet),
      'change-block-type',
    );
  },

  toggleCode: function(editorState: EditorState): EditorState {
    var selection = editorState.getSelection();
    var anchorKey = selection.getAnchorKey();
    var focusKey = selection.getFocusKey();

    if (selection.isCollapsed() || anchorKey !== focusKey) {
      return RichTextEditorUtil.toggleBlockType(editorState, 'code-block');
    }

    return RichTextEditorUtil.toggleInlineStyle(editorState, 'CODE');
  },

  /**
   * Toggle the specified inline style for the selection. If the
   * user's selection is collapsed, apply or remove the style for the
   * internal state. If it is not collapsed, apply the change directly
   * to the document state.
   */
  toggleInlineStyle: function(
    editorState: EditorState,
    inlineStyle: string,
  ): EditorState {
    var selection = editorState.getSelection();
    var currentStyle = editorState.getCurrentInlineStyle();

    // If the selection is collapsed, toggle the specified style on or off and
    // set the result as the new inline style override. This will then be
    // used as the inline style for the next character to be inserted.
    if (selection.isCollapsed()) {
      return EditorState.setInlineStyleOverride(
        editorState,
        currentStyle.has(inlineStyle)
          ? currentStyle.remove(inlineStyle)
          : currentStyle.add(inlineStyle),
      );
    }

    // If characters are selected, immediately apply or remove the
    // inline style on the document state itself.
    var content = editorState.getCurrentContent();
    var newContent;

    // If the style is already present for the selection range, remove it.
    // Otherwise, apply it.
    if (currentStyle.has(inlineStyle)) {
      newContent = DraftModifier.removeInlineStyle(
        content,
        selection,
        inlineStyle,
      );
    } else {
      newContent = DraftModifier.applyInlineStyle(
        content,
        selection,
        inlineStyle,
      );
    }

    return EditorState.push(
      editorState,
      newContent,
      'change-inline-style',
    );
  },

  toggleLink: function(
    editorState: EditorState,
    targetSelection: SelectionState,
    entityKey: ?string,
  ): EditorState {
    var withoutLink = DraftModifier.applyEntity(
      editorState.getCurrentContent(),
      targetSelection,
      entityKey,
    );

    return EditorState.push(
      editorState,
      withoutLink,
      'apply-entity',
    );
  },

  /**
   * When a collapsed cursor is at the start of an empty styled block, allow
   * certain key commands (newline, backspace) to simply change the
   * style of the block instead of the default behavior.
   */
  tryToRemoveBlockStyle: function(editorState: EditorState): ?ContentState {
    var selection = editorState.getSelection();
    var offset = selection.getAnchorOffset();
    if (selection.isCollapsed() && offset === 0) {
      var key = selection.getAnchorKey();
      var content = editorState.getCurrentContent();
      var block = content.getBlockForKey(key);
      if (block.getLength() > 0) {
        return null;
      }

      var type = block.getType();
      var blockBefore = content.getBlockBefore(key);
      if (
        type === 'code-block' &&
        blockBefore &&
        blockBefore.getType() === 'code-block'
      ) {
        return null;
      }

      if (type !== 'unstyled') {
        return DraftModifier.setBlockType(content, selection, 'unstyled');
      }
    }
    return null;
  },
};

module.exports = RichTextEditorUtil;
<commit_msg>Clarify comment above `tryToRemoveBlockStyle`<commit_after>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule RichTextEditorUtil
 * @typechecks
 * @flow
 */

'use strict';

import type ContentState from 'ContentState';
import type {DraftBlockType} from 'DraftBlockType';
import type {DraftEditorCommand} from 'DraftEditorCommand';
import type URI from 'URI';

const DraftModifier = require('DraftModifier');
const EditorState = require('EditorState');
const SelectionState = require('SelectionState');

const adjustBlockDepthForContentState = require('adjustBlockDepthForContentState');
const nullthrows = require('nullthrows');

const RichTextEditorUtil = {
  currentBlockContainsLink: function(
    editorState: EditorState,
  ): boolean {
    var selection = editorState.getSelection();
    const contentState = editorState.getCurrentContent();
    const entityMap = contentState.getEntityMap();
    return contentState
      .getBlockForKey(selection.getAnchorKey())
      .getCharacterList()
      .slice(selection.getStartOffset(), selection.getEndOffset())
      .some(v => {
        var entity = v.getEntity();
        return !!entity && entityMap.__get(entity).getType() === 'LINK';
      });
  },

  getCurrentBlockType: function(editorState: EditorState): DraftBlockType {
    var selection = editorState.getSelection();
    return editorState.getCurrentContent()
      .getBlockForKey(selection.getStartKey())
      .getType();
  },

  getDataObjectForLinkURL: function(uri: URI): Object {
    return {url: uri.toString()};
  },

  handleKeyCommand: function(
    editorState: EditorState,
    command: DraftEditorCommand | string,
  ): ?EditorState {
    switch (command) {
      case 'bold':
        return RichTextEditorUtil.toggleInlineStyle(editorState, 'BOLD');
      case 'italic':
        return RichTextEditorUtil.toggleInlineStyle(editorState, 'ITALIC');
      case 'underline':
        return RichTextEditorUtil.toggleInlineStyle(editorState, 'UNDERLINE');
      case 'code':
        return RichTextEditorUtil.toggleCode(editorState);
      case 'backspace':
      case 'backspace-word':
      case 'backspace-to-start-of-line':
        return RichTextEditorUtil.onBackspace(editorState);
      case 'delete':
      case 'delete-word':
      case 'delete-to-end-of-block':
        return RichTextEditorUtil.onDelete(editorState);
      default: // they may have custom editor commands; ignore those
        return null;
    }
  },

  insertSoftNewline: function(editorState: EditorState): EditorState {
    var contentState = DraftModifier.insertText(
      editorState.getCurrentContent(),
      editorState.getSelection(),
      '\n',
      editorState.getCurrentInlineStyle(),
      null,
    );

    var newEditorState = EditorState.push(
      editorState,
      contentState,
      'insert-characters',
    );

    return EditorState.forceSelection(
      newEditorState,
      contentState.getSelectionAfter(),
    );
  },

  /**
   * For collapsed selections at the start of styled blocks, backspace should
   * just remove the existing style.
   */
  onBackspace: function(editorState: EditorState): ?EditorState {
    var selection = editorState.getSelection();
    if (
      !selection.isCollapsed() ||
      selection.getAnchorOffset() ||
      selection.getFocusOffset()
    ) {
      return null;
    }

    // First, try to remove a preceding atomic block.
    var content = editorState.getCurrentContent();
    var startKey = selection.getStartKey();
    var blockBefore = content.getBlockBefore(startKey);

    if (blockBefore && blockBefore.getType() === 'atomic') {
      const blockMap = content.getBlockMap().delete(blockBefore.getKey());
      var withoutAtomicBlock = content.merge(
        {blockMap, selectionAfter: selection},
      );
      if (withoutAtomicBlock !== content) {
        return EditorState.push(
          editorState,
          withoutAtomicBlock,
          'remove-range',
        );
      }
    }

    // If that doesn't succeed, try to remove the current block style.
    var withoutBlockStyle = RichTextEditorUtil.tryToRemoveBlockStyle(
      editorState,
    );

    if (withoutBlockStyle) {
      return EditorState.push(
        editorState,
        withoutBlockStyle,
        'change-block-type',
      );
    }

    return null;
  },

  onDelete: function(editorState: EditorState): ?EditorState {
    const selection = editorState.getSelection();
    if (!selection.isCollapsed()) {
      return null;
    }

    const content = editorState.getCurrentContent();
    const startKey = selection.getStartKey();
    const block = content.getBlockForKey(startKey);
    const length = block.getLength();

    // The cursor is somewhere within the text. Behave normally.
    if (selection.getStartOffset() < length) {
      return null;
    }

    const blockAfter = content.getBlockAfter(startKey);

    if (!blockAfter || blockAfter.getType() !== 'atomic') {
      return null;
    }

    const atomicBlockTarget = selection.merge({
      focusKey: blockAfter.getKey(),
      focusOffset: blockAfter.getLength(),
    });

    const withoutAtomicBlock = DraftModifier.removeRange(
      content,
      atomicBlockTarget,
      'forward',
    );

    if (withoutAtomicBlock !== content) {
      return EditorState.push(
        editorState,
        withoutAtomicBlock,
        'remove-range',
      );
    }

    return null;
  },

  onTab: function(
    event: SyntheticKeyboardEvent,
    editorState: EditorState,
    maxDepth: number,
  ): EditorState {
    var selection = editorState.getSelection();
    var key = selection.getAnchorKey();
    if (key !== selection.getFocusKey()) {
      return editorState;
    }

    var content = editorState.getCurrentContent();
    var block = content.getBlockForKey(key);
    var type = block.getType();
    if (type !== 'unordered-list-item' && type !== 'ordered-list-item') {
      return editorState;
    }

    event.preventDefault();

    // Only allow indenting one level beyond the block above, and only if
    // the block above is a list item as well.
    var blockAbove = content.getBlockBefore(key);
    if (!blockAbove) {
      return editorState;
    }

    var typeAbove = blockAbove.getType();
    if (
      typeAbove !== 'unordered-list-item' &&
      typeAbove !== 'ordered-list-item'
    ) {
      return editorState;
    }

    var depth = block.getDepth();
    if (!event.shiftKey && depth === maxDepth) {
      return editorState;
    }

    maxDepth = Math.min(blockAbove.getDepth() + 1, maxDepth);

    var withAdjustment = adjustBlockDepthForContentState(
      content,
      selection,
      event.shiftKey ? -1 : 1,
      maxDepth,
    );

    return EditorState.push(
      editorState,
      withAdjustment,
      'adjust-depth',
    );
  },

  toggleBlockType: function(
    editorState: EditorState,
    blockType: DraftBlockType,
  ): EditorState {
    var selection = editorState.getSelection();
    var startKey = selection.getStartKey();
    var endKey = selection.getEndKey();
    var content = editorState.getCurrentContent();
    var target = selection;

    // Triple-click can lead to a selection that includes offset 0 of the
    // following block. The `SelectionState` for this case is accurate, but
    // we should avoid toggling block type for the trailing block because it
    // is a confusing interaction.
    if (startKey !== endKey && selection.getEndOffset() === 0) {
      var blockBefore = nullthrows(content.getBlockBefore(endKey));
      endKey = blockBefore.getKey();
      target = target.merge({
        anchorKey: startKey,
        anchorOffset: selection.getStartOffset(),
        focusKey: endKey,
        focusOffset: blockBefore.getLength(),
        isBackward: false,
      });
    }

    var hasAtomicBlock = content.getBlockMap()
      .skipWhile((_, k) => k !== startKey)
      .reverse()
      .skipWhile((_, k) => k !== endKey)
      .some(v => v.getType() === 'atomic');

    if (hasAtomicBlock) {
      return editorState;
    }

    var typeToSet = content.getBlockForKey(startKey).getType() === blockType ?
      'unstyled' :
      blockType;

    return EditorState.push(
      editorState,
      DraftModifier.setBlockType(content, target, typeToSet),
      'change-block-type',
    );
  },

  toggleCode: function(editorState: EditorState): EditorState {
    var selection = editorState.getSelection();
    var anchorKey = selection.getAnchorKey();
    var focusKey = selection.getFocusKey();

    if (selection.isCollapsed() || anchorKey !== focusKey) {
      return RichTextEditorUtil.toggleBlockType(editorState, 'code-block');
    }

    return RichTextEditorUtil.toggleInlineStyle(editorState, 'CODE');
  },

  /**
   * Toggle the specified inline style for the selection. If the
   * user's selection is collapsed, apply or remove the style for the
   * internal state. If it is not collapsed, apply the change directly
   * to the document state.
   */
  toggleInlineStyle: function(
    editorState: EditorState,
    inlineStyle: string,
  ): EditorState {
    var selection = editorState.getSelection();
    var currentStyle = editorState.getCurrentInlineStyle();

    // If the selection is collapsed, toggle the specified style on or off and
    // set the result as the new inline style override. This will then be
    // used as the inline style for the next character to be inserted.
    if (selection.isCollapsed()) {
      return EditorState.setInlineStyleOverride(
        editorState,
        currentStyle.has(inlineStyle)
          ? currentStyle.remove(inlineStyle)
          : currentStyle.add(inlineStyle),
      );
    }

    // If characters are selected, immediately apply or remove the
    // inline style on the document state itself.
    var content = editorState.getCurrentContent();
    var newContent;

    // If the style is already present for the selection range, remove it.
    // Otherwise, apply it.
    if (currentStyle.has(inlineStyle)) {
      newContent = DraftModifier.removeInlineStyle(
        content,
        selection,
        inlineStyle,
      );
    } else {
      newContent = DraftModifier.applyInlineStyle(
        content,
        selection,
        inlineStyle,
      );
    }

    return EditorState.push(
      editorState,
      newContent,
      'change-inline-style',
    );
  },

  toggleLink: function(
    editorState: EditorState,
    targetSelection: SelectionState,
    entityKey: ?string,
  ): EditorState {
    var withoutLink = DraftModifier.applyEntity(
      editorState.getCurrentContent(),
      targetSelection,
      entityKey,
    );

    return EditorState.push(
      editorState,
      withoutLink,
      'apply-entity',
    );
  },

  /**
   * When a collapsed cursor is at the start of an empty styled block,
   * changes block to 'unstyled'. Returns null if block or selection does not
   * meet that criteria.
   */
  tryToRemoveBlockStyle: function(editorState: EditorState): ?ContentState {
    var selection = editorState.getSelection();
    var offset = selection.getAnchorOffset();
    if (selection.isCollapsed() && offset === 0) {
      var key = selection.getAnchorKey();
      var content = editorState.getCurrentContent();
      var block = content.getBlockForKey(key);
      if (block.getLength() > 0) {
        return null;
      }

      var type = block.getType();
      var blockBefore = content.getBlockBefore(key);
      if (
        type === 'code-block' &&
        blockBefore &&
        blockBefore.getType() === 'code-block'
      ) {
        return null;
      }

      if (type !== 'unstyled') {
        return DraftModifier.setBlockType(content, selection, 'unstyled');
      }
    }
    return null;
  },
};

module.exports = RichTextEditorUtil;
<|endoftext|>


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

var sparqlProxy = function (options) {
  return function (req, res, next) {
    var
      headers = {'Accept': req.headers.accept, 'Content-Type': 'application/sparql-query'},
      query;

    if (req.method === 'GET') {
      query = req.query.query;
    } else if (req.method === 'POST') {
      if ('query' in req.body) {
        query = req.body.query;
      } else {
        query = req.body;
      }
    } else {
      return next();
    }

    log.info({script: __filename}, 'handle SPARQL request for endpoint: ' + options.endpointUrl);
    log.debug({script: __filename}, 'SPARQL query:' + query);

    request
      .post(options.endpointUrl, {headers: headers, body: query})
      .pipe(res);
  };
};

module.exports = sparqlProxy;<commit_msg>support different query operations in SPARQL proxy<commit_after>
var
  request = require('request');

var directPost = function (req, res, endpointUrl, query) {
  headers = {'Accept': req.headers.accept, 'Content-Type': 'application/sparql-query'};

  request
    .post(endpointUrl, {headers: headers, body: query})
    .pipe(res);
}

var urlencodedPost = function (req, res, endpointUrl, query) {
  var headers = {'Accept': req.headers.accept, 'Content-Type': 'application/x-www-form-urlencoded'};

  request
    .post(endpointUrl, {headers: headers, form: {query: query}})
    .pipe(res);
}

var sparqlProxy = function (options) {
  return function (req, res, next) {
    var query;

    if (req.method === 'GET') {
      query = req.query.query;
    } else if (req.method === 'POST') {
      if ('query' in req.body) {
        query = req.body.query;
      } else {
        query = req.body;
      }
    } else {
      return next();
    }

    log.info({script: __filename}, 'handle SPARQL request for endpoint: ' + options.endpointUrl);
    log.debug({script: __filename}, 'SPARQL query:' + query);

    switch(options.queryOperation) {
      case 'urlencoded':
        return urlencodedPost(req, res, options.endpointUrl, query)
      default:
        return directPost(req, res, options.endpointUrl, query)
    }
  };
};

module.exports = sparqlProxy;<|endoftext|>


<commit_before>var Filter = require('broccoli-filter');

function HtmlbarsMinifier(inputTree) {
    if (!(this instanceof HtmlbarsMinifier)) {
        return new HtmlbarsMinifier(inputTree);
    }

    Filter.call(this, inputTree);

    this.inputTree = inputTree;
}

HtmlbarsMinifier.prototype = Object.create(Filter.prototype);
HtmlbarsMinifier.prototype.constructor = HtmlbarsMinifier;
HtmlbarsMinifier.prototype.extensions = ['hbs'];
HtmlbarsMinifier.prototype.targetExtension = 'hbs';
HtmlbarsMinifier.prototype.processString = function (str) {
    str = str.replace(/{{(#|\/|else)/g, '{{~$1');
    str = str.replace(/\s{2,}/g, ' ');
    str = str.replace(/>\s*([^\s])/g, '>$1');
    str = str.replace(/([^\s])\s*</g, '$1<');
    str = str.replace(/}}\s*</g, '}}<');
    str = str.replace(/>\s*{{/g, '>{{');
    str = str.replace(/^\s*/, '');
    str = str.replace(/\s*$/, '');
    str = str.replace(/(<.+?>[^<>]*?}})(\s*)({{[^<>]*?<.+?>)/g, '$1$3');

    return str;
};

module.exports = HtmlbarsMinifier;<commit_msg>Rules documentation<commit_after>var Filter = require('broccoli-filter');

function HtmlbarsMinifier(inputTree) {
    if (!(this instanceof HtmlbarsMinifier)) {
        return new HtmlbarsMinifier(inputTree);
    }

    Filter.call(this, inputTree);

    this.inputTree = inputTree;
}

HtmlbarsMinifier.prototype = Object.create(Filter.prototype);
HtmlbarsMinifier.prototype.constructor = HtmlbarsMinifier;
HtmlbarsMinifier.prototype.extensions = ['hbs'];
HtmlbarsMinifier.prototype.targetExtension = 'hbs';
HtmlbarsMinifier.prototype.processString = function (str) {
    str = str
        // Replaces:
        //   - {{#foo}} => {{~#foo}}
        //   - {{/foo}} => {{~/foo}}
        .replace(/{{(#|\/|else)/g, '{{~$1')

        // Replaces:
        //   - "       " => " "
        .replace(/\s{2,}/g, ' ')

        // Replaces:
        //   - ">           foo" => ">foo"
        .replace(/>\s+/g, '>')

        // Replaces:
        //   - "foo           <" => "foo<"
        .replace(/\s+</g, '<')

        // Replaces:
        //   - "}}      <" => "}}<"
        .replace(/}}\s+</g, '}}<')

        // Replaces:
        //   - ">      {{" => ">{{"
        .replace(/>\s+{{/g, '>{{')

        // Replaces:
        //   - "     foo" => "foo"
        .replace(/^\s+/, '')

        // Replaces:
        //   - "foo     " => "foo"
        .replace(/\s+$/, '')

        // Replaces:
        //   - "<foo>{{bar}}            {{bar}}</foo>" => "<foo>{{bar}}{{bar}}</foo>"
        .replace(/(<.+?>[^<>]*?}})(\s+)({{[^<>]*?<.+?>)/g, '$1$3');

    return str;
};

module.exports = HtmlbarsMinifier;<|endoftext|>