1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is ChatZilla.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998
21 * the Initial Developer. All Rights Reserved.
24 * Robert Ginda, <rginda@netscape.com>, original author
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
42 function isMotif(name
)
44 return "client.prefs['motif.current'] == " +
45 "client.prefs['motif." + name
+ "']";
48 function isFontFamily(name
)
50 return "cx.sourceObject.prefs['font.family'] == '" + name
+ "'";
53 function isFontFamilyCustom()
55 return "!cx.sourceObject.prefs['font.family']." +
56 "match(/^(default|(sans-)?serif|monospace)$/)";
59 function isFontSize(size
)
61 return "cx.fontSize == cx.fontSizeDefault + " + size
;
64 function isFontSizeCustom()
66 // It's "custom" if it's set (non-zero/not default), not the default
67 // size (medium) and not +/-2 (small/large).
68 return "'fontSize' in cx && cx.fontSize != 0 && " +
69 "cx.fontSizeDefault != cx.fontSize && " +
70 "Math.abs((cx.fontSizeDefault - cx.fontSize) / 2) != 1";
73 function onMenuCommand(event
, window
)
75 var commandName
= event
.originalTarget
.getAttribute("commandname");
76 var params
= new Object();
77 if ("cx" in client
.menuManager
&& client
.menuManager
.cx
)
78 params
= client
.menuManager
.cx
;
79 params
.sourceWindow
= window
;
80 params
.source
= "menu";
82 dispatch(commandName
, params
, true);
84 delete client
.menuManager
.cx
;
87 client
.onMenuCommand
= onMenuCommand
;
88 client
.menuSpecs
= new Object();
89 var menuManager
= new MenuManager(client
.commandManager
,
92 "client.onMenuCommand(event, window);");
93 client
.menuManager
= menuManager
;
95 client
.menuSpecs
["maintoolbar"] = {
105 var Win
= "(client.platform == 'Windows')";
106 var NotWin
= "(client.platform != 'Windows')";
107 var Linux
= "(client.platform == 'Linux')";
108 var NotLinux
= "(client.platform != 'Linux')";
109 var Mac
= "(client.platform == 'Mac')";
110 var NotMac
= "(client.platform != 'Mac')";
113 var Mozilla
= "(client.host == 'Mozilla')";
114 var NotMozilla
= "(client.host != 'Mozilla')";
115 var Toolkit
= NotMozilla
;
116 var XULRunner
= "(client.host == 'XULrunner')";
118 // Useful combinations
119 var ToolkitOnLinux
= "(" + Toolkit
+ " and " + Linux
+ ")";
120 var ToolkitNotOnLinux
= "(" + Toolkit
+ " and " + NotLinux
+ ")";
121 var ToolkitOnMac
= "(" + Toolkit
+ " and " + Mac
+ ")";
122 var ToolkitNotOnMac
= "(" + Toolkit
+ " and " + NotMac
+ ")";
124 // IRC specific values
125 var ViewClient
= "(cx.TYPE == 'IRCClient')";
126 var ViewNetwork
= "(cx.TYPE == 'IRCNetwork')";
127 var ViewChannel
= "(cx.TYPE == 'IRCChannel')";
128 var ViewUser
= "(cx.TYPE == 'IRCUser')";
130 // IRC specific combinations
131 var ChannelActive
= "(" + ViewChannel
+ " and cx.channel.active)";
132 var ChannelInactive
= "(" + ViewChannel
+ " and !cx.channel.active)";
133 var NetConnected
= "(cx.network and cx.network.isConnected())";
134 var NetDisconnected
= "(cx.network and !cx.network.isConnected())";
136 client
.menuSpecs
["mainmenu:chatzilla"] = {
137 label
: MSG_MNU_CHATZILLA
,
138 getContext
: getDefaultContext
,
141 ["cmd-prefs", {id
: "menu_preferences"}],
144 ["-", {visibleif
: NotMac
}],
145 ["exit", {visibleif
: Win
}],
146 ["quit", {visibleif
: NotMac
+ " and " + NotWin
}]
150 client
.menuSpecs
["mainmenu:irc"] = {
152 getContext
: getDefaultContext
,
156 // Planned future menu items, not implemented yet.
159 //["manage-networks"],
160 //["manage-plugins"],
162 // Planned future menu items, not implemented yet.
164 //[">popup:current_networks"]
167 ["leave", {visibleif
: ChannelActive
}],
168 ["rejoin", {visibleif
: ChannelInactive
}],
169 ["disconnect", {visibleif
: NetConnected
}],
170 ["reconnect", {visibleif
: NetDisconnected
}],
171 ["-", {visibleif
: "cx.network"}],
173 ["hide-view", {enabledif
: "client.viewsArray.length > 1"}],
174 ["delete-view", {enabledif
: "client.viewsArray.length > 1"}],
178 checkedif
: "isStartupURL(cx.sourceObject.getURL())"}]
182 client
.menuSpecs
["mainmenu:edit"] = {
184 getContext
: getDefaultContext
,
187 ["cmd-undo", {enabledif
: "getCommandEnabled('cmd_undo')"}],
188 ["cmd-redo", {enabledif
: "getCommandEnabled('cmd_redo')"}],
190 ["cmd-cut", {enabledif
: "getCommandEnabled('cmd_cut')"}],
191 ["cmd-copy", {enabledif
: "getCommandEnabled('cmd_copy')"}],
192 ["cmd-paste", {enabledif
: "getCommandEnabled('cmd_paste')"}],
193 ["cmd-delete", {enabledif
: "getCommandEnabled('cmd_delete')"}],
195 ["cmd-selectall", {enabledif
: "getCommandEnabled('cmd_selectAll')"}],
198 ["find-again", {enabledif
: "canFindAgainInPage()"}],
199 // Mozilla (suite) gets : separator, Mozilla Prefs, ChatZilla prefs.
200 // Toolkit Linux apps get: separator, ChatZilla prefs.
201 // Toolkit Mac apps get : ChatZilla prefs (special Mac ID).
202 ["-", {visibleif
: Mozilla
}],
203 ["cmd-mozilla-prefs", {visibleif
: Mozilla
}]
207 client
.menuSpecs
["popup:motifs"] = {
208 label
: MSG_MNU_MOTIFS
,
213 checkedif
: isMotif("default")}],
216 checkedif
: isMotif("dark")}],
219 checkedif
: isMotif("light")}],
223 client
.menuSpecs
["mainmenu:view"] = {
225 getContext
: getDefaultContext
,
230 checkedif
: "isVisible('view-tabs')"}],
233 checkedif
: "cx.sourceObject.prefs['displayHeader']"}],
236 checkedif
: "isVisible('user-list-box')"}],
239 checkedif
: "isVisible('status-bar')"}],
246 checkedif
: "client.prefs['collapseMsgs']"}],
249 checkedif
: "client.prefs['copyMessages']"}],
250 ["toggle-timestamps",
252 checkedif
: "cx.sourceObject.prefs['timestamps']"}]
256 /* Mac expects a help menu with this ID, and there is nothing we can do
258 client
.menuSpecs
["mainmenu:help"] = {
263 ["-", {visibleif
: Mozilla
}],
271 client
.menuSpecs
["popup:fonts"] = {
272 label
: MSG_MNU_FONTS
,
273 getContext
: getFontContext
,
276 ["font-size-bigger", {}],
277 ["font-size-smaller", {}],
279 ["font-size-default",
280 {type
: "checkbox", checkedif
: "!cx.fontSize"}],
282 {type
: "checkbox", checkedif
: isFontSize(-2)}],
284 {type
: "checkbox", checkedif
: isFontSize(0)}],
286 {type
: "checkbox", checkedif
: isFontSize(+2)}],
288 {type
: "checkbox", checkedif
: isFontSizeCustom()}],
290 ["font-family-default",
291 {type
: "checkbox", checkedif
: isFontFamily("default")}],
292 ["font-family-serif",
293 {type
: "checkbox", checkedif
: isFontFamily("serif")}],
294 ["font-family-sans-serif",
295 {type
: "checkbox", checkedif
: isFontFamily("sans-serif")}],
296 ["font-family-monospace",
297 {type
: "checkbox", checkedif
: isFontFamily("monospace")}],
298 ["font-family-other",
299 {type
: "checkbox", checkedif
: isFontFamilyCustom()}]
304 var isop
= "(cx.channel.iAmOp()) && ";
305 // Me is op or half-op.
306 var isopish
= "(cx.channel.iAmOp() || cx.channel.iAmHalfOp()) && ";
307 // Server has half-ops.
308 var shop
= "(cx.server.supports.prefix.indexOf('h') > 0) && ";
310 client
.menuSpecs
["popup:opcommands"] = {
311 label
: MSG_MNU_OPCOMMANDS
,
314 ["op", {visibleif
: isop
+ "!cx.user.isOp"}],
315 ["deop", {visibleif
: isop
+ "cx.user.isOp"}],
316 ["hop", {visibleif
: isopish
+ shop
+ "!cx.user.isHalfOp"}],
317 ["dehop", {visibleif
: isopish
+ shop
+ "cx.user.isHalfOp"}],
318 ["voice", {visibleif
: isopish
+ "!cx.user.isVoice"}],
319 ["devoice", {visibleif
: isopish
+ "cx.user.isVoice"}],
321 ["ban", {enabledif
: "(" + isop
+ "1) || (" + isopish
+ "!cx.user.isOp)"}],
322 ["unban", {enabledif
: "(" + isop
+ "1) || (" + isopish
+ "!cx.user.isOp)"}],
323 ["kick", {enabledif
: "(" + isop
+ "1) || (" + isopish
+ "!cx.user.isOp)"}],
324 ["kick-ban", {enabledif
: "(" + isop
+ "1) || (" + isopish
+ "!cx.user.isOp)"}]
329 client
.menuSpecs
["popup:usercommands"] = {
330 label
: MSG_MNU_USERCOMMANDS
,
333 ["query", {visibleif
: "cx.user"}],
334 ["whois", {visibleif
: "cx.user"}],
335 ["whowas", {visibleif
: "cx.nickname && !cx.user"}],
336 ["ping", {visibleif
: "cx.user"}],
337 ["time", {visibleif
: "cx.user"}],
338 ["version", {visibleif
: "cx.user"}],
339 ["-", {visibleif
: "cx.user"}],
340 ["dcc-chat", {visibleif
: "cx.user"}],
341 ["dcc-send", {visibleif
: "cx.user"}],
346 client
.menuSpecs
["context:userlist"] = {
347 getContext
: getUserlistContext
,
350 ["toggle-usort", {type
: "checkbox",
351 checkedif
: "client.prefs['sortUsersByMode']"}],
352 ["toggle-umode", {type
: "checkbox",
353 checkedif
: "client.prefs['showModeSymbols']"}],
354 ["-", {visibleif
: "cx.nickname"}],
355 ["label-user", {visibleif
: "cx.nickname && (cx.userCount == 1)",
357 ["label-user-multi", {visibleif
: "cx.nickname && (cx.userCount != 1)",
359 [">popup:opcommands", {visibleif
: "cx.nickname",
360 enabledif
: isopish
+ "true"}],
361 [">popup:usercommands", {visibleif
: "cx.nickname",
362 enabledif
: "cx.userCount == 1"}],
366 var urlenabled
= "has('url')";
367 var urlexternal
= "has('url') && cx.url.search(/^ircs?:/i) == -1";
368 var textselected
= "getCommandEnabled('cmd_copy')";
370 client
.menuSpecs
["context:messages"] = {
371 getContext
: getMessagesContext
,
374 ["goto-url", {visibleif
: urlenabled
}],
375 ["goto-url-newwin", {visibleif
: urlexternal
+ " && !" + XULRunner
}],
376 ["goto-url-newtab", {visibleif
: urlexternal
+ " && !" + XULRunner
}],
377 ["cmd-copy-link-url", {visibleif
: urlenabled
}],
378 ["cmd-copy", {visibleif
: "!" + urlenabled
, enabledif
: textselected
}],
379 ["cmd-selectall", {visibleif
: "!" + urlenabled
}],
380 ["-", {visibleif
: "cx.channel && cx.nickname"}],
381 ["label-user", {visibleif
: "cx.channel && cx.nickname", header
: true}],
382 [">popup:opcommands", {visibleif
: "cx.channel && cx.nickname",
383 enabledif
: isopish
+ "cx.user"}],
384 [">popup:usercommands", {visibleif
: "cx.channel && cx.nickname"}],
387 ["hide-view", {enabledif
: "client.viewsArray.length > 1"}],
390 checkedif
: "isStartupURL(cx.sourceObject.getURL())"}],
392 ["leave", {visibleif
: ChannelActive
}],
393 ["rejoin", {visibleif
: ChannelInactive
}],
394 ["delete-view", {visibleif
: "!" + ChannelActive
}],
395 ["disconnect", {visibleif
: NetConnected
}],
396 ["reconnect", {visibleif
: NetDisconnected
}],
402 client
.menuSpecs
["context:tab"] = {
403 getContext
: getTabContext
,
407 ["hide-view", {enabledif
: "client.viewsArray.length > 1"}],
410 checkedif
: "isStartupURL(cx.sourceObject.getURL())"}],
412 ["leave", {visibleif
: ChannelActive
}],
413 ["rejoin", {visibleif
: ChannelInactive
}],
414 ["delete-view", {visibleif
: "!" + ChannelActive
}],
415 ["disconnect", {visibleif
: NetConnected
}],
416 ["reconnect", {visibleif
: NetDisconnected
}],
422 // Gross hacks to figure out if we're away:
423 var netAway
= "cx.network.prefs['away']";
424 var cliAway
= "client.prefs['away']";
425 var awayCheckNet
= "(cx.network and (" + netAway
+ " == item.message))";
426 var awayCheckCli
= "(!cx.network and (" + cliAway
+ " == item.message))";
427 var awayChecked
= awayCheckNet
+ " or " + awayCheckCli
;
428 var areBack
= "(cx.network and !" + netAway
+ ") or " +
429 "(!cx.network and !" + cliAway
+ ")";
431 client
.menuSpecs
["mainmenu:nickname"] = {
432 label
: client
.prefs
["nickname"],
433 domID
: "server-nick",
434 getContext
: getDefaultContext
,
439 ["back", {type
: "checkbox", checkedif
: areBack
}],
440 ["away", {type
: "checkbox",
441 checkedif
: awayChecked
,
442 repeatfor
: "client.awayMsgs",
443 repeatmap
: "cx.reason = item.message" }],
449 client
.menuSpecs
["popup:nickname"] = {
451 getContext
: getDefaultContext
,
452 items
: client
.menuSpecs
["mainmenu:nickname"].items
457 function createMenus()
459 client
.menuManager
.createMenus(document
, "mainmenu");
460 client
.menuManager
.createContextMenus(document
);
462 // The menus and the component bar need to be hidden on some hosts.
463 var winMenu
= document
.getElementById("windowMenu");
464 var tasksMenu
= document
.getElementById("tasksMenu");
465 var comBar
= document
.getElementById("component-bar");
467 if (client
.host
!= "Mozilla") {
468 tasksMenu
.parentNode
.removeChild(tasksMenu
);
469 winMenu
.parentNode
.removeChild(winMenu
);
471 comBar
.collapsed
= false;
474 if (client
.host
== "XULrunner")
476 // This is a hack to work around Gecko bug 98997, which means that
477 // :empty causes menus to be hidden until we force a reflow.
478 var menuBar
= document
.getElementById("mainmenu");
479 menuBar
.hidden
= true;
480 menuBar
.hidden
= false;
484 function getCommandContext (id
, event
)
486 var cx
= { originalEvent
: event
};
488 if (id
in client
.menuSpecs
)
490 if ("getContext" in client
.menuSpecs
[id
])
491 cx
= client
.menuSpecs
[id
].getContext(cx
);
492 else if ("cx" in client
.menuManager
)
494 //dd ("using existing context");
495 cx
= client
.menuManager
.cx
;
504 dd ("getCommandContext: unknown menu id " + id
);
507 if (typeof cx
== "object")
509 if (!("menuManager" in cx
))
510 cx
.menuManager
= client
.menuManager
;
511 if (!("contextSource" in cx
))
512 cx
.contextSource
= id
;
513 if ("dbgContexts" in client
&& client
.dbgContexts
)
514 dd ("context '" + id
+ "'\n" + dumpObjectTree(cx
));