diff --git a/go/base/static/js/src/apps/dialogue/states/choice.js b/go/base/static/js/src/apps/dialogue/states/choice.js index 4b31ddacc..8486db92a 100644 --- a/go/base/static/js/src/apps/dialogue/states/choice.js +++ b/go/base/static/js/src/apps/dialogue/states/choice.js @@ -14,7 +14,8 @@ DialogueStateView = states.DialogueStateView, DialogueStateEditView = states.DialogueStateEditView, DialogueStatePreviewView = states.DialogueStatePreviewView, - TextEditView = states.partials.TextEditView; + TextEditView = states.partials.TextEditView, + maxChars = states.maxChars; var plumbing = go.components.plumbing, EndpointViewCollection = plumbing.endpoints.EndpointViewCollection, @@ -123,6 +124,7 @@ this.model.set( 'label', this.$('.choice-label').prop('value')); + this.mode.render(); }, onRemoveClick: function(e) { @@ -162,14 +164,14 @@ var ChoiceStateEditView = DialogueStateEditView.extend({ events: _({ - 'click .new-choice': 'onNewChoice' + 'click .new-choice': 'onNewChoice', + 'change .text': 'onTextChange' }).defaults(DialogueStateEditView.prototype.events), bodyOptions: function() { return { jst: 'JST.apps_dialogue_states_choice_edit', partials: { - text: new TextEditView({mode: this}), choices: new ChoiceEditCollection({ mode: this, models: this.state.model.get('choice_endpoints') @@ -192,6 +194,11 @@ } }, + onTextChange: function(e) { + this.state.model.set('text', $(e.target).val(), {silent: true}); + this.state.render(); + }, + onNewChoice: function(e) { e.preventDefault(); this.newChoice(); @@ -215,6 +222,8 @@ }); var ChoiceStateView = DialogueStateView.extend({ + maxChars: maxChars, + typeName: 'choice', editModeType: ChoiceStateEditView, @@ -227,7 +236,27 @@ attr: 'choice_endpoints', type: ChoiceEndpointView, collectionType: ChoiceEndpointCollection - }] + }], + + calcChars: function() { + var numChars = this.model.get('choice_endpoints') + .reduce(function(count, choice) { + return ('N. ' + choice.get('label') + '\n').length + count; + }, 0); + + // Remove the '\n' from the last choice_endpoint + numChars--; + numChars += this.model.get('text').length; + return Math.max(numChars, 0); + }, + + charsLeft: function() { + return this.maxChars - this.calcChars(); + }, + + tooManyChars: function() { + return (this.charsLeft() < 0) ? 'text-danger' : ''; + } }); _(exports).extend({ diff --git a/go/base/static/js/src/apps/dialogue/states/end.js b/go/base/static/js/src/apps/dialogue/states/end.js index 788b92380..b52f23d00 100644 --- a/go/base/static/js/src/apps/dialogue/states/end.js +++ b/go/base/static/js/src/apps/dialogue/states/end.js @@ -9,7 +9,8 @@ DialogueStateView = states.DialogueStateView, DialogueStateEditView = states.DialogueStateEditView, DialogueStatePreviewView = states.DialogueStatePreviewView, - TextEditView = states.partials.TextEditView; + TextEditView = states.partials.TextEditView, + maxChars = states.maxChars; var EndStateEditView = DialogueStateEditView.extend({ bodyOptions: function() { @@ -29,12 +30,35 @@ }); var EndStateView = DialogueStateView.extend({ + maxChars: maxChars, + typeName: 'end', editModeType: EndStateEditView, previewModeType: EndStatePreviewView, - endpointSchema: [{attr: 'entry_endpoint', type: EntryEndpointView}] + endpointSchema: [{attr: 'entry_endpoint', type: EntryEndpointView}], + + events: _({ + 'change .text': 'onTextChange' + }).defaults(DialogueStateEditView.prototype.events), + + onTextChange: function(e) { + this.model.set('text', $(e.target).val(), {silent: true}); + this.render(); + }, + + calcChars: function() { + return this.model.get('text').length; + }, + + charsLeft: function() { + return this.maxChars - this.calcChars(); + }, + + tooManyChars: function() { + return (this.charsLeft() < 0) ? 'text-danger' : ''; + } }); _(exports).extend({ diff --git a/go/base/static/js/src/apps/dialogue/states/freetext.js b/go/base/static/js/src/apps/dialogue/states/freetext.js index d3b21522c..349782f3e 100644 --- a/go/base/static/js/src/apps/dialogue/states/freetext.js +++ b/go/base/static/js/src/apps/dialogue/states/freetext.js @@ -9,7 +9,8 @@ DialogueStateView = states.DialogueStateView, DialogueStateEditView = states.DialogueStateEditView, DialogueStatePreviewView = states.DialogueStatePreviewView, - TextEditView = states.partials.TextEditView; + TextEditView = states.partials.TextEditView, + maxChars = states.maxChars; var FreeTextStateEditView = DialogueStateEditView.extend({ bodyOptions: function() { @@ -29,6 +30,8 @@ }); var FreeTextStateView = DialogueStateView.extend({ + maxChars: maxChars, + typeName: 'freetext', editModeType: FreeTextStateEditView, @@ -36,7 +39,28 @@ endpointSchema: [ {attr: 'entry_endpoint', type: EntryEndpointView}, - {attr: 'exit_endpoint', type: ExitEndpointView}] + {attr: 'exit_endpoint', type: ExitEndpointView}], + + events: _({ + 'change .text': 'onTextChange' + }).defaults(DialogueStateEditView.prototype.events), + + onTextChange: function(e) { + this.model.set('text', $(e.target).val(), {silent: true}); + this.render(); + }, + + calcChars: function() { + return this.model.get('text').length; + }, + + charsLeft: function() { + return this.maxChars - this.calcChars(); + }, + + tooManyChars: function() { + return (this.charsLeft() < 0) ? 'text-danger' : ''; + } }); _(exports).extend({ diff --git a/go/base/static/js/src/apps/dialogue/states/states.js b/go/base/static/js/src/apps/dialogue/states/states.js index 96fc1c5e6..cffa4ee1e 100644 --- a/go/base/static/js/src/apps/dialogue/states/states.js +++ b/go/base/static/js/src/apps/dialogue/states/states.js @@ -18,6 +18,8 @@ ParametricEndpointView = endpoints.ParametricEndpointView, AligningEndpointCollection = endpoints.AligningEndpointCollection; + var maxChars = 140; + var DialogueEndpointView = ParametricEndpointView.extend(); var EntryEndpointView = DialogueEndpointView.extend({ @@ -481,6 +483,8 @@ DialogueStateView: DialogueStateView, DialogueStateGridView: DialogueStateGridView, - DialogueStateCollection: DialogueStateCollection + DialogueStateCollection: DialogueStateCollection, + + maxChars: maxChars }); })(go.apps.dialogue.states = {}); diff --git a/go/base/static/js/test/apps/dialogue/states/choice.test.js b/go/base/static/js/test/apps/dialogue/states/choice.test.js index 0e3fa9d69..8428ff2b5 100644 --- a/go/base/static/js/test/apps/dialogue/states/choice.test.js +++ b/go/base/static/js/test/apps/dialogue/states/choice.test.js @@ -212,5 +212,78 @@ describe("go.apps.dialogue.states.choice", function() { editMode.$('[data-uuid="choice:new-endpoint"]'))); }); }); + + describe(".render", function() { + it("should display the char count", function() { + + assert.equal(state.$('.char-count').text().trim(), '44 characters used.'); + var endpoints = state.model.get('choice_endpoints'); + endpoints.at(0).set('label', 'A new label'); + endpoints.at(1).set('label', 'Another new label'); + + state.model.set('text', 'Some text for testing char count'); + state.render(); + assert.equal(state.$('.char-count').text().trim(), '68 characters used.'); + }); + }); + }); + + describe(".ChoiceStatePreviewView", function() { + var ChoiceStatePreviewView = states.choice.ChoiceStatePreviewView; + + var state, + previewMode, + choice1, + choice2; + + beforeEach(function() { + state = diagram.states.get('state1'); + previewMode = state.modes.preview; + state.preview(); + }); + + describe(".render", function() { + it("should display the char count", function() { + assert.equal(state.$('.char-count').text().trim(), '44 characters used.'); + var endpoints = state.model.get('choice_endpoints'); + endpoints.at(0).set('label', 'A new label'); + endpoints.at(1).set('label', 'Another new label'); + state.model.set('text', 'Some text for testing char count'); + state.render(); + assert.equal(state.$('.char-count').text().trim(), '68 characters used.'); + }); + }); + }); + + describe(".ChoiceStateView", function() { + var state; + + beforeEach(function() { + state = diagram.states.get('state1'); + state.maxChars = 100; + }); + + describe(".calcChars", function(){ + it("should calculate the number of characters used", function(){ + assert.equal(state.calcChars(), 44); + }); + }); + + describe(".charsLeft", function(){ + it("should calculate the number of characters left", function(){ + assert.equal(state.charsLeft(), 56); + }); + }); + + describe(".tooManyChars", function(){ + it("should not add a class when maxChars exceeds calcChars", function(){ + assert.equal(state.tooManyChars(),''); + }); + + it("should add a class when calcChars exceeds maxChars", function(){ + state.maxChars = 5; + assert.equal(state.tooManyChars(), 'text-danger'); + }); + }); }); }); diff --git a/go/base/static/js/test/apps/dialogue/states/end.test.js b/go/base/static/js/test/apps/dialogue/states/end.test.js index c2736867b..1b3e7173e 100644 --- a/go/base/static/js/test/apps/dialogue/states/end.test.js +++ b/go/base/static/js/test/apps/dialogue/states/end.test.js @@ -44,5 +44,66 @@ describe("go.apps.dialogue.states.end", function() { 'So Long, and Thanks for All the Fish'); }); }); + + describe(".render", function() { + it("should display the char count", function() { + assert.equal(state.$('.char-count').text().trim(), '31 characters used.'); + + state.model.set('text', 'Some text for testing char count'); + state.render(); + assert.equal(state.$('.char-count').text().trim(), '32 characters used.'); + }); + }); + }); + + describe(".EndStatePreviewView", function() { + var state; + + beforeEach(function() { + state = diagram.states.get('state3'); + state.preview(); + }); + + describe(".render", function() { + it("should display the char count", function() { + assert.equal(state.$('.char-count').text().trim(), '31 characters used.'); + + state.model.set('text', 'Some text for testing char count'); + state.render(); + assert.equal(state.$('.char-count').text().trim(), '32 characters used.'); + }); + }); + }); + + describe(".EndStateView", function() { + var state; + + beforeEach(function() { + state = diagram.states.get('state3'); + state.maxChars = 100; + }); + + describe(".calcChars", function(){ + it("should calculate the number of characters used", function(){ + assert.equal(state.calcChars(), 31); + }); + }); + + describe(".charsLeft", function(){ + it("should calculate the number of characters left", function(){ + assert.equal(state.charsLeft(), 69); + }); + }); + + describe(".tooManyChars", function(){ + it("should not add a class when maxChars exceeds calcChars", function(){ + assert.equal(state.tooManyChars(),''); + }); + + it("should add a class when calcChars exceeds maxChars", function(){ + state.maxChars = 5; + assert.equal(state.tooManyChars(), 'text-danger'); + }); + }); }); }); diff --git a/go/base/static/js/test/apps/dialogue/states/freetext.test.js b/go/base/static/js/test/apps/dialogue/states/freetext.test.js index 4bfc6d734..d5bacc459 100644 --- a/go/base/static/js/test/apps/dialogue/states/freetext.test.js +++ b/go/base/static/js/test/apps/dialogue/states/freetext.test.js @@ -44,5 +44,66 @@ describe("go.apps.dialogue.states.freetext", function() { 'What is your parrot doing?'); }); }); + + describe(".render", function() { + it("should display the char count", function() { + assert.equal(state.$('.char-count').text().trim(), '18 characters used.'); + + state.model.set('text', 'Some text for testing char count'); + state.render(); + assert.equal(state.$('.char-count').text().trim(), '32 characters used.'); + }); + }); + }); + + describe(".FreeTextStatePreviewView", function() { + var state; + + beforeEach(function() { + state = diagram.states.get('state2'); + state.preview(); + }); + + describe(".render", function() { + it("should display the char count", function() { + assert.equal(state.$('.char-count').text().trim(), '18 characters used.'); + + state.model.set('text', 'Some text for testing char count'); + state.render(); + assert.equal(state.$('.char-count').text().trim(), '32 characters used.'); + }); + }); + }); + + describe(".FreeStateView", function() { + var state; + + beforeEach(function() { + state = diagram.states.get('state2'); + state.maxChars = 100; + }); + + describe(".calcChars", function(){ + it("should calculate the number of characters used", function(){ + assert.equal(state.calcChars(), 18); + }); + }); + + describe(".charsLeft", function(){ + it("should calculate the number of characters left", function(){ + assert.equal(state.charsLeft(), 82); + }); + }); + + describe(".tooManyChars", function(){ + it("should not add a class when maxChars exceeds calcChars", function(){ + assert.equal(state.tooManyChars(),''); + }); + + it("should add a class when calcChars exceeds maxChars", function(){ + state.maxChars = 5; + assert.equal(state.tooManyChars(), 'text-danger'); + }); + }); }); }); diff --git a/go/base/static/templates/apps/dialogue/states/choice/edit.jst b/go/base/static/templates/apps/dialogue/states/choice/edit.jst index 12d84138a..aef04badf 100644 --- a/go/base/static/templates/apps/dialogue/states/choice/edit.jst +++ b/go/base/static/templates/apps/dialogue/states/choice/edit.jst @@ -1,5 +1,6 @@
+ <%= partials.text %>
@@ -12,6 +13,10 @@ +
+ <%= state.calcChars() %> characters used. +
+
diff --git a/go/base/static/templates/apps/dialogue/states/choice/preview.jst b/go/base/static/templates/apps/dialogue/states/choice/preview.jst index f58fd75d3..ca00206e1 100644 --- a/go/base/static/templates/apps/dialogue/states/choice/preview.jst +++ b/go/base/static/templates/apps/dialogue/states/choice/preview.jst @@ -8,3 +8,7 @@ <% }); %> + +
+ <%= state.calcChars() %> characters used. +
diff --git a/go/base/static/templates/apps/dialogue/states/end/edit.jst b/go/base/static/templates/apps/dialogue/states/end/edit.jst index b56d6d964..20b7eb2ef 100644 --- a/go/base/static/templates/apps/dialogue/states/end/edit.jst +++ b/go/base/static/templates/apps/dialogue/states/end/edit.jst @@ -4,3 +4,7 @@

Recipients can't answer

+ +
+ <%= state.calcChars() %> characters used. +
\ No newline at end of file diff --git a/go/base/static/templates/apps/dialogue/states/end/preview.jst b/go/base/static/templates/apps/dialogue/states/end/preview.jst index cbcb601f8..3f1c21d9f 100644 --- a/go/base/static/templates/apps/dialogue/states/end/preview.jst +++ b/go/base/static/templates/apps/dialogue/states/end/preview.jst @@ -1,3 +1,7 @@

<%= model.get("text") %>

Recipients can't answer

Session ends

+ +
+ <%= state.calcChars() %> characters used. +
\ No newline at end of file diff --git a/go/base/static/templates/apps/dialogue/states/freetext/edit.jst b/go/base/static/templates/apps/dialogue/states/freetext/edit.jst index f52890513..9e5eebbd5 100644 --- a/go/base/static/templates/apps/dialogue/states/freetext/edit.jst +++ b/go/base/static/templates/apps/dialogue/states/freetext/edit.jst @@ -4,3 +4,7 @@

Recipients reply with own text

+ +
+ <%= state.calcChars() %> characters used. +
\ No newline at end of file diff --git a/go/base/static/templates/apps/dialogue/states/freetext/preview.jst b/go/base/static/templates/apps/dialogue/states/freetext/preview.jst index 3237e81d6..809fb6edc 100644 --- a/go/base/static/templates/apps/dialogue/states/freetext/preview.jst +++ b/go/base/static/templates/apps/dialogue/states/freetext/preview.jst @@ -1,3 +1,7 @@

<%= model.get('text') %>


-Recipients reply with own text +

Recipients reply with own text

+ +
+ <%= state.calcChars() %> characters used. +
\ No newline at end of file