blossom
Version:
Modern, Cross-Platform Application Framework
133 lines (105 loc) • 4.17 kB
JavaScript
// ==========================================================================
// Project: Blossom - Modern, Cross-Platform Application Framework
// Copyright: ©2012 Fohr Motion Picture Studios. All rights reserved.
// License: Licensed under the GPLv3 license (see BLOSSOM-LICENSE).
// ==========================================================================
/*globals sc_assert */
sc_require('surfaces/leaf');
sc_require('text/text_selection');
var base3 = "#fdf6e3";
var base03 = "#002b36";
SC.TextSurface = SC.LeafSurface.extend({
isTextSurface: true, // Walk like a duck.
value: null,
_sc_value: null,
_sc_valueDidChange: function() {
// console.log('SC.TextSurface#_sc_valueDidChange()', SC.guidFor(this));
var cur = this.get('value'),
old = this._sc_value,
txt = this._sc_textarea,
val = txt.value;
// cur === old === val on init(), so nothing to do.
if (cur === old) return;
// This happens when our 'value' was updated by our text area. Avoid
// a loop by not setting 'value' on the text area again.
if (cur === val) {
this._sc_value = cur;
// This happens when our 'value' has been updated by anyone but our
// text area. Let our text area know we've changed.
} else {
this._sc_value = cur;
txt.value = cur;
}
}.observes('value'),
selection: function(key, value) {
var textarea = this._sc_textarea;
if (value !== undefined) {
sc_assert(value instanceof SC.TextSelection);
sc_assert(value.isValid);
if (!textarea.value) {
textarea.setSelectionRange(0, 0);
} else {
textarea.setSelectionRange(value.start, value.end);
}
} else {
return new SC.TextSelection(textarea.selectionStart, textarea.selectionEnd);
}
}.property('value'),
_sc_backgroundColor: 'white',
_sc_borderColor: base03,
_sc_borderWidth: 1,
// ..........................................................
// PSURFACE SUPPORT
//
__tagName__: 'textarea',
/** @private */
didAppendElement: function(textarea) {
// console.log('SC.TextSurface#didAppendElement()', SC.guidFor(this));
sc_assert(textarea);
sc_assert(textarea.id === this.__id__);
sc_assert(textarea.nodeName === this.__tagName__.toUpperCase());
sc_assert(document.getElementById(textarea.id));
this._sc_textarea = textarea; // cache it
// Become the input surface.
SC.Event.add(textarea, 'focus', this, this._sc_textAreaDidFocus);
// Resign the input surface.
SC.Event.add(textarea, 'blur', this, this._sc_textAreaDidBlur);
// There are certain ways users can select text that we can't identify via
// our key/mouse down/up handlers (such as the user choosing Select All
// from a menu).
SC.Event.add(textarea, 'select', this, this._sc_textAreaDidSelect);
// Keep our value in sync.
SC.Event.add(textarea, 'change', this, this._sc_textAreaDidChange);
textarea.value = this.get('value');
},
keyUp: function(evt) {
// console.log('SC.TextSurface#keyUp()', SC.guidFor(this));
evt.allowDefault(); // We want the browser's behavior here.
this.set('value', this._sc_textarea.value);
},
_sc_textAreaDidFocus: function(evt) {
// console.log('SC.TextSurface#_sc_textAreaDidFocus()', SC.guidFor(this));
SC.app.set('inputSurface', this);
var that = this;
setTimeout(function() {
SC.RunLoop.begin();
var value = that.get('value');
if (!value) value = ''
else value = String(value);
that._sc_textarea.setSelectionRange(0, value? value.length : 0);
SC.RunLoop.end();
},0);
},
_sc_textAreaDidBlur: function(evt) {
// console.log('SC.TextSurface#_sc_textAreaDidBlur()', SC.guidFor(this));
SC.app.set('inputSurface', null);
},
_sc_textAreaDidSelect: function(evt) {
// console.log('SC.TextSurface#_sc_textAreaDidSelect()', SC.guidFor(this));
this.notifyPropertyChange('selection');
},
_sc_textAreaDidChange: function(evt) {
// console.log('SC.TextSurface#_sc_textAreaDidChange()', SC.guidFor(this));
this.set('value', this._sc_textarea.value);
}
});