<commit_before>let hovercolor = "rgba(244, 75, 66, 1)"

let pages = ["1First-Page.html","2Second-Page.html","3Third-Page.html","4Fourth-Page.html"]

let pagenames = [],
navbar = $("

"),
navtitle = $("
Title of your html
");
navtitle.css({"color": "white", "font-size": "3.2vw", "text-align": "center"});
let logo = $("");
logo.css({"right": "1vw", "top": "1vh", "position": "absolute","height": "6vh"});

let navicon = $("<object type='image/svg+xml' data='https://rawgit.com/Imperial-visualizations/Physics-Visualizations/master/css/navicon.svg' class='navicon' id='navicon'></object>");
let mousediv=$("

");
let dropdown=$("

");

$("body").append(navbar);
$("#navbar").append(navtitle);
$("#navbar").append(logo);
$("#navbar").append(navicon);
$("body").append(mousediv);
$("body").append(dropdown);

function get_pagename(htmlname){
    htmlname=htmlname.slice(1, htmlname.length-5)
    htmlname = htmlname.replace("-"," ")
    return(htmlname)
}

for (let i = 0; i < pages.length; i++) {
    pagenames[i]=get_pagename(pages[i])
}

let newelement = $("
Electrostatics
");
newelement.css({"height": (60/pages.length).toString()+"vh" , "top": (8).toString()+"vh","font-size": 2.5+"vw","text-align":"center"})
$("#mousediv").append(newelement);

for (let i = 0; i < pages.length; i++) {
    let difference= 70/pages.length, height = difference*i +25
    let newelement = $("
" + (i+1).toString() +". " + pagenames[i]+"
");
    let newbackground = $("

");
    newelement.attr("name",pages[i])
    newelement.css({"height": (difference).toString()+"vh" , "top": (height).toString()+"vh","font-size": (2).toString()+"vw","line-height": (difference).toString()+"vh"})
    newbackground.css({"transition-delay": "0s","transition-duration": "0s","height": (difference).toString()+"vh" ,"width": "30vw", "top": (height).toString()+"vh","border-top": "1px solid rgb(252, 252, 252)","border-bottom":"1px solid rgb(252, 252, 252)","position": "absolute","background-color":"rgba(255, 255, 255,0.2)",})
    $("#mousediv").append(newelement);
    $("#dropdown").append(newbackground);
}

$("#mousediv").mouseover(function(){

    $("#dropdown").animate({width: "30vw"}, 0, "linear");
    $("#mousediv").animate({width: "30vw", height: "100vh"},0,"linear");
    $(".pagetitle").animate({width: "30vw"},0,"linear");
})

$("#mousediv").mouseout(function(){

    $("#dropdown").animate({width: "0vw"}, 0, "linear")
    $(".pagetitle").animate({width: "0vw"},0,"linear")
    $("#mousediv").animate({height: "5vh",width: "5vw"},0,"linear")
})

$(".pagetitle").mouseover(function() {
    if ($(this).attr("id").toString() != "Dropdowntitle") {
    $(this).css({"background-color": hovercolor})
}
})

$(".pagetitle").mouseout(function(){
    $(this).css({"background-color": "rgba(244, 75, 66, 0)"})
})

$(".pagetitle").on("click",function(){
    window.location.href = $(this).attr("name");
})<commit_msg>Updated navigator<commit_after>let hovercolor = "rgba(244, 75, 66, 1)"

let title = $("title").html()
let pagenames = [],
navbar = $("

"),
navtitle = $(`<p>${title}</p>`);
navtitle.css({"color": "white", "font-size": "3.2vw", "text-align": "center"});
let logo = $("");
logo.css({"right": "1vw", "top": "1vh", "position": "absolute","height": "6vh"});

let navicon = $("<object type='image/svg+xml' data='https://rawgit.com/Imperial-visualizations/Physics-Visualizations/master/css/navicon.svg' class='navicon' id='navicon'></object>");
let mousediv=$("

");
let dropdown=$("

");

$("body").append(navbar);
$("#navbar").append(navtitle);
$("#navbar").append(logo);
$("#navbar").append(navicon);
$("body").append(mousediv);
$("body").append(dropdown);

function get_pagename(htmlname){
    htmlname=htmlname.slice(1, htmlname.length-5)
    htmlname = htmlname.replace("-"," ")
    return(htmlname)
}

for (let i = 0; i < pages.length; i++) {
    pagenames[i]=get_pagename(pages[i])
}

let newelement = $(`<div class='pagetitle' id='Dropdowntitle'>${title}</div>`);
newelement.css({"height": (60/pages.length).toString()+"vh" , "top": (8).toString()+"vh","font-size": 2.5+"vw","text-align":"center"})
$("#mousediv").append(newelement);

for (let i = 0; i < pages.length; i++) {
    let difference= 70/pages.length, height = difference*i +25
    let newelement = $("
" + (i+1).toString() +". " + pagenames[i]+"
");
    let newbackground = $("

");
    newelement.attr("name",pages[i])
    newelement.css({"height": (difference).toString()+"vh" , "top": (height).toString()+"vh","font-size": (2).toString()+"vw","line-height": (difference).toString()+"vh"})
    newbackground.css({"transition-delay": "0s","transition-duration": "0s","height": (difference).toString()+"vh" ,"width": "30vw", "top": (height).toString()+"vh","border-top": "1px solid rgb(252, 252, 252)","border-bottom":"1px solid rgb(252, 252, 252)","position": "absolute","background-color":"rgba(255, 255, 255,0.2)",})
    $("#mousediv").append(newelement);
    $("#dropdown").append(newbackground);
}

$("#mousediv").mouseover(function(){

    $("#dropdown").animate({width: "30vw"}, 0, "linear");
    $("#mousediv").animate({width: "30vw", height: "100vh"},0,"linear");
    $(".pagetitle").animate({width: "30vw"},0,"linear");
})

$("#mousediv").mouseout(function(){

    $("#dropdown").animate({width: "0vw"}, 0, "linear")
    $(".pagetitle").animate({width: "0vw"},0,"linear")
    $("#mousediv").animate({height: "5vh",width: "5vw"},0,"linear")
})

$(".pagetitle").mouseover(function() {
    if ($(this).attr("id").toString() != "Dropdowntitle") {
    $(this).css({"background-color": hovercolor})
}
})

$(".pagetitle").mouseout(function(){
    $(this).css({"background-color": "rgba(244, 75, 66, 0)"})
})

$(".pagetitle").on("click",function(){
    window.location.href = $(this).attr("name");
})
<|endoftext|>


<commit_before>var upgrades = [];

var currentRCU = 0;
var priceCRU = 1;

var reduceCooldownUpgrades = [
    {
        multiplier:0.75,
        priceMultiplier:10
    },
    {
        multiplier:0.75,
        priceMultiplier:2
    },
    {
        multiplier:0.75,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    }

];

var currentACU = 0;
var priceACU = 1;

var autoClickUpgrades = [
    {
        multiplier:5,
        priceMultiplier:10
    },
    {
        multiplier:3,
        priceMultiplier:2
    },
    {
        multiplier:2,
        priceMultiplier: 3
    },
    {
        multiplier:1.7,
        priceMultiplier: 3
    },
    {
        multiplier:1.9,
        priceMultiplier: 3
    },
    {
        multiplier:1.9,
        priceMultiplier: 3
    },
    {
        multiplier:1.9,
        priceMultiplier: 3
    }

];

function newRCU() {

    if(points >= priceCRU*reduceCooldownUpgrades[currentRCU].priceMultiplier ){
        points -= priceCRU*reduceCooldownUpgrades[currentRCU].priceMultiplier;
        coolDownTime *= reduceCooldownUpgrades[currentRCU].multiplier;
        priceCRU *= reduceCooldownUpgrades[currentRCU].priceMultiplier;
        currentRCU += 1;
        drawRCU();
    }
}

function newACU() {

    if(points >= priceACU*autoClickUpgrades[currentACU].priceMultiplier ){
        points -= priceACU*autoClickUpgrades[currentACU].priceMultiplier;
        pointsPerSecond *= autoClickUpgrades[currentACU].multiplier;
        priceACU *= autoClickUpgrades[currentACU].priceMultiplier;
        currentACU += 1;
        drawACU();
    }
}

function drawRCU() {
    if(currentRCU != reduceCooldownUpgrades.length){
        $('#reduceCooldownUpgrade .price').html(reduceCooldownUpgrades[currentRCU].priceMultiplier*priceCRU);
        $('#reduceCooldownUpgrade .multiplier').html(100-(reduceCooldownUpgrades[currentRCU].multiplier*100));
    } else {
        $('#reduceCooldownUpgrade').html('Wait until the next level.')
    }
}

function drawACU() {
    if(currentACU != autoClickUpgrades.length){
        $('#autoClickUpgrade .price').html(autoClickUpgrades[currentACU].priceMultiplier*priceACU);
        $('#autoClickUpgrade .multiplier').html((autoClickUpgrades[currentACU].multiplier*100-100));
    } else {
        $('#autoClickUpgrade').html('Wait until the next level.')
    }
}

$('#reduceCooldownUpgrade').click(function(){

    if(currentRCU == reduceCooldownUpgrades.length){
        return 0;
    }
    newRCU();
});

$('#autoClickUpgrade').click(function(){

    if(currentACU == reduceCooldownUpgrades.length){
        return 0;
    }
    newACU();
});

drawRCU();
drawACU();

<commit_msg>order of ACU<commit_after>var upgrades = [];

var currentRCU = 0;
var priceCRU = 1;

var reduceCooldownUpgrades = [
    {
        multiplier:0.75,
        priceMultiplier:10
    },
    {
        multiplier:0.75,
        priceMultiplier:2
    },
    {
        multiplier:0.75,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    },
    {
        multiplier:0.5,
        priceMultiplier: 3
    }

];

var currentACU = 0;
var priceACU = 1;

var autoClickUpgrades = [
    {
        multiplier:5,
        priceMultiplier:10
    },
    {
        multiplier:3,
        priceMultiplier:2
    },
    {
        multiplier:2,
        priceMultiplier: 3
    },
    {
        multiplier:2,
        priceMultiplier: 3
    },
    {
        multiplier:1.7,
        priceMultiplier: 3
    },
    {
        multiplier:1.6,
        priceMultiplier: 3
    },
    {
        multiplier:1.5,
        priceMultiplier: 3
    }

];

function newRCU() {

    if(points >= priceCRU*reduceCooldownUpgrades[currentRCU].priceMultiplier ){
        points -= priceCRU*reduceCooldownUpgrades[currentRCU].priceMultiplier;
        coolDownTime *= reduceCooldownUpgrades[currentRCU].multiplier;
        priceCRU *= reduceCooldownUpgrades[currentRCU].priceMultiplier;
        currentRCU += 1;
        drawRCU();
    }
}

function newACU() {

    if(points >= priceACU*autoClickUpgrades[currentACU].priceMultiplier ){
        points -= priceACU*autoClickUpgrades[currentACU].priceMultiplier;
        pointsPerSecond *= autoClickUpgrades[currentACU].multiplier;
        priceACU *= autoClickUpgrades[currentACU].priceMultiplier;
        currentACU += 1;
        drawACU();
    }
}

function drawRCU() {
    if(currentRCU != reduceCooldownUpgrades.length){
        $('#reduceCooldownUpgrade .price').html(reduceCooldownUpgrades[currentRCU].priceMultiplier*priceCRU);
        $('#reduceCooldownUpgrade .multiplier').html(100-(reduceCooldownUpgrades[currentRCU].multiplier*100));
    } else {
        $('#reduceCooldownUpgrade').html('Wait until the next level.')
    }
}

function drawACU() {
    if(currentACU != autoClickUpgrades.length){
        $('#autoClickUpgrade .price').html(autoClickUpgrades[currentACU].priceMultiplier*priceACU);
        $('#autoClickUpgrade .multiplier').html((autoClickUpgrades[currentACU].multiplier*100-100));
    } else {
        $('#autoClickUpgrade').html('Wait until the next level.')
    }
}

$('#reduceCooldownUpgrade').click(function(){

    if(currentRCU == reduceCooldownUpgrades.length){
        return 0;
    }
    newRCU();
});

$('#autoClickUpgrade').click(function(){

    if(currentACU == reduceCooldownUpgrades.length){
        return 0;
    }
    newACU();
});

drawRCU();
drawACU();

<|endoftext|>


<commit_before>"use strict";

var async = require('async'),

	NodeBB = require('./nodebb'),

	Poll = require('./poll');

(function(Vote) {

	Vote.add = function(voteData, callback) {
		var pollId = voteData.pollId,
			options = voteData.options,
			uid = voteData.uid;

		async.parallel([
			function(next) {
				async.each(options, function(option, next) {
					async.parallel([
						function(next) {
							// Increase option vote count
							NodeBB.db.incrObjectField('poll:' + pollId + ':options:' + option, 'voteCount', next);
						},
						function(next) {
							// Add uid to list of votes
							NodeBB.db.setAdd('poll:' + pollId + ':options:' + option + ':votes', uid, next);
						}
					], next);
				}, next);
			},
			function(next) {
				async.parallel([
					// Add uid to poll voters
					async.apply(NodeBB.db.setAdd, 'poll:' + pollId + ':voters', uid),
					// Increase poll vote count
					async.apply(NodeBB.db.incrObjectFieldBy, 'poll:' + pollId, 'voteCount', options.length)
				], next);
			}
		], function(err) {
			if (err) {
				return callback(err, false);
			}

			callback(null, true);
		});
	};

	Vote.remove = function(voteData, callback) {
		var pollId = voteData.pollId,
			options = voteData.options,
			uid = voteData.uid;

		async.parallel([
			function(next) {
				async.each(options, function(option, next) {
					async.parallel([
						// Decrease option vote count
						async.apply(NodeBB.db.decrObjectField, 'poll:' + pollId + ':options:' + option, 'voteCount'),
						// Remove uid from list of votes
						async.apply(NodeBB.db.setRemove, 'poll:' + pollId + ':options:' + option + ':votes', uid)
					], next);
				}, next);
			},
			function(next) {
				async.parallel([
					// Remove uid from poll voters
					async.apply(NodeBB.db.setRemove, 'poll:' + pollId + ':voters', uid),
					// Decrease poll vote count
					async.apply(NodeBB.db.decrObjectFieldBy, 'poll:' + pollId, 'votecount', options.length)
				], next);
			}
		], function(err) {
			if (err) {
				return callback(err, false);
			}

			callback(null, true);
		});
	};

	Vote.canVote = function(uid, pollId, callback) {
		async.parallel([
			function(next) {
				// Ended?
				Poll.hasEnded(pollId, next);
			},
			function(next) {
				// Deleted?
				Poll.isDeleted(pollId, next);
			},
			function(next) {
				// Already voted?
				Vote.hasUidVoted(uid, pollId, next);
			}
		], function(err, result) {
			callback(err, result.indexOf(true) === -1);
		});
	};

	Vote.hasUidVoted = function(uid, pollId, callback) {
		NodeBB.db.isSetMember('poll:' + pollId + ':voters', uid, callback);
	};

	Vote.hasUidVotedOnOption = function(uid, pollId, option, callback) {
		NodeBB.db.isSetMember('poll:' + pollId + ':options:' + option + ':votes', uid, callback);
	};

})(exports);<commit_msg>Fix a typo<commit_after>"use strict";

var async = require('async'),

	NodeBB = require('./nodebb'),

	Poll = require('./poll');

(function(Vote) {

	Vote.add = function(voteData, callback) {
		var pollId = voteData.pollId,
			options = voteData.options,
			uid = voteData.uid;

		async.parallel([
			function(next) {
				async.each(options, function(option, next) {
					async.parallel([
						function(next) {
							// Increase option vote count
							NodeBB.db.incrObjectField('poll:' + pollId + ':options:' + option, 'voteCount', next);
						},
						function(next) {
							// Add uid to list of votes
							NodeBB.db.setAdd('poll:' + pollId + ':options:' + option + ':votes', uid, next);
						}
					], next);
				}, next);
			},
			function(next) {
				async.parallel([
					// Add uid to poll voters
					async.apply(NodeBB.db.setAdd, 'poll:' + pollId + ':voters', uid),
					// Increase poll vote count
					async.apply(NodeBB.db.incrObjectFieldBy, 'poll:' + pollId, 'voteCount', options.length)
				], next);
			}
		], function(err) {
			if (err) {
				return callback(err, false);
			}

			callback(null, true);
		});
	};

	Vote.remove = function(voteData, callback) {
		var pollId = voteData.pollId,
			options = voteData.options,
			uid = voteData.uid;

		async.parallel([
			function(next) {
				async.each(options, function(option, next) {
					async.parallel([
						// Decrease option vote count
						async.apply(NodeBB.db.decrObjectField, 'poll:' + pollId + ':options:' + option, 'voteCount'),
						// Remove uid from list of votes
						async.apply(NodeBB.db.setRemove, 'poll:' + pollId + ':options:' + option + ':votes', uid)
					], next);
				}, next);
			},
			function(next) {
				async.parallel([
					// Remove uid from poll voters
					async.apply(NodeBB.db.setRemove, 'poll:' + pollId + ':voters', uid),
					// Decrease poll vote count
					async.apply(NodeBB.db.decrObjectFieldBy, 'poll:' + pollId, 'voteCount', options.length)
				], next);
			}
		], function(err) {
			if (err) {
				return callback(err, false);
			}

			callback(null, true);
		});
	};

	Vote.canVote = function(uid, pollId, callback) {
		async.parallel([
			function(next) {
				// Ended?
				Poll.hasEnded(pollId, next);
			},
			function(next) {
				// Deleted?
				Poll.isDeleted(pollId, next);
			},
			function(next) {
				// Already voted?
				Vote.hasUidVoted(uid, pollId, next);
			}
		], function(err, result) {
			callback(err, result.indexOf(true) === -1);
		});
	};

	Vote.hasUidVoted = function(uid, pollId, callback) {
		NodeBB.db.isSetMember('poll:' + pollId + ':voters', uid, callback);
	};

	Vote.hasUidVotedOnOption = function(uid, pollId, option, callback) {
		NodeBB.db.isSetMember('poll:' + pollId + ':options:' + option + ':votes', uid, callback);
	};

})(exports);
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * 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.
 */
var labelToProperty = {
  App:          'app',
  Type:         'type',
  Priority:     'priority',
  Milestone:    'milestone',
  Cr:           'category',
  Iteration:    'iteration',
  ReleaseBlock: 'releaseBlock',
  OS:           'OS'
};

var QIssue = FOAM({
    model_: 'Model',
    extendsModel: 'GeneratedQIssue',

    name: 'QIssue',

    tableProperties: [
      'starred',
      'id',
//      'app',
      'priority',
      'milestone',
      'iteration',
      'releaseBlock',
      'category',
      'status',
      'owner',
      'summary',
      'OS',
      'modified'
    ],

    ids: ['id'],

    properties: [
        {
          model_: 'IntegerProperty',
          name: 'id',
          shortName: 'i',
          label: 'ID',
          required: true,
          tableWidth: '48px',
          tableFormatter: function(value, row, table) {
            var id = table.nextID();

            table.on('mouseover', function(e) {
              table.browser.preview(e, value);
            }, id);

            return '
' + value + '
';
          }
        },
        {
          name: 'author',
          aliases: ['reporter']
        },
        {
          model_: 'StringProperty',
          name: 'priority',
          shortName: 'p',
          aliases: ['pr', 'pri', 'prior'],
          tableLabel: 'Priority',
          tableWidth: '60px',
          compareProperty: function(p1, p2) {
            var priorities = ['Low', 'Medium', 'High', 'Critical'];
            var r = priorities.indexOf(p1) - priorities.indexOf(p2);
            return r === 0 ? 0 : r < 0 ? -1 : 1;
          },
          required: true
        },
        {
          model_: 'StringProperty',
          name: 'app',
          tableWidth: '70px'
        },
        {
          model_: 'StringProperty',
          name: 'type',
          tableWidth: '70px'
        },
        {
            name: 'milestone',
            shortName: 'm',
            aliases: ['mstone'],
            tableLabel: 'M',
            type: 'Integer',
            tableWidth: '70px',
            defaultValue: ''
        },
        {
            name: 'iteration',
            shortName: 'it',
            aliases: ['iter'],
            type: 'String',
            tableWidth: '69px'
        },
        {
            name: 'releaseBlock',
            shortName: 'rb',
            aliases: ['rBlock', 'release'],
            type: 'String',
            tableWidth: '103px',
            defaultValue: ''
        },
        {
            name: 'category',
            shortName: 'c',
            aliases: ['cat', 'cr'],
            label: 'Cr',
            tableWidth: '87px',
            type: 'String',
            defaultValue: ''
        },
        {
            name: 'status',
            shortName: 's',
            aliases: ['stat'],
            type: 'String',
            tableWidth: '58px',
            defaultValue: ''
        },
        {
            name: 'owner',
            shortName: 'o',
            tableWidth: '181px',
            type: 'String'
        },
        {
            name: 'summary',
            shortName: 'su',
            label: 'Summary + Labels',
            type: 'String',
            tableWidth: '100%',
            tableFormatter: function(value, row, tableView) {
              return tableView.strToHTML(value) +
                QIssue.LABELS.tableFormatter(row.labels, row);
            }
        },
        {
            name: 'labels',
            shortName: 'l',
            aliases: ['label'],
            type: 'String',
            view: 'QIssueLabelsView',
          tableFormatter: function(value, row) {
              var sb = [];
              //              var a = value.split(', ');
              var a = value;
              for ( var i = 0 ; i < a.length ; i++ ) {
                // The the column is already being shown, then exclude it's label
                if ( row.model_.tableProperties.indexOf(labelToProperty[a[i].split('-')[0]]) == -1 ) {
                  sb.push(' ');
                  sb.push(a[i]);
                  sb.push('');
                }
              }
              return sb.join('');
            },
            postSet: function(_, a) {
              for ( var i = 0 ; i < a.length ; i++ ) {
                for ( var key in labelToProperty ) {
                  if ( a[i].substring(0, key.length) == key ) {
                    var prop = labelToProperty[key];
                    var val = a[i].substring(key.length+1).intern();
                    // ???: Should be treated as last value or an array?
                    this[prop] = val;
//                  this[prop].push(val);
                    a.splice(i,1);
                    i--;
                    break;
                  }
                }
              }
            }
        },
        {
            name: 'OS',
            tableWidth: '61px',
            type: 'String'
        },
        {
          model_: 'BooleanProperty',
          name: 'blocked',
          tableWidth: '20px',
          getter: function() { return !! this.blockedOn.length; }
        },
        {
         model_: 'DateTimeProperty',
         name: 'modified',
         shortName: 'mod',
         mode: 'read-write',
         required: true,
         tableWidth: '100px',
         valueFactory: function() { return new Date(); }
      },
      {
        name: 'updated',
        hidden: true,
        setter: function(v) { this.modified = v; }
      },
      {
         model_: 'BooleanProperty',
         name: 'starred',
         tableLabel: '',
         tableWidth: '20px',
         tableFormatter: function(val, obj, tableView) {
           var temp = obj.clone();
           var view = ImageBooleanView.create({
               trueImage: 'data:image/gif;base64,R0lGODlhDwAPAMQfAF9h4RYVnZeQJC0u0lRQU42R6P/7Fv74L05NrRkZxi4tW52XXv71D8nAIWxnjnRxr3NuMJKOluXbBe7kCa2x7UFD1vPoB77D8Jqe6n6B5tvTUr62BMrP8lJPh1xbuv///yH5BAEAAB8ALAAAAAAPAA8AAAWD4CeOWQKMaDpESepi3tFlLgpExlK9RT9ohkYi08N8KhWP8nEwMBwIDyJRSTgO2CaDYcBOCAlMgtDYmhmTDSFQ+HAqgbLZIlAMLqiKw7m1EAYuFQsGEhITEwItKBc/EgIEAhINAUYkCBIQAQMBEGonIwAKa21iCgo7IxQDFRQjF1VtHyEAOw==', //'images/star_on.gif',
               falseImage: 'data:image/gif;base64,R0lGODlhDwAPALMPAP///8zj++r7/7vb/rHW/tPt/9Lk+qzT/rbY/sHh/8Te/N7q+Nzy/7nY/djn+f///yH5BAEAAA8ALAAAAAAPAA8AAARg8MkZjpo4k0KyNwlQBB42MICAfEF7APDRBsYzIEkewGKeDI1DgUckMg6GTdFIqC0QgyUgQVhgGkOi4OBBCJYdzILAywIGNcoOgCAQvowBRpE4kgzCQgPjQCAcEwsNTRIRADs=', //'images/star_off.gif',
               value: temp.propertyValue('starred')
             });

           temp.addPropertyListener('starred', function() {
             tableView.browser.IssueDAO.put(temp);
           });

           tableView.addChild(view);

           return view.toHTML();
         },
         view: {
           // TODO: make it so that initialized objects can be used as factories
           create: function() {
             return ImageBooleanView.create({
               trueImage: 'images/star_on.gif',
               falseImage: 'images/star_off.gif'
             });
           }
         },
         tableWidth: '20px',
         help: 'Whether the authenticated user has starred this issue.'
      },
      {
         model_: 'IntegerProperty',
         name: 'stars',
         tableWidth: '20px',
         help: 'Number of stars this issue has.'
      }
    ],

    methods: {
      isOpen: function() {
        return !! ({
          'New':      true,
          'Accepted': true,
          'Started':  true
        }[this.status]);
      },
      writeActions: function(other, out) {
        var diff = this.diff(other);
        delete diff.starred;

        if ( Object.keys(diff).length == 0 ) return;

        function convertArray(key) {
          if ( ! diff[key] ) {
            diff[key] = [];
            return;
          }

          var delta = diff[key].added;
          for ( var i = 0; i < diff[key].removed.length; i++ )
            delta.push("-" + diff[key].removed[i]);
          diff[key] = delta;
        }

        convertArray('blockedOn');
        convertArray('blocking');
        convertArray('cc');
        convertArray('labels');

        function propToLabel(prop, label) {
          if ( diff[prop] ) {
            diff.labels = diff.labels.concat(
              '-' + label + '-' + other[prop],
              label + '-' + diff[prop]);
            delete diff[prop];
          }
        }

        propToLabel('priority', 'Priority');
        propToLabel('app', 'App');
        propToLabel('milestone', 'Milestone');
        propToLabel('category', 'Cr');
        propToLabel('iteration', 'Iteration');
        propToLabel('releaseBlock', 'ReleaseBlock');
        propToLabel('OS', 'OS');

        var comment = QIssueComment.create({
          issueId: this.id,
          updates: IssueCommentUpdate.create(diff)
        });

        out(comment);
      }
    }
});

QIssue.getPrototype();

QIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v) {
      return ('' + v).length ? v : '----';
    };
  }
});

GeneratedQIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v, _, tableView) {
      return ('' + v).length ? v : '----';
    };
  }
  if ( ! p["tableWidth"] ) {
    p["tableWidth"] = '80px;'
  }
});

var QIssueComment = FOAM({
  model_: 'Model',
  name: 'QIssueComment',
  extendsModel: 'IssueComment',

  ids: [ 'id' ],

  properties: [
    {
      name: 'author',
      view: 'QIssueCommentAuthorView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'updates',
      view: 'QIssueCommentUpdateView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'published',
      view: 'RelativeDateTimeFieldView'
    },
    {
      model_: 'ReferenceProperty',
      name: 'issueId'
    }
  ]
});

var QUser = FOAM({
  model_: 'Model',
  name: 'QUser',
  extendsModel: 'User',

  properties: [
    {
      model_: 'StringProperty',
      name: 'email'
    },
    {
      name: 'projects',
      postSet: function(_, newValue) {
        if ( this.preferredProjects.length == 0 ) {
          this.preferredProjects = newValue.map(function(p) { return p.name; });
        }
      }
    },
    {
      model_: 'StringArrayProperty',
      name: 'preferredProjects',
      view: 'MultiLineStringArrayView'
    },
    {
      model_: 'StringProperty',
      name: 'defaultProject',
      defaultValue: 'chromium'
    }
  ]
});
<commit_msg>Crbug: 'starred' tableFormatter was generating garbage and slowing down table renders.<commit_after>/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * 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.
 */
var labelToProperty = {
  App:          'app',
  Type:         'type',
  Priority:     'priority',
  Milestone:    'milestone',
  Cr:           'category',
  Iteration:    'iteration',
  ReleaseBlock: 'releaseBlock',
  OS:           'OS'
};

var QIssue = FOAM({
    model_: 'Model',
    extendsModel: 'GeneratedQIssue',

    name: 'QIssue',

    tableProperties: [
      'starred',
      'id',
//      'app',
      'priority',
      'milestone',
      'iteration',
      'releaseBlock',
      'category',
      'status',
      'owner',
      'summary',
      'OS',
      'modified'
    ],

    ids: ['id'],

    properties: [
        {
          model_: 'IntegerProperty',
          name: 'id',
          shortName: 'i',
          label: 'ID',
          required: true,
          tableWidth: '48px',
          tableFormatter: function(value, row, table) {
            var id = table.nextID();

            table.on('mouseover', function(e) {
              table.browser.preview(e, value);
            }, id);

            return '
' + value + '
';
          }
        },
        {
          name: 'author',
          aliases: ['reporter']
        },
        {
          model_: 'StringProperty',
          name: 'priority',
          shortName: 'p',
          aliases: ['pr', 'pri', 'prior'],
          tableLabel: 'Priority',
          tableWidth: '60px',
          compareProperty: function(p1, p2) {
            var priorities = ['Low', 'Medium', 'High', 'Critical'];
            var r = priorities.indexOf(p1) - priorities.indexOf(p2);
            return r === 0 ? 0 : r < 0 ? -1 : 1;
          },
          required: true
        },
        {
          model_: 'StringProperty',
          name: 'app',
          tableWidth: '70px'
        },
        {
          model_: 'StringProperty',
          name: 'type',
          tableWidth: '70px'
        },
        {
            name: 'milestone',
            shortName: 'm',
            aliases: ['mstone'],
            tableLabel: 'M',
            type: 'Integer',
            tableWidth: '70px',
            defaultValue: ''
        },
        {
            name: 'iteration',
            shortName: 'it',
            aliases: ['iter'],
            type: 'String',
            tableWidth: '69px'
        },
        {
            name: 'releaseBlock',
            shortName: 'rb',
            aliases: ['rBlock', 'release'],
            type: 'String',
            tableWidth: '103px',
            defaultValue: ''
        },
        {
            name: 'category',
            shortName: 'c',
            aliases: ['cat', 'cr'],
            label: 'Cr',
            tableWidth: '87px',
            type: 'String',
            defaultValue: ''
        },
        {
            name: 'status',
            shortName: 's',
            aliases: ['stat'],
            type: 'String',
            tableWidth: '58px',
            defaultValue: ''
        },
        {
            name: 'owner',
            shortName: 'o',
            tableWidth: '181px',
            type: 'String'
        },
        {
            name: 'summary',
            shortName: 'su',
            label: 'Summary + Labels',
            type: 'String',
            tableWidth: '100%',
            tableFormatter: function(value, row, tableView) {
              return tableView.strToHTML(value) +
                QIssue.LABELS.tableFormatter(row.labels, row);
            }
        },
        {
            name: 'labels',
            shortName: 'l',
            aliases: ['label'],
            type: 'String',
            view: 'QIssueLabelsView',
          tableFormatter: function(value, row) {
              var sb = [];
              //              var a = value.split(', ');
              var a = value;
              for ( var i = 0 ; i < a.length ; i++ ) {
                // The the column is already being shown, then exclude it's label
                if ( row.model_.tableProperties.indexOf(labelToProperty[a[i].split('-')[0]]) == -1 ) {
                  sb.push(' ');
                  sb.push(a[i]);
                  sb.push('');
                }
              }
              return sb.join('');
            },
            postSet: function(_, a) {
              for ( var i = 0 ; i < a.length ; i++ ) {
                for ( var key in labelToProperty ) {
                  if ( a[i].substring(0, key.length) == key ) {
                    var prop = labelToProperty[key];
                    var val = a[i].substring(key.length+1).intern();
                    // ???: Should be treated as last value or an array?
                    this[prop] = val;
//                  this[prop].push(val);
                    a.splice(i,1);
                    i--;
                    break;
                  }
                }
              }
            }
        },
        {
            name: 'OS',
            tableWidth: '61px',
            type: 'String'
        },
        {
          model_: 'BooleanProperty',
          name: 'blocked',
          tableWidth: '20px',
          getter: function() { return !! this.blockedOn.length; }
        },
        {
         model_: 'DateTimeProperty',
         name: 'modified',
         shortName: 'mod',
         mode: 'read-write',
         required: true,
         tableWidth: '100px',
         valueFactory: function() { return new Date(); }
      },
      {
        name: 'updated',
        hidden: true,
        setter: function(v) { this.modified = v; }
      },
      {
         model_: 'BooleanProperty',
         name: 'starred',
         tableLabel: '',
         tableWidth: '20px',
         tableFormatter: function(val, obj, tableView) {
           var view = ImageBooleanView.create({
               trueImage: 'data:image/gif;base64,R0lGODlhDwAPAMQfAF9h4RYVnZeQJC0u0lRQU42R6P/7Fv74L05NrRkZxi4tW52XXv71D8nAIWxnjnRxr3NuMJKOluXbBe7kCa2x7UFD1vPoB77D8Jqe6n6B5tvTUr62BMrP8lJPh1xbuv///yH5BAEAAB8ALAAAAAAPAA8AAAWD4CeOWQKMaDpESepi3tFlLgpExlK9RT9ohkYi08N8KhWP8nEwMBwIDyJRSTgO2CaDYcBOCAlMgtDYmhmTDSFQ+HAqgbLZIlAMLqiKw7m1EAYuFQsGEhITEwItKBc/EgIEAhINAUYkCBIQAQMBEGonIwAKa21iCgo7IxQDFRQjF1VtHyEAOw==', //'images/star_on.gif',
               falseImage: 'data:image/gif;base64,R0lGODlhDwAPALMPAP///8zj++r7/7vb/rHW/tPt/9Lk+qzT/rbY/sHh/8Te/N7q+Nzy/7nY/djn+f///yH5BAEAAA8ALAAAAAAPAA8AAARg8MkZjpo4k0KyNwlQBB42MICAfEF7APDRBsYzIEkewGKeDI1DgUckMg6GTdFIqC0QgyUgQVhgGkOi4OBBCJYdzILAywIGNcoOgCAQvowBRpE4kgzCQgPjQCAcEwsNTRIRADs=', //'images/star_off.gif',
             value: SimpleValue.create(obj.starred)
             });

           view.value.addListener(function() {
             var tmp = obj.clone();
             tmp.starred = view.value.get();
             tableView.browser.IssueDAO.put(tmp);
           });

           tableView.addChild(view);

           return view.toHTML();
         },
         view: {
           // TODO: make it so that initialized objects can be used as factories
           create: function() {
             return ImageBooleanView.create({
               trueImage: 'images/star_on.gif',
               falseImage: 'images/star_off.gif'
             });
           }
         },
         tableWidth: '20px',
         help: 'Whether the authenticated user has starred this issue.'
      },
      {
         model_: 'IntegerProperty',
         name: 'stars',
         tableWidth: '20px',
         help: 'Number of stars this issue has.'
      }
    ],

    methods: {
      isOpen: function() {
        return !! ({
          'New':      true,
          'Accepted': true,
          'Started':  true
        }[this.status]);
      },
      writeActions: function(other, out) {
        var diff = this.diff(other);
        delete diff.starred;

        if ( Object.keys(diff).length == 0 ) return;

        function convertArray(key) {
          if ( ! diff[key] ) {
            diff[key] = [];
            return;
          }

          var delta = diff[key].added;
          for ( var i = 0; i < diff[key].removed.length; i++ )
            delta.push("-" + diff[key].removed[i]);
          diff[key] = delta;
        }

        convertArray('blockedOn');
        convertArray('blocking');
        convertArray('cc');
        convertArray('labels');

        function propToLabel(prop, label) {
          if ( diff[prop] ) {
            diff.labels = diff.labels.concat(
              '-' + label + '-' + other[prop],
              label + '-' + diff[prop]);
            delete diff[prop];
          }
        }

        propToLabel('priority', 'Priority');
        propToLabel('app', 'App');
        propToLabel('milestone', 'Milestone');
        propToLabel('category', 'Cr');
        propToLabel('iteration', 'Iteration');
        propToLabel('releaseBlock', 'ReleaseBlock');
        propToLabel('OS', 'OS');

        var comment = QIssueComment.create({
          issueId: this.id,
          updates: IssueCommentUpdate.create(diff)
        });

        out(comment);
      }
    }
});

QIssue.getPrototype();

QIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v) {
      return ('' + v).length ? v : '----';
    };
  }
});

GeneratedQIssue.properties.forEach(function(p) {
  if ( ! p["tableFormatter"] ) {
    p["tableFormatter"] = function(v, _, tableView) {
      return ('' + v).length ? v : '----';
    };
  }
  if ( ! p["tableWidth"] ) {
    p["tableWidth"] = '80px;'
  }
});

var QIssueComment = FOAM({
  model_: 'Model',
  name: 'QIssueComment',
  extendsModel: 'IssueComment',

  ids: [ 'id' ],

  properties: [
    {
      name: 'author',
      view: 'QIssueCommentAuthorView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'updates',
      view: 'QIssueCommentUpdateView',
      preSet: function(newValue, _, prop) {
        if ( ! newValue.model_ ) return GLOBAL[prop.subType].create(newValue);
        return newValue;
      }
    },
    {
      name: 'published',
      view: 'RelativeDateTimeFieldView'
    },
    {
      model_: 'ReferenceProperty',
      name: 'issueId'
    }
  ]
});

var QUser = FOAM({
  model_: 'Model',
  name: 'QUser',
  extendsModel: 'User',

  properties: [
    {
      model_: 'StringProperty',
      name: 'email'
    },
    {
      name: 'projects',
      postSet: function(_, newValue) {
        if ( this.preferredProjects.length == 0 ) {
          this.preferredProjects = newValue.map(function(p) { return p.name; });
        }
      }
    },
    {
      model_: 'StringArrayProperty',
      name: 'preferredProjects',
      view: 'MultiLineStringArrayView'
    },
    {
      model_: 'StringProperty',
      name: 'defaultProject',
      defaultValue: 'chromium'
    }
  ]
});
<|endoftext|>


<commit_before>import SPELLS from 'common/SPELLS';
import ITEMS from 'common/ITEMS';
import ISSUE_IMPORTANCE from 'Parser/Core/ISSUE_IMPORTANCE';
import CoreAbilities from 'Parser/Core/Modules/Abilities';

class Abilities extends CoreAbilities {
  spellbook() {
    const combatant = this.selectedCombatant;
    return [
      {
        spell: SPELLS.TRANQUILITY_CAST,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: (_, combatant) => combatant.hasTalent(SPELLS.INNER_PEACE_TALENT.id) ? 120 : 180,
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.75,
          averageIssueEfficiency: 0.55,
          majorIssueEfficiency: 0.30,
        },
      },
      {
        spell: SPELLS.INNERVATE,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 180,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.IRONBARK,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: (_, combatant) => {
          let cd = 90;
          if (combatant.hasTalent(SPELLS.STONEBARK_TALENT.id)) {
            cd -= 30;
          }
          if (combatant.hasHands(ITEMS.XONIS_CARESS.id)) {
            cd *= 0.80;
          }
          return cd;
        },
        castEfficiency: {
          suggestion: true,
          importance: ISSUE_IMPORTANCE.MINOR,
          recommendedEfficiency: 0.60,
        },
      },
      {
        spell: SPELLS.BARKSKIN,
        buffSpellId: SPELLS.BARKSKIN.id,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 60,
        castEfficiency: {
          suggestion: true,
          importance: ISSUE_IMPORTANCE.MINOR,
          recommendedEfficiency: 0.60,
        },
      },
      {
        spell: SPELLS.CENARION_WARD_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: 30,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.CENARION_WARD_TALENT.id),
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.FLOURISH_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 90,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.FLOURISH_TALENT.id),
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.75,
          averageIssueEfficiency: 0.55,
          majorIssueEfficiency: 0.30,
        },
      },
      {
        spell: SPELLS.WILD_GROWTH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL_AOE,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.EFFLORESCENCE_CAST,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL_AOE,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.REJUVENATION,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.INCARNATION_TREE_OF_LIFE_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        enabled: combatant.hasTalent(SPELLS.INCARNATION_TREE_OF_LIFE_TALENT.id),
        cooldown: 180,
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.80,
          averageIssueEfficiency: 0.60,
          majorIssueEfficiency: 0.40,
        },
      },
      {
        spell: SPELLS.ARCANE_TORRENT_MANA,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 90,
        isUndetectable: true,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.REGROWTH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SWIFTMEND,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: (haste, combatant) => combatant.hasTalent(SPELLS.PROSPERITY_TALENT.id) ? 27 : 30,
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.40,
          averageIssueEfficiency: 0.00, // average and "negative" major included for checklist bar scaling in line with a "minor" issue
          majorIssueEfficiency: -1,
          importance: ISSUE_IMPORTANCE.MINOR,
        },
      },
      {
        spell: SPELLS.RENEWAL_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        enabled: combatant.hasTalent(SPELLS.RENEWAL_TALENT.id),
        cooldown: 90,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.SOLAR_WRATH,
        category: Abilities.SPELL_CATEGORIES.HEALER_DAMAGING_SPELL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.MOONFIRE,
        category: Abilities.SPELL_CATEGORIES.HEALER_DAMAGING_SPELL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SUNFIRE_CAST,
        category: Abilities.SPELL_CATEGORIES.HEALER_DAMAGING_SPELL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BEAR_FORM,
        buffSpellId: SPELLS.BEAR_FORM.id,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.CAT_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.DASH,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.DISPLACER_BEAST_TALENT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.DISPLACER_BEAST_TALENT.id),
      },
      {
        spell: SPELLS.FEROCIOUS_BITE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.RAKE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.MASS_ENTANGLEMENT_TALENT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.MASS_ENTANGLEMENT_TALENT.id),
      },
      {
        spell: SPELLS.STAG_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.TRAVEL_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.RIP,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SHRED,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.CAT_SWIPE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SWIPE_BEAR,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.URSOLS_VORTEX,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.MIGHTY_BASH_TALENT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.MIGHTY_BASH_TALENT.id),
      },
      {
        spell: SPELLS.TYPHOON,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.TYPHOON.id),
      },
      {
        spell: SPELLS.MOONKIN_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.STARSURGE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.LIFEBLOOM_HOT_HEAL,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.NATURES_CURE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
    ];
  }
}

export default Abilities;
<commit_msg>Updated ironbark cd<commit_after>import SPELLS from 'common/SPELLS';
import ITEMS from 'common/ITEMS';
import ISSUE_IMPORTANCE from 'Parser/Core/ISSUE_IMPORTANCE';
import CoreAbilities from 'Parser/Core/Modules/Abilities';

class Abilities extends CoreAbilities {
  spellbook() {
    const combatant = this.selectedCombatant;
    return [
      {
        spell: SPELLS.TRANQUILITY_CAST,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: (_, combatant) => combatant.hasTalent(SPELLS.INNER_PEACE_TALENT.id) ? 120 : 180,
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.75,
          averageIssueEfficiency: 0.55,
          majorIssueEfficiency: 0.30,
        },
      },
      {
        spell: SPELLS.INNERVATE,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 180,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.IRONBARK,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: (_, combatant) => {
          let cd = 60;
          if (combatant.hasTalent(SPELLS.STONEBARK_TALENT.id)) {
            cd -= 15;
          }
          if (combatant.hasHands(ITEMS.XONIS_CARESS.id)) {
            cd *= 0.80;
          }
          return cd;
        },
        castEfficiency: {
          suggestion: true,
          importance: ISSUE_IMPORTANCE.MINOR,
          recommendedEfficiency: 0.60,
        },
      },
      {
        spell: SPELLS.BARKSKIN,
        buffSpellId: SPELLS.BARKSKIN.id,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        cooldown: 60,
        castEfficiency: {
          suggestion: true,
          importance: ISSUE_IMPORTANCE.MINOR,
          recommendedEfficiency: 0.60,
        },
      },
      {
        spell: SPELLS.CENARION_WARD_TALENT,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: 30,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.CENARION_WARD_TALENT.id),
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.FLOURISH_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 90,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.FLOURISH_TALENT.id),
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.75,
          averageIssueEfficiency: 0.55,
          majorIssueEfficiency: 0.30,
        },
      },
      {
        spell: SPELLS.WILD_GROWTH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL_AOE,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.EFFLORESCENCE_CAST,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL_AOE,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.REJUVENATION,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.INCARNATION_TREE_OF_LIFE_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        enabled: combatant.hasTalent(SPELLS.INCARNATION_TREE_OF_LIFE_TALENT.id),
        cooldown: 180,
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.80,
          averageIssueEfficiency: 0.60,
          majorIssueEfficiency: 0.40,
        },
      },
      {
        spell: SPELLS.ARCANE_TORRENT_MANA,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        cooldown: 90,
        isUndetectable: true,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.REGROWTH,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SWIFTMEND,
        category: Abilities.SPELL_CATEGORIES.ROTATIONAL,
        cooldown: (haste, combatant) => combatant.hasTalent(SPELLS.PROSPERITY_TALENT.id) ? 27 : 30,
        gcd: {
          base: 1500,
        },
        castEfficiency: {
          suggestion: true,
          recommendedEfficiency: 0.40,
          averageIssueEfficiency: 0.00, // average and "negative" major included for checklist bar scaling in line with a "minor" issue
          majorIssueEfficiency: -1,
          importance: ISSUE_IMPORTANCE.MINOR,
        },
      },
      {
        spell: SPELLS.RENEWAL_TALENT,
        category: Abilities.SPELL_CATEGORIES.COOLDOWNS,
        enabled: combatant.hasTalent(SPELLS.RENEWAL_TALENT.id),
        cooldown: 90,
        castEfficiency: {
          suggestion: true,
        },
      },
      {
        spell: SPELLS.SOLAR_WRATH,
        category: Abilities.SPELL_CATEGORIES.HEALER_DAMAGING_SPELL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.MOONFIRE,
        category: Abilities.SPELL_CATEGORIES.HEALER_DAMAGING_SPELL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SUNFIRE_CAST,
        category: Abilities.SPELL_CATEGORIES.HEALER_DAMAGING_SPELL,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.BEAR_FORM,
        buffSpellId: SPELLS.BEAR_FORM.id,
        category: Abilities.SPELL_CATEGORIES.DEFENSIVE,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.CAT_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.DASH,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.DISPLACER_BEAST_TALENT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.DISPLACER_BEAST_TALENT.id),
      },
      {
        spell: SPELLS.FEROCIOUS_BITE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.RAKE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.MASS_ENTANGLEMENT_TALENT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.MASS_ENTANGLEMENT_TALENT.id),
      },
      {
        spell: SPELLS.STAG_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.TRAVEL_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.RIP,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SHRED,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.CAT_SWIPE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.SWIPE_BEAR,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.URSOLS_VORTEX,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.MIGHTY_BASH_TALENT,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.MIGHTY_BASH_TALENT.id),
      },
      {
        spell: SPELLS.TYPHOON,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
        enabled: combatant.hasTalent(SPELLS.TYPHOON.id),
      },
      {
        spell: SPELLS.MOONKIN_FORM,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.STARSURGE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.LIFEBLOOM_HOT_HEAL,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
      {
        spell: SPELLS.NATURES_CURE,
        category: Abilities.SPELL_CATEGORIES.OTHERS,
        gcd: {
          base: 1500,
        },
      },
    ];
  }
}

export default Abilities;
<|endoftext|>


<commit_before>const baseUrl = 'http://localhost:3333/api/';
//test

module.exports = {

  getNewToken: (name, password) => {
    return new Promise((resolve, reject)=>{
      $.ajax((baseUrl + 'authenticate'), {
        type: 'POST',
        dataType: 'json',
        data: {
          name: name,
          password
        },

        success: function(data){
          if(data.success)
            resolve(data);
          reject(data);
        },

        error: function(){
          reject('Could not log-in. Server could be down');
        }
      });
    });
  },

  createChart: (token, chart) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'create/chart'), {
        type: 'POST',
        dataType: 'json',
        data: {
          title: chart.title,
          desc: chart.desc,
          data: JSON.stringify(chart.points)
        },

        success: function(data){
          data.success && resolve(data);
          reject(data.message);
        },

        error: function(){
          reject('Could not create chart. Server could be down');
        },

        beforeSend: function (jqXHR){
          jqXHR.setRequestHeader('x-access-token', token);
          jqXHR.setRequestHeader(
            'Content-Type',
            'application/x-www-form-urlencoded'
          );
        }
      });
    });
  },

  getCharts: (token) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'charts'), {
        type: 'GET',
        dataType: 'json',
        headers: {
          'x-access-token': token
        },
        success: function(data){
          data.success && resolve(data);
          reject(
            data.message ||
            'Did not get chart data from request to service'
          );
        },
        error: () => {
          reject('Error trying to get polls from RESTful service');
        }
      });
    });
  },

  getLatestCharts: () => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'latestcharts'), {
        type: 'GET',
        dataType: 'json',
        success: function(data){
          data.success && resolve(data);
          reject(
            data.message ||
            'Did no get chart data from request to service'
          );
        },
        error: () => {
          reject('Error trying to get latest polls from RESTful service');
        }
      });
    });
  },

  vote: (chartid, votefor) => {
    //need to move vote limits on the server side this is easy to cheat with
    if(window.localStorage.getItem("voted"+chartid) != "voted"){
      window.localStorage.setItem("voted"+chartid, "voted");
      return new Promise((resolve, reject) => {
        $.ajax((baseUrl + 'vote'), {
          type: 'GET',
          dataType: 'json',
          data: {
            chartid,
            votefor
          },
          success: function(data){
            data.success && resolve(data);
            reject(data.message || 'Voting did not work');
          },
          error: () => {
            reject('Error trying to talk to the RESTful service');
          }
        });
      });
    }
    return new Promise((resolve, reject) => {
      reject("You have already voted on this poll");
    })
  },

  addAnswer: (token, chartid, newanswer) => {
    return new Promise((resolve, reject) => {
      $.ajax(
        (baseUrl + 'add/answer'),
        {
          type: 'POST',
          dataType: 'json',
          data: {
            chartid,
            newanswer
          },
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          success: function(data){
            data.success && resolve(data);
            reject(data.message || 'Answer addition did not work');
          },
          error: () => {
            reject('Error trying to talk to the RESTful service');
          },
          beforeSend: function (jqXHR){
            jqXHR.setRequestHeader('x-access-token', token);
            jqXHR.setRequestHeader(
              'Content-Type',
              'application/x-www-form-urlencoded'
            );
          }
        }
      );
    });
  },

  getChart: (pollId) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'chart'), {
        type: 'GET',
        dataType: 'json',
        data: {
          chartId: pollId
        },
        success: function(data){
          data.success && resolve(data);
          reject(
            data.message ||
            'Did not get chart data from request to service'
          );
        },
        error: () => {
          reject('Error trying to get polls from RESTful service');
        }
      });
    });
  },

  deleteChart: (token, id) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'delete/chart'), {
        type: 'DELETE',
        dataType: 'json',
        data: {
          chartId: id
        },
        headers: {
          'x-access-token': token,
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        success: function(data){
          data.success && resolve(data);
          reject('Connected to server but could not delete ', id);
        },
        error: () => {
          reject('Error trying to delete polls from RESTful service');
        }
      });
    });
  },

  createUser: (name, password) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'create/user'), {
        type: 'POST',
        dataType: 'json',
        data: { name, password },
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        success: function(data){
          data.success && resolve(data);
          reject('Connected to server but could not create the user ' + name);
        },
        error: () => {
          reject(
            'Error trying to create the user from the RESTful serivce ' +
          '(is the server up?)'
        );
        }
      });
    });
  }

};
<commit_msg>(debug) undo test<commit_after>const baseUrl = 'http://localhost:3333/api/';

module.exports = {

  getNewToken: (name, password) => {
    return new Promise((resolve, reject)=>{
      $.ajax((baseUrl + 'authenticate'), {
        type: 'POST',
        dataType: 'json',
        data: {
          name: name,
          password
        },

        success: function(data){
          if(data.success)
            resolve(data);
          reject(data);
        },

        error: function(){
          reject('Could not log-in. Server could be down');
        }
      });
    });
  },

  createChart: (token, chart) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'create/chart'), {
        type: 'POST',
        dataType: 'json',
        data: {
          title: chart.title,
          desc: chart.desc,
          data: JSON.stringify(chart.points)
        },

        success: function(data){
          data.success && resolve(data);
          reject(data.message);
        },

        error: function(){
          reject('Could not create chart. Server could be down');
        },

        beforeSend: function (jqXHR){
          jqXHR.setRequestHeader('x-access-token', token);
          jqXHR.setRequestHeader(
            'Content-Type',
            'application/x-www-form-urlencoded'
          );
        }
      });
    });
  },

  getCharts: (token) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'charts'), {
        type: 'GET',
        dataType: 'json',
        headers: {
          'x-access-token': token
        },
        success: function(data){
          data.success && resolve(data);
          reject(
            data.message ||
            'Did not get chart data from request to service'
          );
        },
        error: () => {
          reject('Error trying to get polls from RESTful service');
        }
      });
    });
  },

  getLatestCharts: () => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'latestcharts'), {
        type: 'GET',
        dataType: 'json',
        success: function(data){
          data.success && resolve(data);
          reject(
            data.message ||
            'Did no get chart data from request to service'
          );
        },
        error: () => {
          reject('Error trying to get latest polls from RESTful service');
        }
      });
    });
  },

  vote: (chartid, votefor) => {
    //need to move vote limits on the server side this is easy to cheat with
    if(window.localStorage.getItem("voted"+chartid) != "voted"){
      window.localStorage.setItem("voted"+chartid, "voted");
      return new Promise((resolve, reject) => {
        $.ajax((baseUrl + 'vote'), {
          type: 'GET',
          dataType: 'json',
          data: {
            chartid,
            votefor
          },
          success: function(data){
            data.success && resolve(data);
            reject(data.message || 'Voting did not work');
          },
          error: () => {
            reject('Error trying to talk to the RESTful service');
          }
        });
      });
    }
    return new Promise((resolve, reject) => {
      reject("You have already voted on this poll");
    })
  },

  addAnswer: (token, chartid, newanswer) => {
    return new Promise((resolve, reject) => {
      $.ajax(
        (baseUrl + 'add/answer'),
        {
          type: 'POST',
          dataType: 'json',
          data: {
            chartid,
            newanswer
          },
          headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
          success: function(data){
            data.success && resolve(data);
            reject(data.message || 'Answer addition did not work');
          },
          error: () => {
            reject('Error trying to talk to the RESTful service');
          },
          beforeSend: function (jqXHR){
            jqXHR.setRequestHeader('x-access-token', token);
            jqXHR.setRequestHeader(
              'Content-Type',
              'application/x-www-form-urlencoded'
            );
          }
        }
      );
    });
  },

  getChart: (pollId) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'chart'), {
        type: 'GET',
        dataType: 'json',
        data: {
          chartId: pollId
        },
        success: function(data){
          data.success && resolve(data);
          reject(
            data.message ||
            'Did not get chart data from request to service'
          );
        },
        error: () => {
          reject('Error trying to get polls from RESTful service');
        }
      });
    });
  },

  deleteChart: (token, id) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'delete/chart'), {
        type: 'DELETE',
        dataType: 'json',
        data: {
          chartId: id
        },
        headers: {
          'x-access-token': token,
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        success: function(data){
          data.success && resolve(data);
          reject('Connected to server but could not delete ', id);
        },
        error: () => {
          reject('Error trying to delete polls from RESTful service');
        }
      });
    });
  },

  createUser: (name, password) => {
    return new Promise((resolve, reject) => {
      $.ajax((baseUrl + 'create/user'), {
        type: 'POST',
        dataType: 'json',
        data: { name, password },
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        success: function(data){
          data.success && resolve(data);
          reject('Connected to server but could not create the user ' + name);
        },
        error: () => {
          reject(
            'Error trying to create the user from the RESTful serivce ' +
          '(is the server up?)'
        );
        }
      });
    });
  }

};
<|endoftext|>


<commit_before>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.provide("frappe.ui.form");

frappe.ui.form.Attachments = Class.extend({
	init: function(opts) {
		$.extend(this, opts);
		this.make();
	},
	make: function() {
		var me = this;
		this.parent.find(".add-attachment").click(function() {
			me.new_attachment();
		});
		this.add_attachment_wrapper = this.parent.find(".add_attachment").parent();
		this.attachments_label = this.parent.find(".attachments-label");
	},
	max_reached: function() {
		// no of attachments
		var n = Object.keys(this.get_attachments()).length;

		// button if the number of attachments is less than max
		if(n < this.frm.meta.max_attachments || !this.frm.meta.max_attachments) {
			return false;
		}
		return true;
	},
	refresh: function() {
		var me = this;

		if(this.frm.doc.__islocal) {
			this.parent.toggle(false);
			return;
		}
		this.parent.toggle(true);
		this.parent.find(".attachment-row").remove();

		var max_reached = this.max_reached();
		this.add_attachment_wrapper.toggleClass("hide", !max_reached);

		// add attachment objects
		var attachments = this.get_attachments();
		if(attachments.length) {
			attachments.forEach(function(attachment) {
				me.add_attachment(attachment)
			});
		} else {
			this.attachments_label.removeClass("has-attachments");
		}

	},
	get_attachments: function() {
		return this.frm.get_docinfo().attachments;
	},
	add_attachment: function(attachment) {
		var file_name = attachment.file_name;
		var file_url = this.get_file_url(attachment);
		var fileid = attachment.name;
		if (!file_name) {
			file_name = file_url;
		}

		var me = this;
		var $attach = $(repl('
\
				×\
				%(lock_icon)s\
				\
					%(file_name)s\

', {
				lock_icon: attachment.is_private ? ' ': "",
				file_name: file_name,
				file_url: frappe.urllib.get_full_url(file_url)
			}))
			.insertAfter(this.attachments_label.addClass("has-attachments"));

		var $close =
			$attach.find(".close")
			.data("fileid", fileid)
			.click(function() {
				var remove_btn = this;
				frappe.confirm(__("Are you sure you want to delete the attachment?"),
					function() {
						me.remove_attachment($(remove_btn).data("fileid"))
					}
				);
				return false
			});

		if(!frappe.model.can_write(this.frm.doctype, this.frm.name)) {
			$close.remove();
		}
	},
	get_file_url: function(attachment) {
		var file_url = attachment.file_url;
		if (!file_url) {
			if (attachment.file_name.indexOf('files/') === 0) {
				file_url = '/' + attachment.file_name;
			}
			else {
				file_url = '/files/' + attachment.file_name;
			}
		}
		// hash is not escaped, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
		return encodeURI(file_url).replace(/#/g, '%23');
	},
	get_file_id_from_file_url: function(file_url) {
		var fid;
		$.each(this.get_attachments(), function(i, attachment) {
			if (attachment.file_url === file_url) {
				fid = attachment.name;
				return false;
			}
		});
		return fid;
	},
	remove_attachment_by_filename: function(filename, callback) {
		this.remove_attachment(this.get_file_id_from_file_url(filename), callback);
	},
	remove_attachment: function(fileid, callback) {
		if (!fileid) {
			if (callback) callback();
			return;
		}

		var me = this;
		return frappe.call({
			method: 'frappe.desk.form.utils.remove_attach',
			args: {
				fid: fileid,
				dt: me.frm.doctype,
				dn: me.frm.docname
			},
			callback: function(r,rt) {
				if(r.exc) {
					if(!r._server_messages)
						frappe.msgprint(__("There were errors"));
					return;
				}
				me.remove_fileid(fileid);
				me.frm.get_docinfo().communications.push(r.message);
				me.frm.timeline.refresh();
				if (callback) callback();
			}
		});
	},
	new_attachment: function(fieldname) {
		var me = this;
		if (this.dialog) {
			// remove upload dialog
			this.dialog.$wrapper.remove();
		}

		// make upload dialog
		this.dialog = frappe.ui.get_upload_dialog({
			"args": me.get_args(),
			"callback": function(attachment, r) { me.attachment_uploaded(attachment, r) },
			"max_width": me.frm.cscript ? me.frm.cscript.attachment_max_width : null,
			"max_height": me.frm.cscript ? me.frm.cscript.attachment_max_height : null
		});
	},
	get_args: function() {
		return {
			from_form: 1,
			doctype: this.frm.doctype,
			docname: this.frm.docname,
		}
	},
	attachment_uploaded:  function(attachment, r) {
		this.dialog && this.dialog.hide();
		this.update_attachment(attachment, r.message.comment);

		if(this.fieldname) {
			this.frm.set_value(this.fieldname, attachment.file_url);
		}
	},
	update_attachment: function(attachment, comment) {
		if(attachment.name) {
			this.add_to_attachments(attachment);
			this.refresh();
			if(comment) {
				this.frm.get_docinfo().communications.push(comment);
				this.frm.timeline.refresh();
			}
		}
	},
	add_to_attachments: function (attachment) {
		var form_attachments = this.get_attachments();
		for(var i in form_attachments) {
			// prevent duplicate
			if(form_attachments[i]["name"] === attachment.name) return;
		}
		form_attachments.push(attachment);
	},
	remove_fileid: function(fileid) {
		var attachments = this.get_attachments();
		var new_attachments = [];
		$.each(attachments, function(i, attachment) {
			if(attachment.name!=fileid) {
				new_attachments.push(attachment);
			}
		});
		this.frm.get_docinfo().attachments = new_attachments;
		this.refresh();
	}
});

frappe.ui.get_upload_dialog = function(opts){
	var dialog = new frappe.ui.Dialog({
		title: __('Upload Attachment'),
		no_focus: true,
		fields: [
			{"fieldtype": "Section Break"},
			{"fieldtype": "Link" , "fieldname": "file" , "label": __("Select uploaded file"), "options": "File"},
			{"hidden": !opts.args.doctype || !frappe.boot.gsuite_enabled,"fieldtype": "Section Break", "label": __("GSuite Document")},
			{"fieldtype": "Link" ,"fieldname": "gs_template" ,"label": __("Select template"), "options": "GSuite Templates", reqd : false, filters: {'related_doctype': opts.args.doctype}},
		],
	});
	var btn = dialog.set_primary_action(__("Attach"));
	btn.removeClass("btn-primary").addClass("btn-default");

	dialog.show();
	var upload_area = $('

').prependTo(dialog.body);

	var fd = dialog.fields_dict;

	$(fd.gs_template.input).change(function() {
		opts.args.gs_template = fd.gs_template.get_value();
	});

	$(fd.file.input).change(function() {
		frappe.call({
			'method': 'frappe.client.get_value',
			'args': {
				'doctype': 'File',
				'fieldname': ['file_url','file_name','is_private'],
				'filters': {
					'name': dialog.get_value("file")
				}
			},
			callback: function(r){
				if(!r.message) return;
				dialog.$wrapper.find('[name="file_url"]').val(r.message.file_url);
				dialog.$wrapper.find('.private-file input').prop('checked', r.message.is_private);
				opts.args.filename = r.message.file_name;
			}
		});
	});
	frappe.upload.make({
		parent: upload_area,
		args: opts.args,
		callback: function(attachment, r) {
			dialog.hide();
			if(opts.callback){
				opts.callback(attachment, r);
			}
		},
		on_select: function() {
			btn.removeClass("btn-default").addClass("btn-primary");
		},
		onerror: function() {
			dialog.hide();
		},
		btn: btn,
		max_width: opts.max_width,
		max_height: opts.max_height,
	});

	return dialog;
}
<commit_msg>[hotfix] set the file_url on file field on change event (#3934)<commit_after>// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt

frappe.provide("frappe.ui.form");

frappe.ui.form.Attachments = Class.extend({
	init: function(opts) {
		$.extend(this, opts);
		this.make();
	},
	make: function() {
		var me = this;
		this.parent.find(".add-attachment").click(function() {
			me.new_attachment();
		});
		this.add_attachment_wrapper = this.parent.find(".add_attachment").parent();
		this.attachments_label = this.parent.find(".attachments-label");
	},
	max_reached: function() {
		// no of attachments
		var n = Object.keys(this.get_attachments()).length;

		// button if the number of attachments is less than max
		if(n < this.frm.meta.max_attachments || !this.frm.meta.max_attachments) {
			return false;
		}
		return true;
	},
	refresh: function() {
		var me = this;

		if(this.frm.doc.__islocal) {
			this.parent.toggle(false);
			return;
		}
		this.parent.toggle(true);
		this.parent.find(".attachment-row").remove();

		var max_reached = this.max_reached();
		this.add_attachment_wrapper.toggleClass("hide", !max_reached);

		// add attachment objects
		var attachments = this.get_attachments();
		if(attachments.length) {
			attachments.forEach(function(attachment) {
				me.add_attachment(attachment)
			});
		} else {
			this.attachments_label.removeClass("has-attachments");
		}

	},
	get_attachments: function() {
		return this.frm.get_docinfo().attachments;
	},
	add_attachment: function(attachment) {
		var file_name = attachment.file_name;
		var file_url = this.get_file_url(attachment);
		var fileid = attachment.name;
		if (!file_name) {
			file_name = file_url;
		}

		var me = this;
		var $attach = $(repl('
\
				×\
				%(lock_icon)s\
				\
					%(file_name)s\

', {
				lock_icon: attachment.is_private ? ' ': "",
				file_name: file_name,
				file_url: frappe.urllib.get_full_url(file_url)
			}))
			.insertAfter(this.attachments_label.addClass("has-attachments"));

		var $close =
			$attach.find(".close")
			.data("fileid", fileid)
			.click(function() {
				var remove_btn = this;
				frappe.confirm(__("Are you sure you want to delete the attachment?"),
					function() {
						me.remove_attachment($(remove_btn).data("fileid"))
					}
				);
				return false
			});

		if(!frappe.model.can_write(this.frm.doctype, this.frm.name)) {
			$close.remove();
		}
	},
	get_file_url: function(attachment) {
		var file_url = attachment.file_url;
		if (!file_url) {
			if (attachment.file_name.indexOf('files/') === 0) {
				file_url = '/' + attachment.file_name;
			}
			else {
				file_url = '/files/' + attachment.file_name;
			}
		}
		// hash is not escaped, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
		return encodeURI(file_url).replace(/#/g, '%23');
	},
	get_file_id_from_file_url: function(file_url) {
		var fid;
		$.each(this.get_attachments(), function(i, attachment) {
			if (attachment.file_url === file_url) {
				fid = attachment.name;
				return false;
			}
		});
		return fid;
	},
	remove_attachment_by_filename: function(filename, callback) {
		this.remove_attachment(this.get_file_id_from_file_url(filename), callback);
	},
	remove_attachment: function(fileid, callback) {
		if (!fileid) {
			if (callback) callback();
			return;
		}

		var me = this;
		return frappe.call({
			method: 'frappe.desk.form.utils.remove_attach',
			args: {
				fid: fileid,
				dt: me.frm.doctype,
				dn: me.frm.docname
			},
			callback: function(r,rt) {
				if(r.exc) {
					if(!r._server_messages)
						frappe.msgprint(__("There were errors"));
					return;
				}
				me.remove_fileid(fileid);
				me.frm.get_docinfo().communications.push(r.message);
				me.frm.timeline.refresh();
				if (callback) callback();
			}
		});
	},
	new_attachment: function(fieldname) {
		var me = this;
		if (this.dialog) {
			// remove upload dialog
			this.dialog.$wrapper.remove();
		}

		// make upload dialog
		this.dialog = frappe.ui.get_upload_dialog({
			"args": me.get_args(),
			"callback": function(attachment, r) { me.attachment_uploaded(attachment, r) },
			"max_width": me.frm.cscript ? me.frm.cscript.attachment_max_width : null,
			"max_height": me.frm.cscript ? me.frm.cscript.attachment_max_height : null
		});
	},
	get_args: function() {
		return {
			from_form: 1,
			doctype: this.frm.doctype,
			docname: this.frm.docname,
		}
	},
	attachment_uploaded:  function(attachment, r) {
		this.dialog && this.dialog.hide();
		this.update_attachment(attachment, r.message.comment);

		if(this.fieldname) {
			this.frm.set_value(this.fieldname, attachment.file_url);
		}
	},
	update_attachment: function(attachment, comment) {
		if(attachment.name) {
			this.add_to_attachments(attachment);
			this.refresh();
			if(comment) {
				this.frm.get_docinfo().communications.push(comment);
				this.frm.timeline.refresh();
			}
		}
	},
	add_to_attachments: function (attachment) {
		var form_attachments = this.get_attachments();
		for(var i in form_attachments) {
			// prevent duplicate
			if(form_attachments[i]["name"] === attachment.name) return;
		}
		form_attachments.push(attachment);
	},
	remove_fileid: function(fileid) {
		var attachments = this.get_attachments();
		var new_attachments = [];
		$.each(attachments, function(i, attachment) {
			if(attachment.name!=fileid) {
				new_attachments.push(attachment);
			}
		});
		this.frm.get_docinfo().attachments = new_attachments;
		this.refresh();
	}
});

frappe.ui.get_upload_dialog = function(opts){
	var dialog = new frappe.ui.Dialog({
		title: __('Upload Attachment'),
		no_focus: true,
		fields: [
			{
				"fieldtype": "Section Break"
			},
			{
				"fieldtype": "Link" ,
				"fieldname": "file" ,
				"label": __("Select uploaded file"),
				"options": "File",
				onchange: function() {
					frappe.call({
						'method': 'frappe.client.get_value',
						'args': {
							'doctype': 'File',
							'fieldname': ['file_url','file_name','is_private'],
							'filters': {
								'name': dialog.get_value("file")
							}
						},
						callback: function(r){
							if(!r.message) {
								dialog.$wrapper.find('[name="file_url"]').val("");
								return;
							}
							dialog.$wrapper.find('[name="file_url"]').val(r.message.file_url);
							dialog.$wrapper.find('.private-file input').prop('checked', r.message.is_private);
							opts.args.filename = r.message.file_name;
						}
					});
				}
			},
			{
				"hidden": !opts.args.doctype || !frappe.boot.gsuite_enabled,
				"fieldtype": "Section Break",
				"label": __("GSuite Document"),
			},
			{
				"fieldtype": "Link" ,
				"fieldname": "gs_template" ,
				"label": __("Select template"),
				"options": "GSuite Templates",
				"reqd" : false,
				"filters": {
					'related_doctype': opts.args.doctype
				}
			},
		],
	});
	var btn = dialog.set_primary_action(__("Attach"));
	btn.removeClass("btn-primary").addClass("btn-default");

	dialog.show();
	var upload_area = $('

').prependTo(dialog.body);

	var fd = dialog.fields_dict;

	$(fd.gs_template.input).change(function() {
		opts.args.gs_template = fd.gs_template.get_value();
	});

	frappe.upload.make({
		parent: upload_area,
		args: opts.args,
		callback: function(attachment, r) {
			dialog.hide();
			if(opts.callback){
				opts.callback(attachment, r);
			}
		},
		on_select: function() {
			btn.removeClass("btn-default").addClass("btn-primary");
		},
		onerror: function() {
			dialog.hide();
		},
		btn: btn,
		max_width: opts.max_width,
		max_height: opts.max_height,
	});

	return dialog;
}
<|endoftext|>