Implemented card archiving, both the DataModel login and UI (still very rough, though)
This commit is contained in:
		| @@ -236,6 +236,17 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt | ||||
| 		], {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 () { | ||||
| @@ -988,12 +999,18 @@ Clipperz.PM.DataModel.Record.defaultCardInfo = { | ||||
| 	'_reference':			MochiKit.Base.methodcaller('reference'), | ||||
| 	'_searchableContent':	MochiKit.Base.methodcaller('searchableContent'), | ||||
| 	'_accessDate':			MochiKit.Base.methodcaller('accessDate'), | ||||
| 	'_isArchived':			MochiKit.Base.methodcaller('isArchived'), | ||||
| 	'label':				MochiKit.Base.methodcaller('label'), | ||||
| 	'favicon':				MochiKit.Base.methodcaller('favicon') | ||||
| }; | ||||
| 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) { | ||||
| 	return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagChar + aTag, 'g'); | ||||
| }; | ||||
|   | ||||
| @@ -515,8 +515,15 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { | ||||
| 			MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.methodcaller('tags')), | ||||
| 			Clipperz.Async.collectAll, | ||||
| 			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}); | ||||
| 	}, | ||||
|  | ||||
| @@ -534,7 +541,19 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, { | ||||
| 		return Clipperz.Async.callbacks("User.getRecordsInfo", [ | ||||
| 			MochiKit.Base.method(this, 'getRecords'), | ||||
| 			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}); | ||||
| 	}, | ||||
| /* | ||||
|   | ||||
| @@ -39,7 +39,8 @@ Clipperz.PM.UI.Components.Cards.List = React.createClass({ | ||||
| 	 | ||||
| 	renderItem: function (anItem) { | ||||
| 		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']}, [ | ||||
|   | ||||
| @@ -36,8 +36,22 @@ Clipperz.PM.UI.Components.Selections = React.createClass({ | ||||
| 		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 () { | ||||
| //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'}, [ | ||||
| 			React.DOM.ul({'className':'defaultSet'}, [ | ||||
| 				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.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") | ||||
| 			]), | ||||
| 		]); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -30,6 +30,7 @@ Clipperz.PM.UI.Components.TagIndexItem = React.createClass({ | ||||
|  | ||||
| 	propTypes: { | ||||
| 		'label':	React.PropTypes.string.isRequired, | ||||
| 		'count':	React.PropTypes.number.isRequired, | ||||
| 	}, | ||||
|  | ||||
| 	handleClick: function (anEvent) { | ||||
| @@ -38,7 +39,10 @@ Clipperz.PM.UI.Components.TagIndexItem = React.createClass({ | ||||
| 	}, | ||||
| 	 | ||||
| 	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']) | ||||
| 		]); | ||||
| 	}, | ||||
|  | ||||
| 	//========================================================================= | ||||
|   | ||||
| @@ -32,6 +32,8 @@ Clipperz.PM.UI.MainController = function() { | ||||
| 	this._user		= null; | ||||
| 	this._filter	= {'type':'ALL'}; | ||||
|  | ||||
| 	this._shouldIncludeArchivedCards = false; | ||||
|  | ||||
| 	this._isSelectionPanelOpen = false; | ||||
| 	this._isSettingsPanelOpen = false; | ||||
| 	 | ||||
| @@ -76,6 +78,9 @@ Clipperz.PM.UI.MainController = function() { | ||||
| 		'archiveCard', | ||||
| 		'editCard', | ||||
| 		 | ||||
| 		'showArchivedCards', | ||||
| 		'hideArchivedCards', | ||||
| 		 | ||||
| 		'goBackToMainPage', | ||||
| 		'maskClick', | ||||
| 	]); | ||||
| @@ -366,6 +371,15 @@ console.log("SET USER", aUser); | ||||
| 		return this._filter; | ||||
| 	}, | ||||
|  | ||||
|  | ||||
| 	shouldIncludeArchivedCards: function () { | ||||
| 		return this._shouldIncludeArchivedCards; | ||||
| 	}, | ||||
| 	 | ||||
| 	setShouldIncludeArchivedCards: function (aValue) { | ||||
| 		this._shouldIncludeArchivedCards = aValue; | ||||
| 	}, | ||||
|  | ||||
| 	//---------------------------------------------------------------------------- | ||||
|  | ||||
| 	collectFieldInfo: function (aField) { | ||||
| @@ -418,6 +432,8 @@ console.log("SET USER", aUser); | ||||
| 		deferredResult.setValue('notes'); | ||||
| 		deferredResult.addMethod(aRecord, 'tags'); | ||||
| 		deferredResult.setValue('tags'); | ||||
| 		deferredResult.addMethod(aRecord, 'isArchived'); | ||||
| 		deferredResult.setValue('isArchived'); | ||||
|  | ||||
| 		deferredResult.addMethod(aRecord, 'fields'); | ||||
| 		deferredResult.addCallback(MochiKit.Base.values); | ||||
| @@ -533,6 +549,27 @@ console.log("SET USER", aUser); | ||||
| 		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) { | ||||
| @@ -543,19 +580,21 @@ console.log("SET USER", aUser); | ||||
| 		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 () { | ||||
| 		var deferredResult; | ||||
|  | ||||
| 		deferredResult = new Clipperz.Async.Deferred('MainController.renderAccountData', {trace:false}); | ||||
| 		deferredResult.addMethod(this, 'setFilter', 'ALL'); | ||||
| 		deferredResult.addMethod(this, 'updateSelectedCards', false); | ||||
| 		 | ||||
| 		deferredResult.addMethod(this.user(), 'getTags'); | ||||
| 		deferredResult.addMethodcaller('sort', Clipperz.Base.caseInsensitiveCompare); | ||||
| 		deferredResult.addMethod(this, 'setPageProperties', 'mainPage', 'tags'); | ||||
| 		deferredResult.callback(); | ||||
|  | ||||
| 		return deferredResult; | ||||
| 		return Clipperz.Async.callbacks("MainController.renderAccountData", [ | ||||
| 			MochiKit.Base.method(this, 'setFilter', 'ALL'), | ||||
| //			MochiKit.Base.method(this, 'refreshSelectedCards'), | ||||
| //			MochiKit.Base.method(this, 'renderTags'), | ||||
| 			MochiKit.Base.method(this, 'refreshUI', null) | ||||
| 		], {trace:false}); | ||||
| 	}, | ||||
|  | ||||
| 	//========================================================================= | ||||
| @@ -858,8 +897,20 @@ console.log("SET USER", aUser); | ||||
| 		this.refreshCurrentPage(); | ||||
| 	}, | ||||
|  | ||||
| 	cardSelected_handler: function (aReference) { | ||||
| 		this.updateSelectedCard(aReference); | ||||
| 	cardSelected_handler: function (someInfo) { | ||||
| 		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) { | ||||
| 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) { | ||||
| 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) { | ||||
| @@ -889,17 +951,29 @@ console.log("EDIT CARD", anEvent['reference']); | ||||
|  | ||||
| 	selectAllCards_handler: function () { | ||||
| 		this.setFilter('ALL'); | ||||
| 		this.updateSelectedCards(false, this.filter()); | ||||
| 		return this.refreshSelectedCards(); | ||||
| 	}, | ||||
| 	 | ||||
| 	selectRecentCards_handler: function () { | ||||
| 		this.setFilter('RECENT'); | ||||
| 		this.updateSelectedCards(false, this.filter()); | ||||
| 		return this.refreshSelectedCards(); | ||||
| 	}, | ||||
|  | ||||
| 	tagSelected_handler: function (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(); | ||||
| 	}, | ||||
| 	 | ||||
| 	//---------------------------------------------------------------------------- | ||||
|   | ||||
| @@ -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 { | ||||
| //	background-color: $yellow; | ||||
|  | ||||
|   | ||||
| @@ -14,10 +14,6 @@ div.cardList { | ||||
| 	} | ||||
|  | ||||
| 	ul { | ||||
| 		li.selected { | ||||
| 			background-color: yellow; | ||||
| 		} | ||||
|  | ||||
| 		li { | ||||
| 			cursor: pointer; | ||||
|  | ||||
| @@ -26,6 +22,14 @@ div.cardList { | ||||
| 			@include flexbox(); | ||||
| 			@include flex-direction(row); | ||||
|  | ||||
| 			&.selected { | ||||
| 				background-color: yellow; | ||||
| 			} | ||||
| 			 | ||||
| 			&.archived { | ||||
| 				background-color: pink; | ||||
| 			} | ||||
|  | ||||
| 			.favicon { | ||||
| 				width: $cardListHeight; | ||||
| 				@include flex(none); | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| 	color: $main-alternate-text-color; | ||||
| 	font-size: 18pt; | ||||
| 	overflow: scroll; | ||||
| 	height: 100%; | ||||
| //	height: 100%; | ||||
|  | ||||
| 	$iconColumnWidth: 40px; | ||||
|  | ||||
| @@ -66,4 +66,7 @@ | ||||
| 			font-size: 14pt; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	.showArchivedCards { | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Giulio Cesare Solaroli
					Giulio Cesare Solaroli