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'));
33 // Keep focus on the input box as we flick between panels
34 _kiwi
.app
.panels
.bind('active', function (active_panel
) {
35 if (active_panel
.isChannel() || active_panel
.isServer() || active_panel
.isQuery()) {
36 that
.$('.inp').focus();
42 var send_message_text
= translateText('client_views_controlbox_message');
43 this.$('.inp').attr('placeholder', send_message_text
);
48 showNickChange: function (ev
) {
49 // Nick box already open? Don't do it again
53 this.nick_change
= new _kiwi
.view
.NickChangeBox();
54 this.nick_change
.render();
56 this.listenTo(this.nick_change
, 'close', function() {
57 delete this.nick_change
;
61 process: function (ev
) {
63 inp
= $(ev
.currentTarget
),
67 if (navigator
.appVersion
.indexOf("Mac") !== -1) {
73 // If not a tab key, reset the tabcomplete data
74 if (this.tabcomplete
.active
&& ev
.keyCode
!== 9) {
75 this.tabcomplete
.active
= false;
76 this.tabcomplete
.data
= [];
77 this.tabcomplete
.prefix
= '';
81 case (ev
.keyCode
=== 13): // return
82 inp_val
= inp_val
.trim();
85 $.each(inp_val
.split('\n'), function (idx
, line
) {
86 that
.processInput(line
);
89 this.buffer
.push(inp_val
);
90 this.buffer_pos
= this.buffer
.length
;
98 case (ev
.keyCode
=== 38): // up
99 if (this.buffer_pos
> 0) {
101 inp
.val(this.buffer
[this.buffer_pos
]);
103 //suppress browsers default behavior as it would set the cursor at the beginning
106 case (ev
.keyCode
=== 40): // down
107 if (this.buffer_pos
< this.buffer
.length
) {
109 inp
.val(this.buffer
[this.buffer_pos
]);
113 case (ev
.keyCode
=== 219 && meta
): // [ + meta
114 // Find all the tab elements and get the index of the active tab
115 var $tabs
= $('#kiwi .tabs').find('li[class!=connection]');
116 var cur_tab_ind
= (function() {
117 for (var idx
=0; idx
<$tabs
.length
; idx
++){
118 if ($($tabs
[idx
]).hasClass('active'))
123 // Work out the previous tab along. Wrap around if needed
124 if (cur_tab_ind
=== 0) {
125 $prev_tab
= $($tabs
[$tabs
.length
- 1]);
127 $prev_tab
= $($tabs
[cur_tab_ind
- 1]);
133 case (ev
.keyCode
=== 221 && meta
): // ] + meta
134 // Find all the tab elements and get the index of the active tab
135 var $tabs
= $('#kiwi .tabs').find('li[class!=connection]');
136 var cur_tab_ind
= (function() {
137 for (var idx
=0; idx
<$tabs
.length
; idx
++){
138 if ($($tabs
[idx
]).hasClass('active'))
143 // Work out the next tab along. Wrap around if needed
144 if (cur_tab_ind
=== $tabs
.length
- 1) {
145 $next_tab
= $($tabs
[0]);
147 $next_tab
= $($tabs
[cur_tab_ind
+ 1]);
153 case (ev
.keyCode
=== 9 //Check if ONLY tab is pressed
154 && !ev
.shiftKey
//(user could be using some browser
155 && !ev
.altKey
//keyboard shortcut)
158 this.tabcomplete
.active
= true;
159 if (_
.isEqual(this.tabcomplete
.data
, [])) {
160 // Get possible autocompletions
162 members
= _kiwi
.app
.panels().active
.get('members');
164 // If we have a members list, get the models. Otherwise empty array
165 members
= members
? members
.models
: [];
167 $.each(members
, function (i
, member
) {
169 ac_data
.push(member
.get('nick'));
172 ac_data
.push(_kiwi
.app
.panels().active
.get('name'));
174 ac_data
= _
.sortBy(ac_data
, function (nick
) {
177 this.tabcomplete
.data
= ac_data
;
180 if (inp_val
[inp
[0].selectionStart
- 1] === ' ') {
185 var tokens
, // Words before the cursor position
186 val
, // New value being built up
187 p1
, // Position in the value just before the nick
188 newnick
, // New nick to be displayed (cycles through)
189 range
, // TextRange for setting new text cursor position
190 nick
, // Current nick in the value
191 trailing
= ': '; // Text to be inserted after a tabbed nick
193 tokens
= inp_val
.substring(0, inp
[0].selectionStart
).split(' ');
194 if (tokens
[tokens
.length
-1] == ':')
197 // Only add the trailing text if not at the beginning of the line
198 if (tokens
.length
> 1)
201 nick
= tokens
[tokens
.length
- 1];
203 if (this.tabcomplete
.prefix
=== '') {
204 this.tabcomplete
.prefix
= nick
;
207 this.tabcomplete
.data
= _
.select(this.tabcomplete
.data
, function (n
) {
208 return (n
.toLowerCase().indexOf(that
.tabcomplete
.prefix
.toLowerCase()) === 0);
211 if (this.tabcomplete
.data
.length
> 0) {
212 // Get the current value before cursor position
213 p1
= inp
[0].selectionStart
- (nick
.length
);
214 val
= inp_val
.substr(0, p1
);
216 // Include the current selected nick
217 newnick
= this.tabcomplete
.data
.shift();
218 this.tabcomplete
.data
.push(newnick
);
221 if (inp_val
.substr(inp
[0].selectionStart
, 2) !== trailing
)
224 // Now include the rest of the current value
225 val
+= inp_val
.substr(inp
[0].selectionStart
);
229 // Move the cursor position to the end of the nick
230 if (inp
[0].setSelectionRange
) {
231 inp
[0].setSelectionRange(p1
+ newnick
.length
+ trailing
.length
, p1
+ newnick
.length
+ trailing
.length
);
232 } else if (inp
[0].createTextRange
) { // not sure if this bit is actually needed....
233 range
= inp
[0].createTextRange();
234 range
.collapse(true);
235 range
.moveEnd('character', p1
+ newnick
.length
+ trailing
.length
);
236 range
.moveStart('character', p1
+ newnick
.length
+ trailing
.length
);
246 processInput: function (command_raw
) {
248 command
, params
, events_data
,
251 // If sending a message when not in a channel or query window, automatically
252 // convert it into a command
253 if (command_raw
[0] !== '/' && !_kiwi
.app
.panels().active
.isChannel() && !_kiwi
.app
.panels().active
.isQuery()) {
254 command_raw
= '/' + command_raw
;
257 // The default command
258 if (command_raw
[0] !== '/' || command_raw
.substr(0, 2) === '//') {
259 // Remove any slash escaping at the start (ie. //)
260 command_raw
= command_raw
.replace(/^\/\//, '/');
262 // Prepend the default command
263 command_raw
= '/msg ' + _kiwi
.app
.panels().active
.get('name') + ' ' + command_raw
;
266 // Process the raw command for any aliases
267 this.preprocessor
.vars
.server
= _kiwi
.app
.connections
.active_connection
.get('name');
268 this.preprocessor
.vars
.channel
= _kiwi
.app
.panels().active
.get('name');
269 this.preprocessor
.vars
.destination
= this.preprocessor
.vars
.channel
;
270 command_raw
= this.preprocessor
.process(command_raw
);
272 // Extract the command and parameters
273 params
= command_raw
.split(/\s/);
274 if (params
[0][0] === '/') {
275 command
= params
[0].substr(1).toLowerCase();
276 params
= params
.splice(1, params
.length
- 1);
280 params
.unshift(_kiwi
.app
.panels().active
.get('name'));
283 // Emit a plugin event for any modifications
284 events_data
= {command
: command
, params
: params
};
286 _kiwi
.global
.events
.emit('command', events_data
)
288 // Trigger the command events
289 that
.trigger('command', {command
: events_data
.command
, params
: events_data
.params
});
290 that
.trigger('command:' + events_data
.command
, {command
: events_data
.command
, params
: events_data
.params
});
292 // If we didn't have any listeners for this event, fire a special case
293 // TODO: This feels dirty. Should this really be done..?
294 if (!that
._events
['command:' + events_data
.command
]) {
295 that
.trigger('unknown_command', {command
: events_data
.command
, params
: events_data
.params
});
301 addPluginIcon: function ($icon
) {
302 var $tool
= $('<div class="tool"></div>').append($icon
);
303 this.$el
.find('.input_tools').append($tool
);
304 _kiwi
.app
.view
.doLayout();