// Funcom Custom Submit Form
/**
* From Perforce Public Depot
*
* checkAll(theName, theChecked): Handy utility function that takes a value returned
* from a clicked checkbox and toggles all of the checkboxes for the associated
* checklist.
*/
function checkAll(theName, theChecked) {
var toToggle = document.getElementsByName(theName + 'Box');
for (var i = 0; i < toToggle.length; i++) {
toToggle[i].checked = theChecked;
}
}
/**
* From Perforce Public Depot
*
* Loads the current changelist that the submit is for into an
* object literal with the key/value pairs of the current
* changelist.
*
* @return - object literal of current changelist data
*/
function getChange() {
var changelist = {};
try {
var clNumber = P4JsApi.getSubmitChange();
if (clNumber && parseInt(clNumber) > 0) {
var changelistData = P4JsApi.p4("describe " + clNumber);
if (changelistData) {
changelist = changelistData;
}
}
else {
var changelistData = P4JsApi.p4("change -o");
if (changelistData) {
changelist = changelistData;
}
}
} catch(e) {
changelist = {};
}
return (changelist.data && changelist.data[0]) ? changelist.data[0] : {};
}
/**
* From the Perforce Public Depot
*
* Gets all occurrences of an incrementing key sequence from the specified JSON data object.
* This method looks for properties in the specified data object starting at key+index where
* index starts at zero and increments until no property is found by key+index in data.
*
*
* @param data - Object to index into for specified key
* @param key - incrementing key sequence
*
* @return - non-null but possibly empty array of value found by the specified incrementing key
*/
function getEntries(data, key) {
var entries = [];
if (data && key) {
if (data[key]) {
// For handling data from commands like p4 opened
entries.push(data[key]);
} else {
// For handling data from commands like p4 describe
var index = 0;
while (data[key + index]) {
entries.push(data[key + index]);
index++;
}
}
}
return entries;
}
/**
* From the Perforce Public Depot
*
* getCheckList(theField): Passing the name of a checklist ('jobs' or 'files')
* returns a newline delimited list, each line padded with a tab to make it
* changelist legal.
*/
function getCheckList(theField) {
var boxes = document.getElementsByName(theField + 'Box');
var result = "";
for (var i = 0; i < boxes.length; i++) {
if (boxes[i].checked) {
result = result + "\n\t" + boxes[i].value;
}
}
return result;
}
/**
* From the Perforce Public Depot
*
* getSubmitOptions(): Uses both the drop down menu and the "check out files after
* submit" checkbox to create the "-f" arguments for submitting the change.
*/
function getSubmitOptions() {
var fileOpt = "";
switch (document.getElementById("fileoption_submit").value) {
case 'Submit all selected files':
fileOpt = "submitunchanged";
break;
case 'Don\'t submit unchanged files':
fileOpt = "leaveunchanged";
break;
case 'Revert unchanged files':
fileOpt = "revertunchanged";
break;
}
if (document.getElementById("recheckout").checked) {
fileOpt = fileOpt + "+reopen";
}
var options = " -f " + fileOpt;
return options;
}
// InitializeForm: This is called when the Submit form loads.
// submitForm() in the original code
function InitializeForm() {
// Set the initial state of the checkboxes
SetDefaultOptions();
// Load the current changelist. This object does not know if the changelist is numbered or not.
var CurrentChangelist = getChange();
// Create the file list
var Files;
// The dreaded changelist number is here
// It can either be a number or the literal string "default"
// These need to be handled differently!
var ChangelistNumber = P4JsApi.getSubmitChange();
// Distinguish between numbered and default changelists
if ( (ChangelistNumber == "default") || (ChangelistNumber == "new") ) {
// This is the default changelist
// The information we get from this changelist is partial and needs to be manually filled
// with some Perforce manual changelist writing.
// First thing: the file list. In the default changelist, the files are read with
// p4 change -o
// Which has an output in format "Files0 <filename>\nFiles1 <filename>\n...FilesN <filename>\n"
// We can use getEntries from the Perforce Depot to decode this easily
// Populate the file list
Files = getEntries(CurrentChangelist, "Files");
// Populate the actual file list in the HTML page
document.getElementById("filelist").innerHTML = LoadFilelist(Files, "Files", true, null, null, null);
}
else {
// Make sure we got an actual number from Perforce and something that is not null
if (ChangelistNumber && parseInt(ChangelistNumber) > 0) {
// See above. Numbered changelists return files in a different format than default changelists
// Analyze the changelist
Files = getEntries(CurrentChangelist, "depotFile");
var Types = getEntries(CurrentChangelist, "type");
var Revisions = getEntries(CurrentChangelist, "rev");
var Actions = getEntries(CurrentChangelist, "action");
// Populate the actual file list in the HTML page
document.getElementById("filelist").innerHTML = LoadFilelist(Files, "Files", true, Revisions, Types, Actions);
}
}
// Hide additional information inside the document object, for later use.
document.getElementById("description").value = CurrentChangelist.Description;
document.getElementById("change").value = CurrentChangelist.Change;
document.getElementById("user").value = CurrentChangelist.User;
document.getElementById("client").value = CurrentChangelist.Client;
document.getElementById("status").value = CurrentChangelist.Status;
}
// LoadFileList: Generates the HTML required to display the filelist in the HTML page.
// List is the filelist object
// Label is the string header of the list
// IsDefault is true if the Changelist is the default one, false if it's a numbered one
// Revision is the File Revision list (applies to numbered changelists only)
// Type is the File type (applies to numbered changelists only)
// Action is the Action for each File in the File list (applies to numbered changelists only)
function LoadFilelist(List, Label, IsDefault, Revisions, Types, Actions) {
// HTML container
var HTMLChecklist = "";
// Automatic ticking of all checkboxes for each added file
var CheckState = "checked=\"checked\"";
// Iterate through the list of files
for (var i = 0; i < List.length; i++) {
// Alternate between the rows to create a color pattern
if (i % 2) {
var RowClass = " class=\"alt-row\" ";
}
else {
var RowClass = "";
}
// We want to create HTML that is generically of this format:
// <li {class="alt-row"}>
// <label for="RFiles1234" \>
// <input id="RFiles1234" type="checkbox" {checked="checked"}
// name="FilesBox value="{file path}" />
// {file path}#123 <font color="#999999"> ({file type}) {file action}
// </font></label></li>
// However the default changelist has less information available, so the file path, type and action
// are going to be excluded from the HTML
if (IsDefault == true) {
// Append HTML code
HTMLChecklist = HTMLChecklist + '<li ' + RowClass + '>' +
'<label for=\"R' + Label + i + '\">' +
'<input id=\"R' + Label + i + '\" type=\"checkbox\" ' + CheckState +
' name=\"' + Label + 'Box\" value=\"' + List[i] + '\" />' +
List[i] + '</label></li>\n';
}
else {
// Append HTML code
HTMLChecklist = HTMLChecklist + '<li ' + RowClass + '>' +
'<label for=\"R' + Label + i + '\">' +
'<input id=\"R' + Label + i + '\" type=\"checkbox\" ' + CheckState +
' name=\"' + Label + 'Box\" value=\"' + List[i] + '\" />' +
List[i] + '#' + Revisions[i] + '<font color=\"#999999\"> (' + Types[i] + ') ' + Actions[i] + '</font>' +
'</label></li>\n';
}
}
return HTMLChecklist;
}
// SaveChangelist: Saves the current changelist as a numbered changelist. If it already has a number, it just saves it.
function SaveChangelist() {
var ChangelistNumber = P4JsApi.getSubmitChange();
var P4Form = "";
// Different treatment if the Changelist is the default one or not.
if ( (ChangelistNumber == "default") || (ChangelistNumber == "new") ) {
// Generate the form to submit to P4
P4Form = CreateP4Form(true, false);
}
else {
// Always check to have a parsable non null
if (ChangelistNumber && parseInt(ChangelistNumber) > 0) {
// Generate the form to submit to P4
P4Form = CreateP4Form(false, false);
}
}
// If we actually managed to create a P4 form, finally save it.
if (P4Form != "") {
var Result = P4JsApi.p4('change -i "' + P4Form + '"');
if (Result.error) {
alert("Perforce error: " + Result.error);
}
else {
P4JsApi.refreshAll();
P4JsApi.accepted();
}
}
}
// CreateP4Form: Creates a valid changelist form which can be submitted to p4
// to SAVE or SUBMIT the changelist.
// IsDefault is true if the changelist is the default changelist, false otherwise
// ToBeSubmitted is true if this form is also being submitted, false otherwise.
function CreateP4Form(IsDefault, ToBeSubmitted) {
// Retrieve the data that was stored in the document object
var Changelist = document.getElementById("change").value;
var User = document.getElementById("user").value;
var Client = document.getElementById("client").value;
var Status = document.getElementById("status").value;
var Description = document.getElementById("description").value;
// Manipulate the Description.
if (!Description) {
// The field is empty. Create anyway a valid description
Description = "No description was given for this changelist.";
}
if (Description.indexOf("<enter description here>") > -1 ) {
// The field is invalid. Create anyway a valid description
Description = "No description was given for this changelist.";
}
// Split the Description by new lines.
// We want to format the Description correctly.
var DescriptionTokens = Description.split("\n");
// Construct the formatted Description
// Format the Description so it fits Perforce requirements for formatting.
// Description:\n
// \tLine1\n
// \tLine2\n
// \tLineN\n
// \n
// It always starts with \n but it will be appended by the changelist generator at the end
var FormattedDescription = "";
// Add a tabbed line for each description line
for (var i = 0; i < DescriptionTokens.length; i++) {
FormattedDescription = FormattedDescription + "\t" + DescriptionTokens[i] + "\n";
}
// If the form needs to be submitted, add the issue tracker link.
if (ToBeSubmitted) {
var JiraLink = GetJiraLink();
if (JiraLink != "") {
FormattedDescription = FormattedDescription + "\t" + JiraLink + "\n";
}
}
// Remove any error message in the HTML form for the description
document.getElementById("desc_header").innerHTML = " ";
var Files;
if (IsDefault) {
// The files, again, need to be fetched differently if the changelist is default or not
// We have to reparse the default changelist again
var TempChangelist = getChange();
var TempList = getEntries(TempChangelist, "Files");
// Create an empty string
Files = "";
// Construct the file list from the default changelist
for (var i = 0; i < TempList.length; i++) {
Files = Files + '\t' + TempList[i] + '\t\n';
}
}
else {
// Get a list of files using the library from Perforce:
Files = getCheckList("Files");
}
// At this point, Files is filled with our file list, and it's perforce compatible.
// If the Files list is empty, display an error.
if (!Files) {
document.getElementById("files_header").innerHTML = "Select files to submit:";
alert("You cannot save a changelist that does not contain any files.\nPlease select at least one file from the list.");
return "";
}
// Remove any error message in the HTML form for the file list
document.getElementById("files_header").innerHTML = " ";
// Build the changelist, making sure that at least Description and Files are not null
if (Description && Files) {
var SavableForm = "Change:\t" + Changelist + "\n" +
"Client:\t" + Client + "\n" +
"User:\t" + User + "\n" +
"Status:\t " + Status + "\n" +
"Description:\n" + FormattedDescription + "\n" +
"Files:\n" + Files;
return SavableForm;
}
else {
return "";
}
}
// SubmitChangelist: Submits the current Changelist.
function SubmitChangelist() {
var P4Form;
var ChangelistNumber = document.getElementById("change").value;
var SubmitOptions = getSubmitOptions();
if ( (ChangelistNumber == "default") || (ChangelistNumber == "new") ) {
// Create a P4 default changelist form
P4Form = CreateP4Form(true, true);
// Get the changelist number from change -i
var Result = P4JsApi.p4('change -i "' + P4Form + '"');
// Parse the output to get the number
var NewChangelistNumber = Result.data[0].info.split(" ", 2)[1];
// Submit the now numbered changelist
P4JsApi.p4('submit -c ' + NewChangelistNumber + SubmitOptions);
}
else {
// Create a P4 numbered changelist form
P4Form = CreateP4Form(false, true);
P4JsApi.p4('change -i "' + P4Form + '"');
P4JsApi.p4('submit -c ' + ChangelistNumber + SubmitOptions);
}
P4JsApi.refreshAll();
P4JsApi.accepted();
}
// GetJiraLink: Returns the specified JIRA link, if any.
function GetJiraLink(){
var JiraLink = document.getElementById("jiraissue").value;
if (JiraLink == "") {
return "";
}
else {
return JiraLink;
}
}