diff options
Diffstat (limited to 'js/common.js')
-rwxr-xr-x | js/common.js | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/js/common.js b/js/common.js new file mode 100755 index 000000000..427e3034c --- /dev/null +++ b/js/common.js @@ -0,0 +1,311 @@ +'use strict' +/* global dijit, __ */ + +let _label_base_index = -1024; +let loading_progress = 0; + +/* error reporting shim */ + +// TODO: deprecated; remove +function exception_error(e, e_compat, filename, lineno, colno) { + if (typeof e == "string") + e = e_compat; + + App.Error.report(e, {filename: filename, lineno: lineno, colno: colno}); +} + +/* xhr shorthand helpers */ + +function xhrPost(url, params, complete) { + console.log("xhrPost:", params); + return new Ajax.Request(url, { + parameters: params, + onComplete: complete + }); +} + +function xhrJson(url, params, complete) { + return xhrPost(url, params, (reply) => { + try { + const obj = JSON.parse(reply.responseText); + complete(obj); + } catch (e) { + console.error("xhrJson", e, reply); + complete(null); + } + + }) +} + +/* add method to remove element from array */ +Array.prototype.remove = function(s) { + for (let i=0; i < this.length; i++) { + if (s == this[i]) this.splice(i, 1); + } +}; + +/* common helpers not worthy of separate Dojo modules */ + +const Lists = { + onRowChecked: function(elem) { + const checked = elem.domNode ? elem.attr("checked") : elem.checked; + // account for dojo checkboxes + elem = elem.domNode || elem; + + const row = elem.up("li"); + + if (row) + checked ? row.addClassName("Selected") : row.removeClassName("Selected"); + } +}; + +// noinspection JSUnusedGlobalSymbols +const Tables = { + onRowChecked: function(elem) { + // account for dojo checkboxes + const checked = elem.domNode ? elem.attr("checked") : elem.checked; + elem = elem.domNode || elem; + + const row = elem.up("tr"); + + if (row) + checked ? row.addClassName("Selected") : row.removeClassName("Selected"); + + }, + select: function(elemId, selected) { + $(elemId).select("tr").each((row) => { + const checkNode = row.select(".dijitCheckBox,input[type=checkbox]")[0]; + if (checkNode) { + const widget = dijit.getEnclosingWidget(checkNode); + + if (widget) { + widget.attr("checked", selected); + } else { + checkNode.checked = selected; + } + + this.onRowChecked(widget); + } + }); + }, + getSelected: function(elemId) { + const rv = []; + + $(elemId).select("tr").each((row) => { + if (row.hasClassName("Selected")) { + // either older prefix-XXX notation or separate attribute + const rowId = row.getAttribute("data-row-id") || row.id.replace(/^[A-Z]*?-/, ""); + + if (!isNaN(rowId)) + rv.push(parseInt(rowId)); + } + }); + + return rv; + } +}; + +const Cookie = { + set: function (name, value, lifetime) { + const d = new Date(); + d.setTime(d.getTime() + lifetime * 1000); + const expires = "expires=" + d.toUTCString(); + document.cookie = name + "=" + encodeURIComponent(value) + "; " + expires; + }, + get: function (name) { + name = name + "="; + const ca = document.cookie.split(';'); + for (let i=0; i < ca.length; i++) { + let c = ca[i]; + while (c.charAt(0) == ' ') c = c.substring(1); + if (c.indexOf(name) == 0) return decodeURIComponent(c.substring(name.length, c.length)); + } + return ""; + }, + delete: function(name) { + const expires = "expires=Thu, 01-Jan-1970 00:00:01 GMT"; + document.cookie = name + "=" + "" + "; " + expires; + } +}; + +/* runtime notifications */ + +const Notify = { + KIND_GENERIC: 0, + KIND_INFO: 1, + KIND_ERROR: 2, + KIND_PROGRESS: 3, + timeout: 0, + default_timeout: 5 * 1000, + close: function() { + this.msg(""); + }, + msg: function(msg, keep, kind) { + kind = kind || this.KIND_GENERIC; + keep = keep || false; + + const notify = $("notify"); + + window.clearTimeout(this.timeout); + + if (!msg) { + notify.removeClassName("visible"); + return; + } + + let msgfmt = "<span class=\"msg\">%s</span>".replace("%s", __(msg)); + let icon = false; + + + notify.className = "notify"; + + console.warn('notify', msg, kind); + + switch (kind) { + case this.KIND_INFO: + notify.addClassName("notify_info") + icon = App.getInitParam("icon_information"); + break; + case this.KIND_ERROR: + notify.addClassName("notify_error"); + icon = App.getInitParam("icon_alert"); + break; + case this.KIND_PROGRESS: + notify.addClassName("notify_progress"); + icon = App.getInitParam("icon_indicator_white") + break; + } + + if (icon) msgfmt = "<span><img src=\"%s\"></span>".replace("%s", icon) + msgfmt; + + msgfmt += (" <span><img src=\"%s\" class='close' title=\"" + + __("Click to close") + "\" onclick=\"Notify.close()\"></span>") + .replace("%s", App.getInitParam("icon_cross")); + + notify.innerHTML = msgfmt; + notify.addClassName("visible"); + + if (!keep) + this.timeout = window.setTimeout(() => { + notify.removeClassName("visible"); + }, this.default_timeout); + + }, + info: function(msg, keep) { + keep = keep || false; + this.msg(msg, keep, this.KIND_INFO); + }, + progress: function(msg, keep) { + keep = keep || true; + this.msg(msg, keep, this.KIND_PROGRESS); + }, + error: function(msg, keep) { + keep = keep || true; + this.msg(msg, keep, this.KIND_ERROR); + } +}; + +// noinspection JSUnusedGlobalSymbols +function displayIfChecked(checkbox, elemId) { + if (checkbox.checked) { + Effect.Appear(elemId, {duration : 0.5}); + } else { + Effect.Fade(elemId, {duration : 0.5}); + } +} + +function fatalError(code, msg, ext_info) { + if (code == 6) { + window.location.href = "index.php"; + } else if (code == 5) { + window.location.href = "public.php?op=dbupdate"; + } else { + + if (msg == "") msg = "Unknown error"; + + if (ext_info) { + if (ext_info.responseText) { + ext_info = ext_info.responseText; + } + } + + /* global ERRORS */ + if (ERRORS && ERRORS[code] && !msg) { + msg = ERRORS[code]; + } + + let content = "<div><b>Error code:</b> " + code + "</div>" + + "<p>" + msg + "</p>"; + + if (ext_info) { + content = content + "<div><b>Additional information:</b></div>" + + "<textarea style='width: 100%' readonly=\"1\">" + + ext_info + "</textarea>"; + } + + const dialog = new dijit.Dialog({ + title: "Fatal error", + style: "width: 600px", + content: content}); + + dialog.show(); + + } + + return false; + +} + +/* function strip_tags(s) { + return s.replace(/<\/?[^>]+(>|$)/g, ""); +} */ + +// noinspection JSUnusedGlobalSymbols +function label_to_feed_id(label) { + return _label_base_index - 1 - Math.abs(label); +} + +// noinspection JSUnusedGlobalSymbols +function feed_to_label_id(feed) { + return _label_base_index - 1 + Math.abs(feed); +} + +// http://stackoverflow.com/questions/6251937/how-to-get-selecteduser-highlighted-text-in-contenteditable-element-and-replac +function getSelectionText() { + let text = ""; + + if (typeof window.getSelection != "undefined") { + const sel = window.getSelection(); + if (sel.rangeCount) { + const container = document.createElement("div"); + for (let i = 0, len = sel.rangeCount; i < len; ++i) { + container.appendChild(sel.getRangeAt(i).cloneContents()); + } + text = container.innerHTML; + } + } else if (typeof document.selection != "undefined") { + if (document.selection.type == "Text") { + text = document.selection.createRange().textText; + } + } + + return text.stripTags(); +} + +// noinspection JSUnusedGlobalSymbols +function popupOpenUrl(url) { + const w = window.open(""); + + w.opener = null; + w.location = url; +} + +// noinspection JSUnusedGlobalSymbols +function popupOpenArticle(id) { + const w = window.open("", + "ttrss_article_popup", + "height=900,width=900,resizable=yes,status=no,location=no,menubar=no,directories=no,scrollbars=yes,toolbar=no"); + + w.opener = null; + w.location = "backend.php?op=article&method=view&mode=raw&html=1&zoom=1&id=" + id + "&csrf_token=" + App.getInitParam("csrf_token"); +} |