From 2368d471e8104939ed5339dfd40819efa1cf562a Mon Sep 17 00:00:00 2001 From: Giulio Cesare Solaroli Date: Tue, 3 Mar 2015 17:42:25 +0100 Subject: [PATCH] Added HTML native support for auto-completion in tag editor Not sure on which browser this feature is working; only tested in Chrome for Mac. --- .../Clipperz/PM/UI/Components/Cards/Detail.js | 4 ++ .../Clipperz/PM/UI/Components/Cards/Edit.js | 12 ++--- .../PM/UI/Components/Cards/TagEditor.js | 50 +++++++++++-------- .../PM/UI/Components/Pages/CardDetailPage.js | 4 ++ .../PM/UI/Components/Pages/MainPage.js | 2 + .../PM/UI/Components/Panels/MainPanel.js | 7 +-- .../delta/js/Clipperz/PM/UI/MainController.js | 8 +-- 7 files changed, 53 insertions(+), 34 deletions(-) diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Detail.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Detail.js index f52148a..5951bff 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Detail.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Detail.js @@ -25,6 +25,10 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Cards'); Clipperz.PM.UI.Components.Cards.Detail = React.createClass({ + propTypes: { + 'allTags': React.PropTypes.array, + }, + viewComponentProps: function () { var result; diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Edit.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Edit.js index aa19ef1..2b683df 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Edit.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/Edit.js @@ -29,6 +29,7 @@ Clipperz.PM.UI.Components.Cards.Edit = React.createClass({ //============================================================================ propTypes: { + 'allTags': React.PropTypes.array, // 'label': React.PropTypes.string /*.isRequired */ , // 'loading': React.PropTypes.bool, }, @@ -264,13 +265,12 @@ console.log("DROP"); //, anEvent); //............................................................................ - renderTags: function (someTags) { - var tags; - var allTags; + cleanupTags: function (someTags) { + return MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, someTags).sort(Clipperz.Base.caseInsensitiveCompare); + }, - tags = MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, someTags).sort(Clipperz.Base.caseInsensitiveCompare); - allTags = tags; - return Clipperz.PM.UI.Components.Cards.TagEditor({'selectedTags':tags, 'allTags':allTags, 'readOnly':false }); + renderTags: function (someTags) { + return Clipperz.PM.UI.Components.Cards.TagEditor({'selectedTags':this.cleanupTags(someTags), 'allTags':this.cleanupTags(this.props['allTags']), 'readOnly':false }); }, //............................................................................ diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/TagEditor.js b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/TagEditor.js index e06f072..2c3b389 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Cards/TagEditor.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Cards/TagEditor.js @@ -43,10 +43,14 @@ Clipperz.PM.UI.Components.Cards.TagEditor = React.createClass({ //---------------------------------------------------------------------------- - stillNotUsedTags: function () { -// return MochiKit.Base.filter(function, this.props['allTags']); + listOfTagsNotUsedYet: function () { + var selectedTags = this.props['selectedTags']; +//console.log("ALL TAGS", this.props['allTags']); +//console.log("SELECTED TAGS", this.props['selectedTags']); + return MochiKit.Base.filter(function (aTag) { return selectedTags.indexOf(aTag) == -1 }, this.props['allTags']); +// return this.props['allTags']; }, - + //---------------------------------------------------------------------------- removeTagHandler: function (anEvent) { @@ -67,24 +71,23 @@ Clipperz.PM.UI.Components.Cards.TagEditor = React.createClass({ //---------------------------------------------------------------------------- + addTagValue: function (anEvent) { + this.addTag(anEvent.currentTarget.value); + anEvent.currentTarget.value = ""; + }, + handleKeyDown: function(anEvent) { switch (anEvent.keyCode) { case 9: // tab - console.log("TAB"); -// if (anEvent.shiftKey || !this.state.isOpen) { -// return; -// } -// this.selectFocusedOption(); - break; + this.addTagValue(anEvent); + break; case 13: // enter - console.log("ENTER"); - this.addTag(anEvent.currentTarget.value); - anEvent.currentTarget.value = ""; -// this.selectFocusedOption(); - break; - + this.addTagValue(anEvent); + anEvent.preventDefault(); + break; +/* case 27: // escape console.log("ESCAPE"); // if (this.state.isOpen) { @@ -92,22 +95,22 @@ Clipperz.PM.UI.Components.Cards.TagEditor = React.createClass({ // } else { // this.clearValue(); // } - break; + break; case 38: // up console.log("UP"); // this.focusPreviousOption(); - break; + break; case 40: // down console.log("DOWN"); // this.focusNextOption(); - break; + break; - default: return; + default: + return; +*/ } - - anEvent.preventDefault(); }, //---------------------------------------------------------------------------- @@ -120,7 +123,10 @@ Clipperz.PM.UI.Components.Cards.TagEditor = React.createClass({ }, renderEditField: function () { - return React.DOM.input({'type':'text', 'onKeyDown':this.handleKeyDown, 'placeholder': "tag"}); + return [ + React.DOM.input({'type':'text', 'list':'tagListData', 'onKeyDown':this.handleKeyDown, 'placeholder': "tag"}), + React.DOM.datalist({'id':'tagListData'}, MochiKit.Base.map(function (aTag) { return React.DOM.option({}, aTag); }, this.listOfTagsNotUsedYet())) + ]; }, render: function () { diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js index 2cc2a78..49d7041 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/CardDetailPage.js @@ -24,6 +24,10 @@ refer to http://www.clipperz.com. Clipperz.Base.module('Clipperz.PM.UI.Components.Pages'); Clipperz.PM.UI.Components.Pages.CardDetailPage = React.createClass({ + propTypes: { + 'allTags': React.PropTypes.array, + }, + /* viewComponentProps: function () { var result; diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/MainPage.js b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/MainPage.js index 866c31b..3ed9ae1 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Pages/MainPage.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Pages/MainPage.js @@ -33,6 +33,8 @@ Clipperz.PM.UI.Components.Pages.MainPage = React.createClass({ }, propTypes: { + 'tags': React.PropTypes.object, + 'allTags': React.PropTypes.array, 'messageBox': React.PropTypes.object.isRequired, 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL', 'OFFLINE']).isRequired, 'accountInfo': React.PropTypes.object.isRequired, diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js index 894fce6..34d4028 100644 --- a/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js +++ b/frontend/delta/js/Clipperz/PM/UI/Components/Panels/MainPanel.js @@ -29,9 +29,10 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({ //========================================================================= propTypes: { - 'messageBox': React.PropTypes.object.isRequired, - 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL', 'OFFLINE']).isRequired, - 'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired, + 'allTags': React.PropTypes.array, + 'messageBox': React.PropTypes.object.isRequired, + 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL', 'OFFLINE']).isRequired, + 'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired, }, style: function () { diff --git a/frontend/delta/js/Clipperz/PM/UI/MainController.js b/frontend/delta/js/Clipperz/PM/UI/MainController.js index ec8c73c..8315804 100644 --- a/frontend/delta/js/Clipperz/PM/UI/MainController.js +++ b/frontend/delta/js/Clipperz/PM/UI/MainController.js @@ -242,12 +242,11 @@ console.log("THE BROWSER IS OFFLINE"); shouldShowRegistrationForm = parameters['shouldShowRegistrationForm'] && canRegisterNewUsers; this.pages()['loginPage'].setProps({'mode':this.loginMode(), 'isNewUserRegistrationAvailable':canRegisterNewUsers}); + this.showLoginForm(); if (shouldShowRegistrationForm) { this.showRegistrationForm_handler(); - } else { - this.showLoginForm(); } - + // this.overlay().done("", 0.5); this.overlay().hide(); }, @@ -725,6 +724,9 @@ console.log("THE BROWSER IS OFFLINE"); // MochiKit.Base.method(this.user(), 'getTags', this.shouldIncludeArchivedCards()), MochiKit.Base.method(this, 'allTags', this.shouldIncludeArchivedCards()), MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'tags'), + MochiKit.Base.method(this, 'allTags', true || this.shouldIncludeArchivedCards()), + MochiKit.Base.keys, + MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'allTags'), MochiKit.Base.method(this, 'getAllCardsCount'), MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'allCardsCount'), MochiKit.Base.method(this, 'getArchivedCardsCount'),