Initial commit
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
Used for the newcustomimage_modal actions
|
||||
|
||||
The .data('recipe') value on the outer element determines which
|
||||
recipe ID is used as the basis for the new custom image recipe created via
|
||||
this modal.
|
||||
|
||||
Use newCustomImageModalSetRecipes() to set the recipes available as a base
|
||||
for the new custom image. This will manage the addition of radio buttons
|
||||
to select the base image (or remove the radio buttons, if there is only a
|
||||
single base image available).
|
||||
*/
|
||||
|
||||
function newCustomImageModalInit(){
|
||||
|
||||
var newCustomImgBtn = $("#create-new-custom-image-btn");
|
||||
var imgCustomModal = $("#new-custom-image-modal");
|
||||
var invalidNameHelp = $("#invalid-name-help");
|
||||
var invalidRecipeHelp = $("#invalid-recipe-help");
|
||||
var nameInput = imgCustomModal.find('input');
|
||||
|
||||
var invalidNameMsg = "Image names cannot contain spaces or capital letters. The only allowed special character is dash (-).";
|
||||
var duplicateNameMsg = "An image with this name already exists. Image names must be unique.";
|
||||
var duplicateImageInProjectMsg = "An image with this name already exists in this project."
|
||||
var invalidBaseRecipeIdMsg = "Please select an image to customise.";
|
||||
var missingParentRecipe = "The parent recipe file was not found. Cancel this action, build any target (like 'quilt-native') to force all new layers to clone, and try again";
|
||||
var unknownError = "Unexpected error: ";
|
||||
|
||||
// set button to "submit" state and enable text entry so user can
|
||||
// enter the custom recipe name
|
||||
showSubmitState();
|
||||
|
||||
/* capture clicks on radio buttons inside the modal; when one is selected,
|
||||
* set the recipe on the modal
|
||||
*/
|
||||
imgCustomModal.on("click", "[name='select-image']", function(e) {
|
||||
clearRecipeError();
|
||||
$(".radio").each(function(){
|
||||
$(this).removeClass("has-error");
|
||||
});
|
||||
|
||||
var recipeId = $(e.target).attr('data-recipe');
|
||||
imgCustomModal.data('recipe', recipeId);
|
||||
});
|
||||
|
||||
newCustomImgBtn.click(function(e){
|
||||
// disable the button and text entry
|
||||
showLoadingState();
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
var baseRecipeId = imgCustomModal.data('recipe');
|
||||
|
||||
if (!baseRecipeId) {
|
||||
showRecipeError(invalidBaseRecipeIdMsg);
|
||||
$(".radio").each(function(){
|
||||
$(this).addClass("has-error");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (nameInput.val().length > 0) {
|
||||
libtoaster.createCustomRecipe(nameInput.val(), baseRecipeId,
|
||||
function(ret) {
|
||||
showSubmitState();
|
||||
if (ret.error !== "ok") {
|
||||
console.warn(ret.error);
|
||||
if (ret.error === "invalid-name") {
|
||||
showNameError(invalidNameMsg);
|
||||
return;
|
||||
} else if (ret.error === "recipe-already-exists") {
|
||||
showNameError(duplicateNameMsg);
|
||||
return;
|
||||
} else if (ret.error === "image-already-exists") {
|
||||
showNameError(duplicateImageInProjectMsg);
|
||||
return;
|
||||
} else if (ret.error === "recipe-parent-not-exist") {
|
||||
showNameError(missingParentRecipe);
|
||||
} else {
|
||||
showNameError(unknownError + ret.error);
|
||||
}
|
||||
} else {
|
||||
imgCustomModal.modal('hide');
|
||||
imgCustomModal.one('hidden.bs.modal', showSubmitState);
|
||||
window.location.replace(ret.url + '?notify=new');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// enable text entry, show "Create image" button text
|
||||
function showSubmitState() {
|
||||
libtoaster.enableAjaxLoadingTimer();
|
||||
newCustomImgBtn.find('[data-role="loading-state"]').hide();
|
||||
newCustomImgBtn.find('[data-role="submit-state"]').show();
|
||||
newCustomImgBtn.removeAttr('disabled');
|
||||
nameInput.removeAttr('disabled');
|
||||
}
|
||||
|
||||
// disable text entry, show "Creating image..." button text;
|
||||
// we also disabled the page-level ajax loading spinner while this spinner
|
||||
// is active
|
||||
function showLoadingState() {
|
||||
libtoaster.disableAjaxLoadingTimer();
|
||||
newCustomImgBtn.find('[data-role="submit-state"]').hide();
|
||||
newCustomImgBtn.find('[data-role="loading-state"]').show();
|
||||
newCustomImgBtn.attr('disabled', 'disabled');
|
||||
nameInput.attr('disabled', 'disabled');
|
||||
}
|
||||
|
||||
function showNameError(text){
|
||||
invalidNameHelp.text(text);
|
||||
invalidNameHelp.show();
|
||||
nameInput.parent().addClass('has-error');
|
||||
}
|
||||
|
||||
function showRecipeError(text){
|
||||
invalidRecipeHelp.text(text);
|
||||
invalidRecipeHelp.show();
|
||||
}
|
||||
|
||||
function clearRecipeError(){
|
||||
invalidRecipeHelp.hide();
|
||||
}
|
||||
|
||||
nameInput.on('keyup', function(){
|
||||
if (nameInput.val().length === 0){
|
||||
newCustomImgBtn.prop("disabled", true);
|
||||
return
|
||||
}
|
||||
|
||||
if (nameInput.val().search(/[^a-z|0-9|-]/) != -1){
|
||||
showNameError(invalidNameMsg);
|
||||
newCustomImgBtn.prop("disabled", true);
|
||||
nameInput.parent().addClass('has-error');
|
||||
} else {
|
||||
invalidNameHelp.hide();
|
||||
newCustomImgBtn.prop("disabled", false);
|
||||
nameInput.parent().removeClass('has-error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Set the image recipes which can used as the basis for the custom
|
||||
* image recipe the user is creating
|
||||
* baseRecipes: a list of one or more recipes which can be
|
||||
* used as the base for the new custom image recipe in the format:
|
||||
* [{'id': <recipe ID>, 'name': <recipe name>'}, ...]
|
||||
*
|
||||
* if recipes is a single recipe, just show the text box to set the
|
||||
* name for the new custom image; if recipes contains multiple recipe objects,
|
||||
* show a set of radio buttons so the user can decide which to use as the
|
||||
* basis for the new custom image
|
||||
*/
|
||||
function newCustomImageModalSetRecipes(baseRecipes) {
|
||||
var imgCustomModal = $("#new-custom-image-modal");
|
||||
var imageSelector = $('#new-custom-image-modal [data-role="image-selector"]');
|
||||
var imageSelectRadiosContainer = $('#new-custom-image-modal [data-role="image-selector-radios"]');
|
||||
|
||||
// remove any existing radio buttons + labels
|
||||
imageSelector.remove('[data-role="image-radio"]');
|
||||
|
||||
if (baseRecipes.length === 1) {
|
||||
// hide the radio button container
|
||||
imageSelector.hide();
|
||||
|
||||
/* set the single recipe ID on the modal as it's the only one
|
||||
* we can build from.
|
||||
*/
|
||||
imgCustomModal.data('recipe', baseRecipes[0].id);
|
||||
}
|
||||
else {
|
||||
// add radio buttons; note that the handlers for the radio buttons
|
||||
// are set in newCustomImageModalInit via event delegation
|
||||
for (var i = 0; i < baseRecipes.length; i++) {
|
||||
var recipe = baseRecipes[i];
|
||||
imageSelectRadiosContainer.append(
|
||||
'<div class="radio"><label data-role="image-radio">' +
|
||||
'<input type="radio" name="select-image" ' +
|
||||
'data-recipe="' + recipe.id + '">' +
|
||||
recipe.name +
|
||||
'</label></div>'
|
||||
);
|
||||
}
|
||||
|
||||
/* select the first radio button as default selection. Radio button
|
||||
* groups should always display with an option checked
|
||||
*/
|
||||
imageSelectRadiosContainer.find("input:radio:first").attr("checked", "checked");
|
||||
|
||||
/* check which radio button is selected by default inside the modal,
|
||||
* and set the recipe on the modal accordingly
|
||||
*/
|
||||
imageSelectRadiosContainer.find("input:radio").each(function(){
|
||||
if ( $(this).is(":checked") ) {
|
||||
var recipeId = $(this).attr("data-recipe");
|
||||
imgCustomModal.data("recipe", recipeId);
|
||||
}
|
||||
});
|
||||
|
||||
// show the radio button container
|
||||
imageSelector.show();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user