Skip to content

Commit

Permalink
Added proper form validation to printer profile editor to the UI
Browse files Browse the repository at this point in the history
Closes #809
  • Loading branch information
foosel committed Mar 13, 2015
1 parent 5cadfb5 commit 91b9fb3
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 11 deletions.
85 changes: 80 additions & 5 deletions src/octoprint/static/js/app/viewmodels/printerprofiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ $(function() {
}
};

self.requestInProgress = ko.observable(false);

self.profiles = new ItemListHelper(
"printerProfiles",
{
Expand All @@ -57,6 +59,7 @@ $(function() {
self.editorName = ko.observable();
self.editorColor = ko.observable();
self.editorIdentifier = ko.observable();
self.editorIdentifierPlaceholder = ko.observable();
self.editorModel = ko.observable();

self.editorVolumeWidth = ko.observable();
Expand Down Expand Up @@ -110,6 +113,46 @@ $(function() {
return extruderOffsets.slice(0, numExtruders);
});

self.editorNameInvalid = ko.computed(function() {
return !self.editorName();
});

self.editorIdentifierInvalid = ko.computed(function() {
var identifier = self.editorIdentifier();
var placeholder = self.editorIdentifierPlaceholder();
var data = identifier;
if (!identifier) {
data = placeholder;
}

var validCharacters = (data && (data == self._sanitize(data)));

var existingProfile = self.profiles.getItem(function(item) {return item.id == data});
return !data || !validCharacters || (self.editorNew() && existingProfile != undefined);
});

self.editorIdentifierInvalidText = ko.computed(function() {
if (!self.editorIdentifierInvalid()) {
return "";
}

if (!self.editorIdentifier() && !self.editorIdentifierPlaceholder()) {
return gettext("Identifier must be set");
} else if (self.editorIdentifier() != self._sanitize(self.editorIdentifier())) {
return gettext("Invalid characters, only a-z, A-Z, 0-9, -, ., _, ( and ) are allowed")
} else {
return gettext("A profile with such an identifier already exists");
}
});

self.enableEditorSubmitButton = ko.computed(function() {
return !self.editorNameInvalid() && !self.editorIdentifierInvalid() && !self.requestInProgress();
});

self.editorName.subscribe(function() {
self.editorIdentifierPlaceholder(self._sanitize(self.editorName()).toLowerCase());
});

self.makeDefault = function(data) {
var profile = {
id: data.id,
Expand Down Expand Up @@ -153,30 +196,43 @@ $(function() {

self.addProfile = function(callback) {
var profile = self._editorData();
self.requestInProgress(true);
$.ajax({
url: API_BASEURL + "printerprofiles",
type: "POST",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({profile: profile}),
success: function() {
self.requestInProgress(false);
if (callback !== undefined) {
callback();
}
self.requestData();
},
error: function(jqXHR) {
alert(jqXHR.responseText);
error: function() {
self.requestInProgress(false);
var text = gettext("There was unexpected error while saving the printer profile, please consult the logs.");
new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false});
}
});
};

self.removeProfile = function(data) {
self.requestInProgress(true);
$.ajax({
url: data.resource,
type: "DELETE",
dataType: "json",
success: self.requestData
success: function() {
self.requestInProgress(false);
self.requestData();
},
error: function() {
self.requestInProgress(false);
var text = gettext("There was unexpected error while removing the printer profile, please consult the logs.");
new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false});
}
})
};

Expand All @@ -185,17 +241,25 @@ $(function() {
profile = self._editorData();
}

self.requestInProgress(true);

$.ajax({
url: API_BASEURL + "printerprofiles/" + profile.id,
type: "PATCH",
dataType: "json",
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({profile: profile}),
success: function() {
self.requestInProgress(false);
if (callback !== undefined) {
callback();
}
self.requestData();
},
error: function() {
self.requestInProgress(false);
var text = gettext("There was unexpected error while updating the printer profile, please consult the logs.");
new PNotify({title: gettext("Saving failed"), text: text, type: "error", hide: false});
}
});
};
Expand Down Expand Up @@ -248,7 +312,9 @@ $(function() {
dialogTitle.text(add ? gettext("Add Printer Profile") : _.sprintf(gettext("Edit Printer Profile \"%(name)s\""), {name: data.name}));
confirmButton.unbind("click");
confirmButton.bind("click", function() {
self.confirmEditProfile(add);
if (self.enableEditorSubmitButton()) {
self.confirmEditProfile(add);
}
});
editDialog.modal("show");
};
Expand All @@ -266,8 +332,13 @@ $(function() {
};

self._editorData = function() {
var identifier = self.editorIdentifier();
if (!identifier) {
identifier = self.editorIdentifierPlaceholder();
}

var profile = {
id: self.editorIdentifier(),
id: identifier,
name: self.editorName(),
color: self.editorColor(),
model: self.editorModel(),
Expand Down Expand Up @@ -314,6 +385,10 @@ $(function() {
return profile;
};

self._sanitize = function(name) {
return name.replace(/[^a-zA-Z0-9\-_\.\(\) ]/g, "").replace(/ /g, "_");
};

self.onSettingsShown = self.requestData;
self.onStartup = self.requestData;
}
Expand Down
14 changes: 8 additions & 6 deletions src/octoprint/templates/dialogs/settings/printerprofiles.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<td class="settings_printerProfiles_profiles_name"><span class="icon-star" data-bind="invisible: !isdefault()"></span> <span data-bind="text: name"></span></td>
<td class="settings_printerProfiles_profiles_model" data-bind="text: model"></td>
<td class="settings_printerProfiles_profiles_action">
<a href="#" class="icon-star" title="{{ _('Set as default profile') }}" data-bind="click: function() { $root.printerProfiles.makeDefault($data); }"></a>&nbsp;|&nbsp;<a href="#" class="icon-pencil" title="{{ _('Edit Profile') }}" data-bind="click: function() { $root.printerProfiles.showEditProfileDialog($data); }"></a>&nbsp;|&nbsp;<a href="#" class="icon-trash" title="{{ _('Delete Profile') }}" data-bind="click: function() { $root.printerProfiles.removeProfile($data); }"></a>
<a href="#" class="icon-star" title="{{ _('Set as default profile') }}" data-bind="click: function() { $root.printerProfiles.makeDefault($data); }, css: {disabled: $root.printerProfiles.requestInProgress()}, enabled: !$root.printerProfiles.requestInProgress()"></a>&nbsp;|&nbsp;<a href="#" class="icon-pencil" title="{{ _('Edit Profile') }}" data-bind="click: function() { $root.printerProfiles.showEditProfileDialog($data); }, css: {disabled: $root.printerProfiles.requestInProgress()}, enabled: !$root.printerProfiles.requestInProgress()"></a>&nbsp;|&nbsp;<a href="#" class="icon-trash" title="{{ _('Delete Profile') }}" data-bind="click: function() { $root.printerProfiles.removeProfile($data); }, css: {disabled: $root.printerProfiles.requestInProgress()}, enabled: !$root.printerProfiles.requestInProgress()"></a>
</td>
</tr>
</tbody>
Expand Down Expand Up @@ -40,16 +40,18 @@
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="control-group">
<div class="control-group" data-bind="css: {error: printerProfiles.editorNameInvalid()}">
<label class="control-label">{{ _('Name') }}</label>
<div class="controls">
<input type="text" data-bind="value: printerProfiles.editorName">
<input type="text" data-bind="value: printerProfiles.editorName, valueUpdate: 'afterkeydown'">
<span data-bind="visible: printerProfiles.editorNameInvalid()"><br><span class="help-inline">{{ _('Name must be set') }}</span></span>
</div>
</div>
<div class="control-group">
<div class="control-group" data-bind="css: {error: printerProfiles.editorIdentifierInvalid()}">
<label class="control-label">{{ _('Identifier') }}</label>
<div class="controls">
<input type="text" data-bind="value: printerProfiles.editorIdentifier, enable: $root.printerProfiles.editorNew, css: {disabled: !$root.printerProfiles.editorNew()}">
<input type="text" data-bind="value: printerProfiles.editorIdentifier, valueUpdate: 'afterkeydown', enable: printerProfiles.editorNew, css: {disabled: !printerProfiles.editorNew()}, attr: {placeholder: printerProfiles.editorIdentifierPlaceholder}">
<span data-bind="visible: printerProfiles.editorIdentifierInvalid()"><br><span class="help-inline" data-bind="text: printerProfiles.editorIdentifierInvalidText()"></span></span>
</div>
</div>
<div class="control-group">
Expand Down Expand Up @@ -180,6 +182,6 @@
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">{{ _('Abort') }}</button>
<button class="btn btn-primary btn-confirm">{{ _('Confirm') }}</button>
<button class="btn btn-primary btn-confirm" data-bind="enabled: printerProfiles.enableEditorSubmitButton, css: {disabled: !printerProfiles.enableEditorSubmitButton()}"><i class="icon-spinner icon-spin" data-bind="visible: printerProfiles.requestInProgress()"></i> {{ _('Confirm') }}</button>
</div>
</div>

0 comments on commit 91b9fb3

Please sign in to comment.