// Dialog to handle creating a connection
// Init should be called on page initialization
// open should be triggered by connectors being drawn.
Mjs.Dialogs.CreateConnector = {
open: function(source, target){
Mjs.Dialogs.CreateConnector._open(source, target);
},
init: function() {
$( "#radio1" ).button({
text: false,
icons: {
primary: 'ui-icon-arrowthick-1-e'
}
});
$( "#radio2" ).button({
text: false,
icons: {
primary: 'ui-icon-arrowthick-2-e-w'
}
});
$( "#radio3" ).button({
text: false,
icons: {
primary: 'ui-icon-arrowthick-1-w'
}
});
var dialogLayout = false;
var dialogLayout_settings = {
// HANDLE BUG IN CHROME - required if using 'modal'
// (background mask)
zIndex: 0,
// resizes with the dialog, not the window
resizeWithWindow: false,
spacing_open: 1,
spacing_closed: 1,
closable: false,
resizable: false,
slidable: false ,
west__size: '47%',
east__size: '48%',
south__size: 'auto',
south__closable: false,
south__resizable: false,
south__slidable: false,
north__size: 'auto',
north__closable: false,
north__resizable: false,
north__slidable: false
//applyDefaultStyles: true // DEBUGGING
};
// browser branches is only loaded within this dialog
$( "#browse_branch" )
.button()
.click(function() {
Mjs.Dialogs.BrowseBranches.open({
// when the dialog closes, set our value
onFinish : Mjs.Dialogs.CreateConnector._updateBranchViewPaths
});
});
$( "#dialog-create-connector" ).dialog({
autoOpen: false, // don't open right away, since we're
// really just configuring
width: 900,
height: 500,
modal: true,
buttons: {
Finish: function() {
Mjs.Dialogs.CreateConnector._buttonFinish(this);
},
Cancel: function() {$( this ).dialog( "close" );}
},
close: function() {
$( "#branch_name" ).val( "" ).removeClass( "ui-state-error" );
// get rid of the key up event for handling the enter key
// as triggering the finish button
$(this).data().dialog.uiDialog.disableEnterKeyHandling();
},
open: function() {
// for validation later
var depotCallback = function(depotsArray) {
$('#dialog-create-connector').data('depotsArray', depotsArray);
};
P4JsApi.p4("depots", depotCallback);
// handle keyup for enter triggering finish
var me = this;
$(this).data().dialog.uiDialog.handleEnterKey(function() {
Mjs.Dialogs.CreateConnector._buttonFinish(me);
});
// 'this' refers to the jQuery Dialog DOM element
// dE means DialogElement
var dE = this;
var bnEl = $( "#branch_name", dE );
bnEl.focus();
bnEl.val( "" ).removeClass( "ui-state-error" );
// Get the stored result
var params = $(this).data('sourceAndTarget');
$("#source_name").val($("#" + params.source).text());
$("#target_name").val($("#" + params.target).text());
// if there is no layout, make sure we init it,
// otherwise resize the dialog
if (!dialogLayout) {
// init layout *the first time* dialog opens
dialogLayout = $("#dialog-create-connector")
.layout( dialogLayout_settings );
} else {
// just in case - probably not required
dialogLayout.resizeAll();
}
$( "#radio", dE ).buttonset();
// Fix corners of buttons for vertical layout
$('label:first', "#radio" ).removeClass('ui-corner-left').addClass('ui-corner-top');
$('label:last', "#radio").removeClass('ui-corner-right').addClass('ui-corner-bottom');
// set up a change handler for whether we're dealing
// with a path or a branch
$('.conn_menu').change(function() {
var dialogElemJ = $('#dialog-create-connector');
// clear any previos classes
dialogElemJ.removeClass('path branch');
var selectedType = $('.conn_menu option:selected', dE).val();
// add our selected type
dialogElemJ.addClass(selectedType);
var sl = $('.source-left', dialogElemJ);
var sr = $('.source-right', dialogElemJ);
// remove any existing information
sl.html('');
sr.html('');
Mjs.Dialogs.CreateConnector._appendPathElem(sl);
Mjs.Dialogs.CreateConnector._appendPathElem(sr);
var pathElems = $('.path-text', dialogElemJ);
if (selectedType == 'path') {
pathElems.val("Type or drag a depot path");
// set up editable text if we're in path mode
var handleDragOver = function(evt) {
console.log('drag over');
evt.stopPropagation();
evt.preventDefault();
};
pathElems.selectonfocus();
pathElems.first().focus();
pathElems.on('dragover', handleDragOver);
pathElems.on('drop', function(evt) {
var event = evt.originalEvent;
console.log("drop event = ", evt);
var types = event.dataTransfer.types; // Types of things being transferred
var p4v = types.length > 1 && types[1] == "p4vobject/plain";
var type = types[0];
var value = event.dataTransfer.getData(type);
if (type == "text/plain" && p4v) {
value = value + "/...";
}
evt.target.value = value;
});
}
});
},
resize: function(){ if (dialogLayout) dialogLayout.resizeAll(); }
});
},
getInterchanges: function ( type, me, direction, param1, param2) {
// Run interchanges to populate number of changelists in connector
var sourceAndTarget = $(me).data('sourceAndTarget');
var left = null;
var right = null;
var opts = {};
if (type === "branch") {
opts = {branchName: param1};
if (direction === "source"){
opts.reverseMappings = true;
}
} else {
if (direction === "target" || direction === "both") {
left = param1;
right = param2;
} else if (direction === "source") {
left = param2;
right = param1;
}
}
var paths = type == 'branch'? param1 : (param1 + " " + param2);
var targetNumCL = null;
var sourceNumCL = null;
var options = type == 'branch'? ("-b " + param1) : (left + " " + right);
var changelists = P4JsApi.p4("interchanges " + options);
// setup some callbacks so we don't get things too far indented
var getLatestChangeForPaths = function(pathsArray, callback) {
P4JsApi.p4("changes -m " + pathsArray.length + " " + pathsArray, function(changelists) {
var maxChangeId = -1;
var i = 0, len = changelists.size;
for (i = 0; i < len; ++i) {
if (changelists.data[i].Change > maxChangeId) {
maxChangeId = changelists.data[i].Change;
}
}
callback(maxChangeId);
});
};
var createConnector = function() {
if (direction === "both") {
var opts1 = type == 'branch'? ("-r -b branch " + param1) : (left + " " + right);
P4JsApi.p4("interchanges " + opts1, function(changelists) {
connectorParams.sourceNumCL = P4JsApi.encodeForHTML(changelists.size);
Mjs.Collections.connectorCollection.add(connectorParams);
});
} else {
Mjs.Collections.connectorCollection.add(connectorParams);
}
$( me ).dialog( "close" );
};
if (direction === "target" || direction === "both") {
targetNumCL = P4JsApi.encodeForHTML(changelists.size);
} else if (direction === "source") {
sourceNumCL = P4JsApi.encodeForHTML(changelists.size);
}
var connectorParams = {
type: type,
name: paths,
sourceNumCL : sourceNumCL,
targetNumCL: targetNumCL,
direction: direction,
source: sourceAndTarget.source,
target: sourceAndTarget.target
};
if (type == 'branch') {
var branch = P4JsApi.p4("branch -o " + param1);
var branchData = branch.data[0];
var len = Object.keys(branchData).length;
var sourcePathsArray = [];
var targetPathsArray = [];
// Go thru branch spec object and get all View0, View1, etc to populate form
for (var i = 0; i < len ; ++i) {
var viewData = branchData["View"+i];
if (viewData != null) {
var res = viewData.split("/... ");
var leftPath = res[0];
var rightPath = res[1];
sourcePathsArray.push(leftPath);
targetPathsArray.push(rightPath);
}
}
var getLatestTargetChange = function(changeId) {
connectorParams.latestSource = changeId;
var createConn = function(changeId) {
connectorParams.latestTarget = changeId;
createConnector(connectorParams);
};
getLatestChangeForPaths(targetPathsArray,
createConn);
};
getLatestChangeForPaths(sourcePathsArray,
getLatestTargetChange);
} else {
getLatestChangeForPaths([param1], function(changeId) {
connectorParams.latestSource = changeId;;
getLatestChangeForPaths([param2], function(changeId) {
connectorParams.latestTarget = changeId;
createConnector(connectorParams);
});
});
}
},
_resetHtml : function(jEl) {
// clear any old paths if they exist
$('.source-right', jEl).html('');
$('.source-left', jEl).html('');
jEl.removeClass('path branch');
jEl.addClass('branch');
$('.conn_menu', jEl).val('branch');
$('.validateTips', jEl).html('Add a new codeline to the page');
},
_open: function(source, target) {
var jEl = $( "#dialog-create-connector" );
Mjs.Dialogs.CreateConnector._resetHtml(jEl);
jEl.data('sourceAndTarget', {source: source, target: target});
jEl.dialog( "open" );
},
_buttonFinish : function(dialogElem) {
var me = dialogElem;
var bValid = true;
$( "#branch_name" ).removeClass( "ui-state-error" );
var mode = $("#conn_type option:selected").val();
var direction = $('input:radio[name=radio]:checked').val();
// what type? branch or paths
// path
if ( mode == "path") {
var sourcePath = $('.source-left .path-text').val();
var targetPath = $('.source-right .path-text').val();
// validate that these are real depot paths.
// check that they have a '/' or .
if ((sourcePath[0] != '/' && sourcePath[0] != '.') ||
(targetPath[0] != '/' && targetPath[0] != '.')) {
// error don't continue
Mjs.Util.updateTips("Paths are invalid");
return;
}
// check that they start with a valid depot path
var depotPaths = $('#dialog-create-connector').data('depotsArray');;
var validDepot = _.some(depotPaths.data, function(depot) {
return sourcePath.indexOf('//' + depot.Depot) == 0;
});
if (!validDepot) {
Mjs.Util.updateTips("Source path is for a non-existent depot");
return;
}
validDepot = _.any(depotPaths.data, function(depot) {
return targetPath.indexOf('//' + depot.Depot) == 0;
});
if (!validDepot) {
Mjs.Util.updateTips("Target path is for a non-existent depot");
return;
}
// if we have valid depots, then go find whether the
// specific paths exist
var sourceData = P4JsApi.p4("fstat -m 1 " + sourcePath);
var targetData = P4JsApi.p4("fstat -m 1 " + targetPath);
// Check to see if paths entered are valid - it will return p4ERROR if not valid
// Could check message field for exact error message
if (targetData.data[0].p4ERROR == undefined && sourceData.data[0].p4ERROR == undefined) {
Mjs.Dialogs.CreateConnector
.getInterchanges('path',
me,
direction,
sourcePath,
targetPath );
} else {
Mjs.Util.updateTips("The paths entered are invalid. Please edit them and try again.");
}
}
else {
bValid = bValid &&
Mjs.Util.checkLength( $( "#branch_name" ),
"branch name", 1, 25, dialogElem );
if (bValid ) {
var branchName = $( "#branch_name" ).val();
var branch = P4JsApi.p4("branch " + branchName);
if (branch.size === 1) { // branch exists
Mjs.Dialogs.CreateConnector.
getInterchanges('branch',
me,
direction,
$( "#branch_name" ).val());
} // end of if (branch.length === 1)
else {
$( "#branch_name" ).addClass( "ui-state-error" );
Mjs.Util.updateTips( "Branch " +
$( "#branch_name" ).val() +
" does not exist.");
}
}
} // end of bValid
},
_appendPathElem : function(container, path, disabled) {
var el = document.createElement('input');
el.className = "path-text";
//div.innerHTML = path;
if (path) {
el.value = path;
}
if (disabled) {
el.disabled = true;
}
container.append(el);
},
_updateBranchViewPaths: function(branch_id) {
var appendPathDiv = function(container, path) {
Mjs.Dialogs.CreateConnector._appendPathElem(container, path, true);
};
// set the branch name
$('#branch_name').val(branch_id);
// fetch the branch information
var branch = P4JsApi.p4("branch -o " + branch_id);
var sl = $('.source-left');
var sr = $('.source-right');
// remove any existing information
sl.html('');
sr.html('');
// go through the view map and write out
// the path information
var branchData = branch.data[0];
var len = Object.keys(branchData).length;
for (var i = 0; i < len ; ++i) {
var viewData = branchData["View"+i];
if (viewData != null) {
var res = viewData.split("/... ");
var leftPath = res[0];
var rightPath = res[1];
appendPathDiv(sl, leftPath);
appendPathDiv(sr, rightPath);
}
}
}
};