<commit_before>import ui.View as View;
import ui.ImageView as ImageView;
import src.constants.gameConstants as gameConstants;
import ui.TextView as TextView;
import ui.widget.ButtonView as ButtonView;
import src.lib.parseUtil as ParseUtil;
import ui.TextEditView as TextEditView;
import src.models.Donor as Donor;
import src.models.Donation as Donation;

exports = Class(View, function (supr) {

	this.init = function(opts) {

		opts = merge(opts, {
			x: 0,
			y: 0,
			width: gameConstants.GAME_WIDTH,
			height: gameConstants.GAME_HEIGHT,
			backgroundColor: '#ef6e07'
		});

		supr(this, 'init', [opts]);

		this.buildView();
	};

	this.buildView = function() {

		this.background = new ImageView({
			parent: this,
			x: 0,
			y: 0,
			width: gameConstants.GAME_WIDTH,
			height: 960,
			image: "resources/images/backgrounds/donation_bg.png",
			opacity: 1
		});

		/*this.TitleText = new TextView({
			parent: this,
			x: gameConstants.GAME_WIDTH / 2 - 180,
			y: 100,
			width: 350,
			height: 150,
			text: "Donate",
			fontFamily: gameConstants.MAIN_FONT,
			color: 'white',
			size: 50,
			canHandleEvents: false
		});*/

    	this.BackButton = new ButtonView({
		    superview: this,
		    width: 80,
		    height: 80,
		    x: 480,
		    y: 10,
		    images: {
		      up: "resources/images/buttons/close_button.png"
		      //down: "resources/images/buttons/brown_button_down.png"
		    },
		    on: {
		      up: bind(this, function () {
		      		this.emit('Back');
				})
		    }
    	});

    	this.selectOneView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 35,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedTwoDollarView.hide();
		      		this.selectedFiveDollarView.hide();
		      		this.selectedTenDollarView.hide();
		      		this.selectedOneDollarView.show();
				})
		    }
    	});

    	this.selectTwoView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 159,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedOneDollarView.hide();
		      		this.selectedFiveDollarView.hide();
		      		this.selectedTenDollarView.hide();
		      		this.selectedTwoDollarView.show();
				})
		    }
    	});

    	this.selectFiveView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 293,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedOneDollarView.hide();
		      		this.selectedTwoDollarView.hide();
		      		this.selectedTenDollarView.hide();
		      		this.selectedFiveDollarView.show();
				})
		    }
    	});

    	this.selectTenView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 417,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedOneDollarView.hide();
		      		this.selectedTwoDollarView.hide();
		      		this.selectedFiveDollarView.hide();
		      		this.selectedTenDollarView.show();
				})
		    }
    	});

    	this.selectedOneDollarView = new ImageView({
    		parent: this,
			x: 35,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/one_selected.png",
			opacity: 1
    	});

    	this.selectedTwoDollarView = new ImageView({
    		parent: this,
			x: 159,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/two_selected.png",
			opacity: 1
    	});

    	this.selectedFiveDollarView = new ImageView({
    		parent: this,
			x: 293,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/five_selected.png",
			opacity: 1
    	});

		this.selectedTenDollarView = new ImageView({
    		parent: this,
			x: 417,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/ten_selected.png",
			opacity: 1
    	});

		this.customAmountEditView = new TextEditView({
			superview: this,
			x: 30,
			y: 425,
			//backgroundColor: "#ffffff",
			width: 456,
			height: 80,
			fontWeight: "bold",
			//horizontalAlign: "center",
			color: "#ffffff",
			hintColor: "#ffffff",
			hint: "Enter Custom Amount"
		});

		this.emailEditView = new TextEditView({
			superview: this,
			x: 30,
			y: 530,
			//backgroundColor: "#ffffff",
			width: 456,
			height: 80,
			fontWeight: "bold",
			//horizontalAlign: "center",
			color: "#ef7c21",
			hintColor: "#ef7c21",
			hint: "Enter Email"
		});

    	this.donateButton = new ButtonView({
			superview: this,
			width: 190,
			height: 125,
			x: gameConstants.GAME_WIDTH / 2 - 100,
			y: 670,
			images: {
				up: "resources/images/buttons/donate_button.png"
				//down: "resources/images/buttons/brown_button_down.png"
			},
			on: {
				up: bind(this, function () {
					var email = this.emailEditView.getText(),
						donor = GLOBAL.gameData.donorCollection.modelWithId(email);
					function saveDonation() {
						GLOBAL.gameData.donationCollection.add(new Donation({
							amount: 2,
							time: (new Date()).toString(),
							student: GLOBAL.gameData.student.get('id'),
							donor: email
						}));
						GLOBAL.gameData.donationCollection.save(function () {
							this.emit('Back');
						}.bind(this));
					}
					if (!donor) {
						GLOBAL.gameData.donorCollection.add(donor = new Donor({
							id: email,
							name: email.substring(0, email.indexOf('@'))
						}));
						GLOBAL.gameData.donorCollection.save(function () {
							saveDonation.call(this);
						}.bind(this));
					} else {
						saveDonation.call(this);
					}
				})
			}
		});
	};
});
<commit_msg>Hooked up donation amounts<commit_after>import ui.View as View;
import ui.ImageView as ImageView;
import src.constants.gameConstants as gameConstants;
import ui.TextView as TextView;
import ui.widget.ButtonView as ButtonView;
import src.lib.parseUtil as ParseUtil;
import ui.TextEditView as TextEditView;
import src.models.Donor as Donor;
import src.models.Donation as Donation;

exports = Class(View, function (supr) {

	this.init = function(opts) {

		opts = merge(opts, {
			x: 0,
			y: 0,
			width: gameConstants.GAME_WIDTH,
			height: gameConstants.GAME_HEIGHT,
			backgroundColor: '#ef6e07'
		});

		supr(this, 'init', [opts]);

		this.buildView();
	};

	this.buildView = function() {

		this.background = new ImageView({
			parent: this,
			x: 0,
			y: 0,
			width: gameConstants.GAME_WIDTH,
			height: 960,
			image: "resources/images/backgrounds/donation_bg.png",
			opacity: 1
		});

		/*this.TitleText = new TextView({
			parent: this,
			x: gameConstants.GAME_WIDTH / 2 - 180,
			y: 100,
			width: 350,
			height: 150,
			text: "Donate",
			fontFamily: gameConstants.MAIN_FONT,
			color: 'white',
			size: 50,
			canHandleEvents: false
		});*/

    	this.BackButton = new ButtonView({
		    superview: this,
		    width: 80,
		    height: 80,
		    x: 480,
		    y: 10,
		    images: {
		      up: "resources/images/buttons/close_button.png"
		      //down: "resources/images/buttons/brown_button_down.png"
		    },
		    on: {
		      up: bind(this, function () {
		      		this.emit('Back');
				})
		    }
    	});

    	this.selectOneView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 35,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedTwoDollarView.hide();
		      		this.selectedFiveDollarView.hide();
		      		this.selectedTenDollarView.hide();
		      		this.selectedOneDollarView.show();
					this._selectedAmount = 1;
				})
		    }
    	});

    	this.selectTwoView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 159,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedOneDollarView.hide();
		      		this.selectedFiveDollarView.hide();
		      		this.selectedTenDollarView.hide();
		      		this.selectedTwoDollarView.show();
					this._selectedAmount = 2;
				})
		    }
    	});

    	this.selectFiveView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 293,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedOneDollarView.hide();
		      		this.selectedTwoDollarView.hide();
		      		this.selectedTenDollarView.hide();
		      		this.selectedFiveDollarView.show();
					this._selectedAmount = 5;
				})
		    }
    	});

    	this.selectTenView = new ButtonView({
    		superview: this,
    		width: 124,
    		height: 139,
    		x: 417,
    		y: 240,
		    on: {
		      up: bind(this, function () {
		      		this.selectedOneDollarView.hide();
		      		this.selectedTwoDollarView.hide();
		      		this.selectedFiveDollarView.hide();
		      		this.selectedTenDollarView.show();
					this._selectedAmount = 10;
				})
		    }
    	});

    	this.selectedOneDollarView = new ImageView({
    		parent: this,
			x: 35,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/one_selected.png",
			opacity: 1
    	});

    	this.selectedTwoDollarView = new ImageView({
    		parent: this,
			x: 159,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/two_selected.png",
			opacity: 1
    	});

    	this.selectedFiveDollarView = new ImageView({
    		parent: this,
			x: 293,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/five_selected.png",
			opacity: 1
    	});

		this.selectedTenDollarView = new ImageView({
    		parent: this,
			x: 417,
			y: 240,
			width: 124,
			height: 139,
			visible: false,
			image: "resources/images/donation/ten_selected.png",
			opacity: 1
    	});

		this.customAmountEditView = new TextEditView({
			superview: this,
			x: 30,
			y: 425,
			//backgroundColor: "#ffffff",
			width: 456,
			height: 80,
			fontWeight: "bold",
			//horizontalAlign: "center",
			color: "#ffffff",
			hintColor: "#ffffff",
			hint: "Enter Custom Amount"
		});

		this.emailEditView = new TextEditView({
			superview: this,
			x: 30,
			y: 530,
			//backgroundColor: "#ffffff",
			width: 456,
			height: 80,
			fontWeight: "bold",
			//horizontalAlign: "center",
			color: "#ef7c21",
			hintColor: "#ef7c21",
			hint: "Enter Email"
		});

    	this.donateButton = new ButtonView({
			superview: this,
			width: 190,
			height: 125,
			x: gameConstants.GAME_WIDTH / 2 - 100,
			y: 670,
			images: {
				up: "resources/images/buttons/donate_button.png"
				//down: "resources/images/buttons/brown_button_down.png"
			},
			on: {
				up: bind(this, function () {
					var email = this.emailEditView.getText(),
						donor = GLOBAL.gameData.donorCollection.modelWithId(email);
					function saveDonation() {
						GLOBAL.gameData.donationCollection.add(new Donation({
							amount: this._selectedAmount,
							time: (new Date()).toString(),
							student: GLOBAL.gameData.student.get('id'),
							donor: email
						}));
						GLOBAL.gameData.donationCollection.save(function () {
							this.emit('Back');
						}.bind(this));
					}
					if (!donor) {
						GLOBAL.gameData.donorCollection.add(donor = new Donor({
							id: email,
							name: email.substring(0, email.indexOf('@'))
						}));
						GLOBAL.gameData.donorCollection.save(function () {
							saveDonation.call(this);
						}.bind(this));
					} else {
						saveDonation.call(this);
					}
				})
			}
		});
	};
});
<|endoftext|>


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

  /*
   * @ngdoc directive
   * @name horizon.framework.widgets.modal-wait-spinner.directive:waitSpinner
   * @description
   * A "global" wait spinner that displays a line of text followed by "...".
   *
   * Requires {@link http://angular-ui.github.io/bootstrap/ `Angular-bootstrap`}
   *
   * Used when the user must wait before any additional action is possible.  Can be
   * launched from modal dialogs.
   *
   * @example
   * <example>
   *

   *    angular
   *      .controller('MyController', MyController);
   *
   *    MyController.$inject = [
   *      '$scope',
   *      'horizon.framework.widgets.modal.modal-wait-spinner.service'
   *    ];
   *
   *    function MyController($scope, modalWaitSpinnerService) {
   *      $scope.showSpinner = function () {
   *        modalWaitSpinnerService.showModalSpinner(gettext("Loading"));
   *      }
   *
   *      $scope.hideSpinner = function () {
   *        modalWaitSpinnerService.hideModalSpinner();
   *      }
   *    }
   *

   * </example>
   */

  angular
    .module('horizon.framework.widgets.modal-wait-spinner')
    .directive('waitSpinner', waitSpinner);

  waitSpinner.$inject = ['horizon.framework.conf.spinner_options'];

  function waitSpinner(spinnerOptions) {

    var directive = {
      scope: {
        text: '@text'   // One-direction binding (reads from parent)
      },
      restrict: 'A',
      link:     link,
      template: '
{$text$}…
'
    };

    return directive;

    ////////////////////

    /*
     * At the time link is executed, element may not have been sized by the browser.
     * Spin.js may mistakenly places the spinner at 50% of 0 (left:0, top:0). To work around
     * this, explicitly set 50% left and top to center the spinner in the parent
     * container
     */
    function link(scope, element) {
      element.spin(spinnerOptions.modal);
      element.find('.spinner').css({'left': '50%', 'top': '50%'});
    }
  }
})();
<commit_msg>Fix documentation of angular modal spinner<commit_after>(function () {
  'use strict';

  /*
   * @ngdoc directive
   * @name horizon.framework.widgets.modal-wait-spinner.directive:waitSpinner
   * @description
   * A "global" wait spinner that displays a line of text followed by "...".
   *
   * Requires {@link http://angular-ui.github.io/bootstrap/ `Angular-bootstrap`}
   *
   * Used when the user must wait before any additional action is possible.  Can be
   * launched from modal dialogs.
   *
   * @example
   * <example>
   *

   *    angular
   *      .controller('MyController', MyController);
   *
   *    MyController.$inject = [
   *      '$scope',
   *      'horizon.framework.widgets.modal-wait-spinner.service'
   *    ];
   *
   *    function MyController($scope, modalWaitSpinnerService) {
   *      $scope.showSpinner = function () {
   *        modalWaitSpinnerService.showModalSpinner(gettext("Loading"));
   *      }
   *
   *      $scope.hideSpinner = function () {
   *        modalWaitSpinnerService.hideModalSpinner();
   *      }
   *    }
   *

   * </example>
   */

  angular
    .module('horizon.framework.widgets.modal-wait-spinner')
    .directive('waitSpinner', waitSpinner);

  waitSpinner.$inject = ['horizon.framework.conf.spinner_options'];

  function waitSpinner(spinnerOptions) {

    var directive = {
      scope: {
        text: '@text'   // One-direction binding (reads from parent)
      },
      restrict: 'A',
      link:     link,
      template: '
{$text$}…
'
    };

    return directive;

    ////////////////////

    /*
     * At the time link is executed, element may not have been sized by the browser.
     * Spin.js may mistakenly places the spinner at 50% of 0 (left:0, top:0). To work around
     * this, explicitly set 50% left and top to center the spinner in the parent
     * container
     */
    function link(scope, element) {
      element.spin(spinnerOptions.modal);
      element.find('.spinner').css({'left': '50%', 'top': '50%'});
    }
  }
})();
<|endoftext|>


<commit_before>import { route } from './util';

route(/^\/spam-waves/, () => {
  const forExpiry = $('[for="expiry"]');
  const expiryInput = $('#expiry');
  const existingButton = $('.expiry-in-48-hours-button');
  if (forExpiry.length > 0 && expiryInput.length > 0 && existingButton.length === 0) {
    const new48HoursButton = $('<button class="expiry-in-48-hours-button">in 48 hours</button>').on('click', event => {
      const newExpire = new Date(Date.now() + 48 * 60 * 60 * 1000);
      newExpire.setMilliseconds(0);
      expiryInput.val(newExpire.toISOString().replace('.000Z', '+00.0'));
      event.preventDefault();
    })
      .css({ marginLeft: '10px' });
    forExpiry.after(new48HoursButton);
    const valCriteriaList = ['title', 'body', 'username', 'max_user_rep'];
    const newSearchButton = $('(Search)')
      .css({
        'font-size': '14px',
        'margin-left': '10px'
      });
    newSearchButton
      .find('a')
      .on('mousedown mouseover', function () {
        const criteriaInPage = valCriteriaList.map(key => [key, $(`#conditions_${key}${key.includes('rep') ? '' : '_regex'}`).val()]);
        const encodedCriteria = criteriaInPage.reduce((sum, [key, value]) => key === 'max_user_rep' ? sum + `&user_rep_direction=%3C%3D&user_reputation=${value}` : sum + `&${key}_is_regex=1&${key}=${encodeURIComponent(value)}`, '');
        const sitesSelect = $('#sites');
        const selectionInnerUlLi = sitesSelect.closest('.bootstrap-select').find('.inner.open ul.inner > li');
        const selectedSiteLi = selectionInnerUlLi.filter('.selected');
        let siteParameter = '';
        let siteOptions = $();
        if (selectionInnerUlLi.length === 0) {
          // The select dropdown has not been opened, so we get the <option selected="selected">
          siteOptions = sitesSelect.find('option[selected="selected"]');
        }
        else if (selectedSiteLi.length === 1) {
          // The site dropdown has been opened and populated and there's only one site selected.
          // Search only supports a single site, so we don't try to handle converting multiple selections.
          const site = selectedSiteLi.text().trim();
          siteOptions = sitesSelect.find('option').filter(function () {
            return this.textContent.trim() === site;
          });
        }
        if (siteOptions.length === 1) {
          // Search only supports a single site
          siteParameter = `&site=${siteOptions.val()}`;
        }
        const url = `https://metasmoke.erwaysoftware.com/search?utf8=%E2%9C%93${encodedCriteria}${siteParameter}`;
        $(this).attr('href', url);
      });
    $('h3:contains("Conditions")').append(newSearchButton);
  }
  $('[type="datetime-local"]').attr('type', 'datetime');
});
<commit_msg>Handle Unicode codepoint escapes translate Regexp -> search<commit_after>import { route } from './util';

route(/^\/spam-waves/, () => {
  const forExpiry = $('[for="expiry"]');
  const expiryInput = $('#expiry');
  const existingButton = $('.expiry-in-48-hours-button');
  if (forExpiry.length > 0 && expiryInput.length > 0 && existingButton.length === 0) {
    const new48HoursButton = $('<button class="expiry-in-48-hours-button">in 48 hours</button>').on('click', event => {
      const newExpire = new Date(Date.now() + 48 * 60 * 60 * 1000);
      newExpire.setMilliseconds(0);
      expiryInput.val(newExpire.toISOString().replace('.000Z', '+00.0'));
      event.preventDefault();
    })
      .css({ marginLeft: '10px' });
    forExpiry.after(new48HoursButton);
    const valCriteriaList = ['title', 'body', 'username', 'max_user_rep'];
    const newSearchButton = $('(Search)')
      .css({
        'font-size': '14px',
        'margin-left': '10px'
      });
    newSearchButton
      .find('a')
      .on('mousedown mouseover', function () {
        const criteriaInPage = valCriteriaList.map(key => [key, $(`#conditions_${key}${key.includes('rep') ? '' : '_regex'}`).val()]);
        const encodedCriteria = criteriaInPage.reduce((sum, [key, value]) => {
          if (key === 'max_user_rep') {
            return sum + `&user_rep_direction=%3C%3D&user_reputation=${value}`;
          } // Else
          // Convert the Unicode codepoint escapes from the format needed in spam waves to what's needed in search.
          value = value.replace(/\\u([\da-fA-F]{4})/g, '\\x{$1}');
          return sum + `&${key}_is_regex=1&${key}=${encodeURIComponent(value)}`;
        }, '');
        const sitesSelect = $('#sites');
        const selectionInnerUlLi = sitesSelect.closest('.bootstrap-select').find('.inner.open ul.inner > li');
        const selectedSiteLi = selectionInnerUlLi.filter('.selected');
        let siteParameter = '';
        let siteOptions = $();
        if (selectionInnerUlLi.length === 0) {
          // The select dropdown has not been opened, so we get the <option selected="selected">
          siteOptions = sitesSelect.find('option[selected="selected"]');
        }
        else if (selectedSiteLi.length === 1) {
          // The site dropdown has been opened and populated and there's only one site selected.
          // Search only supports a single site, so we don't try to handle converting multiple selections.
          const site = selectedSiteLi.text().trim();
          siteOptions = sitesSelect.find('option').filter(function () {
            return this.textContent.trim() === site;
          });
        }
        if (siteOptions.length === 1) {
          // Search only supports a single site
          siteParameter = `&site=${siteOptions.val()}`;
        }
        const url = `https://metasmoke.erwaysoftware.com/search?utf8=%E2%9C%93${encodedCriteria}${siteParameter}`;
        $(this).attr('href', url);
      });
    $('h3:contains("Conditions")').append(newSearchButton);
  }
  $('[type="datetime-local"]').attr('type', 'datetime');
});
<|endoftext|>


<commit_before>window.charts = window.charts || {};

charts.graphUrl; // /v1/users/... without query params
charts.dataPoints = [];

var getEventsFor = function (type, typeId, objectTags, actionTags, operation, period, shareToken, readToken) {
    return $.ajax({
        url: "/v1/" + type + "/" + typeId + "/events/" + objectTags + "/" + actionTags + "/" + operation + "/" + period + "/" + "type/json",
        data: {
            shareToken: shareToken,
            readToken: readToken
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    });
};

var plotChart = function (events) {
    if (renderType === "barchart") {
        if (events === null || events.length == 0) {
            $(".no-data").show();
        } else {
            charts.plotBarChart("#chart", events, null, null);
            $('.detailsSection').show();
            $('.share-button-container').show();
        }
    }
};

charts.addComment = function () {
    var commentText = $("#commentText").val();
    var comment = {
        text: commentText,
        user: username,
        avatarUrl: avatarUrl
    };
    var graph = {
        graphUrl: charts.graphUrl,
        dataPointDate: charts.selectedDate,
        username: graphOwner,
        objectTags: objectTags,
        actionTags: actionTags,
        operation: operation,
        period: period,
        renderType: renderType,
        comment: comment
    };
    $.ajax({
        url: "/v1/comments",
        method: "POST",
        data: graph,
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (data) {
        var displayedComment = {text: commentText, avatarUrl: graphOwnerAvatarUrl};
        var selectedDataPoint = _.find(charts.dataPoints, function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        });
        if (_.isEmpty(selectedDataPoint)) {
            var newDataPoint = {
                dataPointDate: charts.selectedDate,
                avatars: [graphOwnerAvatarUrl],
                comments: [displayedComment]
            };
            charts.dataPoints.push(newDataPoint);
        } else {
            selectedDataPoint.comments.push(displayedComment);
        }
        $(".commentList").append("

" +
            "

" + comment.text + "
" +
            "

");
        $("#commentText").val("");
    });
};

$("#addCommentInput").keyup(function (e) {
    if (e.keyCode == 13) {
        charts.addComment();
    }
});

var handleAddComment = function () {
    if (isUserLoggedIn) {
        $("#addCommentInput").show();
    }
    else {
        $("#loginModal").modal({show: true});
    }
};

var handleShareGraph = function () {
    var unregisteredUserOnStreamsPage = function () {
        return !isUserLoggedIn && (window.location.pathname.search("streams") !== -1);
    };

    if (isUserLoggedIn) {
        $.ajax({
            url: "/v1/graph/share?graphUrl=" + window.location.pathname,
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = " "+link+" ";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
                $("#shareModal").modal({show: true});
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    } else if (unregisteredUserOnStreamsPage()) {
        $("#loginModal").modal({show: true});
    } else {
        $.ajax({
            url: "/v1/graph/share?graphUrl=" + window.location.pathname,
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = ""+link+"";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    }
};

var showChartTitle = function () {
    $("#chartTitle").html(chartTitle);
    if (isUserLoggedIn) {
        $("#avatar").html("").addClass('avatar');
    }
    if (isUserLoggedIn || (!isUserLoggedIn && !(_.isEmpty(shareToken)))) {
        $.when(getEventsFor("users", graphOwner, objectTags, actionTags, operation, period, shareToken, readToken))
            .done(plotChart)
            .fail();
    } else {
        $.when(getEventsFor("streams", streamId, objectTags, actionTags, operation, period, shareToken, readToken))
            .done(plotChart)
            .fail();
    }
};

var submitShare = function () {
    var emailId = $("#emailId").val();
    var graphShareUrl = $("#graphShareLink").html();

    $.ajax({
        url: "/v1/share_graph",
        method: "POST",
        data: { graphShareUrl: graphShareUrl, toEmailId: emailId },
        success: function () {
            $(".shareEmailNoticeMessage").html("Graph link emailed successfully");
        },
        error: function () {
            alert("some problem. Please try again later.");
        }
    });
};

charts.showComments = function () {
    var commentsDiv = $(".commentList");
    commentsDiv.empty();

    charts.dataPoints
        .filter(function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        })
        .forEach(function (dataPoint) {
            dataPoint.comments.forEach(function (comment) {
                commentsDiv.append("

" +
                    "
" + comment.text + "

");
            });
        });
};

var displayCommentsSummary = function () {
    for (var i = 6; i >= 0; i--) {
        var currentDataPointDate = moment.utc().subtract(i, 'days').format("YYYY-MM-DD"); // "2014-11-14"
        var currentDataPoint = _.findWhere(charts.dataPoints, {"dataPointDate": currentDataPointDate});
        if (!_.isEmpty(currentDataPoint)) {
            var latest3Avatars = currentDataPoint.avatars.slice(0, 3);
            latest3Avatars.forEach(function (avatarUrl, j) {
                $("#group" + i + "-avatar" + j).css({'background-image': 'url(' + avatarUrl + ')'});
            });
            if (currentDataPoint.comments.length > 3) {
                $("#group" + i + "-commentCount").addClass("count").html(currentDataPoint.comments.length);
            }
        }
    }
};

$(document).ready(function () {
    showChartTitle();
    $.ajax({
        url: "/v1/comments",
        method: "GET",
        data: {
            username: graphOwner,
            objectTags: objectTags,
            actionTags: actionTags,
            operation: operation,
            period: period,
            renderType: renderType
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (comments) {
        charts.dataPoints = comments;
        displayCommentsSummary();
    });
    $("#shareSubmit").click(submitShare);

    var cw = $('.avatar_group').width();
    var ch = $(window).width() * (cw / 100);
    $('.avatar_group').css({'height': ch+'px'});
});
<commit_msg>Explicitly force show comments after 3s<commit_after>window.charts = window.charts || {};

charts.graphUrl; // /v1/users/... without query params
charts.dataPoints = [];

var getEventsFor = function (type, typeId, objectTags, actionTags, operation, period, shareToken, readToken) {
    return $.ajax({
        url: "/v1/" + type + "/" + typeId + "/events/" + objectTags + "/" + actionTags + "/" + operation + "/" + period + "/" + "type/json",
        data: {
            shareToken: shareToken,
            readToken: readToken
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    });
};

var plotChart = function (events) {
    if (renderType === "barchart") {
        if (events === null || events.length == 0) {
            $(".no-data").show();
        } else {
            charts.plotBarChart("#chart", events, null, null);
            $('.detailsSection').show();
            $('.share-button-container').show();
        }
    }
};

charts.addComment = function () {
    var commentText = $("#commentText").val();
    var comment = {
        text: commentText,
        user: username,
        avatarUrl: avatarUrl
    };
    var graph = {
        graphUrl: charts.graphUrl,
        dataPointDate: charts.selectedDate,
        username: graphOwner,
        objectTags: objectTags,
        actionTags: actionTags,
        operation: operation,
        period: period,
        renderType: renderType,
        comment: comment
    };
    $.ajax({
        url: "/v1/comments",
        method: "POST",
        data: graph,
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (data) {
        var displayedComment = {text: commentText, avatarUrl: graphOwnerAvatarUrl};
        var selectedDataPoint = _.find(charts.dataPoints, function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        });
        if (_.isEmpty(selectedDataPoint)) {
            var newDataPoint = {
                dataPointDate: charts.selectedDate,
                avatars: [graphOwnerAvatarUrl],
                comments: [displayedComment]
            };
            charts.dataPoints.push(newDataPoint);
        } else {
            selectedDataPoint.comments.push(displayedComment);
        }
        $(".commentList").append("

" +
            "

" + comment.text + "
" +
            "

");
        $("#commentText").val("");
    });
};

$("#addCommentInput").keyup(function (e) {
    if (e.keyCode == 13) {
        charts.addComment();
    }
});

var handleAddComment = function () {
    if (isUserLoggedIn) {
        $("#addCommentInput").show();
    }
    else {
        $("#loginModal").modal({show: true});
    }
};

var handleShareGraph = function () {
    var unregisteredUserOnStreamsPage = function () {
        return !isUserLoggedIn && (window.location.pathname.search("streams") !== -1);
    };

    if (isUserLoggedIn) {
        $.ajax({
            url: "/v1/graph/share?graphUrl=" + window.location.pathname,
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = " "+link+" ";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
                $("#shareModal").modal({show: true});
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    } else if (unregisteredUserOnStreamsPage()) {
        $("#loginModal").modal({show: true});
    } else {
        $.ajax({
            url: "/v1/graph/share?graphUrl=" + window.location.pathname,
            success: function (data) {
                $("#shareModal").modal({show: true});
                $("#loadingDiv").hide();
                var link = window.location.origin + data.graphShareUrl;
                var graphShareLink = ""+link+"";
                $("#graphShareHyperLink").html(graphShareLink);
                $("#graphShareLink").html(link);
            },
            error: function () {
                alert("some problem. Please try again later.");
            }
        });
    }
};

var showChartTitle = function () {
    $("#chartTitle").html(chartTitle);
    if (isUserLoggedIn) {
        $("#avatar").html("").addClass('avatar');
    }
    if (isUserLoggedIn || (!isUserLoggedIn && !(_.isEmpty(shareToken)))) {
        $.when(getEventsFor("users", graphOwner, objectTags, actionTags, operation, period, shareToken, readToken))
            .done(plotChart)
            .fail();
    } else {
        $.when(getEventsFor("streams", streamId, objectTags, actionTags, operation, period, shareToken, readToken))
            .done(plotChart)
            .fail();
    }
};

var submitShare = function () {
    var emailId = $("#emailId").val();
    var graphShareUrl = $("#graphShareLink").html();

    $.ajax({
        url: "/v1/share_graph",
        method: "POST",
        data: { graphShareUrl: graphShareUrl, toEmailId: emailId },
        success: function () {
            $(".shareEmailNoticeMessage").html("Graph link emailed successfully");
        },
        error: function () {
            alert("some problem. Please try again later.");
        }
    });
};

charts.showComments = function () {
    var commentsDiv = $(".commentList");
    commentsDiv.empty();

    charts.dataPoints
        .filter(function (dataPoint) {
            return dataPoint.dataPointDate === charts.selectedDate;
        })
        .forEach(function (dataPoint) {
            dataPoint.comments.forEach(function (comment) {
                commentsDiv.append("

" +
                    "
" + comment.text + "

");
            });
        });
};

var displayCommentsSummary = function () {
    for (var i = 6; i >= 0; i--) {
        var currentDataPointDate = moment.utc().subtract(i, 'days').format("YYYY-MM-DD"); // "2014-11-14"
        var currentDataPoint = _.findWhere(charts.dataPoints, {"dataPointDate": currentDataPointDate});
        if (!_.isEmpty(currentDataPoint)) {
            var latest3Avatars = currentDataPoint.avatars.slice(0, 3);
            latest3Avatars.forEach(function (avatarUrl, j) {
                $("#group" + i + "-avatar" + j).css({'background-image': 'url(' + avatarUrl + ')'});
            });
            if (currentDataPoint.comments.length > 3) {
                $("#group" + i + "-commentCount").addClass("count").html(currentDataPoint.comments.length);
            }
        }
    }
};

$(document).ready(function () {
    showChartTitle();
    $.ajax({
        url: "/v1/comments",
        method: "GET",
        data: {
            username: graphOwner,
            objectTags: objectTags,
            actionTags: actionTags,
            operation: operation,
            period: period,
            renderType: renderType
        },
        headers: {
            "Accept": "application/json",
            "Authorization": $.cookie("_eun")
        }
    }).done(function (comments) {
        charts.dataPoints = comments;
        displayCommentsSummary();
    });
    $("#shareSubmit").click(submitShare);

    var cw = $('.avatar_group').width();
    var ch = $(window).width() * (cw / 100);
    $('.avatar_group').css({'height': ch+'px'});

    setTimeout(function(){charts.showComments();}, 3000)
});
<|endoftext|>


<commit_before>import _ from 'lodash';
import { FETCH_POSTS, FETCH_POST } from '../actions';

export default function(state = {}, action) {
  switch (action.type) {
    case FETCH_POST:
      const post = action.payload.data;
      // const newState = { ...state  };
      // newState[post.id] = post;
      // return newState;

      return { ...state, [action.payload.data.id]: action.payload.data };
    case FETCH_POSTS:
      return _.mapKeys(action.payload.data, 'id');
    default:
      return state;
  }
}
<commit_msg>Add DELETE_POST to reducer function<commit_after>import _ from 'lodash';
import { FETCH_POSTS, FETCH_POST, DELETE_POST } from '../actions';

export default function(state = {}, action) {
  switch (action.type) {
    case DELETE_POST:
      return _.omit(state, action.payload);
    case FETCH_POST:
      const post = action.payload.data;
      // const newState = { ...state  };
      // newState[post.id] = post;
      // return newState;

      return { ...state, [action.payload.data.id]: action.payload.data };
    case FETCH_POSTS:
      return _.mapKeys(action.payload.data, 'id');
    default:
      return state;
  }
}
<|endoftext|>


<commit_before>/**
 * TODO: Andrew
 */
MOL.modules.ColorSetter = function(mol) {

    mol.ui.ColorSetter = {};

    mol.ui.ColorSetter.Color = Class.extend(
        {
            init: function(r, g, b) {
                this._r = r;
                this._g = g;
                this._b = b;
            },

            getRed: function() {
                return this._r;
            },

            getGreen: function() {
                return this._g;
            },

            getBlue: function() {
                return this._b;
            },

            toString: function() {
                return 'Red=' + this._r + ', Green=' + this._g +', Blue=' + this._b;
            }
        }
    );

    mol.ui.ColorSetter.Api = Class.extend(
        {
            /**
             * @constructor
             */
            init: function(config) {
                this._bus = config.bus;
                this._types = {};
                this._bindEvents();
            },

            _bindEvents: function() {
                var bus = this._bus,
                    ColorEvent = mol.events.ColorEvent;

                bus.addHandler(
                    ColorEvent.TYPE,
                    function(event) {
                        var action = event.getAction(),
                            category = event.getCategory(),
                            id = event.getId(),
                            color = null,
                            config = {
                                action: 'change',
                                color: null,
                                category: category,
                                id: id
                            };

                        switch (action) {

                        case 'get':
                            switch (category) {

                            case 'points':
                                // TODO(andrew): Logic for getting next color.
                                config.color = new mol.ui.ColorSetter.Color(32, 40, 73);
                                break;

                            case 'range':
                                config.color = new mol.ui.ColorSetter.Color(183, 42, 16);
                                break;
                            case 'ecoregion':
                                config.color = new mol.ui.ColorSetter.Color(131, 209, 6);
                                break;
                            case 'pa':
                                config.color = new mol.ui.ColorSetter.Color(150, 6, 209);
                                break;
                            }
                            bus.fireEvent(new ColorEvent(config));
                        }
                    }
                );
            }
        }
    );
};
<commit_msg>pa tile color change to yellow<commit_after>/**
 * TODO: Andrew
 */
MOL.modules.ColorSetter = function(mol) {

    mol.ui.ColorSetter = {};

    mol.ui.ColorSetter.Color = Class.extend(
        {
            init: function(r, g, b) {
                this._r = r;
                this._g = g;
                this._b = b;
            },

            getRed: function() {
                return this._r;
            },

            getGreen: function() {
                return this._g;
            },

            getBlue: function() {
                return this._b;
            },

            toString: function() {
                return 'Red=' + this._r + ', Green=' + this._g +', Blue=' + this._b;
            }
        }
    );

    mol.ui.ColorSetter.Api = Class.extend(
        {
            /**
             * @constructor
             */
            init: function(config) {
                this._bus = config.bus;
                this._types = {};
                this._bindEvents();
            },

            _bindEvents: function() {
                var bus = this._bus,
                    ColorEvent = mol.events.ColorEvent;

                bus.addHandler(
                    ColorEvent.TYPE,
                    function(event) {
                        var action = event.getAction(),
                            category = event.getCategory(),
                            id = event.getId(),
                            color = null,
                            config = {
                                action: 'change',
                                color: null,
                                category: category,
                                id: id
                            };

                        switch (action) {

                        case 'get':
                            switch (category) {

                            case 'points':
                                // TODO(andrew): Logic for getting next color.
                                config.color = new mol.ui.ColorSetter.Color(32, 40, 73);
                                break;

                            case 'range':
                                config.color = new mol.ui.ColorSetter.Color(183, 42, 16);
                                break;
                            case 'ecoregion':
                                config.color = new mol.ui.ColorSetter.Color(131, 209, 6);
                                break;
                            case 'pa':
                                config.color = new mol.ui.ColorSetter.Color(255, 191, 0);
                                break;
                            }
                            bus.fireEvent(new ColorEvent(config));
                        }
                    }
                );
            }
        }
    );
};
<|endoftext|>


<commit_before>import {RecipeState, SceneSelectionType} from 'app/home/body/process/mosaic/mosaicRecipe'
import EarthEngineImageLayer from 'app/home/map/earthEngineLayer'
import {sepalMap} from 'app/home/map/map'
import backend from 'backend'
import _ from 'lodash'
import React from 'react'
import {connect} from 'store'
import {msg, Msg} from 'translate'
import Icon from 'widget/icon'
import MapStatus from 'widget/mapStatus'
import styles from './mosaicPreview.module.css'

const mapStateToProps = (state, ownProps) => {
    const recipeState = RecipeState(ownProps.recipeId)
    return {
        recipe: recipeState()
    }
}

class MosaicPreview extends React.Component {
    state = {}

    render() {
        const {initializing, tiles, error} = this.state
        if (this.isHidden())
            return null
        else if (error) {
            return (
                <MapStatus loading={false} error={error}/>
            )
        }
        else if (initializing)
            return (
                <MapStatus message={msg('process.mosaic.preview.initializing')}/>
            )
        else if (tiles && (!tiles.complete || tiles.failed))
            return (
                <MapStatus
                    loading={!tiles.complete}
                    message={msg('process.mosaic.preview.loading', {loaded: tiles.loaded, count: tiles.count})}
                    error={tiles.failed ? msg('process.mosaic.preview.tilesFailed', {failed: tiles.failed}) : error}/>
            )
        else
            return null
    }

    onProgress(tiles) {
        this.setState(prevState => ({...prevState, tiles, initializing: false}))
    }

    onError() {
        this.setState(prevState => ({
            ...prevState,
            error:

                    <Msg id='process.mosaic.preview.error'/>

                         {
                                e.preventDefault()
                                this.reload()
                            }}>
                            <Icon name='sync'/>
                            <Msg id='button.retry'/>

        }))
    }

    reload() {
        const {recipeId} = this.props
        this.setState(prevState => ({...prevState, error: null}))
        sepalMap.getContext(recipeId).setLayer({id: 'preview', layer: null})
    }

    isPreviewShown() {
        const {recipe} = this.props
        return recipe.ui.initialized
            && !recipe.ui.autoSelectingScenes
            && recipe.bands
            && (recipe.sceneSelectionOptions.type === SceneSelectionType.ALL
                || (recipe.scenes && Object.keys(recipe.scenes).find(sceneAreaId => recipe.scenes[sceneAreaId].length > 0)))
    }

    toLayerProps(recipe) {
        return _.omit(recipe, ['ui', 'placeholder', 'title'])
    }

    componentDidUpdate(prevProps) {
        const {recipe} = this.props
        const layerProps = this.toLayerProps(recipe)
        const layerChanged = !_.isEqual(layerProps, this.toLayerProps(prevProps.recipe))
        if (layerChanged)
            this.updateLayer()
        const context = sepalMap.getContext(recipe.id)
        context.hideLayer('preview', this.isHidden(recipe))
    }

    updateLayer() {
        const {recipe, componentWillUnmount$} = this.props
        const {initializing, error} = this.state
        const layer = this.isPreviewShown()
            ? new EarthEngineImageLayer({
                layerIndex: 0,
                bounds: recipe.ui.aoi.bounds,
                mapId$: backend.gee.preview$(recipe),
                props: this.toLayerProps(recipe),
                onProgress: (tiles) => this.onProgress(tiles)
            })
            : null
        const context = sepalMap.getContext(recipe.id)
        const changed = context.setLayer({
            id: 'preview',
            layer,
            destroy$: componentWillUnmount$,
            onError: () => this.onError()
        })
        if (changed && initializing !== !!layer)
            this.setState(prevState => ({...prevState, initializing: !!layer, error: null}))
        else if (changed && error)
            this.setState(prevState => ({...prevState, error: null}))
    }

    isHidden() {
        const {recipe} = this.props
        return !this.isPreviewShown() || !recipe || !recipe.ui || !!recipe.ui.selectedPanel
    }
}

export default connect(mapStateToProps)(MosaicPreview)
<commit_msg>Updated layer when mosaic preview mounts.<commit_after>import {RecipeState, SceneSelectionType} from 'app/home/body/process/mosaic/mosaicRecipe'
import EarthEngineImageLayer from 'app/home/map/earthEngineLayer'
import {sepalMap} from 'app/home/map/map'
import backend from 'backend'
import _ from 'lodash'
import React from 'react'
import {connect} from 'store'
import {msg, Msg} from 'translate'
import Icon from 'widget/icon'
import MapStatus from 'widget/mapStatus'
import styles from './mosaicPreview.module.css'

const mapStateToProps = (state, ownProps) => {
    const recipeState = RecipeState(ownProps.recipeId)
    return {
        recipe: recipeState()
    }
}

class MosaicPreview extends React.Component {
    state = {}

    render() {
        const {initializing, tiles, error} = this.state
        if (this.isHidden())
            return null
        else if (error) {
            return (
                <MapStatus loading={false} error={error}/>
            )
        }
        else if (initializing)
            return (
                <MapStatus message={msg('process.mosaic.preview.initializing')}/>
            )
        else if (tiles && (!tiles.complete || tiles.failed))
            return (
                <MapStatus
                    loading={!tiles.complete}
                    message={msg('process.mosaic.preview.loading', {loaded: tiles.loaded, count: tiles.count})}
                    error={tiles.failed ? msg('process.mosaic.preview.tilesFailed', {failed: tiles.failed}) : error}/>
            )
        else
            return null
    }

    onProgress(tiles) {
        this.setState(prevState => ({...prevState, tiles, initializing: false}))
    }

    onError() {
        this.setState(prevState => ({
            ...prevState,
            error:

                    <Msg id='process.mosaic.preview.error'/>

                         {
                                e.preventDefault()
                                this.reload()
                            }}>
                            <Icon name='sync'/>
                            <Msg id='button.retry'/>

        }))
    }

    reload() {
        const {recipeId} = this.props
        this.setState(prevState => ({...prevState, error: null}))
        sepalMap.getContext(recipeId).setLayer({id: 'preview', layer: null})
    }

    isPreviewShown() {
        const {recipe} = this.props
        return recipe.ui.initialized
            && !recipe.ui.autoSelectingScenes
            && recipe.bands
            && (recipe.sceneSelectionOptions.type === SceneSelectionType.ALL
                || (recipe.scenes && Object.keys(recipe.scenes).find(sceneAreaId => recipe.scenes[sceneAreaId].length > 0)))
    }

    toLayerProps(recipe) {
        return _.omit(recipe, ['ui', 'placeholder', 'title'])
    }

    componentDidMount() {
        this.updateLayer()
    }

    componentDidUpdate(prevProps) {
        const {recipe} = this.props
        const layerProps = this.toLayerProps(recipe)
        const layerChanged = !_.isEqual(layerProps, this.toLayerProps(prevProps.recipe))
        if (layerChanged)
            this.updateLayer()
        const context = sepalMap.getContext(recipe.id)
        context.hideLayer('preview', this.isHidden(recipe))
    }

    updateLayer() {
        const {recipe, componentWillUnmount$} = this.props
        const {initializing, error} = this.state
        const layer = this.isPreviewShown()
            ? new EarthEngineImageLayer({
                layerIndex: 0,
                bounds: recipe.ui.aoi.bounds,
                mapId$: backend.gee.preview$(recipe),
                props: this.toLayerProps(recipe),
                onProgress: (tiles) => this.onProgress(tiles)
            })
            : null
        const context = sepalMap.getContext(recipe.id)
        const changed = context.setLayer({
            id: 'preview',
            layer,
            destroy$: componentWillUnmount$,
            onError: () => this.onError()
        })
        if (changed && initializing !== !!layer)
            this.setState(prevState => ({...prevState, initializing: !!layer, error: null}))
        else if (changed && error)
            this.setState(prevState => ({...prevState, error: null}))
    }

    isHidden() {
        const {recipe} = this.props
        return !this.isPreviewShown() || !recipe || !recipe.ui || !!recipe.ui.selectedPanel
    }
}

export default connect(mapStateToProps)(MosaicPreview)
<|endoftext|>


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

    angular
        .module('dpSearchResults')
        .component('dpSearchResults', {
            bindings: {
                isLoading: '=',
                query: '@',
                location: '=',
                category: '@',
                numberOfResults: '='
            },
            templateUrl: 'modules/search-results/components/search-results/search-results.html',
            controller: DpSearchResultsController,
            controllerAs: 'vm'
        });

    DpSearchResultsController.$inject = [
        '$rootScope', '$scope', 'search', 'geosearch', 'TabHeader', 'user', 'store', 'ACTIONS',
        'OVERLAYS', 'activeOverlays', 'zoom'
    ];

    function DpSearchResultsController ($rootScope, $scope, search, geosearch, TabHeader, user, store, ACTIONS,
                                        OVERLAYS, activeOverlays, zoom) {
        const vm = this;

        /**
         * watch isLoading and the query and location parameters of the state
         * if isLoading becomes true then find out what has te be loaded and get it
         */
        $scope.$watch('vm.isLoading', () => {
            if (vm.isLoading) {
                // First try to search on location
                // Test on isArray(location) is more precise than isString(query) because null maps to empty string (@)
                if (!searchByLocation(vm.location)) {
                    searchByQuery(vm.query, vm.category);
                }
            }
        });

        $scope.$watchGroup(['vm.query', 'vm.category'], () => {
            if (!vm.isLoading) {
                searchByQuery(vm.query, vm.category);
            }
        });

        $scope.$watchCollection('vm.location', () => {
            if (!vm.isLoading) {
                searchByLocation(vm.location);
            }
        });

        // Show warning depending on authorization
        const unwatchAuthorizationLevel = $rootScope.$watch(() => user.getAuthorizationLevel(), updateWarningMessage);
        $rootScope.$on('$destroy', unwatchAuthorizationLevel);

        vm.loadMore = function () {
            vm.isLoadMoreLoading = true;

            search.loadMore(vm.searchResults[0]).then(function (searchResults) {
                vm.isLoadMoreLoading = false;

                vm.searchResults[0] = searchResults;
            });
        };

        vm.showTabHeader = () => !angular.isArray(vm.location) && !vm.category;

        vm.meetsRequiredLevel = user.meetsRequiredLevel;
        vm.layerWarning = false;

        vm.tabHeader = new TabHeader('data-datasets');
        vm.tabHeader.activeTab = vm.tabHeader.getTab('data');

        function updateTabHeader (query, count) {
            if (vm.showTabHeader()) {
                vm.tabHeader.query = query;
                vm.tabHeader.getTab('data').count = count;
            }
        }

        function searchByQuery (query, category) {
            const isQuery = angular.isString(query);
            if (isQuery) {
                if (angular.isString(category) && category.length) {
                    search.search(query, category).then(setSearchResults).then(updateWarningMessage);
                } else {
                    search.search(query).then(setSearchResults).then(updateWarningMessage);
                }
            }
            return isQuery;
        }

        function searchByLocation (location) {
            const isLocation = angular.isArray(location);

            if (isLocation) {
                vm.layerWarning = activeOverlays.getResultCount() === 0 ? activeOverlays.getOverlaysWarning() : false;
                geosearch.searchFeatures(location).then(setSearchResults).then(updateWarningMessage);
            }

            return isLocation;
        }

        function updateWarningMessage () {
            const kadastraleSubject = vm.searchResults &&
                vm.searchResults.find(category => category.slug === 'subject');
            if (kadastraleSubject) {
                if (user.meetsRequiredLevel(user.AUTHORIZATION_LEVEL.EMPLOYEE_PLUS)) {
                    delete kadastraleSubject.warning;
                } else if (user.meetsRequiredLevel(user.AUTHORIZATION_LEVEL.EMPLOYEE)) {
                    kadastraleSubject.warning = 'Medewerkers met speciale bevoegdheden' +
                        ' kunnen alle gegevens vinden (ook natuurlijke personen).';
                } else {
                    kadastraleSubject.warning = 'Om kadastraal subjecten te kunnen vinden,' +
                        ' moet je als medewerker/ketenpartner van Gemeente Amsterdam inloggen.' +
                        ' Om ook natuurlijke personen te vinden, moet je als medewerker bovendien' +
                        ' speciale bevoegdheden hebben.';
                }
            }
        }

        /**
         * For both SEARCH BY QUERY (with and without category) and GEOSEARCH
         */
        function setSearchResults (searchResults) {
            const numberOfResults = searchResults.reduce(function (previous, current) {
                return previous + current.count;
            }, 0);

            updateTabHeader(vm.query, numberOfResults);

            store.dispatch({
                type: ACTIONS.SHOW_SEARCH_RESULTS,
                payload: numberOfResults
            });

            // @TODO remove the exception when backend uses correct sub type name tg-3551
            searchResults = replaceBuurtcombinatie(searchResults);

            vm.searchResults = searchResults;

            vm.hasLoadMore = function () {
                return angular.isString(vm.category) &&
                    vm.searchResults[0].count > vm.searchResults[0].results.length &&
                    !vm.isLoadMoreLoading;
            };
        }

        // @TODO remove the exception when backend uses correct sub type name tg-3551
        function replaceBuurtcombinatie (searchResults) {
            const results = angular.copy(searchResults);

            results.forEach((result) => {
                result.results.forEach((item) => {
                    if (item.subtype === 'buurtcombinatie') {
                        item.subtypeLabel = 'wijk';
                    }
                });
            });

            return results;
        }
    }
})();
<commit_msg>removed dependencies tg-4096<commit_after>(function () {
    'use strict';

    angular
        .module('dpSearchResults')
        .component('dpSearchResults', {
            bindings: {
                isLoading: '=',
                query: '@',
                location: '=',
                category: '@',
                numberOfResults: '='
            },
            templateUrl: 'modules/search-results/components/search-results/search-results.html',
            controller: DpSearchResultsController,
            controllerAs: 'vm'
        });

    DpSearchResultsController.$inject = [
        '$rootScope', '$scope', 'search', 'geosearch', 'TabHeader', 'user', 'store', 'ACTIONS', 'activeOverlays'
    ];

    function DpSearchResultsController ($rootScope, $scope, search, geosearch, TabHeader, user, store, ACTIONS,
                                        activeOverlays) {
        const vm = this;

        /**
         * watch isLoading and the query and location parameters of the state
         * if isLoading becomes true then find out what has te be loaded and get it
         */
        $scope.$watch('vm.isLoading', () => {
            if (vm.isLoading) {
                // First try to search on location
                // Test on isArray(location) is more precise than isString(query) because null maps to empty string (@)
                if (!searchByLocation(vm.location)) {
                    searchByQuery(vm.query, vm.category);
                }
            }
        });

        $scope.$watchGroup(['vm.query', 'vm.category'], () => {
            if (!vm.isLoading) {
                searchByQuery(vm.query, vm.category);
            }
        });

        $scope.$watchCollection('vm.location', () => {
            if (!vm.isLoading) {
                searchByLocation(vm.location);
            }
        });

        // Show warning depending on authorization
        const unwatchAuthorizationLevel = $rootScope.$watch(() => user.getAuthorizationLevel(), updateWarningMessage);
        $rootScope.$on('$destroy', unwatchAuthorizationLevel);

        vm.loadMore = function () {
            vm.isLoadMoreLoading = true;

            search.loadMore(vm.searchResults[0]).then(function (searchResults) {
                vm.isLoadMoreLoading = false;

                vm.searchResults[0] = searchResults;
            });
        };

        vm.showTabHeader = () => !angular.isArray(vm.location) && !vm.category;

        vm.meetsRequiredLevel = user.meetsRequiredLevel;
        vm.layerWarning = false;

        vm.tabHeader = new TabHeader('data-datasets');
        vm.tabHeader.activeTab = vm.tabHeader.getTab('data');

        function updateTabHeader (query, count) {
            if (vm.showTabHeader()) {
                vm.tabHeader.query = query;
                vm.tabHeader.getTab('data').count = count;
            }
        }

        function searchByQuery (query, category) {
            const isQuery = angular.isString(query);
            if (isQuery) {
                if (angular.isString(category) && category.length) {
                    search.search(query, category).then(setSearchResults).then(updateWarningMessage);
                } else {
                    search.search(query).then(setSearchResults).then(updateWarningMessage);
                }
            }
            return isQuery;
        }

        function searchByLocation (location) {
            const isLocation = angular.isArray(location);

            if (isLocation) {
                vm.layerWarning = activeOverlays.getResultCount() === 0 ? activeOverlays.getOverlaysWarning() : false;
                geosearch.searchFeatures(location).then(setSearchResults).then(updateWarningMessage);
            }

            return isLocation;
        }

        function updateWarningMessage () {
            const kadastraleSubject = vm.searchResults &&
                vm.searchResults.find(category => category.slug === 'subject');
            if (kadastraleSubject) {
                if (user.meetsRequiredLevel(user.AUTHORIZATION_LEVEL.EMPLOYEE_PLUS)) {
                    delete kadastraleSubject.warning;
                } else if (user.meetsRequiredLevel(user.AUTHORIZATION_LEVEL.EMPLOYEE)) {
                    kadastraleSubject.warning = 'Medewerkers met speciale bevoegdheden' +
                        ' kunnen alle gegevens vinden (ook natuurlijke personen).';
                } else {
                    kadastraleSubject.warning = 'Om kadastraal subjecten te kunnen vinden,' +
                        ' moet je als medewerker/ketenpartner van Gemeente Amsterdam inloggen.' +
                        ' Om ook natuurlijke personen te vinden, moet je als medewerker bovendien' +
                        ' speciale bevoegdheden hebben.';
                }
            }
        }

        /**
         * For both SEARCH BY QUERY (with and without category) and GEOSEARCH
         */
        function setSearchResults (searchResults) {
            const numberOfResults = searchResults.reduce(function (previous, current) {
                return previous + current.count;
            }, 0);

            updateTabHeader(vm.query, numberOfResults);

            store.dispatch({
                type: ACTIONS.SHOW_SEARCH_RESULTS,
                payload: numberOfResults
            });

            // @TODO remove the exception when backend uses correct sub type name tg-3551
            searchResults = replaceBuurtcombinatie(searchResults);

            vm.searchResults = searchResults;

            vm.hasLoadMore = function () {
                return angular.isString(vm.category) &&
                    vm.searchResults[0].count > vm.searchResults[0].results.length &&
                    !vm.isLoadMoreLoading;
            };
        }

        // @TODO remove the exception when backend uses correct sub type name tg-3551
        function replaceBuurtcombinatie (searchResults) {
            const results = angular.copy(searchResults);

            results.forEach((result) => {
                result.results.forEach((item) => {
                    if (item.subtype === 'buurtcombinatie') {
                        item.subtypeLabel = 'wijk';
                    }
                });
            });

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


<commit_before>// sagas
import { authenticationFlowSaga } from './login';

export default [
  authenticationFlowSaga,
];

<commit_msg>prettyfier<commit_after>// sagas
import { authenticationFlowSaga } from "./login";

export default [authenticationFlowSaga];
<|endoftext|>


<commit_before>/*globals svgEditor */
svgEditor.readLang({
	lang: "bg",
	dir : "ltr",
	common: {
		"ok": "Спасявам",
		"cancel": "Отказ",
		"key_backspace": "backspace",
		"key_del": "delete",
		"key_down": "down",
		"key_up": "up",
		"more_opts": "More Options",
		"url": "URL",
		"width": "Width",
		"height": "Height"
	},
	misc: {
		"powered_by": "Powered by"
	},
	ui: {
		"toggle_stroke_tools": "Show/hide more stroke tools",
		"palette_info": "Кликнете, за да промени попълнете цвят, на смени, кликнете да променят цвета си удар",
		"zoom_level": "Промяна на ниво на мащабиране",
		"panel_drag": "Drag left/right to resize side panel"
	},
	properties: {
		"id": "Identify the element",
		"fill_color": "Промяна попълнете цвят",
		"stroke_color": "Промяна на инсулт цвят",
		"stroke_style": "Промяна на стила удар тире",
		"stroke_width": "Промяна на ширината инсулт",
		"pos_x": "Change X coordinate",
		"pos_y": "Change Y coordinate",
		"linecap_butt": "Linecap: Butt",
		"linecap_round": "Linecap: Round",
		"linecap_square": "Linecap: Square",
		"linejoin_bevel": "Linejoin: Bevel",
		"linejoin_miter": "Linejoin: Miter",
		"linejoin_round": "Linejoin: Round",
		"angle": "Промяна ъгъл на завъртане",
		"blur": "Change gaussian blur value",
		"opacity": "Промяна на избрания елемент непрозрачност",
		"circle_cx": "CX Промяна кръг на координатната",
		"circle_cy": "Промяна кръг's CY координира",
		"circle_r": "Промяна кръг радиус",
		"ellipse_cx": "Промяна на елипса's CX координира",
		"ellipse_cy": "Промяна на елипса's CY координира",
		"ellipse_rx": "Промяна на елипса's X радиус",
		"ellipse_ry": "Промяна на елипса's Y радиус",
		"line_x1": "Промяна на линия, започваща х координира",
		"line_x2": "Промяна на линията приключва х координира",
		"line_y1": "Промяна линия, започваща Y координира",
		"line_y2": "Промяна на линията приключва Y координира",
		"rect_height": "Промяна на правоъгълник височина",
		"rect_width": "Промяна на правоъгълник ширина",
		"corner_radius": "Промяна на правоъгълник Corner Radius",
		"image_width": "Промяна на изображението ширина",
		"image_height": "Промяна на изображението височина",
		"image_url": "Промяна на URL",
		"node_x": "Change node's x coordinate",
		"node_y": "Change node's y coordinate",
		"seg_type": "Change Segment type",
		"straight_segments": "Straight",
		"curve_segments": "Curve",
		"text_contents": "Промяна на текст съдържание",
		"font_family": "Промяна на шрифта Семейство",
		"font_size": "Промени размера на буквите",
		"bold": "Получер текст",
		"italic": "Курсив текст"
	},
	tools: {
		"main_menu": "Main Menu",
		"bkgnd_color_opac": "Промяна на цвета на фона / непрозрачност",
		"connector_no_arrow": "No arrow",
		"fitToContent": "Fit към съдържание",
		"fit_to_all": "Побери цялото съдържание",
		"fit_to_canvas": "Fit на платно",
		"fit_to_layer_content": "Fit да слой съдържание",
		"fit_to_sel": "Fit за подбор",
		"align_relative_to": "Привеждане в сравнение с ...",
		"relativeTo": "в сравнение с:",
		"страница": "страница",
		"largest_object": "най-големият обект",
		"selected_objects": "избраните обекти",
		"smallest_object": "най-малката обект",
		"new_doc": "Ню Имидж",
		"open_doc": "Отворете изображението",
		"export_img": "Export",
		"save_doc": "Save Image",
		"import_doc": "Import Image",
		"align_to_page": "Align Element to Page",
		"align_bottom": "Привеждане Отдолу",
		"align_center": "Подравняване в средата",
		"align_left": "Подравняване вляво",
		"align_middle": "Привеждане в Близкия",
		"align_right": "Подравняване надясно",
		"align_top": "Привеждане Топ",
		"mode_select": "Select Tool",
		"mode_fhpath": "Pencil Tool",
		"mode_line": "Line Tool",
		"mode_connect": "Connect two objects",
		"mode_rect": "Rectangle Tool",
		"mode_square": "Square Tool",
		"mode_fhrect": "Свободен Употребявани правоъгълник",
		"mode_ellipse": "Елипса",
		"mode_circle": "Кръгът",
		"mode_fhellipse": "Свободен Употребявани Елипса",
		"mode_path": "Поли Tool",
		"mode_shapelib": "Shape library",
		"mode_text": "Текст Оръдие",
		"mode_image": "Image Tool",
		"mode_zoom": "Zoom Tool",
		"mode_eyedropper": "Eye Dropper Tool",
		"no_embed": "NOTE: This image cannot be embedded. It will depend on this path to be displayed",
		"undo": "Отмени",
		"redo": "Възстановяване",
		"tool_source": "Редактиране Източник",
		"wireframe_mode": "Wireframe Mode",
		"toggle_grid": "Show/Hide Grid",
		"clone": "Clone Element(s)",
		"del": "Delete Element(s)",
		"group_elements": "Група Елементи",
		"make_link": "Make (hyper)link",
		"set_link_url": "Set link URL (leave empty to remove)",
		"to_path": "Convert to Path",
		"reorient_path": "Reorient path",
		"ungroup": "Разгрупирай Елементи",
		"docprops": "Document Properties",
		"imagelib": "Image Library",
		"move_bottom": "Премести надолу",
		"move_top": "Премести в началото",
		"node_clone": "Clone Node",
		"node_delete": "Delete Node",
		"node_link": "Link Control Points",
		"add_subpath": "Add sub-path",
		"openclose_path": "Open/close sub-path",
		"source_save": "Спасявам",
		"cut": "Cut",
		"copy": "Copy",
		"paste": "Paste",
		"paste_in_place": "Paste in Place",
		"delete": "Delete",
		"group": "Group",
		"move_front": "Bring to Front",
		"move_up": "Bring Forward",
		"move_down": "Send Backward",
		"move_back": "Send to Back"
	},
	layers: {
		"layer":"Layer",
		"layers": "Layers",
		"del": "Изтриване на слой",
		"move_down": "Move слой надолу",
		"new": "Нов слой",
		"rename": "Преименуване Layer",
		"move_up": "Move Up Layer",
		"dupe": "Duplicate Layer",
		"merge_down": "Merge Down",
		"merge_all": "Merge All",
		"move_elems_to": "Move elements to:",
		"move_selected": "Move selected elements to a different layer"
	},
	config: {
		"image_props": "Image Properties",
		"doc_title": "Title",
		"doc_dims": "Canvas Dimensions",
		"included_images": "Included Images",
		"image_opt_embed": "Embed data (local files)",
		"image_opt_ref": "Use file reference",
		"editor_prefs": "Editor Preferences",
		"icon_size": "Icon size",
		"language": "Language",
		"background": "Editor Background",
		"editor_img_url": "Image URL",
		"editor_bg_note": "Note: Background will not be saved with image.",
		"icon_large": "Large",
		"icon_medium": "Medium",
		"icon_small": "Small",
		"icon_xlarge": "Extra Large",
		"select_predefined": "Изберете предварително:",
		"units_and_rulers": "Units & Rulers",
		"show_rulers": "Show rulers",
		"base_unit": "Base Unit:",
		"grid": "Grid",
		"snapping_onoff": "Snapping on/off",
		"snapping_stepsize": "Snapping Step-Size:",
		"grid_color": "Grid color"
	},
	shape_cats: {
		"basic": "Basic",
		"object": "Objects",
		"symbol": "Symbols",
		"arrow": "Arrows",
		"flowchart": "Flowchart",
		"animal": "Animals",
		"game": "Cards & Chess",
		"dialog_balloon": "Dialog balloons",
		"electronics": "Electronics",
		"math": "Mathematical",
		"music": "Music",
		"misc": "Miscellaneous",
		"raphael_1": "raphaeljs.com set 1",
		"raphael_2": "raphaeljs.com set 2"
	},
	imagelib: {
		"select_lib": "Select an image library",
		"show_list": "Show library list",
		"import_single": "Import single",
		"import_multi": "Import multiple",
		"open": "Open as new document"
	},
	notification: {
		"invalidAttrValGiven":"Invalid value given",
		"noContentToFitTo":"No content to fit to",
		"dupeLayerName":"There is already a layer named that!",
		"enterUniqueLayerName":"Please enter a unique layer name",
		"enterNewLayerName":"Please enter the new layer name",
		"layerHasThatName":"Layer already has that name",
		"QmoveElemsToLayer":"Move selected elements to layer '%s'?",
		"QwantToClear":"Do you want to clear the drawing?\nThis will also erase your undo history!",
		"QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!",
		"QerrorsRevertToSource":"There were parsing errors in your SVG source.\nRevert back to original SVG source?",
		"QignoreSourceChanges":"Ignore changes made to SVG source?",
		"featNotSupported":"Feature not supported",
		"enterNewImgURL":"Enter the new image URL",
		"defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.",
		"loadingImage":"Loading image, please wait...",
		"saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file.",
		"noteTheseIssues": "Also note the following issues: ",
		"unsavedChanges": "There are unsaved changes.",
		"enterNewLinkURL": "Enter the new hyperlink URL",
		"errorLoadingSVG": "Error: Unable to load SVG data",
		"URLloadFail": "Unable to load from URL",
		"retrieving": "Retrieving \"%s\"..."
	},
	confirmSetStorage: {
		message: "By default and where supported, SVG-Edit can store your editor "+
		"preferences and SVG content locally on your machine so you do not "+
		"need to add these back each time you load SVG-Edit. If, for privacy "+
		"reasons, you do not wish to store this information on your machine, "+
		"you can change away from the default option below.",
		storagePrefsAndContent: "Store preferences and SVG content locally",
		storagePrefsOnly: "Only store preferences locally",
		storagePrefs: "Store preferences locally",
		storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
		storageNoPrefs: "Do not store my preferences locally",
		rememberLabel: "Remember this choice?",
		rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
	}
});<commit_msg>Update lang.bg.js<commit_after>/*globals svgEditor */
svgEditor.readLang({
	lang: "bg",
	dir : "ltr",
	common: {
		"ok": "Спасявам",
		"cancel": "Отказ",
		"key_backspace": "backspace",
		"key_del": "delete",
		"key_down": "down",
		"key_up": "up",
		"more_opts": "More Options",
		"url": "URL",
		"width": "Width",
		"height": "Height"
	},
	misc: {
		"powered_by": "Powered by"
	},
	ui: {
		"toggle_stroke_tools": "Show/hide more stroke tools",
		"palette_info": "Кликнете, за да промени попълнете цвят, на смени, кликнете да променят цвета си удар",
		"zoom_level": "Промяна на ниво на мащабиране",
		"panel_drag": "Drag left/right to resize side panel"
	},
	properties: {
		"id": "Identify the element",
		"fill_color": "Промяна попълнете цвят",
		"stroke_color": "Промяна на инсулт цвят",
		"stroke_style": "Промяна на стила удар тире",
		"stroke_width": "Промяна на ширината инсулт",
		"pos_x": "Change X coordinate",
		"pos_y": "Change Y coordinate",
		"linecap_butt": "Linecap: Butt",
		"linecap_round": "Linecap: Round",
		"linecap_square": "Linecap: Square",
		"linejoin_bevel": "Linejoin: Bevel",
		"linejoin_miter": "Linejoin: Miter",
		"linejoin_round": "Linejoin: Round",
		"angle": "Промяна ъгъл на завъртане",
		"blur": "Change gaussian blur value",
		"opacity": "Промяна на избрания елемент непрозрачност",
		"circle_cx": "CX Промяна кръг на координатната",
		"circle_cy": "Промяна кръг's CY координира",
		"circle_r": "Промяна кръг радиус",
		"ellipse_cx": "Промяна на елипса's CX координира",
		"ellipse_cy": "Промяна на елипса's CY координира",
		"ellipse_rx": "Промяна на елипса's X радиус",
		"ellipse_ry": "Промяна на елипса's Y радиус",
		"line_x1": "Промяна на линия, започваща х координира",
		"line_x2": "Промяна на линията приключва х координира",
		"line_y1": "Промяна линия, започваща Y координира",
		"line_y2": "Промяна на линията приключва Y координира",
		"rect_height": "Промяна на правоъгълник височина",
		"rect_width": "Промяна на правоъгълник ширина",
		"corner_radius": "Промяна на правоъгълник Corner Radius",
		"image_width": "Промяна на изображението ширина",
		"image_height": "Промяна на изображението височина",
		"image_url": "Промяна на URL",
		"node_x": "Change node's x coordinate",
		"node_y": "Change node's y coordinate",
		"seg_type": "Change Segment type",
		"straight_segments": "Straight",
		"curve_segments": "Curve",
		"text_contents": "Промяна на текст съдържание",
		"font_family": "Промяна на шрифта Семейство",
		"font_size": "Промени размера на буквите",
		"bold": "Получер текст",
		"italic": "Курсив текст"
	},
	tools: {
		"main_menu": "Main Menu",
		"bkgnd_color_opac": "Промяна на цвета на фона / непрозрачност",
		"connector_no_arrow": "No arrow",
		"fitToContent": "Fit към съдържание",
		"fit_to_all": "Побери цялото съдържание",
		"fit_to_canvas": "Fit на платно",
		"fit_to_layer_content": "Fit да слой съдържание",
		"fit_to_sel": "Fit за подбор",
		"align_relative_to": "Привеждане в сравнение с ...",
		"relativeTo": "в сравнение с:",
		"page": "страница",
		"largest_object": "най-големият обект",
		"selected_objects": "избраните обекти",
		"smallest_object": "най-малката обект",
		"new_doc": "Ню Имидж",
		"open_doc": "Отворете изображението",
		"export_img": "Export",
		"save_doc": "Save Image",
		"import_doc": "Import Image",
		"align_to_page": "Align Element to Page",
		"align_bottom": "Привеждане Отдолу",
		"align_center": "Подравняване в средата",
		"align_left": "Подравняване вляво",
		"align_middle": "Привеждане в Близкия",
		"align_right": "Подравняване надясно",
		"align_top": "Привеждане Топ",
		"mode_select": "Select Tool",
		"mode_fhpath": "Pencil Tool",
		"mode_line": "Line Tool",
		"mode_connect": "Connect two objects",
		"mode_rect": "Rectangle Tool",
		"mode_square": "Square Tool",
		"mode_fhrect": "Свободен Употребявани правоъгълник",
		"mode_ellipse": "Елипса",
		"mode_circle": "Кръгът",
		"mode_fhellipse": "Свободен Употребявани Елипса",
		"mode_path": "Поли Tool",
		"mode_shapelib": "Shape library",
		"mode_text": "Текст Оръдие",
		"mode_image": "Image Tool",
		"mode_zoom": "Zoom Tool",
		"mode_eyedropper": "Eye Dropper Tool",
		"no_embed": "NOTE: This image cannot be embedded. It will depend on this path to be displayed",
		"undo": "Отмени",
		"redo": "Възстановяване",
		"tool_source": "Редактиране Източник",
		"wireframe_mode": "Wireframe Mode",
		"toggle_grid": "Show/Hide Grid",
		"clone": "Clone Element(s)",
		"del": "Delete Element(s)",
		"group_elements": "Група Елементи",
		"make_link": "Make (hyper)link",
		"set_link_url": "Set link URL (leave empty to remove)",
		"to_path": "Convert to Path",
		"reorient_path": "Reorient path",
		"ungroup": "Разгрупирай Елементи",
		"docprops": "Document Properties",
		"imagelib": "Image Library",
		"move_bottom": "Премести надолу",
		"move_top": "Премести в началото",
		"node_clone": "Clone Node",
		"node_delete": "Delete Node",
		"node_link": "Link Control Points",
		"add_subpath": "Add sub-path",
		"openclose_path": "Open/close sub-path",
		"source_save": "Спасявам",
		"cut": "Cut",
		"copy": "Copy",
		"paste": "Paste",
		"paste_in_place": "Paste in Place",
		"delete": "Delete",
		"group": "Group",
		"move_front": "Bring to Front",
		"move_up": "Bring Forward",
		"move_down": "Send Backward",
		"move_back": "Send to Back"
	},
	layers: {
		"layer":"Layer",
		"layers": "Layers",
		"del": "Изтриване на слой",
		"move_down": "Move слой надолу",
		"new": "Нов слой",
		"rename": "Преименуване Layer",
		"move_up": "Move Up Layer",
		"dupe": "Duplicate Layer",
		"merge_down": "Merge Down",
		"merge_all": "Merge All",
		"move_elems_to": "Move elements to:",
		"move_selected": "Move selected elements to a different layer"
	},
	config: {
		"image_props": "Image Properties",
		"doc_title": "Title",
		"doc_dims": "Canvas Dimensions",
		"included_images": "Included Images",
		"image_opt_embed": "Embed data (local files)",
		"image_opt_ref": "Use file reference",
		"editor_prefs": "Editor Preferences",
		"icon_size": "Icon size",
		"language": "Language",
		"background": "Editor Background",
		"editor_img_url": "Image URL",
		"editor_bg_note": "Note: Background will not be saved with image.",
		"icon_large": "Large",
		"icon_medium": "Medium",
		"icon_small": "Small",
		"icon_xlarge": "Extra Large",
		"select_predefined": "Изберете предварително:",
		"units_and_rulers": "Units & Rulers",
		"show_rulers": "Show rulers",
		"base_unit": "Base Unit:",
		"grid": "Grid",
		"snapping_onoff": "Snapping on/off",
		"snapping_stepsize": "Snapping Step-Size:",
		"grid_color": "Grid color"
	},
	shape_cats: {
		"basic": "Basic",
		"object": "Objects",
		"symbol": "Symbols",
		"arrow": "Arrows",
		"flowchart": "Flowchart",
		"animal": "Animals",
		"game": "Cards & Chess",
		"dialog_balloon": "Dialog balloons",
		"electronics": "Electronics",
		"math": "Mathematical",
		"music": "Music",
		"misc": "Miscellaneous",
		"raphael_1": "raphaeljs.com set 1",
		"raphael_2": "raphaeljs.com set 2"
	},
	imagelib: {
		"select_lib": "Select an image library",
		"show_list": "Show library list",
		"import_single": "Import single",
		"import_multi": "Import multiple",
		"open": "Open as new document"
	},
	notification: {
		"invalidAttrValGiven":"Invalid value given",
		"noContentToFitTo":"No content to fit to",
		"dupeLayerName":"There is already a layer named that!",
		"enterUniqueLayerName":"Please enter a unique layer name",
		"enterNewLayerName":"Please enter the new layer name",
		"layerHasThatName":"Layer already has that name",
		"QmoveElemsToLayer":"Move selected elements to layer '%s'?",
		"QwantToClear":"Do you want to clear the drawing?\nThis will also erase your undo history!",
		"QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!",
		"QerrorsRevertToSource":"There were parsing errors in your SVG source.\nRevert back to original SVG source?",
		"QignoreSourceChanges":"Ignore changes made to SVG source?",
		"featNotSupported":"Feature not supported",
		"enterNewImgURL":"Enter the new image URL",
		"defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.",
		"loadingImage":"Loading image, please wait...",
		"saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file.",
		"noteTheseIssues": "Also note the following issues: ",
		"unsavedChanges": "There are unsaved changes.",
		"enterNewLinkURL": "Enter the new hyperlink URL",
		"errorLoadingSVG": "Error: Unable to load SVG data",
		"URLloadFail": "Unable to load from URL",
		"retrieving": "Retrieving \"%s\"..."
	},
	confirmSetStorage: {
		message: "By default and where supported, SVG-Edit can store your editor "+
		"preferences and SVG content locally on your machine so you do not "+
		"need to add these back each time you load SVG-Edit. If, for privacy "+
		"reasons, you do not wish to store this information on your machine, "+
		"you can change away from the default option below.",
		storagePrefsAndContent: "Store preferences and SVG content locally",
		storagePrefsOnly: "Only store preferences locally",
		storagePrefs: "Store preferences locally",
		storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
		storageNoPrefs: "Do not store my preferences locally",
		rememberLabel: "Remember this choice?",
		rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
	}
});
<|endoftext|>


<commit_before>import Pretender from 'pretender';
import Service from '@ember/service';
import hbs from 'htmlbars-inline-precompile';
import md5 from 'npm:blueimp-md5';
import wait from 'ember-test-helpers/wait';
import {describe, it} from 'mocha';
import {expect} from 'chai';
import {run} from '@ember/runloop';
import {setupComponentTest} from 'ember-mocha';
import {timeout} from 'ember-concurrency';

let pathsStub = Service.extend({
    init() {
        this._super(...arguments);

        this.url = {
            api() {
                return '';
            },
            asset(src) {
                return src;
            }
        };
    }
});

const stubKnownGravatar = function (server) {
    server.get('http://www.gravatar.com/avatar/:md5', function () {
        return [200, {'Content-Type': 'image/png'}, ''];
    });

    server.head('http://www.gravatar.com/avatar/:md5', function () {
        return [200, {'Content-Type': 'image/png'}, ''];
    });
};

const stubUnknownGravatar = function (server) {
    server.get('http://www.gravatar.com/avatar/:md5', function () {
        return [404, {}, ''];
    });

    server.head('http://www.gravatar.com/avatar/:md5', function () {
        return [404, {}, ''];
    });
};

let configStubuseGravatar = Service.extend({
    useGravatar: true
});

describe('Integration: Component: gh-profile-image', function () {
    setupComponentTest('gh-profile-image', {
        integration: true
    });

    let server;

    beforeEach(function () {
        this.register('service:ghost-paths', pathsStub);
        this.inject.service('ghost-paths', {as: 'ghost-paths'});
        this.register('service:config', configStubuseGravatar);
        this.inject.service('config', {as: 'config'});

        server = new Pretender();
        stubKnownGravatar(server);
    });

    afterEach(function () {
        server.shutdown();
    });

    it('renders', function () {
        this.set('email', '');

        this.render(hbs`
            {{gh-profile-image email=email}}
        `);

        expect(this.$()).to.have.length(1);
    });

    it('renders default image if no email supplied', function () {
        this.set('email', null);

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=50}}
        `);

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal('display: none');
    });

    it('renders the gravatar if valid email supplied and privacy.useGravatar allows it', async function () {
        let email = 'test@example.com';
        let expectedUrl = `//www.gravatar.com/avatar/${md5(email)}?s=100&d=404`;

        this.set('email', email);

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=50}}
        `);

        // wait for the ajax request to complete
        await wait();

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal(`background-image: url(${expectedUrl}); display: block`);
    });

    it('doesn\'t render the gravatar if valid email supplied but privacy.useGravatar forbids it', async function () {
        let email = 'test@example.com';

        this.set('email', email);
        this.set('config.useGravatar', false);

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=50}}
        `);

        await wait();

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal('display: none');
    });

    it('doesn\'t add background url if gravatar image doesn\'t exist', async function () {
        stubUnknownGravatar(server);

        this.render(hbs`
            {{gh-profile-image email="test@example.com" size=100 debounce=50}}
        `);

        await wait();

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal('background-image: url(); display: none');
    });

    it('throttles gravatar loading as email is changed', async function () {
        let email = 'test@example.com';
        let expectedUrl = `//www.gravatar.com/avatar/${md5(email)}?s=100&d=404`;

        this.set('email', 'test');

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=300}}
        `);

        run(() => {
            this.set('email', email);
        });

        expect(this.$('.gravatar-img').attr('style'), '.gravatar-img background not immediately changed on email change')
            .to.equal('display: none');

        await timeout(250);

        expect(this.$('.gravatar-img').attr('style'), '.gravatar-img background still not changed before debounce timeout')
            .to.equal('display: none');

        await timeout(100);

        expect(this.$('.gravatar-img').attr('style'), '.gravatar-img background changed after debounce timeout')
            .to.equal(`background-image: url(${expectedUrl}); display: block`);
    });
});
<commit_msg>Fixed gh-profile-image tests<commit_after>import Pretender from 'pretender';
import Service from '@ember/service';
import hbs from 'htmlbars-inline-precompile';
import md5 from 'npm:blueimp-md5';
import wait from 'ember-test-helpers/wait';
import {describe, it} from 'mocha';
import {expect} from 'chai';
import {run} from '@ember/runloop';
import {setupComponentTest} from 'ember-mocha';
import {timeout} from 'ember-concurrency';

let pathsStub = Service.extend({
    assetRoot: '/ghost/assets/',

    init() {
        this._super(...arguments);

        this.url = {
            api() {
                return '';
            },
            asset(src) {
                return src;
            }
        };
    }
});

const stubKnownGravatar = function (server) {
    server.get('http://www.gravatar.com/avatar/:md5', function () {
        return [200, {'Content-Type': 'image/png'}, ''];
    });

    server.head('http://www.gravatar.com/avatar/:md5', function () {
        return [200, {'Content-Type': 'image/png'}, ''];
    });
};

const stubUnknownGravatar = function (server) {
    server.get('http://www.gravatar.com/avatar/:md5', function () {
        return [404, {}, ''];
    });

    server.head('http://www.gravatar.com/avatar/:md5', function () {
        return [404, {}, ''];
    });
};

let configStubuseGravatar = Service.extend({
    useGravatar: true
});

describe('Integration: Component: gh-profile-image', function () {
    setupComponentTest('gh-profile-image', {
        integration: true
    });

    let server;

    beforeEach(function () {
        this.register('service:ghost-paths', pathsStub);
        this.inject.service('ghost-paths', {as: 'ghost-paths'});
        this.register('service:config', configStubuseGravatar);
        this.inject.service('config', {as: 'config'});

        server = new Pretender();
        stubKnownGravatar(server);
    });

    afterEach(function () {
        server.shutdown();
    });

    it('renders', function () {
        this.set('email', '');

        this.render(hbs`
            {{gh-profile-image email=email}}
        `);

        expect(this.$()).to.have.length(1);
    });

    it('renders default image if no email supplied', function () {
        this.set('email', null);

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=50}}
        `);

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal('display: none');
    });

    it('renders the gravatar if valid email supplied and privacy.useGravatar allows it', async function () {
        let email = 'test@example.com';
        let expectedUrl = `//www.gravatar.com/avatar/${md5(email)}?s=100&d=404`;

        this.set('email', email);

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=50}}
        `);

        // wait for the ajax request to complete
        await wait();

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal(`background-image: url(${expectedUrl}); display: block`);
    });

    it('doesn\'t render the gravatar if valid email supplied but privacy.useGravatar forbids it', async function () {
        let email = 'test@example.com';

        this.set('email', email);
        this.set('config.useGravatar', false);

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=50}}
        `);

        await wait();

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal('display: none');
    });

    it('doesn\'t add background url if gravatar image doesn\'t exist', async function () {
        stubUnknownGravatar(server);

        this.render(hbs`
            {{gh-profile-image email="test@example.com" size=100 debounce=50}}
        `);

        await wait();

        expect(this.$('.gravatar-img').attr('style'), 'gravatar image style')
            .to.equal('background-image: url(); display: none');
    });

    it('throttles gravatar loading as email is changed', async function () {
        let email = 'test@example.com';
        let expectedUrl = `//www.gravatar.com/avatar/${md5(email)}?s=100&d=404`;

        this.set('email', 'test');

        this.render(hbs`
            {{gh-profile-image email=email size=100 debounce=300}}
        `);

        run(() => {
            this.set('email', email);
        });

        expect(this.$('.gravatar-img').attr('style'), '.gravatar-img background not immediately changed on email change')
            .to.equal('display: none');

        await timeout(250);

        expect(this.$('.gravatar-img').attr('style'), '.gravatar-img background still not changed before debounce timeout')
            .to.equal('display: none');

        await timeout(100);

        expect(this.$('.gravatar-img').attr('style'), '.gravatar-img background changed after debounce timeout')
            .to.equal(`background-image: url(${expectedUrl}); display: block`);
    });
});
<|endoftext|>