Improved text area autoresize behaviour
This commit is contained in:
parent
375fc0c10e
commit
a4718b2c04
@ -1812,7 +1812,8 @@ span.count {
|
|||||||
#extraFeaturesPanel div ul li p {
|
#extraFeaturesPanel div ul li p {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
padding-bottom: 5px; }
|
padding-bottom: 5px;
|
||||||
|
line-height: 1.2em; }
|
||||||
#extraFeaturesPanel div ul li a.button {
|
#extraFeaturesPanel div ul li a.button {
|
||||||
-webkit-border-radius: 2;
|
-webkit-border-radius: 2;
|
||||||
-moz-border-radius: 2;
|
-moz-border-radius: 2;
|
||||||
@ -2018,7 +2019,11 @@ div.cardList.narrow {
|
|||||||
#cardDetailPage .edit .cardDetailToolbar, .cardDetail .edit .cardDetailToolbar {
|
#cardDetailPage .edit .cardDetailToolbar, .cardDetail .edit .cardDetailToolbar {
|
||||||
background-color: #1863a1;
|
background-color: #1863a1;
|
||||||
color: white; }
|
color: white; }
|
||||||
#cardDetailPage .edit .cardField:hover, .cardDetail .edit .cardField:hover {
|
#cardDetailPage .edit .cardField, .cardDetail .edit .cardField {
|
||||||
|
border-top: 1px solid #eee; }
|
||||||
|
#cardDetailPage .edit .cardField:last-child, .cardDetail .edit .cardField:last-child {
|
||||||
|
border-bottom: 1px solid #eee; }
|
||||||
|
#cardDetailPage .edit .cardField:hover, .cardDetail .edit .cardField:hover {
|
||||||
background-color: #eee; }
|
background-color: #eee; }
|
||||||
#cardDetailPage .edit input::-webkit-input-placeholder, #cardDetailPage .edit textarea::-webkit-input-placeholder, .cardDetail .edit input::-webkit-input-placeholder, .cardDetail .edit textarea::-webkit-input-placeholder {
|
#cardDetailPage .edit input::-webkit-input-placeholder, #cardDetailPage .edit textarea::-webkit-input-placeholder, .cardDetail .edit input::-webkit-input-placeholder, .cardDetail .edit textarea::-webkit-input-placeholder {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
@ -2063,13 +2068,13 @@ div.cardList.narrow {
|
|||||||
.content .tagEditor {
|
.content .tagEditor {
|
||||||
padding: 10px; }
|
padding: 10px; }
|
||||||
.content .cardNotes {
|
.content .cardNotes {
|
||||||
padding: 10px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
font-style: italic;
|
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word; }
|
word-wrap: break-word; }
|
||||||
|
.content .cardNotes div {
|
||||||
|
padding: 10px; }
|
||||||
.content .dropArea {
|
.content .dropArea {
|
||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -44,35 +44,6 @@ Clipperz.PM.UI.Components.Cards.Edit = React.createClass({
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
componentDidMount: function() {
|
|
||||||
var textareas;
|
|
||||||
var autoresize = this.autoresize;
|
|
||||||
|
|
||||||
textareas = [].slice.call(this.getDOMNode().querySelectorAll('textarea'));
|
|
||||||
textareas.forEach(function(aTextarea) {
|
|
||||||
aTextarea.addEventListener('input', autoresize, false);
|
|
||||||
autoresize({target:aTextarea});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
|
||||||
var textareas;
|
|
||||||
var autoresize = this.autoresize;
|
|
||||||
|
|
||||||
textareas = [].slice.call(this.getDOMNode().querySelectorAll('textarea'));
|
|
||||||
textareas.forEach(function(aTextarea) {
|
|
||||||
aTextarea.removeEventListener('input', autoresize, false);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
autoresize: function (anEvent) {
|
|
||||||
anEvent.target.style.height = 'auto';
|
|
||||||
anEvent.target.style.height = anEvent.target.scrollHeight+'px';
|
|
||||||
window.scrollTo(window.scrollLeft, (anEvent.target.scrollTop + anEvent.target.scrollHeight));
|
|
||||||
},
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
record: function () {
|
record: function () {
|
||||||
return this.props['_record'];
|
return this.props['_record'];
|
||||||
},
|
},
|
||||||
@ -287,7 +258,8 @@ console.log("DROP"); //, anEvent);
|
|||||||
},
|
},
|
||||||
|
|
||||||
renderNotes: function (someNotes) {
|
renderNotes: function (someNotes) {
|
||||||
return React.DOM.textarea({'className':'cardNotes', 'onChange':this.handleChange(this.record(), 'setNotes'), 'defaultValue':someNotes, 'key':this.props['_reference'] + '_notes', 'placeholder': "notes"});
|
// return React.DOM.textarea({'className':'cardNotes', 'onChange':this.handleChange(this.record(), 'setNotes'), 'defaultValue':someNotes, 'key':this.props['_reference'] + '_notes', 'placeholder': "notes"});
|
||||||
|
return Clipperz.PM.UI.Components.Cards.TextArea({'className':'cardNotes', 'onChange':this.handleChange(this.record(), 'setNotes'), 'defaultValue':someNotes, 'key':this.props['_reference'] + '_notes', 'placeholder': "notes"});
|
||||||
},
|
},
|
||||||
|
|
||||||
//............................................................................
|
//............................................................................
|
||||||
@ -343,7 +315,8 @@ console.log("DROP"); //, anEvent);
|
|||||||
React.DOM.input({'_className_':'_fieldLabel_', 'onChange':this.handleChange(field, 'setLabel'), 'defaultValue':aField['label'], 'placeholder': "label"}),
|
React.DOM.input({'_className_':'_fieldLabel_', 'onChange':this.handleChange(field, 'setLabel'), 'defaultValue':aField['label'], 'placeholder': "label"}),
|
||||||
]),
|
]),
|
||||||
React.DOM.div({'className':'fieldValue'}, [
|
React.DOM.div({'className':'fieldValue'}, [
|
||||||
React.DOM.textarea({'className':React.addons.classSet(cardFieldValueClasses), 'onChange':this.handleChange(field, 'setValue'), 'defaultValue':aField['value'], 'placeholder': "value"}),
|
// React.DOM.textarea({'className':React.addons.classSet(cardFieldValueClasses), 'onChange':this.handleChange(field, 'setValue'), 'defaultValue':aField['value'], 'placeholder': "value"}),
|
||||||
|
Clipperz.PM.UI.Components.Cards.TextArea({'className':React.addons.classSet(cardFieldValueClasses), 'onChange':this.handleChange(field, 'setValue'), 'defaultValue':aField['value'], 'placeholder': "value"}),
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
React.DOM.div({'className':'fieldAction action'}, aField['actionType'].toLowerCase())
|
React.DOM.div({'className':'fieldAction action'}, aField['actionType'].toLowerCase())
|
||||||
|
110
frontend/delta/js/Clipperz/PM/UI/Components/Cards/TextArea.js
Normal file
110
frontend/delta/js/Clipperz/PM/UI/Components/Cards/TextArea.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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.TextArea = React.createClass({
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
componentDidMount: function() {
|
||||||
|
this.recalculateSize();
|
||||||
|
this.getDOMNode().addEventListener('input', this.recalculateSize, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
this.getDOMNode().removeEventListener('input', this.recalculateSize, false);
|
||||||
|
},
|
||||||
|
|
||||||
|
// componentDidUpdate: function(prevProps) {
|
||||||
|
// if (prevProps.style || prevProps.value !== this.props.value || this.props.value == null) {
|
||||||
|
// this.recalculateSize();
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
// onChange: function(e) {
|
||||||
|
// if (this.props.onChange) {
|
||||||
|
// this.props.onChange(e);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (this.props.value === undefined) {
|
||||||
|
// // controlled mode
|
||||||
|
// this.recalculateSize();
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
recalculateSize: function () {
|
||||||
|
this.recalculateSize_1()
|
||||||
|
},
|
||||||
|
|
||||||
|
// http://maximilianhoffmann.com/posts/autoresizing-textareas
|
||||||
|
recalculateSize_1: function () {
|
||||||
|
var node = this.getDOMNode();
|
||||||
|
|
||||||
|
node.style.height = 'auto';
|
||||||
|
node.style.height = node.scrollHeight+'px';
|
||||||
|
window.scrollTo(window.scrollLeft, (node.scrollTop + node.scrollHeight));
|
||||||
|
},
|
||||||
|
|
||||||
|
recalculateSize_2: function() {
|
||||||
|
var diff;
|
||||||
|
var node = this.getDOMNode();
|
||||||
|
|
||||||
|
if (window.getComputedStyle) {
|
||||||
|
var styles = window.getComputedStyle(node);
|
||||||
|
|
||||||
|
// If the textarea is set to border-box, it's not necessary to subtract the padding.
|
||||||
|
if (
|
||||||
|
styles.getPropertyValue('box-sizing') === "border-box"
|
||||||
|
|| styles.getPropertyValue('-moz-box-sizing') === "border-box"
|
||||||
|
|| styles.getPropertyValue('-webkit-box-sizing') === "border-box"
|
||||||
|
) {
|
||||||
|
diff = 0;
|
||||||
|
} else {
|
||||||
|
diff = ( parseInt(styles.getPropertyValue('padding-bottom') || 0, 10)
|
||||||
|
+ parseInt(styles.getPropertyValue('padding-top') || 0, 10)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
diff = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// var node = this.getDOMNode();
|
||||||
|
node.style.height = 'auto';
|
||||||
|
node.style.height = (node.scrollHeight - diff) + 'px';
|
||||||
|
},
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// render: function () {
|
||||||
|
// return React.DOM.textarea({'className':'cardNotes', /*'onChange':this.handleChange(this.record(), 'setNotes'), 'defaultValue':someNotes, 'key':this.props['_reference'] + '_notes',*/ 'placeholder': "notes"});
|
||||||
|
// },
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return React.DOM.textarea(this.props, this.props.children);
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
@ -91,7 +91,9 @@ Clipperz.PM.UI.Components.Cards.View = React.createClass({
|
|||||||
|
|
||||||
//console.log("NOTES", someNotes);
|
//console.log("NOTES", someNotes);
|
||||||
if (someNotes != "") {
|
if (someNotes != "") {
|
||||||
result = React.DOM.div({'className':'cardNotes'}, someNotes);
|
result = React.DOM.div({'className':'cardNotes'}, [
|
||||||
|
React.DOM.div({}, someNotes)
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
result = null;
|
result = null;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ Clipperz.PM.UI.Components.Selections = React.createClass({
|
|||||||
var filterType;
|
var filterType;
|
||||||
var filterValue;
|
var filterValue;
|
||||||
|
|
||||||
console.log("SELECTIONS PROPS", this.props);
|
//console.log("SELECTIONS PROPS", this.props);
|
||||||
tagInfo = this.props['tags'] ? this.props['tags'] : {};
|
tagInfo = this.props['tags'] ? this.props['tags'] : {};
|
||||||
tags = MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, MochiKit.Base.keys(tagInfo)).sort(Clipperz.Base.caseInsensitiveCompare);
|
tags = MochiKit.Base.filter(Clipperz.PM.DataModel.Record.isRegularTag, MochiKit.Base.keys(tagInfo)).sort(Clipperz.Base.caseInsensitiveCompare);
|
||||||
archivedCardsCount = this.props['archivedCardsCount'];
|
archivedCardsCount = this.props['archivedCardsCount'];
|
||||||
|
@ -225,6 +225,12 @@ $cardViewBasePadding: 10px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cardField {
|
.cardField {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
@ -305,17 +311,19 @@ $cardViewBasePadding: 10px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cardNotes {
|
.cardNotes {
|
||||||
padding: $cardViewBasePadding;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 0px;
|
border: 0px;
|
||||||
|
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
font-style: italic;
|
// font-style: italic;
|
||||||
|
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
|
||||||
// background-color: gold;
|
// background-color: gold;
|
||||||
|
div {
|
||||||
|
padding: $cardViewBasePadding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropArea {
|
.dropArea {
|
||||||
|
@ -77,6 +77,7 @@
|
|||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
font-weight: 100;
|
font-weight: 100;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
|
line-height: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.button {
|
a.button {
|
||||||
|
Loading…
Reference in New Issue
Block a user