<commit_before>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
define(['jquery'], function($) {
  var XWikiMeta = function () {
    var self = this;

    self.init = function () {
      // Note: Starting with XWiki 7.2M3, the returned "document", "xwiki", "space" and "page" variables are deprecated
      // and it's recommended to use the new "reference" variable, which holds the full String reference of the current
      // document.
      // In addition starting with XWiki 7.2M1, the "space" variable now holds the full space reference (i.e. one or
      // several spaces separated by dots, e.g. "space1.space2").
      var html = $('html');
      // Case 1: meta information are stored in the data- attributes of the <html> tag
      // (since Flamingo)
      if (html.data('xwiki-reference') !== undefined) {
        self.documentReference = XWiki.Model.resolve(html.data('xwiki-reference'), XWiki.EntityType.DOCUMENT);
        var wikiReference = documentReference.extractReference(XWiki.EntityType.WIKI);
        var spaceReference = documentReference.extractReference(XWiki.EntityType.SPACE);
        // deprecated, use 'documentReference' instead
        self.document = XWiki.Model.serialize(documentReference.relativeTo(wikiReference));
        // deprecated, use 'documentReference' instead
        self.wiki = wikiReference.getName();
        // deprecated, use 'documentReference' instead
        self.space = XWiki.Model.serialize(spaceReference.relativeTo(wikiReference));
        self.page = documentReference.getName();
        self.version = html.data('xwiki-version');
        self.restURL = html.data('xwiki-rest-url');
        self.form_token = html.data('xwiki-form-token');
        // Since 10.4RC1
        self.userReference = XWiki.Model.resolve(html.data('xwiki-user-reference'), XWiki.EntityType.DOCUMENT);
        // Since 11.2RC1
        self.isNew = html.data('xwiki-isnew');
      } else {
        // Case 2: meta information are stored in deprecated <meta> tags
        // (in colibri)
        var metaTags = $('meta');
        var lookingFor = ['document', 'wiki', 'space', 'page', 'version', 'restURL', 'form_token'];
        for (var i = 0; i < metaTags.length; ++i) {
          var metaTag = $(metaTags[i]);
          var name = metaTag.attr('name');
          for (var j = 0; j < lookingFor.length; ++j) {
            if (name == lookingFor[j]) {
              self[name] = metaTag.attr('content');
            }
          }
        }
      }
    };

    self.setVersion = function (newVersion) {
      self.version = newVersion;
      document.fire('xwiki:document:changeVersion', {'version': self.version, 'documentReference': documentReference});
    };

    /**
     * Refresh the version of a document from a REST endpoint. It fires a xwiki:document:changeVersion event.
     * In case of 404 this certainly means that the document is new.
     * @param handle404 function to choose how to handle when the document is new.
     */
    self.refreshVersion = function (handle404) {
      var pageInfoUrl = self.restURL;
      pageInfoUrl += "?media=json";
      $.getJSON(pageInfoUrl).done(function (data) {
        self.setVersion(data.version);
      }).fail(function (err) {
        if (err.status === 404 && typeof(handle404) === "function") {
          handle404(err);
        } else {
          console.error("Error while refreshing the version from URL "+pageInfoUrl, err);
        }
      });
    };

    self.init();
  };

  return new XWikiMeta();
});
<commit_msg>XWIKI-16443: Conflict warning still displayed when using the browser's Back button on IE11 and Chrome<commit_after>/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
define(['jquery'], function($) {
  var XWikiMeta = function () {
    var self = this;

    self.init = function () {
      // Note: Starting with XWiki 7.2M3, the returned "document", "xwiki", "space" and "page" variables are deprecated
      // and it's recommended to use the new "reference" variable, which holds the full String reference of the current
      // document.
      // In addition starting with XWiki 7.2M1, the "space" variable now holds the full space reference (i.e. one or
      // several spaces separated by dots, e.g. "space1.space2").
      var html = $('html');
      // Case 1: meta information are stored in the data- attributes of the <html> tag
      // (since Flamingo)
      if (html.data('xwiki-reference') !== undefined) {
        self.documentReference = XWiki.Model.resolve(html.data('xwiki-reference'), XWiki.EntityType.DOCUMENT);
        var wikiReference = documentReference.extractReference(XWiki.EntityType.WIKI);
        var spaceReference = documentReference.extractReference(XWiki.EntityType.SPACE);
        // deprecated, use 'documentReference' instead
        self.document = XWiki.Model.serialize(documentReference.relativeTo(wikiReference));
        // deprecated, use 'documentReference' instead
        self.wiki = wikiReference.getName();
        // deprecated, use 'documentReference' instead
        self.space = XWiki.Model.serialize(spaceReference.relativeTo(wikiReference));
        self.page = documentReference.getName();
        self.version = html.data('xwiki-version');
        self.restURL = html.data('xwiki-rest-url');
        self.form_token = html.data('xwiki-form-token');
        // Since 10.4RC1
        self.userReference = XWiki.Model.resolve(html.data('xwiki-user-reference'), XWiki.EntityType.DOCUMENT);
        // Since 11.2RC1
        self.isNew = html.data('xwiki-isnew');
      } else {
        // Case 2: meta information are stored in deprecated <meta> tags
        // (in colibri)
        var metaTags = $('meta');
        var lookingFor = ['document', 'wiki', 'space', 'page', 'version', 'restURL', 'form_token'];
        for (var i = 0; i < metaTags.length; ++i) {
          var metaTag = $(metaTags[i]);
          var name = metaTag.attr('name');
          for (var j = 0; j < lookingFor.length; ++j) {
            if (name == lookingFor[j]) {
              self[name] = metaTag.attr('content');
            }
          }
        }
      }
    };

    self.setVersion = function (newVersion) {
      self.version = newVersion;
      document.fire('xwiki:document:changeVersion', {'version': self.version, 'documentReference': documentReference});
    };

    /**
     * Refresh the version of a document from a REST endpoint. It fires a xwiki:document:changeVersion event.
     * In case of 404 this certainly means that the document is new.
     * @param handle404 function to choose how to handle when the document is new.
     */
    self.refreshVersion = function (handle404) {
      var pageInfoUrl = self.restURL;
      // We put a timestamp in the JSON URL to avoid getting it from cache.
      pageInfoUrl += "?media=json&timestamp=" + new Date().getTime();
      $.getJSON(pageInfoUrl).done(function (data) {
        self.setVersion(data.version);
      }).fail(function (err) {
        if (err.status === 404 && typeof(handle404) === "function") {
          handle404(err);
        } else {
          console.error("Error while refreshing the version from URL "+pageInfoUrl, err);
        }
      });
    };

    self.init();
  };

  return new XWikiMeta();
});
<|endoftext|>


<commit_before>angular.module("umbraco").controller("TeaCommerce.PropertyEditors.variantEditorNodeType", [
'$scope',
'$rootScope',
'$timeout',
'$routeParams',
'contentResource',
'entityResource',
'dialogService',
    function ($scope, $rootScope, $timeout, $routeParams, contentResource, entityResource, dialogService) {

      var config = {
        multiPicker: false,
        callback: function (selectedNode) {
          if (selectedNode) {
            $scope.model.value.contentId = selectedNode.id;
            $scope.model.value.showXPath;
            $scope.model.value.selectedNode = selectedNode;
            $scope.model.value.showChosenContent = true;
            console.log(selectedNode);
          } else {
            $scope.clearContent();
          }
        }
      };

      $scope.openContentPicker = function () {
        var ds = dialogService.contentPicker(config);
      }

      //Clear chosen content
      $scope.clearContent = function () {
        $scope.model.value.contentId = "";
        $scope.model.value.selectedNode = "";
        $scope.model.value.showChosenContent = false;
      };

    }]
);<commit_msg>Fixed null pointer bug<commit_after>angular.module("umbraco").controller("TeaCommerce.PropertyEditors.variantEditorNodeType", [
'$scope',
'$rootScope',
'$timeout',
'$routeParams',
'contentResource',
'entityResource',
'dialogService',
    function ($scope, $rootScope, $timeout, $routeParams, contentResource, entityResource, dialogService) {

      if (!$scope.model.value) {
        $scope.model.value = {};
      }

      var config = {
        multiPicker: false,
        callback: function (selectedNode) {
          if (selectedNode) {
            $scope.model.value.contentId = selectedNode.id;
            $scope.model.value.selectedNode = selectedNode;
            $scope.model.value.showChosenContent = true;
            console.log(selectedNode);
          } else {
            $scope.clearContent();
          }
        }
      };

      $scope.openContentPicker = function () {
        var ds = dialogService.contentPicker(config);
      }

      //Clear chosen content
      $scope.clearContent = function () {
        $scope.model.value.contentId = "";
        $scope.model.value.selectedNode = "";
        $scope.model.value.showChosenContent = false;
      };

    }]
);<|endoftext|>


<commit_before>/// <reference path="../Services/IdentityService.js" />
/// <reference path="../Services/PollService.js" />
/// <reference path="../Services/TokenService.js" />
/// <reference path="../Services/VoteService.js" />
(function () {
    'use strict';

    angular
        .module('GVA.Voting')
        .controller('BasicVoteController', BasicVoteController);

    BasicVoteController.$inject = ['$scope', '$routeParams', 'IdentityService', 'PollService', 'TokenService', 'VoteService', 'ngDialog'];

    function BasicVoteController($scope, $routeParams, IdentityService, PollService, TokenService, VoteService, ngDialog) {

        var pollId = $routeParams.pollId;
        var token = null;

        $scope.options = {};
        $scope.optionAddingAllowed = false;

        $scope.addOption = addOption;
        $scope.notifyOptionAdded = notifyOptionAdded;

        // Register our getVotes strategy with the parent controller
        $scope.setVoteCallback(getVotes);

        activate();

        function activate() {
            $scope.$watch('poll', function () {
                if ($scope.poll) {
                    $scope.options = $scope.poll.Options;
                    $scope.optionAddingAllowed = $scope.poll.OptionAddingAllowed;
                }
            });

            TokenService.getToken(pollId, getTokenSuccessCallback);
        }

        function getTokenSuccessCallback(tokenData) {
            token = tokenData;

            VoteService.getTokenVotes(pollId, token, getTokenVotesSuccessCallback);
        }

        function getTokenVotesSuccessCallback(voteData) {

            if (!voteData || voteData.length === 0) {
                return;
            }

            var vote = voteData[0];

            angular.forEach($scope.options, function (option) {
                if (option.Id === vote.OptionId) {
                    option.selected = true;
                }
            });
        }

        function addOption() {
            ngDialog.open({
                template: '/Routes/AddOptionDialog',
                controller: 'AddVoterOptionDialogController',
                scope: $scope,
                data: { pollId: pollId }
            });
        }

        function notifyOptionAdded() {
            $scope.$emit('voterOptionAddedEvent');
        }

        function getVotes(option) {
            return [{
                OptionId: option.Id,
                VoteValue: 1,
                VoterName: IdentityService.identity && $scope.poll && $scope.poll.NamedVoting ?
                           IdentityService.identity.name : null
            }];
        }
    }
})();
<commit_msg>Fix Voter add option not showing for Basic Vote<commit_after>/// <reference path="../Services/IdentityService.js" />
/// <reference path="../Services/PollService.js" />
/// <reference path="../Services/TokenService.js" />
/// <reference path="../Services/VoteService.js" />
(function () {
    'use strict';

    angular
        .module('GVA.Voting')
        .controller('BasicVoteController', BasicVoteController);

    BasicVoteController.$inject = ['$scope', '$routeParams', 'IdentityService', 'PollService', 'TokenService', 'VoteService', 'ngDialog'];

    function BasicVoteController($scope, $routeParams, IdentityService, PollService, TokenService, VoteService, ngDialog) {

        var pollId = $routeParams.pollId;
        var token = null;

        $scope.options = {};
        $scope.optionAddingAllowed = false;

        $scope.addOption = addOption;
        $scope.notifyOptionAdded = notifyOptionAdded;

        // Register our getVotes strategy with the parent controller
        $scope.setVoteCallback(getVotes);

        activate();

        function activate() {
            $scope.$watch('poll', function () {
                if ($scope.poll) {
                    $scope.options = $scope.poll.Options;
                    $scope.optionAddingAllowed = $scope.poll.OptionAdding;
                }
            });

            TokenService.getToken(pollId, getTokenSuccessCallback);
        }

        function getTokenSuccessCallback(tokenData) {
            token = tokenData;

            VoteService.getTokenVotes(pollId, token, getTokenVotesSuccessCallback);
        }

        function getTokenVotesSuccessCallback(voteData) {

            if (!voteData || voteData.length === 0) {
                return;
            }

            var vote = voteData[0];

            angular.forEach($scope.options, function (option) {
                if (option.Id === vote.OptionId) {
                    option.selected = true;
                }
            });
        }

        function addOption() {
            ngDialog.open({
                template: '/Routes/AddOptionDialog',
                controller: 'AddVoterOptionDialogController',
                scope: $scope,
                data: { pollId: pollId }
            });
        }

        function notifyOptionAdded() {
            $scope.$emit('voterOptionAddedEvent');
        }

        function getVotes(option) {
            return [{
                OptionId: option.Id,
                VoteValue: 1,
                VoterName: IdentityService.identity && $scope.poll && $scope.poll.NamedVoting ?
                           IdentityService.identity.name : null
            }];
        }
    }
})();
<|endoftext|>


<commit_before>import { createSelector } from 'reselect';
import { deburrUpper } from 'app/utils';

const filterCountries = (countries, queryUpper) => {
  if (!queryUpper) return countries;
  return countries.filter(country =>
    deburrUpper(country.wri_standard_name).includes(queryUpper)
  );
};

const getCountries = state => state.countries;
const getQuery = state => state.query;
export const getQueryUpper = state => deburrUpper(state.query);

const addCountriesPath = (countries, query) => {
  const ndcResults = countries.reduce((ndcResult, country) => {
    ndcResult.push({
      value: `${country.iso_code3}`,
      label: `${country.wri_standard_name} Country Page`,
      path: `/countries/${country.iso_code3}`
    });
    ndcResult.push({
      value: `${country.iso_code3}-overview`,
      label: `${country.wri_standard_name} NDC - Overview`,
      path: `/ndcs/country/${country.iso_code3}`
    });
    return ndcResult;
  }, []);

  ndcResults.push({
    value: query,
    label: `Search "${query}" in the content of all NDC's`,
    path: `/ndc-search?searchBy=query&query=${query}`
  });
  return ndcResults;
};

export const getFilteredCountries = createSelector(
  [getCountries, getQueryUpper],
  filterCountries
);

export const getFilteredCountriesWithPath = createSelector(
  [getFilteredCountries, getQuery],
  addCountriesPath
);

export default {
  getFilteredCountries,
  getFilteredCountriesWithPath
};
<commit_msg>another place with unescaped query<commit_after>import { createSelector } from 'reselect';
import { deburrUpper } from 'app/utils';

const filterCountries = (countries, queryUpper) => {
  if (!queryUpper) return countries;
  return countries.filter(country =>
    deburrUpper(country.wri_standard_name).includes(queryUpper)
  );
};

const getCountries = state => state.countries;
const getQuery = state => state.query;
export const getQueryUpper = state => deburrUpper(state.query);

const addCountriesPath = (countries, query) => {
  const ndcResults = countries.reduce((ndcResult, country) => {
    ndcResult.push({
      value: `${country.iso_code3}`,
      label: `${country.wri_standard_name} Country Page`,
      path: `/countries/${country.iso_code3}`
    });
    ndcResult.push({
      value: `${country.iso_code3}-overview`,
      label: `${country.wri_standard_name} NDC - Overview`,
      path: `/ndcs/country/${country.iso_code3}`
    });
    return ndcResult;
  }, []);

  ndcResults.push({
    value: query,
    label: `Search "${query}" in the content of all NDC's`,
    path: `/ndc-search?searchBy=query&query=${encodeURIComponent(query)}`
  });
  return ndcResults;
};

export const getFilteredCountries = createSelector(
  [getCountries, getQueryUpper],
  filterCountries
);

export const getFilteredCountriesWithPath = createSelector(
  [getFilteredCountries, getQuery],
  addCountriesPath
);

export default {
  getFilteredCountries,
  getFilteredCountriesWithPath
};
<|endoftext|>


<commit_before>var Backbone = require('backbone');
var _ = require('underscore');
var pollTimer = 2000;

/**
 *  Geocoding model
 *
 */

module.exports = cdb.core.Model.extend({

  defaults: {
    kind: '',
    formatter: '',
    table_name: '',
    state: ''
  },

  url: function(method) {
    var version = cdb.config.urlVersion('geocoding', method);

    var base = '/api/' + version + '/geocodings/';
    if (this.isNew()) {
      return base;
    }
    return base + this.id;
  },

  setUrlRoot: function(urlRoot) {
    this.urlRoot = urlRoot;
  },

  parse: function(r) {
    // Don't override table_name value
    return _.omit(r, 'table_name');
  },

  initialize: function() {
    this._initBinds();
    this._checkModel();
  },

  _initBinds: function() {
    this.bind('change:id', this._checkModel, this);
    this.bind('change:state', this._checkState, this);
  },

  _checkModel: function() {
    var self = this;

    if (this.get('id')) {
      this.pollCheck();
    } else {
      this._createModel();
    }
  },

  _createModel: function() {
    if (this.isNew()) {
      this.save({}, {
        error: function() {
          self.set('error', {
            title: 'Oops, there was a problem',
            description: 'Unfortunately there was an error starting the geocoder'
          });
        }
      });
    }
  },

  // checks for poll to finish
  pollCheck: function(i) {
    var self = this;
    this.pollTimer = setInterval(function() {
      self.fetch({
        error: function(e) {
          self.trigger("change");
        }
      });
    }, pollTimer);
  },

  destroyCheck: function() {
    clearInterval(this.pollTimer);
    delete this.pollTimer;
  },

  _checkState: function() {
    var state = this.get('state');
    if (state === "finished" || state === "failed" || state === "reset" || state === "cancelled") {
      this.destroyCheck();
    }
  },

  getError: function() {
    return this.get('error');
  },

  hasFailed: function() {
    var state = this.get('state');
    return state === "failed" || state === "reset" || state === "cancelled"
  },

  hasCompleted: function() {
    return this.get('state') === "finished"
  },

  cancelGeocoding: function() {
    this.destroyCheck();
    this.save({ state: 'cancelled' }, { wait:true });
  },

  resetGeocoding: function() {
    this.destroyCheck();
    this.set('state', 'reset');
  }

});
<commit_msg>Fixed geocoding model error when save fails<commit_after>var Backbone = require('backbone');
var _ = require('underscore');
var pollTimer = 2000;

/**
 *  Geocoding model
 *
 */

module.exports = cdb.core.Model.extend({

  defaults: {
    kind: '',
    formatter: '',
    table_name: '',
    state: ''
  },

  url: function(method) {
    var version = cdb.config.urlVersion('geocoding', method);

    var base = '/api/' + version + '/geocodings/';
    if (this.isNew()) {
      return base;
    }
    return base + this.id;
  },

  setUrlRoot: function(urlRoot) {
    this.urlRoot = urlRoot;
  },

  parse: function(r) {
    // Don't override table_name value
    return _.omit(r, 'table_name');
  },

  initialize: function() {
    this._initBinds();
    this._checkModel();
  },

  _initBinds: function() {
    this.bind('change:id', this._checkModel, this);
    this.bind('change:state', this._checkState, this);
  },

  _checkModel: function() {
    var self = this;

    if (this.get('id')) {
      this.pollCheck();
    } else {
      this._createModel();
    }
  },

  _createModel: function() {
    var self = this;
    if (this.isNew()) {
      this.save({}, {
        error: function() {
          self.set({
            state: 'failed',
            error: {
              title: 'Oops, there was a problem',
              description: 'Unfortunately there was an error starting the geocoder'
            }
          });
        }
      });
    }
  },

  // checks for poll to finish
  pollCheck: function(i) {
    var self = this;
    this.pollTimer = setInterval(function() {
      self.fetch({
        error: function(e) {
          self.trigger("change");
        }
      });
    }, pollTimer);
  },

  destroyCheck: function() {
    clearInterval(this.pollTimer);
    delete this.pollTimer;
  },

  _checkState: function() {
    var state = this.get('state');
    if (state === "finished" || state === "failed" || state === "reset" || state === "cancelled") {
      this.destroyCheck();
    }
  },

  getError: function() {
    return this.get('error');
  },

  hasFailed: function() {
    var state = this.get('state');
    return state === "failed" || state === "reset" || state === "cancelled"
  },

  hasCompleted: function() {
    return this.get('state') === "finished"
  },

  cancelGeocoding: function() {
    this.destroyCheck();
    this.save({ state: 'cancelled' }, { wait:true });
  },

  resetGeocoding: function() {
    this.destroyCheck();
    this.set('state', 'reset');
  }

});
<|endoftext|>


<commit_before>/*
 * Copyright 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.analytics.CellMenu',
    dependencies: ['og.common.gadgets.mapping'],
    obj: function () {
        var module = this,
            icons = '.og-num, .og-icon-new-window-2',
            open_icon = '.og-small',
            expand_class = 'og-expanded',
            panels = ['south', 'dock-north', 'dock-center', 'dock-south'],
            width = 34,
            mapping = og.common.gadgets.mapping;
        var constructor = function (grid) {
            var cellmenu = this, depgraph = grid.source.depgraph, primitives = grid.source.type === 'primitives',
                parent = grid.elements.parent, inplace_config, timer;
            cellmenu.frozen = false;
            cellmenu.grid = grid;
            if (og.analytics.containers.initialize) throw new Error(module.name + ': there are no panels');
            cellmenu.busy = (function (busy) {
                return function (value) {return busy = typeof value !== 'undefined' ? value : busy;};
            })(false);
            og.api.text({module: 'og.analytics.cell_options'}).pipe(function (template) {
                (cellmenu.menu = $(template)).hide()
                .on('mouseleave', function () {
                    clearTimeout(timer), cellmenu.menu.removeClass(expand_class), cellmenu.hide();
                })
                .on('mouseenter', open_icon, function () {
                    clearTimeout(timer), timer = setTimeout(function () {cellmenu.menu.addClass(expand_class);}, 500);
                })
                .on('mouseenter', function () {$.data(cellmenu, 'hover', true);})
                .on('click', open_icon, function () {
                    cellmenu.destroy_frozen();
                    cellmenu.menu.addClass(expand_class);
                })
                .on('mouseenter', icons, function () {
                    var panel = panels[$(this).text() - 1];
                    panels.forEach(function (val) {og.analytics.containers[val].highlight(true, val === panel);});
                })
                .on('mouseleave', icons, function () {
                    panels.forEach(function (val) {og.analytics.containers[val].highlight(false);});
                })
                .on('click', icons, function () {
                    var panel = panels[+$(this).text() - 1], cell = cellmenu.current,
                        options = mapping.options(cell, grid, panel);
                    cellmenu.destroy_frozen();
                    cellmenu.hide();
                    if (!panel) og.analytics.url.launch(options); else og.analytics.url.add(panel, options);
                });
                grid.on('cellhoverin', function (cell) {
                    if (cellmenu.frozen || cellmenu.busy()) return;
                    var type = cell.type, hide;
                    cellmenu.menu.removeClass(expand_class);
                    clearTimeout(timer);
                    cellmenu.current = cell;
                    hide =
                        // Hide the cell menu if...
                        !cell.value.logLevel &&                                 // always show if log exists
                        ((cell.col === ((!primitives && !depgraph) && 1))       // Second column of portfolio
                        || ((depgraph || primitives) && cell.col < 1)           // 1st column of depgraph or primitives
                        || (type === 'NODE_ID')                                 // Is node
                        || (cell.right > parent.width())                        // End of the cell not visible
                        || (depgraph && ~mapping.depgraph_blacklist.indexOf(type)));    // Unsupported type on depgraph
                    if (hide) cellmenu.hide(); else cellmenu.show();
                })
                .on('cellhoverout', function () {
                    clearTimeout(timer);
                    setTimeout(function () {if (!cellmenu.menu.is(':hover')) {cellmenu.hide();}});
                })
                .on('scrollstart', function () {
                    cellmenu.busy(true);
                    if (cellmenu.frozen) cellmenu.destroy_frozen(); else cellmenu.hide();
                })
                .on('scrollend', function () {cellmenu.busy(false);});
                og.api.text({module: 'og.analytics.inplace_tash'}).pipe(function (tmpl_inplace) {
                    var unique = og.common.id('inplace');
                    inplace_config = {$cntr: $('.og-inplace', cellmenu.menu), tmpl: tmpl_inplace, data: {name: unique}};
                    cellmenu.inplace = new og.common.util.ui.DropMenu(inplace_config);
                    cellmenu.container = new og.common.gadgets.GadgetsContainer('.OG-layout-analytics-', unique);
                    cellmenu.inplace.$dom.toggle.on('click', function () {
                        if (cellmenu.inplace.toggle_handler()) {
                            cellmenu.create_inplace('.OG-layout-analytics-' + unique);
                            cellmenu.inplace.$dom.menu.blurkill(cellmenu.destroy_frozen.bind(cellmenu));
                        }
                        else cellmenu.destroy_frozen();
                    });
                    cellmenu.container.on('del', function () {cellmenu.destroy_frozen();});
                });
            });
        };
        constructor.prototype.destroy_frozen = function () {
           $('.OG-cell-options.og-frozen').remove();
           $('.og-inplace-resizer').remove();
           og.common.gadgets.manager.clean();
        };
        constructor.prototype.create_inplace = function (unique) {
            var cellmenu = this, panel = 'inplace', options, cell = cellmenu.current, fingerprint,
                offset = cellmenu.inplace.$dom.cntr.offset(), inner = cellmenu.inplace.$dom.menu;
            cellmenu.destroy_frozen();
            cellmenu.frozen = true;
            cellmenu.menu.addClass('og-frozen');
            options = mapping.options(cell, cellmenu.grid, panel);
            fingerprint = JSON.stringify(options);
            options.fingerprint = fingerprint;
            cellmenu.container.add([options]);
            if ((offset.top + inner.height())> $(window).height())
                inner.css({marginTop: -inner.height()});
            if ((offset.left + inner.width())> $(window).width())
                inner.css({marginLeft: -inner.width() + width} );
            new constructor(cellmenu.grid);
            og.analytics.resize({
                selector: unique,
                tmpl: '
',
                handler: function (right, bottom) {
                    var newWidth = ($(window).width() - right) - offset.left,
                        newHeight = ($(window).height() - bottom) - offset.top;
                    inner.css({width: newWidth});
                    inner.css({height: newHeight});
                },
                context:  function (preset) {
                    console.log(preset);
                }
            });
        };
        constructor.prototype.hide = function () {
           var cellmenu = this;
            if (cellmenu.menu && cellmenu.menu.length && !cellmenu.frozen) {
                cellmenu.menu.hide();
            }
        };
        constructor.prototype.show = function () {
            var cellmenu = this, current = this.current;
            if (cellmenu.menu && cellmenu.menu.length) cellmenu.menu.appendTo($('body'))
                .css({top: current.top, left: current.right - width + cellmenu.grid.offset.left}).show();
        };
        return constructor;
    }
});
<commit_msg>resize inplace min width and fixed displaced resizing bug<commit_after>/*
 * Copyright 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.analytics.CellMenu',
    dependencies: ['og.common.gadgets.mapping'],
    obj: function () {
        var module = this,
            icons = '.og-num, .og-icon-new-window-2',
            open_icon = '.og-small',
            expand_class = 'og-expanded',
            panels = ['south', 'dock-north', 'dock-center', 'dock-south'],
            width = 34,
            mapping = og.common.gadgets.mapping;
        var constructor = function (grid) {
            var cellmenu = this, depgraph = grid.source.depgraph, primitives = grid.source.type === 'primitives',
                parent = grid.elements.parent, inplace_config, timer;
            cellmenu.frozen = false;
            cellmenu.grid = grid;
            if (og.analytics.containers.initialize) throw new Error(module.name + ': there are no panels');
            cellmenu.busy = (function (busy) {
                return function (value) {return busy = typeof value !== 'undefined' ? value : busy;};
            })(false);
            og.api.text({module: 'og.analytics.cell_options'}).pipe(function (template) {
                (cellmenu.menu = $(template)).hide()
                .on('mouseleave', function () {
                    clearTimeout(timer), cellmenu.menu.removeClass(expand_class), cellmenu.hide();
                })
                .on('mouseenter', open_icon, function () {
                    clearTimeout(timer), timer = setTimeout(function () {cellmenu.menu.addClass(expand_class);}, 500);
                })
                .on('mouseenter', function () {$.data(cellmenu, 'hover', true);})
                .on('click', open_icon, function () {
                    cellmenu.destroy_frozen();
                    cellmenu.menu.addClass(expand_class);
                })
                .on('mouseenter', icons, function () {
                    var panel = panels[$(this).text() - 1];
                    panels.forEach(function (val) {og.analytics.containers[val].highlight(true, val === panel);});
                })
                .on('mouseleave', icons, function () {
                    panels.forEach(function (val) {og.analytics.containers[val].highlight(false);});
                })
                .on('click', icons, function () {
                    var panel = panels[+$(this).text() - 1], cell = cellmenu.current,
                        options = mapping.options(cell, grid, panel);
                    cellmenu.destroy_frozen();
                    cellmenu.hide();
                    if (!panel) og.analytics.url.launch(options); else og.analytics.url.add(panel, options);
                });
                grid.on('cellhoverin', function (cell) {
                    if (cellmenu.frozen || cellmenu.busy()) return;
                    var type = cell.type, hide;
                    cellmenu.menu.removeClass(expand_class);
                    clearTimeout(timer);
                    cellmenu.current = cell;
                    hide =
                        // Hide the cell menu if...
                        !cell.value.logLevel &&                                 // always show if log exists
                        ((cell.col === ((!primitives && !depgraph) && 1))       // Second column of portfolio
                        || ((depgraph || primitives) && cell.col < 1)           // 1st column of depgraph or primitives
                        || (type === 'NODE_ID')                                 // Is node
                        || (cell.right > parent.width())                        // End of the cell not visible
                        || (depgraph && ~mapping.depgraph_blacklist.indexOf(type)));    // Unsupported type on depgraph
                    if (hide) cellmenu.hide(); else cellmenu.show();
                })
                .on('cellhoverout', function () {
                    clearTimeout(timer);
                    setTimeout(function () {if (!cellmenu.menu.is(':hover')) {cellmenu.hide();}});
                })
                .on('scrollstart', function () {
                    cellmenu.busy(true);
                    if (cellmenu.frozen) cellmenu.destroy_frozen(); else cellmenu.hide();
                })
                .on('scrollend', function () {cellmenu.busy(false);});
                og.api.text({module: 'og.analytics.inplace_tash'}).pipe(function (tmpl_inplace) {
                    var unique = og.common.id('inplace');
                    inplace_config = {$cntr: $('.og-inplace', cellmenu.menu), tmpl: tmpl_inplace, data: {name: unique}};
                    cellmenu.inplace = new og.common.util.ui.DropMenu(inplace_config);
                    cellmenu.container = new og.common.gadgets.GadgetsContainer('.OG-layout-analytics-', unique);
                    cellmenu.inplace.$dom.toggle.on('click', function () {
                        if (cellmenu.inplace.toggle_handler()) {
                            cellmenu.create_inplace('.OG-layout-analytics-' + unique);
                            cellmenu.inplace.$dom.menu.blurkill(cellmenu.destroy_frozen.bind(cellmenu));
                        }
                        else cellmenu.destroy_frozen();
                    });
                    cellmenu.container.on('del', function () {cellmenu.destroy_frozen();});
                });
            });
        };
        constructor.prototype.destroy_frozen = function () {
           $('.OG-cell-options.og-frozen').remove();
           $('.og-inplace-resizer').remove();
           og.common.gadgets.manager.clean();
        };
        constructor.prototype.create_inplace = function (unique) {
            var cellmenu = this, panel = 'inplace', options, cell = cellmenu.current, fingerprint,
                offset = cellmenu.inplace.$dom.cntr.offset(), inner = cellmenu.inplace.$dom.menu;
            cellmenu.destroy_frozen();
            cellmenu.frozen = true;
            cellmenu.menu.addClass('og-frozen');
            options = mapping.options(cell, cellmenu.grid, panel);
            fingerprint = JSON.stringify(options);
            options.fingerprint = fingerprint;
            cellmenu.container.add([options]);
            if ((offset.top + inner.height())> $(window).height())
                inner.css({marginTop: -inner.height()});
            if ((offset.left + inner.width())> $(window).width())
                inner.css({marginLeft: -inner.width() + width} );
            new constructor(cellmenu.grid);
            og.analytics.resize({
                selector: unique,
                tmpl: '
',
                handler: function (right, bottom) {
                    var newWidth = Math.max(480,($(document).outerWidth() - right) - inner.offset().left),
                        newHeight = ($(window).height() - bottom) - inner.offset().top;
                    inner.css({width: newWidth});
                    inner.css({height: newHeight});
                }
            });
        };
        constructor.prototype.hide = function () {
           var cellmenu = this;
            if (cellmenu.menu && cellmenu.menu.length && !cellmenu.frozen) {
                cellmenu.menu.hide();
            }
        };
        constructor.prototype.show = function () {
            var cellmenu = this, current = this.current;
            if (cellmenu.menu && cellmenu.menu.length) cellmenu.menu.appendTo($('body'))
                .css({top: current.top, left: current.right - width + cellmenu.grid.offset.left}).show();
        };
        return constructor;
    }
});
<|endoftext|>


<commit_before>/*
 * Copyright 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.analytics.DropMenu',
    dependencies: ['og.common.util.ui.DropMenu'],
    obj: function () {
        var events = {
                queryselected: 'dropmenu:queryselected',
                querycancelled: 'dropmenu:querycancelled'
            },
            DropMenu = function (config) {
                /**
                * TODO AG: Must provide Getters/Setters for static instance properties as these should
                * really be private and not accessible directly via the instance.
                */
                var menu = new og.common.util.ui.DropMenu(config), dummy_s = '<wrapper>';
                menu.$dom.toggle_prefix = $(dummy_s);
                menu.$dom.toggle_infix = $(dummy_s).append('then');
                menu.$dom.menu_actions = $('.og-menu-actions', menu.$dom.menu);
                menu.$dom.opt = $('.OG-dropmenu-options', menu.$dom.menu);
                menu.$dom.opt.data('pos', ((menu.opts = []).push(menu.$dom.opt), menu.opts.length-1));
                menu.$dom.add = $('.OG-link-add', menu.$dom.menu);
                menu.$dom.opt_cp = menu.$dom.opt.clone(true);
                if (menu.$dom.toggle) menu.$dom.toggle.on('click', menu.toggle_menu.bind(menu));
                return menu;
            };
        DropMenu.prototype = og.common.util.ui.DropMenu.prototype;
        DropMenu.prototype.toggle_menu = function (event){
            this.opts[this.opts.length-1].find('select').first().focus();
            this.toggle_handler();
        };
        DropMenu.prototype.add_handler = function () {
            return len = this.opts.length, opt = this.$dom.opt_cp.clone(true).data("pos", this.opts.length),
                this.opts.push(opt), this.$dom.add.focus(), this.opts[len].find('.number span').text(this.opts.length),
                this.$dom.menu_actions.before(this.opts[len]);
        };
        DropMenu.prototype.delete_handler = function (elem) {
            var data = elem.data();
            if (this.opts.length === 1) return;
            this.opts.splice(data.pos, 1);
            elem.remove();
            this.update_opt_nums(data.pos);
            if (data.pos < this.opts.length) this.opts[data.pos].find('select').first().focus();
            else this.opts[data.pos-1].find('select').first().focus();
        };
        DropMenu.prototype.update_opt_nums = function (pos) {
            for (var i = pos || 0, len = this.opts.length; i < len;)
                this.opts[i].data('pos', i).find('.number span').text(i+=1);
        };
        DropMenu.prototype.sort_opts = function (a, b) {
            if (a.pos  b.pos) return 1;
            return 0;
        };
        DropMenu.prototype.button_handler = function (val) {
            if (val === 'OK') this.emitEvent(this.events.close).emitEvent(events.queryselected, [this]);
            else if (val === 'Cancel') this.emitEvent(this.events.close).emitEvent(events.querycancelled, [this]);
        };
        DropMenu.prototype.capitalize = function (string) {
            return string.charAt(0).toUpperCase() + string.slice(1);
        };
        return DropMenu;
    }
});<commit_msg>focus select fix in DropMenu<commit_after>/*
 * Copyright 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 * Please see distribution for license.
 */
$.register_module({
    name: 'og.analytics.DropMenu',
    dependencies: ['og.common.util.ui.DropMenu'],
    obj: function () {
        var events = {
                queryselected: 'dropmenu:queryselected',
                querycancelled: 'dropmenu:querycancelled'
            },
            DropMenu = function (config) {
                /**
                * TODO AG: Must provide Getters/Setters for static instance properties as these should
                * really be private and not accessible directly via the instance.
                */
                var menu = new og.common.util.ui.DropMenu(config), dummy_s = '<wrapper>';
                menu.$dom.toggle_prefix = $(dummy_s);
                menu.$dom.toggle_infix = $(dummy_s).append('then');
                menu.$dom.menu_actions = $('.og-menu-actions', menu.$dom.menu);
                menu.$dom.opt = $('.OG-dropmenu-options', menu.$dom.menu);
                menu.$dom.opt.data('pos', ((menu.opts = []).push(menu.$dom.opt), menu.opts.length-1));
                menu.$dom.add = $('.OG-link-add', menu.$dom.menu);
                menu.$dom.opt_cp = menu.$dom.opt.clone(true);
                if (menu.$dom.toggle) menu.$dom.toggle.on('click', menu.toggle_menu.bind(menu));
                return menu;
            };
        DropMenu.prototype = og.common.util.ui.DropMenu.prototype;
        DropMenu.prototype.toggle_menu = function (event){
            this.opts[this.opts.length-1].find('select').first().focus(0);
            this.toggle_handler();
        };
        DropMenu.prototype.add_handler = function () {
            var len, opt;
            return len = this.opts.length, opt = this.$dom.opt_cp.clone(true).data("pos", this.opts.length),
                this.opts.push(opt), this.$dom.add.focus(), this.opts[len].find('.number span').text(this.opts.length),
                this.$dom.menu_actions.before(this.opts[len]);
        };
        DropMenu.prototype.delete_handler = function (elem) {
            var data = elem.data();
            if (this.opts.length === 1) return;
            this.opts.splice(data.pos, 1);
            elem.remove();
            this.update_opt_nums(data.pos);
            if (data.pos < this.opts.length) this.opts[data.pos].find('select').first().focus();
            else this.opts[data.pos-1].find('select').first().focus();
        };
        DropMenu.prototype.update_opt_nums = function (pos) {
            for (var i = pos || 0, len = this.opts.length; i < len;)
                this.opts[i].data('pos', i).find('.number span').text(i+=1);
        };
        DropMenu.prototype.sort_opts = function (a, b) {
            if (a.pos  b.pos) return 1;
            return 0;
        };
        DropMenu.prototype.button_handler = function (val) {
            if (val === 'OK') this.emitEvent(this.events.close).emitEvent(events.queryselected, [this]);
            else if (val === 'Cancel') this.emitEvent(this.events.close).emitEvent(events.querycancelled, [this]);
        };
        DropMenu.prototype.capitalize = function (string) {
            return string.charAt(0).toUpperCase() + string.slice(1);
        };
        return DropMenu;
    }
});<|endoftext|>


<commit_before>/**
 * (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
(function () {
  'use strict';

  angular
    .module('horizon.dashboard.project.search')
    .filter('commonVisibility', commonStatusFilter);

  commonStatusFilter.$inject = [
    'imageVisibilityFilter',
    'horizon.framework.util.i18n.gettext'
  ];

  /**
   * @ngdoc filter
   * @name commonStatusFilter
   * @description
   * Takes raw status from the API and returns the user friendly status if found.
   *
   * @param {function} $filter angular filter
   *
   * @param {function} gettext internationalization
   *
   * @returns {String} User friendly status if found.
   */
  function commonStatusFilter(imageVisibility, gettext) {
    var defaultVisibilities = {
      'public': gettext('Public'),
      'private': gettext('Private'),
      'shared_with_me': gettext('Shared with Me'),
      'shared': gettext('Shared with Me'),
      'unknown': null
    };

    //TODO use the registry
    var registeredFilters = {
      'OS::Glance::Image': imageVisibility,
      'OS::Glance::Snapshot': imageVisibility
    };

    return function getVisibility(resourceType, resourceSource, currentProjectId) {
      if (null !== resourceSource && angular.isDefined(resourceSource)) {
        if (registeredFilters[resourceType]) {
          return registeredFilters[resourceType](resourceSource, currentProjectId);
        }
      }

      return evaluateBasicVisbilityRules(resourceSource, currentProjectId);
    };

    function evaluateBasicVisbilityRules(resourceSource, currentProjectId) {
      // visibility property is preferred over is_public property
      var translatedVisibility;
      if (angular.isDefined(resourceSource.visibility)) {
        translatedVisibility = safeTranslateVisibility(resourceSource.visibility);
      } else if (angular.isDefined(resourceSource.is_public)) {
        translatedVisibility = translateIsPublic(resourceSource.is_public);
      } else if (angular.isDefined(resourceSource.shared)) {
        translatedVisibility = translateShared(resourceSource.shared);
      } else {
        translatedVisibility = defaultVisibilities.unknown;
      }

      return deriveSharingStatus(resourceSource, currentProjectId, translatedVisibility);
    }

    function deriveSharingStatus(resourceSource, currentProjectId, translatedVisibility) {
      if (angular.equals(defaultVisibilities.unknown, translatedVisibility) &&
        angular.isDefined(currentProjectId) &&
        angular.isDefined(resourceSource.project_id)) {
        if (angular.equals(resourceSource.project_id, currentProjectId)) {
          return defaultVisibilities.private;
        } else {
          return defaultVisibilities.shared_with_me;
        }
      }
      else {
        return translatedVisibility;
      }
    }

    function safeTranslateVisibility(visibility) {
      // Rather than show a default visibility when the visibility is not found
      // this will show the untranslated visibility. This allows the code
      // to be more forgiving if a new status is added.
      var translation = defaultVisibilities[visibility];
      if (angular.isDefined(translation)) {
        return translation;
      } else {
        return visibility;
      }
    }

    function translateIsPublic(isPublic) {
      if (isPublic) {
        return defaultVisibilities.public;
      } else {
        return defaultVisibilities.private;
      }
    }

    function translateShared(shared) {
      if (shared) {
        return defaultVisibilities.shared;
      } else {
        return defaultVisibilities.private;
      }
    }

  }

}());
<commit_msg>some visibility fixes<commit_after>/**
 * (c) Copyright 2015 Hewlett-Packard Development Company, L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
(function () {
  'use strict';

  angular
    .module('horizon.dashboard.project.search')
    .filter('commonVisibility', commonStatusFilter);

  commonStatusFilter.$inject = [
    'imageVisibilityFilter',
    'horizon.framework.util.i18n.gettext'
  ];

  /**
   * @ngdoc filter
   * @name commonStatusFilter
   * @description
   * Takes raw status from the API and returns the user friendly status if found.
   *
   * @param {function} $filter angular filter
   *
   * @param {function} gettext internationalization
   *
   * @returns {String} User friendly status if found.
   */
  function commonStatusFilter(imageVisibility, gettext) {
    var defaultVisibilities = {
      'public': gettext('Public'),
      'private': gettext('Private'),
      'shared_with_me': gettext('Shared with Me'),
      'shared_by_me': gettext('Shared by Me'),
      'shared': gettext('Shared with Me'),
      'unknown': null
    };

    var sharedByMeIfOwnedByMe = [
      defaultVisibilities.public,
      defaultVisibilities.shared,
      defaultVisibilities.shared_by_me,
      defaultVisibilities.shared
    ];

    //TODO use the registry
    var registeredFilters = {
      'OS::Glance::Image': imageVisibility,
      'OS::Glance::Snapshot': imageVisibility
    };

    return function getVisibility(resourceType, resourceSource, currentProjectId) {
      if (null !== resourceSource && angular.isDefined(resourceSource)) {
        if (registeredFilters[resourceType]) {
          return registeredFilters[resourceType](resourceSource, currentProjectId);
        }
      }

      return evaluateBasicVisbilityRules(resourceSource, currentProjectId);
    };

    function evaluateBasicVisbilityRules(resourceSource, currentProjectId) {
      // visibility property is preferred over is_public property
      var translatedVisibility;
      if (angular.isDefined(resourceSource.visibility)) {
        translatedVisibility = safeTranslateVisibility(resourceSource.visibility);
      } else if (angular.isDefined(resourceSource.is_public)) {
        translatedVisibility = translateIsPublic(resourceSource.is_public);
      } else if (angular.isDefined(resourceSource.shared)) {
        translatedVisibility = translateShared(resourceSource.shared);
      } else {
        translatedVisibility = defaultVisibilities.unknown;
      }

      return deriveSharingStatus(resourceSource, currentProjectId, translatedVisibility);
    }

    function deriveSharingStatus(resourceSource, currentProjectId, translatedVisibility) {
      if (angular.equals(defaultVisibilities.unknown, translatedVisibility)) {
        if (isOwnedByMe(resourceSource, currentProjectId)) {
          return defaultVisibilities.private;
        } else {
          return defaultVisibilities.shared_with_me;
        }
      } else if (isOwnedByMe(resourceSource, currentProjectId) &&
          sharedByMeIfOwnedByMe.indexOf(translatedVisibility)) {
          return defaultVisibilities.shared_by_me;
      }
      else {
        return translatedVisibility;
      }
    }

    function safeTranslateVisibility(visibility) {
      // Rather than show a default visibility when the visibility is not found
      // this will show the untranslated visibility. This allows the code
      // to be more forgiving if a new status is added.
      var translation = defaultVisibilities[visibility];
      if (angular.isDefined(translation)) {
        return translation;
      } else {
        return visibility;
      }
    }

    function translateIsPublic(isPublic) {
      if (isPublic) {
        return defaultVisibilities.public;
      } else {
        return defaultVisibilities.private;
      }
    }

    function translateShared(shared) {
      if (shared) {
        return defaultVisibilities.shared;
      } else {
        return defaultVisibilities.private;
      }
    }

    function isOwnedByMe(resourceSource, currentProjectId) {
      return angular.equals(resourceSource.project_id, currentProjectId)
    }
  }

}());
<|endoftext|>


<commit_before>describe('contentEditingHelper tests', function () {
    var contentEditingHelper, $routeParams, serverValidationManager, mocksUtils, notificationsService;

    beforeEach(module('umbraco.services'));
    beforeEach(module('umbraco.mocks'));

    beforeEach(inject(function ($injector) {
        contentEditingHelper = $injector.get('contentEditingHelper');
        $routeParams = $injector.get('$routeParams');
        serverValidationManager = $injector.get('serverValidationManager');
        mocksUtils = $injector.get('mocksUtils');
        notificationsService = $injector.get('notificationsService');
    }));

    describe('handles http validation errors', function () {

        it('handles validation errors for 403 results', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var err = {
                data: content,
                status: 403
            };
            err.data.ModelState = {};

            //act
            var handled = contentEditingHelper.handleSaveError({
                err: err,
                allNewProps: contentEditingHelper.getAllProps(content),
                allOrigProps: contentEditingHelper.getAllProps(content)
            });

            //assert
            expect(handled).toBe(true);
        });

        it('does not handle validation errors that are not 403', function () {

            //arrange
            var err = {
                status: 400
            };

            //act
            var handled = contentEditingHelper.handleSaveError({
                err: err,
                allNewProps: [],
                allOrigProps: []
            });

            //assert
            expect(handled).toBe(false);
        });

        it('does not handle validation errors that are 403 without model state', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var err = {
                data: content,
                status: 403
            };

            //act
            var handled = contentEditingHelper.handleSaveError({
                err: err,
                allNewProps: contentEditingHelper.getAllProps(content),
                allOrigProps: contentEditingHelper.getAllProps(content)
            });

            //assert
            expect(handled).toBe(false);
        });

    });

    describe('handling validation errors', function () {

        it('adds a field level server validation error when name is invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(allProps, { Name: ["Required"] });

            //assert
            expect(serverValidationManager.items.length).toBe(1);
            expect(serverValidationManager.items[0].fieldName).toBe("Name");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe(null);
        });

        it('adds a property level server validation error when a property is invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(allProps, { "Property.bodyText": ["Required"] });

            //assert
            expect(serverValidationManager.items.length).toBe(1);
            expect(serverValidationManager.items[0].fieldName).toBe("");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe("bodyText");
        });

        it('adds a property level server validation error with a specific field when a property is invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(allProps, { "Property.bodyText.value": ["Required"] });

            //assert
            expect(serverValidationManager.items.length).toBe(1);
            expect(serverValidationManager.items[0].fieldName).toBe("value");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe("bodyText");
        });

        it('adds a multiple property and field level server validation errors when they are invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(
                allProps,
                {
                    "Name": ["Required"],
                    "UpdateDate": ["Invalid date"],
                    "Property.bodyText.value": ["Required field"],
                    "Property.textarea": ["Invalid format"]
                });

            //assert
            expect(serverValidationManager.items.length).toBe(4);
            expect(serverValidationManager.items[0].fieldName).toBe("Name");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe(null);
            expect(serverValidationManager.items[1].fieldName).toBe("UpdateDate");
            expect(serverValidationManager.items[1].errorMsg).toBe("Invalid date");
            expect(serverValidationManager.items[1].propertyAlias).toBe(null);
            expect(serverValidationManager.items[2].fieldName).toBe("value");
            expect(serverValidationManager.items[2].errorMsg).toBe("Required field");
            expect(serverValidationManager.items[2].propertyAlias).toBe("bodyText");
            expect(serverValidationManager.items[3].fieldName).toBe("");
            expect(serverValidationManager.items[3].errorMsg).toBe("Invalid format");
            expect(serverValidationManager.items[3].propertyAlias).toBe("textarea");
        });

    });

    describe('redirecting behavior after saving content', function () {

        it('does not redirect when editing existing content', function () {

            //arrange
            $routeParams.create = undefined;

            //act
            var result = contentEditingHelper.redirectToCreatedContent(1234, null);

            //assert
            expect(result).toBe(false);
        });

        it('does a redirect when creating content with a valid name', function () {

            //arrange
            $routeParams.create = true;

            //act
            var result = contentEditingHelper.redirectToCreatedContent(1234, null);

            //assert
            expect(result).toBe(true);
        });

        it('does not redirect when creating content with an invalid name', function () {

            //arrange
            $routeParams.create = true;

            //act
            var result = contentEditingHelper.redirectToCreatedContent(1234, {Name: ["Required"]});

            //assert
            expect(result).toBe(false);

        });

    });

    describe('wires up property values after saving', function () {

        it('does not update un-changed values', function () {

            //arrange
            var origContent = mocksUtils.getMockContent(1234);
            origContent.tabs[0].properties[0].value = { complex1: "origValue1a", complex2: "origValue1b" };
            origContent.tabs[1].properties[0].value = "origValue2";
            origContent.tabs[1].properties[1].value = "origValue3";
            origContent.tabs[1].properties[2].value = "origValue4";

            var newContent = mocksUtils.getMockContent(1234);
            newContent.tabs[0].properties[0].value = { complex1: "origValue1a", complex2: "newValue1b" };
            newContent.tabs[1].properties[0].value = "origValue2";
            newContent.tabs[1].properties[1].value = "newValue3";
            newContent.tabs[1].properties[2].value = "origValue4";

            //act
            var changed = contentEditingHelper.reBindChangedProperties(origContent, newContent);

            //assert
            expect(changed.length).toBe(2);
            expect(changed[0].alias).toBe("list");
            expect(changed[1].alias).toBe("bodyText");
        });

    });
});<commit_msg>added 1.2 upgrade note<commit_after>describe('contentEditingHelper tests', function () {
    var contentEditingHelper, $routeParams, serverValidationManager, mocksUtils, notificationsService;

    beforeEach(module('umbraco.services'));
    beforeEach(module('umbraco.mocks'));

    //Only for 1.2: beforeEach(module('ngRoute'));

    beforeEach(inject(function ($injector) {
        contentEditingHelper = $injector.get('contentEditingHelper');
        $routeParams = $injector.get('$routeParams');
        serverValidationManager = $injector.get('serverValidationManager');
        mocksUtils = $injector.get('mocksUtils');
        notificationsService = $injector.get('notificationsService');
    }));

    describe('handles http validation errors', function () {

        it('handles validation errors for 403 results', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var err = {
                data: content,
                status: 403
            };
            err.data.ModelState = {};

            //act
            var handled = contentEditingHelper.handleSaveError({
                err: err,
                allNewProps: contentEditingHelper.getAllProps(content),
                allOrigProps: contentEditingHelper.getAllProps(content)
            });

            //assert
            expect(handled).toBe(true);
        });

        it('does not handle validation errors that are not 403', function () {

            //arrange
            var err = {
                status: 400
            };

            //act
            var handled = contentEditingHelper.handleSaveError({
                err: err,
                allNewProps: [],
                allOrigProps: []
            });

            //assert
            expect(handled).toBe(false);
        });

        it('does not handle validation errors that are 403 without model state', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var err = {
                data: content,
                status: 403
            };

            //act
            var handled = contentEditingHelper.handleSaveError({
                err: err,
                allNewProps: contentEditingHelper.getAllProps(content),
                allOrigProps: contentEditingHelper.getAllProps(content)
            });

            //assert
            expect(handled).toBe(false);
        });

    });

    describe('handling validation errors', function () {

        it('adds a field level server validation error when name is invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(allProps, { Name: ["Required"] });

            //assert
            expect(serverValidationManager.items.length).toBe(1);
            expect(serverValidationManager.items[0].fieldName).toBe("Name");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe(null);
        });

        it('adds a property level server validation error when a property is invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(allProps, { "Property.bodyText": ["Required"] });

            //assert
            expect(serverValidationManager.items.length).toBe(1);
            expect(serverValidationManager.items[0].fieldName).toBe("");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe("bodyText");
        });

        it('adds a property level server validation error with a specific field when a property is invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(allProps, { "Property.bodyText.value": ["Required"] });

            //assert
            expect(serverValidationManager.items.length).toBe(1);
            expect(serverValidationManager.items[0].fieldName).toBe("value");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe("bodyText");
        });

        it('adds a multiple property and field level server validation errors when they are invalid', function () {

            //arrange
            var content = mocksUtils.getMockContent(1234);
            var allProps = contentEditingHelper.getAllProps(content);

            //act
            contentEditingHelper.handleValidationErrors(
                allProps,
                {
                    "Name": ["Required"],
                    "UpdateDate": ["Invalid date"],
                    "Property.bodyText.value": ["Required field"],
                    "Property.textarea": ["Invalid format"]
                });

            //assert
            expect(serverValidationManager.items.length).toBe(4);
            expect(serverValidationManager.items[0].fieldName).toBe("Name");
            expect(serverValidationManager.items[0].errorMsg).toBe("Required");
            expect(serverValidationManager.items[0].propertyAlias).toBe(null);
            expect(serverValidationManager.items[1].fieldName).toBe("UpdateDate");
            expect(serverValidationManager.items[1].errorMsg).toBe("Invalid date");
            expect(serverValidationManager.items[1].propertyAlias).toBe(null);
            expect(serverValidationManager.items[2].fieldName).toBe("value");
            expect(serverValidationManager.items[2].errorMsg).toBe("Required field");
            expect(serverValidationManager.items[2].propertyAlias).toBe("bodyText");
            expect(serverValidationManager.items[3].fieldName).toBe("");
            expect(serverValidationManager.items[3].errorMsg).toBe("Invalid format");
            expect(serverValidationManager.items[3].propertyAlias).toBe("textarea");
        });

    });

    describe('redirecting behavior after saving content', function () {

        it('does not redirect when editing existing content', function () {

            //arrange
            $routeParams.create = undefined;

            //act
            var result = contentEditingHelper.redirectToCreatedContent(1234, null);

            //assert
            expect(result).toBe(false);
        });

        it('does a redirect when creating content with a valid name', function () {

            //arrange
            $routeParams.create = true;

            //act
            var result = contentEditingHelper.redirectToCreatedContent(1234, null);

            //assert
            expect(result).toBe(true);
        });

        it('does not redirect when creating content with an invalid name', function () {

            //arrange
            $routeParams.create = true;

            //act
            var result = contentEditingHelper.redirectToCreatedContent(1234, {Name: ["Required"]});

            //assert
            expect(result).toBe(false);

        });

    });

    describe('wires up property values after saving', function () {

        it('does not update un-changed values', function () {

            //arrange
            var origContent = mocksUtils.getMockContent(1234);
            origContent.tabs[0].properties[0].value = { complex1: "origValue1a", complex2: "origValue1b" };
            origContent.tabs[1].properties[0].value = "origValue2";
            origContent.tabs[1].properties[1].value = "origValue3";
            origContent.tabs[1].properties[2].value = "origValue4";

            var newContent = mocksUtils.getMockContent(1234);
            newContent.tabs[0].properties[0].value = { complex1: "origValue1a", complex2: "newValue1b" };
            newContent.tabs[1].properties[0].value = "origValue2";
            newContent.tabs[1].properties[1].value = "newValue3";
            newContent.tabs[1].properties[2].value = "origValue4";

            //act
            var changed = contentEditingHelper.reBindChangedProperties(origContent, newContent);

            //assert
            expect(changed.length).toBe(2);
            expect(changed[0].alias).toBe("list");
            expect(changed[1].alias).toBe("bodyText");
        });

    });
});<|endoftext|>


<commit_before>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 07.05.18
 */
Imcms.define(
    "imcms-admin-panel-settings-builder",
    ["imcms-bem-builder", "imcms-i18n-texts", "jquery"],
    function (BEM, texts, $) {

        texts = texts.panel.settingsList;

        var settingEnabledClass = BEM.buildClass("settings-section", "setting", "enabled");
        var settingEnabledClassSelector = "." + settingEnabledClass;

        var $settings;

        function buildSection(name, settings) {

            var settingsObjects = settings.map(function (setting) {
                setting.click = function () {
                    var $this = $(this);

                    if ($this.hasClass(settingEnabledClass)) return;

                    $this.parent(".settings-section")
                        .find(settingEnabledClassSelector)
                        .removeClass(settingEnabledClass);

                    $this.addClass(settingEnabledClass);

                    setting.onSettingClick.call();
                };

                return {
                    "setting": $("<div>", setting)
                };
            });

            return new BEM({
                block: "settings-section",
                elements: [{
                    "section-name": $("<div>", {text: name})
                }].concat(settingsObjects)
            }).buildBlockStructure("<div>");
        }

        function buildSettings($settingsButton) {
            var bemOptions = {
                block: "admin-panel-settings-list",
                elements: [
                    {
                        "section": buildSection(texts.size.name, [
                            {
                                text: texts.size.small,
                                title: texts.size.smallTitle,
                                onSettingClick: function () {
                                    console.log("Setting 00")
                                }
                            }, {
                                text: texts.size.large,
                                title: texts.size.largeTitle,
                                "class": settingEnabledClass,
                                onSettingClick: function () {
                                    console.log("Setting 01")
                                }
                            }
                        ])
                    }, {
                        "section": buildSection(texts.appearance.name, [
                            {
                                text: texts.appearance.auto,
                                title: texts.appearance.autoTitle,
                                "class": settingEnabledClass,
                                onSettingClick: function () {
                                    console.log("Setting 10")
                                }
                            }, {
                                text: texts.appearance.hidden,
                                title: texts.appearance.hiddenTitle,
                                onSettingClick: function () {
                                    console.log("Setting 11")
                                }
                            }, {
                                text: texts.appearance.visible,
                                title: texts.appearance.visibleTitle,
                                onSettingClick: function () {
                                    console.log("Setting 12")
                                }
                            }
                        ])
                    }
                ]
            };

            return new BEM(bemOptions)
                .buildBlockStructure("<div>", {style: "display: none;"})
                .insertAfter($settingsButton);
        }

        return {
            onSettingsClicked: function () {
                ($settings || ($settings = buildSettings($(this)))).slideToggle();
            },
            hideSettings: function () {
                $settings.slideUp(300);
            }
        }
    }
);
<commit_msg>IMCMS-290 - Add a "pin" icon to imCMS's panel: - Implemented saving chosen settings into cookies.<commit_after>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 07.05.18
 */
Imcms.define(
    "imcms-admin-panel-settings-builder",
    ["imcms-bem-builder", "imcms-cookies", "imcms-i18n-texts", "jquery"],
    function (BEM, cookies, texts, $) {

        texts = texts.panel.settingsList;

        var settingEnabledClass = BEM.buildClass("settings-section", "setting", "enabled");
        var settingEnabledClassSelector = "." + settingEnabledClass;

        var $settings;

        function activateSetting(element) {
            var $setting = $(element);

            if ($setting.hasClass(settingEnabledClass)) return true;

            $setting.parent(".settings-section")
                .find(settingEnabledClassSelector)
                .removeClass(settingEnabledClass);

            $setting.addClass(settingEnabledClass);

            return false;
        }

        function buildSection(id, name, settings) {
            var cookieName = "panel" + id;
            var savedSetting = cookies.getCookie(cookieName);

            var settingsElements = settings.map(function (setting) {
                setting.click = function () {
                    activateSetting(this) && setting.onSettingClick.call();
                    cookies.setCookie(cookieName, setting.id);
                };

                if ((savedSetting && (savedSetting === setting.id))
                    || (!savedSetting && setting.isDefault))
                {
                    setting["class"] = settingEnabledClass;
                }

                return {
                    "setting": $("<div>", setting)
                };
            });

            return new BEM({
                block: "settings-section",
                elements: [{
                    "section-name": $("<div>", {text: name})
                }].concat(settingsElements)
            }).buildBlockStructure("<div>");
        }

        function buildSettings($settingsButton) {
            var bemOptions = {
                block: "admin-panel-settings-list",
                elements: [
                    {
                        "section": buildSection("size", texts.size.name, [
                            {
                                id: "panel-size-small",
                                text: texts.size.small,
                                title: texts.size.smallTitle,
                                onSettingClick: function () {
                                    console.log("Setting 00")
                                }
                            }, {
                                id: "panel-size-large",
                                isDefault: true,
                                text: texts.size.large,
                                title: texts.size.largeTitle,
                                onSettingClick: function () {
                                    console.log("Setting 01")
                                }
                            }
                        ])
                    }, {
                        "section": buildSection("appearance", texts.appearance.name, [
                            {
                                id: "panel-appearance-auto",
                                isDefault: true,
                                text: texts.appearance.auto,
                                title: texts.appearance.autoTitle,
                                onSettingClick: function () {
                                    console.log("Setting 10")
                                }
                            }, {
                                id: "panel-appearance-hidden",
                                text: texts.appearance.hidden,
                                title: texts.appearance.hiddenTitle,
                                onSettingClick: function () {
                                    console.log("Setting 11")
                                }
                            }, {
                                id: "panel-appearance-visible",
                                text: texts.appearance.visible,
                                title: texts.appearance.visibleTitle,
                                onSettingClick: function () {
                                    console.log("Setting 12")
                                }
                            }
                        ])
                    }
                ]
            };

            return new BEM(bemOptions)
                .buildBlockStructure("<div>", {style: "display: none;"})
                .insertAfter($settingsButton);
        }

        return {
            onSettingsClicked: function () {
                ($settings || ($settings = buildSettings($(this)))).slideToggle();
            },
            hideSettings: function () {
                $settings.slideUp(300);
            }
        }
    }
);
<|endoftext|>


<commit_before>import React from 'react';

import { formatNumber, formatPercentage } from 'common/format';
import { calculateSecondaryStatDefault } from 'common/stats';

import SPELLS from 'common/SPELLS/index';
import ITEMS from 'common/ITEMS/index';

import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events from 'parser/core/Events';
import Abilities from 'parser/core/modules/Abilities';
import StatTracker from 'parser/shared/modules/StatTracker';
import ItemStatistic from 'interface/statistics/ItemStatistic';
import ItemDamageTaken from 'interface/others/ItemDamageTaken';
import BoringItemValueText from 'interface/statistics/components/BoringItemValueText';
import MasteryIcon from 'interface/icons/Mastery';
import { TooltipElement } from 'common/Tooltip';
import ItemLink from 'common/ItemLink';

//Example Log: https://www.warcraftlogs.com/reports/vZQfwra1xVK76M4L/#fight=13&source=17
//Second Example Log: https://www.warcraftlogs.com/reports/vZQfwra1xVK76M4L/#fight=13&source=1

class LurkersInsidiousGift extends Analyzer {
  static dependencies = {
    abilities: Abilities,
    statTracker: StatTracker,
  };

  static cooldown = 120; //seconds
  static duration = 30; //seconds
  static maxStacks = 30;

  stacks = {};
  uses = 0;
  damageTaken = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTrinket(ITEMS.LURKERS_INSIDIOUS_GIFT.id);
    if(!this.active) {
      return;
    }
    const item = this.selectedCombatant.getItem(ITEMS.LURKERS_INSIDIOUS_GIFT.id);
    this.masteryRating = calculateSecondaryStatDefault(395, 881, item.itemLevel);
    this.statTracker.add(SPELLS.INSIDIOUS_GIFT.id, {
      mastery: this.masteryRating,
    });
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.INSIDIOUS_GIFT_CAST), this._cast);
    this.addEventListener(Events.applydebuffstack.to(SELECTED_PLAYER).spell(SPELLS.SUFFERING_DEBUFF), this._stack);
    this.addEventListener(Events.damage.to(SELECTED_PLAYER).spell(SPELLS.SUFFERING_DAMAGE), this._takeDamage);
    this.addEventListener(Events.fightend, this._end);

    this.abilities.add({
      spell: SPELLS.INSIDIOUS_GIFT_CAST,
      name: ITEMS.LURKERS_INSIDIOUS_GIFT.name,
      category: Abilities.SPELL_CATEGORIES.ITEMS,
      cooldown: this.constructor.cooldown,
      castEfficiency: {
        suggestion: true,
      },
    });
  }

  _cast(event){
    this.uses += 1;
    this.stacks[this.uses] = 0;
  }

  _stack(event){
    this.stacks[this.uses] += 1;
  }

  _takeDamage(event){
    this.damageTaken += (event.amount || 0) + (event.absorbed || 0);
  }

  _end(event){
    this.stacks[this.uses] = this.constructor.maxStacks; //if fight ends with debuff still running, pretend it ran for all 30 stacks
  }

  get possibleUseCount() {
    return Math.ceil(this.owner.fightDuration / (this.constructor.cooldown * 1000));
  }

  get averageStat(){
    return this.masteryRating * this.selectedCombatant.getBuffUptime(SPELLS.INSIDIOUS_GIFT.id) / this.owner.fightDuration;
  }

  get wastedStacks(){
    const totalStacksGained = Object.values(this.stacks).reduce((total, cur) => {
      return total + cur;
    }, 0);
    const totalStacksPossible = this.uses * this.constructor.maxStacks;
    return (totalStacksPossible - totalStacksGained) / totalStacksPossible;
  }

  statistic() {
    return (
      <ItemStatistic
        size="flexible"
        tooltip={(
          <>
            Uses: {this.uses} out of {this.possibleUseCount} possible use{this.possibleUseCount !== 1 && <>s</>}

          </>
        )}
      >
        <BoringItemValueText item={ITEMS.LURKERS_INSIDIOUS_GIFT}>
          <MasteryIcon /> {formatNumber(this.averageStat)} average Mastery

          <TooltipElement content={`Damage taken: ${formatNumber(this.damageTaken)}`}>
            <ItemDamageTaken amount={this.damageTaken} />
          </TooltipElement>
        </BoringItemValueText>
      </ItemStatistic>
    );
  }

  get suggestedStacks() {
    return {
      actual: this.wastedStacks,
      isGreaterThan: {
        minor: 0.05,
        average: 0.08,
        major: 0.1,
      },
      style: 'number',
    };
  }

  suggestions(when) {
    when(this.suggestedStacks).addSuggestion((suggest, actual, recommended) => {
      return suggest(
        <>
          Your usage of <ItemLink id={ITEMS.LURKERS_INSIDIOUS_GIFT.id} /> can be improved. Try to use it when you will get the most duration out of the mastery buff without having to cancel it (and without losing uses).
        </>
      )
        .icon(ITEMS.LURKERS_INSIDIOUS_GIFT.icon)
        .actual(`${formatPercentage(actual)}% of stacks wasted.`)
        .recommended(`<5.00% of stacks wasted is recommended`);
    });
  }

}

export default LurkersInsidiousGift;
<commit_msg>moved suggestion to use uptime instead of stacks<commit_after>import React from 'react';

import { formatNumber, formatPercentage } from 'common/format';
import { calculateSecondaryStatDefault } from 'common/stats';

import SPELLS from 'common/SPELLS/index';
import ITEMS from 'common/ITEMS/index';

import Analyzer, { SELECTED_PLAYER } from 'parser/core/Analyzer';
import Events from 'parser/core/Events';
import Abilities from 'parser/core/modules/Abilities';
import StatTracker from 'parser/shared/modules/StatTracker';
import ItemStatistic from 'interface/statistics/ItemStatistic';
import ItemDamageTaken from 'interface/others/ItemDamageTaken';
import BoringItemValueText from 'interface/statistics/components/BoringItemValueText';
import MasteryIcon from 'interface/icons/Mastery';
import { TooltipElement } from 'common/Tooltip';
import ItemLink from 'common/ItemLink';

//Example Log: https://www.warcraftlogs.com/reports/vZQfwra1xVK76M4L/#fight=13&source=17
//Second Example Log: https://www.warcraftlogs.com/reports/vZQfwra1xVK76M4L/#fight=13&source=1

class LurkersInsidiousGift extends Analyzer {
  static dependencies = {
    abilities: Abilities,
    statTracker: StatTracker,
  };

  static cooldown = 120; //seconds
  static duration = 30; //seconds
  static maxStacks = 30;

  possibleUptime = 0;
  uses = 0;
  damageTaken = 0;

  constructor(...args) {
    super(...args);
    this.active = this.selectedCombatant.hasTrinket(ITEMS.LURKERS_INSIDIOUS_GIFT.id);
    if(!this.active) {
      return;
    }
    const item = this.selectedCombatant.getItem(ITEMS.LURKERS_INSIDIOUS_GIFT.id);
    this.masteryRating = calculateSecondaryStatDefault(395, 881, item.itemLevel);
    this.statTracker.add(SPELLS.INSIDIOUS_GIFT.id, {
      mastery: this.masteryRating,
    });
    this.addEventListener(Events.cast.by(SELECTED_PLAYER).spell(SPELLS.INSIDIOUS_GIFT_CAST), this._cast);
    this.addEventListener(Events.damage.to(SELECTED_PLAYER).spell(SPELLS.SUFFERING_DAMAGE), this._takeDamage);

    this.abilities.add({
      spell: SPELLS.INSIDIOUS_GIFT_CAST,
      name: ITEMS.LURKERS_INSIDIOUS_GIFT.name,
      category: Abilities.SPELL_CATEGORIES.ITEMS,
      cooldown: this.constructor.cooldown,
      castEfficiency: {
        suggestion: true,
      },
    });
  }

  _cast(event){
    this.uses += 1;
    const timeLeft = this.owner.fight.end_time - event.timestamp;
    if(timeLeft < this.constructor.duration * 1000){
      this.possibleUptime += timeLeft;
    }else{
      this.possibleUptime += this.constructor.duration * 1000;
    }
  }

  _takeDamage(event){
    this.damageTaken += (event.amount || 0) + (event.absorbed || 0);
  }

  get possibleUseCount() {
    return Math.ceil(this.owner.fightDuration / (this.constructor.cooldown * 1000));
  }

  get averageStat(){
    return this.masteryRating * this.selectedCombatant.getBuffUptime(SPELLS.INSIDIOUS_GIFT.id) / this.owner.fightDuration;
  }

  get wastedUptime(){
    return (this.possibleUptime - this.selectedCombatant.getBuffUptime(SPELLS.INSIDIOUS_GIFT.id)) / this.possibleUptime;
  }

  statistic() {
    return (
      <ItemStatistic
        size="flexible"
        tooltip={(
          <>
            Uses: {this.uses} out of {this.possibleUseCount} possible use{this.possibleUseCount !== 1 && <>s</>}

          </>
        )}
      >
        <BoringItemValueText item={ITEMS.LURKERS_INSIDIOUS_GIFT}>
          <MasteryIcon /> {formatNumber(this.averageStat)} average Mastery

          <TooltipElement content={`Damage taken: ${formatNumber(this.damageTaken)}`}>
            <ItemDamageTaken amount={this.damageTaken} />
          </TooltipElement>
        </BoringItemValueText>
      </ItemStatistic>
    );
  }

  get suggestedUptime() {
    return {
      actual: this.wastedUptime,
      isGreaterThan: {
        minor: 0.05,
        average: 0.08,
        major: 0.1,
      },
      style: 'number',
    };
  }

  suggestions(when) {
    when(this.suggestedUptime).addSuggestion((suggest, actual, recommended) => {
      return suggest(
        <>
          Your usage of <ItemLink id={ITEMS.LURKERS_INSIDIOUS_GIFT.id} /> can be improved. Try to use it when you will get the most duration out of the mastery buff without having to cancel it (and without losing uses).
        </>
      )
        .icon(ITEMS.LURKERS_INSIDIOUS_GIFT.icon)
        .actual(`${formatPercentage(actual)}% of buff uptime wasted.`)
        .recommended(`<5.00% of buff uptime wasted is recommended`);
    });
  }

}

export default LurkersInsidiousGift;
<|endoftext|>


<commit_before>(function (module) {
    module.controller('projectEditProcess', projectEditProcess);
    projectEditProcess.$inject = ["project", "modalInstance", "$state", "processTemplates", "template"];

    function projectEditProcess(project, modalInstance, $state, processTemplates, template) {
        var ctrl = this;
        ctrl.cancel = cancel;
        ctrl.openFile = openFile;
        ctrl.openSample = openSample;
        ctrl.done = done;

        ctrl.project = project;
        ctrl.template = template;

        function cancel() {
            $state.go('projects.project.processes.list.view');
        }

        function openFile(file) {
            modalInstance.openModal(file, 'datafile', ctrl.project);
        }

        function openSample(sample) {
            modalInstance.openModal(sample, 'sample', ctrl.project);
        }

        function done() {
            //mcapi('/processes/%', $scope.template.id)
            //    .success(function (proc) {
            //        //Currently i'm reloading all the projects , but we need to reload single project.
            //        Projects.getList(true).then(function (projects) {
            //            var i = _.indexOf(projects, function (p) {
            //                return p.id == project.id;
            //            });
            //            current.setProject(projects[i]);
            //            project.processes = projects[i].processes;
            //            project.samples = projects[i].samples;
            //            $scope.template = '';
            //            $scope.bk = {
            //                selectedSample: {}
            //            };
            //            console.log("success");
            //            $state.go('projects.project.processes.list.view');
            //        });
            //    }).put({
            //        name: $scope.template.name, what: $scope.template.what, why: $scope.template.why,
            //        setup: $scope.template.setup[0].setupproperties, samples: $scope.template.samples
            //    });
        }
    }
}(angular.module('materialscommons')));

<commit_msg>Remove parameters.<commit_after>(function (module) {
    module.controller('projectEditProcess', projectEditProcess);
    projectEditProcess.$inject = ["project", "modalInstance", "$state"];

    function projectEditProcess(project, modalInstance, $state) {
        var ctrl = this;
        ctrl.cancel = cancel;
        ctrl.openFile = openFile;
        ctrl.openSample = openSample;
        ctrl.done = done;

        ctrl.project = project;

        function cancel() {
            $state.go('projects.project.processes.list.view');
        }

        function openFile(file) {
            modalInstance.openModal(file, 'datafile', ctrl.project);
        }

        function openSample(sample) {
            modalInstance.openModal(sample, 'sample', ctrl.project);
        }

        function done() {
            //mcapi('/processes/%', $scope.template.id)
            //    .success(function (proc) {
            //        //Currently i'm reloading all the projects , but we need to reload single project.
            //        Projects.getList(true).then(function (projects) {
            //            var i = _.indexOf(projects, function (p) {
            //                return p.id == project.id;
            //            });
            //            current.setProject(projects[i]);
            //            project.processes = projects[i].processes;
            //            project.samples = projects[i].samples;
            //            $scope.template = '';
            //            $scope.bk = {
            //                selectedSample: {}
            //            };
            //            console.log("success");
            //            $state.go('projects.project.processes.list.view');
            //        });
            //    }).put({
            //        name: $scope.template.name, what: $scope.template.what, why: $scope.template.why,
            //        setup: $scope.template.setup[0].setupproperties, samples: $scope.template.samples
            //    });
        }
    }
}(angular.module('materialscommons')));

<|endoftext|>