You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1172 lines
30 KiB
HTML
1172 lines
30 KiB
HTML
|
|
<style>
|
|
@import url(common.css);
|
|
</style>
|
|
<script type="text/tiscript">
|
|
const CommonNative = View.CommonNative;
|
|
|
|
const NODE_DIV = 1;
|
|
const NODE_GROUP = 2;
|
|
const NODE_CONTACT = 3;
|
|
const GA_NONE = 0;
|
|
const GA_ADD = 1;
|
|
const GA_RENAME = 2;
|
|
const GA_REMOVE = 3;
|
|
|
|
VM.unhandledExceptionHandler = function(err) {
|
|
view.msgbox(#error, err.toString(), "Sciter error", #ok);
|
|
return true;
|
|
}
|
|
|
|
class KillOverscroll: Behavior {
|
|
function wheelEvent(e) {
|
|
return (this.scroll(#top) <= 0 && e.wheelDelta > 0) || (this.scroll(#bottom) <= 0 && e.wheelDelta < 0);
|
|
}
|
|
|
|
function attached() {
|
|
this.subscribe(this.wheelEvent, Event.MOUSE, Event.MOUSE_WHEEL);
|
|
}
|
|
|
|
function detached() {
|
|
this.unsubscribe(this.wheelEvent);
|
|
}
|
|
}
|
|
|
|
class KillOverscrollNoFocus: KillOverscroll {
|
|
function attached() {
|
|
super.attached();
|
|
this.state.focusable = false;
|
|
}
|
|
}
|
|
|
|
class GlobalCaretPos: Behavior {
|
|
var savedCaretPos = 0;
|
|
var savedEdge = false;
|
|
|
|
function getCaretPos() {
|
|
if (!this.selection.caret) return 0;
|
|
var caretEdge = false;
|
|
var caretPos = this.selection.caret[1];
|
|
var priornode = this.selection.caret[0].parent.prior;
|
|
while (priornode) {
|
|
caretPos += priornode.text.length + 2;
|
|
priornode = priornode.prior;
|
|
}
|
|
caretEdge = this.selection.caret[2];
|
|
return caretPos + (caretEdge ? 1 : 0);
|
|
}
|
|
|
|
function getCaretEdge() {
|
|
if (!this.selection.caret) return false;
|
|
return this.selection.caret[2];
|
|
}
|
|
|
|
function setCaretPos(caretPos, caretEdge) {
|
|
if (caretPos < 0 || this.value == "" || this.value.length == 0) return;
|
|
this.selection.advance(#first);
|
|
var pos = 0;
|
|
var node = this.first;
|
|
while (node.next && pos + node.text.length + 2 <= caretPos) {
|
|
pos += node.text.length + 2;
|
|
node = node.next;
|
|
}
|
|
this.selection.select([bookmark: node.firstNode, caretPos - pos + (caretEdge ? -1 : 0), caretEdge]);
|
|
}
|
|
|
|
function saveCaretPos() {
|
|
this.savedCaretPos = this.getCaretPos();
|
|
this.savedEdge = this.getCaretEdge();
|
|
}
|
|
|
|
function restoreCaretPos() {
|
|
this.setCaretPos(this.savedCaretPos, this.savedEdge);
|
|
}
|
|
|
|
function attached() {
|
|
// if (this.selection) // init empty selection
|
|
// if (this.selection.caret === null) this.selection.select(this, #content);
|
|
}
|
|
}
|
|
|
|
class ThemedImage: Behavior {
|
|
function setupIcon() {
|
|
if (!View.MainNative) {
|
|
this.setVisible(false);
|
|
return;
|
|
}
|
|
this.applySprite(getSpriteData(this.@#pic));
|
|
this.update();
|
|
}
|
|
|
|
function setIcon(pic) {
|
|
this.@#pic = pic;
|
|
this.setupIcon();
|
|
}
|
|
|
|
function attached() {
|
|
if (this.@#auto == "") this.setupIcon();
|
|
}
|
|
}
|
|
|
|
class CustomTabs: Behavior {
|
|
var strip, panels;
|
|
|
|
function init() {
|
|
this.strip.on("click", "div[panel]", function(e) {
|
|
this super.switchTab(this);
|
|
});
|
|
|
|
// Select first
|
|
var tabs = this.strip.$$(> *);
|
|
if (tabs.length > 1)
|
|
tabs.first.@#selected = "";
|
|
else
|
|
this.strip.style#display = "none";
|
|
if (this.panels.first) this.panels.first.@#selected = "";
|
|
}
|
|
|
|
function switchTab(theTab) {
|
|
var tabs = this.strip.$$(> *);
|
|
for (var tab in tabs)
|
|
if (tab !== theTab) tab.@.remove("selected");
|
|
theTab.@#selected = "";
|
|
if (theTab.onOpen) theTab.onOpen();
|
|
|
|
var panels = this.panels.$$(> *);
|
|
for (var panel in panels) panel.@.remove("selected");
|
|
this.panels.$([panel="{theTab.@#panel}"]).@#selected = "";
|
|
}
|
|
|
|
function addTab(stripContent, panelContent, onOpen = null) {
|
|
this.strip.append(stripContent);
|
|
this.panels.append(panelContent);
|
|
if (onOpen) this.strip.last.onOpen = onOpen;
|
|
}
|
|
|
|
function attached() {
|
|
this.strip = this.$(.strip);
|
|
this.panels = this.$(.panels);
|
|
if (this.@#auto == "") this.init();
|
|
}
|
|
|
|
property selectedTabIndex(index) {
|
|
get return this.panels.$([selected]).index;
|
|
}
|
|
}
|
|
|
|
function TranslateMenu() {
|
|
try {
|
|
if (CommonNative.GetTranslation)
|
|
this.text = CommonNative.GetTranslation(this.text);
|
|
} catch(e) {}
|
|
}
|
|
|
|
function setupWindow(resize = true, min = true, max = true) {
|
|
view.windowResizable = resize;
|
|
view.windowMinimizable = min;
|
|
view.windowMaximizable = max;
|
|
}
|
|
|
|
function animateWindow() {
|
|
if (View.commonSettings.animateWindows) self.post(:{
|
|
var (x, y) = view.box(#position, #border, #screen);
|
|
self.animate(:progress {
|
|
view.move(x, (y - progress * 7).toInteger());
|
|
}, 100ms);
|
|
});
|
|
}
|
|
|
|
function translateWindow(selector) {
|
|
var elements = self.selectAll(selector);
|
|
var texts = [];
|
|
for (var element in elements) texts.push(element.text);
|
|
if (texts.length > 0) {
|
|
var ttexts = CommonNative.GetTranslations(texts);
|
|
for (var (index, element) in elements) element.text = ttexts[index];
|
|
}
|
|
|
|
elements = $$([title]);
|
|
texts = [];
|
|
for (var element in elements) texts.push(element.attributes["title"]);
|
|
if (texts.length > 0) {
|
|
var ttexts = CommonNative.GetTranslations(texts);
|
|
for (var (index, element) in elements) element.attributes["title"] = ttexts[index];
|
|
}
|
|
}
|
|
|
|
function activate(reorder = false) {
|
|
view.activate(reorder ? #toFront : #noChange);
|
|
}
|
|
|
|
function getBounds() {
|
|
var (x, y, width, height) = view.box(#rectw, #border, #screen);
|
|
return [x, y, width, height];
|
|
}
|
|
|
|
function setBounds(left, top, width, height) {
|
|
view.move(left, top, width, height, false);
|
|
}
|
|
|
|
function setPosition(left, top) {
|
|
view.move(left, top, false);
|
|
}
|
|
|
|
function fixMenu(menu, e, exec = null) {
|
|
if (e.target == menu)
|
|
if (e.type == Event.POPUP_READY) {
|
|
menu.focusback = view.focus && view.focus.tag != "menu" ? view.focus : null;
|
|
menu.state.focus = true;
|
|
} else if (e.type == Event.POPUP_DISMISSING) {
|
|
if (exec != null) exec();
|
|
var item = menu.$(:current);
|
|
if (item) item.state.current = false;
|
|
if (menu.focusback && CommonNative.IsWindowActive(menu.focusback))
|
|
view.focus = menu.focusback;
|
|
}
|
|
}
|
|
|
|
function setMenuListener(menu, callback) {
|
|
menu.subscribe(function(e) {
|
|
fixMenu(this, e);
|
|
if (e.type == Event.MENU_ITEM_CLICK) e.target.timer(1ms, callback); // focus fix
|
|
}, Event.BEHAVIOR_EVENT);
|
|
}
|
|
|
|
function setSystemColor(r, g, b) {
|
|
View.activeClr = color(r, g, b);
|
|
for (var window in View.all)
|
|
if (window.root.ns.applySystemColor) window.root.ns.applySystemColor();
|
|
}
|
|
|
|
function applyActiveColor(activeClr) {
|
|
if (!activeClr) return;
|
|
self.style.variable("activeColor", activeClr);
|
|
self.style.variable("activeColorHover", activeClr.tint(0.85, -1));
|
|
self.style.variable("activeColorCurrent", activeClr.tint(0.7, -0.75));
|
|
self.style.variable("activeColorHoverCurrent", activeClr.tint(0.6, -0.7));
|
|
self.style.variable("activeColorLight", activeClr.tint(0.2));
|
|
self.style.variable("activeColorDark", activeClr.tint(-0.2));
|
|
}
|
|
|
|
function applySystemColor() {
|
|
if (View.activeClr) applyActiveColor(View.activeClr)
|
|
}
|
|
applySystemColor();
|
|
|
|
function getSpriteData(pic) {
|
|
return CommonNative.GetSpriteData(pic);
|
|
}
|
|
|
|
function renderGroupLists(opt, addOut) {
|
|
var groupitems = View.MainNative.GetGroups(addOut);
|
|
opt.clear();
|
|
for (var groupitem in groupitems)
|
|
if (groupitem.caption == "-")
|
|
opt.append(<hr/>);
|
|
else
|
|
opt.append(<li groupid={groupitem.id}><div pic={groupitem.img}></div><span>{groupitem.caption}</span></li>);
|
|
|
|
var pics = opt.$$(div[pic]);
|
|
for (var pic in pics) {
|
|
pic.setupIcon();
|
|
pic.update();
|
|
}
|
|
}
|
|
|
|
function findWindow(uniq) {
|
|
for (var window in View.all)
|
|
if (window.uniqueid == uniq) return window;
|
|
return null;
|
|
}
|
|
|
|
function findWindows(uniq) {
|
|
var windows = [];
|
|
for (var window in View.all)
|
|
if (window.uniqueid == uniq) windows.push(window);
|
|
return windows;
|
|
}
|
|
|
|
function matchWindows(text) {
|
|
var windows = [];
|
|
for (var window in View.all)
|
|
if (window.uniqueid instanceof String && window.uniqueid.indexOf(text) == 0) windows.push(window);
|
|
return windows;
|
|
}
|
|
|
|
function getActiveWindow() {
|
|
for (var window in View.all)
|
|
if (CommonNative.IsWindowActive(window.root)) return window;
|
|
return null;
|
|
}
|
|
|
|
function openSingleWindow(props) {
|
|
var window = findWindow(props.uniqueid);
|
|
if (window) {
|
|
if (window.windowState == View.WINDOW_MINIMIZED)
|
|
window.windowState = View.WINDOW_SHOWN;
|
|
window.activate(#toFront);
|
|
return window.isDialog ? "" : window;
|
|
}
|
|
var scr = view.screen;
|
|
if (props.screen) {
|
|
var scrwin = findWindow(props.screen);
|
|
if (scrwin) scr = scrwin.screen;
|
|
} else {
|
|
var actwin = getActiveWindow();
|
|
if (actwin) scr = actwin.screen;
|
|
}
|
|
var winparams = {
|
|
type: props.tool ? View.TOOL_WINDOW : View.FRAME_WINDOW,
|
|
state: props.hidden ? View.WINDOW_HIDDEN : View.WINDOW_SHOWN,
|
|
url: self.url(props.url),
|
|
screen: scr,
|
|
caption: props.translate === false ? props.caption : CommonNative.GetTranslation(props.caption)
|
|
};
|
|
if (props.cascade) {
|
|
var windows = matchWindows(props.uniqueid.split(":")[0]);
|
|
var curx = 0, cury = 0;
|
|
for (var window in windows) {
|
|
var (x, y) = window.box(#position, #border, #screen);
|
|
curx = Integer.max(curx, x);
|
|
cury = Integer.max(cury, y);
|
|
}
|
|
|
|
var (sx, sy, sw, sh) = view.screenBox(scr, #frame, #rectw);
|
|
if (curx == 0 || cury == 0 || curx > sx + sw / 3 || cury > sy + sh / 3) {
|
|
curx = sx + sw / 4;
|
|
cury = sy + sh / 6;
|
|
} else {
|
|
curx += 40;
|
|
cury += 40;
|
|
}
|
|
|
|
props.x = curx;
|
|
props.y = cury;
|
|
}
|
|
if (props.alignment) winparams = winparams.extend({ alignment: props.alignment });
|
|
if (props.params) winparams = winparams.extend({ parameters: props.params });
|
|
if (props.x) winparams = winparams.extend({ x: props.x });
|
|
if (props.y) winparams = winparams.extend({ y: props.y });
|
|
if (props.width) winparams = winparams.extend({ width: props.width });
|
|
if (props.height) winparams = winparams.extend({ height: props.height });
|
|
|
|
if (props.disable) self.state.disabled = true;
|
|
if (props.dialog) {
|
|
return view.dialog(winparams);
|
|
} else {
|
|
var window = props.detach === true ? View.window(winparams) : view.window(winparams);
|
|
window.uniqueid = props.uniqueid;
|
|
if (props.disable) window.on("close", :: self.state.disabled = false);
|
|
return window;
|
|
}
|
|
}
|
|
|
|
function createContactList() {
|
|
var window = openSingleWindow({
|
|
url: "main.htm",
|
|
caption: "",
|
|
hidden: true,
|
|
//detach: true, // makes window unowned and shows taskbar button
|
|
translate: false,
|
|
uniqueid: #main,
|
|
alignment: 5,
|
|
width: 250,
|
|
height: 400
|
|
});
|
|
return window.root;
|
|
}
|
|
|
|
function createChat() {
|
|
var window = openSingleWindow({
|
|
url: "chat.htm",
|
|
caption: "",
|
|
hidden: true,
|
|
detach: true,
|
|
translate: false,
|
|
uniqueid: #chat,
|
|
alignment: 5,
|
|
width: 600,
|
|
height: 400
|
|
});
|
|
return window.root;
|
|
}
|
|
|
|
function createLog() {
|
|
var window = openSingleWindow({
|
|
url: "log.htm",
|
|
caption: "",
|
|
hidden: true,
|
|
detach: true,
|
|
uniqueid: #log,
|
|
alignment: 5,
|
|
width: 800,
|
|
height: 600
|
|
});
|
|
return window.root;
|
|
}
|
|
|
|
function openLog() {
|
|
var window = findWindow(#log);
|
|
if (window) window.root.ns.showLog(view.screen);
|
|
}
|
|
|
|
function openSessionsManager() {
|
|
var (px, py, dw, dh) = view.screenBox(#frame, #rectw);
|
|
openSingleWindow({
|
|
url: "sessionsmgr.htm",
|
|
caption: "Sessions manager",
|
|
uniqueid: #sessionsmgr,
|
|
detach: true,
|
|
alignment: 5,
|
|
width: dw / 3,
|
|
height: dh / 2.5
|
|
});
|
|
}
|
|
|
|
function updateSessionsManager(current) {
|
|
var window = findWindow(#sessionsmgr);
|
|
if (window)
|
|
if (current)
|
|
window.root.ns.removeCurrent();
|
|
else
|
|
window.root.ns.updateSessionsList();
|
|
}
|
|
|
|
function createTips() {
|
|
var window = openSingleWindow({
|
|
url: "tips.htm",
|
|
caption: "",
|
|
//detach: true,
|
|
translate: false,
|
|
uniqueid: #tips,
|
|
x: -9999,
|
|
y: -9999,
|
|
width: 1,
|
|
height: 1
|
|
});
|
|
return window.root;
|
|
}
|
|
|
|
function openPasswordDialog(type, title, pwd = "", maxlen = 0, translate = true) {
|
|
return openSingleWindow({
|
|
dialog: type != #acc,
|
|
translate: translate,
|
|
url: "enterpassword.htm",
|
|
caption: title,
|
|
uniqueid: type != #acc ? #loginpassword : #accpassword,
|
|
alignment: 5,
|
|
params: {
|
|
type: type,
|
|
password: pwd,
|
|
maxlength: maxlen
|
|
}
|
|
});
|
|
}
|
|
|
|
function openLoginDialog() {
|
|
var res = openPasswordDialog(#login,
|
|
CommonNative.GetTranslation("Login password") + " (" + View.MainNative.GetCurrentUserAcc() + ")",
|
|
View.MainNative.GetPwd(),
|
|
View.MainNative.GetMaxPasswordLength(),
|
|
false
|
|
);
|
|
if (res) {
|
|
View.MainNative.SavePassword(res);
|
|
return true;
|
|
} else return false;
|
|
}
|
|
|
|
function openAccDialog() {
|
|
return openPasswordDialog(#acc,
|
|
CommonNative.GetTranslation("Account password") + " (" + View.MainNative.GetCurrentUserAcc() + ")",
|
|
"", 0, false
|
|
);
|
|
}
|
|
|
|
function enterPassword(title, maxLen) {
|
|
return openPasswordDialog(#pwd, title, "", maxLen, false);
|
|
}
|
|
|
|
function enterLockPassword(title, hint, maxLen) {
|
|
self.post(:: openSingleWindow({
|
|
detach: true,
|
|
translate: false,
|
|
url: "enterpassword.htm",
|
|
caption: title,
|
|
uniqueid: #lock,
|
|
screen: #main,
|
|
alignment: 5,
|
|
params: {
|
|
type: #lockpwd,
|
|
maxlength: 0,
|
|
hint: hint
|
|
}
|
|
}));
|
|
}
|
|
|
|
function enterUIN(caption, icon) {
|
|
return openSingleWindow({
|
|
dialog: true,
|
|
url: "enterstring.htm",
|
|
caption: caption,
|
|
uniqueid: #enteruin,
|
|
alignment: 5,
|
|
params: {
|
|
uniqueid: #enteruin,
|
|
icon: icon
|
|
}
|
|
});
|
|
}
|
|
|
|
function inputQuery(caption, text, icon) {
|
|
return openSingleWindow({
|
|
dialog: true,
|
|
url: "enterstring.htm",
|
|
caption: caption,
|
|
uniqueid: #enterstr,
|
|
alignment: 5,
|
|
params: {
|
|
uniqueid: #enterstr,
|
|
icon: icon,
|
|
text: text
|
|
}
|
|
});
|
|
}
|
|
|
|
function viewInfoAbout() {
|
|
var uin = enterUIN("View info about...", "info");
|
|
if (uin && uin != "") self.post(:: View.MainNative.ViewInfoAbout(uin));
|
|
}
|
|
|
|
function openChatWith() {
|
|
var uin = enterUIN("Open chat with...", "msg");
|
|
if (uin && uin != "") self.post(:: View.MainNative.OpenChatWith(uin));
|
|
}
|
|
|
|
function createNewAccount() {
|
|
var uin = enterUIN("New user", "uin");
|
|
if (uin && uin != "") CommonNative.CreateAccount(uin)
|
|
}
|
|
|
|
function switchUser(conflict = false) {
|
|
if (conflict) self.post(:: showAlert(#warning, "There is another instance with this user already running"));
|
|
return openSingleWindow({
|
|
dialog: true,
|
|
url: "users.htm",
|
|
caption: "Users",
|
|
uniqueid: #users,
|
|
screen: #main,
|
|
alignment: 5,
|
|
width: 450,
|
|
height: 310
|
|
});
|
|
}
|
|
|
|
function showAlert(type, message, translate = true) {
|
|
var alert = openSingleWindow({
|
|
url: "alert.htm",
|
|
caption: "",
|
|
detach: true,
|
|
uniqueid: #alert,
|
|
screen: #main,
|
|
alignment: 5
|
|
});
|
|
alert.root.ns.addMessage({
|
|
type: type,
|
|
message: translate ? CommonNative.GetTranslation(message) : message
|
|
});
|
|
}
|
|
|
|
function createDialog(icon, title, msg, left = false, buttons = null, defbtn = null, cancelbtn = null, timeout = 0) {
|
|
return openSingleWindow({
|
|
dialog: true,
|
|
url: "dialog.htm",
|
|
caption: title,
|
|
translate: false,
|
|
uniqueid: #msgdlg,
|
|
alignment: 5,
|
|
params: {
|
|
icon: icon,
|
|
message: msg,
|
|
left: left,
|
|
buttons: buttons,
|
|
default: defbtn,
|
|
cancel: cancelbtn,
|
|
timeout: timeout
|
|
}
|
|
});
|
|
}
|
|
|
|
function openViewInfo(uid, title = "", updateOnly = false) {
|
|
var window = findWindow("info:" + uid);
|
|
if (window) {
|
|
if (window.windowState == View.WINDOW_MINIMIZED)
|
|
window.windowState = View.WINDOW_SHOWN;
|
|
window.activate(#toFront);
|
|
window.root.ns.updateData();
|
|
} else if (!updateOnly) {
|
|
openSingleWindow({
|
|
url: "viewinfo.htm",
|
|
caption: title,
|
|
detach: true,
|
|
cascade: true,
|
|
translate: false,
|
|
uniqueid: "info:" + uid,
|
|
alignment: 7,
|
|
width: 450,
|
|
height: 550,
|
|
params: {
|
|
contact: uid
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function updateViewInfoAnP(uid) {
|
|
var window = findWindow("info:" + uid);
|
|
if (window) window.root.ns.updateAvatarAndPhoto();
|
|
}
|
|
|
|
function updateDB() {
|
|
var window = findWindow(#db);
|
|
if (window) window.root.ns.updateList();
|
|
}
|
|
|
|
function openContactsDB() {
|
|
openSingleWindow({
|
|
url: "contactsdb.htm",
|
|
caption: CommonNative.GetTranslation("Contacts database"),
|
|
detach: true,
|
|
uniqueid: #db,
|
|
alignment: 5,
|
|
width: 850,
|
|
height: 500
|
|
});
|
|
}
|
|
|
|
function openAbout() {
|
|
openSingleWindow({
|
|
url: "about.htm",
|
|
caption: "About",
|
|
detach: true,
|
|
uniqueid: #about,
|
|
alignment: 5,
|
|
width: 310,
|
|
height: 265
|
|
});
|
|
}
|
|
|
|
function openHistorySearch(uid = null, displayed = null) {
|
|
var (px, py, dw, dh) = view.screenBox(#frame, #rectw);
|
|
var window = openSingleWindow({
|
|
url: "search.htm",
|
|
caption: "History search",
|
|
detach: true,
|
|
uniqueid: #search,
|
|
alignment: 5,
|
|
width: dw / 3,
|
|
height: dh / 1.5
|
|
});
|
|
if (window) window.root.ns.refreshState({
|
|
UID: uid,
|
|
Display: displayed,
|
|
RowID: -1
|
|
});
|
|
}
|
|
|
|
function openOutbox() {
|
|
var (px, py, dw, dh) = view.screenBox(#frame, #rectw);
|
|
openSingleWindow({
|
|
url: "outbox.htm",
|
|
caption: "Outbox",
|
|
detach: true,
|
|
uniqueid: #outbox,
|
|
alignment: 5,
|
|
width: dw / 2.5,
|
|
height: dh / 2.2
|
|
});
|
|
}
|
|
|
|
function updateOutbox() {
|
|
var window = findWindow(#outbox);
|
|
if (window) {
|
|
window.root.ns.updateList(true);
|
|
window.root.ns.updateText();
|
|
}
|
|
}
|
|
|
|
function openUpdater() {
|
|
openSingleWindow({
|
|
url: "updater.htm",
|
|
caption: CommonNative.GetTranslation("Check for updates"),
|
|
detach: true,
|
|
uniqueid: #updater,
|
|
alignment: 5
|
|
});
|
|
}
|
|
|
|
function openLangs(langs) {
|
|
return openSingleWindow({
|
|
url: "langs.htm",
|
|
caption: CommonNative.GetTranslation("Select a language"),
|
|
uniqueid: #langs,
|
|
dialog: true;
|
|
alignment: 5,
|
|
width: 450,
|
|
height: 310,
|
|
params: {
|
|
langs: langs
|
|
}
|
|
});
|
|
}
|
|
|
|
function openUINList(caption, btn, options, uid = "") {
|
|
options = options ?? [];
|
|
return openSingleWindow({
|
|
url: "uinlist.htm",
|
|
caption: "Select contacts",
|
|
uniqueid: #uinlist,
|
|
dialog: true,
|
|
alignment: 5,
|
|
width: 250,
|
|
height: options.indexOf(#sco_predefined) >= 0 ? 500 : 400,
|
|
params: {
|
|
caption: CommonNative.GetTranslation(caption),
|
|
btn: CommonNative.GetTranslation(btn),
|
|
options: options,
|
|
uid: uid
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateUINList(record) {
|
|
var window = findWindow(#uinlist);
|
|
if (window) window.root.ns.updateContact(uin, status);
|
|
}
|
|
|
|
function openTextWindow(id, title, body, wrap = true, images = [], formicon = null) {
|
|
var (px, py, dw, dh) = view.screenBox(#frame, #rectw);
|
|
openSingleWindow({
|
|
url: "window.htm",
|
|
caption: title,
|
|
detach: true,
|
|
cascade: true,
|
|
translate: false,
|
|
uniqueid: "message:" + id,
|
|
alignment: 7,
|
|
width: dw/2.5,
|
|
height: dh/2.5,
|
|
params: {
|
|
body: body,
|
|
wrap: wrap,
|
|
images: images,
|
|
formicon: formicon,
|
|
}
|
|
});
|
|
}
|
|
|
|
function openTextEdit(text) {
|
|
var (px, py, dw, dh) = view.screenBox(#frame, #rectw);
|
|
return openSingleWindow({
|
|
url: "textedit.htm",
|
|
caption: "Edit message",
|
|
dialog: true,
|
|
uniqueid: "message:" + id,
|
|
alignment: 5,
|
|
width: dw/4,
|
|
height: dh/4,
|
|
params: {
|
|
text: text
|
|
}
|
|
});
|
|
}
|
|
|
|
function openPrefs(page = '', full = true) {
|
|
var (px, py, dw, dh) = view.screenBox(#frame, #rectw);
|
|
var window = openSingleWindow({
|
|
url: "preferences.htm",
|
|
caption: "Preferences",
|
|
hidden: true,
|
|
detach: true,
|
|
uniqueid: #prefs,
|
|
alignment: 5,
|
|
width: dw / 2.2,
|
|
height: dh / 2.2
|
|
});
|
|
window.root.ns.setViewMode(page, full);
|
|
}
|
|
|
|
function closeChildWindows() {
|
|
for (var window in View.all)
|
|
if (window.uniqueid != #main && window.uniqueid != #chat && window.uniqueid != #users) window.close();
|
|
}
|
|
|
|
// function autosizeWindow() {
|
|
// self.post(:{
|
|
// var (x, y, w, h) = view.box(#rectw, #client, #screen);
|
|
// view.windowMove(x, y, w, $(body).box(#height, #margin), true);
|
|
// });
|
|
// }
|
|
|
|
// function coordScreenToView(x, y) {
|
|
// var (vx, vy) = view.box(#position, #client, #screen);
|
|
// x -= vx;
|
|
// y -= vy;
|
|
// return (x, y);
|
|
// }
|
|
|
|
function coordViewToScreen(x, y) {
|
|
var (vx, vy) = view.box(#position, #client, #screen);
|
|
x += vx;
|
|
y += vy;
|
|
return (x, y);
|
|
}
|
|
|
|
function getScreenFromCoord(x, y) {
|
|
for (var scr in view.screens) {
|
|
var (x1, y1, x2, y2) = view.screenBox(scr, #frame, #rect);
|
|
if (x >= x1 && x <= x2 && y >= y1 && y <= y2) return scr;
|
|
}
|
|
return view.screen;
|
|
}
|
|
|
|
function getPopupPosition(x, y, size, hgap = 0, vgap = 0) {
|
|
var (sx, sy, sw, sh) = view.screenBox(#frame, #rectw);
|
|
var (x2, y2) = coordViewToScreen(x, y);
|
|
var overw = x2 + size > sx + sw;
|
|
var overh = y2 + size > sy + sh;
|
|
if (overw && overh)
|
|
return (3, x - hgap, y - vgap);
|
|
else if (overw)
|
|
return (9, x - hgap, y + vgap * 2);
|
|
else if (overh)
|
|
return (1, x + hgap, y - vgap);
|
|
else
|
|
return (7, x + hgap, y + vgap * 2);
|
|
}
|
|
|
|
var hint = self.$append(<popup id="hint"></popup>),
|
|
hintAncor = null,
|
|
hintData = null,
|
|
hintX = -1,
|
|
hintY = -1;
|
|
|
|
function prepareHint() {
|
|
function checkField(field) {
|
|
return field != "" ? <b>{field}</b> : {CommonNative.GetTranslation("Unknown")}>;
|
|
}
|
|
|
|
if (hintData instanceof String) hintData = CommonNative.GetContactData(hintData);
|
|
|
|
if (hintData.kind == NODE_GROUP && cldata) {
|
|
var total = cldata.getTotalGroupCount(hintData.group);
|
|
var onoffline = [];
|
|
if (CommonNative.IsOnline()) {
|
|
var online = cldata.getGroupCount(hintData.group, 0);
|
|
var offline = cldata.getGroupCount(hintData.group, 1) + cldata.getGroupCount(hintData.group, 4);
|
|
var unknown = cldata.getGroupCount(hintData.group, 2) + cldata.getGroupCount(hintData.group, 3);
|
|
onoffline.push(<div key="hintonline">{CommonNative.GetTranslation("Online")}: <b>{online}</b></div>);
|
|
onoffline.push(<div key="hintoffline">{CommonNative.GetTranslation("Offline")}: <b>{offline}</b></div>);
|
|
onoffline.push(<div key="hintunknown">{CommonNative.GetTranslation("Unknown")}: <b>{unknown}</b></div>);
|
|
}
|
|
|
|
hint.merge(<popup id="hint">
|
|
<div key="hinttotal">{CommonNative.GetTranslation("Total")}: <b>{total}</b></div>
|
|
{onoffline}
|
|
</popup>);
|
|
return;
|
|
}
|
|
|
|
if (hintData.kind != NODE_CONTACT) return;
|
|
|
|
var texts = {
|
|
hintstatusmsg: "Message",
|
|
hintidle: "Idle time",
|
|
hintimportant: "Important",
|
|
hintofficial: "Official contact",
|
|
hintbot: "Bot contact",
|
|
hintbirth: "Birthday",
|
|
hintgroup: "Group",
|
|
hintnoclient: "Client was closed",
|
|
hintclientdesc: "Client",
|
|
hintclientonline: "Online since",
|
|
hintclientoffline: "Last time seen online",
|
|
hintignored: "Being ignored",
|
|
hintauth: "Authorization required",
|
|
hintstatus: "Status",
|
|
hintxstatus: "XStatus",
|
|
hintnick: "Nick",
|
|
hintfirst: "First name",
|
|
hintlast: "Last name"
|
|
};
|
|
var ttexts = CommonNative.GetTranslations(texts);
|
|
|
|
var desc = [];
|
|
if (hintData.status.desc != "")
|
|
desc = <div key="hintstatusmsg">{ttexts["hintstatusmsg"]}: <span class="limited"><b>{hintData.status.desc}</b></span></div>;
|
|
|
|
var idle = [];
|
|
var idleTime = CommonNative.GetContactIdle(hintData.uid);
|
|
if (idleTime > 0)
|
|
idle = <div key="hintidle">{ttexts["hintidle"]}: <b>{String.printf("%d:%02d", (idleTime % 3600) / 60, idleTime % 60)}</b></div>;
|
|
|
|
var important = [];
|
|
var importantText = CommonNative.GetContactImportant(hintData.uid, false);
|
|
if (importantText != "")
|
|
important = <div key="hintimportant">{ttexts["hintimportant"]}: <span class="limited"><b>{importantText}</b></span></div>;
|
|
|
|
var importantLocal = [];
|
|
importantText = CommonNative.GetContactImportant(hintData.uid, true);
|
|
if (importantText != "")
|
|
importantLocal = <div key="hintimportantlocal">{ttexts["hintimportant"]}: <span class="limited"><b>{importantText}</b></span></div>;
|
|
|
|
var official = [];
|
|
if (hintData.status.official)
|
|
official = <div key="hintofficial"><b>{ttexts["hintofficial"]}</b></div>;
|
|
|
|
var bot = [];
|
|
if (hintData.status.bot)
|
|
bot = <div key="hintbot"><b>{ttexts["hintbot"]}</b></div>;
|
|
|
|
var birth = [];
|
|
if (hintData.birthLocal != '')
|
|
birth = <div key="hintbirth">{ttexts["hintbirth"]}: <b>{hintData.birthLocal}</b></div>;
|
|
// else if (hintData.birth != '')
|
|
// birth = |
|
|
|
var group = [];
|
|
var groupName = CommonNative.GetGroupName(hintData.group);
|
|
if (groupName != "")
|
|
group = <div key="hintgroup">{ttexts["hintgroup"]}: <b>{groupName}</b></div>;
|
|
|
|
var noClient = [];
|
|
if (hintData.noClient)
|
|
noClient = <div key="hintnoclient">{ttexts["hintnoclient"]}: <b>{hintData.clientClosed}</b></div>;
|
|
|
|
var client = [];
|
|
if (hintData.status.code != 1 && hintData.status.code != 2) { // is online
|
|
if (hintData.clientDesc != "")
|
|
client.push(<div key="hintclientdesc">{ttexts["hintclientdesc"]}: <b>{hintData.clientDesc}</b></div>);
|
|
if (hintData.onlineSince != "")
|
|
client.push(<div key="hintclientonline">{ttexts["hintclientonline"]}: <b>{hintData.onlineSince}</b></div>);
|
|
} else {
|
|
if (hintData.lastTimeSeenOnline != "")
|
|
client.push(<div key="hintclientoffline">{ttexts["hintclientoffline"]}: <b>{hintData.lastTimeSeenOnline}</b></div>);
|
|
}
|
|
|
|
var ignored = [];
|
|
var isIgnored = CommonNative.GetContactIgnored(hintData.uid);
|
|
if (isIgnored)
|
|
ignored = <div key="hintignored"><b>{ttexts["hintignored"]}</b></div>;
|
|
|
|
var needAuth = [];
|
|
if (hintData.needAuth)
|
|
needAuth = <div key="hintauth"><b>{ttexts["hintauth"]}</b></div>;
|
|
|
|
var avatar = [];
|
|
if (View.commonSettings.supportAvatars && View.commonSettings.avatarShowInHint && hintData.hasAvatar)
|
|
avatar = <div key="hintavatar" class="hintheader2"><img src={String.$(miniavatar:{hintData.uid})} /></div>;
|
|
|
|
var xstatus = [];
|
|
var xstatustext = [];
|
|
if (hintData.xstatus.status != "") {
|
|
xstatus = <span key="xstatus" class="xstatus">{hintData.xstatus.status}</span>;
|
|
xstatustext = <div key="hintxstatus">{ttexts["hintxstatus"]}: <b>{hintData.xstatus.text}</b></div>
|
|
}
|
|
|
|
hint.merge(<popup id="hint">
|
|
<div class="hintheader">
|
|
<div class="hintheader1">
|
|
<div><div id="hinticon"></div>{xstatus}<span>UIN </span><span key="hintuin"><b>{hintData.uid2show}</b></span></div>
|
|
<div key="hintstatus">{ttexts["hintstatus"]}: <b>{hintData.status.name}</b></div>
|
|
{xstatustext}
|
|
</div>
|
|
{avatar}
|
|
</div>
|
|
{desc}
|
|
{idle}
|
|
<hr/>
|
|
{important}
|
|
{importantLocal}
|
|
{official}
|
|
{bot}
|
|
<div key="hintnick">{ttexts["hintnick"]}: {checkField(hintData.nick)}</div>
|
|
<div key="hintfirst">{ttexts["hintfirst"]}: {checkField(hintData.first)}</div>
|
|
<div key="hintlast">{ttexts["hintlast"]}: {checkField(hintData.last)}</div>
|
|
{birth}
|
|
{group}
|
|
{noClient}
|
|
{client}
|
|
{ignored}
|
|
{needAuth}
|
|
</popup>);
|
|
hint.$(#hinticon).applySprite(hintData.status.statusimg);
|
|
hint.$(#hinticon).update();
|
|
}
|
|
|
|
function showHintFunc() {
|
|
if (!hintAncor || !hintAncor.tag || self.state.ownspopup) return;
|
|
if (self.view.uniqueid != #main) { // check for menu in main
|
|
var main = findWindow(#main);
|
|
if (main && main.root.state.ownspopup) return;
|
|
}
|
|
|
|
var gap = 0;
|
|
if (hintX == -1 && hintY == -1) {
|
|
(hintX, hintY) = view.cursorLocation();
|
|
gap = self.toPixels(10dip)
|
|
}
|
|
prepareHint();
|
|
var pos = 7;
|
|
if (hintData.kind == NODE_CONTACT) {
|
|
(pos, hintX, hintY) = getPopupPosition(hintX, hintY, self.toPixels(200dip), gap, gap);
|
|
} else {
|
|
hintX += gap;
|
|
hintY += gap;
|
|
}
|
|
|
|
hintAncor.popup(hint, pos, hintX, hintY);
|
|
}
|
|
|
|
function showHint(ancor, data, x = -1, y = -1) {
|
|
self.timer(0, hideHint);
|
|
var wasPresent = hint.state.popup;
|
|
hideHint();
|
|
hintAncor = ancor;
|
|
hintData = data;
|
|
hintX = x;
|
|
hintY = y;
|
|
var delay = wasPresent ? 100 : 1000;
|
|
self.timer(delay, showHintFunc);
|
|
}
|
|
|
|
function hideHint() {
|
|
self.timer(0, showHintFunc);
|
|
hintX = -1;
|
|
hintY = -1;
|
|
hint.closePopup();
|
|
hint.update();
|
|
}
|
|
|
|
function showSelectPopup(el) {
|
|
var cur = el.$(option:current);
|
|
if (!cur) cur = el.$(option);
|
|
if (!cur) return;
|
|
el.popup(
|
|
el.$(popup),
|
|
el.box(#left, #border, #root),
|
|
el.box(#top, #border, #root) - el.$(popup).style#padding-top
|
|
- (cur.style#line-height + cur.style#padding-top + cur.style#padding-bottom) * cur.index - 1
|
|
);
|
|
el.$(popup).state.focus = true;
|
|
}
|
|
|
|
function initUWPSelect(editable = false) {
|
|
var body = $(body);
|
|
|
|
body.on("~keydown", "select:not([type]):not([default])", :e {
|
|
if (e.target.tag == "select" &&
|
|
(e.keyCode == Event.VK_RETURN || e.keyCode == Event.VK_SPACE)) {
|
|
showSelectPopup(this);
|
|
return true;
|
|
}
|
|
});
|
|
|
|
body.on("~mousedown", "select:not([type]):not([default])", :e {
|
|
if (editable && e.target.tag == "caption") return false;
|
|
if (e.target.tag !== "option") return true;
|
|
});
|
|
|
|
body.on("~mouseup", "select:not([type]):not([default])", :e {
|
|
if (editable && e.target.tag == "caption") return false;
|
|
if (e.target.tag !== "option") {
|
|
showSelectPopup(this);
|
|
return true;
|
|
} else {
|
|
this.$(popup).closePopup();
|
|
}
|
|
});
|
|
|
|
body.subscribe(:e {
|
|
if (e.target.$p(select:not([type]):not([default]))) return true;
|
|
}, Event.BEHAVIOR_EVENT, Event.BUTTON_PRESS | Event.SINKING);
|
|
}
|
|
|
|
function cubicOut(t, b = 0.0, c = 1.0, d = 1.0) {
|
|
return c*((t=t/d-1)*t*t + 1) + b;
|
|
}
|
|
|
|
function String.toLocalPath() {
|
|
return URL.toPath(this).replace("/", "\\");
|
|
}
|
|
|
|
function Element.setVisible(vis, update = true) {
|
|
this.style#display = vis ? undefined : "none";
|
|
if (update) this.update();
|
|
}
|
|
|
|
function Element.reloadImage(url, cache = true) {
|
|
var target = this.tag ? this.view.root : findWindow(#chat).root;
|
|
if (target && url)
|
|
target.loadImage(url, :image {
|
|
target.bindImage(url, image);
|
|
}, cache);
|
|
}
|
|
|
|
function Element.applySprite(pic, cat = #theme) {
|
|
if (cat == #plugin) this.reloadImage("pluginpic:" + pic["name"], false);
|
|
if (pic) this.style.set({
|
|
background-image: [url: (cat == #plugin ? "pluginpic:" : "themepic:") + pic["name"]],
|
|
background-position: [px(pic["x"]), px(pic["y"])],
|
|
width: px(pic["width"]),
|
|
height: px(pic["height"])
|
|
});
|
|
}
|
|
|
|
function Element.clearSprite() {
|
|
this.style.set({
|
|
background-image: "none",
|
|
width: "auto",
|
|
height: "auto"
|
|
});
|
|
}
|
|
|
|
function makeSpriteStyle(pic) {
|
|
return {
|
|
background-image: [url: "themepic:" + pic["name"]],
|
|
background-position: [px(pic["x"]), px(pic["y"])],
|
|
width: px(pic["width"]),
|
|
height: px(pic["height"])
|
|
}
|
|
}
|
|
|
|
function Function.throttle(milliseconds, options = {}) {
|
|
milliseconds = milliseconds.toInteger();
|
|
var context, args, result;
|
|
var running = false;
|
|
var previous = options.leading === false ? 0 : Date.ticks() - milliseconds - 1;
|
|
var func = this;
|
|
function later() {
|
|
previous = options.leading === false ? 0 : Date.ticks();
|
|
running = false;
|
|
result = func.apply(context, args);
|
|
};
|
|
return function(arguments..) {
|
|
var now = Date.ticks();
|
|
if (!previous && options.leading === false) previous = now;
|
|
var remaining = milliseconds - (now - previous);
|
|
context = this;
|
|
args = arguments;
|
|
if (remaining <= 0) {
|
|
self.timer(0,later,true);
|
|
running = false;
|
|
previous = now;
|
|
result = func.apply(context, args);
|
|
} else if (!running && options.trailing !== false) {
|
|
running = true;
|
|
self.timer(remaining, later,true);
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
</script> |