mirror of
				http://git.whoc.org.uk/git/password-manager.git
				synced 2025-10-31 19:27:34 +01:00 
			
		
		
		
	Added very first rough prototype of tag editor
This commit is contained in:
		| @@ -27,12 +27,13 @@ Clipperz.PM.UI.Components.Cards.Detail = React.createClass({ | ||||
|  | ||||
| 	viewComponentProps: function () { | ||||
| 		var	result; | ||||
| 		 | ||||
|  | ||||
| 		result = this.props['selectedCard']; | ||||
| 		if (result) { | ||||
| 			result['style'] = this.props['style']; | ||||
| 			result['ask'] = (this.props['style'] == 'narrow') ? this.props['ask'] : null; | ||||
| 			result['showGlobalMask'] = this.props['showGlobalMask']; | ||||
| 			result['allTags'] = this.props['allTags']; | ||||
| 		} | ||||
| 		 | ||||
| 		return result; | ||||
|   | ||||
| @@ -243,15 +243,13 @@ console.log("DROP");	//, anEvent); | ||||
|  | ||||
| 	//............................................................................ | ||||
|  | ||||
| 	renderTag: function (aTag) { | ||||
| 		return	React.DOM.div({'className':'cardTag'}, aTag); | ||||
| 	}, | ||||
| 	 | ||||
| 	renderTags: function (someTags) { | ||||
| 		var	tags; | ||||
| 		var	allTags; | ||||
|  | ||||
| 		tags = MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, someTags).sort(Clipperz.Base.caseInsensitiveCompare); | ||||
| 		return	React.DOM.div({'className':'cardTags'}, MochiKit.Base.map(this.renderTag, tags)); | ||||
| 		allTags = tags; | ||||
| 		return	Clipperz.PM.UI.Components.Cards.TagEditor({'selectedTags':tags, 'allTags':allTags, 'readOnly':false }); | ||||
| 	}, | ||||
|  | ||||
| 	//............................................................................ | ||||
|   | ||||
							
								
								
									
										142
									
								
								frontend/delta/js/Clipperz/PM/UI/Components/Cards/TagEditor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								frontend/delta/js/Clipperz/PM/UI/Components/Cards/TagEditor.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| /* | ||||
|  | ||||
| Copyright 2008-2013 Clipperz Srl | ||||
|  | ||||
| This file is part of Clipperz, the online password manager. | ||||
| For further information about its features and functionalities please | ||||
| refer to http://www.clipperz.com. | ||||
|  | ||||
| * Clipperz is free software: you can redistribute it and/or modify it | ||||
|   under the terms of the GNU Affero General Public License as published | ||||
|   by the Free Software Foundation, either version 3 of the License, or  | ||||
|   (at your option) any later version. | ||||
|  | ||||
| * Clipperz is distributed in the hope that it will be useful, but  | ||||
|   WITHOUT ANY WARRANTY; without even the implied warranty of  | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
|   See the GNU Affero General Public License for more details. | ||||
|  | ||||
| * You should have received a copy of the GNU Affero General Public | ||||
|   License along with Clipperz. If not, see http://www.gnu.org/licenses/. | ||||
|  | ||||
| */ | ||||
|  | ||||
| 'use strict'; | ||||
| Clipperz.Base.module('Clipperz.PM.UI.Components.Cards'); | ||||
|  | ||||
| Clipperz.PM.UI.Components.Cards.TagEditor = React.createClass({ | ||||
|  | ||||
| 	//============================================================================ | ||||
|  | ||||
| 	propTypes: { | ||||
| 		'allTags':				React.PropTypes.array, | ||||
| 		'selectedTags':			React.PropTypes.array.isRequired, | ||||
| 		'readOnly':				React.PropTypes.bool.isRequired, | ||||
| 		'updateTagsCallback':	React.PropTypes.func, | ||||
| 	}, | ||||
|  | ||||
| 	//---------------------------------------------------------------------------- | ||||
|  | ||||
| 	isReadOnly: function () { | ||||
| 		return this.props['readOnly']; | ||||
| 	}, | ||||
|  | ||||
| 	//---------------------------------------------------------------------------- | ||||
|  | ||||
| 	stillNotUsedTags: function () { | ||||
| //		return MochiKit.Base.filter(function, this.props['allTags']); | ||||
| 	}, | ||||
|  | ||||
| 	//---------------------------------------------------------------------------- | ||||
|  | ||||
| 	removeTagHandler: function (anEvent) { | ||||
| 		this.removeTag(anEvent.currentTarget.dataset['label']); | ||||
| 	}, | ||||
|  | ||||
| 	addTag: function (aTag) { | ||||
| //console.log("ADD TAG", aTag); | ||||
| 		//	TODO: here we may need to include the record or its reference to let the MainController handle it properly. | ||||
| 		MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'addTag', aTag); | ||||
| 	}, | ||||
| 	 | ||||
| 	removeTag: function (aTag) { | ||||
| //console.log("REMOVE TAG", aTag); | ||||
| 		//	TODO: here we may need to include the record or its reference to let the MainController handle it properly. | ||||
| 		MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'removeTag', aTag); | ||||
| 	}, | ||||
|  | ||||
| 	//---------------------------------------------------------------------------- | ||||
|  | ||||
| 	handleKeyDown: function(anEvent) { | ||||
| 		switch (anEvent.keyCode) { | ||||
| 			 | ||||
| 			case 9: // tab | ||||
| 				console.log("TAB"); | ||||
| //				if (anEvent.shiftKey || !this.state.isOpen) { | ||||
| //					return; | ||||
| //				} | ||||
| //				this.selectFocusedOption(); | ||||
| 			break; | ||||
| 			 | ||||
| 			case 13: // enter | ||||
| 				console.log("ENTER"); | ||||
| 				this.addTag(anEvent.currentTarget.value); | ||||
| 				anEvent.currentTarget.value = ""; | ||||
| //				this.selectFocusedOption(); | ||||
| 			break; | ||||
| 			 | ||||
| 			case 27: // escape | ||||
| 				console.log("ESCAPE"); | ||||
| //				if (this.state.isOpen) { | ||||
| //					this.closeOnEscape(); | ||||
| //				} else { | ||||
| //					this.clearValue(); | ||||
| //				} | ||||
| 			break; | ||||
| 			 | ||||
| 			case 38: // up | ||||
| 				console.log("UP"); | ||||
| //				this.focusPreviousOption(); | ||||
| 			break; | ||||
| 			 | ||||
| 			case 40: // down | ||||
| 				console.log("DOWN"); | ||||
| //				this.focusNextOption(); | ||||
| 			break; | ||||
| 			 | ||||
| 			default: return; | ||||
| 		} | ||||
| 		 | ||||
| 		anEvent.preventDefault(); | ||||
| 	}, | ||||
| 	 | ||||
| 	//---------------------------------------------------------------------------- | ||||
|  | ||||
| 	renderTag: function (aTag) { | ||||
| 		return	React.DOM.li({'className':'tag'}, [ | ||||
| 			React.DOM.span({'className':'tagLabel'}, aTag), | ||||
| 			this.isReadOnly() ? null : React.DOM.span({'className':'tagRemoveButton', 'onClick':this.removeTagHandler, 'data-label':aTag}, 'delete') | ||||
| 		]) | ||||
| 	}, | ||||
| 	 | ||||
| 	renderEditField: function () { | ||||
| 		return	React.DOM.input({'type':'text', 'onKeyDown': this.handleKeyDown}); | ||||
| 	}, | ||||
| 	 | ||||
| 	render: function () { | ||||
| 		var	classes = { | ||||
| 			'tagEditor':	true, | ||||
| 			'readOnly':		this.props['readOnly'], | ||||
| 			'readWrite':	!this.props['readOnly'] | ||||
| 		}; | ||||
| 		 | ||||
| 		return	React.DOM.div({'className':React.addons.classSet(classes)}, [ | ||||
| 			React.DOM.ul({},[ | ||||
| 				MochiKit.Base.map(this.renderTag, this.props['selectedTags']), | ||||
| 				this.isReadOnly() ? null : this.renderEditField() | ||||
| 			]) | ||||
| 		]); | ||||
| 	}, | ||||
|  | ||||
| 	//========================================================================= | ||||
| }); | ||||
| @@ -78,15 +78,16 @@ Clipperz.PM.UI.Components.Cards.View = React.createClass({ | ||||
|  | ||||
| 	//............................................................................ | ||||
|  | ||||
| 	renderTag: function (aTag) { | ||||
| 		return	React.DOM.div({'className':'cardTag'}, aTag); | ||||
| 	}, | ||||
| //	renderTag: function (aTag) { | ||||
| //		return	React.DOM.div({'className':'cardTag'}, aTag); | ||||
| //	}, | ||||
| 	 | ||||
| 	renderTags: function (someTags) { | ||||
| 		var	tags; | ||||
|  | ||||
| 		tags = MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, someTags).sort(Clipperz.Base.caseInsensitiveCompare); | ||||
| 		return	React.DOM.div({'className':'cardTags'}, MochiKit.Base.map(this.renderTag, tags)); | ||||
| //		return	React.DOM.div({'className':'cardTags'}, MochiKit.Base.map(this.renderTag, tags)); | ||||
| 		return	Clipperz.PM.UI.Components.Cards.TagEditor({'selectedTags':tags, 'readOnly':true }); | ||||
| 	}, | ||||
|  | ||||
| 	//............................................................................ | ||||
|   | ||||
| @@ -56,38 +56,18 @@ Clipperz.PM.UI.MainController = function() { | ||||
| 	]); | ||||
|  | ||||
| 	this.registerForNotificationCenterEvents([ | ||||
| 		'doLogin', | ||||
| 		'registerNewUser', | ||||
| 		'showRegistrationForm', | ||||
| 		'goBack', | ||||
| 			 | ||||
| 		'toggleSelectionPanel', | ||||
| 		'toggleSettingsPanel', | ||||
| 			 | ||||
| 		'matchMediaQuery', | ||||
| 		'unmatchMediaQuery', | ||||
| 		 | ||||
| 		'selectAllCards', | ||||
| 		'selectRecentCards', | ||||
| 		'tagSelected', | ||||
| 		'selectUntaggedCards', | ||||
|  | ||||
| 		'doLogin', 'registerNewUser', 'showRegistrationForm', 'goBack', | ||||
| 		'toggleSelectionPanel', 'toggleSettingsPanel', | ||||
| 		'matchMediaQuery', 'unmatchMediaQuery', | ||||
| 		'selectAllCards', 'selectRecentCards', 'tagSelected', 'selectUntaggedCards', | ||||
| 		'refreshCardEditDetail', | ||||
| //		'refreshCardEditToolbar', | ||||
| 		'saveCardEdits', | ||||
| 		'cancelCardEdits', | ||||
|  | ||||
| 		'saveCardEdits', 'cancelCardEdits', | ||||
| 		'cardSelected', | ||||
| 		 | ||||
| 		'addCardClick', | ||||
| 		'deleteCard', | ||||
| 		'archiveCard', | ||||
| 		'cloneCard', | ||||
| 		'editCard', | ||||
| 		 | ||||
| 		'showArchivedCards', | ||||
| 		'hideArchivedCards', | ||||
| 		 | ||||
| 		'deleteCard', 'archiveCard', 'cloneCard', 'editCard', | ||||
| 		'addTag', 'removeTag', | ||||
| 		'showArchivedCards', 'hideArchivedCards', | ||||
| 		'goBackToMainPage', | ||||
| 		'maskClick', | ||||
| 	]); | ||||
| @@ -626,9 +606,14 @@ console.log("SET USER", aUser); | ||||
| 		return aValue; | ||||
| 	}, | ||||
|  | ||||
| 	allTags: function (shouldIncludeArchivedCards) { | ||||
| 		return this.user().getTags(shouldIncludeArchivedCards); | ||||
| 	}, | ||||
| 	 | ||||
| 	renderTags: function () { | ||||
| 		return Clipperz.Async.callbacks("MainController.renderTags", [ | ||||
| 			MochiKit.Base.method(this.user(), 'getTags', this.shouldIncludeArchivedCards()), | ||||
| //			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, 'getArchivedCardsCount'), | ||||
| 			MochiKit.Base.method(this, 'setPageProperties', 'mainPage', 'archivedCardsCount'), | ||||
| @@ -1046,9 +1031,10 @@ console.log("SET USER", aUser); | ||||
| 			MochiKit.Base.method(this.user(), 'createNewRecord'), | ||||
| 			MochiKit.Base.methodcaller('reference'), | ||||
| 			MochiKit.Base.method(this, 'refreshUI'), | ||||
| 			MochiKit.Base.bind(function () { | ||||
| 				this.pages()[this.currentPage()].setProps({'mode': 'edit'}); | ||||
| 			}, this), | ||||
| //			MochiKit.Base.bind(function () { | ||||
| //				this.pages()[this.currentPage()].setProps({'mode': 'edit'}); | ||||
| //			}, this), | ||||
| 			MochiKit.Base.method(this, 'enterEditMode'), | ||||
| 		], {trace:false}); | ||||
| 	}, | ||||
|  | ||||
| @@ -1092,9 +1078,55 @@ console.log("SET USER", aUser); | ||||
| 		], {trace:false}); | ||||
| 	}, | ||||
| 	 | ||||
| 	enterEditMode: function () { | ||||
| 		var	currentPage = this.pages()[this.currentPage()]; | ||||
|  | ||||
| 		currentPage.setProps({'mode': 'edit'}); | ||||
| 		 | ||||
| 		return Clipperz.Async.callbacks("MainController.enterEditMode", [ | ||||
| 			MochiKit.Base.method(this, 'allTags', true), | ||||
| 			MochiKit.Base.keys, | ||||
| 			function (aValue) { | ||||
| 				currentPage.setProps({'allTags': aValue}); | ||||
| 			}, | ||||
| 		], {trace:false}); | ||||
| 		 | ||||
| 	}, | ||||
| 	 | ||||
| 	editCard_handler: function (anEvent) { | ||||
| //console.log("EDIT CARD", anEvent['reference']); | ||||
| 		this.pages()[this.currentPage()].setProps({'mode': 'edit'}); | ||||
| //		this.pages()[this.currentPage()].setProps({'mode': 'edit'}); | ||||
| 		this.enterEditMode(); | ||||
| 	}, | ||||
|  | ||||
| 	addTag_handler: function (anEvent) { | ||||
| 		var	record = this.pages()[this.currentPage()].props['selectedCard']['_record']; | ||||
| 		var	tag = anEvent; | ||||
| 		var	deferredResult; | ||||
|  | ||||
| 		deferredResult = new Clipperz.Async.Deferred('MainController.addTag', {trace:false}); | ||||
| 		deferredResult.addMethod(record, 'addTag', tag); | ||||
| 		deferredResult.addMethod(this, 'collectRecordInfo', record); | ||||
| 		deferredResult.addMethod(this, 'setPageProperties', this.currentPage(), 'selectedCard'); | ||||
| //		deferredResult.addMethod(this, 'refreshCurrentPage'); | ||||
| 		deferredResult.callback(); | ||||
| 		 | ||||
| 		return deferredResult; | ||||
| 	}, | ||||
| 	 | ||||
| 	removeTag_handler: function (anEvent) { | ||||
| 		var	record = this.pages()[this.currentPage()].props['selectedCard']['_record']; | ||||
| 		var	tag = anEvent; | ||||
| 		var	deferredResult; | ||||
|  | ||||
| 		deferredResult = new Clipperz.Async.Deferred('MainController.removeTag', {trace:false}); | ||||
| 		deferredResult.addMethod(record, 'removeTag', tag); | ||||
| 		deferredResult.addMethod(this, 'collectRecordInfo', record); | ||||
| 		deferredResult.addMethod(this, 'setPageProperties', this.currentPage(), 'selectedCard'); | ||||
| //		deferredResult.addMethod(this, 'refreshCurrentPage'); | ||||
| 		deferredResult.callback(); | ||||
| 		 | ||||
| 		return deferredResult; | ||||
| 	}, | ||||
|  | ||||
| 	goBackToMainPage_handler: function (anEvent) { | ||||
|   | ||||
| @@ -159,6 +159,7 @@ | ||||
| 		"Clipperz/PM/UI/Components/Cards/Edit.js", | ||||
| 		"Clipperz/PM/UI/Components/Cards/CommandToolbar.js", | ||||
| 		"Clipperz/PM/UI/Components/Cards/EditToolbar.js", | ||||
| 		"Clipperz/PM/UI/Components/Cards/TagEditor.js", | ||||
|  | ||||
| 		"Clipperz/PM/UI/Components/AccountStatus.js", | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| @import "core/overlay"; | ||||
| @import "core/behavior"; | ||||
| @import "core/layout"; | ||||
| @import "core/tagEditor"; | ||||
|  | ||||
| @import "style/loadingPage"; | ||||
| @import "style/loginPage"; | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										31
									
								
								frontend/delta/scss/core/tagEditor.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								frontend/delta/scss/core/tagEditor.scss
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| .tagEditor { | ||||
|  | ||||
| 	&.readWrite { | ||||
| 		border: 1px solid red; | ||||
| 	} | ||||
|  | ||||
| 	ul { | ||||
| 		@include flexbox(); | ||||
| 		@include flex-direction(row); | ||||
| 		@include align-items(flex-start); | ||||
|  | ||||
| 		li.tag { | ||||
| 			@include flex(none); | ||||
| 			font-size: 14pt; | ||||
| 			padding-right: 10px; | ||||
| 		 | ||||
| 			&:before { | ||||
| 				content: 'tag'; | ||||
| 				@include icon-font(); | ||||
| 				font-size: 10pt; | ||||
| 				padding-right: 4px; | ||||
| 			} | ||||
| 			 | ||||
| 			span.tagRemoveButton { | ||||
| 				@include icon-font(); | ||||
| 				color: gray; | ||||
| 				cursor: pointer; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -224,27 +224,10 @@ $cardViewBasePadding: 10px; | ||||
| 		padding: $cardViewBasePadding; | ||||
| 	} | ||||
|  | ||||
| 	.cardTags { | ||||
| 		@include flexbox(); | ||||
| 		@include flex-direction(row); | ||||
| 		@include align-items(flex-start); | ||||
| 		 | ||||
| 	.tagEditor { | ||||
| 		padding: $cardViewBasePadding; | ||||
|  | ||||
| 		.cardTag { | ||||
| 			@include flex(none); | ||||
| 			font-size: 14pt; | ||||
| 			padding-right: 10px; | ||||
| 			 | ||||
| 			&:before { | ||||
| 				content: 'tag'; | ||||
| 				@include icon-font(); | ||||
| 				font-size: 10pt; | ||||
| 				padding-right: 4px; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	.cardNotes { | ||||
| 		padding: $cardViewBasePadding; | ||||
| 	} | ||||
| @@ -281,7 +264,9 @@ $cardViewBasePadding: 10px; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 		 | ||||
| 			.removeField { | ||||
| 				cursor: pointer; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		.fieldAction { | ||||
| @@ -298,6 +283,10 @@ $cardViewBasePadding: 10px; | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	.newCardField { | ||||
| 		cursor: pointer; | ||||
| 	} | ||||
|  | ||||
| 	.cardDirectLogin { | ||||
| 		font-size: 18pt; | ||||
| 		padding: $cardViewBasePadding; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Giulio Cesare Solaroli
					Giulio Cesare Solaroli