1
0
mirror of http://git.whoc.org.uk/git/password-manager.git synced 2024-11-14 19:09:03 +01:00

Implemented card archiving, both the DataModel login and UI (still very rough, though)

This commit is contained in:
Giulio Cesare Solaroli 2014-07-30 09:28:05 +02:00
parent c0f96f5de9
commit 86634cc4af
9 changed files with 213 additions and 32 deletions

View File

@ -236,6 +236,17 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
], {trace:false}); ], {trace:false});
}, },
'archive': function () {
return this.addTag(Clipperz.PM.DataModel.Record.archivedTag);
},
'isArchived': function () {
return Clipperz.Async.callbacks("Record.isArchived", [
MochiKit.Base.method(this, 'tags'),
function (someTags) { return MochiKit.Iter.some(someTags, MochiKit.Base.partial(MochiKit.Base.objEqual, Clipperz.PM.DataModel.Record.archivedTag))},
], {trace:false});
},
//========================================================================= //=========================================================================
'headerNotes': function () { 'headerNotes': function () {
@ -988,12 +999,18 @@ Clipperz.PM.DataModel.Record.defaultCardInfo = {
'_reference': MochiKit.Base.methodcaller('reference'), '_reference': MochiKit.Base.methodcaller('reference'),
'_searchableContent': MochiKit.Base.methodcaller('searchableContent'), '_searchableContent': MochiKit.Base.methodcaller('searchableContent'),
'_accessDate': MochiKit.Base.methodcaller('accessDate'), '_accessDate': MochiKit.Base.methodcaller('accessDate'),
'_isArchived': MochiKit.Base.methodcaller('isArchived'),
'label': MochiKit.Base.methodcaller('label'), 'label': MochiKit.Base.methodcaller('label'),
'favicon': MochiKit.Base.methodcaller('favicon') 'favicon': MochiKit.Base.methodcaller('favicon')
}; };
Clipperz.PM.DataModel.Record.defaultSearchField = '_searchableContent'; Clipperz.PM.DataModel.Record.defaultSearchField = '_searchableContent';
Clipperz.PM.DataModel.Record.tagChar = '#'; Clipperz.PM.DataModel.Record.tagChar = '\uE009';
Clipperz.PM.DataModel.Record.specialTagsWrapper = '___';
Clipperz.PM.DataModel.Record.specialTagsConstructor = function (aTag) {
return Clipperz.PM.DataModel.Record.specialTagsWrapper + aTag + Clipperz.PM.DataModel.Record.specialTagsWrapper;
}
Clipperz.PM.DataModel.Record.archivedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('archived');
Clipperz.PM.DataModel.Record.regExpForTag = function (aTag) { Clipperz.PM.DataModel.Record.regExpForTag = function (aTag) {
return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagChar + aTag, 'g'); return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagChar + aTag, 'g');
}; };

View File

@ -515,8 +515,15 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('tags')), MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('tags')),
Clipperz.Async.collectAll, Clipperz.Async.collectAll,
MochiKit.Base.flattenArray, MochiKit.Base.flattenArray,
Clipperz.Base.arrayWithUniqueValues MochiKit.Iter.groupby,
function (someGroups) {
return MochiKit.Iter.reduce(function(aCollector, aGroup) {
if (aGroup[0] != Clipperz.PM.DataModel.Record.archivedTag) {
aCollector[aGroup[0]] = MochiKit.Iter.list(aGroup[1]).length;
}
return aCollector;
}, someGroups, {});
}
], {trace:false}); ], {trace:false});
}, },
@ -534,7 +541,19 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
return Clipperz.Async.callbacks("User.getRecordsInfo", [ return Clipperz.Async.callbacks("User.getRecordsInfo", [
MochiKit.Base.method(this, 'getRecords'), MochiKit.Base.method(this, 'getRecords'),
MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", someInfo, {trace:false})), MochiKit.Base.partial(MochiKit.Base.map, Clipperz.Async.collectResults("collectResults", someInfo, {trace:false})),
Clipperz.Async.collectAll Clipperz.Async.collectAll,
function (aResult) {
var result;
if (shouldIncludeArchivedCards == false) {
result = MochiKit.Base.filter(function (aRecordInfo) { return !aRecordInfo['_isArchived']; }, aResult);
} else {
result = aResult;
}
return result;
}
], {trace:false}); ], {trace:false});
}, },
/* /*

View File

@ -39,7 +39,8 @@ Clipperz.PM.UI.Components.Cards.List = React.createClass({
renderItem: function (anItem) { renderItem: function (anItem) {
var classes = { var classes = {
'selected': this.props['selectedCard'] ? this.props['selectedCard']['_reference'] == anItem['_reference'] : false 'selected': this.props['selectedCard'] ? this.props['selectedCard']['_reference'] == anItem['_reference'] : false,
'archived': anItem['_isArchived']
}; };
return React.DOM.li({'className':React.addons.classSet(classes), 'onClick': this.handleClick, 'key':anItem['_reference'], 'data-reference':anItem['_reference'], 'data-label':anItem['label']}, [ return React.DOM.li({'className':React.addons.classSet(classes), 'onClick': this.handleClick, 'key':anItem['_reference'], 'data-reference':anItem['_reference'], 'data-label':anItem['label']}, [

View File

@ -36,8 +36,22 @@ Clipperz.PM.UI.Components.Selections = React.createClass({
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectRecentCards'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectRecentCards');
}, },
handleCheckboxChanges: function (anEvent) {
if (anEvent.target.checked) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showArchivedCards');
} else {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'hideArchivedCards');
}
},
render: function () { render: function () {
//console.log("Selections", this.props); var tagInfo;
var tags;
tagInfo = this.props['tags'] ? this.props['tags'] : {};
// tagInfo = {"tag1":1, "tag2":2, "tag3":1, "tag4":2, "tag5":1, "tag6":2, "tag7":1, "tag8":3, "tag9":1, "tag10":11, "tag11":1, "tag12":8, "tag13":1, "tag14":3, "tag15":1, "tag16":1};
tags = MochiKit.Base.keys(tagInfo).sort(Clipperz.Base.caseInsensitiveCompare);
return React.DOM.div({'key':'selections', 'id':'selections'}, [ return React.DOM.div({'key':'selections', 'id':'selections'}, [
React.DOM.ul({'className':'defaultSet'}, [ React.DOM.ul({'className':'defaultSet'}, [
React.DOM.li({'className':'allCards', onClick: this.selectAll}, "All"), React.DOM.li({'className':'allCards', onClick: this.selectAll}, "All"),
@ -49,7 +63,11 @@ Clipperz.PM.UI.Components.Selections = React.createClass({
React.DOM.input({'type':'text', 'id':'searchValue', 'name':'search'}) React.DOM.input({'type':'text', 'id':'searchValue', 'name':'search'})
]) ])
]), ]),
React.DOM.ul({'className':'tagList'}, MochiKit.Base.map(function (aTag) { return Clipperz.PM.UI.Components.TagIndexItem({'label':aTag}); }, this.props['tags'] ? this.props['tags'] : [])) React.DOM.ul({'className':'tagList'}, MochiKit.Base.map(function (aTag) {return Clipperz.PM.UI.Components.TagIndexItem({'label':aTag, 'count':tagInfo[aTag]}); }, tags)),
React.DOM.div({'className':'showArchivedCards'}, [
React.DOM.input({'type':'checkbox', 'onChange':this.handleCheckboxChanges}),
React.DOM.h5({}, "Show archived cards")
]),
]); ]);
} }

View File

@ -30,6 +30,7 @@ Clipperz.PM.UI.Components.TagIndexItem = React.createClass({
propTypes: { propTypes: {
'label': React.PropTypes.string.isRequired, 'label': React.PropTypes.string.isRequired,
'count': React.PropTypes.number.isRequired,
}, },
handleClick: function (anEvent) { handleClick: function (anEvent) {
@ -38,7 +39,10 @@ Clipperz.PM.UI.Components.TagIndexItem = React.createClass({
}, },
render: function () { render: function () {
return React.DOM.li({onClick: this.handleClick, 'data-tag':this.props['label']}, this.props['label']); return React.DOM.li({'onClick': this.handleClick, 'data-tag':this.props['label']}, [
React.DOM.span({'className':'tagLabel'}, this.props['label']),
React.DOM.span({'className':'tagCount'}, this.props['count'])
]);
}, },
//========================================================================= //=========================================================================

View File

@ -32,6 +32,8 @@ Clipperz.PM.UI.MainController = function() {
this._user = null; this._user = null;
this._filter = {'type':'ALL'}; this._filter = {'type':'ALL'};
this._shouldIncludeArchivedCards = false;
this._isSelectionPanelOpen = false; this._isSelectionPanelOpen = false;
this._isSettingsPanelOpen = false; this._isSettingsPanelOpen = false;
@ -76,6 +78,9 @@ Clipperz.PM.UI.MainController = function() {
'archiveCard', 'archiveCard',
'editCard', 'editCard',
'showArchivedCards',
'hideArchivedCards',
'goBackToMainPage', 'goBackToMainPage',
'maskClick', 'maskClick',
]); ]);
@ -366,6 +371,15 @@ console.log("SET USER", aUser);
return this._filter; return this._filter;
}, },
shouldIncludeArchivedCards: function () {
return this._shouldIncludeArchivedCards;
},
setShouldIncludeArchivedCards: function (aValue) {
this._shouldIncludeArchivedCards = aValue;
},
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
collectFieldInfo: function (aField) { collectFieldInfo: function (aField) {
@ -418,6 +432,8 @@ console.log("SET USER", aUser);
deferredResult.setValue('notes'); deferredResult.setValue('notes');
deferredResult.addMethod(aRecord, 'tags'); deferredResult.addMethod(aRecord, 'tags');
deferredResult.setValue('tags'); deferredResult.setValue('tags');
deferredResult.addMethod(aRecord, 'isArchived');
deferredResult.setValue('isArchived');
deferredResult.addMethod(aRecord, 'fields'); deferredResult.addMethod(aRecord, 'fields');
deferredResult.addCallback(MochiKit.Base.values); deferredResult.addCallback(MochiKit.Base.values);
@ -533,6 +549,27 @@ console.log("SET USER", aUser);
return deferredResult; return deferredResult;
}, },
refreshSelectedCards: function () {
return this.updateSelectedCards(this.shouldIncludeArchivedCards(), this.filter());
},
refreshUI: function (selectedCardReference) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.refreshUI', {trace:false});
deferredResult.addMethod(this, 'refreshSelectedCards');
deferredResult.addMethod(this, 'renderTags');
if (selectedCardReference != null) {
deferredResult.addMethod(this.user(), 'getRecord', selectedCardReference);
deferredResult.addMethod(this, 'collectRecordInfo');
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'selectedCard');
}
deferredResult.callback();
return deferredResult;
},
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
setPageProperties: function (aPageName, aKey, aValue) { setPageProperties: function (aPageName, aKey, aValue) {
@ -543,19 +580,21 @@ console.log("SET USER", aUser);
return aValue; return aValue;
}, },
renderTags: function () {
return Clipperz.Async.callbacks("MainController.renderTags", [
MochiKit.Base.method(this.user(), 'getTags'),
// MochiKit.Base.methodcaller('sort', Clipperz.Base.caseInsensitiveCompare),
MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'tags'),
], {trace:false});
},
renderAccountData: function () { renderAccountData: function () {
var deferredResult; return Clipperz.Async.callbacks("MainController.renderAccountData", [
MochiKit.Base.method(this, 'setFilter', 'ALL'),
deferredResult = new Clipperz.Async.Deferred('MainController.renderAccountData', {trace:false}); // MochiKit.Base.method(this, 'refreshSelectedCards'),
deferredResult.addMethod(this, 'setFilter', 'ALL'); // MochiKit.Base.method(this, 'renderTags'),
deferredResult.addMethod(this, 'updateSelectedCards', false); MochiKit.Base.method(this, 'refreshUI', null)
], {trace:false});
deferredResult.addMethod(this.user(), 'getTags');
deferredResult.addMethodcaller('sort', Clipperz.Base.caseInsensitiveCompare);
deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'tags');
deferredResult.callback();
return deferredResult;
}, },
//========================================================================= //=========================================================================
@ -858,8 +897,20 @@ console.log("SET USER", aUser);
this.refreshCurrentPage(); this.refreshCurrentPage();
}, },
cardSelected_handler: function (aReference) { cardSelected_handler: function (someInfo) {
this.updateSelectedCard(aReference); this.updateSelectedCard(someInfo);
},
//----------------------------------------------------------------------------
askConfirmation: function (aMessage) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('MainController.askConfirmation', {trace:false});
deferredResult.callback();
// deferredResult.cancel();
return deferredResult;
}, },
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -869,11 +920,22 @@ console.log("ADD CARD CLICK");
}, },
deleteCard_handler: function (anEvent) { deleteCard_handler: function (anEvent) {
console.log("DELETE CARD", anEvent['reference']); return Clipperz.Async.callbacks("MainController.deleteCard_handler", [
MochiKit.Base.method(this, 'askConfirmation', {'message':"Delete card?"}),
MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']),
MochiKit.Base.method(this.user(), 'deleteRecord'),
MochiKit.Base.method(this.user(), 'saveChanges'),
MochiKit.Base.method(this, 'refreshUI')
], {trace:false});
}, },
archiveCard_handler: function (anEvent) { archiveCard_handler: function (anEvent) {
console.log("ARCHIVE CARD", anEvent['reference']); return Clipperz.Async.callbacks("MainController.archiveCard_handler", [
MochiKit.Base.method(this.user(), 'getRecord', anEvent['reference']),
MochiKit.Base.methodcaller('archive'),
MochiKit.Base.method(this.user(), 'saveChanges'),
MochiKit.Base.method(this, 'refreshUI', anEvent['reference'])
], {trace:true});
}, },
editCard_handler: function (anEvent) { editCard_handler: function (anEvent) {
@ -889,17 +951,29 @@ console.log("EDIT CARD", anEvent['reference']);
selectAllCards_handler: function () { selectAllCards_handler: function () {
this.setFilter('ALL'); this.setFilter('ALL');
this.updateSelectedCards(false, this.filter()); return this.refreshSelectedCards();
}, },
selectRecentCards_handler: function () { selectRecentCards_handler: function () {
this.setFilter('RECENT'); this.setFilter('RECENT');
this.updateSelectedCards(false, this.filter()); return this.refreshSelectedCards();
}, },
tagSelected_handler: function (aTag) { tagSelected_handler: function (aTag) {
this.setFilter('TAG', aTag); this.setFilter('TAG', aTag);
this.updateSelectedCards(false, this.filter()); return this.refreshSelectedCards();
},
//............................................................................
showArchivedCards_handler: function () {
this.setShouldIncludeArchivedCards(true);
return this.refreshSelectedCards();
},
hideArchivedCards_handler: function () {
this.setShouldIncludeArchivedCards(false);
return this.refreshSelectedCards();
}, },
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -16,6 +16,47 @@
} }
} }
#selections {
@include flexbox();
@include flex-direction(column);
min-height: 100%;
ul.defaultSet {
@include flex(none);
}
.search {
@include flex(none);
}
ul.tagList {
@include flex(auto);
margin-left: 0px;
// overflow-y: scroll;
li {
// @include flexbox();
span.tagLabel {
// @include flex(auto);
}
span.tagCount {
// @include flex(none);
background-color: gray;
font-size: 10pt;
margin-left: 10px;
padding: 0px 4px;
@include border-radius(4px);
}
}
}
.showArchivedCards {
@include flex(none);
}
}
#mainPanel { #mainPanel {
// background-color: $yellow; // background-color: $yellow;

View File

@ -14,10 +14,6 @@ div.cardList {
} }
ul { ul {
li.selected {
background-color: yellow;
}
li { li {
cursor: pointer; cursor: pointer;
@ -26,6 +22,14 @@ div.cardList {
@include flexbox(); @include flexbox();
@include flex-direction(row); @include flex-direction(row);
&.selected {
background-color: yellow;
}
&.archived {
background-color: pink;
}
.favicon { .favicon {
width: $cardListHeight; width: $cardListHeight;
@include flex(none); @include flex(none);

View File

@ -3,7 +3,7 @@
color: $main-alternate-text-color; color: $main-alternate-text-color;
font-size: 18pt; font-size: 18pt;
overflow: scroll; overflow: scroll;
height: 100%; // height: 100%;
$iconColumnWidth: 40px; $iconColumnWidth: 40px;
@ -66,4 +66,7 @@
font-size: 14pt; font-size: 14pt;
} }
} }
.showArchivedCards {
}
} }