summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
Unidiff
Diffstat (limited to 'frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js85
1 files changed, 69 insertions, 16 deletions
diff --git a/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
index df514a2..12ddce3 100644
--- a/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
+++ b/frontend/delta/js/Clipperz/PM/UI/Components/CardDetail.js
@@ -1,142 +1,195 @@
1/* 1/*
2 2
3Copyright 2008-2013 Clipperz Srl 3Copyright 2008-2013 Clipperz Srl
4 4
5This file is part of Clipperz, the online password manager. 5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please 6For further information about its features and functionalities please
7refer to http://www.clipperz.com. 7refer to http://www.clipperz.com.
8 8
9* Clipperz is free software: you can redistribute it and/or modify it 9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published 10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or 11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version. 12 (at your option) any later version.
13 13
14* Clipperz is distributed in the hope that it will be useful, but 14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of 15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details. 17 See the GNU Affero General Public License for more details.
18 18
19* You should have received a copy of the GNU Affero General Public 19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/. 20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21 21
22*/ 22*/
23 23
24Clipperz.PM.UI.Components.CardDetail = React.createClass({ 24Clipperz.PM.UI.Components.CardDetail = React.createClass({
25 25
26 getDefaultProps: function () { 26 getDefaultProps: function () {
27 return { 27 return {
28 // searchDelay: 0.3 28 // searchDelay: 0.3
29 } 29 }
30 }, 30 },
31 31
32 propTypes: { 32 propTypes: {
33 card: React.PropTypes.object.isRequired 33 card: React.PropTypes.object.isRequired
34 }, 34 },
35 35
36 getInitialState: function () { 36 getInitialState: function () {
37 return { 37 return {
38 // showSearch: false, 38 // showSearch: false,
39 // searchTimer: null, 39 // searchTimer: null,
40 unmaskedFields: new Clipperz.Set(),
40 starred: false 41 starred: false
41 }; 42 };
42 }, 43 },
43 44
44 handleDirectLoginClick: function (aDirectLoginReference, anEvent) { 45 handleDirectLoginClick: function (aDirectLoginReference, anEvent) {
45 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference}); 46 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'runDirectLogin', {record:this.props.card['reference'], directLogin:aDirectLoginReference});
46 }, 47 },
47 48
49 toggleFieldVisibility: function (aField, anEvent) {
50 var unmaskedFields;
51 var fieldReference;
52
53 unmaskedFields = this.state['unmaskedFields'];
54 fieldReference = aField['reference']
55 if (unmaskedFields.contains(fieldReference)) {
56 unmaskedFields.remove(fieldReference)
57 } else {
58 unmaskedFields.add(fieldReference)
59 }
60
61 this.setState({'unmaskedFields': unmaskedFields});
62 },
63
64 handleGoAction: function (aField, anEvent) {
65 var newWindow;
66
67 newWindow = MochiKit.DOM.currentWindow().open(aField['value'], '_blank');
68 newWindow.focus();
69 },
70
71 handleEmailAction: function (aField, anEvent) {
72 MochiKit.DOM.currentWindow().location = 'mailto:' + aField['value'];
73 },
74
48 //========================================================================= 75 //=========================================================================
49 76
50 normalizeFieldValue: function (aValue) { 77 normalizeFieldValue: function (aValue) {
51 varresult = []; 78 varresult = [];
52 varrows = aValue.split('\n'); 79 varrows = aValue.split('\n');
53 80
54 for (var i = 0; i < rows.length; i++) { 81 for (var i = 0; i < rows.length; i++) {
55 if (i > 0) { 82 if (i > 0) {
56 result.push(React.DOM.br()); 83 result.push(React.DOM.br());
57 } 84 }
58 result.push(rows[i].replace(/[\s]/g, '\u00A0')); 85 result.push(rows[i].replace(/[\s]/g, '\u00A0'));
59 } 86 }
60 87
61 return result; 88 return result;
62 }, 89 },
63 90
64 renderField: function (aField) { 91 renderFieldActionButton: function (aField) {
65//console.log("FIELD", aField); 92 // varactionLabel;
66 varactionLabel; 93 var result;
67 94
68 if (aField['actionType'] == 'URL') { 95 if (aField['actionType'] == 'URL') {
69 actionLabel = "go"; 96 result = React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleGoAction', aField)}, [
97 React.DOM.a({className:aField['actionType']}, "go")
98 ]);
70 } else if (aField['actionType'] == 'PASSWORD') { 99 } else if (aField['actionType'] == 'PASSWORD') {
71 actionLabel = "locked"; 100 var icon;
101
102 if (this.state['unmaskedFields'].contains(aField['reference'])) {
103 icon = "unlocked";
104 } else {
105 icon = "locked";
106 }
107 result =React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'toggleFieldVisibility', aField)}, [
108 React.DOM.a({className:aField['actionType']}, icon)
109 ]);
72 } else if (aField['actionType'] == 'EMAIL') { 110 } else if (aField['actionType'] == 'EMAIL') {
73 actionLabel = "email"; 111 result =React.DOM.div({className:'actionWrapper', onClick:MochiKit.Base.method(this, 'handleEmailAction', aField)}, [
112 React.DOM.a({className:aField['actionType']}, "email")
113 ]);
74 } else { 114 } else {
75 actionLabel = ""; 115 result = null;
116 }
117
118 return result;
119 },
120
121 renderField: function (aField) {
122//console.log("FIELD", aField);
123 var fieldExtraClass;
124
125 fieldExtraClass = aField['actionType'];
126 if (this.state['unmaskedFields'].contains(aField['reference'])) {
127 fieldExtraClass = fieldExtraClass + ' unlocked';
76 } 128 }
77 129
78 returnReact.DOM.div({className:'listItem ' + aField['actionType']}, [ 130 returnReact.DOM.div({className:'listItem ' + fieldExtraClass, key:aField['reference']}, [
79 React.DOM.div({className:'fieldWrapper'}, [ 131 React.DOM.div({className:'fieldWrapper'}, [
80 React.DOM.div({className:'fieldInnerWrapper'}, [ 132 React.DOM.div({className:'fieldInnerWrapper'}, [
81 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])), 133 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aField['label'])),
82 React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + aField['actionType']}, this.normalizeFieldValue(aField['value']))) 134 React.DOM.div({className:'valueWrapper'}, React.DOM.span({className:'value ' + fieldExtraClass}, this.normalizeFieldValue(aField['value'])))
83 ]) 135 ])
84 ]), 136 ]),
85 React.DOM.div({className:'actionWrapper'}, [ 137 this.renderFieldActionButton(aField)
86 React.DOM.div({className:aField['actionType']}, actionLabel) 138 // React.DOM.div({className:'actionWrapper'}, [
87 ]) 139 // React.DOM.div({className:aField['actionType']}, actionLabel)
140 // ])
88 ]); 141 ]);
89 }, 142 },
90 143
91 renderDirectLogin: function (aDirectLogin) { 144 renderDirectLogin: function (aDirectLogin) {
92//console.log("DIRECT LOGIN", aDirectLogin); 145//console.log("DIRECT LOGIN", aDirectLogin);
93 returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleDirectLoginClick', aDirectLogin['reference'])}, [ 146 returnReact.DOM.div({className:'listItem', onClick:MochiKit.Base.method(this, 'handleDirectLoginClick', aDirectLogin['reference'])}, [
94 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aDirectLogin['label'])), 147 React.DOM.div({className:'labelWrapper'}, React.DOM.span({className:'label'}, aDirectLogin['label'])),
95 React.DOM.div({className:'faviconWrapper'}, React.DOM.img({className:'favicon', src:aDirectLogin['favicon']})), 148 React.DOM.div({className:'faviconWrapper'}, React.DOM.img({className:'favicon', src:aDirectLogin['favicon']})),
96 React.DOM.div({className:'directLoginLinkWrapper'}, React.DOM.span({className:'directLoginLink'}, "go")) 149 React.DOM.div({className:'directLoginLinkWrapper'}, React.DOM.span({className:'directLoginLink'}, "go"))
97 ]); 150 ]);
98 }, 151 },
99 152
100 handleBackClick: function (anEvent) { 153 handleBackClick: function (anEvent) {
101 window.history.back(); 154 // window.history.back();
155 MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'goBack');
102 }, 156 },
103 157
104 handleStarClick: function (anEvent) { 158 handleStarClick: function (anEvent) {
105 this.setState({starred: !this.state['starred']}); 159 this.setState({starred: !this.state['starred']});
106 }, 160 },
107 161
108 //========================================================================= 162 //=========================================================================
109 163
110 render: function () { 164 render: function () {
111 var card = this.props.card; 165 var card = this.props.card;
112 var starredStatus = (this.state['starred'] ? "starred" : "unstarred"); 166 // var starredStatus = (this.state['starred'] ? "starred" : "unstarred");
113 167
114 if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) { 168 if ((typeof(card['fields']) != 'undefined') && (card['notes'] != '')) {
115 card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] }) 169 card['fields'].push({ 'actionType': 'NOTES', 'isHidden': false, 'label': "notes", 'reference': "notes", 'value': card['notes'] })
116 } 170 }
117 171
118 returnReact.DOM.div({className:'cardDetail'}, [ 172 returnReact.DOM.div({className:'cardDetail'}, [
119 React.DOM.div({className:'header'}, [ 173 React.DOM.div({className:'header'}, [
120 React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)), 174 React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title)),
121 // React.DOM.div({className:'titleWrapper'}, React.DOM.div({className:'title'}, card.title + ' ' + card.title + ' ' + card.title + ' ' + card.title)),
122 React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")), 175 React.DOM.div({className:'backWrapper'}, React.DOM.a({className:'button back', onClick:this.handleBackClick}, "back")),
123 React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus)) 176 // React.DOM.div({className:'starWrapper'}, React.DOM.a({className:'star', onClick:this.handleStarClick}, starredStatus))
124 ]), 177 ]),
125 React.DOM.div({className:'content'}, [ 178 React.DOM.div({className:'content'}, [
126 card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null, 179 card.fields ? React.DOM.div({className:'fields'}, MochiKit.Base.map(this.renderField, card.fields)) : null,
127 card.directLogins ? React.DOM.div({className:'directLogins'}, MochiKit.Base.map(this.renderDirectLogin,card.directLogins)): null 180 card.directLogins ? React.DOM.div({className:'directLogins'}, MochiKit.Base.map(this.renderDirectLogin,card.directLogins)): null
128 ]), 181 ]),
129 React.DOM.div({className:'footer'}, [ 182 React.DOM.div({className:'footer'}, [
130 /* 183 /*
131 // React.DOM.a({className:'cancel'}, "cancel"), 184 // React.DOM.a({className:'cancel'}, "cancel"),
132 // React.DOM.a({className:'save'}, "save") 185 // React.DOM.a({className:'save'}, "save")
133 186
134 React.DOM.a({className:'cancel button'}, "failed"), 187 React.DOM.a({className:'cancel button'}, "failed"),
135 React.DOM.a({className:'save button'}, "done") 188 React.DOM.a({className:'save button'}, "done")
136*/ 189*/
137 ]) 190 ])
138 ]); 191 ]);
139 } 192 }
140 193
141 //========================================================================= 194 //=========================================================================
142}); 195});