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 // Nick box already open? Don't do it again
39 this.nick_change
= new _kiwi
.view
.NickChangeBox();
40 this.nick_change
.render();
42 this.listenTo(this.nick_change
, 'close', function() {
43 delete this.nick_change
;
47 process: function (ev
) {
49 inp
= $(ev
.currentTarget
),
53 if (navigator
.appVersion
.indexOf("Mac") !== -1) {
59 // If not a tab key, reset the tabcomplete data
60 if (this.tabcomplete
.active
&& ev
.keyCode
!== 9) {
61 this.tabcomplete
.active
= false;
62 this.tabcomplete
.data
= [];
63 this.tabcomplete
.prefix
= '';
67 case (ev
.keyCode
=== 13): // return
68 inp_val
= inp_val
.trim();
71 $.each(inp_val
.split('\n'), function (idx
, line
) {
72 that
.processInput(line
);
75 this.buffer
.push(inp_val
);
76 this.buffer_pos
= this.buffer
.length
;
84 case (ev
.keyCode
=== 38): // up
85 if (this.buffer_pos
> 0) {
87 inp
.val(this.buffer
[this.buffer_pos
]);
89 //suppress browsers default behavior as it would set the cursor at the beginning
92 case (ev
.keyCode
=== 40): // down
93 if (this.buffer_pos
< this.buffer
.length
) {
95 inp
.val(this.buffer
[this.buffer_pos
]);
99 case (ev
.keyCode
=== 219 && meta
): // [ + meta
100 // Find all the tab elements and get the index of the active tab
101 var $tabs
= $('#kiwi .tabs').find('li[class!=connection]');
102 var cur_tab_ind
= (function() {
103 for (var idx
=0; idx
<$tabs
.length
; idx
++){
104 if ($($tabs
[idx
]).hasClass('active'))
109 // Work out the previous tab along. Wrap around if needed
110 if (cur_tab_ind
=== 0) {
111 $prev_tab
= $($tabs
[$tabs
.length
- 1]);
113 $prev_tab
= $($tabs
[cur_tab_ind
- 1]);
119 case (ev
.keyCode
=== 221 && meta
): // ] + meta
120 // Find all the tab elements and get the index of the active tab
121 var $tabs
= $('#kiwi .tabs').find('li[class!=connection]');
122 var cur_tab_ind
= (function() {
123 for (var idx
=0; idx
<$tabs
.length
; idx
++){
124 if ($($tabs
[idx
]).hasClass('active'))
129 // Work out the next tab along. Wrap around if needed
130 if (cur_tab_ind
=== $tabs
.length
- 1) {
131 $next_tab
= $($tabs
[0]);
133 $next_tab
= $($tabs
[cur_tab_ind
+ 1]);
139 case (ev
.keyCode
=== 9 //Check if ONLY tab is pressed
140 && !ev
.shiftKey
//(user could be using some browser
141 && !ev
.altKey
//keyboard shortcut)
144 this.tabcomplete
.active
= true;
145 if (_
.isEqual(this.tabcomplete
.data
, [])) {
146 // Get possible autocompletions
148 members
= _kiwi
.app
.panels().active
.get('members');
150 // If we have a members list, get the models. Otherwise empty array
151 members
= members
? members
.models
: [];
153 $.each(members
, function (i
, member
) {
155 ac_data
.push(member
.get('nick'));
158 ac_data
.push(_kiwi
.app
.panels().active
.get('name'));
160 ac_data
= _
.sortBy(ac_data
, function (nick
) {
163 this.tabcomplete
.data
= ac_data
;
166 if (inp_val
[inp
[0].selectionStart
- 1] === ' ') {
171 var tokens
, // Words before the cursor position
172 val
, // New value being built up
173 p1
, // Position in the value just before the nick
174 newnick
, // New nick to be displayed (cycles through)
175 range
, // TextRange for setting new text cursor position
176 nick
, // Current nick in the value
177 trailing
= ': '; // Text to be inserted after a tabbed nick
179 tokens
= inp_val
.substring(0, inp
[0].selectionStart
).split(' ');
180 if (tokens
[tokens
.length
-1] == ':')
183 // Only add the trailing text if not at the beginning of the line
184 if (tokens
.length
> 1)
187 nick
= tokens
[tokens
.length
- 1];
189 if (this.tabcomplete
.prefix
=== '') {
190 this.tabcomplete
.prefix
= nick
;
193 this.tabcomplete
.data
= _
.select(this.tabcomplete
.data
, function (n
) {
194 return (n
.toLowerCase().indexOf(that
.tabcomplete
.prefix
.toLowerCase()) === 0);
197 if (this.tabcomplete
.data
.length
> 0) {
198 // Get the current value before cursor position
199 p1
= inp
[0].selectionStart
- (nick
.length
);
200 val
= inp_val
.substr(0, p1
);
202 // Include the current selected nick
203 newnick
= this.tabcomplete
.data
.shift();
204 this.tabcomplete
.data
.push(newnick
);
207 if (inp_val
.substr(inp
[0].selectionStart
, 2) !== trailing
)
210 // Now include the rest of the current value
211 val
+= inp_val
.substr(inp
[0].selectionStart
);
215 // Move the cursor position to the end of the nick
216 if (inp
[0].setSelectionRange
) {
217 inp
[0].setSelectionRange(p1
+ newnick
.length
+ trailing
.length
, p1
+ newnick
.length
+ trailing
.length
);
218 } else if (inp
[0].createTextRange
) { // not sure if this bit is actually needed....
219 range
= inp
[0].createTextRange();
220 range
.collapse(true);
221 range
.moveEnd('character', p1
+ newnick
.length
+ trailing
.length
);
222 range
.moveStart('character', p1
+ newnick
.length
+ trailing
.length
);
232 processInput: function (command_raw
) {
236 // The default command
237 if (command_raw
[0] !== '/' || command_raw
.substr(0, 2) === '//') {
238 // Remove any slash escaping at the start (ie. //)
239 command_raw
= command_raw
.replace(/^\/\//, '/');
241 // Prepend the default command
242 command_raw
= '/msg ' + _kiwi
.app
.panels().active
.get('name') + ' ' + command_raw
;
245 // Process the raw command for any aliases
246 this.preprocessor
.vars
.server
= _kiwi
.app
.connections
.active_connection
.get('name');
247 this.preprocessor
.vars
.channel
= _kiwi
.app
.panels().active
.get('name');
248 this.preprocessor
.vars
.destination
= this.preprocessor
.vars
.channel
;
249 command_raw
= this.preprocessor
.process(command_raw
);
251 // Extract the command and parameters
252 params
= command_raw
.split(/\s/);
253 if (params
[0][0] === '/') {
254 command
= params
[0].substr(1).toLowerCase();
255 params
= params
.splice(1, params
.length
- 1);
259 params
.unshift(_kiwi
.app
.panels().active
.get('name'));
262 // Trigger the command events
263 this.trigger('command', {command
: command
, params
: params
});
264 this.trigger('command:' + command
, {command
: command
, params
: params
});
266 // If we didn't have any listeners for this event, fire a special case
267 // TODO: This feels dirty. Should this really be done..?
268 if (!this._events
['command:' + command
]) {
269 this.trigger('unknown_command', {command
: command
, params
: params
});
274 addPluginIcon: function ($icon
) {
275 var $tool
= $('<div class="tool"></div>').append($icon
);
276 this.$el
.find('.input_tools').append($tool
);
277 _kiwi
.app
.view
.doLayout();