From 8611867930b7778918a90cc36b8517d0649e926c Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Thu, 24 Apr 2014 22:16:32 -0400 Subject: [PATCH 01/12] Remove dead code :skull: --- core/modules/widgets/navigator.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/modules/widgets/navigator.js b/core/modules/widgets/navigator.js index c58caa2e3..60c917e38 100755 --- a/core/modules/widgets/navigator.js +++ b/core/modules/widgets/navigator.js @@ -281,8 +281,7 @@ NavigatorWidget.prototype.generateDraftTitle = function(title) { NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) { var title = event.param || event.tiddlerTitle, tiddler = this.wiki.getTiddler(title), - storyList = this.getStoryList(), - storyTiddlerModified = false; // We have to special case saving the story tiddler itself + storyList = this.getStoryList(); // Replace the original tiddler with the draft if(tiddler) { var draftTitle = (tiddler.fields["draft.title"] || "").trim(), From 540681b2bc220d5dcc496bd453c82c2a5fe25c1d Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Fri, 25 Apr 2014 08:42:45 -0400 Subject: [PATCH 02/12] Add $tw.util.isEqual This checks to see if an array is equal. Should handle case where an array is considered null or undefined. It short circuits when the lengths are different and will only loop when needed. --- boot/boot.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/boot/boot.js b/boot/boot.js index 658f8e980..b02e2380f 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -85,6 +85,18 @@ $tw.utils.each = function(object,callback) { } }; +/* +Check if an array is equal by value and by reference. +*/ +$tw.utils.isEqual = function(array1,array2) { + if(array1 === array2) { return true; } + array1 = array1 || []; array2 = array2 || []; + if(array1.length !== array2.length) { return false; } + return array1.every(function(value,index) { + return value === array2[index]; + }); +}; + /* Helper for making DOM elements tag: tag name From 23640d7af44fda362c7bdd2b01b2d92f4641a603 Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Fri, 25 Apr 2014 08:44:34 -0400 Subject: [PATCH 03/12] Add isDraft to Tiddler object Check to see if this tiddler is a draft (has a draft.of field) --- boot/boot.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/boot/boot.js b/boot/boot.js index b02e2380f..74d736cce 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -791,6 +791,10 @@ $tw.Tiddler.prototype.hasField = function(field) { return $tw.utils.hop(this.fields,field); }; +$tw.Tiddler.prototype.isDraft = function() { + return this.hasField("draft.of"); +}; + /* Register and install the built in tiddler field modules */ From 3a78465d2d3150f2cafff18ab8ff8772b9dbdf22 Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Fri, 25 Apr 2014 08:45:17 -0400 Subject: [PATCH 04/12] Add isModified to Tiddler object Adds a check to see if this tiddler differers from the tiddler referenced in the draft.of field. It iterates of the fields property skiping those feilds that offer a false positives. Uses the isEqual util for the tags array. --- boot/boot.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/boot/boot.js b/boot/boot.js index 74d736cce..67d1a5582 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -795,6 +795,20 @@ $tw.Tiddler.prototype.isDraft = function() { return this.hasField("draft.of"); }; +$tw.Tiddler.prototype.isModified = function() { + if(!this.isDraft()) { return false; } + var ignoredFields = ["created", "modified", "title", "draft.title", "draft.of", "tags"], + tiddler = this, + origTiddler = $tw.wiki.getTiddler(this.fields["draft.of"]); + if(!$tw.utils.isEqual(tiddler.fields.tags,origTiddler.fields.tags)) { + return true; + } + return !Object.keys(tiddler.fields).every(function(field) { + if(ignoredFields.indexOf(field) >= 0) { return true; } + return tiddler.fields[field] === origTiddler.fields[field]; + }); +}; + /* Register and install the built in tiddler field modules */ From 5226c7a2fa64afbf09016655e25495714d565edf Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Fri, 25 Apr 2014 08:46:51 -0400 Subject: [PATCH 05/12] Prevent saving un-modified tiddlers When saving a tiddler we check to see if the tiddler has changed (isModified) if it hasn't then bounce the event to tw-cancel-tiddler instead. Addresses first line item in issue #570 --- core/modules/widgets/navigator.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/modules/widgets/navigator.js b/core/modules/widgets/navigator.js index 60c917e38..eb0d5425a 100755 --- a/core/modules/widgets/navigator.js +++ b/core/modules/widgets/navigator.js @@ -296,12 +296,14 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) { {title: draftTitle} } )); - } - if(isConfirmed) { + } else if(!tiddler.isModified()) { + event.type = "tw-cancel-tiddler"; + this.dispatchEvent(event); + } else if(isConfirmed) { // Save the draft tiddler as the real tiddler this.wiki.addTiddler(new $tw.Tiddler(this.wiki.getCreationFields(),tiddler,{ title: draftTitle, - "draft.title": undefined, + "draft.title": undefined, "draft.of": undefined },this.wiki.getModificationFields())); // Remove the draft tiddler From d0636f212437995f90f1b30aeb8aeb3877e9ea69 Mon Sep 17 00:00:00 2001 From: Devin Weaver Date: Fri, 25 Apr 2014 09:40:24 -0400 Subject: [PATCH 06/12] Add a confirmation to edit a shadow tiddler Should only display the confirmation if the shadow tiddler has not been overridden in the first place. It checks this by looking for the existence of a modified field for which the default system based shadow do not have until a user changes them. This addresses the second line item on issue #570 We will need new translations for the added string `ConfirmEditShadowTiddler` --- core/language/en-GB/Misc.multids | 1 + core/modules/widgets/navigator.js | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/core/language/en-GB/Misc.multids b/core/language/en-GB/Misc.multids index e7dfd68c3..35502b737 100644 --- a/core/language/en-GB/Misc.multids +++ b/core/language/en-GB/Misc.multids @@ -6,6 +6,7 @@ CloseAll/Button: close all ConfirmCancelTiddler: Do you wish to discard changes to the tiddler "<$text text=<>/>"? ConfirmDeleteTiddler: Do you wish to delete the tiddler "<$text text=<<title>>/>"? ConfirmOverwriteTiddler: Do you wish to overwrite the tiddler "<$text text=<<title>>/>"? +ConfirmEditShadowTiddler: Your about to edit a ShaddowTiddler. This will override the default system making upgrading non-trivial. Are you sure you want to edit "<$text text=<<title>>/>"? InvalidFieldName: Illegal characters in field name "<$text text=<<fieldName>>/>". Fields can only contain lowercase letters and the characters underscore (`_`), hyphen (`-`) and period (`.`) MissingTiddler/Hint: Missing tiddler "<$text text=<<currentTiddler>>/>" - click {{$:/core/images/edit-button}} to create RecentChanges/DateFormat: DDth MMM YYYY diff --git a/core/modules/widgets/navigator.js b/core/modules/widgets/navigator.js index eb0d5425a..0f75cb7e9 100755 --- a/core/modules/widgets/navigator.js +++ b/core/modules/widgets/navigator.js @@ -181,9 +181,28 @@ NavigatorWidget.prototype.handleCloseOtherTiddlersEvent = function(event) { // Place a tiddler in edit mode NavigatorWidget.prototype.handleEditTiddlerEvent = function(event) { + function isUnmodifiedShadow(title) { + // jshint eqnull:true + var tiddler = $tw.wiki.getTiddler(title); + return ( + $tw.wiki.isShadowTiddler(title) && + tiddler.fields.modified == null + ); + } + function confirmEditShadow(title) { + return confirm($tw.language.getString( + "ConfirmEditShadowTiddler", + {variables: + {title: title} + } + )); + } + var title = event.param || event.tiddlerTitle; + if(isUnmodifiedShadow(title) && !confirmEditShadow(title)) { + return false; + } // Replace the specified tiddler with a draft in edit mode - var title = event.param || event.tiddlerTitle, - draftTiddler = this.makeDraftTiddler(title), + var draftTiddler = this.makeDraftTiddler(title), draftTitle = draftTiddler.fields.title, storyList = this.getStoryList(); this.removeTitleFromStory(storyList,draftTitle); From 3be21853e122c35e8e31d41f1aa5028529985177 Mon Sep 17 00:00:00 2001 From: Devin Weaver <suki@tritarget.org> Date: Sat, 26 Apr 2014 19:41:54 -0400 Subject: [PATCH 07/12] Add warning box while editing a shadow tiddler This addresses the third line item of issue #570 TODO: The filter is not working. TODO: The message is too genaric and needs help. --- core/language/en-GB/EditTemplate.multids | 1 + core/ui/EditTemplate/body.tid | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/core/language/en-GB/EditTemplate.multids b/core/language/en-GB/EditTemplate.multids index 27572963c..d6eb2a525 100644 --- a/core/language/en-GB/EditTemplate.multids +++ b/core/language/en-GB/EditTemplate.multids @@ -4,6 +4,7 @@ Body/Hint: Use [[wiki text|http://tiddlywiki.com/static/WikiText.html]] to add f Body/Placeholder: Type the text for this tiddler Body/Preview/Button/Hide: hide preview Body/Preview/Button/Show: show preview +Body/ShadowWarning: You are editing a shadow tiddler. Any changes will override the default version. Fields/Add/Button: add Fields/Add/Name/Placeholder: field name Fields/Add/Prompt: Add a new field: diff --git a/core/ui/EditTemplate/body.tid b/core/ui/EditTemplate/body.tid index fb80c55b9..18c7d66dd 100644 --- a/core/ui/EditTemplate/body.tid +++ b/core/ui/EditTemplate/body.tid @@ -2,6 +2,14 @@ title: $:/core/ui/EditTemplate/body tags: $:/tags/EditTemplate \define lingo-base() $:/language/EditTemplate/ +<$list filter="[all[current]is[shadow]]"> +<div class="tw-message-box"> + +<<lingo Body/ShadowWarning>> + +</div> +</$list> + <$reveal state="$:/ShowEditPreview" type="match" text="yes"> <em class="tw-edit"><<lingo Body/Hint>></em> <$button type="set" set="$:/ShowEditPreview" setTo="no"><<lingo Body/Preview/Button/Hide>></$button> From 8556e0ea495275b05831b43a31f60a4426e96964 Mon Sep 17 00:00:00 2001 From: Devin Weaver <suki@tritarget.org> Date: Sun, 27 Apr 2014 10:02:22 -0400 Subject: [PATCH 08/12] Fix coding style --- boot/boot.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/boot/boot.js b/boot/boot.js index 67d1a5582..0e1168c2e 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -796,7 +796,9 @@ $tw.Tiddler.prototype.isDraft = function() { }; $tw.Tiddler.prototype.isModified = function() { - if(!this.isDraft()) { return false; } + if(!this.isDraft()) { + return false; + } var ignoredFields = ["created", "modified", "title", "draft.title", "draft.of", "tags"], tiddler = this, origTiddler = $tw.wiki.getTiddler(this.fields["draft.of"]); From 3bbe53a58e09f8ea3587ef73a054e48e05ef7e37 Mon Sep 17 00:00:00 2001 From: Devin Weaver <suki@tritarget.org> Date: Sun, 27 Apr 2014 11:38:14 -0400 Subject: [PATCH 09/12] Move shadowWarning to it's own template segment --- core/ui/EditTemplate/body.tid | 8 -------- core/ui/EditTemplate/shadowWarning.tid | 11 +++++++++++ core/wiki/tags/EditTemplate.tid | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) create mode 100644 core/ui/EditTemplate/shadowWarning.tid diff --git a/core/ui/EditTemplate/body.tid b/core/ui/EditTemplate/body.tid index 18c7d66dd..fb80c55b9 100644 --- a/core/ui/EditTemplate/body.tid +++ b/core/ui/EditTemplate/body.tid @@ -2,14 +2,6 @@ title: $:/core/ui/EditTemplate/body tags: $:/tags/EditTemplate \define lingo-base() $:/language/EditTemplate/ -<$list filter="[all[current]is[shadow]]"> -<div class="tw-message-box"> - -<<lingo Body/ShadowWarning>> - -</div> -</$list> - <$reveal state="$:/ShowEditPreview" type="match" text="yes"> <em class="tw-edit"><<lingo Body/Hint>></em> <$button type="set" set="$:/ShowEditPreview" setTo="no"><<lingo Body/Preview/Button/Hide>></$button> diff --git a/core/ui/EditTemplate/shadowWarning.tid b/core/ui/EditTemplate/shadowWarning.tid new file mode 100644 index 000000000..0c1086e68 --- /dev/null +++ b/core/ui/EditTemplate/shadowWarning.tid @@ -0,0 +1,11 @@ +title: $:/core/ui/EditTemplate/shadowWarning +tags: $:/tags/EditTemplate + +\define lingo-base() $:/language/EditTemplate/ +<$list filter="[all[current]is[shadow]]"> +<div class="tw-message-box"> + +<<lingo Body/ShadowWarning>> + +</div> +</$list> diff --git a/core/wiki/tags/EditTemplate.tid b/core/wiki/tags/EditTemplate.tid index 9a0c11a89..9a405fb2d 100644 --- a/core/wiki/tags/EditTemplate.tid +++ b/core/wiki/tags/EditTemplate.tid @@ -1,2 +1,2 @@ title: $:/tags/EditTemplate -list: [[$:/core/ui/EditTemplate/controls]] [[$:/core/ui/EditTemplate/title]] [[$:/core/ui/EditTemplate/tags]] [[$:/core/ui/ViewTemplate/classic]] [[$:/core/ui/EditTemplate/body]] [[$:/core/ui/EditTemplate/type]] [[$:/core/ui/EditTemplate/fields]] +list: [[$:/core/ui/EditTemplate/controls]] [[$:/core/ui/EditTemplate/title]] [[$:/core/ui/EditTemplate/tags]] [[$:/core/ui/EditTemplate/shadowWarning]] [[$:/core/ui/ViewTemplate/classic]] [[$:/core/ui/EditTemplate/body]] [[$:/core/ui/EditTemplate/type]] [[$:/core/ui/EditTemplate/fields]] From 23a71b433e935cf183b0b51b94a4eecfb03ca767 Mon Sep 17 00:00:00 2001 From: Devin Weaver <suki@tritarget.org> Date: Sun, 27 Apr 2014 15:33:14 -0400 Subject: [PATCH 10/12] Rename isEqual to isArrayEqual --- boot/boot.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index 0e1168c2e..25101f55e 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -88,7 +88,7 @@ $tw.utils.each = function(object,callback) { /* Check if an array is equal by value and by reference. */ -$tw.utils.isEqual = function(array1,array2) { +$tw.utils.isArrayEqual = function(array1,array2) { if(array1 === array2) { return true; } array1 = array1 || []; array2 = array2 || []; if(array1.length !== array2.length) { return false; } @@ -802,7 +802,7 @@ $tw.Tiddler.prototype.isModified = function() { var ignoredFields = ["created", "modified", "title", "draft.title", "draft.of", "tags"], tiddler = this, origTiddler = $tw.wiki.getTiddler(this.fields["draft.of"]); - if(!$tw.utils.isEqual(tiddler.fields.tags,origTiddler.fields.tags)) { + if(!$tw.utils.isArrayEqual(tiddler.fields.tags,origTiddler.fields.tags)) { return true; } return !Object.keys(tiddler.fields).every(function(field) { From a505b6ffc07d19c1bdcb79e0c30e31dfce7f2433 Mon Sep 17 00:00:00 2001 From: Devin Weaver <suki@tritarget.org> Date: Sun, 27 Apr 2014 16:31:00 -0400 Subject: [PATCH 11/12] Move isModified from Tiddler to Wiki Replace this with a $tw.wiki.isModifiedTiddler(title) as part of the wiki object. This allows it to be used outside of the current Wiki which can change. --- boot/boot.js | 32 +++++++++++++++---------------- core/modules/widgets/navigator.js | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/boot/boot.js b/boot/boot.js index 25101f55e..c54fa53d6 100644 --- a/boot/boot.js +++ b/boot/boot.js @@ -795,22 +795,6 @@ $tw.Tiddler.prototype.isDraft = function() { return this.hasField("draft.of"); }; -$tw.Tiddler.prototype.isModified = function() { - if(!this.isDraft()) { - return false; - } - var ignoredFields = ["created", "modified", "title", "draft.title", "draft.of", "tags"], - tiddler = this, - origTiddler = $tw.wiki.getTiddler(this.fields["draft.of"]); - if(!$tw.utils.isArrayEqual(tiddler.fields.tags,origTiddler.fields.tags)) { - return true; - } - return !Object.keys(tiddler.fields).every(function(field) { - if(ignoredFields.indexOf(field) >= 0) { return true; } - return tiddler.fields[field] === origTiddler.fields[field]; - }); -}; - /* Register and install the built in tiddler field modules */ @@ -1140,6 +1124,22 @@ $tw.Wiki.prototype.deserializeTiddlers = function(type,text,srcFields) { } }; +$tw.Wiki.prototype.isModifiedTiddler = function(title) { + var tiddler = this.getTiddler(title); + if(!tiddler.isDraft()) { + return false; + } + var ignoredFields = ["created", "modified", "title", "draft.title", "draft.of", "tags"], + origTiddler = this.getTiddler(tiddler.fields["draft.of"]); + if(!$tw.utils.isArrayEqual(tiddler.fields.tags,origTiddler.fields.tags)) { + return true; + } + return !Object.keys(tiddler.fields).every(function(field) { + if(ignoredFields.indexOf(field) >= 0) { return true; } + return tiddler.fields[field] === origTiddler.fields[field]; + }); +}; + /* Register the built in tiddler deserializer modules */ diff --git a/core/modules/widgets/navigator.js b/core/modules/widgets/navigator.js index 0f75cb7e9..40aaae9cf 100755 --- a/core/modules/widgets/navigator.js +++ b/core/modules/widgets/navigator.js @@ -315,7 +315,7 @@ NavigatorWidget.prototype.handleSaveTiddlerEvent = function(event) { {title: draftTitle} } )); - } else if(!tiddler.isModified()) { + } else if(!this.wiki.isModifiedTiddler(title)) { event.type = "tw-cancel-tiddler"; this.dispatchEvent(event); } else if(isConfirmed) { From 075cf544e48472f9d04b97c409f4322d90f64f03 Mon Sep 17 00:00:00 2001 From: Devin Weaver <suki@tritarget.org> Date: Sun, 27 Apr 2014 17:13:27 -0400 Subject: [PATCH 12/12] Use new get filter from commit 570cad1c --- core/ui/EditTemplate/shadowWarning.tid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ui/EditTemplate/shadowWarning.tid b/core/ui/EditTemplate/shadowWarning.tid index 0c1086e68..ba4da6a99 100644 --- a/core/ui/EditTemplate/shadowWarning.tid +++ b/core/ui/EditTemplate/shadowWarning.tid @@ -2,7 +2,7 @@ title: $:/core/ui/EditTemplate/shadowWarning tags: $:/tags/EditTemplate \define lingo-base() $:/language/EditTemplate/ -<$list filter="[all[current]is[shadow]]"> +<$list filter="[all[current]get[draft.of]is[shadow]]"> <div class="tw-message-box"> <<lingo Body/ShadowWarning>>