1 _kiwi
.view
.ControlBox
= Backbone
.View
.extend({
3 'keydown .inp': 'process',
4 'click .nick': 'showNickChange'
7 initialize: function () {
10 this.buffer
= []; // Stores previously run commands
11 this.buffer_pos
= 0; // The current position in the buffer
13 this.preprocessor
= new InputPreProcessor();
14 this.preprocessor
.recursive_depth
= 5;
16 // Hold tab autocomplete data
17 this.tabcomplete
= {active
: false, data
: [], prefix
: ''};
19 // Keep the nick view updated with nick changes
20 _kiwi
.app
.connections
.on('change:nick', function(connection
) {
21 // Only update the nick view if it's the active connection
22 if (connection
!== _kiwi
.app
.connections
.active_connection
)
25 $('.nick', that
.$el
).text(connection
.get('nick'));
28 // Update our nick view as we flick between connections
29 _kiwi
.app
.connections
.on('active', function(panel
, connection
) {
30 $('.nick', that
.$el
).text(connection
.get('nick'));
34 showNickChange: function (ev
) {
35 (new _kiwi
.view
.NickChangeBox()).render();
38 process: function (ev
) {
40 inp
= $(ev
.currentTarget
),
44 if (navigator
.appVersion
.indexOf("Mac") !== -1) {
50 // If not a tab key, reset the tabcomplete data
51 if (this.tabcomplete
.active
&& ev
.keyCode
!== 9) {
52 this.tabcomplete
.active
= false;
53 this.tabcomplete
.data
= [];
54 this.tabcomplete
.prefix
= '';
58 case (ev
.keyCode
=== 13): // return
59 inp_val
= inp_val
.trim();
62 $.each(inp_val
.split('\n'), function (idx
, line
) {
63 that
.processInput(line
);
66 this.buffer
.push(inp_val
);
67 this.buffer_pos
= this.buffer
.length
;
75 case (ev
.keyCode
=== 38): // up
76 if (this.buffer_pos
> 0) {
78 inp
.val(this.buffer
[this.buffer_pos
]);
80 //suppress browsers default behavior as it would set the cursor at the beginning
83 case (ev
.keyCode
=== 40): // down
84 if (this.buffer_pos
< this.buffer
.length
) {
86 inp
.val(this.buffer
[this.buffer_pos
]);
90 case (ev
.keyCode
=== 219 && meta
): // [ + meta
91 // Find all the tab elements and get the index of the active tab
92 var $tabs
= $('#kiwi .tabs').find('li[class!=connection]');
93 var cur_tab_ind
= (function() {
94 for (var idx
=0; idx
<$tabs
.length
; idx
++){
95 if ($($tabs
[idx
]).hasClass('active'))
100 // Work out the previous tab along. Wrap around if needed
101 if (cur_tab_ind
=== 0) {
102 $prev_tab
= $($tabs
[$tabs
.length
- 1]);
104 $prev_tab
= $($tabs
[cur_tab_ind
- 1]);
110 case (ev
.keyCode
=== 221 && meta
): // ] + meta
111 // Find all the tab elements and get the index of the active tab
112 var $tabs
= $('#kiwi .tabs').find('li[class!=connection]');
113 var cur_tab_ind
= (function() {
114 for (var idx
=0; idx
<$tabs
.length
; idx
++){
115 if ($($tabs
[idx
]).hasClass('active'))
120 // Work out the next tab along. Wrap around if needed
121 if (cur_tab_ind
=== $tabs
.length
- 1) {
122 $next_tab
= $($tabs
[0]);
124 $next_tab
= $($tabs
[cur_tab_ind
+ 1]);
130 case (ev
.keyCode
=== 9 //Check if ONLY tab is pressed
131 && !ev
.shiftKey
//(user could be using some browser
132 && !ev
.altKey
//keyboard shortcut)
135 this.tabcomplete
.active
= true;
136 if (_
.isEqual(this.tabcomplete
.data
, [])) {
137 // Get possible autocompletions
139 members
= _kiwi
.app
.panels().active
.get('members');
141 // If we have a members list, get the models. Otherwise empty array
142 members
= members
? members
.models
: [];
144 $.each(members
, function (i
, member
) {
146 ac_data
.push(member
.get('nick'));
149 ac_data
.push(_kiwi
.app
.panels().active
.get('name'));
151 ac_data
= _
.sortBy(ac_data
, function (nick
) {
154 this.tabcomplete
.data
= ac_data
;
157 if (inp_val
[inp
[0].selectionStart
- 1] === ' ') {
162 var tokens
, // Words before the cursor position
163 val
, // New value being built up
164 p1
, // Position in the value just before the nick
165 newnick
, // New nick to be displayed (cycles through)
166 range
, // TextRange for setting new text cursor position
167 nick
, // Current nick in the value
168 trailing
= ': '; // Text to be inserted after a tabbed nick
170 tokens
= inp_val
.substring(0, inp
[0].selectionStart
).split(' ');
171 if (tokens
[tokens
.length
-1] == ':')
174 // Only add the trailing text if not at the beginning of the line
175 if (tokens
.length
> 1)
178 nick
= tokens
[tokens
.length
- 1];
180 if (this.tabcomplete
.prefix
=== '') {
181 this.tabcomplete
.prefix
= nick
;
184 this.tabcomplete
.data
= _
.select(this.tabcomplete
.data
, function (n
) {
185 return (n
.toLowerCase().indexOf(that
.tabcomplete
.prefix
.toLowerCase()) === 0);
188 if (this.tabcomplete
.data
.length
> 0) {
189 // Get the current value before cursor position
190 p1
= inp
[0].selectionStart
- (nick
.length
);
191 val
= inp_val
.substr(0, p1
);
193 // Include the current selected nick
194 newnick
= this.tabcomplete
.data
.shift();
195 this.tabcomplete
.data
.push(newnick
);
198 if (inp_val
.substr(inp
[0].selectionStart
, 2) !== trailing
)
201 // Now include the rest of the current value
202 val
+= inp_val
.substr(inp
[0].selectionStart
);
206 // Move the cursor position to the end of the nick
207 if (inp
[0].setSelectionRange
) {
208 inp
[0].setSelectionRange(p1
+ newnick
.length
+ trailing
.length
, p1
+ newnick
.length
+ trailing
.length
);
209 } else if (inp
[0].createTextRange
) { // not sure if this bit is actually needed....
210 range
= inp
[0].createTextRange();
211 range
.collapse(true);
212 range
.moveEnd('character', p1
+ newnick
.length
+ trailing
.length
);
213 range
.moveStart('character', p1
+ newnick
.length
+ trailing
.length
);
223 processInput: function (command_raw
) {
227 // The default command
228 if (command_raw
[0] !== '/' || command_raw
.substr(0, 2) === '//') {
229 // Remove any slash escaping at the start (ie. //)
230 command_raw
= command_raw
.replace(/^\/\//, '/');
232 // Prepend the default command
233 command_raw
= '/msg ' + _kiwi
.app
.panels().active
.get('name') + ' ' + command_raw
;
236 // Process the raw command for any aliases
237 this.preprocessor
.vars
.server
= _kiwi
.app
.connections
.active_connection
.get('name');
238 this.preprocessor
.vars
.channel
= _kiwi
.app
.panels().active
.get('name');
239 this.preprocessor
.vars
.destination
= this.preprocessor
.vars
.channel
;
240 command_raw
= this.preprocessor
.process(command_raw
);
242 // Extract the command and parameters
243 params
= command_raw
.split(/\s/);
244 if (params
[0][0] === '/') {
245 command
= params
[0].substr(1).toLowerCase();
246 params
= params
.splice(1, params
.length
- 1);
250 params
.unshift(_kiwi
.app
.panels().active
.get('name'));
253 // Trigger the command events
254 this.trigger('command', {command
: command
, params
: params
});
255 this.trigger('command:' + command
, {command
: command
, params
: params
});
257 // If we didn't have any listeners for this event, fire a special case
258 // TODO: This feels dirty. Should this really be done..?
259 if (!this._events
['command:' + command
]) {
260 this.trigger('unknown_command', {command
: command
, params
: params
});
265 addPluginIcon: function ($icon
) {
266 var $tool
= $('<div class="tool"></div>').append($icon
);
267 this.$el
.find('.input_tools').append($tool
);
268 _kiwi
.app
.view
.doLayout();