yzt
2023-05-26 de4278af2fd46705a40bac58ec01122db6b7f3d7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
define([
    "dojo/_base/declare", // declare
    "dojo/dom-construct", // domConstruct.create
    "dojo/has",
    "dojo/_base/lang", // lang.hitch
    "dojo/on",
    "dojo/_base/window", // win.body
    "../Viewport"
], function(declare, domConstruct, has, lang, on, win, Viewport){
 
    // module:
    //      dijit/form/_ExpandingTextAreaMixin
 
    // feature detection, true for mozilla and webkit
    has.add("textarea-needs-help-shrinking", function(){
        var body = win.body(),  // note: if multiple documents exist, doesn't matter which one we use
            te = domConstruct.create('textarea', {
            rows:"5",
            cols:"20",
            value: ' ',
            style: {zoom:1, fontSize:"12px", height:"96px", overflow:'hidden', visibility:'hidden', position:'absolute', border:"5px solid white", margin:"0", padding:"0", boxSizing: 'border-box', MsBoxSizing: 'border-box', WebkitBoxSizing: 'border-box', MozBoxSizing: 'border-box' }
        }, body, "last");
        var needsHelpShrinking = te.scrollHeight >= te.clientHeight;
        body.removeChild(te);
        return needsHelpShrinking;
    });
 
    return declare("dijit.form._ExpandingTextAreaMixin", null, {
        // summary:
        //      Mixin for textarea widgets to add auto-expanding capability
 
        _setValueAttr: function(){
            this.inherited(arguments);
            this.resize();
        },
 
        postCreate: function(){
            this.inherited(arguments);
            var textarea = this.textbox;
            textarea.style.overflowY = "hidden";
            this.own(on(textarea, "focus, resize", lang.hitch(this, "_resizeLater")));
        },
 
        startup: function(){ 
            this.inherited(arguments);
            this.own(Viewport.on("resize", lang.hitch(this, "_resizeLater")));
            this._resizeLater();
        },
 
        _onInput: function(e){
            this.inherited(arguments);
            this.resize();
        },
 
        _estimateHeight: function(){
            // summary:
            //      Approximate the height when the textarea is invisible with the number of lines in the text.
            //      Fails when someone calls setValue with a long wrapping line, but the layout fixes itself when the user clicks inside so . . .
            //      In IE, the resize event is supposed to fire when the textarea becomes visible again and that will correct the size automatically.
            //
            var textarea = this.textbox;
            // #rows = #newlines+1
            textarea.rows = (textarea.value.match(/\n/g) || []).length + 1;
        },
 
        _resizeLater: function(){
            this.defer("resize");
        },
 
        resize: function(){
            // summary:
            //      Resizes the textarea vertically (should be called after a style/value change)
 
            var textarea = this.textbox;
 
            function textareaScrollHeight(){
                var empty = false;
                if(textarea.value === ''){
                    textarea.value = ' ';
                    empty = true;
                }
                var sh = textarea.scrollHeight;
                if(empty){ textarea.value = ''; }
                return sh;
            }
 
            if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
            if(this.busyResizing){ return; }
            this.busyResizing = true;
            if(textareaScrollHeight() || textarea.offsetHeight){
                var newH = textareaScrollHeight() + Math.max(textarea.offsetHeight - textarea.clientHeight, 0);
                var newHpx = newH + "px";
                if(newHpx != textarea.style.height){
                    textarea.style.height = newHpx;
                    textarea.rows = 1; // rows can act like a minHeight if not cleared
                }
                if(has("textarea-needs-help-shrinking")){
                    var origScrollHeight = textareaScrollHeight(),
                        newScrollHeight = origScrollHeight,
                        origMinHeight = textarea.style.minHeight,
                        decrement = 4, // not too fast, not too slow
                        thisScrollHeight,
                        origScrollTop = textarea.scrollTop;
                    textarea.style.minHeight = newHpx; // maintain current height
                    textarea.style.height = "auto"; // allow scrollHeight to change
                    while(newH > 0){
                        textarea.style.minHeight = Math.max(newH - decrement, 4) + "px";
                        thisScrollHeight = textareaScrollHeight();
                        var change = newScrollHeight - thisScrollHeight;
                        newH -= change;
                        if(change < decrement){
                            break; // scrollHeight didn't shrink
                        }
                        newScrollHeight = thisScrollHeight;
                        decrement <<= 1;
                    }
                    textarea.style.height = newH + "px";
                    textarea.style.minHeight = origMinHeight;
                    textarea.scrollTop = origScrollTop;
                }
                textarea.style.overflowY = textareaScrollHeight() > textarea.clientHeight ? "auto" : "hidden";
                if(textarea.style.overflowY == "hidden"){ textarea.scrollTop = 0; }
            }else{
                // hidden content of unknown size
                this._estimateHeight();
            }
            this.busyResizing = false;
        }
    });
});