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 | "use strict" ;
|
28 |
|
29 |
|
30 |
|
31 | const Element = require( './Element.js' ) ;
|
32 | const Button = require( './Button.js' ) ;
|
33 |
|
34 |
|
35 | const IDENTITY = v => v ;
|
36 |
|
37 |
|
38 |
|
39 | function Slider( options ) {
|
40 |
|
41 | options = ! options ? {} : options.internal ? options : Object.create( options ) ;
|
42 | options.internal = true ;
|
43 |
|
44 | Element.call( this , options ) ;
|
45 |
|
46 | this.onClick = this.onClick.bind( this ) ;
|
47 | this.onDrag = this.onDrag.bind( this ) ;
|
48 | this.onWheel = this.onWheel.bind( this ) ;
|
49 | this.onButtonSubmit = this.onButtonSubmit.bind( this ) ;
|
50 |
|
51 | this.isVertical = !! options.isVertical ;
|
52 | this.slideRate = 0 ;
|
53 | this.handleOffset = 0 ;
|
54 |
|
55 | this.rateToValue = typeof options.rateToValue === 'function' ? options.rateToValue : IDENTITY ;
|
56 | this.valueToRate = typeof options.valueToRate === 'function' ? options.valueToRate : IDENTITY ;
|
57 |
|
58 | this.buttonBlurAttr = options.buttonBlurAttr || { bgColor: 'black' , color: 'white' , bold: true } ;
|
59 | this.buttonFocusAttr = options.buttonFocusAttr || { bgColor: 'white' , color: 'black' , bold: true } ;
|
60 | this.buttonSubmittedAttr = options.buttonSubmittedAttr || { bgColor: 'gray' , color: 'brightWhite' , bold: true } ;
|
61 |
|
62 | this.backwardSymbol = options.backwardSymbol || ( this.isVertical ? '▲' : '◀' ) ;
|
63 | this.forwardSymbol = options.forwardSymbol || ( this.isVertical ? '▼' : '▶' ) ;
|
64 |
|
65 | this.handleAttr = options.handleAttr || { bgColor: 'brightWhite' , color: 'black' } ;
|
66 | this.handleSymbol = options.handleSymbol || '◆' ;
|
67 |
|
68 | this.barAttr = options.barAttr || { bgColor: 'gray' , color: 'brightWhite' } ;
|
69 | this.barSymbol = options.barSymbol || ' ' ;
|
70 |
|
71 | this.backwardButton = this.forwardButton = null ;
|
72 |
|
73 | this.on( 'click' , this.onClick ) ;
|
74 | this.on( 'drag' , this.onDrag ) ;
|
75 | this.on( 'wheel' , this.onWheel ) ;
|
76 |
|
77 | this.initChildren() ;
|
78 |
|
79 |
|
80 | if ( this.elementType === 'Slider' && ! options.noDraw ) { this.draw() ; }
|
81 | }
|
82 |
|
83 | module.exports = Slider ;
|
84 |
|
85 | Slider.prototype = Object.create( Element.prototype ) ;
|
86 | Slider.prototype.constructor = Slider ;
|
87 | Slider.prototype.elementType = 'Slider' ;
|
88 |
|
89 |
|
90 |
|
91 |
|
92 | Slider.prototype.keyBindings = {
|
93 | UP: 'backward' ,
|
94 | DOWN: 'forward' ,
|
95 | LEFT: 'backward' ,
|
96 | RIGHT: 'forward' ,
|
97 | PAGE_UP: 'backward' ,
|
98 | PAGE_DOWN: 'forward' ,
|
99 | ' ': 'forward' ,
|
100 | HOME: 'start' ,
|
101 | END: 'end'
|
102 | } ;
|
103 |
|
104 |
|
105 |
|
106 | Slider.prototype.buttonKeyBindings = {
|
107 | ENTER: 'submit' ,
|
108 | KP_ENTER: 'submit'
|
109 | } ;
|
110 |
|
111 |
|
112 |
|
113 | Slider.prototype.destroy = function( isSubDestroy ) {
|
114 | this.off( 'click' , this.onClick ) ;
|
115 | this.off( 'drag' , this.onDrag ) ;
|
116 | this.off( 'wheel' , this.onWheel ) ;
|
117 | Element.prototype.destroy.call( this , isSubDestroy ) ;
|
118 | } ;
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | Slider.prototype.initChildren = function() {
|
124 | this.backwardButton = new Button( {
|
125 | internal: true ,
|
126 | parent: this ,
|
127 | internalRole: 'backward' ,
|
128 | content: this.backwardSymbol ,
|
129 | outputX: this.outputX ,
|
130 | outputY: this.outputY ,
|
131 | blurAttr: this.buttonBlurAttr ,
|
132 | focusAttr: this.buttonFocusAttr ,
|
133 |
|
134 | submittedAttr: this.buttonSubmittedAttr ,
|
135 | keyBindings: this.buttonKeyBindings ,
|
136 |
|
137 | noDraw: true
|
138 | } ) ;
|
139 |
|
140 | this.backwardButton.on( 'submit' , this.onButtonSubmit ) ;
|
141 |
|
142 | this.forwardButton = new Button( {
|
143 | internal: true ,
|
144 | parent: this ,
|
145 | internalRole: 'forward' ,
|
146 | content: this.forwardSymbol ,
|
147 | outputX: this.isVertical ? this.outputX : this.outputX + this.outputWidth - 1 ,
|
148 | outputY: this.isVertical ? this.outputY + this.outputHeight - 1 : this.outputY ,
|
149 | blurAttr: this.buttonBlurAttr ,
|
150 | focusAttr: this.buttonFocusAttr ,
|
151 |
|
152 | submittedAttr: this.buttonSubmittedAttr ,
|
153 | keyBindings: this.buttonKeyBindings ,
|
154 |
|
155 | noDraw: true
|
156 | } ) ;
|
157 |
|
158 | this.forwardButton.on( 'submit' , this.onButtonSubmit ) ;
|
159 |
|
160 | this.computeHandleOffset() ;
|
161 | } ;
|
162 |
|
163 |
|
164 |
|
165 | Slider.prototype.preDrawSelf = function() {
|
166 | return this.isVertical ? this.preDrawSelfVertical() : this.preDrawSelfHorizontal() ;
|
167 | } ;
|
168 |
|
169 |
|
170 |
|
171 | Slider.prototype.preDrawSelfVertical = function() {
|
172 | var offset = 0 ,
|
173 | y = this.outputY + 1 ,
|
174 | yMax = this.outputY + this.outputHeight - 2 ;
|
175 |
|
176 | for ( ; y <= yMax ; y ++ , offset ++ ) {
|
177 | if ( offset === this.handleOffset ) {
|
178 | this.outputDst.put( { x: this.outputX , y , attr: this.handleAttr } , this.handleSymbol ) ;
|
179 | }
|
180 | else {
|
181 | this.outputDst.put( { x: this.outputX , y , attr: this.barAttr } , this.barSymbol ) ;
|
182 | }
|
183 | }
|
184 | } ;
|
185 |
|
186 |
|
187 |
|
188 | Slider.prototype.preDrawSelfHorizontal = function() {
|
189 | var offset = 0 ,
|
190 | x = this.outputX + 1 ,
|
191 | xMax = this.outputX + this.outputWidth - 2 ;
|
192 |
|
193 | for ( ; x <= xMax ; x ++ , offset ++ ) {
|
194 | if ( offset === this.handleOffset ) {
|
195 | this.outputDst.put( { x , y: this.outputY , attr: this.handleAttr } , this.handleSymbol ) ;
|
196 | }
|
197 | else {
|
198 | this.outputDst.put( { x , y: this.outputY , attr: this.barAttr } , this.barSymbol ) ;
|
199 | }
|
200 | }
|
201 | } ;
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 | Slider.prototype.postDrawSelf = function() {
|
209 | if ( this.isVertical ) {
|
210 | this.outputDst.moveTo( this.outputX , this.outputY + this.handleOffset + 1 ) ;
|
211 | }
|
212 | else {
|
213 | this.outputDst.moveTo( this.outputX + this.handleOffset + 1 , this.outputY ) ;
|
214 | }
|
215 | } ;
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 | Slider.prototype.computeHandleOffset = function() {
|
229 | var delta = ( this.isVertical ? this.outputHeight : this.outputWidth ) - 3 ;
|
230 | this.handleOffset = Math.round( delta * this.slideRate ) ;
|
231 | } ;
|
232 |
|
233 |
|
234 |
|
235 |
|
236 | Slider.prototype.setHandleOffset = function( offset , internalAndNoDraw = false ) {
|
237 | var delta = ( this.isVertical ? this.outputHeight : this.outputWidth ) - 3 ;
|
238 |
|
239 | this.handleOffset = Math.max( 0 , Math.min( delta , Math.round( offset || 0 ) ) ) ;
|
240 | this.slideRate = Math.max( 0 , Math.min( 1 , this.handleOffset / delta || 0 ) ) ;
|
241 |
|
242 | if ( ! internalAndNoDraw ) {
|
243 | this.emit( 'slide' , this.getValue() ) ;
|
244 | this.draw() ;
|
245 | }
|
246 | } ;
|
247 |
|
248 |
|
249 |
|
250 | Slider.prototype.setSlideRate = function( rate , internalAndNoDraw = false ) {
|
251 | this.slideRate = Math.max( 0 , Math.min( 1 , rate || 0 ) ) ;
|
252 | this.computeHandleOffset() ;
|
253 |
|
254 | if ( ! internalAndNoDraw ) {
|
255 | this.emit( 'slide' , this.getValue() ) ;
|
256 | this.draw() ;
|
257 | }
|
258 | } ;
|
259 |
|
260 |
|
261 |
|
262 | Slider.prototype.getHandleOffset = function() { return this.handleOffset ; } ;
|
263 | Slider.prototype.getSlideRate = function() { return this.slideRate ; } ;
|
264 |
|
265 |
|
266 |
|
267 | Slider.prototype.onButtonSubmit = function( buttonValue , action , button ) {
|
268 | switch ( button.internalRole ) {
|
269 | case 'backward' :
|
270 | this.emit( 'slideStep' , -1 ) ;
|
271 | break ;
|
272 | case 'forward' :
|
273 | this.emit( 'slideStep' , 1 ) ;
|
274 | break ;
|
275 | }
|
276 | } ;
|
277 |
|
278 |
|
279 |
|
280 | Slider.prototype.getValue = function() {
|
281 | return this.rateToValue( this.slideRate ) ;
|
282 | } ;
|
283 |
|
284 |
|
285 |
|
286 | Slider.prototype.setValue = function( value , internalAndNoDraw ) {
|
287 | return this.setSlideRate( this.valueToRate( value ) , internalAndNoDraw ) ;
|
288 | } ;
|
289 |
|
290 |
|
291 |
|
292 | Slider.prototype.onClick = function( data ) {
|
293 | if ( ! this.hasFocus ) { this.document.giveFocusTo( this , 'select' ) ; }
|
294 | this.setHandleOffset( ( this.isVertical ? data.y : data.x ) - 1 ) ;
|
295 | } ;
|
296 |
|
297 |
|
298 |
|
299 | Slider.prototype.onDrag = function( data ) {
|
300 | this.setHandleOffset( ( this.isVertical ? data.y : data.x ) - 1 ) ;
|
301 | } ;
|
302 |
|
303 |
|
304 |
|
305 | Slider.prototype.onWheel = function( data ) {
|
306 | this.emit( 'slideStep' , data.yDirection ) ;
|
307 | } ;
|
308 |
|