<commit_before>var TLDS = TLDS || [];
if (typeof require != 'undefined') {
	TLDS = require('./tlds').TLDS;
}

function loadValidTLDS() {
	var tldsArray = [];

	TLDS.forEach(function(tld){
		tldsArray.push('\\.' + tld + '(?!\\.|\\w)');
	});

	return tldsArray.join('|');
}

var validLinkMarkDownRegEx = new RegExp('[a-zA-Z0-9](' + loadValidTLDS() + ')|^https?:\\/\\/[a-zA-Z0-9]', "i");

var _ = _ || null;
if ((typeof require != 'undefined') && !_) {
	var _ = require('underscore');
}

var Markdown = function(raw, options) {
	var options = options || {};
	if (!raw) {
		return '';
	}
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	var code_blocks = {};
	var block_count = 0;
	var quote_tag = options.use_blockquote ? 'span class="blockquote"' : 'q';
	var end_quote_tag = options.use_blockquote ? '/span' : '/q';
	var bench = +new Date();
	var link_last_offset = bold_last_offset = italic_last_offset = strike_last_offset = underline_last_offset = 0;
	var test = 0;
	var total = 0;
	var link_was_inside_tag = bold_in_url = italic_in_url = strike_in_url = underline_in_url = false;
	var val = raw.replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			if (text === 'code') {
				return full_match;
			}

			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			if (typeof window !== 'undefined') {
				if (window.location && window.location.origin) {
					if (link.indexOf(window.location.origin) === 0) {
						if (link.indexOf('join') !== 0) {
							var link_pieces = link.split('/');
							var group_id = link_pieces[link_pieces.length - 1];
							return "
" + link + "
";
						}
						return "" + text + "";
					}
				}
			}

			return "" + text + "";

		}).
		replace(/\[code\]([\s\S]*?)(\[\/code\]|$)/gi, function(full_match, text) {
			var code;
			try {
				code = unescape(text);
				code = code.replace(/</g, '<').replace(/>/g, '>');
			}
			catch(error) {
				code = text.replace(/(\%\w\w)/g, function(fm, esc) {
					return unescape(esc);
				});
			}
			code_blocks['code_' + block_count] = code;
			var to_return = '[code_' + block_count + ']';
			block_count++;
			return to_return;
		}).
		replace(Markdown.global_url_regex, function(
			full_match,
			maybe_email1,
			maybe_email2,
			link,
			proto_and_slashes,
			protocol,
			junk,
			junkpoint5,
			junk1,
			junk2,
			junk3,
			junk4,
			junk5,
			junk6,
			last_char,
			offset,
			full_str
	) {
			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			var sub_bench = +new Date();
			var start = full_str.substr(link_last_offset, offset - link_last_offset);
			link_last_offset = offset;
			if (start.match(/.*\($/)) {
				return full_match;
			}
			var inside_tag = link_was_inside_tag ? (start.match(/.*>[^<]*$/) ? false : true) : start.match(/.*<[^>]*$/);
			if (inside_tag) {
				link_was_inside_tag = true;
				return full_match;
			}
			link_was_inside_tag = false;
			var inside_post_tag = start.match(/.*(\{\{-\{\{)(?![\s\S]*\}\}-\}\})[\s\S]*$/);
			if (inside_post_tag) {
				return full_match;
			}
			var lead_match = full_str.substring(0, offset);
			var lead_str = lead_match + full_match;
			var link_matches = lead_str.replace(/\{\{\-\{\{/g, '<').replace(/\}\}-\}\}/g, '>').match(/^[\s\S]*([\s\S]*?)$/);
			if (link_matches) {
				var link_match = link_matches[1];
				if (!link_match.match(/<\/a>/) || link_match.match(/<\/a>$/)) {
					return full_match;
				}
			}
			//console.warn("nomatch:", +new Date() - sub_bench);
			var no_blank = false;
			if (typeof window !== 'undefined') {
				if (window.location && window.location.origin) {
					if (link.indexOf(window.location.origin) === 0) {
						if (link.indexOf('join') !== 0) {
							var link_pieces = link.split('/');
							var group_id = link_pieces[link_pieces.length - 1];
							return "
" + link + "
";
						}
						no_blank = true;
					}
				}
			}

			link = link.replace(/[.,?]$/, function(m) { last_char = m; return ''; });
			return "" +
					(maybe_email2 ? maybe_email2 : '') +
					link + "" + last_char;
		}).
		replace(/\|([^\n]*)\|(\s|\n|$)/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			var percent = (100 / cols.length).toFixed(0);
			return "

" +
					cols.join("	") +
				"

";
		}).
		replace(/<\/table>
/g, '').
		replace(/((^|\n)\* [^\*\n]*)+/g, function(full_match, junk, start) {
			var parts = full_match.split(/\n/);
			if (parts[0].length === 0) {
				parts.shift();
			}
			return start + "

" +
				parts.map(function(part) { return part.replace(/^\* /, ''); }).
					join("

") +
				"

";
		}).
		replace(/\*\*(\S[^\*\*]*?\S)\*\*/g, function(full_match, text, offset, full_str) {
			total++;
			if (Markdown.is_in_url(full_match, text, offset, full_str, bold_in_url, bold_last_offset)) {
				bold_last_offset = offset;
				bold_in_url = true;
				return full_match;
			}
			bold_last_offset = offset;
			bold_in_url = false;
			return "" + text + "";
		}).
		replace(/\*(\S[^\*]*?\S)\*/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, italic_in_url, italic_last_offset)) {
				italic_last_offset = offset;
				italic_in_url = true;
				return full_match;
			}
			italic_last_offset = offset;
			italic_in_url = false;
			return "" + text + "";
		}).
		replace(/__(\S[^__]*?\S)__/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, underline_in_url, underline_last_offset)) {
				underline_last_offset = offset;
				underline_in_url = true;
				return full_match;
			}
			underline_last_offset = offset;
			underline_in_url = false;
			return "" + text + "";
		}).
		replace(/~~(\S[^~~]*?\S)~~/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, strike_in_url, strike_last_offset)) {
				strike_last_offset = offset;
				strike_in_url = true;
				return full_match;
			}
			strike_last_offset = offset;
			strike_in_url = false;
			return "" + text + "";
		}).
		replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text, offset, full_str) {
			return "" + text + "";
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + "<" + quote_tag + ">" + text + "<" + end_quote_tag + ">";
		}).
		replace(/\[code_(\w+)\]/g, function(full_match, which) {
			return "
" + code_blocks['code_' + which] + "
";
		}).
		replace(/mailto:<a href=/g, function(full_match, which) {
			return "[^<]*$/) : start.match(/.*<[^>]*$/);
	if (inside_tag) { return true; }
	var last_str = /([A-Za-z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.\:]+)$/g.exec(start);
	if (last_str) {
		var potential_url = last_str[0] + text;
		if (potential_url.match(Markdown.url_regex)) {
			return true;
		}
	}
	return false;
};

var Markdown_Is_Valid_Link = function(link) {
	return validLinkMarkDownRegEx.test(link);
}

Markdown.tld_url_regex = validLinkMarkDownRegEx;
Markdown.url_regex = /^((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?($|(\/\S?(\/\S)*\/?)|(\#\S?)|(\?\S?))/i;
Markdown.global_url_regex = /(([a-zA-Z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.]+@)?)(((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?(((\/([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=])*)+)\??([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\%])*)?)([^A-Za-z]|$)/gi;

var Markdown_For_Search = function(raw, options) {
	options = options || {};
	if (!raw) { return ''; }
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	return raw.replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text) {
		return "" + text + "";
	});
};

var Remove_Markdown = function(raw, options) {
	options = options || {};
	return (options.dont_escape ? raw : _.escape(raw)).
		replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[code\]/g, '').
		replace(/\[\/code\]/g,'').
		replace(/\|([^\n]*)\|/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			return cols.join('\t');
		}).
		replace(/\*\*(\S[^\*\*]*?\S)\*\*/g, function(full_match, text) {
			return text;
		}).
		// replace(/\`(.*?)\`/g, function(full_match, text) {
		// 	return text;
		// }).
		replace(/\*(\S[^\*]*?\S)\*/g, function(full_match, text) {
			return text;
		}).
		replace(/__(\S[^__]*?\S)__/g, function(full_match, text) {
			return text;
		}).
		replace(/~~(\S[^~~]*?\S)~~/g, function(full_match, text) {
			return text;
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + " " + text + " ";
		}).
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			return text;
		});
};

if (typeof exports == 'object') {
	exports.Markdown = Markdown;
	exports.Remove_Markdown = Remove_Markdown;
	exports.Markdown_For_Search = Markdown_For_Search;
	exports.Markdown_Is_Valid_Link = Markdown_Is_Valid_Link;
}
<commit_msg>Fixed markdown parser issue about strike/italic/underline/bold for such cases: ****bold**, ***bold**, bold * bold, ~~~~strike~~, ~~~strike~~, strike ~ strike, **italic*, italic * italic, ____underline__, ___underline__<commit_after>var TLDS = TLDS || [];
if (typeof require != 'undefined') {
	TLDS = require('./tlds').TLDS;
}

function loadValidTLDS() {
	var tldsArray = [];

	TLDS.forEach(function(tld){
		tldsArray.push('\\.' + tld + '(?!\\.|\\w)');
	});

	return tldsArray.join('|');
}

var validLinkMarkDownRegEx = new RegExp('[a-zA-Z0-9](' + loadValidTLDS() + ')|^https?:\\/\\/[a-zA-Z0-9]', "i");

var _ = _ || null;
if ((typeof require != 'undefined') && !_) {
	var _ = require('underscore');
}

var Markdown = function(raw, options) {
	var options = options || {};
	if (!raw) {
		return '';
	}
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	var code_blocks = {};
	var block_count = 0;
	var quote_tag = options.use_blockquote ? 'span class="blockquote"' : 'q';
	var end_quote_tag = options.use_blockquote ? '/span' : '/q';
	var bench = +new Date();
	var link_last_offset = bold_last_offset = italic_last_offset = strike_last_offset = underline_last_offset = 0;
	var test = 0;
	var total = 0;
	var link_was_inside_tag = bold_in_url = italic_in_url = strike_in_url = underline_in_url = false;
	var val = raw.replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			if (text === 'code') {
				return full_match;
			}

			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			if (typeof window !== 'undefined') {
				if (window.location && window.location.origin) {
					if (link.indexOf(window.location.origin) === 0) {
						if (link.indexOf('join') !== 0) {
							var link_pieces = link.split('/');
							var group_id = link_pieces[link_pieces.length - 1];
							return "
" + link + "
";
						}
						return "" + text + "";
					}
				}
			}

			return "" + text + "";

		}).
		replace(/\[code\]([\s\S]*?)(\[\/code\]|$)/gi, function(full_match, text) {
			var code;
			try {
				code = unescape(text);
				code = code.replace(/</g, '<').replace(/>/g, '>');
			}
			catch(error) {
				code = text.replace(/(\%\w\w)/g, function(fm, esc) {
					return unescape(esc);
				});
			}
			code_blocks['code_' + block_count] = code;
			var to_return = '[code_' + block_count + ']';
			block_count++;
			return to_return;
		}).
		replace(Markdown.global_url_regex, function(
			full_match,
			maybe_email1,
			maybe_email2,
			link,
			proto_and_slashes,
			protocol,
			junk,
			junkpoint5,
			junk1,
			junk2,
			junk3,
			junk4,
			junk5,
			junk6,
			last_char,
			offset,
			full_str
	) {
			if(!validLinkMarkDownRegEx.test(link)) {
				return full_match;
			}

			var sub_bench = +new Date();
			var start = full_str.substr(link_last_offset, offset - link_last_offset);
			link_last_offset = offset;
			if (start.match(/.*\($/)) {
				return full_match;
			}
			var inside_tag = link_was_inside_tag ? (start.match(/.*>[^<]*$/) ? false : true) : start.match(/.*<[^>]*$/);
			if (inside_tag) {
				link_was_inside_tag = true;
				return full_match;
			}
			link_was_inside_tag = false;
			var inside_post_tag = start.match(/.*(\{\{-\{\{)(?![\s\S]*\}\}-\}\})[\s\S]*$/);
			if (inside_post_tag) {
				return full_match;
			}
			var lead_match = full_str.substring(0, offset);
			var lead_str = lead_match + full_match;
			var link_matches = lead_str.replace(/\{\{\-\{\{/g, '<').replace(/\}\}-\}\}/g, '>').match(/^[\s\S]*([\s\S]*?)$/);
			if (link_matches) {
				var link_match = link_matches[1];
				if (!link_match.match(/<\/a>/) || link_match.match(/<\/a>$/)) {
					return full_match;
				}
			}
			//console.warn("nomatch:", +new Date() - sub_bench);
			var no_blank = false;
			if (typeof window !== 'undefined') {
				if (window.location && window.location.origin) {
					if (link.indexOf(window.location.origin) === 0) {
						if (link.indexOf('join') !== 0) {
							var link_pieces = link.split('/');
							var group_id = link_pieces[link_pieces.length - 1];
							return "
" + link + "
";
						}
						no_blank = true;
					}
				}
			}

			link = link.replace(/[.,?]$/, function(m) { last_char = m; return ''; });
			return "" +
					(maybe_email2 ? maybe_email2 : '') +
					link + "" + last_char;
		}).
		replace(/\|([^\n]*)\|(\s|\n|$)/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			var percent = (100 / cols.length).toFixed(0);
			return "

" +
					cols.join("	") +
				"

";
		}).
		replace(/<\/table>
/g, '').
		replace(/((^|\n)\* [^\*\n]*)+/g, function(full_match, junk, start) {
			var parts = full_match.split(/\n/);
			if (parts[0].length === 0) {
				parts.shift();
			}
			return start + "

" +
				parts.map(function(part) { return part.replace(/^\* /, ''); }).
					join("

") +
				"

";
		}).
		replace(/\*\*([^\*\*]+)\*\*/g, function(full_match, text, offset, full_str) {
			total++;
			if (Markdown.is_in_url(full_match, text, offset, full_str, bold_in_url, bold_last_offset)) {
				bold_last_offset = offset;
				bold_in_url = true;
				return full_match;
			}
			bold_last_offset = offset;
			bold_in_url = false;
			return "" + text + "";
		}).
		replace(/\*([^\*]+)\*/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, italic_in_url, italic_last_offset)) {
				italic_last_offset = offset;
				italic_in_url = true;
				return full_match;
			}
			italic_last_offset = offset;
			italic_in_url = false;
			return "" + text + "";
		}).
		replace(/__([^__]+)__/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, underline_in_url, underline_last_offset)) {
				underline_last_offset = offset;
				underline_in_url = true;
				return full_match;
			}
			underline_last_offset = offset;
			underline_in_url = false;
			return "" + text + "";
		}).
		replace(/~~([^~~]+)~~/g, function(full_match, text, offset, full_str) {
			if (Markdown.is_in_url(full_match, text, offset, full_str, strike_in_url, strike_last_offset)) {
				strike_last_offset = offset;
				strike_in_url = true;
				return full_match;
			}
			strike_last_offset = offset;
			strike_in_url = false;
			return "" + text + "";
		}).
		replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text, offset, full_str) {
			return "" + text + "";
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + "<" + quote_tag + ">" + text + "<" + end_quote_tag + ">";
		}).
		replace(/\[code_(\w+)\]/g, function(full_match, which) {
			return "
" + code_blocks['code_' + which] + "
";
		}).
		replace(/mailto:<a href=/g, function(full_match, which) {
			return "[^<]*$/) : start.match(/.*<[^>]*$/);
	if (inside_tag) { return true; }
	var last_str = /([A-Za-z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.\:]+)$/g.exec(start);
	if (last_str) {
		var potential_url = last_str[0] + text;
		if (potential_url.match(Markdown.url_regex)) {
			return true;
		}
	}
	return false;
};

var Markdown_Is_Valid_Link = function(link) {
	return validLinkMarkDownRegEx.test(link);
}

Markdown.tld_url_regex = validLinkMarkDownRegEx;
Markdown.url_regex = /^((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?($|(\/\S?(\/\S)*\/?)|(\#\S?)|(\?\S?))/i;
Markdown.global_url_regex = /(([a-zA-Z0-9\!\#\$\%\&\'\*\+\-\/\=\?\%\_\`\{\|\}\~\.]+@)?)(((ftp|https?):\/\/)?[-\w]+\.([-\w]+\.)*(\d+\.\d+\.\d+|[-A-Za-z]+)(:\d+)?(((\/([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=])*)+)\??([A-Za-z0-9-\._~:\/\?\#\[\]\@\!\$\&\'\(\)\*\+\,\;\=\%])*)?)([^A-Za-z]|$)/gi;

var Markdown_For_Search = function(raw, options) {
	options = options || {};
	if (!raw) { return ''; }
	if (!options.dont_escape) {
		raw = _.escape(raw);
	}
	return raw.replace(/\{\{\[\[-([^\{\{\[\[]*?)-\]\]\}\}/g, function(full_match, text) {
		return "" + text + "";
	});
};

var Remove_Markdown = function(raw, options) {
	options = options || {};
	return (options.dont_escape ? raw : _.escape(raw)).
		replace(/\&\#x2F;/g, '/'). // not sure why underscore replaces these...docs don't even claim that it does
		replace(/\[code\]/g, '').
		replace(/\[\/code\]/g,'').
		replace(/\|([^\n]*)\|/g, function(full_match, text) {
			var cols = text.split(/\|/);
			if (!cols.length) {
				return text;
			}
			return cols.join('\t');
		}).
		replace(/\*\*(\S[^\*\*]*?\S)\*\*/g, function(full_match, text) {
			return text;
		}).
		// replace(/\`(.*?)\`/g, function(full_match, text) {
		// 	return text;
		// }).
		replace(/\*(\S[^\*]*?\S)\*/g, function(full_match, text) {
			return text;
		}).
		replace(/__(\S[^__]*?\S)__/g, function(full_match, text) {
			return text;
		}).
		replace(/~~(\S[^~~]*?\S)~~/g, function(full_match, text) {
			return text;
		}).
		replace(/(^|\n)> ([^\n]*)/g, function(full_match, start, text) {
			return start + " " + text + " ";
		}).
		replace(/\[([^\]]*?)\]\(([\s\S]*?)\)/g, function(full_match, text, link) {
			return text;
		});
};

if (typeof exports == 'object') {
	exports.Markdown = Markdown;
	exports.Remove_Markdown = Remove_Markdown;
	exports.Markdown_For_Search = Markdown_For_Search;
	exports.Markdown_Is_Valid_Link = Markdown_Is_Valid_Link;
}
<|endoftext|>


<commit_before>function updateBuildPanel(buildData) {
  document.querySelector("link[rel='shortcut icon'").setAttribute("href", buildData["favicon-path"])
  document.getElementsByClassName("build-panel")[0].className = "build-panel " + buildData["state"];
  document.getElementsByClassName("status")[0].innerHTML = buildData["status-text"];
  document.getElementsByClassName("build-definition-name")[0].innerHTML = buildData["build-definition-name"];
  document.getElementsByClassName("build-number")[0].innerHTML = buildData["build-number"];
  document.getElementsByClassName("commit-message")[0].innerHTML = buildData["commit-message"];
}

function showRefreshIcon() {
  document.getElementsByClassName("refresh-icon")[0].className = "refresh-icon";
}

function hideRefreshIcon() {
  document.getElementsByClassName("refresh-icon")[0].className = "refresh-icon hidden";
}

function showErrorModal() {
  document.getElementsByClassName("error-modal")[0].className = "error-modal";
}

function hideErrorModal() {
  document.getElementsByClassName("error-modal")[0].className = "error-modal hidden";
}

function refreshBuildPanel(buildDefinitionId) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (xhttp.readyState == 4) {
      if (xhttp.status == 200) {
        hideErrorModal();
        var buildData = JSON.parse(xhttp.responseText);
        updateBuildPanel(buildData);
      }
      else {
        showErrorModal();
      }
    }
  };
  xhttp.open("GET", "/ajax/build-definitions/" + buildDefinitionId, false);
  xhttp.send();
}

function refreshBuild() {
  showRefreshIcon();
  for (i = 0; i < window.buildDefinitionIds.length; i++) {
    refreshBuildPanel(window.buildDefinitionIds[i]);
  }
  hideRefreshIcon();
}

window.onload=function(){
  window.setInterval(refreshBuild, window.refreshSeconds * 1000);
};
<commit_msg>Target specific build-panel when updating with javascript<commit_after>function updateBuildPanel(buildPanel, buildData) {
  document.querySelector("link[rel='shortcut icon'").setAttribute("href", buildData["favicon-path"])
  buildPanel.className = "build-panel " + buildData["state"];
  buildPanel.getElementsByClassName("status")[0].innerHTML = buildData["status-text"];
  buildPanel.getElementsByClassName("build-definition-name")[0].innerHTML = buildData["build-definition-name"];
  buildPanel.getElementsByClassName("build-number")[0].innerHTML = buildData["build-number"];
  buildPanel.getElementsByClassName("commit-message")[0].innerHTML = buildData["commit-message"];
}

function showRefreshIcon() {
  document.getElementsByClassName("refresh-icon")[0].className = "refresh-icon";
}

function hideRefreshIcon() {
  document.getElementsByClassName("refresh-icon")[0].className = "refresh-icon hidden";
}

function showErrorModal() {
  document.getElementsByClassName("error-modal")[0].className = "error-modal";
}

function hideErrorModal() {
  document.getElementsByClassName("error-modal")[0].className = "error-modal hidden";
}

function refreshBuildPanel(buildDefinitionId) {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (xhttp.readyState == 4) {
      if (xhttp.status == 200) {
        hideErrorModal();
        var buildData = JSON.parse(xhttp.responseText);
        var buildPanelId = "build-definition-id-" + buildDefinitionId;
        var buildPanel = document.getElementById(buildPanelId);
        updateBuildPanel(buildPanel, buildData);
      }
      else {
        showErrorModal();
      }
    }
  };
  xhttp.open("GET", "/ajax/build-definitions/" + buildDefinitionId, false);
  xhttp.send();
}

function refreshBuild() {
  showRefreshIcon();
  for (i = 0; i < window.buildDefinitionIds.length; i++) {
    refreshBuildPanel(window.buildDefinitionIds[i]);
  }
  hideRefreshIcon();
}

window.onload=function(){
  window.setInterval(refreshBuild, window.refreshSeconds * 1000);
};
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Philippe Leefsma 2014 - ADN/Developer Technical Services
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Namespace declaration
//
///////////////////////////////////////////////////////////////////////////////
AutodeskNamespace("Autodesk.ADN.Toolkit.Viewer");

///////////////////////////////////////////////////////////////////////////////
// Autodesk.ADN.Toolkit.Viewer.AdnViewerManager
//
///////////////////////////////////////////////////////////////////////////////
Autodesk.ADN.Toolkit.Viewer.AdnViewerManager = function (
    tokenOrUrl,
    viewerContainer,
    environment) {

    ///////////////////////////////////////////////////////////////////////////
    // Check if string is a valid url
    //
    ///////////////////////////////////////////////////////////////////////////
    var _validateURL = function(str) {

        return(str.indexOf('http:') > -1 || str.indexOf('https:') > -1);
    }

    var _newGuid = function () {

        var d = new Date().getTime();

        var guid = 'xxxx-xxxx-xxxx-xxxx-xxxx'.replace(
            /[xy]/g,
            function (c) {
                var r = (d + Math.random() * 16) % 16 | 0;
                d = Math.floor(d / 16);
                return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
            });

        return guid;
    };

    ///////////////////////////////////////////////////////////////////////////
    // Private Members
    //
    ///////////////////////////////////////////////////////////////////////////
    var _viewerDivId = _newGuid();

    var _viewerContainer = viewerContainer;

    var _viewer = null;

    var _self = this;

    //Motion intervals

    var _explodeMotion = null;

    var _rotateMotion = null;

    ///////////////////////////////////////////////////////////////////////////
    // Returns adsk viewer
    //
    ///////////////////////////////////////////////////////////////////////////
    this.getViewer = function () {

        return _viewer;
    };

    ///////////////////////////////////////////////////////////////////////////
    // Initialize Viewer and load document
    //
    ///////////////////////////////////////////////////////////////////////////
    this.loadDocument = function (urn, onViewerInitialized, onError) {

        var options = {
            env: (environment ? environment : "AutodeskProduction")
            //env: "AutodeskStaging"
        };

        // initialized with getToken callback
        if (_validateURL(tokenOrUrl)) {

            var getToken =  function() {

                var xhr = new XMLHttpRequest();

                xhr.open("GET", tokenOrUrl, false);
                xhr.send(null);

                var response = JSON.parse(
                    xhr.responseText);

                return response.access_token;
            }

            options.getAccessToken = getToken;

            options.refreshToken = getToken;
        }

        // initialized with access token
        else {

            options.accessToken = tokenOrUrl;
        }

        var viewerElement = _createViewerElement(_viewerContainer);

        Autodesk.Viewing.Initializer(options, function () {

            _getViewablePath(
                urn, null, function (path, role) {

                    if (!path ) {

                        // error loading document
                        if(onError)
                            onError(role);

                        return;
                    }

                    if (_viewer) {

                        _viewer.finish();
                    }

                    if (role === '3d' || role === '2d') {

                        _viewer = new Autodesk.Viewing.Private.GuiViewer3D(
                            //_viewer = new Autodesk.Viewing.Viewer3D(
                            viewerElement);

                        _viewer.start();

                        _viewer.setProgressiveRendering(true);

                        _viewer.setQualityLevel(true, true);

                        _viewer.impl.setLightPreset(8);

                        _viewer.setBackgroundColor(3,4,5, 250, 250, 250);
                    }

                    else {

                        //error
                        return;
                    }

                    _viewer.addEventListener(

                        Autodesk.Viewing.GEOMETRY_LOADED_EVENT,

                        function(event) {
                            _viewer.fitToView(false);
                        });

                    if (onViewerInitialized)
                        onViewerInitialized(_viewer);

                    _viewer.load(path);
                });
        });

        //fit view on escape
        $(document).keyup(function (e) {
            // esc
            if (e.keyCode == 27) {
                _viewer.fitToView(false);
            }
        });
    };

    ///////////////////////////////////////////////////////////////////////////
    // Close current document if any
    //
    ///////////////////////////////////////////////////////////////////////////
    this.closeDocument = function () {

        var viewerDiv = document.getElementById(_viewerDivId);

        if (viewerDiv) {

            viewerDiv.parentNode.removeChild(viewerDiv);
        }

        _viewer = null;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Creates new viewer div element
    //
    ///////////////////////////////////////////////////////////////////////////
    var _createViewerElement = function (viewerContainer) {

        var viewerDiv = document.getElementById(
            _viewerDivId);

        if (viewerDiv) {

            viewerDiv.parentNode.removeChild(
                viewerDiv);
        }

        viewerDiv = document.createElement("div");

        viewerDiv.id = _viewerDivId;

        viewerDiv.style.height = "100%";

        viewerContainer.appendChild(viewerDiv);

        // disable default context menu on viewer div
        $('#' + _viewerDivId).on('contextmenu',
            function (e) {
                e.preventDefault();
            });

        // disable scrolling on DOM document
        // while mouse pointer is over viewer area
        $('#' + _viewerDivId).hover(
            function () {
                var x = window.scrollX;
                var y = window.scrollY;
                window.onscroll = function () {
                    window.scrollTo(x, y);
                };
            },
            function () {
                window.onscroll = null;
            }
        );

        return viewerDiv;
    };

    ///////////////////////////////////////////////////////////////////////////
    // Get 2d or 3d viewable path
    //
    ///////////////////////////////////////////////////////////////////////////
    var _getViewablePath = function (documentId, initialItemId, callback) {

        if (documentId.indexOf('urn:') !== 0)
            documentId = 'urn:' + documentId;

        Autodesk.Viewing.Document.load(
            documentId,
            function (document) {

                var items = [];

                if (initialItemId) {
                    items = Autodesk.Viewing.Document.getSubItemsWithProperties(
                        document.getRootItem(),
                        { 'guid': initialItemId },
                        true);
                }

                if (items.length == 0) {

                    items = Autodesk.Viewing.Document.getSubItemsWithProperties(
                        document.getRootItem(),
                        { 'type': 'geometry', 'role': '2d' },
                        true);

                    if (items.length > 0) {

                        var path2d = document.getViewablePath(items[0]);

                        callback(path2d, '2d');
                        return;
                    }
                }

                if (items.length == 0) {

                    items = Autodesk.Viewing.Document.getSubItemsWithProperties(
                        document.getRootItem(),
                        { 'type': 'geometry', 'role': '3d' },
                        true);

                    if (items.length > 0) {

                        var path3d = document.getViewablePath(items[0]);

                        callback(path3d, '3d');
                        return;
                    }
                }
            },
            function (error) {
                console.log("Error loading document: " + error)
                callback(null, error);
            }
        );
    };
}

<commit_msg>update<commit_after>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Autodesk, Inc. All rights reserved
// Written by Philippe Leefsma 2014 - ADN/Developer Technical Services
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Namespace declaration
//
///////////////////////////////////////////////////////////////////////////////
AutodeskNamespace("Autodesk.ADN.Toolkit.Viewer");

///////////////////////////////////////////////////////////////////////////////
// Autodesk.ADN.Toolkit.Viewer.AdnViewerManager
//
///////////////////////////////////////////////////////////////////////////////
Autodesk.ADN.Toolkit.Viewer.AdnViewerManager = function (
    tokenOrUrl,
    viewerContainer,
    config) {

    ///////////////////////////////////////////////////////////////////////////
    // Check if string is a valid url
    //
    ///////////////////////////////////////////////////////////////////////////
    var _validateURL = function(str) {

        return(str.indexOf('http:') > -1 || str.indexOf('https:') > -1);
    }

    var _newGuid = function () {

        var d = new Date().getTime();

        var guid = 'xxxx-xxxx-xxxx-xxxx-xxxx'.replace(
            /[xy]/g,
            function (c) {
                var r = (d + Math.random() * 16) % 16 | 0;
                d = Math.floor(d / 16);
                return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
            });

        return guid;
    };

    ///////////////////////////////////////////////////////////////////////////
    // Private Members
    //
    ///////////////////////////////////////////////////////////////////////////
    var _viewerDivId = _newGuid();

    var _viewerContainer = viewerContainer;

    var _viewer = null;

    var _self = this;

    //Motion intervals

    var _explodeMotion = null;

    var _rotateMotion = null;

    ///////////////////////////////////////////////////////////////////////////
    // Returns adsk viewer
    //
    ///////////////////////////////////////////////////////////////////////////
    this.getViewer = function () {

        return _viewer;
    };

    ///////////////////////////////////////////////////////////////////////////
    // Initialize Viewer and load document
    //
    ///////////////////////////////////////////////////////////////////////////
    this.loadDocument = function (urn, onViewerInitialized, onError) {

        var options = {

            env: (config && config.environment ? environment : "AutodeskProduction")
            //env: "AutodeskStaging"
        };

        // initialized with getToken callback
        if (_validateURL(tokenOrUrl)) {

            var getToken =  function() {

                var xhr = new XMLHttpRequest();

                xhr.open("GET", tokenOrUrl, false);
                xhr.send(null);

                var response = JSON.parse(
                    xhr.responseText);

                return response.access_token;
            }

            options.getAccessToken = getToken;

            options.refreshToken = getToken;
        }

        // initialized with access token
        else {

            options.accessToken = tokenOrUrl;
        }

        var viewerElement = _createViewerElement(_viewerContainer);

        Autodesk.Viewing.Initializer(options, function () {

            _getViewablePath(
                urn, null, function (path, role) {

                    if (!path ) {

                        // error loading document
                        if(onError)
                            onError(role);

                        return;
                    }

                    if (_viewer) {

                        _viewer.finish();
                    }

                    if (role === '3d' || role === '2d') {

                        _viewer = new Autodesk.Viewing.Private.GuiViewer3D(
                            //_viewer = new Autodesk.Viewing.Viewer3D(
                            viewerElement);

                        _viewer.start();

                        _viewer.setProgressiveRendering(true);

                        _viewer.setQualityLevel(true, true);

                        _viewer.impl.setLightPreset(8);

                        _viewer.setBackgroundColor(3,4,5, 250, 250, 250);
                    }

                    else {

                        //error
                        return;
                    }

                    _viewer.addEventListener(

                        Autodesk.Viewing.GEOMETRY_LOADED_EVENT,

                        function(event) {
                            _viewer.fitToView(false);
                        });

                    if (onViewerInitialized)
                        onViewerInitialized(_viewer);

                    _viewer.load(path);
                });
        });

        //fit view on escape
        $(document).keyup(function (e) {
            // esc
            if (e.keyCode == 27) {
                _viewer.fitToView(false);
            }
        });
    };

    ///////////////////////////////////////////////////////////////////////////
    // Close current document if any
    //
    ///////////////////////////////////////////////////////////////////////////
    this.closeDocument = function () {

        var viewerDiv = document.getElementById(_viewerDivId);

        if (viewerDiv) {

            viewerDiv.parentNode.removeChild(viewerDiv);
        }

        _viewer = null;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Creates new viewer div element
    //
    ///////////////////////////////////////////////////////////////////////////
    var _createViewerElement = function (viewerContainer) {

        var viewerDiv = document.getElementById(
            _viewerDivId);

        if (viewerDiv) {

            viewerDiv.parentNode.removeChild(
                viewerDiv);
        }

        viewerDiv = document.createElement("div");

        viewerDiv.id = _viewerDivId;

        viewerDiv.style.height = "100%";

        viewerContainer.appendChild(viewerDiv);

        // disable default context menu on viewer div
        $('#' + _viewerDivId).on('contextmenu',
            function (e) {
                e.preventDefault();
            });

        // disable scrolling on DOM document
        // while mouse pointer is over viewer area
        $('#' + _viewerDivId).hover(
            function () {
                var x = window.scrollX;
                var y = window.scrollY;
                window.onscroll = function () {
                    window.scrollTo(x, y);
                };
            },
            function () {
                window.onscroll = null;
            }
        );

        return viewerDiv;
    };

    ///////////////////////////////////////////////////////////////////////////
    // Get 2d or 3d viewable path
    //
    ///////////////////////////////////////////////////////////////////////////
    var _getViewablePath = function (documentId, initialItemId, callback) {

        if (documentId.indexOf('urn:') !== 0)
            documentId = 'urn:' + documentId;

        Autodesk.Viewing.Document.load(
            documentId,
            function (document) {

                var items = [];

                if (initialItemId) {
                    items = Autodesk.Viewing.Document.getSubItemsWithProperties(
                        document.getRootItem(),
                        { 'guid': initialItemId },
                        true);
                }

                if (items.length == 0) {

                    items = Autodesk.Viewing.Document.getSubItemsWithProperties(
                        document.getRootItem(),
                        { 'type': 'geometry', 'role': '2d' },
                        true);

                    if (items.length > 0) {

                        var path2d = document.getViewablePath(items[0]);

                        callback(path2d, '2d');
                        return;
                    }
                }

                if (items.length == 0) {

                    items = Autodesk.Viewing.Document.getSubItemsWithProperties(
                        document.getRootItem(),
                        { 'type': 'geometry', 'role': '3d' },
                        true);

                    if (items.length > 0) {

                        var path3d = document.getViewablePath(items[0]);

                        callback(path3d, '3d');
                        return;
                    }
                }
            },
            function (error) {
                console.log("Error loading document: " + error)
                callback(null, error);
            }
        );
    };
}

<|endoftext|>


<commit_before>/*global Backbone, DOMPurify */
hqDefine("cloudcare/js/formplayer/utils/util", function () {
    var Util = {};

    /**
     * confirmationModal
     *
     * Takes an options hash that specifies options for a confirmation modal.
     *
     * @param options - Object
     *      {
     *          'title': <title> | 'Confirm?',
     *          'message': <message>,
     *          'confirmText': <confirmText> | 'OK',
     *          'cancelText': <cancelText> | 'Cancel',
     *          'onConfirm': function() {},
     *      }
     */
    Util.confirmationModal = function (options) {
        options = _.defaults(options, {
            title: gettext('Confirm?'),
            message: '',
            confirmText: gettext('OK'),
            cancelText: gettext('Cancel'),
            onConfirm: function () {},
        });
        var $modal = $('#js-confirmation-modal');
        $modal.find('.js-modal-title').text(options.title);
        $modal.find('.js-modal-body').html(DOMPurify.sanitize(options.message));
        $modal.find('#js-confirmation-confirm').text(options.confirmText);
        $modal.find('#js-confirmation-cancel').text(options.cancelText);

        var $confirmationButton = $modal.find('#js-confirmation-confirm');
        $confirmationButton.off('.confirmationModal');
        $confirmationButton.on('click.confirmationModal', function (e) {
            options.onConfirm(e);
        });
        $modal.modal('show');
    };

    Util.encodedUrlToObject = function (encodedUrl) {
        return decodeURIComponent(encodedUrl);
    };

    Util.objectToEncodedUrl = function (object) {
        return encodeURIComponent(object);
    };

    Util.currentUrlToObject = function () {
        var url = Backbone.history.getFragment();
        try {
            return Util.CloudcareUrl.fromJson(Util.encodedUrlToObject(url));
        } catch (e) {
            // This means that we're on the homepage
            return new Util.CloudcareUrl({});
        }
    };

    Util.setUrlToObject = function (urlObject, replace) {
        replace = replace || false;
        var encodedUrl = Util.objectToEncodedUrl(urlObject.toJson());
        hqImport("cloudcare/js/formplayer/app").navigate(encodedUrl, { replace: replace });
    };

    Util.doUrlAction = function (actionCallback) {
        var currentObject = Util.CurrentUrlToObject();
        actionCallback(currentObject);
        Util.setUrlToObject(currentObject);
    };

    Util.setCrossDomainAjaxOptions = function (options) {
        options.type = 'POST';
        options.dataType = "json";
        options.crossDomain = {crossDomain: true};
        options.xhrFields = {withCredentials: true};
        options.contentType = "application/json;charset=UTF-8";
    };

    Util.saveDisplayOptions = function (displayOptions) {
        var displayOptionsKey = Util.getDisplayOptionsKey();
        localStorage.setItem(displayOptionsKey, JSON.stringify(displayOptions));
    };

    Util.getSavedDisplayOptions = function () {
        var displayOptionsKey = Util.getDisplayOptionsKey();
        try {
            return JSON.parse(localStorage.getItem(displayOptionsKey));
        } catch (e) {
            window.console.warn('Unabled to parse saved display options');
            return {};
        }
    };

    Util.getDisplayOptionsKey = function () {
        var user = hqImport("cloudcare/js/formplayer/app").getChannel().request('currentUser');
        return [
            user.environment,
            user.domain,
            user.username,
            'displayOptions',
        ].join(':');
    };

    Util.pagesToShow = function (selectedPage, totalPages, limit) {
        var limitHalf = Math.floor(limit / 2);
        if (totalPages < limit) {
            return {
                start: 0,
                end: totalPages,
            };
        }

        if (selectedPage < limitHalf) {
            return {
                start: 0,
                end: limit,
            };
        }

        if (selectedPage > totalPages - limitHalf) {
            return {
                start: totalPages - limit,
                end: totalPages,
            };
        }

        return {
            start: selectedPage - limitHalf,
            end: selectedPage + limitHalf,
        };
    };

    Util.getCurrentQueryInputs = function () {
        var queryData = Util.currentUrlToObject().queryData[sessionStorage.queryKey];
        if (queryData) {
            return queryData.inputs || {};
        }
        return {};
    };

    Util.getStickyQueryInputs = function () {
        if (!hqImport("hqwebapp/js/toggles").toggleEnabled('WEBAPPS_STICKY_SEARCH')) {
            return {};
        }
        if (!this.stickyQueryInputs) {
            return {};
        }
        return this.stickyQueryInputs[sessionStorage.queryKey] || {};
    };

    Util.setStickyQueryInputs = function (inputs) {
        if (!this.stickyQueryInputs) {
            this.stickyQueryInputs = {};
        }
        this.stickyQueryInputs[sessionStorage.queryKey] = inputs;
    };

    Util.CloudcareUrl = function (options) {
        this.appId = options.appId;
        this.copyOf = options.copyOf;
        this.sessionId = options.sessionId;
        this.selections = options.selections;
        this.endpointId = options.endpointId;
        this.endpointArgs = options.endpointArgs;
        this.page = options.page;
        this.search = options.search;
        this.casesPerPage = options.casesPerPage;
        this.queryData = options.queryData;
        this.singleApp = options.singleApp;
        this.sortIndex = options.sortIndex;
        this.forceLoginAs = options.forceLoginAs;
        this.forceManualAction = options.forceManualAction;

        this.setSelections = function (selections) {
            this.selections = selections;
        };

        this.addSelection = function (selection) {
            if (!this.selections) {
                this.selections = [];
            }

            // Selections only deal with strings, because formplayer will send them back as strings
            this.selections.push(String(selection));

            // clear out pagination and search when we navigate
            this.page = null;
            this.search = null;
        };

        this.setPage = function (page) {
            this.page = page;
        };

        this.setCasesPerPage = function (casesPerPage) {
            this.casesPerPage = casesPerPage;
            this.page = null;
            this.sortIndex = null;
        };

        this.setSort = function (sortIndex) {
            this.sortIndex = sortIndex;
        };

        this.setSearch = function (search) {
            this.search = search;
            //clear out pagination on search
            this.page = null;
            this.sortIndex = null;
        };

        this.setQueryData = function (queryDict, execute, forceManualSearch) {
            var selections = hqImport("cloudcare/js/formplayer/utils/util").currentUrlToObject().selections;
            this.queryData[sessionStorage.queryKey] = _.defaults({
                inputs: queryDict,
                execute: execute,
                force_manual_search: forceManualSearch,
                selections: selections,
            }, this.queryData[sessionStorage.queryKey]);
            this.page = null;
            this.search = null;
        };

        this.setForceManualAction = function (force) {
            this.forceManualAction = force;
        };

        this.replaceEndpoint = function (selections) {
            delete this.endpointId;
            delete this.endpointArgs;
            this.selections = selections || [];
        };

        this.clearExceptApp = function () {
            this.sessionId = null;
            this.selections = null;
            this.page = null;
            this.sortIndex = null;
            this.search = null;
            this.queryData = null;
            this.forceManualAction = null;
        };

        this.onSubmit = function () {
            this.page = null;
            this.sortIndex = null;
            this.search = null;
            this.queryData = null;
            this.forceManualAction = null;
        };

        this.spliceSelections = function (index) {
            // null out the session if we clicked the root (home)
            if (index === 0) {
                this.selections = null;
                this.sessionId = null;
            } else {
                this.selections = this.selections.splice(0, index);
                var key = this.selections.join(",");
                // Query data is necessary to formplayer navigation, so keep it,
                // but only for the selections that are still relevant to the session.
                this.queryData = _.pick(this.queryData, function (value) {
                    var valueKey = value.selections.join(",");
                    return key.startsWith(valueKey) && key !== valueKey;
                });
            }
            this.page = null;
            this.search = null;
            this.sortIndex = null;
            this.queryData = null;
            this.forceManualAction = null;
        };
    };

    Util.CloudcareUrl.prototype.toJson = function () {
        var self = this;
        var dict = {
            appId: self.appId,
            copyOf: self.copyOf,
            endpointId: self.endpointId,
            endpointArgs: self.endpointArgs,
            sessionId: self.sessionId,
            selections: self.selections,
            page: self.page,
            search: self.search,
            queryData: self.queryData || {},    // formplayer can't handle a null
            singleApp: self.singleApp,
            sortIndex: self.sortIndex,
            forceLoginAs: self.forceLoginAs,
            forceManualAction: self.forceManualAction,
        };
        return JSON.stringify(dict);
    };

    Util.CloudcareUrl.fromJson = function (json) {
        var data = JSON.parse(json);
        var options = {
            'appId': data.appId,
            'copyOf': data.copyOf,
            'endpointId': data.endpointId,
            'endpointArgs': data.endpointArgs,
            'sessionId': data.sessionId,
            'selections': data.selections,
            'page': data.page,
            'search': data.search,
            'queryData': data.queryData,
            'singleApp': data.singleApp,
            'sortIndex': data.sortIndex,
            'forceLoginAs': data.forceLoginAs,
            'forceManualAction': data.forceManualAction,
        };
        return new Util.CloudcareUrl(options);
    };

    if (!String.prototype.startsWith) {
        String.prototype.startsWith = function (searchString, position) {
            position = position || 0;
            return this.substr(position, searchString.length) === searchString;
        };
    }

    if (!String.prototype.endsWith) {
        String.prototype.endsWith = function (searchString, position) {
            var subjectString = this.toString();
            if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
                position = subjectString.length;
            }
            position -= searchString.length;
            var lastIndex = subjectString.lastIndexOf(searchString, position);
            return lastIndex !== -1 && lastIndex === position;
        };
    }

    if (!String.prototype.includes) {
        String.prototype.includes = function (search, start) {
            'use strict';
            if (typeof start !== 'number') {
                start = 0;
            }
            if (start + search.length > this.length) {
                return false;
            } else {
                return this.indexOf(search, start) !== -1;
            }
        };
    }

    if (!String.prototype.repeat) {
        String.prototype.repeat = function (count) {
            var result = "",
                string = this.valueOf();
            while (count > 0) {
                result += string;
                count -= 1;
            }
            return result;
        };
    }

    Util.savePerPageLimitCookie = function (name, perPageLimit) {
        var savedPath = window.location.pathname;
        var initialPageData = hqImport("hqwebapp/js/initial_page_data");
        $.cookie(name + '-per-page-limit', perPageLimit, {
            expires: 365,
            path: savedPath,
            secure: initialPageData.get('secure_cookies'),
        });
    };

    return Util;
});
<commit_msg>Renamed var<commit_after>/*global Backbone, DOMPurify */
hqDefine("cloudcare/js/formplayer/utils/util", function () {
    var Util = {};

    /**
     * confirmationModal
     *
     * Takes an options hash that specifies options for a confirmation modal.
     *
     * @param options - Object
     *      {
     *          'title': <title> | 'Confirm?',
     *          'message': <message>,
     *          'confirmText': <confirmText> | 'OK',
     *          'cancelText': <cancelText> | 'Cancel',
     *          'onConfirm': function() {},
     *      }
     */
    Util.confirmationModal = function (options) {
        options = _.defaults(options, {
            title: gettext('Confirm?'),
            message: '',
            confirmText: gettext('OK'),
            cancelText: gettext('Cancel'),
            onConfirm: function () {},
        });
        var $modal = $('#js-confirmation-modal');
        $modal.find('.js-modal-title').text(options.title);
        $modal.find('.js-modal-body').html(DOMPurify.sanitize(options.message));
        $modal.find('#js-confirmation-confirm').text(options.confirmText);
        $modal.find('#js-confirmation-cancel').text(options.cancelText);

        var $confirmationButton = $modal.find('#js-confirmation-confirm');
        $confirmationButton.off('.confirmationModal');
        $confirmationButton.on('click.confirmationModal', function (e) {
            options.onConfirm(e);
        });
        $modal.modal('show');
    };

    Util.encodedUrlToObject = function (encodedUrl) {
        return decodeURIComponent(encodedUrl);
    };

    Util.objectToEncodedUrl = function (object) {
        return encodeURIComponent(object);
    };

    Util.currentUrlToObject = function () {
        var url = Backbone.history.getFragment();
        try {
            return Util.CloudcareUrl.fromJson(Util.encodedUrlToObject(url));
        } catch (e) {
            // This means that we're on the homepage
            return new Util.CloudcareUrl({});
        }
    };

    Util.setUrlToObject = function (urlObject, replace) {
        replace = replace || false;
        var encodedUrl = Util.objectToEncodedUrl(urlObject.toJson());
        hqImport("cloudcare/js/formplayer/app").navigate(encodedUrl, { replace: replace });
    };

    Util.doUrlAction = function (actionCallback) {
        var currentObject = Util.CurrentUrlToObject();
        actionCallback(currentObject);
        Util.setUrlToObject(currentObject);
    };

    Util.setCrossDomainAjaxOptions = function (options) {
        options.type = 'POST';
        options.dataType = "json";
        options.crossDomain = {crossDomain: true};
        options.xhrFields = {withCredentials: true};
        options.contentType = "application/json;charset=UTF-8";
    };

    Util.saveDisplayOptions = function (displayOptions) {
        var displayOptionsKey = Util.getDisplayOptionsKey();
        localStorage.setItem(displayOptionsKey, JSON.stringify(displayOptions));
    };

    Util.getSavedDisplayOptions = function () {
        var displayOptionsKey = Util.getDisplayOptionsKey();
        try {
            return JSON.parse(localStorage.getItem(displayOptionsKey));
        } catch (e) {
            window.console.warn('Unabled to parse saved display options');
            return {};
        }
    };

    Util.getDisplayOptionsKey = function () {
        var user = hqImport("cloudcare/js/formplayer/app").getChannel().request('currentUser');
        return [
            user.environment,
            user.domain,
            user.username,
            'displayOptions',
        ].join(':');
    };

    Util.pagesToShow = function (selectedPage, totalPages, limit) {
        var limitHalf = Math.floor(limit / 2);
        if (totalPages < limit) {
            return {
                start: 0,
                end: totalPages,
            };
        }

        if (selectedPage < limitHalf) {
            return {
                start: 0,
                end: limit,
            };
        }

        if (selectedPage > totalPages - limitHalf) {
            return {
                start: totalPages - limit,
                end: totalPages,
            };
        }

        return {
            start: selectedPage - limitHalf,
            end: selectedPage + limitHalf,
        };
    };

    Util.getCurrentQueryInputs = function () {
        var queryData = Util.currentUrlToObject().queryData[sessionStorage.queryKey];
        if (queryData) {
            return queryData.inputs || {};
        }
        return {};
    };

    Util.getStickyQueryInputs = function () {
        if (!hqImport("hqwebapp/js/toggles").toggleEnabled('WEBAPPS_STICKY_SEARCH')) {
            return {};
        }
        if (!this.stickyQueryInputs) {
            return {};
        }
        return this.stickyQueryInputs[sessionStorage.queryKey] || {};
    };

    Util.setStickyQueryInputs = function (inputs) {
        if (!this.stickyQueryInputs) {
            this.stickyQueryInputs = {};
        }
        this.stickyQueryInputs[sessionStorage.queryKey] = inputs;
    };

    Util.CloudcareUrl = function (options) {
        this.appId = options.appId;
        this.copyOf = options.copyOf;
        this.sessionId = options.sessionId;
        this.selections = options.selections;
        this.endpointId = options.endpointId;
        this.endpointArgs = options.endpointArgs;
        this.page = options.page;
        this.search = options.search;
        this.casesPerPage = options.casesPerPage;
        this.queryData = options.queryData;
        this.singleApp = options.singleApp;
        this.sortIndex = options.sortIndex;
        this.forceLoginAs = options.forceLoginAs;
        this.forceManualAction = options.forceManualAction;

        this.setSelections = function (selections) {
            this.selections = selections;
        };

        this.addSelection = function (selection) {
            if (!this.selections) {
                this.selections = [];
            }

            // Selections only deal with strings, because formplayer will send them back as strings
            this.selections.push(String(selection));

            // clear out pagination and search when we navigate
            this.page = null;
            this.search = null;
        };

        this.setPage = function (page) {
            this.page = page;
        };

        this.setCasesPerPage = function (casesPerPage) {
            this.casesPerPage = casesPerPage;
            this.page = null;
            this.sortIndex = null;
        };

        this.setSort = function (sortIndex) {
            this.sortIndex = sortIndex;
        };

        this.setSearch = function (search) {
            this.search = search;
            //clear out pagination on search
            this.page = null;
            this.sortIndex = null;
        };

        this.setQueryData = function (inputs, execute, forceManualSearch) {
            var selections = hqImport("cloudcare/js/formplayer/utils/util").currentUrlToObject().selections;
            this.queryData[sessionStorage.queryKey] = _.defaults({
                inputs: inputs,
                execute: execute,
                force_manual_search: forceManualSearch,
                selections: selections,
            }, this.queryData[sessionStorage.queryKey]);
            this.page = null;
            this.search = null;
        };

        this.setForceManualAction = function (force) {
            this.forceManualAction = force;
        };

        this.replaceEndpoint = function (selections) {
            delete this.endpointId;
            delete this.endpointArgs;
            this.selections = selections || [];
        };

        this.clearExceptApp = function () {
            this.sessionId = null;
            this.selections = null;
            this.page = null;
            this.sortIndex = null;
            this.search = null;
            this.queryData = null;
            this.forceManualAction = null;
        };

        this.onSubmit = function () {
            this.page = null;
            this.sortIndex = null;
            this.search = null;
            this.queryData = null;
            this.forceManualAction = null;
        };

        this.spliceSelections = function (index) {
            // null out the session if we clicked the root (home)
            if (index === 0) {
                this.selections = null;
                this.sessionId = null;
            } else {
                this.selections = this.selections.splice(0, index);
                var key = this.selections.join(",");
                // Query data is necessary to formplayer navigation, so keep it,
                // but only for the selections that are still relevant to the session.
                this.queryData = _.pick(this.queryData, function (value) {
                    var valueKey = value.selections.join(",");
                    return key.startsWith(valueKey) && key !== valueKey;
                });
            }
            this.page = null;
            this.search = null;
            this.sortIndex = null;
            this.queryData = null;
            this.forceManualAction = null;
        };
    };

    Util.CloudcareUrl.prototype.toJson = function () {
        var self = this;
        var dict = {
            appId: self.appId,
            copyOf: self.copyOf,
            endpointId: self.endpointId,
            endpointArgs: self.endpointArgs,
            sessionId: self.sessionId,
            selections: self.selections,
            page: self.page,
            search: self.search,
            queryData: self.queryData || {},    // formplayer can't handle a null
            singleApp: self.singleApp,
            sortIndex: self.sortIndex,
            forceLoginAs: self.forceLoginAs,
            forceManualAction: self.forceManualAction,
        };
        return JSON.stringify(dict);
    };

    Util.CloudcareUrl.fromJson = function (json) {
        var data = JSON.parse(json);
        var options = {
            'appId': data.appId,
            'copyOf': data.copyOf,
            'endpointId': data.endpointId,
            'endpointArgs': data.endpointArgs,
            'sessionId': data.sessionId,
            'selections': data.selections,
            'page': data.page,
            'search': data.search,
            'queryData': data.queryData,
            'singleApp': data.singleApp,
            'sortIndex': data.sortIndex,
            'forceLoginAs': data.forceLoginAs,
            'forceManualAction': data.forceManualAction,
        };
        return new Util.CloudcareUrl(options);
    };

    if (!String.prototype.startsWith) {
        String.prototype.startsWith = function (searchString, position) {
            position = position || 0;
            return this.substr(position, searchString.length) === searchString;
        };
    }

    if (!String.prototype.endsWith) {
        String.prototype.endsWith = function (searchString, position) {
            var subjectString = this.toString();
            if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
                position = subjectString.length;
            }
            position -= searchString.length;
            var lastIndex = subjectString.lastIndexOf(searchString, position);
            return lastIndex !== -1 && lastIndex === position;
        };
    }

    if (!String.prototype.includes) {
        String.prototype.includes = function (search, start) {
            'use strict';
            if (typeof start !== 'number') {
                start = 0;
            }
            if (start + search.length > this.length) {
                return false;
            } else {
                return this.indexOf(search, start) !== -1;
            }
        };
    }

    if (!String.prototype.repeat) {
        String.prototype.repeat = function (count) {
            var result = "",
                string = this.valueOf();
            while (count > 0) {
                result += string;
                count -= 1;
            }
            return result;
        };
    }

    Util.savePerPageLimitCookie = function (name, perPageLimit) {
        var savedPath = window.location.pathname;
        var initialPageData = hqImport("hqwebapp/js/initial_page_data");
        $.cookie(name + '-per-page-limit', perPageLimit, {
            expires: 365,
            path: savedPath,
            secure: initialPageData.get('secure_cookies'),
        });
    };

    return Util;
});
<|endoftext|>


<commit_before>module.exports = function (bb8,options) {
 var radius = options.radius; //mm
 var distance = 2*Math.PI*radius;
 var colors = ["red","green"];
 var i = 0;
 return setInterval(function() {
    var direction = 30;
    bb8.roll(Math.floor(distance/12),direction*i);
    var chosen = (function(){
      if (Math.random() > 0.5) {
        return 1;
       } else {
        return 0;
       }
    })();
    bb8.color(colors[chosen]);
    i++;
    if (i>11) {
        i = 0;
    }
 }, 500);
};
<commit_msg>fixing counter name and adding lodash to color sampler<commit_after>module.exports = function (bb8,options) {
    var radius = options.radius; //mm
    var distance = 2*Math.PI*radius;
    var colors = ["red","green"];
    var angle_counter = 0;
    var direction = 30;
    return setInterval(function() {
        bb8.roll(Math.floor(distance/12),direction*angle_counter);
        bb8.color(_.sample(colors));
        angle_counter++;
        if (angle_counter>11) {
            angle_counter = 0;
        }
    }, 500);
};
<|endoftext|>


<commit_before>var game = require('../game');
var gameStatus = require('../status');
var utils = require('../../../utils');
var throttle = require('lodash-node/modern/functions/throttle');
var i18n = require('../../../i18n');

module.exports = {
  standard: function(ctrl, condition, icon, hint, socketMsg) {
    return condition(ctrl.data) ? m('button[data-icon=' + icon + ']', {
      config: utils.ontouchend(utils.ƒ(ctrl.socket.send, socketMsg, null))
    }, i18n(hint)) : null;
  },
  forceResign: function(ctrl) {
    return game.forceResignable(ctrl.data) ?
      m('div.force_resign_zone', [
        i18n('theOtherPlayerHasLeftTheGameYouCanForceResignationOrWaitForHim'),
        m('br'),
        m('button[data-icon=E]', {
          config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'resign-force', null)),
        }, i18n('forceResignation')),
        m('button[data-icon=E]', {
          config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-force', null)),
        }, i18n('forceDraw'))
      ]) : null;
  },
  threefoldClaimDraw: function(ctrl) {
    return (ctrl.data.game.threefold) ? m('div.claim_draw_zone', [
      i18n('threefoldRepetition'),
      m.trust(' '),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-claim', null))
      }, i18n('claimADraw'))
    ]) : null;
  },
  cancelDrawOffer: function(ctrl) {
    if (ctrl.data.player.offeringDraw) return m('div.negotiation', [
      i18n('drawOfferSent') + ' ',
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-no', null))
      }, i18n('cancel'))
    ]);
  },
  answerOpponentDrawOffer: function(ctrl) {
    if (ctrl.data.opponent.offeringDraw) return m('div.negotiation', [
      i18n('yourOpponentOffersADraw'),
      m('br'),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-yes', null))
      }, i18n('accept')),
      m.trust(' '),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-no', null))
      }, i18n('decline')),
    ]);
  },
  cancelTakebackProposition: function(ctrl) {
    if (ctrl.data.player.proposingTakeback) return m('div.negotiation', [
      i18n('takebackPropositionSent') + ' ',
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'takeback-no', null))
      }, i18n('cancel'))
    ]);
  },
  answerOpponentTakebackProposition: function(ctrl) {
    if (ctrl.data.opponent.proposingTakeback) return m('div.negotiation', [
      i18n('yourOpponentProposesATakeback'),
      m('br'),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'takeback-yes', null))
      }, i18n('accept')),
      m.trust(' '),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'takeback-no', null))
      }, i18n('decline')),
    ]);
  },
  rematch: function(ctrl) {
    if ((gameStatus.finished(ctrl.data) || gameStatus.aborted(ctrl.data)) && !ctrl.data.tournament) {
      if (ctrl.data.opponent.onGame || ctrl.data.game.perf === 'correspondence') {
        return m('button[data-icon=B]', {
          config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-yes', null))
        }, i18n('rematch'));
      } else {
        return null;
      }
    }
  },
  answerOpponentRematch: function(ctrl) {
    if (ctrl.data.opponent.offeringRematch) return [
      i18n('yourOpponentWantsToPlayANewGameWithYou'),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-yes', null))
      }, i18n('joinTheGame')),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-no', null))
      }, i18n('declineInvitation'))
    ];
  },
  cancelRematch: function(ctrl) {
    if (ctrl.data.player.offeringRematch) return [
      i18n('rematchOfferSent'),
      m('br'),
      i18n('waitingForOpponent'),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-no', null))
      }, i18n('cancelRematchOffer'))
    ];
  },
  joinRematch: function(ctrl) {
    if (ctrl.data.game.rematch) return [
      i18n('rematchOfferAccepted'),
      m('button[data-icon=E]', {}, i18n('joinTheGame'))
    ];
  },
  moretime: function(ctrl) {
    if (game.moretimeable(ctrl.data)) return m('button[data-icon=O]', {
      config: utils.ontouchend(throttle(utils.ƒ(ctrl.socket.send, 'moretime', null), 600))
    }, i18n('giveNbSeconds', 15));
  }
};
<commit_msg>minor rematch style fix<commit_after>var game = require('../game');
var gameStatus = require('../status');
var utils = require('../../../utils');
var throttle = require('lodash-node/modern/functions/throttle');
var i18n = require('../../../i18n');

module.exports = {
  standard: function(ctrl, condition, icon, hint, socketMsg) {
    return condition(ctrl.data) ? m('button[data-icon=' + icon + ']', {
      config: utils.ontouchend(utils.ƒ(ctrl.socket.send, socketMsg, null))
    }, i18n(hint)) : null;
  },
  forceResign: function(ctrl) {
    return game.forceResignable(ctrl.data) ?
      m('div.force_resign_zone', [
        i18n('theOtherPlayerHasLeftTheGameYouCanForceResignationOrWaitForHim'),
        m('br'),
        m('button[data-icon=E]', {
          config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'resign-force', null)),
        }, i18n('forceResignation')),
        m('button[data-icon=E]', {
          config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-force', null)),
        }, i18n('forceDraw'))
      ]) : null;
  },
  threefoldClaimDraw: function(ctrl) {
    return (ctrl.data.game.threefold) ? m('div.claim_draw_zone', [
      i18n('threefoldRepetition'),
      m.trust(' '),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-claim', null))
      }, i18n('claimADraw'))
    ]) : null;
  },
  cancelDrawOffer: function(ctrl) {
    if (ctrl.data.player.offeringDraw) return m('div.negotiation', [
      i18n('drawOfferSent') + ' ',
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-no', null))
      }, i18n('cancel'))
    ]);
  },
  answerOpponentDrawOffer: function(ctrl) {
    if (ctrl.data.opponent.offeringDraw) return m('div.negotiation', [
      i18n('yourOpponentOffersADraw'),
      m('br'),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-yes', null))
      }, i18n('accept')),
      m.trust(' '),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'draw-no', null))
      }, i18n('decline')),
    ]);
  },
  cancelTakebackProposition: function(ctrl) {
    if (ctrl.data.player.proposingTakeback) return m('div.negotiation', [
      i18n('takebackPropositionSent') + ' ',
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'takeback-no', null))
      }, i18n('cancel'))
    ]);
  },
  answerOpponentTakebackProposition: function(ctrl) {
    if (ctrl.data.opponent.proposingTakeback) return m('div.negotiation', [
      i18n('yourOpponentProposesATakeback'),
      m('br'),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'takeback-yes', null))
      }, i18n('accept')),
      m.trust(' '),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'takeback-no', null))
      }, i18n('decline')),
    ]);
  },
  rematch: function(ctrl) {
    if ((gameStatus.finished(ctrl.data) || gameStatus.aborted(ctrl.data)) && !ctrl.data.tournament) {
      if (ctrl.data.opponent.onGame || ctrl.data.game.perf === 'correspondence') {
        return m('button[data-icon=B]', {
          config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-yes', null))
        }, i18n('rematch'));
      } else {
        return null;
      }
    }
  },
  answerOpponentRematch: function(ctrl) {
    if (ctrl.data.opponent.offeringRematch) return [
      i18n('yourOpponentWantsToPlayANewGameWithYou'),
      m('br'),
      m('button[data-icon=E]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-yes', null))
      }, i18n('joinTheGame')),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-no', null))
      }, i18n('declineInvitation'))
    ];
  },
  cancelRematch: function(ctrl) {
    if (ctrl.data.player.offeringRematch) return [
      i18n('rematchOfferSent'),
      m('br'),
      i18n('waitingForOpponent'),
      m('button[data-icon=L]', {
        config: utils.ontouchend(utils.ƒ(ctrl.socket.send, 'rematch-no', null))
      }, i18n('cancelRematchOffer'))
    ];
  },
  joinRematch: function(ctrl) {
    if (ctrl.data.game.rematch) return [
      i18n('rematchOfferAccepted'),
      m('button[data-icon=E]', {}, i18n('joinTheGame'))
    ];
  },
  moretime: function(ctrl) {
    if (game.moretimeable(ctrl.data)) return m('button[data-icon=O]', {
      config: utils.ontouchend(throttle(utils.ƒ(ctrl.socket.send, 'moretime', null), 600))
    }, i18n('giveNbSeconds', 15));
  }
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

'use strict';

const Platform = require('../../Utilities/Platform');
const React = require('react');

import type {ColorValue} from '../../StyleSheet/StyleSheetTypes';
import type {ViewProps} from '../View/ViewPropTypes';
import AndroidSwipeRefreshLayoutNativeComponent, {
  Commands as AndroidSwipeRefreshLayoutCommands,
} from './AndroidSwipeRefreshLayoutNativeComponent';
import PullToRefreshViewNativeComponent, {
  Commands as PullToRefreshCommands,
} from './PullToRefreshViewNativeComponent';

let RefreshLayoutConsts: any;
if (Platform.OS === 'android') {
  const AndroidSwipeRefreshLayout = require('../../ReactNative/UIManager').getViewManagerConfig(
    'AndroidSwipeRefreshLayout',
  );
  RefreshLayoutConsts = AndroidSwipeRefreshLayout
    ? AndroidSwipeRefreshLayout.Constants
    : {SIZE: {}};
} else {
  RefreshLayoutConsts = {SIZE: {}};
}

type IOSProps = $ReadOnly<{|
  /**
   * The color of the refresh indicator.
   */
  tintColor?: ?ColorValue,
  /**
   * Title color.
   */
  titleColor?: ?ColorValue,
  /**
   * The title displayed under the refresh indicator.
   */
  title?: ?string,
|}>;

type AndroidProps = $ReadOnly<{|
  /**
   * Whether the pull to refresh functionality is enabled.
   */
  enabled?: ?boolean,
  /**
   * The colors (at least one) that will be used to draw the refresh indicator.
   */
  colors?: ?$ReadOnlyArray<ColorValue>,
  /**
   * The background color of the refresh indicator.
   */
  progressBackgroundColor?: ?ColorValue,
  /**
   * Size of the refresh indicator, see RefreshControl.SIZE.
   */
  size?: ?(
    | typeof RefreshLayoutConsts.SIZE.DEFAULT
    | typeof RefreshLayoutConsts.SIZE.LARGE
  ),
  /**
   * Progress view top offset
   */
  progressViewOffset?: ?number,
|}>;

export type RefreshControlProps = $ReadOnly<{|
  ...ViewProps,
  ...IOSProps,
  ...AndroidProps,

  /**
   * Called when the view starts refreshing.
   */
  onRefresh?: ?() => void,

  /**
   * Whether the view should be indicating an active refresh.
   */
  refreshing: boolean,
|}>;

/**
 * This component is used inside a ScrollView or ListView to add pull to refresh
 * functionality. When the ScrollView is at `scrollY: 0`, swiping down
 * triggers an `onRefresh` event.
 *
 * ### Usage example
 *
 * ``` js
 * class RefreshableList extends Component {
 *   constructor(props) {
 *     super(props);
 *     this.state = {
 *       refreshing: false,
 *     };
 *   }
 *
 *   _onRefresh() {
 *     this.setState({refreshing: true});
 *     fetchData().then(() => {
 *       this.setState({refreshing: false});
 *     });
 *   }
 *
 *   render() {
 *     return (
 *       <ListView
 *         refreshControl={
 *           <RefreshControl
 *             refreshing={this.state.refreshing}
 *             onRefresh={this._onRefresh.bind(this)}
 *           />
 *         }
 *         ...
 *       >
 *       ...
 *       </ListView>
 *     );
 *   }
 *   ...
 * }
 * ```
 *
 * __Note:__ `refreshing` is a controlled prop, this is why it needs to be set to true
 * in the `onRefresh` function otherwise the refresh indicator will stop immediately.
 */
class RefreshControl extends React.Component<RefreshControlProps> {
  static SIZE: any = RefreshLayoutConsts.SIZE;

  _nativeRef: ?React.ElementRef<
    | typeof PullToRefreshViewNativeComponent
    | typeof AndroidSwipeRefreshLayoutNativeComponent,
  >;
  _lastNativeRefreshing = false;

  componentDidMount() {
    this._lastNativeRefreshing = this.props.refreshing;
  }

  componentDidUpdate(prevProps: RefreshControlProps) {
    // RefreshControl is a controlled component so if the native refreshing
    // value doesn't match the current js refreshing prop update it to
    // the js value.
    if (this.props.refreshing !== prevProps.refreshing) {
      this._lastNativeRefreshing = this.props.refreshing;
    } else if (
      this.props.refreshing !== this._lastNativeRefreshing &&
      this._nativeRef
    ) {
      if (Platform.OS === 'android') {
        AndroidSwipeRefreshLayoutCommands.setNativeRefreshing(
          this._nativeRef,
          this.props.refreshing,
        );
      } else {
        PullToRefreshCommands.setNativeRefreshing(
          this._nativeRef,
          this.props.refreshing,
        );
      }
      this._lastNativeRefreshing = this.props.refreshing;
    }
  }

  render(): React.Node {
    if (Platform.OS === 'ios') {
      const {
        enabled,
        colors,
        progressBackgroundColor,
        size,
        progressViewOffset,
        ...props
      } = this.props;
      return (
        <PullToRefreshViewNativeComponent
          {...props}
          ref={this._setNativeRef}
          onRefresh={this._onRefresh}
        />
      );
    } else {
      const {tintColor, titleColor, title, ...props} = this.props;
      return (
        <AndroidSwipeRefreshLayoutNativeComponent
          {...props}
          ref={this._setNativeRef}
          onRefresh={this._onRefresh}
        />
      );
    }
  }

  _onRefresh = () => {
    this._lastNativeRefreshing = true;

    this.props.onRefresh && this.props.onRefresh();

    // The native component will start refreshing so force an update to
    // make sure it stays in sync with the js component.
    this.forceUpdate();
  };

  _setNativeRef = (
    ref: ?React.ElementRef<
      | typeof PullToRefreshViewNativeComponent
      | typeof AndroidSwipeRefreshLayoutNativeComponent,
    >,
  ) => {
    this._nativeRef = ref;
  };
}

module.exports = RefreshControl;
<commit_msg>change onRefresh flow typing (#28167)<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

'use strict';

const Platform = require('../../Utilities/Platform');
const React = require('react');

import type {ColorValue} from '../../StyleSheet/StyleSheetTypes';
import type {ViewProps} from '../View/ViewPropTypes';
import AndroidSwipeRefreshLayoutNativeComponent, {
  Commands as AndroidSwipeRefreshLayoutCommands,
} from './AndroidSwipeRefreshLayoutNativeComponent';
import PullToRefreshViewNativeComponent, {
  Commands as PullToRefreshCommands,
} from './PullToRefreshViewNativeComponent';

let RefreshLayoutConsts: any;
if (Platform.OS === 'android') {
  const AndroidSwipeRefreshLayout = require('../../ReactNative/UIManager').getViewManagerConfig(
    'AndroidSwipeRefreshLayout',
  );
  RefreshLayoutConsts = AndroidSwipeRefreshLayout
    ? AndroidSwipeRefreshLayout.Constants
    : {SIZE: {}};
} else {
  RefreshLayoutConsts = {SIZE: {}};
}

type IOSProps = $ReadOnly<{|
  /**
   * The color of the refresh indicator.
   */
  tintColor?: ?ColorValue,
  /**
   * Title color.
   */
  titleColor?: ?ColorValue,
  /**
   * The title displayed under the refresh indicator.
   */
  title?: ?string,
|}>;

type AndroidProps = $ReadOnly<{|
  /**
   * Whether the pull to refresh functionality is enabled.
   */
  enabled?: ?boolean,
  /**
   * The colors (at least one) that will be used to draw the refresh indicator.
   */
  colors?: ?$ReadOnlyArray<ColorValue>,
  /**
   * The background color of the refresh indicator.
   */
  progressBackgroundColor?: ?ColorValue,
  /**
   * Size of the refresh indicator, see RefreshControl.SIZE.
   */
  size?: ?(
    | typeof RefreshLayoutConsts.SIZE.DEFAULT
    | typeof RefreshLayoutConsts.SIZE.LARGE
  ),
  /**
   * Progress view top offset
   */
  progressViewOffset?: ?number,
|}>;

export type RefreshControlProps = $ReadOnly<{|
  ...ViewProps,
  ...IOSProps,
  ...AndroidProps,

  /**
   * Called when the view starts refreshing.
   */
  onRefresh?: ?() => void | Promise<void>,

  /**
   * Whether the view should be indicating an active refresh.
   */
  refreshing: boolean,
|}>;

/**
 * This component is used inside a ScrollView or ListView to add pull to refresh
 * functionality. When the ScrollView is at `scrollY: 0`, swiping down
 * triggers an `onRefresh` event.
 *
 * ### Usage example
 *
 * ``` js
 * class RefreshableList extends Component {
 *   constructor(props) {
 *     super(props);
 *     this.state = {
 *       refreshing: false,
 *     };
 *   }
 *
 *   _onRefresh() {
 *     this.setState({refreshing: true});
 *     fetchData().then(() => {
 *       this.setState({refreshing: false});
 *     });
 *   }
 *
 *   render() {
 *     return (
 *       <ListView
 *         refreshControl={
 *           <RefreshControl
 *             refreshing={this.state.refreshing}
 *             onRefresh={this._onRefresh.bind(this)}
 *           />
 *         }
 *         ...
 *       >
 *       ...
 *       </ListView>
 *     );
 *   }
 *   ...
 * }
 * ```
 *
 * __Note:__ `refreshing` is a controlled prop, this is why it needs to be set to true
 * in the `onRefresh` function otherwise the refresh indicator will stop immediately.
 */
class RefreshControl extends React.Component<RefreshControlProps> {
  static SIZE: any = RefreshLayoutConsts.SIZE;

  _nativeRef: ?React.ElementRef<
    | typeof PullToRefreshViewNativeComponent
    | typeof AndroidSwipeRefreshLayoutNativeComponent,
  >;
  _lastNativeRefreshing = false;

  componentDidMount() {
    this._lastNativeRefreshing = this.props.refreshing;
  }

  componentDidUpdate(prevProps: RefreshControlProps) {
    // RefreshControl is a controlled component so if the native refreshing
    // value doesn't match the current js refreshing prop update it to
    // the js value.
    if (this.props.refreshing !== prevProps.refreshing) {
      this._lastNativeRefreshing = this.props.refreshing;
    } else if (
      this.props.refreshing !== this._lastNativeRefreshing &&
      this._nativeRef
    ) {
      if (Platform.OS === 'android') {
        AndroidSwipeRefreshLayoutCommands.setNativeRefreshing(
          this._nativeRef,
          this.props.refreshing,
        );
      } else {
        PullToRefreshCommands.setNativeRefreshing(
          this._nativeRef,
          this.props.refreshing,
        );
      }
      this._lastNativeRefreshing = this.props.refreshing;
    }
  }

  render(): React.Node {
    if (Platform.OS === 'ios') {
      const {
        enabled,
        colors,
        progressBackgroundColor,
        size,
        progressViewOffset,
        ...props
      } = this.props;
      return (
        <PullToRefreshViewNativeComponent
          {...props}
          ref={this._setNativeRef}
          onRefresh={this._onRefresh}
        />
      );
    } else {
      const {tintColor, titleColor, title, ...props} = this.props;
      return (
        <AndroidSwipeRefreshLayoutNativeComponent
          {...props}
          ref={this._setNativeRef}
          onRefresh={this._onRefresh}
        />
      );
    }
  }

  _onRefresh = () => {
    this._lastNativeRefreshing = true;

    this.props.onRefresh && this.props.onRefresh();

    // The native component will start refreshing so force an update to
    // make sure it stays in sync with the js component.
    this.forceUpdate();
  };

  _setNativeRef = (
    ref: ?React.ElementRef<
      | typeof PullToRefreshViewNativeComponent
      | typeof AndroidSwipeRefreshLayoutNativeComponent,
    >,
  ) => {
    this._nativeRef = ref;
  };
}

module.exports = RefreshControl;
<|endoftext|>