<commit_before>$(function(){

	//阻止默认行为
		$("a:not([href^=http])").each(function(){
			$(this).click(function(e){
				e.preventDefault();
			})
		})

	//直接link阻止冒泡
		$("a[href^='http']").each(function(){
			$(this).attr('target',"_blank")
			$(this).click(function(e){
				e.stopPropagation();
			})
		})

	//侧边栏与内容相关功能
		var $sidebar_list = $(".c-sidebar-list")
		var $sidebar_list_ul = $(".c-sidebar-list ul")
		var $sidebar_list_item = $(".c-sidebar-list ul li")
		var $c_tab = $(".c-tab")

		//当屏幕高度不足以展示侧边栏时
		var _screen_H = $(window).height()
		var _sidebar_list_height = $sidebar_list_ul.height()
		var _sidebar_list_visheight = _screen_H - 38 - 42 - 20;
		_sidebar_list_height > _sidebar_list_visheight ? $sidebar_list.addClass('scroll') : $sidebar_list.removeClass('scroll');

		//自动生成侧边栏tab卡指向地址
		$sidebar_list_item.each(function(){
			var i = $(this).index()
			var link = '?c=' + i
			$(this).attr('href',link)
		})

		//侧边栏关联内容卡开关
		$sidebar_list_item.on('click',function(){
			$sidebar_list_item.removeClass('on')
			$(this).addClass('on')
			var i = $(this).index()
			$c_tab.removeClass('on').eq(i).addClass('on')
			window.location.search = '?c=' + i
		})

		//动态访问指定tab卡
		var getRequest = function(paras){
		    var url = location.search;
		    var _request = {};

		    if( url.indexOf("?") != -1){
		        var str = url.substr(1),
		            i = 0,
		            strs = str.split("&");

		        for( ;i<strs.length;i+=1 ){
		            _request[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]);
		        }
		    }

		    var value = _request[paras.toLowerCase()];
		    if(typeof(value) == "undefined"){
		        return "";
		    } else {
		        return value;
		    }
		};
		var category = getRequest('c');
		var category = parseInt(category);
		isNaN(category) ? category=0 : category=category
		$sidebar_list_item.eq(category).addClass('on');
		$c_tab.eq(category).addClass('on');

	//内容区
		var
		$main = $("#main"),
		$btg = $('h3').add('h4'),
		$mnav = $("#showmenu"),
		screenW = $(window).width()

		//h3 & 4 Toggle
			$btg.on('click',function(){
				$(this).next('div,ul').slideToggle('slow')
				var status = $(this).children('span').html()
				if(status=='-'){
					$(this).children('span').html('+')}
				else if(status=='+'){
					$(this).children('span').html('-');
				}
			})

		//Tips Layout
			$main.on('mouseover','h4+ul>li',function(e){
				$(this).children('span').css({
						left:e.pageX+12+'px',
						top:e.pageY+8+'px',
						display:'block'
					})
				}).on('mouseout','h4+ul>li',function(){
					$(this).children('span').hide()
				})

		//Snippet Box
			$("#closebox").click(function(){
				$("#snippet").hide()
			})

			$("#snippet").draggable({
				handle:'h6',
				cursor:'move',
			});

			$("#main").on('click','h4+ul>li',function(){
				var originFn = $(this).children("a:first-child").html() || ''
				var prevArg = $(this).children("em:first-child").html() || ''
				var nextArg = $(this).children("em:nth-child(2)").html() || ''
				var title =  prevArg + originFn + nextArg
				//title || (title = "Snippet");
				var info = $(this).children("span").html();

				$("#snippet").show()
				$("#box-title").html(title)
				$("#box").html(info)
			})

	//公共tab卡功能
		$(".e-tab li").on('click',function(){
			$(this).siblings('li').removeClass('on')
			$(this).addClass('on')
			var i = $(this).index()
			var $tabbox = $(this).parent('.e-tab').siblings('.e-tab-box')
			$tabbox.removeClass('on').eq(i).addClass('on')
		})

	//mobile

})<commit_msg>修改为location.hash动态访问<commit_after>$(function(){

	//阻止默认行为
		$("a:not([href^=http])").each(function(){
			$(this).click(function(e){
				e.preventDefault();
			})
		})

	//直接link阻止冒泡
		$("a[href^='http']").each(function(){
			$(this).attr('target',"_blank")
			$(this).click(function(e){
				e.stopPropagation();
			})
		})

	//侧边栏与内容相关功能
		var $sidebar_list = $(".c-sidebar-list")
		var $sidebar_list_ul = $(".c-sidebar-list ul")
		var $sidebar_list_item = $(".c-sidebar-list ul li")
		var $c_tab = $(".c-tab")

		//当屏幕高度不足以展示侧边栏时
			var _screen_H = $(window).height()
			var _sidebar_list_height = $sidebar_list_ul.height()
			var _sidebar_list_visheight = _screen_H - 38 - 42 - 20;
			_sidebar_list_height > _sidebar_list_visheight ? $sidebar_list.addClass('scroll') : $sidebar_list.removeClass('scroll');

		//自动生成侧边栏tab卡指向地址
			$sidebar_list_item.each(function(){
				var i = $(this).index()
				var link = '#' + i
				$(this).attr('href',link)
			})

		//侧边栏关联内容卡开关
			$sidebar_list_item.on('click',function(e){
				$sidebar_list_item.removeClass('on')
				$(this).addClass('on')
				var i = $(this).index()
				$c_tab.removeClass('on').eq(i).addClass('on')
				window.location.hash = '#' + i
			})

		//动态访问指定tab卡
			/*var getRequest = function(paras){
			    var url = location.location;
			    var _request = {};

			    if( url.indexOf("?") != -1){
			        var str = url.substr(1),
			            i = 0,
			            strs = str.split("&");

			        for( ;i<strs.length;i+=1 ){
			            _request[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]);
			        }
			    }

			    var value = _request[paras.toLowerCase()];
			    if(typeof(value) == "undefined"){
			        return "";
			    } else {
			        return value;
			    }
			};
			var category = getRequest('c');
			var category = parseInt(category);*/

		//通过hash访问
			var cur_hash = window.location.hash
			function visitByHash(){
				//默认访问时
				if (!cur_hash){
					cur_hash = '#0'
					$sidebar_list_item.eq(0).addClass('on')
					$c_tab.eq(0).addClass('on')
					return
				}
				//有带hash访问时
				var i = parseInt(cur_hash.slice(1))
				$sidebar_list_item.eq(i).addClass('on')
				$c_tab.eq(i).addClass('on')
			}
			visitByHash();

	//内容区
		var
		$main = $("#main"),
		$btg = $('h3').add('h4'),
		$mnav = $("#showmenu"),
		screenW = $(window).width()

		//h3 & 4 Toggle
			$btg.on('click',function(){
				$(this).next('div,ul').slideToggle('slow')
				var status = $(this).children('span').html()
				if(status=='-'){
					$(this).children('span').html('+')}
				else if(status=='+'){
					$(this).children('span').html('-');
				}
			})

		//Tips Layout
			$main.on('mouseover','h4+ul>li',function(e){
				$(this).children('span').css({
						left:e.pageX+12+'px',
						top:e.pageY+8+'px',
						display:'block'
					})
				}).on('mouseout','h4+ul>li',function(){
					$(this).children('span').hide()
				})

		//Snippet Box
			$("#closebox").click(function(){
				$("#snippet").hide()
			})

			$("#snippet").draggable({
				handle:'h6',
				cursor:'move',
			});

			$("#main").on('click','h4+ul>li',function(){
				var originFn = $(this).children("a:first-child").html() || ''
				var prevArg = $(this).children("em:first-child").html() || ''
				var nextArg = $(this).children("em:nth-child(2)").html() || ''
				var title =  prevArg + originFn + nextArg
				//title || (title = "Snippet");
				var info = $(this).children("span").html();

				$("#snippet").show()
				$("#box-title").html(title)
				$("#box").html(info)
			})

	//公共tab卡功能
		$(".e-tab li").on('click',function(){
			$(this).siblings('li').removeClass('on')
			$(this).addClass('on')
			var i = $(this).index()
			var $tabbox = $(this).parent('.e-tab').siblings('.e-tab-box')
			$tabbox.removeClass('on').eq(i).addClass('on')
		})

	//mobile

})<|endoftext|>


<commit_before>Meteor.startup(function() {
    if (typeof(ngMeteor) !== 'undefined') {
        ngMeteor.requires.push('ui.grid');
    }
});
<commit_msg>Adding selection module of ui-grid to ngMeteor<commit_after>Meteor.startup(function() {
    if (typeof(ngMeteor) !== 'undefined') {
        ngMeteor.requires.push('ui.grid');
        ngMeteor.requires.push('ui.grid.selection');
    }
});
<|endoftext|>


<commit_before>var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;
var moment = require("moment");
var async = require("async");
var ObjectId = mongoose.Schema.Types.ObjectId;
var Currency = require('./currency_model');
var User = require("./user_model");
var Organisation = require("./organisation_model");

var WalletSchema   = new Schema({
	name: { type: String, required: true, validate: /\S+/ },
	currency_id: { type: ObjectId, index: true, ref: "Currency", required: true },
	priority: { type: Number, required: true },
	quota_frequency: { type: String, validate: /daily|weekly|monthly|annually|never/, index: true, default: "never" },
	quota_amount: { type: Number, default: 0 },
	last_quota_date: { type: Date, index: true, default: Date.now },
	user_id: [{ type: ObjectId, index: true, ref: "User", required: true }],
	organisation_id: { type: ObjectId, index: true, ref: "Organisation" },
	balance: { type: Number, default: 0 },
	date_created: { type: Date, default: Date.now },
	personal: Boolean,
	_owner_id: ObjectId
});

WalletSchema.set("_perms", {
	admin: "crud",
	user: "r",
});

WalletSchema.index({ name: 1, user_id: 1 }, { unique: true });

WalletSchema.statics.topup_daily = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().subtract(1, "day").startOf("day").format("YYYY-MM-DD");
	return Wallet.find({ quota_frequency: "daily", last_quota_date: { $lte: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

WalletSchema.statics.topup_weekly = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().subtract(1, "week");
	return Wallet.find({ quota_frequency: "weekly", last_quota_date: { $lte: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

WalletSchema.statics.topup_monthly = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().startOf('month');
	return Wallet.find({ quota_frequency: "monthly", last_quota_date: { $lt: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

WalletSchema.statics.topup_annually = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().subtract(1, "year");
	return Wallet.find({ quota_frequency: "annually", last_quota_date: { $lte: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

// Set this wallet as the Personal wallet and unset any other wallets for the same currency and user
WalletSchema.statics.set_personal = function(_id) {
	var Wallet = require("./wallet_model");
	var queue = [];
	var wallet = null;
	return Wallet.findOne({ _id })
	.then(result => {
		wallet = result;
		return Wallet.find({ currency: wallet.currency, user_id: wallet.user_id, personal: true });
	})
	.then(wallets => {
		wallets.forEach(w => {
			if (w._id.toString() !== wallet._id.toString()) {
				queue.push(cb => {
					w.personal = false;
					w.save()
					.then(result => {
						cb(null, result);
					}, err => {
						console.error(err);
						cb(err);
					});
				});
			}
		});
		queue.push(cb => {
			wallet.personal = true;
			wallet.save()
			.then(result => {
				cb(null, result);
			}, err => {
				console.error(err);
				cb(err);
			});
		});
		return new Promise((resolve, reject) => {
			async.series(queue, (err, result) => {
				if (err)
					return reject(err);
				return resolve(result);
			});
		});
	});
};

module.exports = mongoose.model('Wallet', WalletSchema);<commit_msg>Log day_ago<commit_after>var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;
var moment = require("moment");
var async = require("async");
var ObjectId = mongoose.Schema.Types.ObjectId;
var Currency = require('./currency_model');
var User = require("./user_model");
var Organisation = require("./organisation_model");

var WalletSchema   = new Schema({
	name: { type: String, required: true, validate: /\S+/ },
	currency_id: { type: ObjectId, index: true, ref: "Currency", required: true },
	priority: { type: Number, required: true },
	quota_frequency: { type: String, validate: /daily|weekly|monthly|annually|never/, index: true, default: "never" },
	quota_amount: { type: Number, default: 0 },
	last_quota_date: { type: Date, index: true, default: Date.now },
	user_id: [{ type: ObjectId, index: true, ref: "User", required: true }],
	organisation_id: { type: ObjectId, index: true, ref: "Organisation" },
	balance: { type: Number, default: 0 },
	date_created: { type: Date, default: Date.now },
	personal: Boolean,
	_owner_id: ObjectId
});

WalletSchema.set("_perms", {
	admin: "crud",
	user: "r",
});

WalletSchema.index({ name: 1, user_id: 1 }, { unique: true });

WalletSchema.statics.topup_daily = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().subtract(1, "day").startOf("day").format("YYYY-MM-DD");
	console.log({ day_ago });
	return Wallet.find({ quota_frequency: "daily", last_quota_date: { $lte: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

WalletSchema.statics.topup_weekly = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().subtract(1, "week");
	return Wallet.find({ quota_frequency: "weekly", last_quota_date: { $lte: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

WalletSchema.statics.topup_monthly = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().startOf('month');
	return Wallet.find({ quota_frequency: "monthly", last_quota_date: { $lt: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

WalletSchema.statics.topup_annually = function() {
	var Wallet = require("./wallet_model");
	var day_ago = moment().subtract(1, "year");
	return Wallet.find({ quota_frequency: "annually", last_quota_date: { $lte: day_ago } })
	.then(wallets => {
		var result = [];
		wallets.forEach(wallet => {
			wallet.balance = wallet.quota_amount;
			wallet.last_quota_date = new Date();
			wallet.save();
			result.push(wallet);
		});
		return result;
	});
};

// Set this wallet as the Personal wallet and unset any other wallets for the same currency and user
WalletSchema.statics.set_personal = function(_id) {
	var Wallet = require("./wallet_model");
	var queue = [];
	var wallet = null;
	return Wallet.findOne({ _id })
	.then(result => {
		wallet = result;
		return Wallet.find({ currency: wallet.currency, user_id: wallet.user_id, personal: true });
	})
	.then(wallets => {
		wallets.forEach(w => {
			if (w._id.toString() !== wallet._id.toString()) {
				queue.push(cb => {
					w.personal = false;
					w.save()
					.then(result => {
						cb(null, result);
					}, err => {
						console.error(err);
						cb(err);
					});
				});
			}
		});
		queue.push(cb => {
			wallet.personal = true;
			wallet.save()
			.then(result => {
				cb(null, result);
			}, err => {
				console.error(err);
				cb(err);
			});
		});
		return new Promise((resolve, reject) => {
			async.series(queue, (err, result) => {
				if (err)
					return reject(err);
				return resolve(result);
			});
		});
	});
};

module.exports = mongoose.model('Wallet', WalletSchema);
<|endoftext|>


<commit_before>'use strict';

var moment = require('moment'), _ = require('lodash'), util = require('./util');

var durationOrThrow = _.partialRight(util.ensure, 'duration', moment.isDuration);
var momentOrThrow = _.partialRight(util.ensure, 'moment', moment.isMoment, function (value) {
    return value.clone();
});
var dateOrThrow = _.partialRight(util.ensure, 'date', _.isDate);
var numberOfMillisOrThrow = _.partialRight(util.ensure, 'number of milliseconds', _.isNumber);

var dateConversions = {
    numberOfMillisecondsAsDuration: function (durationInMillis) {
        return durationInMillis;
    }
};

var momentConversions = {
    numberOfMillisecondsAsDuration: function (durationInMillis) {
        return moment.duration(durationInMillis);
    }
};

var dateClockwork = {
    now: function () {
        return new Date();
    }
};

var momentClockwork = {
    now: function () {
        return moment();
    }
};

function TimeoutsAndIntervals(durationToMs) {
    return {
        setTimeout: function (callback, timeout) {
            return setTimeout(callback, durationToMs(timeout));
        },
        clearTimeout: function (id) {
            return clearTimeout(id);
        },
        setInterval: function (callback, interval) {
            return setInterval(callback, durationToMs(interval));
        },
        clearInterval: function (id) {
            return clearInterval(id);
        }
    };
}

exports.DateClock = function () {
    return _.extend(new TimeoutsAndIntervals(numberOfMillisOrThrow), dateConversions, dateClockwork);
};

exports.MomentClock = function () {
    return _.extend(new TimeoutsAndIntervals(function (duration) {
            return durationOrThrow(duration).asMilliseconds();
        }), momentConversions, momentClockwork);
};

function StubTimeoutsAndIntervals() {
    var intervals = {};
    var timeouts = {};

    return {
        setTimeout: function (callback) {
            var id = util.createGuid();
            timeouts[id] = callback;
            return id;
        },
        clearTimeout: function (id) {
            delete timeouts[id];
            return id;
        },
        setInterval: function (callback) {
            var id = util.createGuid();
            intervals[id] = callback;
            return id;
        },
        clearInterval: function (id) {
            delete intervals[id];
            return id;
        },
        triggerAll: function () {
            var ids = _.keys(timeouts).concat(_.keys(intervals));
            _.map(timeouts, function (timeout, id) {
                timeout();
                delete timeouts[id];
                return id;
            });
            _.each(intervals, function (interval) {
                interval();
            });
            return ids;
        }
    };
}

var StubClockwork = function (fns, current, tickSize, implicitTickFlag) {
    var current = current ? fns.dateCheck(current) : fns.dateFn(0);
    var tickSize = tickSize ? fns.durationCheck(tickSize) : fns.durationFn(1000);
    var implicitTickFlag = implicitTickFlag === undefined ? false : implicitTickFlag;

    return {
        now: function () {
            if (arguments.length > 0) {
                current = fns.dateCheck(arguments[0]);
            } else if (implicitTickFlag) {
                current = fns.incrementBy(current, tickSize);
            }
            return fns.dateFn(current);
        },
        tick: function (duration) {
            current = fns.incrementBy(current, duration ? fns.durationCheck(arguments[0]) : tickSize);
            return fns.dateFn(current);
        },
        tickSize: function (duration) {
            if (duration) {
                tickSize = fns.durationCheck(duration);
            }
            return tickSize;
        },
        implicitTick: function () {
            if (arguments.length > 0) {
                implicitTickFlag = arguments[0];
            }
            return implicitTickFlag;
        }
    };
};

exports.StubMomentClock = function (current, tickSize, implicitTickFlag) {
    var fns = {
        dateFn: moment,
        durationFn: function (ms) {
            return moment.duration(ms, 'milliseconds');
        },
        incrementBy: function (date, tickSize) {
            return moment(date).add(tickSize);
        },
        dateCheck: momentOrThrow,
        durationCheck: durationOrThrow
    };
    return _.extend(new StubTimeoutsAndIntervals(), new StubClockwork(fns, current, tickSize, implicitTickFlag), momentConversions);
};

exports.StubDateClock = function (current, tickSize, implicitTickFlag) {
    var fns = {
        dateFn: function (millis) {
            return new Date(millis);
        },
        durationFn: function (ms) {
            return ms;
        },
        incrementBy: function (date, tickSize) {
            return new Date(date.getTime() + tickSize);
        },
        dateCheck: dateOrThrow,
        durationCheck: numberOfMillisOrThrow
    };
    return _.extend(new StubTimeoutsAndIntervals(), new StubClockwork(fns, current, tickSize, implicitTickFlag), new StubTimeoutsAndIntervals(), dateConversions);
};
<commit_msg>refactoring clock<commit_after>'use strict';

var moment = require('moment'), _ = require('lodash'), util = require('./util');

var durationOrThrow = _.partialRight(util.ensure, 'duration', moment.isDuration);
var momentOrThrow = _.partialRight(util.ensure, 'moment', moment.isMoment, function (value) {
    return value.clone();
});
var dateOrThrow = _.partialRight(util.ensure, 'date', _.isDate);
var numberOfMillisOrThrow = _.partialRight(util.ensure, 'number of milliseconds', _.isNumber);

var dateConversions = {
    numberOfMillisecondsAsDuration: function (durationInMillis) {
        return durationInMillis;
    }
};

var momentConversions = {
    numberOfMillisecondsAsDuration: function (durationInMillis) {
        return moment.duration(durationInMillis);
    }
};

var dateClockwork = {
    now: function () {
        return new Date();
    }
};

var momentClockwork = {
    now: function () {
        return moment();
    }
};

function TimeoutsAndIntervals(durationToMs) {
    return {
        setTimeout: function (callback, timeout) {
            return setTimeout(callback, durationToMs(timeout));
        },
        clearTimeout: function (id) {
            return clearTimeout(id);
        },
        setInterval: function (callback, interval) {
            return setInterval(callback, durationToMs(interval));
        },
        clearInterval: function (id) {
            return clearInterval(id);
        }
    };
}

function StubTimeoutsAndIntervals() {
    var intervals = {};
    var timeouts = {};

    return {
        setTimeout: function (callback) {
            var id = util.createGuid();
            timeouts[id] = callback;
            return id;
        },
        clearTimeout: function (id) {
            delete timeouts[id];
            return id;
        },
        setInterval: function (callback) {
            var id = util.createGuid();
            intervals[id] = callback;
            return id;
        },
        clearInterval: function (id) {
            delete intervals[id];
            return id;
        },
        triggerAll: function () {
            var ids = _.keys(timeouts).concat(_.keys(intervals));
            _.map(timeouts, function (timeout, id) {
                timeout();
                delete timeouts[id];
                return id;
            });
            _.each(intervals, function (interval) {
                interval();
            });
            return ids;
        }
    };
}

var StubClockwork = function (fns, current, tickSize, implicitTickFlag) {
    var current = current ? fns.dateCheck(current) : fns.dateFn(0);
    var tickSize = tickSize ? fns.durationCheck(tickSize) : fns.durationFn(1000);
    var implicitTickFlag = implicitTickFlag === undefined ? false : implicitTickFlag;

    return {
        now: function () {
            if (arguments.length > 0) {
                current = fns.dateCheck(arguments[0]);
            } else if (implicitTickFlag) {
                current = fns.incrementBy(current, tickSize);
            }
            return fns.dateFn(current);
        },
        tick: function (duration) {
            current = fns.incrementBy(current, duration ? fns.durationCheck(arguments[0]) : tickSize);
            return fns.dateFn(current);
        },
        tickSize: function (duration) {
            if (duration) {
                tickSize = fns.durationCheck(duration);
            }
            return tickSize;
        },
        implicitTick: function () {
            if (arguments.length > 0) {
                implicitTickFlag = arguments[0];
            }
            return implicitTickFlag;
        }
    };
};

exports.DateClock = function () {
    return _.extend(new TimeoutsAndIntervals(numberOfMillisOrThrow), dateClockwork, dateConversions);
};

exports.MomentClock = function () {
    return _.extend(new TimeoutsAndIntervals(function (duration) {
        return durationOrThrow(duration).asMilliseconds();
    }), momentClockwork, momentConversions);
};

exports.StubDateClock = function (current, tickSize, implicitTickFlag) {
    var fns = {
        dateFn: function (millis) {
            return new Date(millis);
        },
        durationFn: function (ms) {
            return ms;
        },
        incrementBy: function (date, tickSize) {
            return new Date(date.getTime() + tickSize);
        },
        dateCheck: dateOrThrow,
        durationCheck: numberOfMillisOrThrow
    };
    return _.extend(new StubTimeoutsAndIntervals(), new StubClockwork(fns, current, tickSize, implicitTickFlag), dateConversions);
};

exports.StubMomentClock = function (current, tickSize, implicitTickFlag) {
    var fns = {
        dateFn: moment,
        durationFn: function (ms) {
            return moment.duration(ms, 'milliseconds');
        },
        incrementBy: function (date, tickSize) {
            return moment(date).add(tickSize);
        },
        dateCheck: momentOrThrow,
        durationCheck: durationOrThrow
    };
    return _.extend(new StubTimeoutsAndIntervals(), new StubClockwork(fns, current, tickSize, implicitTickFlag), momentConversions);
};

exports.StubMomentClock = function (current, tickSize, implicitTickFlag) {
    var fns = {
        dateFn: moment,
        durationFn: function (ms) {
            return moment.duration(ms, 'milliseconds');
        },
        incrementBy: function (date, tickSize) {
            return moment(date).add(tickSize);
        },
        dateCheck: momentOrThrow,
        durationCheck: durationOrThrow
    };
    return _.extend(new StubTimeoutsAndIntervals(), new StubClockwork(fns, current, tickSize, implicitTickFlag), momentConversions);
};

<|endoftext|>


<commit_before>ManageIQ.angular.app.controller('ansibleCredentialsFormController', ['$window', 'credentialId', 'miqService', 'API', function($window, credentialId,  miqService, API) {
  var vm = this;

  var init = function() {
    vm.credentialModel = {
      id: null,
      name: '',
      type: '',
    };

    vm.credential_options = {};
    vm.select_options = [];

    vm.newRecord = credentialId === 'new';
    vm.afterGet = false;
    vm.model = 'credentialModel';
    ManageIQ.angular.scope = vm;
    vm.saveable = miqService.saveable;

    miqService.sparkleOn();

    // get credential specific options for all supported credential types
    API.options('/api/authentications')
      .then(getCredentialOptions)
      .catch(miqService.handleFailure);

    if (credentialId !== 'new') {
      API.get('/api/authentications/' + credentialId)
        .then(getCredentialFormData)
        .catch(miqService.handleFailure);
    } else {
      vm.select_options.push({'label':__('<Choose>'), 'value': ''});
      // FIXME: this should go away once https://github.com/ManageIQ/manageiq/pull/14483 is merged
      vm.credentialModel.organization = 1; // work-around, organization id needs to be filled in automatically by the backend

      // credential creation requires manager_resource
      API.get('/api/providers?collection_class=ManageIQ::Providers::EmbeddedAutomationManager')
        .then(setManagerResource)
        .catch(miqService.handleFailure);

      vm.afterGet = true;
      vm.modelCopy = angular.copy( vm.credentialModel );
      miqService.sparkleOff();
    }
  };

  vm.cancelClicked = function(angularForm) {
    if (credentialId === 'new') {
      getBack(__("Creation of new Credential was canceled by the user."), true);
    } else {
      getBack(sprintf(__("Edit of Credential \"%s\" was canceled by the user."), vm.credentialModel.name), true);
    }
  };

  vm.resetClicked = function(angularForm) {
    vm.credentialModel = angular.copy( vm.modelCopy );
    angularForm.$setPristine(true);
    miqService.miqFlash("warn", __("All changes have been reset"));
  };

  vm.saveClicked = function(angularForm) {
    API.put('/api/authentications/' + credentialId, vm.credentialModel)
       .then(getBack(sprintf(__("Modification of Credential \"%s\" has been successfully queued."), vm.credentialModel.name), false))
       .catch(miqService.handleFailure);
  };

  vm.addClicked = function(angularForm) {
    addCredentialKind();
    API.post('/api/authentications/', vm.credentialModel)
       .then(getBack(sprintf(__("Add of Credential \"%s\" has been successfully queued."), vm.credentialModel.name)))
       .catch(miqService.handleFailure);
  };

  function getCredentialOptions(response) {
    Object.assign(vm.credential_options, response.data.credential_types.embedded_ansible_credential_types);

    for (var opt in vm.credential_options) {
      vm.select_options.push({'value': opt, 'label': vm.credential_options[opt].label});
    }
  }

  function getCredentialFormData(response) {
    vm.credentialModel.id = response.id;
    vm.credentialModel.name = response.name;
    vm.credentialModel.type = response.type;

    // we need to merge options and vm.credentialModel
    for (var opt in response.options) {
      var item = vm.credential_options[vm.credentialModel.type]['attributes'][opt];

      // void the password fields first
      if (item.hasOwnProperty('type') && item['type'] === 'password') {
        vm.credentialModel[opt] = '';
      } else {
        vm.credentialModel[opt] = response.options[opt];
      }
    }

    vm.modelCopy = angular.copy( vm.credentialModel );
    vm.afterGet = true;
    miqService.sparkleOff();
  }

  function getBack(message, warning, error) {
    var url = '/ansible_credential/show_list' + '?flash_msg=' + message + '&escape=true';

    if (warning) {
      url += '&flash_warning=true&flash_error=false';
    } else if (error) {
      url += '&flash_warning=false&flash_error=true';
    }

    $window.location.href = url;
  }

  function setManagerResource(response) {
    vm.credentialModel.manager_resource = { "href": response.resources[0].href };
  }

  // FIXME: this should go away once https://github.com/ManageIQ/manageiq/pull/14483 is merged
  // For creation, we need to send json like: {"kind": "scm", "type": "ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ScmCredential"}
  function addCredentialKind() {
    vm.credentialModel.kind = vm.credential_options[vm.credentialModel.type].type;
  }

  init();
}]);
<commit_msg>set afterGet after the OPTIONS data is actually retrieved<commit_after>ManageIQ.angular.app.controller('ansibleCredentialsFormController', ['$window', 'credentialId', 'miqService', 'API', function($window, credentialId,  miqService, API) {
  var vm = this;

  var init = function() {
    vm.credentialModel = {
      id: null,
      name: '',
      type: '',
    };

    vm.credential_options = {};
    vm.select_options = [];

    vm.newRecord = credentialId === 'new';
    vm.afterGet = false;
    vm.model = 'credentialModel';
    ManageIQ.angular.scope = vm;
    vm.saveable = miqService.saveable;

    miqService.sparkleOn();

    // get credential specific options for all supported credential types
    API.options('/api/authentications')
      .then(getCredentialOptions)
      .catch(miqService.handleFailure);

    if (credentialId !== 'new') {
      API.get('/api/authentications/' + credentialId)
        .then(getCredentialFormData)
        .catch(miqService.handleFailure);
    } else {
      vm.select_options.push({'label':__('<Choose>'), 'value': ''});
      // FIXME: this should go away once https://github.com/ManageIQ/manageiq/pull/14483 is merged
      vm.credentialModel.organization = 1; // work-around, organization id needs to be filled in automatically by the backend

      // credential creation requires manager_resource
      API.get('/api/providers?collection_class=ManageIQ::Providers::EmbeddedAutomationManager')
        .then(setManagerResource)
        .catch(miqService.handleFailure);

      vm.modelCopy = angular.copy( vm.credentialModel );
      miqService.sparkleOff();
    }
  };

  vm.cancelClicked = function(angularForm) {
    if (credentialId === 'new') {
      getBack(__("Creation of new Credential was canceled by the user."), true);
    } else {
      getBack(sprintf(__("Edit of Credential \"%s\" was canceled by the user."), vm.credentialModel.name), true);
    }
  };

  vm.resetClicked = function(angularForm) {
    vm.credentialModel = angular.copy( vm.modelCopy );
    angularForm.$setPristine(true);
    miqService.miqFlash("warn", __("All changes have been reset"));
  };

  vm.saveClicked = function(angularForm) {
    API.put('/api/authentications/' + credentialId, vm.credentialModel)
       .then(getBack(sprintf(__("Modification of Credential \"%s\" has been successfully queued."), vm.credentialModel.name), false))
       .catch(miqService.handleFailure);
  };

  vm.addClicked = function(angularForm) {
    addCredentialKind();
    API.post('/api/authentications/', vm.credentialModel)
       .then(getBack(sprintf(__("Add of Credential \"%s\" has been successfully queued."), vm.credentialModel.name)))
       .catch(miqService.handleFailure);
  };

  function getCredentialOptions(response) {
    Object.assign(vm.credential_options, response.data.credential_types.embedded_ansible_credential_types);

    for (var opt in vm.credential_options) {
      vm.select_options.push({'value': opt, 'label': vm.credential_options[opt].label});
    }
    vm.afterGet = true;
  }

  function getCredentialFormData(response) {
    vm.credentialModel.id = response.id;
    vm.credentialModel.name = response.name;
    vm.credentialModel.type = response.type;

    // we need to merge options and vm.credentialModel
    for (var opt in response.options) {
      var item = vm.credential_options[vm.credentialModel.type]['attributes'][opt];

      // void the password fields first
      if (item.hasOwnProperty('type') && item['type'] === 'password') {
        vm.credentialModel[opt] = '';
      } else {
        vm.credentialModel[opt] = response.options[opt];
      }
    }

    vm.modelCopy = angular.copy( vm.credentialModel );
    vm.afterGet = true;
    miqService.sparkleOff();
  }

  function getBack(message, warning, error) {
    var url = '/ansible_credential/show_list' + '?flash_msg=' + message + '&escape=true';

    if (warning) {
      url += '&flash_warning=true&flash_error=false';
    } else if (error) {
      url += '&flash_warning=false&flash_error=true';
    }

    $window.location.href = url;
  }

  function setManagerResource(response) {
    vm.credentialModel.manager_resource = { "href": response.resources[0].href };
  }

  // FIXME: this should go away once https://github.com/ManageIQ/manageiq/pull/14483 is merged
  // For creation, we need to send json like: {"kind": "scm", "type": "ManageIQ::Providers::EmbeddedAnsible::AutomationManager::ScmCredential"}
  function addCredentialKind() {
    vm.credentialModel.kind = vm.credential_options[vm.credentialModel.type].type;
  }

  init();
}]);
<|endoftext|>


<commit_before>var global = require('../../global');

module.exports = function (data, offset) {
    var header = [
        {
            text: 'PT. DAN LIRIS',
            style: ['size08', 'bold']
        },
        {
            stack: [
                'Head Office   : ',
                'Kelurahan Banaran, Kecamatan Grogol',
                'Sukoharjo 57193 - INDONESIA',
                'PO.BOX 166 Solo 57100',
                'Telp. (0271) 740888, 714400',
                'Fax. (0271) 735222, 740777'
            ],
            style: ['size07', 'bold']
        },
        {
            alignment: "center",
            text: 'NOTA KOREKSI',
            style: ['size09', 'bold']
        },
        '\n'
    ];

    var locale = global.config.locale;
    var moment = require('moment');
    moment.locale(locale.name);

    var subHeader = [
        {
            columns: [{
                width: '15%',
                text: 'No. Nota Koreksi',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.no,
                style: ['size08']
            },
            {
                width: '15%',
                text: 'Tanggal',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: `${moment(data.date).add(offset, 'h').format("DD MMM YYYY")}`,
                style: ['size08']
            }]
        },
        {
            columns: [{
                width: '15%',
                text: 'Kode Supplier',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.deliveryOrder.supplier.code,
                style: ['size08']
            },
            {
                width: '15%',
                text: 'No. Surat Jalan',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.deliveryOrder.no,
                style: ['size08']
            }]
        },
        {
            columns: [{
                width: '15%',
                text: 'Nama Supplier',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.deliveryOrder.supplier.name,
                style: ['size08']
            },
            {
                width: '15%',
                text: 'Tanggal Surat Jalan',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: `${moment(data.deliveryOrder.supplierDoDate).add(offset, 'h').format("DD MMM YYYY")}`,
                style: ['size08']
            }]
        }
    ];

    var thead = [{
        text: 'Plan PO',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Artikel',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Kode Barang',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Nama Barang',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Jumlah SJ',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Satuan',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Harga Satuan',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Jumlah Koreksi',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Harga/Satuan (Koreksi)',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Total Harga',
        style: ['size08', 'bold', 'center']
    }];

    var units = [];
    var totalAmount = 0;

    var tbody = data.items.map(function (item, index) {
        var doItem = data.deliveryOrder.items.find(i => i.purchaseOrderExternalId.toString() === item.purchaseOrderExternalId.toString());
        var fulfillment = doItem.fulfillments.find(fulfillment => fulfillment.purchaseOrderId.toString() === item.purchaseOrderInternalId.toString() && fulfillment.purchaseRequestId.toString() === item.purchaseRequestId.toString() && fulfillment.productId.toString() === item.productId.toString());

        fulfillment.corrections = fulfillment.corrections || [];

        var pricePerUnit = 0,
            priceTotal = 0;

        if(fulfillment.corrections.length > 0) {
            pricePerUnit = item.pricePerUnit - fulfillment.corrections[fulfillment.corrections.length - 1].correctionPricePerUnit;
            priceTotal = item.priceTotal - fulfillment.corrections[fulfillment.corrections.length - 1].correctionPriceTotal;
        }
        else {
            pricePerUnit = item.pricePerUnit - fulfillment.pricePerDealUnit;
            priceTotal = item.priceTotal - (fulfillment.pricePerDealUnit * fulfillment.quantity);
        }

        if(data.correctionType === "Harga Total") {
            pricePerUnit = "-";
        }

        if(item.purchaseOrderInternal) {
            var po = item.purchaseOrderInternal;
            var unit = units.find(u => u.code === po.unit.code);

            if(!unit) {
                units.push({
                    code: po.unit.code,
                    total: data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity) : priceTotal
                });
            }
            else {
                unit.total = unit.total + (data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity) : priceTotal);
            }
        }

        totalAmount = totalAmount + (data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity) : priceTotal);

        item.purchaseOrderInternal = item.purchaseOrderInternal || {};

        return [{
            text: item.purchaseOrderInternal.refNo,
            style: ['size08', 'left']
        }, {
            text: item.purchaseOrderInternal.artikel,
            style: ['size08', 'left']
        }, {
            text: item.product.code,
            style: ['size08', 'left']
        }, {
            text: item.product.name,
            style: ['size08', 'left']
        }, {
            text: fulfillment.deliveredQuantity,
            style: ['size08', 'right']
        }, {
            text: item.uom.unit,
            style: ['size08', 'left']
        }, {
            text: fulfillment.pricePerDealUnit.toFixed(4),
            style: ['size08', 'right']
        }, {
            text: "-",
            style: ['size08', 'right']
        }, {
            text: pricePerUnit === "-" ? pricePerUnit : pricePerUnit.toFixed(4),
            style: ['size08', 'right']
        }, {
            text: data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity).toFixed(4) : priceTotal.toFixed(4),
            style: ['size08', 'right']
        }];
    });

    var poUnits = [];

    var totalHargaPokok = (totalAmount * data.deliveryOrder.items[0].fulfillments[0].currency.rate).toFixed(4);
    var totalCols = [{
        columns: [{
            width: '15%',
            text: "Total Amount",
            style: ['size08']
        }, {
            width: '2%',
            text: ':',
            style: ['size08']
        }, {
            width: '33%',
            text: totalAmount  < 0 ? "(" + Math.abs(totalAmount).toFixed(4) + ")" : totalAmount.toFixed(4),
            style: ['size08']
        }]
    }, {
        columns: [{
            width: '15%',
            text: "Mata Uang",
            style: ['size08']
        }, {
            width: '2%',
            text: ':',
            style: ['size08']
        }, {
            width: '33%',
            text: data.deliveryOrder.items[0].fulfillments[0].currency.code,
            style: ['size08']
        }]
    }, {
        columns: [{
            width: '15%',
            text: "Total Harga Pokok (Rp)",
            style: ['size08']
        }, {
            width: '2%',
            text: ':',
            style: ['size08']
        }, {
            width: '33%',
            text: totalHargaPokok < 0 ? "(" + Math.abs(totalHargaPokok).toFixed(4) + ")" : totalHargaPokok,
            style: ['size08']
        }]
    }];

    for(var unit of units) {
        var obj = {
            columns: [{
                width: '15%',
                text: "Total " + unit.code,
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: unit.total < 0 ? "(" + Math.abs(unit.total).toFixed(4) + ")" : unit.total.toFixed(4),
                style: ['size08']
            },]
        };

        poUnits.push(obj);
    }

    for(var i = 0; i < totalCols.length; i++) {
        if(poUnits[i]) {
            poUnits[i].columns.push(totalCols[i].columns[0]);
            poUnits[i].columns.push(totalCols[i].columns[1]);
            poUnits[i].columns.push(totalCols[i].columns[2]);
        }
        else {
            var obj = {
                columns: [{
                    width: '15%',
                    text: "",
                    style: ['size08']
                }, {
                    width: '2%',
                    text: '',
                    style: ['size08']
                }, {
                    width: '33%',
                    text: "",
                    style: ['size08']
                }, totalCols[i].columns[0], totalCols[i].columns[1], totalCols[i].columns[2]]
            };
            poUnits.push(obj);
        }
    }

    if(poUnits.length)
    poUnits.push(totalCols);

    var table = ['\n', {
        table: {
            headerRows: 1,
            body: [].concat([thead], tbody)
        }
    }];

    var footer = ['\n\n\n', {
        table: {
            widths: ['33%', '34%', '33%'],
            body: [
                [
                    {
                        text: 'Administrasi',
                        style: ['size08', 'bold', 'center']
                    }, {
                        text: 'Staff Pembelian',
                        style: ['size08', 'bold', 'center']
                    }, {
                        text: 'Verifikasi',
                        style: ['size08', 'bold', 'center']
                    }
                ],
                [
                    {
                        stack: ['\n\n\n\n',
                            {
                                text: '(Nama & Tanggal)',
                                style: ['size08', 'center']
                            }
                        ]
                    }, {
                        stack: ['\n\n\n\n',
                            {
                                text: '(Nama & Tanggal)',
                                style: ['size08', 'center']
                            }
                        ]
                    }, {
                        stack: ['\n\n\n\n',
                            {
                                text: '(Nama & Tanggal)',
                                style: ['size08', 'center']
                            }
                        ]
                    }
                ]
            ],
            style: ['center']
        }
    }];

    var purchasePriceCorrectionPDFDefinition = {
        pageSize: 'A4',
        pageOrientation: 'portrait',
        pageMargins: 10,
        content: [].concat(header, subHeader, table, ['\n'], poUnits, footer),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            }
        }
    };

    return purchasePriceCorrectionPDFDefinition;
}<commit_msg>[Purchase Price Correction PDF] Support Multiple Purchase Order External<commit_after>var global = require('../../global');

module.exports = function (data, offset) {
    var header = [
        {
            text: 'PT. DAN LIRIS',
            style: ['size08', 'bold']
        },
        {
            stack: [
                'Head Office   : ',
                'Kelurahan Banaran, Kecamatan Grogol',
                'Sukoharjo 57193 - INDONESIA',
                'PO.BOX 166 Solo 57100',
                'Telp. (0271) 740888, 714400',
                'Fax. (0271) 735222, 740777'
            ],
            style: ['size07', 'bold']
        },
        {
            alignment: "center",
            text: 'NOTA KOREKSI',
            style: ['size09', 'bold']
        },
        '\n'
    ];

    var locale = global.config.locale;
    var moment = require('moment');
    moment.locale(locale.name);

    var subHeader = [
        {
            columns: [{
                width: '15%',
                text: 'No. Nota Koreksi',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.no,
                style: ['size08']
            },
            {
                width: '15%',
                text: 'Tanggal',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: `${moment(data.date).add(offset, 'h').format("DD MMM YYYY")}`,
                style: ['size08']
            }]
        },
        {
            columns: [{
                width: '15%',
                text: 'Kode Supplier',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.deliveryOrder.supplier.code,
                style: ['size08']
            },
            {
                width: '15%',
                text: 'No. Surat Jalan',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.deliveryOrder.no,
                style: ['size08']
            }]
        },
        {
            columns: [{
                width: '15%',
                text: 'Nama Supplier',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: data.deliveryOrder.supplier.name,
                style: ['size08']
            },
            {
                width: '15%',
                text: 'Tanggal Surat Jalan',
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: `${moment(data.deliveryOrder.supplierDoDate).add(offset, 'h').format("DD MMM YYYY")}`,
                style: ['size08']
            }]
        }
    ];

    var thead = [{
        text: 'Plan PO',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Artikel',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Kode Barang',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Nama Barang',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Jumlah SJ',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Satuan',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Harga Satuan',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Jumlah Koreksi',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Harga/Satuan (Koreksi)',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'Total Harga',
        style: ['size08', 'bold', 'center']
    }];

    var units = [];
    var totalAmount = 0;

    var tbody = data.items.map(function (item, index) {
        let doItems = data.deliveryOrder.items.filter(i => i.purchaseOrderExternalId.toString() === item.purchaseOrderExternalId.toString());
        let fulfillment;

        for (let doItem of doItems) {
            fulfillment = doItem.fulfillments.find(p => p.purchaseOrderId.toString() === item.purchaseOrderInternalId.toString() && p.purchaseRequestId.toString() === item.purchaseRequestId.toString() && p.productId.toString() === item.productId.toString());

            if (fulfillment)
                break;
        }

        fulfillment.corrections = fulfillment.corrections || [];

        var pricePerUnit = 0,
            priceTotal = 0;

        if(fulfillment.corrections.length > 0) {
            pricePerUnit = item.pricePerUnit - fulfillment.corrections[fulfillment.corrections.length - 1].correctionPricePerUnit;
            priceTotal = item.priceTotal - fulfillment.corrections[fulfillment.corrections.length - 1].correctionPriceTotal;
        }
        else {
            pricePerUnit = item.pricePerUnit - fulfillment.pricePerDealUnit;
            priceTotal = item.priceTotal - (fulfillment.pricePerDealUnit * fulfillment.quantity);
        }

        if(data.correctionType === "Harga Total") {
            pricePerUnit = "-";
        }

        if(item.purchaseOrderInternal) {
            var po = item.purchaseOrderInternal;
            var unit = units.find(u => u.code === po.unit.code);

            if(!unit) {
                units.push({
                    code: po.unit.code,
                    total: data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity) : priceTotal
                });
            }
            else {
                unit.total = unit.total + (data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity) : priceTotal);
            }
        }

        totalAmount = totalAmount + (data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity) : priceTotal);

        item.purchaseOrderInternal = item.purchaseOrderInternal || {};

        return [{
            text: item.purchaseOrderInternal.refNo,
            style: ['size08', 'left']
        }, {
            text: item.purchaseOrderInternal.artikel,
            style: ['size08', 'left']
        }, {
            text: item.product.code,
            style: ['size08', 'left']
        }, {
            text: item.product.name,
            style: ['size08', 'left']
        }, {
            text: fulfillment.deliveredQuantity,
            style: ['size08', 'right']
        }, {
            text: item.uom.unit,
            style: ['size08', 'left']
        }, {
            text: fulfillment.pricePerDealUnit.toFixed(4),
            style: ['size08', 'right']
        }, {
            text: "-",
            style: ['size08', 'right']
        }, {
            text: pricePerUnit === "-" ? pricePerUnit : pricePerUnit.toFixed(4),
            style: ['size08', 'right']
        }, {
            text: data.correctionType != "Harga Total" ? (pricePerUnit * item.quantity).toFixed(4) : priceTotal.toFixed(4),
            style: ['size08', 'right']
        }];
    });

    var poUnits = [];

    var totalHargaPokok = (totalAmount * data.deliveryOrder.items[0].fulfillments[0].currency.rate).toFixed(4);
    var totalCols = [{
        columns: [{
            width: '15%',
            text: "Total Amount",
            style: ['size08']
        }, {
            width: '2%',
            text: ':',
            style: ['size08']
        }, {
            width: '33%',
            text: totalAmount  < 0 ? "(" + Math.abs(totalAmount).toFixed(4) + ")" : totalAmount.toFixed(4),
            style: ['size08']
        }]
    }, {
        columns: [{
            width: '15%',
            text: "Mata Uang",
            style: ['size08']
        }, {
            width: '2%',
            text: ':',
            style: ['size08']
        }, {
            width: '33%',
            text: data.deliveryOrder.items[0].fulfillments[0].currency.code,
            style: ['size08']
        }]
    }, {
        columns: [{
            width: '15%',
            text: "Total Harga Pokok (Rp)",
            style: ['size08']
        }, {
            width: '2%',
            text: ':',
            style: ['size08']
        }, {
            width: '33%',
            text: totalHargaPokok < 0 ? "(" + Math.abs(totalHargaPokok).toFixed(4) + ")" : totalHargaPokok,
            style: ['size08']
        }]
    }];

    for(var unit of units) {
        var obj = {
            columns: [{
                width: '15%',
                text: "Total " + unit.code,
                style: ['size08']
            }, {
                width: '2%',
                text: ':',
                style: ['size08']
            }, {
                width: '33%',
                text: unit.total < 0 ? "(" + Math.abs(unit.total).toFixed(4) + ")" : unit.total.toFixed(4),
                style: ['size08']
            },]
        };

        poUnits.push(obj);
    }

    for(var i = 0; i < totalCols.length; i++) {
        if(poUnits[i]) {
            poUnits[i].columns.push(totalCols[i].columns[0]);
            poUnits[i].columns.push(totalCols[i].columns[1]);
            poUnits[i].columns.push(totalCols[i].columns[2]);
        }
        else {
            var obj = {
                columns: [{
                    width: '15%',
                    text: "",
                    style: ['size08']
                }, {
                    width: '2%',
                    text: '',
                    style: ['size08']
                }, {
                    width: '33%',
                    text: "",
                    style: ['size08']
                }, totalCols[i].columns[0], totalCols[i].columns[1], totalCols[i].columns[2]]
            };
            poUnits.push(obj);
        }
    }

    if(poUnits.length)
    poUnits.push(totalCols);

    var table = ['\n', {
        table: {
            headerRows: 1,
            body: [].concat([thead], tbody)
        }
    }];

    var footer = ['\n\n\n', {
        table: {
            widths: ['33%', '34%', '33%'],
            body: [
                [
                    {
                        text: 'Administrasi',
                        style: ['size08', 'bold', 'center']
                    }, {
                        text: 'Staff Pembelian',
                        style: ['size08', 'bold', 'center']
                    }, {
                        text: 'Verifikasi',
                        style: ['size08', 'bold', 'center']
                    }
                ],
                [
                    {
                        stack: ['\n\n\n\n',
                            {
                                text: '(Nama & Tanggal)',
                                style: ['size08', 'center']
                            }
                        ]
                    }, {
                        stack: ['\n\n\n\n',
                            {
                                text: '(Nama & Tanggal)',
                                style: ['size08', 'center']
                            }
                        ]
                    }, {
                        stack: ['\n\n\n\n',
                            {
                                text: '(Nama & Tanggal)',
                                style: ['size08', 'center']
                            }
                        ]
                    }
                ]
            ],
            style: ['center']
        }
    }];

    var purchasePriceCorrectionPDFDefinition = {
        pageSize: 'A4',
        pageOrientation: 'portrait',
        pageMargins: 10,
        content: [].concat(header, subHeader, table, ['\n'], poUnits, footer),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            }
        }
    };

    return purchasePriceCorrectionPDFDefinition;
}<|endoftext|>


<commit_before>import actions from '../../../data/actions';

export default ({ text }) => ({
    text,
    quick_replies: process.env.NODE_ENV === 'dev' ? actions : [],
});
<commit_msg>Properly add quick replies if in dev mode.<commit_after>import actions from '../../../data/actions';

export default ({ text }) => {
    const message = { text };
    if (process.env.NODE_ENV === 'dev') message.quick_replies = actions;

    return message;
};
<|endoftext|>


<commit_before>/**!
 * Social Private Sharing for Greenpeace Action Template v0.3
 *
 * @name            p3.social_sharing.js
 * @fileOverview    Enables social sharing without compromising privacy,
 *                  Obtains share counts from JSON endpoint
 * @copyright       Copyright 2013, Greenpeace International
 * @license         MIT License (opensource.org/licenses/MIT)
 * @version         0.1.6
 * @author          Ray Walker <hello@raywalker.it>
 * @requires        jQuery 1.6+,
 *                  Modernizr,
 * @example         $.p3.social_sharing('#action-social-share'[, options]);
 */
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, devel:true, jquery:true, indent:4, maxerr:50 */
/*global jQuery, Modernizr */

(function($, M, w) {
    'use strict';

    var _p3 = $.p3 || {},
        prefix = ' :: $.p3.social_sharing :: ',
        defaults = {
            pageURL: false,
            popup: {
                top: 200,
                left: 100,
                width: 550,
                height: 350
            },
            networks: {
                facebook: {
                    enabled: true,
                    url: 'http://www.facebook.com/sharer.php?u=__REFERRER__',
                    count: 0
                },
                twitter: {
                    enabled: true,
                    url: 'https://twitter.com/intent/tweet?original_referer=__REFERRER__&source=tweetbutton&text=__TITLE__&url=__REFERRER__&via=__ACCOUNT__',
                    count: 0,
                    title: false,
                    account: 'greenpeace'
                },
                google: {
                    enabled: true,
                    url: 'https://plus.google.com/share?url=__REFERRER__',
                    count: 0
                },
                linkedin: {
                    enabled: true,
                    url: 'https://www.linkedin.com/cws/share?url=__REFERRER__&original_referer=__REFERRER__',
                    count: 0
                },
                pinterest: {
                    enabled: true,
                    url: 'http://pinterest.com/pin/create/button/?url=__REFERRER__&media=__IMAGE__&description=__DESCRIPTION__',
                    count: 0,
                    image: false,
                    description: false
                }
            },
            precision: 1,
            jsonURL: 'https://www.greenpeace.org/api/p3/pledge/social.json'
        };

    _p3.social_sharing = function(el, options) {

        var config  = $.extend(true, defaults, options || {}),
            $el     = $(el);

        function addCommas(int) {
            var nStr = int + '',
                x = nStr.split('.'),
                x1 = x[0],
                x2 = (x.length > 1 && (x[1] * 1.0) > 0 && int < 100) ? '.' + x[1].replace(/0+$/, "") : '',
                rgx = /(\d+)(\d{3})/;
            while (rgx.test(x1)) {
                x1 = x1.replace(rgx, '$1' + ',' + '$2');
            }
            return x1 + x2;
        }

        function humanise(int) {

            int = int * 1.0;

            // Smaller than 10k doesn't overflow container
            if (int < 10000) {
                return addCommas(int);
            }

            var ordinals = ["", "K", "M", "G", "T", "P", "E"],
                n = int,
                ord = 0;

            while (n > 1000) {
                n /= 1000;
                ord++;
            }

            return addCommas((n.toFixed(config.precision)) * 1.0) + ordinals[ord];
        }

        function init() {

            if (config.pageURL === false) {
                console.warn(prefix + 'page referrer URL is not set, using "' + w.location.href + '"');
                config.pageURL = w.location.href;
            }

            $.each(config.networks, function(network, data) {
                if (data.enabled !== false) {
                    var $a = $('a.' + network, $el),
                        $counter = $('span', $a.prev()),
                        url = data.url;

                    switch (network) {
                        case 'pinterest':
                            if (data.image === false) {
//                            throw new Error('Pinterest sharing requires an image');
                                console.warn(prefix + 'Pinterest sharing requires an image.');
                                data.image = '';
                            }
                            if (data.description === false) {
//                                throw new Error('Pinterest sharing requires a description');
                                console.warn(prefix + 'Pinterest sharing requires a description.');
                                data.description = '';
                            }
                            url = url.replace('__IMAGE__', encodeURIComponent(data.image));
                            url = url.replace('__DESCRIPTION__', encodeURIComponent(data.description));
                            break;
                        case 'twitter':
                            if (data.title === false) {
//                                throw new Error('Twitter sharing requires a title');
                                console.warn(prefix + 'Twitter sharing requires a title.');
                                data.title = '';
                            }
                            url = url.replace('__TITLE__', encodeURIComponent(data.title));
                            url = url.replace('__ACCOUNT__', encodeURIComponent(data.account));
                            break;
                        default:
                            break;
                    }

                    url = url.replace(/__REFERRER__/g, encodeURIComponent(config.pageURL));

                    $a.attr({
                        href: url,
                        target: '_blank'
                    }).click(function(e) {

                        e.preventDefault();

                        w.open(url, 'Share this page', 'left=' + config.popup.left + ',top=' + config.popup.top + ',width=' + config.popup.width + ',height=' + config.popup.height + ',toolbar=0,resizable=1');

                    });

                    // Set counter to humanised number
                    $counter.text(humanise(data.count));
                } // else { console.log(network + ' disabled'); }
            });

        }

        M.load({
            test: w.JSON,
            nope: [
                'dist/js/compat/json.min.js'
            ],
            complete: function() {
                $.getJSON(config.jsonURL, function(json) {
                    $.extend(true, config, json);

                    if (json.status === 'success') {
                        init();
                    } else {
                        console.warn(json);
                        throw new Error(prefix + 'Status: ' + json.status + ': server reported a problem');
                    }

                }).fail(function() {
                    throw new Error(prefix + 'Failed to load JSON: "' + config.jsonURL + '"');
                });

            }
        });

    };

    $.p3 = _p3;

}(jQuery, Modernizr, this));
<commit_msg>p3.social_sharing.js - 0.2.0 - Social sharing no longer requires an API endpoint - set config.api = false when initiating<commit_after>/**!
 * Social Private Sharing for Greenpeace Action Template v0.3
 *
 * @name            p3.social_sharing.js
 * @fileOverview    Enables social sharing without compromising privacy,
 *                  Obtains share counts from JSON endpoint
 * @copyright       Copyright 2013, Greenpeace International
 * @license         MIT License (opensource.org/licenses/MIT)
 * @version         0.2.0
 * @author          Ray Walker <hello@raywalker.it>
 * @requires        jQuery 1.6+,
 *                  Modernizr,
 * @example         $.p3.social_sharing('#action-social-share'[, options]);
 */
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, devel:true, jquery:true, indent:4, maxerr:50 */
/*global jQuery, Modernizr */

(function($, M, w) {
    'use strict';

    var _p3 = $.p3 || {},
        prefix = ' :: $.p3.social_sharing :: ',
        defaults = {
            pageURL: false,
            popup: {
                top: 200,
                left: 100,
                width: 650,
                height: 380
            },
            networks: {
                facebook: {
                    enabled: true,
                    url: 'http://www.facebook.com/sharer.php?u=__REFERRER__',
                    count: 0
                },
                twitter: {
                    enabled: true,
                    url: 'https://twitter.com/intent/tweet?original_referer=__REFERRER__&source=tweetbutton&text=__TITLE__&url=__REFERRER__&via=__ACCOUNT__',
                    count: 0,
                    title: false,
                    account: 'greenpeace'
                },
                google: {
                    enabled: true,
                    url: 'https://plus.google.com/share?url=__REFERRER__',
                    count: 0
                },
                linkedin: {
                    enabled: true,
                    url: 'https://www.linkedin.com/cws/share?url=__REFERRER__&original_referer=__REFERRER__',
                    count: 0
                },
                pinterest: {
                    enabled: true,
                    url: 'http://pinterest.com/pin/create/button/?url=__REFERRER__&media=__IMAGE__&description=__DESCRIPTION__',
                    count: 0,
                    image: false,
                    description: false
                }
            },
            precision: 1,
            api: 'https://www.greenpeace.org/api/p3/pledge/social.json'
        };

    _p3.social_sharing = function(el, options) {

        var config  = $.extend(true, defaults, options || {}),
            $el     = $(el);

        function addCommas(int) {
            var nStr = int + '',
                x = nStr.split('.'),
                x1 = x[0],
                x2 = (x.length > 1 && (x[1] * 1.0) > 0 && int < 100) ? '.' + x[1].replace(/0+$/, "") : '',
                rgx = /(\d+)(\d{3})/;
            while (rgx.test(x1)) {
                x1 = x1.replace(rgx, '$1' + ',' + '$2');
            }
            return x1 + x2;
        }

        function humanise(int) {

            int = int * 1.0;

            // Smaller than 10k doesn't overflow container
            if (int < 10000) {
                return addCommas(int);
            }

            var ordinals = ["", "K", "M", "G", "T", "P", "E"],
                n = int,
                ord = 0;

            while (n > 1000) {
                n /= 1000;
                ord++;
            }

            return addCommas((n.toFixed(config.precision)) * 1.0) + ordinals[ord];
        }

        function init() {

            if (config.pageURL === false) {
                console.warn(prefix + 'page referrer URL is not set, using "' + w.location.href + '"');
                config.pageURL = w.location.href;
            }

            $.each(config.networks, function(network, data) {
                if (data.enabled !== false) {
                    var $a = $('a.' + network, $el),
                        $counter = $('span', $a.prev()) || false,
                        url = data.url;

                    switch (network) {
                        case 'pinterest':
                            if (data.image === false) {
//                            throw new Error('Pinterest sharing requires an image');
                                console.warn(prefix + 'Pinterest sharing requires an image.');
                                data.image = '';
                            }
                            if (data.description === false) {
//                                throw new Error('Pinterest sharing requires a description');
                                console.warn(prefix + 'Pinterest sharing requires a description.');
                                data.description = document.title;
                            }
                            url = url.replace('__IMAGE__', encodeURIComponent(data.image));
                            url = url.replace('__DESCRIPTION__', encodeURIComponent(data.description));
                            break;
                        case 'twitter':
                            if (data.title === false) {
//                                throw new Error('Twitter sharing requires a title');
                                console.warn(prefix + 'Twitter sharing requires a title.');
                                data.title = document.title;
                            }
                            url = url.replace('__TITLE__', encodeURIComponent(data.title));
                            url = url.replace('__ACCOUNT__', encodeURIComponent(data.account));
                            break;
                        default:
                            break;
                    }

                    url = url.replace(/__REFERRER__/g, encodeURIComponent(config.pageURL));

                    $a.attr({
                        href: url,
                        target: '_blank'
                    }).click(function(e) {

                        e.preventDefault();

                        w.open(url, 'Share this page', 'left=' + config.popup.left + ',top=' + config.popup.top + ',width=' + config.popup.width + ',height=' + config.popup.height + ',toolbar=0,resizable=1');

                    });

                    // Set counter to humanised number
                    if ($counter) {
                        $counter.text(humanise(data.count));
                    }
                } // else { console.log(network + ' disabled'); }
            });

        }

        if (config.api) {
            // load data from JSON endpoint
            M.load({
                test: w.JSON,
                nope: [
                    'dist/js/compat/json.min.js'
                ],
                complete: function() {
                    $.getJSON(config.api, function(json) {
                        $.extend(true, config, json);

                        if (json.status === 'success') {
                            init();
                        } else {
                            console.warn(json);
                            throw new Error(prefix + 'Status: ' + json.status + ': server reported a problem');
                        }

                    }).fail(function() {
                        throw new Error(prefix + 'Failed to load JSON: "' + config.api + '"');
                    });

                }
            });
        } else {
            // Just parse what we've got
            init();
        }

    };

    $.p3 = _p3;

}(jQuery, Modernizr, this));
<|endoftext|>


<commit_before>// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Audits.StatusView = class {
  /**
   * @param {!Audits.AuditController} controller
   */
  constructor(controller) {
    this._controller = controller;

    this._statusView = null;
    this._statusHeader = null;
    this._progressWrapper = null;
    this._progressBar = null;
    this._statusText = null;

    this._inspectedURL = '';
    this._textChangedAt = 0;
    this._fastFactsQueued = Audits.StatusView.FastFacts.slice();
    this._currentPhase = null;
    this._scheduledTextChangeTimeout = null;
    this._scheduledFastFactTimeout = null;

    this._dialog = new UI.Dialog();
    this._dialog.setDimmed(true);
    this._dialog.setCloseOnEscape(false);
    this._dialog.setOutsideClickCallback(event => event.consume(true));
    this._render();
  }

  _render() {
    const dialogRoot = UI.createShadowRootWithCoreStyles(this._dialog.contentElement, 'audits/auditsDialog.css');
    const auditsViewElement = dialogRoot.createChild('div', 'audits-view vbox');

    const cancelButton = UI.createTextButton(ls`Cancel`, this._cancel.bind(this));
    const fragment = UI.Fragment.build`

Auditing your web page\u2026

        ${cancelButton}

    `;

    auditsViewElement.appendChild(fragment.element());
    auditsViewElement.tabIndex = 0;

    this._statusView = fragment.$('status-view');
    this._statusHeader = fragment.$('status-header');
    this._progressWrapper = fragment.$('progress-wrapper');
    this._progressBar = fragment.$('progress-bar');
    this._statusText = fragment.$('status-text');
    UI.ARIAUtils.markAsStatus(this._statusText);

    this._dialog.setDefaultFocusedElement(cancelButton);
    this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeight);
    this._dialog.setMaxContentSize(new UI.Size(500, 400));
  }

  _reset() {
    this._resetProgressBarClasses();
    clearTimeout(this._scheduledFastFactTimeout);

    this._textChangedAt = 0;
    this._fastFactsQueued = Audits.StatusView.FastFacts.slice();
    this._currentPhase = null;
    this._scheduledTextChangeTimeout = null;
    this._scheduledFastFactTimeout = null;
  }

  /**
   * @param {!Element} dialogRenderElement
   */
  show(dialogRenderElement) {
    this._reset();
    this.updateStatus(ls`Loading\u2026`);

    const parsedURL = this._inspectedURL.asParsedURL();
    const pageHost = parsedURL && parsedURL.host;
    const statusHeader = pageHost ? ls`Auditing ${pageHost}` : ls`Auditing your web page`;
    this._statusHeader.textContent = `${statusHeader}\u2026`;
    this._dialog.show(dialogRenderElement);
  }

  hide() {
    if (this._dialog.isShowing())
      this._dialog.hide();
  }

  /**
   * @param {string=} url
   */
  setInspectedURL(url = '') {
    this._inspectedURL = url;
  }

  /**
   * @param {?string} message
   */
  updateStatus(message) {
    if (!message || !this._statusText)
      return;

    if (message.startsWith('Cancel')) {
      this._commitTextChange(Common.UIString('Cancelling\u2026'));
      clearTimeout(this._scheduledFastFactTimeout);
      return;
    }

    const nextPhase = this._getPhaseForMessage(message);
    if (!nextPhase && !this._currentPhase) {
      this._commitTextChange(Common.UIString('Lighthouse is warming up\u2026'));
      clearTimeout(this._scheduledFastFactTimeout);
    } else if (nextPhase && (!this._currentPhase || this._currentPhase.order < nextPhase.order)) {
      this._currentPhase = nextPhase;
      this._scheduleTextChange(this._getMessageForPhase(nextPhase));
      this._scheduleFastFactCheck();
      this._resetProgressBarClasses();
      this._progressBar.classList.add(nextPhase.progressBarClass);
    }
  }

  _cancel() {
    this._controller.dispatchEventToListeners(Audits.Events.RequestAuditCancel);
  }

  /**
   * @param {!Audits.StatusView.StatusPhases} phase
   * @return {string}
   */
  _getMessageForPhase(phase) {
    if (phase.message)
      return Common.UIString(phase.message);

    const deviceType = Audits.RuntimeSettings.find(item => item.setting.name === 'audits.device_type').setting.get();
    const throttling = Audits.RuntimeSettings.find(item => item.setting.name === 'audits.throttling').setting.get();
    const match = Audits.StatusView.LoadingMessages.find(item => {
      return item.deviceType === deviceType && item.throttling === throttling;
    });

    return match ? ls`${match.message}` : ls`Lighthouse is loading your page`;
  }

  /**
   * @param {string} message
   * @return {?Audits.StatusView.StatusPhases}
   */
  _getPhaseForMessage(message) {
    return Audits.StatusView.StatusPhases.find(phase => message.startsWith(phase.statusMessagePrefix));
  }

  _resetProgressBarClasses() {
    if (!this._progressBar)
      return;

    this._progressBar.className = 'audits-progress-bar';
  }

  _scheduleFastFactCheck() {
    if (!this._currentPhase || this._scheduledFastFactTimeout)
      return;

    this._scheduledFastFactTimeout = setTimeout(() => {
      this._updateFastFactIfNecessary();
      this._scheduledFastFactTimeout = null;

      this._scheduleFastFactCheck();
    }, 100);
  }

  _updateFastFactIfNecessary() {
    const now = performance.now();
    if (now - this._textChangedAt < Audits.StatusView.fastFactRotationInterval)
      return;
    if (!this._fastFactsQueued.length)
      return;

    const fastFactIndex = Math.floor(Math.random() * this._fastFactsQueued.length);
    this._scheduleTextChange(ls`\ud83d\udca1 ${this._fastFactsQueued[fastFactIndex]}`);
    this._fastFactsQueued.splice(fastFactIndex, 1);
  }

  /**
   * @param {string} text
   */
  _commitTextChange(text) {
    if (!this._statusText)
      return;
    this._textChangedAt = performance.now();
    this._statusText.textContent = text;
  }

  /**
   * @param {string} text
   */
  _scheduleTextChange(text) {
    if (this._scheduledTextChangeTimeout)
      clearTimeout(this._scheduledTextChangeTimeout);

    const msSinceLastChange = performance.now() - this._textChangedAt;
    const msToTextChange = Audits.StatusView.minimumTextVisibilityDuration - msSinceLastChange;

    this._scheduledTextChangeTimeout = setTimeout(() => {
      this._commitTextChange(text);
    }, Math.max(msToTextChange, 0));
  }

  /**
   * @param {!Error} err
   */
  renderBugReport(err) {
    console.error(err);
    clearTimeout(this._scheduledFastFactTimeout);
    clearTimeout(this._scheduledTextChangeTimeout);
    this._resetProgressBarClasses();
    this._progressBar.classList.add('errored');

    this._commitTextChange('');
    this._statusText.createChild('p').createTextChild(Common.UIString('Ah, sorry! We ran into an error.'));
    if (Audits.StatusView.KnownBugPatterns.some(pattern => pattern.test(err.message))) {
      const message = Common.UIString(
          'Try to navigate to the URL in a fresh Chrome profile without any other tabs or extensions open and try again.');
      this._statusText.createChild('p').createTextChild(message);
    } else {
      this._renderBugReportBody(err, this._inspectedURL);
    }
  }

  /**
   * @param {!Error} err
   * @param {string} auditURL
   */
  _renderBugReportBody(err, auditURL) {
    const issueBody = `
${err.message}
\`\`\`
Channel: DevTools
Initial URL: ${auditURL}
Chrome Version: ${navigator.userAgent.match(/Chrome\/(\S+)/)[1]}
Stack Trace: ${err.stack}
\`\`\`
`;
    this._statusText.createChild('p').createTextChild(
        ls`If this issue is reproducible, please report it at the Lighthouse GitHub repo.`);
    this._statusText.createChild('code', 'monospace').createTextChild(issueBody.trim());
  }
};

/** @type {!Array.<!RegExp>} */
Audits.StatusView.KnownBugPatterns = [
  /PARSING_PROBLEM/,
  /DOCUMENT_REQUEST/,
  /READ_FAILED/,
  /TRACING_ALREADY_STARTED/,
  /^You must provide a url to the runner/,
  /^You probably have multiple tabs open/,
];

/** @typedef {{message: string, progressBarClass: string, order: number}} */
Audits.StatusView.StatusPhases = [
  {
    id: 'loading',
    progressBarClass: 'loading',
    statusMessagePrefix: 'Loading page',
    order: 10,
  },
  {
    id: 'gathering',
    progressBarClass: 'gathering',
    message: 'Lighthouse is gathering information about the page to compute your score.',
    statusMessagePrefix: 'Gathering',
    order: 20,
  },
  {
    id: 'auditing',
    progressBarClass: 'auditing',
    message: 'Almost there! Lighthouse is now generating your report.',
    statusMessagePrefix: 'Auditing',
    order: 30,
  }
];

/** @typedef {{message: string, deviceType: string, throttling: string}} */
Audits.StatusView.LoadingMessages = [
  {
    deviceType: 'mobile',
    throttling: 'on',
    message: 'Lighthouse is loading your page with throttling to measure performance on a mobile device on 3G.',
  },
  {
    deviceType: 'desktop',
    throttling: 'on',
    message: 'Lighthouse is loading your page with throttling to measure performance on a slow desktop on 3G.',
  },
  {
    deviceType: 'mobile',
    throttling: 'off',
    message: 'Lighthouse is loading your page with mobile emulation.',
  },
  {
    deviceType: 'desktop',
    throttling: 'off',
    message: 'Lighthouse is loading your page.',
  },
];

Audits.StatusView.FastFacts = [
  '1MB takes a minimum of 5 seconds to download on a typical 3G connection [Source: WebPageTest and DevTools 3G definition].',
  'Rebuilding Pinterest pages for performance increased conversion rates by 15% [Source: WPO Stats]',
  'BBC has seen a loss of 10% of their users for every extra second of page load [Source: WPO Stats]',
  'By reducing the response size of JSON needed for displaying comments, Instagram saw increased impressions [Source: WPO Stats]',
  'Walmart saw a 1% increase in revenue for every 100ms improvement in page load [Source: WPO Stats]',
  'If a site takes >1 second to become interactive, users lose attention, and their perception of completing the page task is broken [Source: Google Developers Blog]',
  '75% of global mobile users in 2016 were on 2G or 3G [Source: GSMA Mobile]',
  'The average user device costs less than 200 USD. [Source: International Data Corporation]',
  '53% of all site visits are abandoned if page load takes more than 3 seconds [Source: Google DoubleClick blog]',
  '19 seconds is the average time a mobile web page takes to load on a 3G connection [Source: Google DoubleClick blog]',
  '14 seconds is the average time a mobile web page takes to load on a 4G connection [Source: Google DoubleClick blog]',
  '70% of mobile pages take nearly 7 seconds for the visual content above the fold to display on the screen. [Source: Think with Google]',
  'As page load time increases from one second to seven seconds, the probability of a mobile site visitor bouncing increases 113%. [Source: Think with Google]',
  'As the number of elements on a page increases from 400 to 6,000, the probability of conversion drops 95%. [Source: Think with Google]',
  '70% of mobile pages weigh over 1MB, 36% over 2MB, and 12% over 4MB. [Source: Think with Google]',
  'Lighthouse only simulates mobile performance; to measure performance on a real device, try WebPageTest.org [Source: Lighthouse team]',
];

/** @const */
Audits.StatusView.fastFactRotationInterval = 6000;
/** @const */
Audits.StatusView.minimumTextVisibilityDuration = 3000;
<commit_msg>DevTools: Remove obstructing tab stop from audit status modal<commit_after>// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Audits.StatusView = class {
  /**
   * @param {!Audits.AuditController} controller
   */
  constructor(controller) {
    this._controller = controller;

    this._statusView = null;
    this._statusHeader = null;
    this._progressWrapper = null;
    this._progressBar = null;
    this._statusText = null;

    this._inspectedURL = '';
    this._textChangedAt = 0;
    this._fastFactsQueued = Audits.StatusView.FastFacts.slice();
    this._currentPhase = null;
    this._scheduledTextChangeTimeout = null;
    this._scheduledFastFactTimeout = null;

    this._dialog = new UI.Dialog();
    this._dialog.setDimmed(true);
    this._dialog.setCloseOnEscape(false);
    this._dialog.setOutsideClickCallback(event => event.consume(true));
    this._render();
  }

  _render() {
    const dialogRoot = UI.createShadowRootWithCoreStyles(this._dialog.contentElement, 'audits/auditsDialog.css');
    const auditsViewElement = dialogRoot.createChild('div', 'audits-view vbox');

    const cancelButton = UI.createTextButton(ls`Cancel`, this._cancel.bind(this));
    const fragment = UI.Fragment.build`

Auditing your web page\u2026

        ${cancelButton}

    `;

    auditsViewElement.appendChild(fragment.element());

    this._statusView = fragment.$('status-view');
    this._statusHeader = fragment.$('status-header');
    this._progressWrapper = fragment.$('progress-wrapper');
    this._progressBar = fragment.$('progress-bar');
    this._statusText = fragment.$('status-text');
    UI.ARIAUtils.markAsStatus(this._statusText);

    this._dialog.setDefaultFocusedElement(cancelButton);
    this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeight);
    this._dialog.setMaxContentSize(new UI.Size(500, 400));
  }

  _reset() {
    this._resetProgressBarClasses();
    clearTimeout(this._scheduledFastFactTimeout);

    this._textChangedAt = 0;
    this._fastFactsQueued = Audits.StatusView.FastFacts.slice();
    this._currentPhase = null;
    this._scheduledTextChangeTimeout = null;
    this._scheduledFastFactTimeout = null;
  }

  /**
   * @param {!Element} dialogRenderElement
   */
  show(dialogRenderElement) {
    this._reset();
    this.updateStatus(ls`Loading\u2026`);

    const parsedURL = this._inspectedURL.asParsedURL();
    const pageHost = parsedURL && parsedURL.host;
    const statusHeader = pageHost ? ls`Auditing ${pageHost}` : ls`Auditing your web page`;
    this._statusHeader.textContent = `${statusHeader}\u2026`;
    this._dialog.show(dialogRenderElement);
  }

  hide() {
    if (this._dialog.isShowing())
      this._dialog.hide();
  }

  /**
   * @param {string=} url
   */
  setInspectedURL(url = '') {
    this._inspectedURL = url;
  }

  /**
   * @param {?string} message
   */
  updateStatus(message) {
    if (!message || !this._statusText)
      return;

    if (message.startsWith('Cancel')) {
      this._commitTextChange(Common.UIString('Cancelling\u2026'));
      clearTimeout(this._scheduledFastFactTimeout);
      return;
    }

    const nextPhase = this._getPhaseForMessage(message);
    if (!nextPhase && !this._currentPhase) {
      this._commitTextChange(Common.UIString('Lighthouse is warming up\u2026'));
      clearTimeout(this._scheduledFastFactTimeout);
    } else if (nextPhase && (!this._currentPhase || this._currentPhase.order < nextPhase.order)) {
      this._currentPhase = nextPhase;
      this._scheduleTextChange(this._getMessageForPhase(nextPhase));
      this._scheduleFastFactCheck();
      this._resetProgressBarClasses();
      this._progressBar.classList.add(nextPhase.progressBarClass);
    }
  }

  _cancel() {
    this._controller.dispatchEventToListeners(Audits.Events.RequestAuditCancel);
  }

  /**
   * @param {!Audits.StatusView.StatusPhases} phase
   * @return {string}
   */
  _getMessageForPhase(phase) {
    if (phase.message)
      return Common.UIString(phase.message);

    const deviceType = Audits.RuntimeSettings.find(item => item.setting.name === 'audits.device_type').setting.get();
    const throttling = Audits.RuntimeSettings.find(item => item.setting.name === 'audits.throttling').setting.get();
    const match = Audits.StatusView.LoadingMessages.find(item => {
      return item.deviceType === deviceType && item.throttling === throttling;
    });

    return match ? ls`${match.message}` : ls`Lighthouse is loading your page`;
  }

  /**
   * @param {string} message
   * @return {?Audits.StatusView.StatusPhases}
   */
  _getPhaseForMessage(message) {
    return Audits.StatusView.StatusPhases.find(phase => message.startsWith(phase.statusMessagePrefix));
  }

  _resetProgressBarClasses() {
    if (!this._progressBar)
      return;

    this._progressBar.className = 'audits-progress-bar';
  }

  _scheduleFastFactCheck() {
    if (!this._currentPhase || this._scheduledFastFactTimeout)
      return;

    this._scheduledFastFactTimeout = setTimeout(() => {
      this._updateFastFactIfNecessary();
      this._scheduledFastFactTimeout = null;

      this._scheduleFastFactCheck();
    }, 100);
  }

  _updateFastFactIfNecessary() {
    const now = performance.now();
    if (now - this._textChangedAt < Audits.StatusView.fastFactRotationInterval)
      return;
    if (!this._fastFactsQueued.length)
      return;

    const fastFactIndex = Math.floor(Math.random() * this._fastFactsQueued.length);
    this._scheduleTextChange(ls`\ud83d\udca1 ${this._fastFactsQueued[fastFactIndex]}`);
    this._fastFactsQueued.splice(fastFactIndex, 1);
  }

  /**
   * @param {string} text
   */
  _commitTextChange(text) {
    if (!this._statusText)
      return;
    this._textChangedAt = performance.now();
    this._statusText.textContent = text;
  }

  /**
   * @param {string} text
   */
  _scheduleTextChange(text) {
    if (this._scheduledTextChangeTimeout)
      clearTimeout(this._scheduledTextChangeTimeout);

    const msSinceLastChange = performance.now() - this._textChangedAt;
    const msToTextChange = Audits.StatusView.minimumTextVisibilityDuration - msSinceLastChange;

    this._scheduledTextChangeTimeout = setTimeout(() => {
      this._commitTextChange(text);
    }, Math.max(msToTextChange, 0));
  }

  /**
   * @param {!Error} err
   */
  renderBugReport(err) {
    console.error(err);
    clearTimeout(this._scheduledFastFactTimeout);
    clearTimeout(this._scheduledTextChangeTimeout);
    this._resetProgressBarClasses();
    this._progressBar.classList.add('errored');

    this._commitTextChange('');
    this._statusText.createChild('p').createTextChild(Common.UIString('Ah, sorry! We ran into an error.'));
    if (Audits.StatusView.KnownBugPatterns.some(pattern => pattern.test(err.message))) {
      const message = Common.UIString(
          'Try to navigate to the URL in a fresh Chrome profile without any other tabs or extensions open and try again.');
      this._statusText.createChild('p').createTextChild(message);
    } else {
      this._renderBugReportBody(err, this._inspectedURL);
    }
  }

  /**
   * @param {!Error} err
   * @param {string} auditURL
   */
  _renderBugReportBody(err, auditURL) {
    const issueBody = `
${err.message}
\`\`\`
Channel: DevTools
Initial URL: ${auditURL}
Chrome Version: ${navigator.userAgent.match(/Chrome\/(\S+)/)[1]}
Stack Trace: ${err.stack}
\`\`\`
`;
    this._statusText.createChild('p').createTextChild(
        ls`If this issue is reproducible, please report it at the Lighthouse GitHub repo.`);
    this._statusText.createChild('code', 'monospace').createTextChild(issueBody.trim());
  }
};

/** @type {!Array.<!RegExp>} */
Audits.StatusView.KnownBugPatterns = [
  /PARSING_PROBLEM/,
  /DOCUMENT_REQUEST/,
  /READ_FAILED/,
  /TRACING_ALREADY_STARTED/,
  /^You must provide a url to the runner/,
  /^You probably have multiple tabs open/,
];

/** @typedef {{message: string, progressBarClass: string, order: number}} */
Audits.StatusView.StatusPhases = [
  {
    id: 'loading',
    progressBarClass: 'loading',
    statusMessagePrefix: 'Loading page',
    order: 10,
  },
  {
    id: 'gathering',
    progressBarClass: 'gathering',
    message: 'Lighthouse is gathering information about the page to compute your score.',
    statusMessagePrefix: 'Gathering',
    order: 20,
  },
  {
    id: 'auditing',
    progressBarClass: 'auditing',
    message: 'Almost there! Lighthouse is now generating your report.',
    statusMessagePrefix: 'Auditing',
    order: 30,
  }
];

/** @typedef {{message: string, deviceType: string, throttling: string}} */
Audits.StatusView.LoadingMessages = [
  {
    deviceType: 'mobile',
    throttling: 'on',
    message: 'Lighthouse is loading your page with throttling to measure performance on a mobile device on 3G.',
  },
  {
    deviceType: 'desktop',
    throttling: 'on',
    message: 'Lighthouse is loading your page with throttling to measure performance on a slow desktop on 3G.',
  },
  {
    deviceType: 'mobile',
    throttling: 'off',
    message: 'Lighthouse is loading your page with mobile emulation.',
  },
  {
    deviceType: 'desktop',
    throttling: 'off',
    message: 'Lighthouse is loading your page.',
  },
];

Audits.StatusView.FastFacts = [
  '1MB takes a minimum of 5 seconds to download on a typical 3G connection [Source: WebPageTest and DevTools 3G definition].',
  'Rebuilding Pinterest pages for performance increased conversion rates by 15% [Source: WPO Stats]',
  'BBC has seen a loss of 10% of their users for every extra second of page load [Source: WPO Stats]',
  'By reducing the response size of JSON needed for displaying comments, Instagram saw increased impressions [Source: WPO Stats]',
  'Walmart saw a 1% increase in revenue for every 100ms improvement in page load [Source: WPO Stats]',
  'If a site takes >1 second to become interactive, users lose attention, and their perception of completing the page task is broken [Source: Google Developers Blog]',
  '75% of global mobile users in 2016 were on 2G or 3G [Source: GSMA Mobile]',
  'The average user device costs less than 200 USD. [Source: International Data Corporation]',
  '53% of all site visits are abandoned if page load takes more than 3 seconds [Source: Google DoubleClick blog]',
  '19 seconds is the average time a mobile web page takes to load on a 3G connection [Source: Google DoubleClick blog]',
  '14 seconds is the average time a mobile web page takes to load on a 4G connection [Source: Google DoubleClick blog]',
  '70% of mobile pages take nearly 7 seconds for the visual content above the fold to display on the screen. [Source: Think with Google]',
  'As page load time increases from one second to seven seconds, the probability of a mobile site visitor bouncing increases 113%. [Source: Think with Google]',
  'As the number of elements on a page increases from 400 to 6,000, the probability of conversion drops 95%. [Source: Think with Google]',
  '70% of mobile pages weigh over 1MB, 36% over 2MB, and 12% over 4MB. [Source: Think with Google]',
  'Lighthouse only simulates mobile performance; to measure performance on a real device, try WebPageTest.org [Source: Lighthouse team]',
];

/** @const */
Audits.StatusView.fastFactRotationInterval = 6000;
/** @const */
Audits.StatusView.minimumTextVisibilityDuration = 3000;
<|endoftext|>