diff --git a/Gruntfile.js b/Gruntfile.js index 7467d1aa82b1f66e74ffead2fb2488030d51c3ca..1a762e6482f507adb486caede8178ae4ea24c5b7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -6,9 +6,7 @@ module.exports = function (grunt) { var typo3_js = 'extension/Resources/Public/JavaScript/'; var typo3_fonts = 'extension/Resources/Public/fonts/'; var js_sources = [ - 'javascript/src/Helper/*.js', - 'javascript/src/Element/*.js', - 'javascript/src/*.js' + 'javascript/src/**/*.js', ]; // Project configuration. diff --git a/javascript/src/QfqForm.js b/javascript/src/QfqForm.js index 99e73277f596ac92516e937a8af66bebf978f463..d634aae706bb4f06af2315d1e89e7cb11f330c23 100644 --- a/javascript/src/QfqForm.js +++ b/javascript/src/QfqForm.js @@ -1190,4 +1190,38 @@ var QfqNS = QfqNS || {}; window.history.back(); }; + n.QfqForm.prototype.disableSaveButton = function () { + this.setButtonEnabled(this.getSaveButton(), false); + this.getSaveButton().removeClass(this.getSaveButtonAttentionClass()); + }; + + n.QfqForm.prototype.enableSaveButton = function () { + this.setButtonEnabled(this.getSaveButton(), true); + this.getSaveButton().addClass(this.getSaveButtonAttentionClass()); + }; + + n.QfqForm.prototype.disableCloseButton = function () { + this.setButtonEnabled(this.getCloseButton(), false); + }; + + n.QfqForm.prototype.enableCloseButton = function () { + this.setButtonEnabled(this.getCloseButton(), true); + }; + + n.QfqForm.prototype.disableNewButton = function () { + this.setButtonEnabled(this.getNewButton(), false); + }; + + n.QfqForm.prototype.enableNewButton = function () { + this.setButtonEnabled(this.getNewButton(), true); + }; + + n.QfqForm.prototype.disableDeleteButton = function () { + this.setButtonEnabled(this.getDeleteButton(), false); + }; + + n.QfqForm.prototype.enableDeleteButton = function () { + this.setButtonEnabled(this.getDeleteButton(), true); + }; + })(QfqNS); \ No newline at end of file diff --git a/javascript/src/QfqFormStates/Buttons/Closed.js b/javascript/src/QfqFormStates/Buttons/Closed.js new file mode 100644 index 0000000000000000000000000000000000000000..4426fdc6844af4fdcbbd15b267a29b1daaea5438 --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/Closed.js @@ -0,0 +1,41 @@ +var QfqNS = QfqNS || {}; +QfqNS.QfqFormStates = QfqNS.QfqFormStates || {}; +QfqNS.QfqFormStates.Buttons = QfqNS.QfqFormStates.Buttons || {}; + +(function (n) { + 'use strict'; + + n.Closed = function (qfqForm) { + this.qfqForm = qfqForm; + }; + + n.Closed.prototype.saveButtonPressed = function () { + QfqNS.Log.warning("saveButtonPressed is not a valid transition for Closed"); + return this; + }; + + n.Closed.prototype.deleteButtonPressed = function () { + QfqNS.Log.warning("deleteButtonPressed is not a valid transition for Closed"); + return this; + }; + + n.Closed.prototype.newButtonPressed = function () { + QfqNS.Log.debug("Transition from Closed to New"); + this.qfqForm.disableSaveButton(); + this.qfqForm.disableDeleteButton(); + this.qfqForm.enableNewButton(); + this.qfqForm.enableCloseButton(); + return n.New(this.qfqForm); + }; + + n.Closed.prototype.closeButtonPressed = function () { + QfqNS.Log.debug("Transition from Closed to Closed"); + return this; + }; + + n.Closed.prototype.formModified = function () { + QfqNS.Log.warning("formModified is not a valid transition for Closed"); + return this; + }; + +})(QfqNS.QfqFormStates.Buttons); \ No newline at end of file diff --git a/javascript/src/QfqFormStates/Buttons/Context.js b/javascript/src/QfqFormStates/Buttons/Context.js new file mode 100644 index 0000000000000000000000000000000000000000..7d992f38ec9d79cb38d97cafbe354d65414e2102 --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/Context.js @@ -0,0 +1,41 @@ +var QfqNS = QfqNS || {}; +QfqNS.QfqFormStates = QfqNS.QfqFormStates || {}; +QfqNS.QfqFormStates.Buttons = QfqNS.QfqFormStates.Buttons || {}; + +(function (n) { + 'use strict'; + + /** + * Buttons State Context. + * + * @param initialState optional initial state. If omitted, New is the initial state. + * + * @param qfqForm optional qfqForm instance. Only used when no `initialState` is provided. + * + * @constructor + */ + n.Context = function (initialState, qfqForm) { + this.state = initialState || new n.New(qfqForm); + }; + + n.Context.prototype.saveButtonPressed = function () { + this.state = this.state.saveButtonPressed(); + }; + + n.Context.prototype.deleteButtonPressed = function () { + this.state = this.state.deleteButtonPressed(); + }; + + n.Context.prototype.newButtonPressed = function () { + this.state = this.state.newButtonPressed(); + }; + + n.Context.prototype.closeButtonPressed = function () { + this.state = this.state.closeButtonPressed(); + }; + + n.Context.prototype.formModified = function () { + this.state = this.state.formModified(); + }; + +})(QfqNS.QfqFormStates.Buttons); \ No newline at end of file diff --git a/javascript/src/QfqFormStates/Buttons/Deleted.js b/javascript/src/QfqFormStates/Buttons/Deleted.js new file mode 100644 index 0000000000000000000000000000000000000000..8f39f5c2a6c530c33a3ac92d2e937d9c8d85f18c --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/Deleted.js @@ -0,0 +1,37 @@ +var QfqNS = QfqNS || {}; +QfqNS.QfqFormStates = QfqNS.QfqFormStates || {}; +QfqNS.QfqFormStates.Buttons = QfqNS.QfqFormStates.Buttons || {}; + +(function (n) { + 'use strict'; + + n.Deleted = function (qfqForm) { + this.qfqForm = qfqForm; + }; + + n.Deleted.prototype.saveButtonPressed = function () { + QfqNS.Log.warning("saveButtonPressed is not a valid transition for Deleted"); + return this; + }; + + n.Deleted.prototype.deleteButtonPressed = function () { + QfqNS.Log.warning("deleteButtonPressed is not a valid transition for Deleted"); + return this; + }; + + n.Deleted.prototype.newButtonPressed = function () { + QfqNS.Log.warning("newButtonPressed is not a valid transition for Deleted"); + return n.New(this); + }; + + n.Deleted.prototype.closeButtonPressed = function () { + QfqNS.Log.warning("closeButtonPressed is not a valid transition for Deleted"); + return n.Closed(this); + }; + + n.Deleted.prototype.formModified = function () { + QfqNS.Log.warning("formModified is not a valid transition for Deleted"); + return this; + }; + +})(QfqNS.QfqFormStates.Buttons); \ No newline at end of file diff --git a/javascript/src/QfqFormStates/Buttons/Modified.js b/javascript/src/QfqFormStates/Buttons/Modified.js new file mode 100644 index 0000000000000000000000000000000000000000..f4507b82a158d8d98124e95abaad0f261e4149a9 --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/Modified.js @@ -0,0 +1,41 @@ +var QfqNS = QfqNS || {}; +QfqNS.QfqFormStates = QfqNS.QfqFormStates || {}; +QfqNS.QfqFormStates.Buttons = QfqNS.QfqFormStates.Buttons || {}; + +(function (n) { + 'use strict'; + + n.Modified = function (qfqForm) { + this.qfqForm = qfqForm; + }; + + n.Modified.prototype.saveButtonPressed = function () { + QfqNS.Log.warning("saveButtonPressed: transition from Modified to Unchanged"); + qfqForm.disableSaveButton(); + qfqForm.enableCloseButton(); + qfqForm.enableNewButton(); + qfqForm.enableDeleteButton(); + return new n.Unchanged(this.qfqForm); + }; + + n.Modified.prototype.deleteButtonPressed = function () { + QfqNS.Log.warning("deleteButtonPressed is not a valid transition for Modified"); + return this; + }; + + n.Modified.prototype.newButtonPressed = function () { + QfqNS.Log.warning("newButtonPressed is not a valid transition for Modified"); + return this; + }; + + n.Modified.prototype.closeButtonPressed = function () { + QfqNS.Log.warning("closeButtonPressed is not a valid transition for Deleted"); + return n.Closed(this.qfqForm); + }; + + n.Modified.prototype.formModified = function () { + QfqNS.Log.debug("formModified: transition from Modified to Modified"); + return this; + }; + +})(QfqNS.QfqFormStates.Buttons); \ No newline at end of file diff --git a/javascript/src/QfqFormStates/Buttons/New.js b/javascript/src/QfqFormStates/Buttons/New.js new file mode 100644 index 0000000000000000000000000000000000000000..9f388af3f2e3503f2b3726432d3b051ee74b71c2 --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/New.js @@ -0,0 +1,43 @@ +var QfqNS = QfqNS || {}; +QfqNS.QfqFormStates = QfqNS.QfqFormStates || {}; +QfqNS.QfqFormStates.Buttons = QfqNS.QfqFormStates.Buttons || {}; + +(function (n) { + 'use strict'; + + n.New = function (qfqForm) { + this.qfqForm = qfqForm; + }; + + n.New.prototype.saveButtonPressed = function () { + QfqNS.Log.warning("saveButtonPressed is not a valid transition for New"); + return this; + }; + + n.New.prototype.deleteButtonPressed = function () { + QfqNS.Log.warning("deleteButtonPressed is not a valid transition for New"); + return this; + }; + + n.New.prototype.newButtonPressed = function () { + QfqNS.Log.debug("Transition from New to New"); + return this; + }; + + n.New.prototype.closeButtonPressed = function () { + QfqNS.Log.warning("closeButtonPressed: transation from New to Closed"); + this.qfqForm.disableSaveButton(); + this.qfqForm.disableCloseButton(); + this.qfqForm.disableDeleteButton(); + this.qfqForm.disableNewButton(); + return n.Closed(this.qfqForm); + }; + + n.New.prototype.formModified = function () { + QfqNS.Log.debug("formModified: transition from New to Changed"); + this.qfqForm.enableSaveButton(); + + return new n.Modified(this.qfqForm); + }; + +})(QfqNS.QfqFormStates.Buttons); diff --git a/javascript/src/QfqFormStates/Buttons/README.md b/javascript/src/QfqFormStates/Buttons/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f6c500ad3386af0c98d774f06e6edc020541b58c --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/README.md @@ -0,0 +1,10 @@ +State interface +=== + +This interface must be implemented by all Button State objects. + + StateInterface#saveButtonPressed() + StateInterface#deleteButtonPressed() + StateInterface#newButtonPressed() + StateInterface#closeButtonPressed() + StateInterface#formModified() diff --git a/javascript/src/QfqFormStates/Buttons/Saved.js b/javascript/src/QfqFormStates/Buttons/Saved.js new file mode 100644 index 0000000000000000000000000000000000000000..597bb97f08f74a6acfda1495368e45339e0551a6 --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/Saved.js @@ -0,0 +1,9 @@ +var QfqNS = QfqNS || {}; +QfqNS.QfqFormStates = QfqNS.QfqFormStates || {}; +QfqNS.QfqFormStates.Buttons = QfqNS.QfqFormStates.Buttons || {}; + +(function (n) { + 'use strict'; + + +})(QfqNS.QfqFormStates.Buttons); \ No newline at end of file diff --git a/javascript/src/QfqFormStates/Buttons/Unchanged.js b/javascript/src/QfqFormStates/Buttons/Unchanged.js new file mode 100644 index 0000000000000000000000000000000000000000..cca46b122b4c2e19c7c5a3a3dcf3c27b409c0e85 --- /dev/null +++ b/javascript/src/QfqFormStates/Buttons/Unchanged.js @@ -0,0 +1,37 @@ +var QfqNS = QfqNS || {}; +QfqNS.QfqFormStates = QfqNS.QfqFormStates || {}; +QfqNS.QfqFormStates.Buttons = QfqNS.QfqFormStates.Buttons || {}; + +(function (n) { + 'use strict'; + n.Unchanged = function (qfqForm) { + this.qfqForm = qfqForm; + }; + + n.Unchanged.prototype.saveButtonPressed = function () { + QfqNS.Log.warning("saveButtonPressed is not a valid transition for Unchanged"); + return this; + }; + + n.Unchanged.prototype.deleteButtonPressed = function () { + QfqNS.Log.warning("deleteButtonPressed is not a valid transition for Unchanged"); + return this; + }; + + n.Unchanged.prototype.newButtonPressed = function () { + QfqNS.Log.debug("Transition from Unchanged to New"); + return new n.New(this.qfqForm); + }; + + n.Unchanged.prototype.closeButtonPressed = function () { + QfqNS.Log.debug("Transition from Unchanged to New"); + return new n.Closed(this.qfqForm); + }; + + n.Unchanged.prototype.formModified = function () { + QfqNS.Log.debug("Transition from Unchanged to Modified"); + this.qfqForm.enableSaveButton(); + return new n.Closed(this.qfqForm); + }; +})(QfqNS.QfqFormStates.Buttons); + diff --git a/tests/jasmine/unit/SpecRunner.html b/tests/jasmine/unit/SpecRunner.html index 71ac68cde99b607ea7e76ea2c4e9bb4c636455d2..221a0cd98488df4bd8c64702452ab304ab6d491c 100644 --- a/tests/jasmine/unit/SpecRunner.html +++ b/tests/jasmine/unit/SpecRunner.html @@ -37,7 +37,7 @@ - + diff --git a/tests/jasmine/unit/spec/ButtonStateSpec.js b/tests/jasmine/unit/spec/ButtonStateSpec.js new file mode 100644 index 0000000000000000000000000000000000000000..bd2db7646866b8674df210708f1fd69a1d80ff6c --- /dev/null +++ b/tests/jasmine/unit/spec/ButtonStateSpec.js @@ -0,0 +1,80 @@ +/* global $ */ +/* global describe */ +/* global it */ +/* global expect */ +/* global QfqNS */ +/* global beforeAll */ +/* global beforeEach */ +/* global jasmine */ + +describe("Button Sate", function () { + 'use strict'; + var stateSpy; + + beforeEach(function () { + stateSpy = { + saveButtonPressed: function () { + return "saveButtonPressed"; + }, + deleteButtonPressed: function () { + return "deleteButtonPressed"; + }, + newButtonPressed: function () { + return "newButtonPressed"; + }, + closeButtonPressed: function () { + return "closeButtonPressed"; + }, + formModified: function () { + return "formModified"; + } + }; + + // Hmm, ain't there a simpler approach to achieve the same? + spyOn(stateSpy, 'saveButtonPressed').and.callThrough(); + spyOn(stateSpy, 'deleteButtonPressed').and.callThrough(); + spyOn(stateSpy, 'newButtonPressed').and.callThrough(); + spyOn(stateSpy, 'closeButtonPressed').and.callThrough(); + spyOn(stateSpy, 'formModified').and.callThrough(); + }); + + it("should call the 'saveButtonPressed' handler and set proper state", function () { + var buttonContext = new QfqNS.QfqFormStates.Buttons.Buttons(stateSpy); + buttonContext.saveButtonPressed(); + + expect(stateSpy.saveButtonPressed).toHaveBeenCalledTimes(1); + expect(buttonContext.state).toBe("saveButtonPressed"); + }); + + it("should call the 'deleteButtonPressed' handler and set proper state", function () { + var buttonContext = new QfqNS.QfqFormStates.Buttons.Buttons(stateSpy); + buttonContext.deleteButtonPressed(); + + expect(stateSpy.deleteButtonPressed).toHaveBeenCalledTimes(1); + expect(buttonContext.state).toBe("deleteButtonPressed"); + }); + + it("should call the 'newButtonPressed' handler and set proper state", function () { + var buttonContext = new QfqNS.QfqFormStates.Buttons.Buttons(stateSpy); + buttonContext.newButtonPressed(); + + expect(stateSpy.newButtonPressed).toHaveBeenCalledTimes(1); + expect(buttonContext.state).toBe("newButtonPressed"); + }); + + it("should call the 'closeButtonPressed' handler and set proper state", function () { + var buttonContext = new QfqNS.QfqFormStates.Buttons.Buttons(stateSpy); + buttonContext.closeButtonPressed(); + + expect(stateSpy.closeButtonPressed).toHaveBeenCalledTimes(1); + expect(buttonContext.state).toBe("closeButtonPressed"); + }); + + it("should call the 'formModified' handler and set proper state", function () { + var buttonContext = new QfqNS.QfqFormStates.Buttons.Buttons(stateSpy); + buttonContext.formModified(); + + expect(stateSpy.formModified).toHaveBeenCalledTimes(1); + expect(buttonContext.state).toBe("formModified"); + }); +}); \ No newline at end of file