Browse Source

Fixes #893

- Adds PackageHandler >> commitPackage:onSuccess:onError:
- Adds Environment >> commitPackage:onSuccess:onError:
- Adds PackageCommitError class
- Adds HLPackageCommitErrorHelper to help the user in case the package
- commits fails.
- Improves HLRequestWidget to also work with inputs instead of textareas
Nicolas Petton 10 years ago
parent
commit
7b76210d3f

+ 9 - 0
css/helios.css

@@ -653,6 +653,10 @@ body[id="helios"] .dialog {
   -moz-transition: top .2s;
   -o-transition: top .2s;
 }
+body[id="helios"] .confirmation .head,
+body[id="helios"] .dialog .head {
+  display: block;
+}
 body[id="helios"] .confirmation .hl_widget .form-actions,
 body[id="helios"] .dialog .hl_widget .form-actions {
   padding: 0;
@@ -687,6 +691,11 @@ body[id="helios"] .dialog textarea {
   display: block;
   width: 235px;
 }
+body[id="helios"] .confirmation input[type="text"],
+body[id="helios"] .dialog input[type="text"] {
+  margin: 5px 0;
+  width: 390px;
+}
 body[id="helios"] .confirmation .progress,
 body[id="helios"] .dialog .progress {
   height: 5px;

+ 9 - 0
css/helios.less

@@ -753,6 +753,10 @@ body[id="helios"] {
 		-moz-transition: top .2s;
 		-o-transition: top .2s;
 
+		.head {
+			display: block;
+		}
+
 		.hl_widget {
 
 			.form-actions {
@@ -790,6 +794,11 @@ body[id="helios"] {
 			width: 235px;
 		}
 
+		input[type="text"] {
+			margin: 5px 0;
+			width: 390px;
+		}
+
 		.progress {
 			height: 5px;
 

+ 0 - 16
src/Helios-Browser.js

@@ -3338,22 +3338,6 @@ globals.HLMethodsListWidget.klass);
 
 smalltalk.addClass('HLPackagesListWidget', globals.HLToolListWidget, [], 'Helios-Browser');
 globals.HLPackagesListWidget.comment="I render a list of the system packages.";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "commitPackage",
-protocol: 'actions',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-_st(self._model())._commitPackage();
-return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLPackagesListWidget)})},
-args: [],
-source: "commitPackage\x0a\x09self model commitPackage",
-messageSends: ["commitPackage", "model"],
-referencedClasses: []
-}),
-globals.HLPackagesListWidget);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "cssClassForItem:",

+ 0 - 4
src/Helios-Browser.st

@@ -1169,10 +1169,6 @@ label
 
 !HLPackagesListWidget methodsFor: 'actions'!
 
-commitPackage
-	self model commitPackage
-!
-
 focusClassesListWidget
 	self model announcer announce: HLClassesListFocus new
 !

+ 63 - 4
src/Helios-Commands-Tools.js

@@ -157,6 +157,28 @@ referencedClasses: []
 }),
 globals.HLCommitPackageCommand);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitPackage",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._commitPackageOnSuccess_onError_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._informSuccess();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(error){
+return smalltalk.withContext(function($ctx2) {
+return self._onPackageCommitError_(error);
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLCommitPackageCommand)})},
+args: [],
+source: "commitPackage\x0a\x09self model \x0a\x09\x09commitPackageOnSuccess: [ self informSuccess ]\x0a\x09\x09onError: [ :error | self onPackageCommitError: error ]",
+messageSends: ["commitPackageOnSuccess:onError:", "model", "informSuccess", "onPackageCommitError:"],
+referencedClasses: []
+}),
+globals.HLCommitPackageCommand);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "execute",
@@ -164,15 +186,35 @@ protocol: 'executing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._model())._commitPackage();
+self._commitPackage();
 return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLCommitPackageCommand)})},
 args: [],
-source: "execute\x0a\x09self model commitPackage",
-messageSends: ["commitPackage", "model"],
+source: "execute\x0a\x09self commitPackage",
+messageSends: ["commitPackage"],
 referencedClasses: []
 }),
 globals.HLCommitPackageCommand);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "informSuccess",
+protocol: 'executing',
+fn: function (){
+var self=this;
+function $HLInformationWidget(){return globals.HLInformationWidget||(typeof HLInformationWidget=="undefined"?nil:HLInformationWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st($HLInformationWidget())._new();
+_st($1)._informationString_("Commit successful!");
+$2=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"informSuccess",{},globals.HLCommitPackageCommand)})},
+args: [],
+source: "informSuccess\x0a\x09HLInformationWidget new\x0a\x09\x09informationString: 'Commit successful!';\x0a\x09\x09show",
+messageSends: ["informationString:", "new", "show"],
+referencedClasses: ["HLInformationWidget"]
+}),
+globals.HLCommitPackageCommand);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "isActive",
@@ -182,12 +224,29 @@ var self=this;
 return true;
 },
 args: [],
-source: "isActive\x0a\x09^ true\x0a\x09\x22 slf model isPackageDirty\x22",
+source: "isActive\x0a\x09^ true\x0a\x09\x22self model isPackageDirty\x22",
 messageSends: [],
 referencedClasses: []
 }),
 globals.HLCommitPackageCommand);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onPackageCommitError:",
+protocol: 'error handling',
+fn: function (anError){
+var self=this;
+function $HLPackageCommitErrorHelper(){return globals.HLPackageCommitErrorHelper||(typeof HLPackageCommitErrorHelper=="undefined"?nil:HLPackageCommitErrorHelper)}
+return smalltalk.withContext(function($ctx1) { 
+_st(_st($HLPackageCommitErrorHelper())._on_(self._model()))._showHelp();
+return self}, function($ctx1) {$ctx1.fill(self,"onPackageCommitError:",{anError:anError},globals.HLCommitPackageCommand)})},
+args: ["anError"],
+source: "onPackageCommitError: anError\x0a\x09(HLPackageCommitErrorHelper on: self model)\x0a\x09\x09showHelp",
+messageSends: ["showHelp", "on:", "model"],
+referencedClasses: ["HLPackageCommitErrorHelper"]
+}),
+globals.HLCommitPackageCommand);
+
 
 smalltalk.addMethod(
 smalltalk.method({

+ 21 - 2
src/Helios-Commands-Tools.st

@@ -65,17 +65,36 @@ category
 	^ 'Packages'
 ! !
 
+!HLCommitPackageCommand methodsFor: 'error handling'!
+
+onPackageCommitError: anError
+	(HLPackageCommitErrorHelper on: self model)
+		showHelp
+! !
+
 !HLCommitPackageCommand methodsFor: 'executing'!
 
+commitPackage
+	self model 
+		commitPackageOnSuccess: [ self informSuccess ]
+		onError: [ :error | self onPackageCommitError: error ]
+!
+
 execute
-	self model commitPackage
+	self commitPackage
+!
+
+informSuccess
+	HLInformationWidget new
+		informationString: 'Commit successful!!';
+		show
 ! !
 
 !HLCommitPackageCommand methodsFor: 'testing'!
 
 isActive
 	^ true
-	" slf model isPackageDirty"
+	"self model isPackageDirty"
 ! !
 
 !HLCommitPackageCommand class methodsFor: 'accessing'!

+ 404 - 175
src/Helios-Core.js

@@ -381,16 +381,16 @@ globals.HLToolModel);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "commitPackage",
+selector: "commitPackageOnSuccess:onError:",
 protocol: 'commands actions',
-fn: function (){
+fn: function (aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._environment())._commitPackage_(self._packageToCommit());
-return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLToolModel)})},
-args: [],
-source: "commitPackage\x0a\x09self environment commitPackage: self packageToCommit",
-messageSends: ["commitPackage:", "environment", "packageToCommit"],
+_st(self._environment())._commitPackage_onSuccess_onError_(self._packageToCommit(),aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitPackageOnSuccess:onError:",{aBlock:aBlock,anotherBlock:anotherBlock},globals.HLToolModel)})},
+args: ["aBlock", "anotherBlock"],
+source: "commitPackageOnSuccess: aBlock onError: anotherBlock\x0a\x09self environment \x0a\x09\x09commitPackage: self packageToCommit\x0a\x09\x09onSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["commitPackage:onSuccess:onError:", "environment", "packageToCommit"],
 referencedClasses: []
 }),
 globals.HLToolModel);
@@ -1843,6 +1843,22 @@ referencedClasses: ["HLManager"]
 }),
 globals.HLWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "inform:",
+protocol: 'actions',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._manager())._inform_(aString);
+return self}, function($ctx1) {$ctx1.fill(self,"inform:",{aString:aString},globals.HLWidget)})},
+args: ["aString"],
+source: "inform: aString\x0a\x09self manager inform: aString",
+messageSends: ["inform:", "manager"],
+referencedClasses: []
+}),
+globals.HLWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "manager",
@@ -3808,6 +3824,26 @@ referencedClasses: []
 }),
 globals.HLManager);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "inform:",
+protocol: 'actions',
+fn: function (aString){
+var self=this;
+function $HLInformationWidget(){return globals.HLInformationWidget||(typeof HLInformationWidget=="undefined"?nil:HLInformationWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st($HLInformationWidget())._new();
+_st($1)._informationString_(aString);
+$2=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"inform:",{aString:aString},globals.HLManager)})},
+args: ["aString"],
+source: "inform: aString\x0a\x09HLInformationWidget new\x0a\x09\x09informationString: aString;\x0a\x09\x09show",
+messageSends: ["informationString:", "new", "show"],
+referencedClasses: ["HLInformationWidget"]
+}),
+globals.HLManager);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "keyBinder",
@@ -4385,116 +4421,8 @@ referencedClasses: []
 globals.HLManager.klass);
 
 
-smalltalk.addClass('HLModalWidget', globals.HLWidget, ['confirmButtonLabel', 'cancelButtonLabel'], 'Helios-Core');
+smalltalk.addClass('HLModalWidget', globals.HLWidget, [], 'Helios-Core');
 globals.HLModalWidget.comment="I implement an abstract modal widget.";
-smalltalk.addMethod(
-smalltalk.method({
-selector: "cancel",
-protocol: 'actions',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self._remove();
-return self}, function($ctx1) {$ctx1.fill(self,"cancel",{},globals.HLModalWidget)})},
-args: [],
-source: "cancel\x0a\x09self remove",
-messageSends: ["remove"],
-referencedClasses: []
-}),
-globals.HLModalWidget);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "cancelButtonLabel",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@cancelButtonLabel"];
-if(($receiver = $2) == nil || $receiver == null){
-$1="Cancel";
-} else {
-$1=$2;
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"cancelButtonLabel",{},globals.HLModalWidget)})},
-args: [],
-source: "cancelButtonLabel\x0a\x09^ cancelButtonLabel ifNil: [ 'Cancel' ]",
-messageSends: ["ifNil:"],
-referencedClasses: []
-}),
-globals.HLModalWidget);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "cancelButtonLabel:",
-protocol: 'accessing',
-fn: function (anObject){
-var self=this;
-self["@cancelButtonLabel"]=anObject;
-return self},
-args: ["anObject"],
-source: "cancelButtonLabel: anObject\x0a\x09cancelButtonLabel := anObject",
-messageSends: [],
-referencedClasses: []
-}),
-globals.HLModalWidget);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "confirm",
-protocol: 'actions',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-self._remove();
-return self}, function($ctx1) {$ctx1.fill(self,"confirm",{},globals.HLModalWidget)})},
-args: [],
-source: "confirm\x0a\x09\x22Override in subclasses\x22\x0a\x09self remove",
-messageSends: ["remove"],
-referencedClasses: []
-}),
-globals.HLModalWidget);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "confirmButtonLabel",
-protocol: 'accessing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $2,$1;
-$2=self["@confirmButtonLabel"];
-if(($receiver = $2) == nil || $receiver == null){
-$1="Confirm";
-} else {
-$1=$2;
-};
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"confirmButtonLabel",{},globals.HLModalWidget)})},
-args: [],
-source: "confirmButtonLabel\x0a\x09^ confirmButtonLabel ifNil: [ 'Confirm' ]",
-messageSends: ["ifNil:"],
-referencedClasses: []
-}),
-globals.HLModalWidget);
-
-smalltalk.addMethod(
-smalltalk.method({
-selector: "confirmButtonLabel:",
-protocol: 'accessing',
-fn: function (anObject){
-var self=this;
-self["@confirmButtonLabel"]=anObject;
-return self},
-args: ["anObject"],
-source: "confirmButtonLabel: anObject\x0a\x09confirmButtonLabel := anObject",
-messageSends: [],
-referencedClasses: []
-}),
-globals.HLModalWidget);
-
 smalltalk.addMethod(
 smalltalk.method({
 selector: "giveFocusToButton:",
@@ -4559,42 +4487,10 @@ selector: "renderButtonsOn:",
 protocol: 'rendering',
 fn: function (html){
 var self=this;
-var confirmButton;
-return smalltalk.withContext(function($ctx1) { 
-var $1,$3,$4,$5,$6,$2;
-$1=_st(html)._div();
-_st($1)._class_("buttons");
-$ctx1.sendIdx["class:"]=1;
-$2=_st($1)._with_((function(){
-return smalltalk.withContext(function($ctx2) {
-$3=_st(html)._button();
-$ctx2.sendIdx["button"]=1;
-_st($3)._class_("button");
-$ctx2.sendIdx["class:"]=2;
-_st($3)._with_(self._cancelButtonLabel());
-$ctx2.sendIdx["with:"]=2;
-$4=_st($3)._onClick_((function(){
-return smalltalk.withContext(function($ctx3) {
-return self._cancel();
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
-$ctx2.sendIdx["onClick:"]=1;
-$4;
-$5=_st(html)._button();
-_st($5)._class_("button default");
-_st($5)._with_(self._confirmButtonLabel());
-$6=_st($5)._onClick_((function(){
-return smalltalk.withContext(function($ctx3) {
-return self._confirm();
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
-confirmButton=$6;
-return confirmButton;
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
-$ctx1.sendIdx["with:"]=1;
-self._giveFocusToButton_(confirmButton);
-return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html,confirmButton:confirmButton},globals.HLModalWidget)})},
+return self},
 args: ["html"],
-source: "renderButtonsOn: html\x0a\x09| confirmButton |\x0a\x09\x0a\x09html div \x0a\x09\x09class: 'buttons';\x0a\x09\x09with: [\x0a\x09\x09\x09html button\x0a\x09\x09\x09\x09class: 'button';\x0a\x09\x09\x09\x09with: self cancelButtonLabel;\x0a\x09\x09\x09\x09onClick: [ self cancel ].\x0a\x09\x09\x09confirmButton := html button\x0a\x09\x09\x09\x09class: 'button default';\x0a\x09\x09\x09\x09with: self confirmButtonLabel;\x0a\x09\x09\x09\x09onClick: [ self confirm ] ].\x0a\x0a\x09self giveFocusToButton:confirmButton",
-messageSends: ["class:", "div", "with:", "button", "cancelButtonLabel", "onClick:", "cancel", "confirmButtonLabel", "confirm", "giveFocusToButton:"],
+source: "renderButtonsOn: html",
+messageSends: [],
 referencedClasses: []
 }),
 globals.HLModalWidget);
@@ -4687,8 +4583,8 @@ globals.HLModalWidget);
 
 
 
-smalltalk.addClass('HLConfirmationWidget', globals.HLModalWidget, ['confirmationString', 'actionBlock', 'cancelBlock'], 'Helios-Core');
-globals.HLConfirmationWidget.comment="I display confirmation messages. \x0a\x0aInstead of creating an instance directly, use `HLWidget >> #confirm:ifTrue:`.";
+smalltalk.addClass('HLConfirmationWidget', globals.HLModalWidget, ['cancelButtonLabel', 'confirmButtonLabel', 'confirmationString', 'actionBlock', 'cancelBlock'], 'Helios-Core');
+globals.HLConfirmationWidget.comment="I display confirmation dialog. \x0a\x0a## API\x0a\x0aHLWidget contains convenience methods like `HLWidget >> #confirm:ifTrue:` for creating confirmation dialogs.";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "actionBlock",
@@ -4736,11 +4632,11 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 _st(self._cancelBlock())._value();
-globals.HLConfirmationWidget.superclass.fn.prototype._cancel.apply(_st(self), []);
+self._remove();
 return self}, function($ctx1) {$ctx1.fill(self,"cancel",{},globals.HLConfirmationWidget)})},
 args: [],
-source: "cancel\x0a\x09self cancelBlock value.\x0a\x09super cancel",
-messageSends: ["value", "cancelBlock", "cancel"],
+source: "cancel\x0a\x09self cancelBlock value.\x0a\x09self remove",
+messageSends: ["value", "cancelBlock", "remove"],
 referencedClasses: []
 }),
 globals.HLConfirmationWidget);
@@ -4784,6 +4680,47 @@ referencedClasses: []
 }),
 globals.HLConfirmationWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cancelButtonLabel",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@cancelButtonLabel"];
+if(($receiver = $2) == nil || $receiver == null){
+$1="Cancel";
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"cancelButtonLabel",{},globals.HLConfirmationWidget)})},
+args: [],
+source: "cancelButtonLabel\x0a\x09^ cancelButtonLabel ifNil: [ 'Cancel' ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+globals.HLConfirmationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "cancelButtonLabel:",
+protocol: 'accessing',
+fn: function (aString){
+var self=this;
+var $1;
+self["@cancelButtonLabel"]=aString;
+$1=self["@cancelButtonLabel"];
+return $1;
+},
+args: ["aString"],
+source: "cancelButtonLabel: aString\x0a\x09^ cancelButtonLabel := aString",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLConfirmationWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "confirm",
@@ -4791,12 +4728,53 @@ protocol: 'actions',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-globals.HLConfirmationWidget.superclass.fn.prototype._confirm.apply(_st(self), []);
+self._remove();
 _st(self._actionBlock())._value();
 return self}, function($ctx1) {$ctx1.fill(self,"confirm",{},globals.HLConfirmationWidget)})},
 args: [],
-source: "confirm\x0a\x09super confirm.\x0a\x09self actionBlock value",
-messageSends: ["confirm", "value", "actionBlock"],
+source: "confirm\x0a\x09self remove.\x0a\x09self actionBlock value",
+messageSends: ["remove", "value", "actionBlock"],
+referencedClasses: []
+}),
+globals.HLConfirmationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "confirmButtonLabel",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@confirmButtonLabel"];
+if(($receiver = $2) == nil || $receiver == null){
+$1="Confirm";
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"confirmButtonLabel",{},globals.HLConfirmationWidget)})},
+args: [],
+source: "confirmButtonLabel\x0a\x09^ confirmButtonLabel ifNil: [ 'Confirm' ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+globals.HLConfirmationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "confirmButtonLabel:",
+protocol: 'accessing',
+fn: function (aString){
+var self=this;
+var $1;
+self["@confirmButtonLabel"]=aString;
+$1=self["@confirmButtonLabel"];
+return $1;
+},
+args: ["aString"],
+source: "confirmButtonLabel: aString\x0a\x09^ confirmButtonLabel := aString",
+messageSends: [],
 referencedClasses: []
 }),
 globals.HLConfirmationWidget);
@@ -4839,6 +4817,52 @@ referencedClasses: []
 }),
 globals.HLConfirmationWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderButtonsOn:",
+protocol: 'rendering',
+fn: function (html){
+var self=this;
+var confirmButton;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$3,$4,$5,$6,$2;
+$1=_st(html)._div();
+_st($1)._class_("buttons");
+$ctx1.sendIdx["class:"]=1;
+$2=_st($1)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
+$3=_st(html)._button();
+$ctx2.sendIdx["button"]=1;
+_st($3)._class_("button");
+$ctx2.sendIdx["class:"]=2;
+_st($3)._with_(self._cancelButtonLabel());
+$ctx2.sendIdx["with:"]=2;
+$4=_st($3)._onClick_((function(){
+return smalltalk.withContext(function($ctx3) {
+return self._cancel();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+$ctx2.sendIdx["onClick:"]=1;
+$4;
+$5=_st(html)._button();
+_st($5)._class_("button default");
+_st($5)._with_(self._confirmButtonLabel());
+$6=_st($5)._onClick_((function(){
+return smalltalk.withContext(function($ctx3) {
+return self._confirm();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
+confirmButton=$6;
+return confirmButton;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$ctx1.sendIdx["with:"]=1;
+self._giveFocusToButton_(confirmButton);
+return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html,confirmButton:confirmButton},globals.HLConfirmationWidget)})},
+args: ["html"],
+source: "renderButtonsOn: html\x0a\x09| confirmButton |\x0a\x09\x0a\x09html div \x0a\x09\x09class: 'buttons';\x0a\x09\x09with: [\x0a\x09\x09\x09html button\x0a\x09\x09\x09\x09class: 'button';\x0a\x09\x09\x09\x09with: self cancelButtonLabel;\x0a\x09\x09\x09\x09onClick: [ self cancel ].\x0a\x09\x09\x09confirmButton := html button\x0a\x09\x09\x09\x09class: 'button default';\x0a\x09\x09\x09\x09with: self confirmButtonLabel;\x0a\x09\x09\x09\x09onClick: [ self confirm ] ].\x0a\x0a\x09self giveFocusToButton:confirmButton",
+messageSends: ["class:", "div", "with:", "button", "cancelButtonLabel", "onClick:", "cancel", "confirmButtonLabel", "confirm", "giveFocusToButton:"],
+referencedClasses: []
+}),
+globals.HLConfirmationWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderMainOn:",
@@ -4846,32 +4870,67 @@ protocol: 'rendering',
 fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(html)._span())._with_(self._confirmationString());
+var $1,$2;
+$1=_st(html)._span();
+_st($1)._class_("head");
+$2=_st($1)._with_(self._confirmationString());
 return self}, function($ctx1) {$ctx1.fill(self,"renderMainOn:",{html:html},globals.HLConfirmationWidget)})},
 args: ["html"],
-source: "renderMainOn: html\x0a\x09html span with: self confirmationString",
-messageSends: ["with:", "span", "confirmationString"],
+source: "renderMainOn: html\x0a\x09html span \x0a\x09\x09class: 'head'; \x0a\x09\x09with: self confirmationString",
+messageSends: ["class:", "span", "with:", "confirmationString"],
 referencedClasses: []
 }),
 globals.HLConfirmationWidget);
 
 
 
-smalltalk.addClass('HLRequestWidget', globals.HLConfirmationWidget, ['input', 'value'], 'Helios-Core');
-globals.HLRequestWidget.comment="I display a modal window requesting user input.\x0a\x0aInstead of creating instances manually, use `HLWidget >> #request:do:` and `#request:value:do:`.";
+smalltalk.addClass('HLRequestWidget', globals.HLConfirmationWidget, ['input', 'multiline', 'value'], 'Helios-Core');
+globals.HLRequestWidget.comment="I display a modal window requesting user input.\x0a\x0a## API\x0a\x0a`HLWidget >> #request:do:` and `#request:value:do:` are convenience methods for creating modal request dialogs.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "beMultiline",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+self["@multiline"]=true;
+return self},
+args: [],
+source: "beMultiline\x0a\x09multiline := true",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLRequestWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "beSingleline",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+self["@multiline"]=false;
+return self},
+args: [],
+source: "beSingleline\x0a\x09multiline := false",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLRequestWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "confirm",
 protocol: 'actions',
 fn: function (){
 var self=this;
+var val;
 return smalltalk.withContext(function($ctx1) { 
-globals.HLRequestWidget.superclass.fn.prototype._confirm.apply(_st(self), []);
-_st(self._actionBlock())._value_(_st(_st(self["@input"])._asJQuery())._val());
-return self}, function($ctx1) {$ctx1.fill(self,"confirm",{},globals.HLRequestWidget)})},
+val=_st(_st(self["@input"])._asJQuery())._val();
+self._remove();
+_st(self._actionBlock())._value_(val);
+return self}, function($ctx1) {$ctx1.fill(self,"confirm",{val:val},globals.HLRequestWidget)})},
 args: [],
-source: "confirm\x0a\x09super confirm.\x0a\x09self actionBlock value: input asJQuery val",
-messageSends: ["confirm", "value:", "actionBlock", "val", "asJQuery"],
+source: "confirm\x0a\x09| val |\x0a\x09val := input asJQuery val.\x0a\x09self remove.\x0a\x09self actionBlock value: val",
+messageSends: ["val", "asJQuery", "remove", "value:", "actionBlock"],
 referencedClasses: []
 }),
 globals.HLRequestWidget);
@@ -4905,6 +4964,29 @@ referencedClasses: []
 }),
 globals.HLRequestWidget);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isMultiline",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@multiline"];
+if(($receiver = $2) == nil || $receiver == null){
+$1=true;
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isMultiline",{},globals.HLRequestWidget)})},
+args: [],
+source: "isMultiline\x0a\x09^ multiline ifNil: [ true ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+globals.HLRequestWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "renderMainOn:",
@@ -4912,16 +4994,33 @@ protocol: 'rendering',
 fn: function (html){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2;
+var $1,$2,$3,$4,$5,$6;
 globals.HLRequestWidget.superclass.fn.prototype._renderMainOn_.apply(_st(self), [html]);
+$1=self._isMultiline();
+if(smalltalk.assert($1)){
 self["@input"]=_st(html)._textarea();
-$1=_st(self["@input"])._asJQuery();
-_st($1)._val_(self._value());
-$2=_st($1)._focus();
+self["@input"];
+} else {
+$2=_st(html)._input();
+_st($2)._type_("text");
+_st($2)._onKeyDown_((function(event){
+return smalltalk.withContext(function($ctx2) {
+$3=_st(_st(event)._keyCode()).__eq((13));
+if(smalltalk.assert($3)){
+return self._confirm();
+};
+}, function($ctx2) {$ctx2.fillBlock({event:event},$ctx1,3)})}));
+$4=_st($2)._yourself();
+self["@input"]=$4;
+self["@input"];
+};
+$5=_st(self["@input"])._asJQuery();
+_st($5)._val_(self._value());
+$6=_st($5)._focus();
 return self}, function($ctx1) {$ctx1.fill(self,"renderMainOn:",{html:html},globals.HLRequestWidget)})},
 args: ["html"],
-source: "renderMainOn: html\x0a\x09super renderMainOn: html.\x0a\x09input := html textarea.\x0a\x09input asJQuery \x0a\x09\x09val: self value;\x0a\x09\x09focus",
-messageSends: ["renderMainOn:", "textarea", "val:", "asJQuery", "value", "focus"],
+source: "renderMainOn: html\x0a\x09super renderMainOn: html.\x0a\x09self isMultiline\x0a\x09\x09ifTrue: [ input := html textarea ]\x0a\x09\x09ifFalse: [ input := html input \x0a\x09\x09\x09type: 'text';\x0a\x09\x09\x09onKeyDown: [ :event |\x0a\x09\x09\x09\x09event keyCode = 13 ifTrue: [\x0a\x09\x09\x09\x09\x09self confirm ] ];\x0a\x09\x09\x09yourself ].\x0a\x09input asJQuery \x0a\x09\x09val: self value;\x0a\x09\x09focus",
+messageSends: ["renderMainOn:", "ifTrue:ifFalse:", "isMultiline", "textarea", "type:", "input", "onKeyDown:", "ifTrue:", "=", "keyCode", "confirm", "yourself", "val:", "asJQuery", "value", "focus"],
 referencedClasses: []
 }),
 globals.HLRequestWidget);
@@ -4966,6 +5065,136 @@ globals.HLRequestWidget);
 
 
 
+smalltalk.addClass('HLInformationWidget', globals.HLModalWidget, ['buttonLabel', 'informationString'], 'Helios-Core');
+globals.HLInformationWidget.comment="I display an information dialog.\x0a\x0a## API\x0a\x0a`HLWidget >> #inform:` is a convenience method for creating information dialogs.";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "buttonLabel",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@buttonLabel"];
+if(($receiver = $2) == nil || $receiver == null){
+$1="Ok";
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"buttonLabel",{},globals.HLInformationWidget)})},
+args: [],
+source: "buttonLabel\x0a\x09^ buttonLabel ifNil: [ 'Ok' ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+globals.HLInformationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "buttonLabel:",
+protocol: 'accessing',
+fn: function (aString){
+var self=this;
+self["@buttonLabel"]=aString;
+return self},
+args: ["aString"],
+source: "buttonLabel: aString\x0a\x09buttonLabel := aString",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLInformationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "informationString",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1;
+$2=self["@informationString"];
+if(($receiver = $2) == nil || $receiver == null){
+$1="";
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"informationString",{},globals.HLInformationWidget)})},
+args: [],
+source: "informationString\x0a\x09^ informationString ifNil: [ '' ]",
+messageSends: ["ifNil:"],
+referencedClasses: []
+}),
+globals.HLInformationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "informationString:",
+protocol: 'accessing',
+fn: function (anObject){
+var self=this;
+self["@informationString"]=anObject;
+return self},
+args: ["anObject"],
+source: "informationString: anObject\x0a\x09informationString := anObject",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLInformationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderButtonsOn:",
+protocol: 'rendering',
+fn: function (html){
+var self=this;
+var button;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$3,$4,$2;
+$1=_st(html)._div();
+_st($1)._class_("buttons");
+$ctx1.sendIdx["class:"]=1;
+$2=_st($1)._with_((function(){
+return smalltalk.withContext(function($ctx2) {
+$3=_st(html)._button();
+_st($3)._class_("button default");
+_st($3)._with_(self._buttonLabel());
+$4=_st($3)._onClick_((function(){
+return smalltalk.withContext(function($ctx3) {
+return self._remove();
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}));
+button=$4;
+return button;
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+$ctx1.sendIdx["with:"]=1;
+self._giveFocusToButton_(button);
+return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html,button:button},globals.HLInformationWidget)})},
+args: ["html"],
+source: "renderButtonsOn: html\x0a\x09| button |\x0a\x09html div \x0a\x09\x09class: 'buttons';\x0a\x09\x09with: [\x0a\x09\x09\x09button := html button\x0a\x09\x09\x09\x09class: 'button default';\x0a\x09\x09\x09\x09with: self buttonLabel;\x0a\x09\x09\x09\x09onClick: [ self remove ] ].\x0a\x0a\x09self giveFocusToButton: button",
+messageSends: ["class:", "div", "with:", "button", "buttonLabel", "onClick:", "remove", "giveFocusToButton:"],
+referencedClasses: []
+}),
+globals.HLInformationWidget);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "renderMainOn:",
+protocol: 'rendering',
+fn: function (html){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(html)._span())._with_(self._informationString());
+return self}, function($ctx1) {$ctx1.fill(self,"renderMainOn:",{html:html},globals.HLInformationWidget)})},
+args: ["html"],
+source: "renderMainOn: html\x0a\x09html span with: self informationString",
+messageSends: ["with:", "span", "informationString"],
+referencedClasses: []
+}),
+globals.HLInformationWidget);
+
+
+
 smalltalk.addClass('HLProgressWidget', globals.HLModalWidget, ['progressBars', 'visible'], 'Helios-Core');
 globals.HLProgressWidget.comment="I am a widget used to display progress modal dialogs.\x0a\x0aMy default instance is accessed with `HLProgressWidget class >> #default`.\x0a\x0aSee `HLProgressHandler` for usage.";
 smalltalk.addMethod(

+ 137 - 56
src/Helios-Core.st

@@ -259,8 +259,11 @@ saveSourceCode
 
 !HLToolModel methodsFor: 'commands actions'!
 
-commitPackage
-	self environment commitPackage: self packageToCommit
+commitPackageOnSuccess: aBlock onError: anotherBlock
+	self environment 
+		commitPackage: self packageToCommit
+		onSuccess: aBlock
+		onError: anotherBlock
 !
 
 copyClassTo: aClassName
@@ -668,6 +671,10 @@ execute: aCommand
 		applyBinding: aCommand asBinding
 !
 
+inform: aString
+	self manager inform: aString
+!
+
 openAsTab
 	HLManager current addTab: (HLTabWidget on: self labelled: self class tabLabel)
 !
@@ -1287,6 +1294,12 @@ confirm: aString ifTrue: aBlock ifFalse: anotherBlock
 		show
 !
 
+inform: aString
+	HLInformationWidget new
+		informationString: aString;
+		show
+!
+
 removeActiveTab
 	self removeTab: self activeTab
 !
@@ -1480,40 +1493,13 @@ new
 ! !
 
 HLWidget subclass: #HLModalWidget
-	instanceVariableNames: 'confirmButtonLabel cancelButtonLabel'
+	instanceVariableNames: ''
 	package: 'Helios-Core'!
 !HLModalWidget commentStamp!
 I implement an abstract modal widget.!
 
-!HLModalWidget methodsFor: 'accessing'!
-
-cancelButtonLabel
-	^ cancelButtonLabel ifNil: [ 'Cancel' ]
-!
-
-cancelButtonLabel: anObject
-	cancelButtonLabel := anObject
-!
-
-confirmButtonLabel
-	^ confirmButtonLabel ifNil: [ 'Confirm' ]
-!
-
-confirmButtonLabel: anObject
-	confirmButtonLabel := anObject
-! !
-
 !HLModalWidget methodsFor: 'actions'!
 
-cancel
-	self remove
-!
-
-confirm
-	"Override in subclasses"
-	self remove
-!
-
 remove
 	'.dialog' asJQuery removeClass: 'active'.
 	[ 
@@ -1539,21 +1525,6 @@ hasButtons
 !
 
 renderButtonsOn: html
-	| confirmButton |
-	
-	html div 
-		class: 'buttons';
-		with: [
-			html button
-				class: 'button';
-				with: self cancelButtonLabel;
-				onClick: [ self cancel ].
-			confirmButton := html button
-				class: 'button default';
-				with: self confirmButtonLabel;
-				onClick: [ self confirm ] ].
-
-	self giveFocusToButton:confirmButton
 !
 
 renderContentOn: html
@@ -1581,12 +1552,14 @@ setupKeyBindings
 ! !
 
 HLModalWidget subclass: #HLConfirmationWidget
-	instanceVariableNames: 'confirmationString actionBlock cancelBlock'
+	instanceVariableNames: 'cancelButtonLabel confirmButtonLabel confirmationString actionBlock cancelBlock'
 	package: 'Helios-Core'!
 !HLConfirmationWidget commentStamp!
-I display confirmation messages. 
+I display confirmation dialog. 
 
-Instead of creating an instance directly, use `HLWidget >> #confirm:ifTrue:`.!
+## API
+
+HLWidget contains convenience methods like `HLWidget >> #confirm:ifTrue:` for creating confirmation dialogs.!
 
 !HLConfirmationWidget methodsFor: 'accessing'!
 
@@ -1606,6 +1579,22 @@ cancelBlock: aBlock
 	cancelBlock := aBlock
 !
 
+cancelButtonLabel
+	^ cancelButtonLabel ifNil: [ 'Cancel' ]
+!
+
+cancelButtonLabel: aString
+	^ cancelButtonLabel := aString
+!
+
+confirmButtonLabel
+	^ confirmButtonLabel ifNil: [ 'Confirm' ]
+!
+
+confirmButtonLabel: aString
+	^ confirmButtonLabel := aString
+!
+
 confirmationString
 	^ confirmationString ifNil: [ 'Confirm' ]
 !
@@ -1618,30 +1607,60 @@ confirmationString: aString
 
 cancel
 	self cancelBlock value.
-	super cancel
+	self remove
 !
 
 confirm
-	super confirm.
+	self remove.
 	self actionBlock value
 ! !
 
 !HLConfirmationWidget methodsFor: 'rendering'!
 
+renderButtonsOn: html
+	| confirmButton |
+	
+	html div 
+		class: 'buttons';
+		with: [
+			html button
+				class: 'button';
+				with: self cancelButtonLabel;
+				onClick: [ self cancel ].
+			confirmButton := html button
+				class: 'button default';
+				with: self confirmButtonLabel;
+				onClick: [ self confirm ] ].
+
+	self giveFocusToButton:confirmButton
+!
+
 renderMainOn: html
-	html span with: self confirmationString
+	html span 
+		class: 'head'; 
+		with: self confirmationString
 ! !
 
 HLConfirmationWidget subclass: #HLRequestWidget
-	instanceVariableNames: 'input value'
+	instanceVariableNames: 'input multiline value'
 	package: 'Helios-Core'!
 !HLRequestWidget commentStamp!
 I display a modal window requesting user input.
 
-Instead of creating instances manually, use `HLWidget >> #request:do:` and `#request:value:do:`.!
+## API
+
+`HLWidget >> #request:do:` and `#request:value:do:` are convenience methods for creating modal request dialogs.!
 
 !HLRequestWidget methodsFor: 'accessing'!
 
+beMultiline
+	multiline := true
+!
+
+beSingleline
+	multiline := false
+!
+
 cssClass
 	^ 'large'
 !
@@ -1657,8 +1676,10 @@ value: aString
 !HLRequestWidget methodsFor: 'actions'!
 
 confirm
-	super confirm.
-	self actionBlock value: input asJQuery val
+	| val |
+	val := input asJQuery val.
+	self remove.
+	self actionBlock value: val
 ! !
 
 !HLRequestWidget methodsFor: 'private'!
@@ -1670,12 +1691,72 @@ giveFocusToButton: aButton
 
 renderMainOn: html
 	super renderMainOn: html.
-	input := html textarea.
+	self isMultiline
+		ifTrue: [ input := html textarea ]
+		ifFalse: [ input := html input 
+			type: 'text';
+			onKeyDown: [ :event |
+				event keyCode = 13 ifTrue: [
+					self confirm ] ];
+			yourself ].
 	input asJQuery 
 		val: self value;
 		focus
 ! !
 
+!HLRequestWidget methodsFor: 'testing'!
+
+isMultiline
+	^ multiline ifNil: [ true ]
+! !
+
+HLModalWidget subclass: #HLInformationWidget
+	instanceVariableNames: 'buttonLabel informationString'
+	package: 'Helios-Core'!
+!HLInformationWidget commentStamp!
+I display an information dialog.
+
+## API
+
+`HLWidget >> #inform:` is a convenience method for creating information dialogs.!
+
+!HLInformationWidget methodsFor: 'accessing'!
+
+buttonLabel
+	^ buttonLabel ifNil: [ 'Ok' ]
+!
+
+buttonLabel: aString
+	buttonLabel := aString
+!
+
+informationString
+	^ informationString ifNil: [ '' ]
+!
+
+informationString: anObject
+	informationString := anObject
+! !
+
+!HLInformationWidget methodsFor: 'rendering'!
+
+renderButtonsOn: html
+	| button |
+	html div 
+		class: 'buttons';
+		with: [
+			button := html button
+				class: 'button default';
+				with: self buttonLabel;
+				onClick: [ self remove ] ].
+
+	self giveFocusToButton: button
+!
+
+renderMainOn: html
+	html span with: self informationString
+! !
+
 HLModalWidget subclass: #HLProgressWidget
 	instanceVariableNames: 'progressBars visible'
 	package: 'Helios-Core'!

+ 164 - 0
src/Helios-Helpers.js

@@ -1048,4 +1048,168 @@ referencedClasses: []
 globals.HLMethodSourceCode);
 
 
+
+smalltalk.addClass('HLPackageCommitErrorHelper', globals.Object, ['model'], 'Helios-Helpers');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitPackage",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLCommitPackageCommand(){return globals.HLCommitPackageCommand||(typeof HLCommitPackageCommand=="undefined"?nil:HLCommitPackageCommand)}
+return smalltalk.withContext(function($ctx1) { 
+_st(_st($HLCommitPackageCommand())._for_(self._model()))._execute();
+return self}, function($ctx1) {$ctx1.fill(self,"commitPackage",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "commitPackage\x0a\x09(HLCommitPackageCommand for: self model)\x0a\x09\x09execute",
+messageSends: ["execute", "for:", "model"],
+referencedClasses: ["HLCommitPackageCommand"]
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitToPath:",
+protocol: 'actions',
+fn: function (aString){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(require)._basicAt_("config"))._value_(globals.HashedCollection._newFromPairs_(["paths",globals.HashedCollection._newFromPairs_([_st(_st(self._package())._transport())._namespace(),aString])]));
+self._commitPackage();
+return self}, function($ctx1) {$ctx1.fill(self,"commitToPath:",{aString:aString},globals.HLPackageCommitErrorHelper)})},
+args: ["aString"],
+source: "commitToPath: aString\x0a\x09\x22We only take AMD package transport into account for now\x22\x0a\x09\x0a\x09(require basicAt: 'config') value: #{\x0a\x09\x09'paths' -> #{\x0a\x09\x09\x09self package transport namespace -> aString\x0a\x09\x09}\x0a\x09}.\x0a\x09\x0a\x09self commitPackage",
+messageSends: ["value:", "basicAt:", "namespace", "transport", "package", "commitPackage"],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+var $1;
+$1=self["@model"];
+return $1;
+},
+args: [],
+source: "model\x0a\x09^ model",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "model:",
+protocol: 'accessing',
+fn: function (aToolModel){
+var self=this;
+self["@model"]=aToolModel;
+return self},
+args: ["aToolModel"],
+source: "model: aToolModel\x0a\x09model := aToolModel",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "package",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(self._model())._packageToCommit();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"package",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "package\x0a\x09^ self model packageToCommit",
+messageSends: ["packageToCommit", "model"],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "showHelp",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLConfirmationWidget(){return globals.HLConfirmationWidget||(typeof HLConfirmationWidget=="undefined"?nil:HLConfirmationWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3,$4;
+$1=_st($HLConfirmationWidget())._new();
+$2=$1;
+$3=_st("Commit failed for namespace \x22".__comma(_st(_st(self._package())._transport())._namespace())).__comma("\x22. Do you want to commit to another path?");
+$ctx1.sendIdx[","]=1;
+_st($2)._confirmationString_($3);
+_st($1)._actionBlock_((function(){
+return smalltalk.withContext(function($ctx2) {
+return self._showNewCommitPath();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}));
+_st($1)._cancelButtonLabel_("Abandon");
+_st($1)._confirmButtonLabel_("Set path");
+$4=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"showHelp",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "showHelp\x0a\x09HLConfirmationWidget new\x0a\x09\x09confirmationString: 'Commit failed for namespace \x22', self package transport namespace, '\x22. Do you want to commit to another path?';\x0a\x09\x09actionBlock: [ self showNewCommitPath ];\x0a\x09\x09cancelButtonLabel: 'Abandon';\x0a\x09\x09confirmButtonLabel: 'Set path';\x0a\x09\x09show\x0a\x09",
+messageSends: ["confirmationString:", "new", ",", "namespace", "transport", "package", "actionBlock:", "showNewCommitPath", "cancelButtonLabel:", "confirmButtonLabel:", "show"],
+referencedClasses: ["HLConfirmationWidget"]
+}),
+globals.HLPackageCommitErrorHelper);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "showNewCommitPath",
+protocol: 'actions',
+fn: function (){
+var self=this;
+function $HLRequestWidget(){return globals.HLRequestWidget||(typeof HLRequestWidget=="undefined"?nil:HLRequestWidget)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2;
+$1=_st($HLRequestWidget())._new();
+_st($1)._beSingleline();
+_st($1)._confirmationString_("Set commit path");
+_st($1)._actionBlock_((function(url){
+return smalltalk.withContext(function($ctx2) {
+return self._commitToPath_(url);
+}, function($ctx2) {$ctx2.fillBlock({url:url},$ctx1,1)})}));
+_st($1)._confirmButtonLabel_("Commit with new path");
+_st($1)._value_("/src");
+$2=_st($1)._show();
+return self}, function($ctx1) {$ctx1.fill(self,"showNewCommitPath",{},globals.HLPackageCommitErrorHelper)})},
+args: [],
+source: "showNewCommitPath\x0a\x09HLRequestWidget new\x0a\x09\x09beSingleline;\x0a\x09\x09confirmationString: 'Set commit path';\x0a\x09\x09actionBlock: [ :url | self commitToPath: url ];\x0a\x09\x09confirmButtonLabel: 'Commit with new path';\x0a\x09\x09value: '/src';\x0a\x09\x09show",
+messageSends: ["beSingleline", "new", "confirmationString:", "actionBlock:", "commitToPath:", "confirmButtonLabel:", "value:", "show"],
+referencedClasses: ["HLRequestWidget"]
+}),
+globals.HLPackageCommitErrorHelper);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "on:",
+protocol: 'instance creation',
+fn: function (aToolModel){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$3,$1;
+$2=self._new();
+_st($2)._model_(aToolModel);
+$3=_st($2)._yourself();
+$1=$3;
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"on:",{aToolModel:aToolModel},globals.HLPackageCommitErrorHelper.klass)})},
+args: ["aToolModel"],
+source: "on: aToolModel\x0a\x09^ self new\x0a\x09\x09model: aToolModel;\x0a\x09\x09yourself",
+messageSends: ["model:", "new", "yourself"],
+referencedClasses: []
+}),
+globals.HLPackageCommitErrorHelper.klass);
+
 });

+ 64 - 0
src/Helios-Helpers.st

@@ -435,3 +435,67 @@ sourceCode: aString
 	sourceCode := aString
 ! !
 
+Object subclass: #HLPackageCommitErrorHelper
+	instanceVariableNames: 'model'
+	package: 'Helios-Helpers'!
+
+!HLPackageCommitErrorHelper methodsFor: 'accessing'!
+
+model
+	^ model
+!
+
+model: aToolModel
+	model := aToolModel
+!
+
+package
+	^ self model packageToCommit
+! !
+
+!HLPackageCommitErrorHelper methodsFor: 'actions'!
+
+commitPackage
+	(HLCommitPackageCommand for: self model)
+		execute
+!
+
+commitToPath: aString
+	"We only take AMD package transport into account for now"
+	
+	(require basicAt: 'config') value: #{
+		'paths' -> #{
+			self package transport namespace -> aString
+		}
+	}.
+	
+	self commitPackage
+!
+
+showHelp
+	HLConfirmationWidget new
+		confirmationString: 'Commit failed for namespace "', self package transport namespace, '". Do you want to commit to another path?';
+		actionBlock: [ self showNewCommitPath ];
+		cancelButtonLabel: 'Abandon';
+		confirmButtonLabel: 'Set path';
+		show
+!
+
+showNewCommitPath
+	HLRequestWidget new
+		beSingleline;
+		confirmationString: 'Set commit path';
+		actionBlock: [ :url | self commitToPath: url ];
+		confirmButtonLabel: 'Commit with new path';
+		value: '/src';
+		show
+! !
+
+!HLPackageCommitErrorHelper class methodsFor: 'instance creation'!
+
+on: aToolModel
+	^ self new
+		model: aToolModel;
+		yourself
+! !
+

+ 4 - 0
src/Kernel-Exceptions.js

@@ -435,4 +435,8 @@ referencedClasses: []
 globals.NonBooleanReceiver);
 
 
+
+smalltalk.addClass('PackageCommitError', globals.Error, [], 'Kernel-Exceptions');
+globals.PackageCommitError.comment="I get signaled when an attempt to commit a package has failed.";
+
 });

+ 6 - 0
src/Kernel-Exceptions.st

@@ -161,3 +161,9 @@ object: anObject
 	object := anObject
 ! !
 
+Error subclass: #PackageCommitError
+	instanceVariableNames: ''
+	package: 'Kernel-Exceptions'!
+!PackageCommitError commentStamp!
+I get signaled when an attempt to commit a package has failed.!
+

+ 93 - 42
src/Kernel-ImportExport.js

@@ -1426,26 +1426,16 @@ smalltalk.addClass('PackageHandler', globals.InterfacingObject, [], 'Kernel-Impo
 globals.PackageHandler.comment="I am responsible for handling package loading and committing.\x0a\x0aI should not be used directly. Instead, use the corresponding `Package` methods.";
 smalltalk.addMethod(
 smalltalk.method({
-selector: "ajaxPutAt:data:",
+selector: "ajaxPutAt:data:onSuccess:onError:",
 protocol: 'private',
-fn: function (aURL,aString){
+fn: function (aURL,aString,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-var $3,$2,$1;
-self._ajax_(globals.HashedCollection._newFromPairs_(["url",aURL,"type","PUT","data",aString,"contentType","text/plain;charset=UTF-8","error",(function(xhr){
-return smalltalk.withContext(function($ctx2) {
-$3=_st("Commiting ".__comma(aURL)).__comma(" failed with reason: \x22");
-$ctx2.sendIdx[","]=3;
-$2=_st($3).__comma(_st(xhr)._responseText());
-$ctx2.sendIdx[","]=2;
-$1=_st($2).__comma("\x22");
-$ctx2.sendIdx[","]=1;
-return self._alert_($1);
-}, function($ctx2) {$ctx2.fillBlock({xhr:xhr},$ctx1,1)})})]));
-return self}, function($ctx1) {$ctx1.fill(self,"ajaxPutAt:data:",{aURL:aURL,aString:aString},globals.PackageHandler)})},
-args: ["aURL", "aString"],
-source: "ajaxPutAt: aURL data: aString\x0a\x09self\x0a\x09\x09ajax: #{\x0a\x09\x09\x09'url' -> aURL.\x0a\x09\x09\x09'type' -> 'PUT'.\x0a\x09\x09\x09'data' -> aString.\x0a\x09\x09\x09'contentType' -> 'text/plain;charset=UTF-8'.\x0a\x09\x09\x09'error' -> [ :xhr | self alert: 'Commiting ' , aURL , ' failed with reason: \x22' , (xhr responseText) , '\x22' ] }",
-messageSends: ["ajax:", "alert:", ",", "responseText"],
+self._ajax_(globals.HashedCollection._newFromPairs_(["url",aURL,"type","PUT","data",aString,"contentType","text/plain;charset=UTF-8","success",aBlock,"error",anotherBlock]));
+return self}, function($ctx1) {$ctx1.fill(self,"ajaxPutAt:data:onSuccess:onError:",{aURL:aURL,aString:aString,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aURL", "aString", "aBlock", "anotherBlock"],
+source: "ajaxPutAt: aURL data: aString onSuccess: aBlock onError: anotherBlock\x0a\x09self\x0a\x09\x09ajax: #{\x0a\x09\x09\x09'url' -> aURL.\x0a\x09\x09\x09'type' -> 'PUT'.\x0a\x09\x09\x09'data' -> aString.\x0a\x09\x09\x09'contentType' -> 'text/plain;charset=UTF-8'.\x0a\x09\x09\x09'success' -> aBlock.\x0a\x09\x09\x09'error' -> anotherBlock\x0a\x09\x09}",
+messageSends: ["ajax:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
@@ -1512,30 +1502,52 @@ selector: "commit:",
 protocol: 'committing',
 fn: function (aPackage){
 var self=this;
+function $PackageCommitError(){return globals.PackageCommitError||(typeof PackageCommitError=="undefined"?nil:PackageCommitError)}
 return smalltalk.withContext(function($ctx1) { 
-_st([(function(){
-return smalltalk.withContext(function($ctx2) {
-return self._commitStFileFor_(aPackage);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),(function(){
-return smalltalk.withContext(function($ctx2) {
-return self._commitJsFileFor_(aPackage);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})})])._do_displayingProgress_((function(each){
+var $1,$2,$3,$4;
+self._commit_onSuccess_onError_(aPackage,(function(){
+}),(function(error){
 return smalltalk.withContext(function($ctx2) {
-return _st(each)._value();
-}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,3)})}),"Committing package ".__comma(_st(aPackage)._name()));
+$1=_st($PackageCommitError())._new();
+$2=$1;
+$3=_st("Commiting failed with reason: \x22".__comma(_st(error)._responseText())).__comma("\x22");
+$ctx2.sendIdx[","]=1;
+_st($2)._messageText_($3);
+$4=_st($1)._signal();
+return $4;
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,2)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"commit:",{aPackage:aPackage},globals.PackageHandler)})},
 args: ["aPackage"],
-source: "commit: aPackage\x0a\x09{\x0a\x09\x09[ self commitStFileFor: aPackage ].\x0a\x09\x09[ self commitJsFileFor: aPackage ]\x0a\x09}\x0a\x09\x09do: [ :each | each value ]\x0a\x09\x09displayingProgress: 'Committing package ', aPackage name",
-messageSends: ["do:displayingProgress:", "commitStFileFor:", "commitJsFileFor:", "value", ",", "name"],
+source: "commit: aPackage\x0a\x09self \x0a\x09\x09commit: aPackage\x0a\x09\x09onSuccess: []\x0a\x09\x09onError: [ :error |\x0a\x09\x09\x09PackageCommitError new\x0a\x09\x09\x09\x09messageText: 'Commiting failed with reason: \x22' , (error responseText) , '\x22';\x0a\x09\x09\x09\x09signal ]",
+messageSends: ["commit:onSuccess:onError:", "messageText:", "new", ",", "responseText", "signal"],
+referencedClasses: ["PackageCommitError"]
+}),
+globals.PackageHandler);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commit:onSuccess:onError:",
+protocol: 'committing',
+fn: function (aPackage,aBlock,anotherBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+self._commitJsFileFor_onSuccess_onError_(aPackage,(function(){
+return smalltalk.withContext(function($ctx2) {
+return self._commitStFileFor_onSuccess_onError_(aPackage,aBlock,anotherBlock);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}),anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commit:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commit: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09self \x0a\x09\x09commitJsFileFor: aPackage \x0a\x09\x09onSuccess: [\x0a\x09\x09\x09self \x0a\x09\x09\x09commitStFileFor: aPackage \x0a\x09\x09\x09onSuccess: aBlock\x0a\x09\x09\x09onError: anotherBlock ] \x0a\x09\x09onError: anotherBlock",
+messageSends: ["commitJsFileFor:onSuccess:onError:", "commitStFileFor:onSuccess:onError:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "commitJsFileFor:",
+selector: "commitJsFileFor:onSuccess:onError:",
 protocol: 'committing',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
@@ -1543,11 +1555,11 @@ $2=_st(_st(self._commitPathJsFor_(aPackage)).__comma("/")).__comma(_st(aPackage)
 $ctx1.sendIdx[","]=2;
 $1=_st($2).__comma(".js");
 $ctx1.sendIdx[","]=1;
-self._ajaxPutAt_data_($1,self._contentsFor_(aPackage));
-return self}, function($ctx1) {$ctx1.fill(self,"commitJsFileFor:",{aPackage:aPackage},globals.PackageHandler)})},
-args: ["aPackage"],
-source: "commitJsFileFor: aPackage\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathJsFor: aPackage), '/', aPackage name, '.js'\x0a\x09\x09data: (self contentsFor: aPackage)",
-messageSends: ["ajaxPutAt:data:", ",", "commitPathJsFor:", "name", "contentsFor:"],
+self._ajaxPutAt_data_onSuccess_onError_($1,self._contentsFor_(aPackage),aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitJsFileFor:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commitJsFileFor: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathJsFor: aPackage), '/', aPackage name, '.js'\x0a\x09\x09data: (self contentsFor: aPackage)\x0a\x09\x09onSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["ajaxPutAt:data:onSuccess:onError:", ",", "commitPathJsFor:", "name", "contentsFor:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
@@ -1586,9 +1598,9 @@ globals.PackageHandler);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "commitStFileFor:",
+selector: "commitStFileFor:onSuccess:onError:",
 protocol: 'committing',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $2,$1;
@@ -1596,11 +1608,11 @@ $2=_st(_st(self._commitPathStFor_(aPackage)).__comma("/")).__comma(_st(aPackage)
 $ctx1.sendIdx[","]=2;
 $1=_st($2).__comma(".st");
 $ctx1.sendIdx[","]=1;
-self._ajaxPutAt_data_($1,self._chunkContentsFor_(aPackage));
-return self}, function($ctx1) {$ctx1.fill(self,"commitStFileFor:",{aPackage:aPackage},globals.PackageHandler)})},
-args: ["aPackage"],
-source: "commitStFileFor: aPackage\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathStFor: aPackage), '/', aPackage name, '.st'\x0a\x09\x09data: (self chunkContentsFor: aPackage)",
-messageSends: ["ajaxPutAt:data:", ",", "commitPathStFor:", "name", "chunkContentsFor:"],
+self._ajaxPutAt_data_onSuccess_onError_($1,self._chunkContentsFor_(aPackage),aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitStFileFor:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageHandler)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commitStFileFor: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09self \x0a\x09\x09ajaxPutAt: (self commitPathStFor: aPackage), '/', aPackage name, '.st'\x0a\x09\x09data: (self chunkContentsFor: aPackage)\x0a\x09\x09onSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["ajaxPutAt:data:onSuccess:onError:", ",", "commitPathStFor:", "name", "chunkContentsFor:"],
 referencedClasses: []
 }),
 globals.PackageHandler);
@@ -1677,6 +1689,29 @@ referencedClasses: []
 }),
 globals.PackageHandler);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onCommitError:",
+protocol: 'error handling',
+fn: function (anError){
+var self=this;
+function $PackageCommitError(){return globals.PackageCommitError||(typeof PackageCommitError=="undefined"?nil:PackageCommitError)}
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$3,$4;
+$1=_st($PackageCommitError())._new();
+$2=$1;
+$3=_st("Commiting failed with reason: \x22".__comma(_st(anError)._responseText())).__comma("\x22");
+$ctx1.sendIdx[","]=1;
+_st($2)._messageText_($3);
+$4=_st($1)._signal();
+return self}, function($ctx1) {$ctx1.fill(self,"onCommitError:",{anError:anError},globals.PackageHandler)})},
+args: ["anError"],
+source: "onCommitError: anError\x0a\x09PackageCommitError new\x0a\x09\x09messageText: 'Commiting failed with reason: \x22' , (anError responseText) , '\x22';\x0a\x09\x09signal",
+messageSends: ["messageText:", "new", ",", "responseText", "signal"],
+referencedClasses: ["PackageCommitError"]
+}),
+globals.PackageHandler);
+
 
 
 smalltalk.addClass('AmdPackageHandler', globals.PackageHandler, [], 'Kernel-ImportExport');
@@ -1924,6 +1959,22 @@ referencedClasses: []
 }),
 globals.PackageTransport);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "commitOnSuccess:onError:",
+protocol: 'committing',
+fn: function (aBlock,anotherBlock){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._commitHandler())._commit_onSuccess_onError_(self._package(),aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitOnSuccess:onError:",{aBlock:aBlock,anotherBlock:anotherBlock},globals.PackageTransport)})},
+args: ["aBlock", "anotherBlock"],
+source: "commitOnSuccess: aBlock onError: anotherBlock\x0a\x09self commitHandler \x0a\x09\x09commit: self package\x0a\x09\x09onSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["commit:onSuccess:onError:", "commitHandler", "package"],
+referencedClasses: []
+}),
+globals.PackageTransport);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "definition",

+ 43 - 10
src/Kernel-ImportExport.st

@@ -582,24 +582,48 @@ exporterClass
 !PackageHandler methodsFor: 'committing'!
 
 commit: aPackage
-	{
-		[ self commitStFileFor: aPackage ].
-		[ self commitJsFileFor: aPackage ]
-	}
-		do: [ :each | each value ]
-		displayingProgress: 'Committing package ', aPackage name
+	self 
+		commit: aPackage
+		onSuccess: []
+		onError: [ :error |
+			PackageCommitError new
+				messageText: 'Commiting failed with reason: "' , (error responseText) , '"';
+				signal ]
 !
 
-commitJsFileFor: aPackage
+commit: aPackage onSuccess: aBlock onError: anotherBlock
+	self 
+		commitJsFileFor: aPackage 
+		onSuccess: [
+			self 
+			commitStFileFor: aPackage 
+			onSuccess: aBlock
+			onError: anotherBlock ] 
+		onError: anotherBlock
+!
+
+commitJsFileFor: aPackage onSuccess: aBlock onError: anotherBlock
 	self 
 		ajaxPutAt: (self commitPathJsFor: aPackage), '/', aPackage name, '.js'
 		data: (self contentsFor: aPackage)
+		onSuccess: aBlock
+		onError: anotherBlock
 !
 
-commitStFileFor: aPackage
+commitStFileFor: aPackage onSuccess: aBlock onError: anotherBlock
 	self 
 		ajaxPutAt: (self commitPathStFor: aPackage), '/', aPackage name, '.st'
 		data: (self chunkContentsFor: aPackage)
+		onSuccess: aBlock
+		onError: anotherBlock
+! !
+
+!PackageHandler methodsFor: 'error handling'!
+
+onCommitError: anError
+	PackageCommitError new
+		messageText: 'Commiting failed with reason: "' , (anError responseText) , '"';
+		signal
 ! !
 
 !PackageHandler methodsFor: 'factory'!
@@ -620,14 +644,16 @@ load: aPackage
 
 !PackageHandler methodsFor: 'private'!
 
-ajaxPutAt: aURL data: aString
+ajaxPutAt: aURL data: aString onSuccess: aBlock onError: anotherBlock
 	self
 		ajax: #{
 			'url' -> aURL.
 			'type' -> 'PUT'.
 			'data' -> aString.
 			'contentType' -> 'text/plain;charset=UTF-8'.
-			'error' -> [ :xhr | self alert: 'Commiting ' , aURL , ' failed with reason: "' , (xhr responseText) , '"' ] }
+			'success' -> aBlock.
+			'error' -> anotherBlock
+		}
 ! !
 
 PackageHandler subclass: #AmdPackageHandler
@@ -725,6 +751,13 @@ type
 
 commit
 	self commitHandler commit: self package
+!
+
+commitOnSuccess: aBlock onError: anotherBlock
+	self commitHandler 
+		commit: self package
+		onSuccess: aBlock
+		onError: anotherBlock
 ! !
 
 !PackageTransport methodsFor: 'converting'!

+ 7 - 7
src/Kernel-Infrastructure.js

@@ -391,16 +391,16 @@ globals.Environment);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "commitPackage:",
+selector: "commitPackage:onSuccess:onError:",
 protocol: 'actions',
-fn: function (aPackage){
+fn: function (aPackage,aBlock,anotherBlock){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(aPackage)._commit();
-return self}, function($ctx1) {$ctx1.fill(self,"commitPackage:",{aPackage:aPackage},globals.Environment)})},
-args: ["aPackage"],
-source: "commitPackage: aPackage\x0a\x09aPackage commit",
-messageSends: ["commit"],
+_st(_st(aPackage)._transport())._commitOnSuccess_onError_(aBlock,anotherBlock);
+return self}, function($ctx1) {$ctx1.fill(self,"commitPackage:onSuccess:onError:",{aPackage:aPackage,aBlock:aBlock,anotherBlock:anotherBlock},globals.Environment)})},
+args: ["aPackage", "aBlock", "anotherBlock"],
+source: "commitPackage: aPackage onSuccess: aBlock onError: anotherBlock\x0a\x09aPackage transport\x0a\x09\x09commitOnSuccess: aBlock\x0a\x09\x09onError: anotherBlock",
+messageSends: ["commitOnSuccess:onError:", "transport"],
 referencedClasses: []
 }),
 globals.Environment);

+ 4 - 2
src/Kernel-Infrastructure.st

@@ -135,8 +135,10 @@ systemAnnouncer
 
 !Environment methodsFor: 'actions'!
 
-commitPackage: aPackage
-	aPackage commit
+commitPackage: aPackage onSuccess: aBlock onError: anotherBlock
+	aPackage transport
+		commitOnSuccess: aBlock
+		onError: anotherBlock
 !
 
 copyClass: aClass to: aClassName