From 70fa4230268a422d0b7eef1ea223ca5cc1c14646 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Thu, 18 Feb 2021 21:51:18 +0300 Subject: [PATCH] initial for RIP prototype/scriptaculous --- classes/handler/public.php | 5 +- classes/pref/prefs.php | 2 +- index.php | 3 +- js/App.js | 75 +- js/Article.js | 36 +- js/CommonDialogs.js | 20 +- js/CommonFilters.js | 22 +- js/FeedTree.js | 4 +- js/Feeds.js | 20 +- js/Headlines.js | 171 +++-- js/PrefFeedTree.js | 10 +- js/PrefFilterTree.js | 4 +- js/PrefHelpers.js | 10 +- js/PrefLabelTree.js | 4 +- js/PrefUsers.js | 2 +- js/common.js | 133 +++- js/tt-rss.js | 15 +- js/utility.js | 2 +- lib/scriptaculous/controls.js | 965 ------------------------ lib/scriptaculous/effects.js | 1123 ---------------------------- lib/scriptaculous/scriptaculous.js | 68 -- plugins/af_readability/init.js | 4 +- plugins/af_zz_vidmute/init.js | 4 +- plugins/share/share.js | 3 - plugins/shorten_expanded/init.js | 4 +- prefs.php | 3 +- 26 files changed, 318 insertions(+), 2394 deletions(-) delete mode 100644 lib/scriptaculous/controls.js delete mode 100644 lib/scriptaculous/effects.js delete mode 100644 lib/scriptaculous/scriptaculous.js diff --git a/classes/handler/public.php b/classes/handler/public.php index b810019c1..80c1c271d 100755 --- a/classes/handler/public.php +++ b/classes/handler/public.php @@ -362,7 +362,6 @@ class Handler_Public extends Handler { echo javascript_tag("lib/dojo/dojo.js"); echo javascript_tag("js/utility.js"); echo javascript_tag("lib/dojo/tt-rss-layer.js"); - echo javascript_tag("lib/scriptaculous/scriptaculous.js?load=effects,controls") ?> @@ -388,10 +387,10 @@ class Handler_Public extends Handler { ready(function() { parser.parse(); - new Ajax.Autocompleter('labels_value', 'labels_choices', + /* new Ajax.Autocompleter('labels_value', 'labels_choices', "backend.php?op=rpc&method=completeLabels", { tokens: ',', paramName: "search" }); - }); + }); */ }); } }; diff --git a/classes/pref/prefs.php b/classes/pref/prefs.php index b760affa0..cfbf83d2a 100644 --- a/classes/pref/prefs.php +++ b/classes/pref/prefs.php @@ -366,7 +366,7 @@ class Pref_Prefs extends Handler_Protected { if (warn) Element.hide(warn); } - new Effect.Appear('pwd_change_infobox'); + Element.show('pwd_change_infobox'); }) } diff --git a/index.php b/index.php index d53fb54a8..4a4d336ca 100644 --- a/index.php +++ b/index.php @@ -76,8 +76,7 @@ { - this.nightModeChanged(mql.matches, $("theme_auto_css")); + this.nightModeChanged(mql.matches, App.byId("theme_auto_css")); }); } catch (e) { console.warn("exception while trying to set MQL event listener"); } - const link = new Element("link", { - rel: "stylesheet", - id: "theme_auto_css" - }); + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.id = "theme_auto_css"; if (callback) { link.onload = function() { @@ -176,7 +184,7 @@ const App = { if (callback) callback(); } }, - enableCsrfSupport: function() { + /*enableCsrfSupport: function() { const _this = this; Ajax.Base.prototype.initialize = Ajax.Base.prototype.initialize.wrap( @@ -196,7 +204,7 @@ const App = { return callOriginal(options); } ); - }, + }, */ postCurrentWindow: function(target, params) { const form = document.createElement("form"); @@ -245,8 +253,13 @@ const App = { } }, - urlParam: function(param) { - return String(window.location.href).parseQuery()[param]; + urlParam: function(name) { + try { + const results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); + return decodeURIComponent(results[1].replace(/\+/g, " ")) || 0; + } catch (e) { + return 0; + } }, next_seq: function() { this._rpc_seq += 1; @@ -262,7 +275,7 @@ const App = { dijit.byId("loading_bar").update({progress: this._loading_progress}); if (this._loading_progress >= 90) { - $("overlay").hide(); + App.byId("overlay").hide(); } }, @@ -293,7 +306,7 @@ const App = { if (!this.hotkey_prefix && hotkeys_map[0].indexOf(keychar) != -1) { this.hotkey_prefix = keychar; - $("cmdline").innerHTML = keychar; + App.byId("cmdline").innerHTML = keychar; Element.show("cmdline"); window.clearTimeout(this.hotkey_prefix_timeout); @@ -342,11 +355,11 @@ const App = { cleanupMemory: function(root) { const dijits = dojo.query("[widgetid]", dijit.byId(root).domNode).map(dijit.byNode); - dijits.each(function (d) { + dijits.forEach(function (d) { dojo.destroy(d.domNode); }); - $$("#" + root + " *").each(function (i) { + App.findAll("#" + root + " *").forEach(function (i) { i.parentNode ? i.parentNode.removeChild(i) : true; }); }, @@ -364,9 +377,9 @@ const App = { }, displayIfChecked: function(checkbox, elemId) { if (checkbox.checked) { - Effect.Appear(elemId, {duration : 0.5}); + Element.show(elemId); } else { - Effect.Fade(elemId, {duration : 0.5}); + Element.hide(elemId); } }, hotkeyHelp: function() { @@ -381,7 +394,7 @@ const App = { }, handleRpcJson: function(transport) { - const netalert = $$("#toolbar .net-alert")[0]; + const netalert = App.findAll("#toolbar .net-alert")[0]; try { const reply = JSON.parse(transport.responseText); @@ -459,7 +472,7 @@ const App = { } if (k == "recent_log_events") { - const alert = $$(".log-alert")[0]; + const alert = App.findAll(".log-alert")[0]; if (alert) { v > 0 ? alert.show() : alert.hide(); @@ -516,7 +529,7 @@ const App = { break; case "cdm_auto_catchup": if (params[k] == 1) { - const hl = $("headlines-frame"); + const hl = App.byId("headlines-frame"); if (hl) hl.addClassName("auto_catchup"); } break; @@ -562,7 +575,7 @@ const App = { } return this.report(error, - Object.extend({title: __("Fatal error")}, params)); + {...{title: __("Fatal error")}, ...params}); }, report: function(error, params = {}) { if (!error) return; @@ -650,7 +663,7 @@ const App = { this.setLoadingProgress(30); this.initHotkeyActions(); - this.enableCsrfSupport(); + //this.enableCsrfSupport(); const params = { op: "rpc", @@ -671,7 +684,7 @@ const App = { checkBrowserFeatures: function() { let errorMsg = ""; - ['MutationObserver'].each(function(wf) { + ['MutationObserver'].forEach(function(wf) { if (!(wf in window)) { errorMsg = `Browser feature check failed: window.${wf} not found.`; throw new Error(errorMsg); @@ -794,9 +807,9 @@ const App = { console.log('update reply', reply); if (reply.id) { - $("updates-available").show(); + App.byId("updates-available").show(); } else { - $("updates-available").hide(); + App.byId("updates-available").hide(); } }); }, @@ -812,7 +825,7 @@ const App = { onViewModeChanged: function() { const view_mode = document.forms["toolbar-main"].view_mode.value; - $$("body")[0].setAttribute("view-mode", view_mode); + App.findAll("body")[0].setAttribute("view-mode", view_mode); return Feeds.reloadCurrent(''); }, @@ -851,8 +864,8 @@ const App = { {width: Cookie.get("ttrss_ci_width") + "px" }); } - $("headlines-frame").setStyle({ borderBottomWidth: '0px' }); - $("headlines-frame").addClassName("wide"); + App.byId("headlines-frame").setStyle({ borderBottomWidth: '0px' }); + App.byId("headlines-frame").addClassName("wide"); } else { @@ -867,8 +880,8 @@ const App = { {height: Cookie.get("ttrss_ci_height") + "px" }); } - $("headlines-frame").setStyle({ borderBottomWidth: '1px' }); - $("headlines-frame").removeClassName("wide"); + App.byId("headlines-frame").setStyle({ borderBottomWidth: '1px' }); + App.byId("headlines-frame").removeClassName("wide"); } @@ -1107,7 +1120,7 @@ const App = { this.hotkey_actions["select_article_cursor"] = () => { const id = Article.getUnderPointer(); if (id) { - const row = $("RROW-" + id); + const row = App.byId("RROW-" + id); if (row) row.toggleClassName("Selected"); @@ -1234,7 +1247,7 @@ const App = { } break; case "qmcHKhelp": - this.hotkeyHelp(); + this.helpDialog("main"); break; default: console.log("quickMenuGo: unknown action: " + opid); diff --git a/js/Article.js b/js/Article.js index 81917fd47..e7498f0b3 100644 --- a/js/Article.js +++ b/js/Article.js @@ -36,19 +36,19 @@ const Article = { const score = prompt(__("Please enter new score for selected articles:")); if (!isNaN(parseInt(score))) { - ids.each((id) => { - const row = $("RROW-" + id); + ids.forEach((id) => { + const row = App.byId("RROW-" + id); if (row) { row.setAttribute("data-score", score); - const pic = row.select(".icon-score")[0]; + const pic = row.querySelector(".icon-score"); pic.innerHTML = Article.getScorePic(score); pic.setAttribute("title", score); ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"] - .each(function(scl) { + .forEach(function(scl) { if (row.hasClassName(scl)) row.removeClassName(scl); }); @@ -72,13 +72,13 @@ const Article = { if (!isNaN(parseInt(score))) { row.setAttribute("data-score", score); - const pic = row.select(".icon-score")[0]; + const pic = row.querySelector(".icon-score"); pic.innerHTML = Article.getScorePic(score); pic.setAttribute("title", score); ["score-low", "score-high", "score-half-low", "score-half-high", "score-neutral"] - .each(function(scl) { + .forEach(function(scl) { if (row.hasClassName(scl)) row.removeClassName(scl); }); @@ -104,7 +104,7 @@ const Article = { } }, */ cdmUnsetActive: function (event) { - const row = $("RROW-" + Article.getActive()); + const row = App.byId("RROW-" + Article.getActive()); if (row) { row.removeClassName("active"); @@ -249,7 +249,7 @@ const Article = { container.innerHTML += " "; // in expandable mode, save content for later, so that we can pack unfocused rows back - if (App.isCombinedMode() && $("main").hasClassName("expandable")) + if (App.isCombinedMode() && App.byId("main").hasClassName("expandable")) row.setAttribute("data-content-original", row.getAttribute("data-content")); row.removeAttribute("data-content"); @@ -351,7 +351,7 @@ const Article = { if (data) { const id = data.id; - const tags = $("ATSTR-" + id); + const tags = App.byId("ATSTR-" + id); const tooltip = dijit.byId("ATSTRTIP-" + id); if (tags) tags.innerHTML = data.content; @@ -370,13 +370,13 @@ const Article = { xhrJson("backend.php", {op: "article", method: "printArticleTags", id: id}, (reply) => { - dijit.getEnclosingWidget($("tags_str")) + dijit.getEnclosingWidget(App.byId("tags_str")) .attr('value', reply.tags.join(", ")) .attr('disabled', false); - new Ajax.Autocompleter("tags_str", "tags_choices", + /* new Ajax.Autocompleter("tags_str", "tags_choices", "backend.php?op=article&method=completeTags", - {tokens: ',', paramName: "search"}); + {tokens: ',', paramName: "search"}); */ }); }); @@ -386,8 +386,8 @@ const Article = { cdmMoveToId: function (id, params = {}) { const force_to_top = params.force_to_top || false; - const ctr = $("headlines-frame"); - const row = $("RROW-" + id); + const ctr = App.byId("headlines-frame"); + const row = App.byId("RROW-" + id); if (!row || !ctr) return; @@ -399,12 +399,12 @@ const Article = { if (id != Article.getActive()) { console.log("setActive", id, "was", Article.getActive()); - $$("div[id*=RROW][class*=active]").each((row) => { + App.findAll("div[id*=RROW][class*=active]").forEach((row) => { row.removeClassName("active"); Article.pack(row); }); - const row = $("RROW-" + id); + const row = App.byId("RROW-" + id); if (row) { Article.unpack(row); @@ -425,10 +425,10 @@ const Article = { return 0; }, scrollByPages: function (page_offset) { - App.Scrollable.scrollByPages($("content-insert"), page_offset); + App.Scrollable.scrollByPages(App.byId("content-insert"), page_offset); }, scroll: function (offset) { - App.Scrollable.scroll($("content-insert"), offset); + App.Scrollable.scroll(App.byId("content-insert"), offset); }, mouseIn: function (id) { this.post_under_pointer = id; diff --git a/js/CommonDialogs.js b/js/CommonDialogs.js index dd0d56194..40313d34f 100644 --- a/js/CommonDialogs.js +++ b/js/CommonDialogs.js @@ -25,7 +25,7 @@ const CommonDialogs = { else Feeds.reload(); - const icon = $$(".feed-editor-icon")[0]; + const icon = App.findAll(".feed-editor-icon")[0]; if (icon) icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime()); @@ -36,7 +36,7 @@ const CommonDialogs = { return false; }, uploadFeedIcon: function() { - const file = $("icon_file"); + const file = App.byId("icon_file"); if (file.value.length == 0) { alert(__("Please select an image file to upload.")); @@ -57,7 +57,7 @@ const CommonDialogs = { else Feeds.reload(); - const icon = $$(".feed-editor-icon")[0]; + const icon = App.findAll(".feed-editor-icon")[0]; if (icon) icon.src = icon.src.replace(/\?[0-9]+$/, "?" + new Date().getTime()); @@ -72,7 +72,7 @@ const CommonDialogs = { break; } }; - xhr.send(new FormData($("feed_icon_upload_form"))); + xhr.send(new FormData(App.byId("feed_icon_upload_form"))); } return false; @@ -165,13 +165,11 @@ const CommonDialogs = { `, show_error: function (msg) { - const elem = $("fadd_error_message"); + const elem = App.byId("fadd_error_message"); elem.innerHTML = msg; - if (!Element.visible(elem)) - new Effect.Appear(elem); - + Element.show(elem); }, execute: function () { if (this.validate()) { @@ -239,7 +237,7 @@ const CommonDialogs = { } } - Effect.Appear('feedDlg_feedsContainer', {duration: 0.5}); + Element.show('feedDlg_feedsContainer'); } break; case 5: @@ -463,8 +461,6 @@ const CommonDialogs = { target.href = new_link; target.innerHTML = new_link; - new Effect.Highlight(target); - Notify.close(); } else { @@ -528,8 +524,6 @@ const CommonDialogs = { target.href = target.href.replace(/&key=.*$/, "&key=" + new_link); - new Effect.Highlight(target); - Notify.close(); } else { diff --git a/js/CommonFilters.js b/js/CommonFilters.js index e3629157b..d5b751f91 100644 --- a/js/CommonFilters.js +++ b/js/CommonFilters.js @@ -9,7 +9,7 @@ const Filters = { filterDlgCheckAction: function(sender) { const action = sender.value; - const action_param = $("filterDlg_paramBox"); + const action_param = App.byId("filterDlg_paramBox"); if (!action_param) { console.log("filterDlgCheckAction: can't find action param box!"); @@ -18,7 +18,7 @@ const Filters = { // if selected action supports parameters, enable params field if (action == 4 || action == 6 || action == 7 || action == 9) { - new Effect.Appear(action_param, {duration: 0.5}); + Element.show(action_param); Element.hide(dijit.byId("filterDlg_actionParam").domNode); Element.hide(dijit.byId("filterDlg_actionParamLabel").domNode); @@ -97,7 +97,7 @@ const Filters = { title: ruleStr ? __("Edit rule") : __("Add rule"), execute: function () { if (this.validate()) { - Filters.createNewRuleElement($("filterDlg_Matches"), replaceNode); + Filters.createNewRuleElement(App.byId("filterDlg_Matches"), replaceNode); this.hide(); } }, @@ -119,7 +119,7 @@ const Filters = { title: actionStr ? __("Edit action") : __("Add action"), execute: function () { if (this.validate()) { - Filters.createNewActionElement($("filterDlg_Actions"), replaceNode); + Filters.createNewActionElement(App.byId("filterDlg_Actions"), replaceNode); this.hide(); } } @@ -158,7 +158,7 @@ const Filters = { console.log("got results:" + result.length); - $("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...") + App.byId("prefFilterProgressMsg").innerHTML = __("Looking for articles (%d processed, %f found)...") .replace("%f", dialog.results) .replace("%d", offset); @@ -167,7 +167,7 @@ const Filters = { for (let i = 0; i < result.length; i++) { const tmp = dojo.create("table", { innerHTML: result[i]}); - $("prefFilterTestResultList").innerHTML += tmp.innerHTML; + App.byId("prefFilterTestResultList").innerHTML += tmp.innerHTML; } if (dialog.results < 30 && offset < dialog.max_offset) { @@ -183,11 +183,11 @@ const Filters = { Element.hide("prefFilterLoadingIndicator"); if (dialog.results == 0) { - $("prefFilterTestResultList").innerHTML = ` + App.byId("prefFilterTestResultList").innerHTML = ` ${__('No recent articles matching this filter have been found.')}`; - $("prefFilterProgressMsg").innerHTML = "Articles matching this filter:"; + App.byId("prefFilterProgressMsg").innerHTML = "Articles matching this filter:"; } else { - $("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:") + App.byId("prefFilterProgressMsg").innerHTML = __("Found %d articles matching this filter:") .replace("%d", dialog.results); } @@ -289,12 +289,12 @@ const Filters = { Filters.addFilterRule(); }, deleteAction: function () { - $$("#filterDlg_Actions li[class*=Selected]").each(function (e) { + App.findAll("#filterDlg_Actions li[class*=Selected]").forEach(function (e) { e.parentNode.removeChild(e) }); }, deleteRule: function () { - $$("#filterDlg_Matches li[class*=Selected]").each(function (e) { + App.findAll("#filterDlg_Matches li[class*=Selected]").forEach(function (e) { e.parentNode.removeChild(e) }); }, diff --git a/js/FeedTree.js b/js/FeedTree.js index 694cf8332..17cd3deea 100755 --- a/js/FeedTree.js +++ b/js/FeedTree.js @@ -286,7 +286,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co // focus headlines to route key events there setTimeout(() => { - $("headlines-frame").focus(); + App.byId("headlines-frame").focus(); if (treeNode) { const node = treeNode.rowNode; @@ -295,7 +295,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "dojo/_base/array", "dojo/co if (node && tree) { // scroll tree to selection if needed if (node.offsetTop < tree.scrollTop || node.offsetTop > tree.scrollTop + tree.clientHeight) { - $("feedTree").scrollTop = node.offsetTop; + App.byId("feedTree").scrollTop = node.offsetTop; } } } diff --git a/js/Feeds.js b/js/Feeds.js index 0567cf8c5..7f3a80f4e 100644 --- a/js/Feeds.js +++ b/js/Feeds.js @@ -117,7 +117,7 @@ const Feeds = { toggle: function() { Element.toggle("feeds-holder"); - const splitter = $("feeds-holder_splitter"); + const splitter = App.byId("feeds-holder_splitter"); Element.visible("feeds-holder") ? splitter.show() : splitter.hide(); @@ -180,7 +180,7 @@ const Feeds = { dojo.disconnect(tmph); }); - $("feeds-holder").appendChild(tree.domNode); + App.byId("feeds-holder").appendChild(tree.domNode); const tmph2 = dojo.connect(tree, 'onLoad', function () { dojo.disconnect(tmph2); @@ -284,8 +284,8 @@ const Feeds = { this._active_feed_id = id; this._active_feed_is_cat = is_cat; - $("headlines-frame").setAttribute("feed-id", id); - $("headlines-frame").setAttribute("is-cat", is_cat ? 1 : 0); + App.byId("headlines-frame").setAttribute("feed-id", id); + App.byId("headlines-frame").setAttribute("is-cat", is_cat ? 1 : 0); this.select(id, is_cat); @@ -310,8 +310,8 @@ const Feeds = { if (tree) return tree.hideRead(hide, App.getInitParam("hide_read_shows_special"));*/ - $$("body")[0].setAttribute("hide-read-feeds", !!hide); - $$("body")[0].setAttribute("hide-read-shows-special", !!App.getInitParam("hide_read_shows_special")); + App.findAll("body")[0].setAttribute("hide-read-feeds", !!hide); + App.findAll("body")[0].setAttribute("hide-read-shows-special", !!App.getInitParam("hide_read_shows_special")); }, open: function(params) { const feed = params.feed; @@ -339,7 +339,7 @@ const Feeds = { }, 10 * 1000); } - Form.enable("toolbar-main"); + //Form.enable("toolbar-main"); let query = Object.assign({op: "feeds", method: "view", feed: feed}, dojo.formToObject("toolbar-main")); @@ -362,7 +362,7 @@ const Feeds = { query.m = "ForceUpdate"; } - Form.enable("toolbar-main"); + //Form.enable("toolbar-main"); if (!delayed) if (!this.setExpando(feed, is_cat, @@ -476,9 +476,9 @@ const Feeds = { if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(str)) { - const rows = $$("#headlines-frame > div[id*=RROW][class*=Unread][data-orig-feed-id='" + id + "']"); + const rows = App.findAll("#headlines-frame > div[id*=RROW][class*=Unread][data-orig-feed-id='" + id + "']"); - rows.each((row) => { + rows.forEach((row) => { row.removeClassName("Unread"); }) } diff --git a/js/Headlines.js b/js/Headlines.js index 128a7e571..143a42d0b 100755 --- a/js/Headlines.js +++ b/js/Headlines.js @@ -44,7 +44,7 @@ const Headlines = { row_observer: new MutationObserver((mutations) => { const modified = []; - mutations.each((m) => { + mutations.forEach((m) => { if (m.type == 'attributes' && ['class', 'data-score'].indexOf(m.attributeName) != -1) { const row = m.target; @@ -54,7 +54,7 @@ const Headlines = { const hl = Headlines.headlines[id]; if (hl) { - const hl_old = Object.extend({}, hl); + const hl_old = {...{}, ...hl}; hl.unread = row.hasClassName("Unread"); hl.marked = row.hasClassName("marked"); @@ -94,7 +94,7 @@ const Headlines = { rescore: {}, }; - modified.each(function (m) { + modified.forEach(function (m) { if (m.old.marked != m.new.marked) ops.tmark.push(m.id); @@ -118,29 +118,29 @@ const Headlines = { } }); - ops.select.each((row) => { - const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]); + ops.select.forEach((row) => { + const cb = dijit.getEnclosingWidget(row.querySelector(".rchk")); if (cb) cb.attr('checked', true); }); - ops.deselect.each((row) => { - const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]); + ops.deselect.forEach((row) => { + const cb = dijit.getEnclosingWidget(row.querySelector(".rchk")); if (cb && !row.hasClassName("active")) cb.attr('checked', false); }); - ops.activate.each((row) => { - const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]); + ops.activate.forEach((row) => { + const cb = dijit.getEnclosingWidget(row.querySelector(".rchk")); if (cb) cb.attr('checked', true); }); - ops.deactivate.each((row) => { - const cb = dijit.getEnclosingWidget(row.select(".rchk")[0]); + ops.deactivate.forEach((row) => { + const cb = dijit.getEnclosingWidget(row.querySelector(".rchk")); if (cb && !row.hasClassName("Selected")) cb.attr('checked', false); @@ -167,7 +167,7 @@ const Headlines = { const scores = Object.keys(ops.rescore); if (scores.length != 0) { - scores.each((score) => { + scores.forEach((score) => { promises.push(xhrPost("backend.php", {op: "article", method: "setScore", id: ops.rescore[score].toString(), score: score})); }); @@ -211,7 +211,7 @@ const Headlines = { Headlines.select('none'); - const scroll_position_A = $("RROW-" + id).offsetTop - $("headlines-frame").scrollTop; + const scroll_position_A = App.byId("RROW-" + id).offsetTop - App.byId("headlines-frame").scrollTop; Article.setActive(id); @@ -222,10 +222,10 @@ const Headlines = { Headlines.toggleUnread(id, 0); } else { - const scroll_position_B = $("RROW-" + id).offsetTop - $("headlines-frame").scrollTop; + const scroll_position_B = App.byId("RROW-" + id).offsetTop - App.byId("headlines-frame").scrollTop; // this would only work if there's enough space - $("headlines-frame").scrollTop -= scroll_position_A-scroll_position_B; + App.byId("headlines-frame").scrollTop -= scroll_position_A-scroll_position_B; Article.cdmMoveToId(id); } @@ -252,7 +252,7 @@ const Headlines = { return false; }, initScrollHandler: function () { - $("headlines-frame").onscroll = (event) => { + App.byId("headlines-frame").onscroll = (event) => { clearTimeout(this._headlines_scroll_timeout); this._headlines_scroll_timeout = window.setTimeout(function () { //console.log('done scrolling', event); @@ -262,8 +262,8 @@ const Headlines = { }, loadMore: function () { const view_mode = document.forms["toolbar-main"].view_mode.value; - const unread_in_buffer = $$("#headlines-frame > div[id*=RROW][class*=Unread]").length; - const num_all = $$("#headlines-frame > div[id*=RROW]").length; + const unread_in_buffer = App.findAll("#headlines-frame > div[id*=RROW][class*=Unread]").length; + const num_all = App.findAll("#headlines-frame > div[id*=RROW]").length; const num_unread = Feeds.getUnread(Feeds.getActive(), Feeds.activeIsCat()); // TODO implement marked & published @@ -289,10 +289,10 @@ const Headlines = { Feeds.open({feed: Feeds.getActive(), is_cat: Feeds.activeIsCat(), offset: offset, append: true}); }, isChildVisible: function (elem) { - return App.Scrollable.isChildVisible(elem, $("headlines-frame")); + return App.Scrollable.isChildVisible(elem, App.byId("headlines-frame")); }, firstVisible: function () { - const rows = $$("#headlines-frame > div[id*=RROW]"); + const rows = App.findAll("#headlines-frame > div[id*=RROW]"); for (let i = 0; i < rows.length; i++) { const row = rows[i]; @@ -303,7 +303,7 @@ const Headlines = { } }, unpackVisible: function(container) { - const rows = $$("#headlines-frame > div[id*=RROW][data-content].cdm"); + const rows = App.findAll("#headlines-frame > div[id*=RROW][data-content].cdm"); for (let i = 0; i < rows.length; i++) { if (App.Scrollable.isChildVisible(rows[i], container)) { @@ -315,8 +315,8 @@ const Headlines = { scrollHandler: function (/*event*/) { try { if (!Feeds.infscroll_disabled && !Feeds.infscroll_in_progress) { - const hsp = $("headlines-spacer"); - const container = $("headlines-frame"); + const hsp = App.byId("headlines-spacer"); + const container = App.byId("headlines-frame"); if (hsp && hsp.previousSibling) { const last_row = hsp.previousSibling; @@ -333,7 +333,7 @@ const Headlines = { } if (App.isCombinedMode() && App.getInitParam("cdm_expanded")) { - const container = $("headlines-frame") + const container = App.byId("headlines-frame") /* don't do anything until there was some scrolling */ if (container.scrollTop > 0) @@ -342,12 +342,12 @@ const Headlines = { if (App.getInitParam("cdm_auto_catchup")) { - const rows = $$("#headlines-frame > div[id*=RROW][class*=Unread]"); + const rows = App.findAll("#headlines-frame > div[id*=RROW][class*=Unread]"); for (let i = 0; i < rows.length; i++) { const row = rows[i]; - if ($("headlines-frame").scrollTop > (row.offsetTop + row.offsetHeight / 2)) { + if (App.byId("headlines-frame").scrollTop > (row.offsetTop + row.offsetHeight / 2)) { row.removeClassName("Unread"); } else { break; @@ -362,23 +362,23 @@ const Headlines = { return this.headlines[id]; }, setCommonClasses: function () { - $("headlines-frame").removeClassName("cdm"); - $("headlines-frame").removeClassName("normal"); + App.byId("headlines-frame").removeClassName("cdm"); + App.byId("headlines-frame").removeClassName("normal"); - $("headlines-frame").addClassName(App.isCombinedMode() ? "cdm" : "normal"); + App.byId("headlines-frame").addClassName(App.isCombinedMode() ? "cdm" : "normal"); // for floating title because it's placed outside of headlines-frame - $("main").removeClassName("expandable"); - $("main").removeClassName("expanded"); + App.byId("main").removeClassName("expandable"); + App.byId("main").removeClassName("expanded"); if (App.isCombinedMode()) - $("main").addClassName(App.getInitParam("cdm_expanded") ? " expanded" : " expandable"); + App.byId("main").addClassName(App.getInitParam("cdm_expanded") ? " expanded" : " expandable"); }, renderAgain: function () { // TODO: wrap headline elements into a knockoutjs model to prevent all this stuff Headlines.setCommonClasses(); - $$("#headlines-frame > div[id*=RROW]").each((row) => { + App.findAll("#headlines-frame > div[id*=RROW]").forEach((row) => { const id = row.getAttribute("data-article-id"); const hl = this.headlines[id]; @@ -401,12 +401,12 @@ const Headlines = { } }); - $$(".cdm .header-sticky-guard").each((e) => { + App.findAll(".cdm .header-sticky-guard").forEach((e) => { this.sticky_header_observer.observe(e) }); if (App.getInitParam("cdm_expanded")) - $$("#headlines-frame > div[id*=RROW].cdm").each((e) => { + App.findAll("#headlines-frame > div[id*=RROW].cdm").forEach((e) => { this.unpack_observer.observe(e) }); @@ -431,7 +431,7 @@ const Headlines = { const tmp = document.createElement("div"); tmp.innerHTML = vgrhdr; - $("headlines-frame").appendChild(tmp.firstChild); + App.byId("headlines-frame").appendChild(tmp.firstChild); this.vgroup_last_feed = hl.feed_id; } @@ -555,11 +555,11 @@ const Headlines = { return tmp.firstChild; }, updateCurrentUnread: function () { - if ($("feed_current_unread")) { + if (App.byId("feed_current_unread")) { const feed_unread = Feeds.getUnread(Feeds.getActive(), Feeds.activeIsCat()); if (feed_unread > 0 && !Element.visible("feeds-holder")) { - $("feed_current_unread").innerText = feed_unread; + App.byId("feed_current_unread").innerText = feed_unread; Element.show("feed_current_unread"); } else { Element.hide("feed_current_unread"); @@ -653,15 +653,15 @@ const Headlines = { // also called in renderAgain() after view mode switch Headlines.setCommonClasses(); - $("headlines-frame").setAttribute("is-vfeed", + App.byId("headlines-frame").setAttribute("is-vfeed", reply['headlines']['is_vfeed'] ? 1 : 0); Article.setActive(0); try { - $("headlines-frame").removeClassName("smooth-scroll"); - $("headlines-frame").scrollTop = 0; - $("headlines-frame").addClassName("smooth-scroll"); + App.byId("headlines-frame").removeClassName("smooth-scroll"); + App.byId("headlines-frame").scrollTop = 0; + App.byId("headlines-frame").addClassName("smooth-scroll"); } catch (e) { console.warn(e); } @@ -669,27 +669,27 @@ const Headlines = { this.headlines = []; this.vgroup_last_feed = undefined; - /*dojo.html.set($("toolbar-headlines"), + /*dojo.html.set(App.byId("toolbar-headlines"), reply['headlines']['toolbar'], {parseContent: true});*/ Headlines.renderToolbar(reply['headlines']); if (typeof reply['headlines']['content'] == 'string') { - $("headlines-frame").innerHTML = reply['headlines']['content']; + App.byId("headlines-frame").innerHTML = reply['headlines']['content']; } else { - $("headlines-frame").innerHTML = ''; + App.byId("headlines-frame").innerHTML = ''; for (let i = 0; i < reply['headlines']['content'].length; i++) { const hl = reply['headlines']['content'][i]; - $("headlines-frame").appendChild(this.render(reply['headlines'], hl)); + App.byId("headlines-frame").appendChild(this.render(reply['headlines'], hl)); this.headlines[parseInt(hl.id)] = hl; } } - let hsp = $("headlines-spacer"); + let hsp = App.byId("headlines-spacer"); if (!hsp) { hsp = document.createElement("div"); @@ -706,7 +706,7 @@ const Headlines = { /* if (Feeds._search_query) { - $("feed_title").innerHTML += "" + + App.byId("feed_title").innerHTML += "" + " (" + __("Cancel search") + ")" + ""; } */ @@ -716,7 +716,7 @@ const Headlines = { } else if (headlines_count > 0 && feed_id == Feeds.getActive() && is_cat == Feeds.activeIsCat()) { const c = dijit.byId("headlines-frame"); - let hsp = $("headlines-spacer"); + let hsp = App.byId("headlines-spacer"); if (hsp) c.domNode.removeChild(hsp); @@ -724,13 +724,13 @@ const Headlines = { let headlines_appended = 0; if (typeof reply['headlines']['content'] == 'string') { - $("headlines-frame").innerHTML = reply['headlines']['content']; + App.byId("headlines-frame").innerHTML = reply['headlines']['content']; } else { for (let i = 0; i < reply['headlines']['content'].length; i++) { const hl = reply['headlines']['content'][i]; if (!this.headlines[parseInt(hl.id)]) { - $("headlines-frame").appendChild(this.render(reply['headlines'], hl)); + App.byId("headlines-frame").appendChild(this.render(reply['headlines'], hl)); this.headlines[parseInt(hl.id)] = hl; ++headlines_appended; @@ -762,7 +762,7 @@ const Headlines = { console.log("no headlines received, infscroll_disabled=", Feeds.infscroll_disabled, 'first_id_changed=', first_id_changed); - const hsp = $("headlines-spacer"); + const hsp = App.byId("headlines-spacer"); if (hsp) { if (first_id_changed) { @@ -775,12 +775,12 @@ const Headlines = { } } - $$(".cdm .header-sticky-guard").each((e) => { + App.findAll(".cdm .header-sticky-guard").forEach((e) => { this.sticky_header_observer.observe(e) }); if (App.getInitParam("cdm_expanded")) - $$("#headlines-frame > div[id*=RROW].cdm").each((e) => { + App.findAll("#headlines-frame > div[id*=RROW].cdm").forEach((e) => { this.unpack_observer.observe(e) }); @@ -826,8 +826,8 @@ const Headlines = { return; } - ids.each((id) => { - const row = $("RROW-" + id); + ids.forEach((id) => { + const row = App.byId("RROW-" + id); if (row) { switch (cmode) { @@ -851,7 +851,7 @@ const Headlines = { return; } - ids.each((id) => { + ids.forEach((id) => { this.toggleMark(id); }); }, @@ -863,19 +863,19 @@ const Headlines = { return; } - ids.each((id) => { + ids.forEach((id) => { this.togglePub(id); }); }, toggleMark: function (id) { - const row = $("RROW-" + id); + const row = App.byId("RROW-" + id); if (row) row.toggleClassName("marked"); }, togglePub: function (id) { - const row = $("RROW-" + id); + const row = App.byId("RROW-" + id); if (row) row.toggleClassName("published"); @@ -889,7 +889,7 @@ const Headlines = { let next_id = false; let current_id = Article.getActive(); - if (!Headlines.isChildVisible($("RROW-" + current_id))) { + if (!Headlines.isChildVisible(App.byId("RROW-" + current_id))) { console.log('active article is obscured, resetting to first visible...'); current_id = Headlines.firstVisible(); prev_id = current_id; @@ -928,15 +928,15 @@ const Headlines = { } } else if (App.isCombinedMode()) { // try to show hsp if no next article exists, in case there's useful information like first_id_changed etc - const row = $("RROW-" + current_id); - const ctr = $("headlines-frame"); + const row = App.byId("RROW-" + current_id); + const ctr = App.byId("headlines-frame"); if (row) { const next = row.nextSibling; // hsp has half-screen height in auto catchup mode therefore we use its first child (normally A element) if (next && Element.visible(next) && next.id == "headlines-spacer" && next.firstChild) { - const offset = $("headlines-spacer").offsetTop - $("headlines-frame").offsetHeight + next.firstChild.offsetHeight; + const offset = App.byId("headlines-spacer").offsetTop - App.byId("headlines-frame").offsetHeight + next.firstChild.offsetHeight; // don't jump back either if (ctr.scrollTop < offset) @@ -948,8 +948,8 @@ const Headlines = { if (prev_id || current_id) { if (App.isCombinedMode()) { window.requestAnimationFrame(() => { - const row = $("RROW-" + current_id); - const ctr = $("headlines-frame"); + const row = App.byId("RROW-" + current_id); + const ctr = App.byId("headlines-frame"); const delta_px = Math.round(row.offsetTop) - Math.round(ctr.scrollTop); console.log('moving back, delta_px', delta_px); @@ -970,7 +970,7 @@ const Headlines = { }, updateSelectedPrompt: function () { const count = Headlines.getSelected().length; - const elem = $("selected_prompt"); + const elem = App.byId("selected_prompt"); if (elem) { elem.innerHTML = ngettext("%d article selected", @@ -980,7 +980,7 @@ const Headlines = { } }, toggleUnread: function (id, cmode) { - const row = $("RROW-" + id); + const row = App.byId("RROW-" + id); if (row) { if (typeof cmode == "undefined") cmode = 2; @@ -1068,7 +1068,7 @@ const Headlines = { getSelected: function () { const rv = []; - $$("#headlines-frame > div[id*=RROW][class*=Selected]").each( + App.findAll("#headlines-frame > div[id*=RROW][class*=Selected]").forEach( function (child) { rv.push(child.getAttribute("data-article-id")); }); @@ -1082,9 +1082,9 @@ const Headlines = { getLoaded: function () { const rv = []; - const children = $$("#headlines-frame > div[id*=RROW-]"); + const children = App.findAll("#headlines-frame > div[id*=RROW-]"); - children.each(function (child) { + children.forEach(function (child) { if (Element.visible(child)) { rv.push(child.getAttribute("data-article-id")); } @@ -1111,7 +1111,7 @@ const Headlines = { if (start == stop) return [start]; - const rows = $$("#headlines-frame > div[id*=RROW]"); + const rows = App.findAll("#headlines-frame > div[id*=RROW]"); const results = []; let collecting = false; @@ -1158,10 +1158,7 @@ const Headlines = { console.warn("select: unknown mode", mode); } - const rows = $$(query); - - for (let i = 0; i < rows.length; i++) { - const row = rows[i]; + App.findAll(query).forEach((row) => { switch (mode) { case "none": @@ -1173,7 +1170,7 @@ const Headlines = { default: row.addClassName("Selected"); } - } + }); }, catchupSelection: function () { const rows = Headlines.getSelected(); @@ -1212,7 +1209,7 @@ const Headlines = { if (!below) { for (let i = 0; i < visible_ids.length; i++) { if (visible_ids[i] != id) { - const e = $("RROW-" + visible_ids[i]); + const e = App.byId("RROW-" + visible_ids[i]); if (e && e.hasClassName("Unread")) { ids_to_mark.push(visible_ids[i]); @@ -1224,7 +1221,7 @@ const Headlines = { } else { for (let i = visible_ids.length - 1; i >= 0; i--) { if (visible_ids[i] != id) { - const e = $("RROW-" + visible_ids[i]); + const e = App.byId("RROW-" + visible_ids[i]); if (e && e.hasClassName("Unread")) { ids_to_mark.push(visible_ids[i]); @@ -1243,7 +1240,7 @@ const Headlines = { if (App.getInitParam("confirm_feed_catchup") != 1 || confirm(msg)) { for (let i = 0; i < ids_to_mark.length; i++) { - const e = $("RROW-" + ids_to_mark[i]); + const e = App.byId("RROW-" + ids_to_mark[i]); e.removeClassName("Unread"); } } @@ -1253,16 +1250,16 @@ const Headlines = { const data = JSON.parse(transport.responseText); if (data) { - data['info-for-headlines'].each(function (elem) { - $$(".HLLCTR-" + elem.id).each(function (ctr) { + data['info-for-headlines'].forEach(function (elem) { + App.findAll(".HLLCTR-" + elem.id).forEach(function (ctr) { ctr.innerHTML = elem.labels; }); }); } }, scrollToArticleId: function (id) { - const container = $("headlines-frame"); - const row = $("RROW-" + id); + const container = App.byId("headlines-frame"); + const row = App.byId("RROW-" + id); if (!container || !row) return; @@ -1361,7 +1358,7 @@ const Headlines = { const labelAddMenu = new dijit.Menu({ownerMenu: menu}); const labelDelMenu = new dijit.Menu({ownerMenu: menu}); - labels.each(function (label) { + labels.forEach(function (label) { const bare_id = label.id; const name = label.caption; @@ -1409,10 +1406,10 @@ const Headlines = { } }, scrollByPages: function (page_offset) { - App.Scrollable.scrollByPages($("headlines-frame"), page_offset); + App.Scrollable.scrollByPages(App.byId("headlines-frame"), page_offset); }, scroll: function (offset) { - App.Scrollable.scroll($("headlines-frame"), offset); + App.Scrollable.scroll(App.byId("headlines-frame"), offset); }, initHeadlinesMenu: function () { if (!dijit.byId("headlinesMenu")) { diff --git a/js/PrefFeedTree.js b/js/PrefFeedTree.js index e081e2e31..92194e037 100644 --- a/js/PrefFeedTree.js +++ b/js/PrefFeedTree.js @@ -126,7 +126,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b return (!item || this.model.store.getValue(item, 'type') == 'category') ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "feed-icon"; }, reload: function() { - const searchElem = $("feed_search"); + const searchElem = App.byId("feed_search"); const search = (searchElem) ? searchElem.value : ""; xhrPost("backend.php", { op: "pref-feeds", search: search }, (transport) => { @@ -228,7 +228,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b const items = tree.model.getCheckedItems(); const rv = []; - items.each(function (item) { + items.forEach(function (item) { if (item.id[0].match("CAT:")) rv.push(tree.model.store.getValue(item, 'bare_id')); }); @@ -262,7 +262,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b const items = tree.model.getCheckedItems(); const rv = []; - items.each(function (item) { + items.forEach(function (item) { if (item.id[0].match("FEED:")) rv.push(tree.model.store.getValue(item, 'bare_id')); }); @@ -304,7 +304,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b title: __("Edit Multiple Feeds"), getChildByName: function (name) { let rv = null; - this.getChildren().each( + this.getChildren().forEach( function (child) { if (child.name == name) { rv = child; @@ -329,7 +329,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dojo/_b /* normalize unchecked checkboxes because [] is not serialized */ - Object.keys(query).each((key) => { + Object.keys(query).forEach((key) => { const val = query[key]; if (typeof val == "object" && val.length == 0) diff --git a/js/PrefFilterTree.js b/js/PrefFilterTree.js index e7d4efdc1..3d00c730c 100644 --- a/js/PrefFilterTree.js +++ b/js/PrefFilterTree.js @@ -80,14 +80,14 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree"], functio const items = tree.model.getCheckedItems(); const rv = []; - items.each(function (item) { + items.forEach(function (item) { rv.push(tree.model.store.getValue(item, 'bare_id')); }); return rv; }, reload: function() { - const user_search = $("filter_search"); + const user_search = App.byId("filter_search"); let search = ""; if (user_search) { search = user_search.value; } diff --git a/js/PrefHelpers.js b/js/PrefHelpers.js index 671431c39..f3c44e30d 100644 --- a/js/PrefHelpers.js +++ b/js/PrefHelpers.js @@ -9,7 +9,7 @@ const Helpers = { return Tables.getSelected("app-password-list"); }, updateContent: function(data) { - $("app_passwords_holder").innerHTML = data; + App.byId("app_passwords_holder").innerHTML = data; dojo.parser.parse("app_passwords_holder"); }, removeSelected: function() { @@ -218,8 +218,8 @@ const Helpers = { title: __("Customize stylesheet"), apply: function() { xhrPost("backend.php", this.attr('value'), () => { - new Effect.Appear("css_edit_apply_msg"); - $("user_css_style").innerText = this.attr('value'); + Element.show("css_edit_apply_msg"); + App.byId("user_css_style").innerText = this.attr('value'); }); }, execute: function () { @@ -291,7 +291,7 @@ const Helpers = { }, OPML: { import: function() { - const opml_file = $("opml_file"); + const opml_file = App.byId("opml_file"); if (opml_file.value.length == 0) { alert(__("Please choose an OPML file first.")); @@ -333,7 +333,7 @@ const Helpers = { dialog.show(); }; - xhr.send(new FormData($("opml_import_form"))); + xhr.send(new FormData(App.byId("opml_import_form"))); return false; } diff --git a/js/PrefLabelTree.js b/js/PrefLabelTree.js index f22423091..4392dfc44 100644 --- a/js/PrefLabelTree.js +++ b/js/PrefLabelTree.js @@ -48,7 +48,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f const items = tree.model.getCheckedItems(); const rv = []; - items.each(function(item) { + items.forEach(function(item) { rv.push(tree.model.store.getValue(item, 'bare_id')); }); @@ -87,7 +87,7 @@ define(["dojo/_base/declare", "dojo/dom-construct", "lib/CheckBoxTree", "dijit/f color = bg; } - const e = $("icon-label-" + id); + const e = App.byId("icon-label-" + id); if (e) { if (bg) e.style.color = bg; diff --git a/js/PrefUsers.js b/js/PrefUsers.js index ebfe9231b..2e8c9c4a8 100644 --- a/js/PrefUsers.js +++ b/js/PrefUsers.js @@ -5,7 +5,7 @@ const Users = { reload: function(sort) { - const user_search = $("user_search"); + const user_search = App.byId("user_search"); const search = user_search ? user_search.value : ""; xhrPost("backend.php", { op: "pref-users", sort: sort, search: search }, (transport) => { diff --git a/js/common.js b/js/common.js index fb5cc6531..982bb94a7 100755 --- a/js/common.js +++ b/js/common.js @@ -3,35 +3,117 @@ /* global dijit, __, App, Ajax */ /* eslint-disable no-new */ -/* error reporting shim */ -// TODO: deprecated; remove -/* function exception_error(e, e_compat, filename, lineno, colno) { - if (typeof e == "string") - e = e_compat; +Element.prototype.hasClassName = function(className) { + dojo.hasClass(this, className); +}; - App.Error.report(e, {filename: filename, lineno: lineno, colno: colno}); -} */ +Element.prototype.addClassName = function(className) { + dojo.addClass(this, className); +}; + +Element.prototype.removeClassName = function(className) { + dojo.removeClass(this, className); +}; + +Element.prototype.setStyle = function(args) { + Object.keys(args).forEach((k) => { + this.style[k] = args[k]; + }); +}; + +Element.prototype.show = function() { + this.style.display = ""; +}; + +Element.prototype.hide = function() { + this.style.display = "none"; +}; + +Element.prototype.toggle = function() { + if (this.visible()) + this.show(); + else + this.hide(); +}; + +Element.prototype.visible = function() { + // TODO: should we actually check for offsetWidth/offsetHeight == 0? + return this.style.display != "none"; +} + +Element.visible = function(elem) { + if (typeof elem == "string") + elem = document.getElementById(elem); + + return elem.visible(); +} + +Element.show = function(elem) { + if (typeof elem == "string") + elem = document.getElementById(elem); + + return elem.show(); +} + +Element.hide = function(elem) { + if (typeof elem == "string") + elem = document.getElementById(elem); + + return elem.hide(); +} + +Element.toggle = function(elem) { + if (typeof elem == "string") + elem = document.getElementById(elem); + + return elem.toggle(); +} + +Element.hasClassName = function (id, className) { + return document.getElementById(id).hasClassName(className); +} /* xhr shorthand helpers */ /* exported xhrPost */ -function xhrPost(url, params, complete) { +function xhrPost(url, params = {}, complete = undefined) { console.log("xhrPost:", params); return new Promise((resolve, reject) => { - new Ajax.Request(url, { - parameters: params, - onComplete: function(reply) { - if (complete != undefined) complete(reply); + if (typeof __csrf_token != "undefined") + params = {...params, ...{csrf_token: __csrf_token}}; - resolve(reply); - } - }); + dojo.xhrPost({url: url, + postData: dojo.objectToQuery(params), + handleAs: "text", + error: function(error) { + reject(error); + }, + load: function(data, ioargs) { + if (complete != undefined) + complete(ioargs.xhr); + + resolve(ioargs.xhr) + }}); }); } +Array.prototype.remove = function(s) { + for (let i=0; i < this.length; i++) { + if (s == this[i]) this.splice(i, 1); + } +}; + +Array.prototype.uniq = function() { + return this.filter((v, i, a) => a.indexOf(v) === i); +}; + +String.prototype.stripTags = function() { + return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?(\/)?>|<\/\w+>/gi, ''); +} + /* exported xhrJson */ -function xhrJson(url, params, complete) { +function xhrJson(url, params = {}, complete = undefined) { return new Promise((resolve, reject) => xhrPost(url, params).then((reply) => { let obj = null; @@ -48,13 +130,6 @@ function xhrJson(url, params, complete) { })); } -/* 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 */ /* exported Lists */ @@ -70,8 +145,8 @@ const Lists = { checked ? row.addClassName("Selected") : row.removeClassName("Selected"); }, select: function(elemId, selected) { - $(elemId).select("li").each((row) => { - const checkNode = row.select(".dijitCheckBox,input[type=checkbox]")[0]; + $(elemId).querySelectorAll("li").forEach((row) => { + const checkNode = row.querySelector(".dijitCheckBox,input[type=checkbox]"); if (checkNode) { const widget = dijit.getEnclosingWidget(checkNode); @@ -101,8 +176,8 @@ const Tables = { }, select: function(elemId, selected) { - $(elemId).select("tr").each((row) => { - const checkNode = row.select(".dijitCheckBox,input[type=checkbox]")[0]; + $(elemId).querySelector("tr").forEach((row) => { + const checkNode = row.querySelector(".dijitCheckBox,input[type=checkbox]"); if (checkNode) { const widget = dijit.getEnclosingWidget(checkNode); @@ -119,7 +194,7 @@ const Tables = { getSelected: function(elemId) { const rv = []; - $(elemId).select("tr").each((row) => { + $(elemId).querySelector("tr").forEach((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]*?-/, ""); @@ -173,7 +248,7 @@ const Notify = { kind = kind || this.KIND_GENERIC; keep = keep || false; - const notify = $("notify"); + const notify = App.byId("notify"); window.clearTimeout(this.timeout); diff --git a/js/tt-rss.js b/js/tt-rss.js index 764667a0d..28b598c25 100644 --- a/js/tt-rss.js +++ b/js/tt-rss.js @@ -70,13 +70,20 @@ require(["dojo/_base/kernel", /* exported hash_get */ function hash_get(key) { - const kv = window.location.hash.substring(1).toQueryParams(); - return kv[key]; + console.warn("FIXME: hash_get", key); + + //const kv = window.location.hash.substring(1).toQueryParams(); + //return kv[key]; + console.warn("FIXME: hash_get", key); } /* exported hash_set */ function hash_set(key, value) { - const kv = window.location.hash.substring(1).toQueryParams(); + console.warn("FIXME: hash_set", key, value); + + /*const kv = window.location.hash.substring(1).toQueryParams(); kv[key] = value; - window.location.hash = $H(kv).toQueryString(); + window.location.hash = $H(kv).toQueryString();*/ + + console.warn("FIXME: hash_set", key); } diff --git a/js/utility.js b/js/utility.js index eef1c6b61..a7530a97f 100644 --- a/js/utility.js +++ b/js/utility.js @@ -2,7 +2,7 @@ /* TODO: this should probably be something like night_mode.js since it does nothing specific to utility scripts */ -Event.observe(window, "load", function() { +window.addEventListener("load", function() { const UtilityJS = { apply_night_mode: function (is_night, link) { console.log("night mode changed to", is_night); diff --git a/lib/scriptaculous/controls.js b/lib/scriptaculous/controls.js deleted file mode 100644 index 5137ab510..000000000 --- a/lib/scriptaculous/controls.js +++ /dev/null @@ -1,965 +0,0 @@ -// script.aculo.us controls.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010 - -// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005-2010 Ivan Krstic (http://blogs.law.harvard.edu/ivan) -// (c) 2005-2010 Jon Tirsen (http://www.tirsen.com) -// Contributors: -// Richard Livsey -// Rahul Bhargava -// Rob Wills -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -// Autocompleter.Base handles all the autocompletion functionality -// that's independent of the data source for autocompletion. This -// includes drawing the autocompletion menu, observing keyboard -// and mouse events, and similar. -// -// Specific autocompleters need to provide, at the very least, -// a getUpdatedChoices function that will be invoked every time -// the text inside the monitored textbox changes. This method -// should get the text for which to provide autocompletion by -// invoking this.getToken(), NOT by directly accessing -// this.element.value. This is to allow incremental tokenized -// autocompletion. Specific auto-completion logic (AJAX, etc) -// belongs in getUpdatedChoices. -// -// Tokenized incremental autocompletion is enabled automatically -// when an autocompleter is instantiated with the 'tokens' option -// in the options parameter, e.g.: -// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); -// will incrementally autocomplete with a comma as the token. -// Additionally, ',' in the above example can be replaced with -// a token array, e.g. { tokens: [',', '\n'] } which -// enables autocompletion on multiple tokens. This is most -// useful when one of the tokens is \n (a newline), as it -// allows smart autocompletion after linebreaks. - -if(typeof Effect == 'undefined') - throw("controls.js requires including script.aculo.us' effects.js library"); - -var Autocompleter = { }; -Autocompleter.Base = Class.create({ - baseInitialize: function(element, update, options) { - element = $(element); - this.element = element; - this.update = $(update); - this.hasFocus = false; - this.changed = false; - this.active = false; - this.index = 0; - this.entryCount = 0; - this.oldElementValue = this.element.value; - - if(this.setOptions) - this.setOptions(options); - else - this.options = options || { }; - - this.options.paramName = this.options.paramName || this.element.name; - this.options.tokens = this.options.tokens || []; - this.options.frequency = this.options.frequency || 0.4; - this.options.minChars = this.options.minChars || 1; - this.options.onShow = this.options.onShow || - function(element, update){ - if(!update.style.position || update.style.position=='absolute') { - update.style.position = 'absolute'; - Position.clone(element, update, { - setHeight: false, - offsetTop: element.offsetHeight - }); - } - Effect.Appear(update,{duration:0.15}); - }; - this.options.onHide = this.options.onHide || - function(element, update){ new Effect.Fade(update,{duration:0.15}) }; - - if(typeof(this.options.tokens) == 'string') - this.options.tokens = new Array(this.options.tokens); - // Force carriage returns as token delimiters anyway - if (!this.options.tokens.include('\n')) - this.options.tokens.push('\n'); - - this.observer = null; - - this.element.setAttribute('autocomplete','off'); - - Element.hide(this.update); - - Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); - Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); - }, - - show: function() { - if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); - if(!this.iefix && - (Prototype.Browser.IE) && - (Element.getStyle(this.update, 'position')=='absolute')) { - new Insertion.After(this.update, - ''); - this.iefix = $(this.update.id+'_iefix'); - } - if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); - }, - - fixIEOverlapping: function() { - Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); - this.iefix.style.zIndex = 1; - this.update.style.zIndex = 2; - Element.show(this.iefix); - }, - - hide: function() { - this.stopIndicator(); - if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); - if(this.iefix) Element.hide(this.iefix); - }, - - startIndicator: function() { - if(this.options.indicator) Element.show(this.options.indicator); - }, - - stopIndicator: function() { - if(this.options.indicator) Element.hide(this.options.indicator); - }, - - onKeyPress: function(event) { - if(this.active) - switch(event.keyCode) { - case Event.KEY_TAB: - case Event.KEY_RETURN: - this.selectEntry(); - Event.stop(event); - case Event.KEY_ESC: - this.hide(); - this.active = false; - Event.stop(event); - return; - case Event.KEY_LEFT: - case Event.KEY_RIGHT: - return; - case Event.KEY_UP: - this.markPrevious(); - this.render(); - Event.stop(event); - return; - case Event.KEY_DOWN: - this.markNext(); - this.render(); - Event.stop(event); - return; - } - else - if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || - (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; - - this.changed = true; - this.hasFocus = true; - - if(this.observer) clearTimeout(this.observer); - this.observer = - setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); - }, - - activate: function() { - this.changed = false; - this.hasFocus = true; - this.getUpdatedChoices(); - }, - - onHover: function(event) { - var element = Event.findElement(event, 'LI'); - if(this.index != element.autocompleteIndex) - { - this.index = element.autocompleteIndex; - this.render(); - } - Event.stop(event); - }, - - onClick: function(event) { - var element = Event.findElement(event, 'LI'); - this.index = element.autocompleteIndex; - this.selectEntry(); - this.hide(); - }, - - onBlur: function(event) { - // needed to make click events working - setTimeout(this.hide.bind(this), 250); - this.hasFocus = false; - this.active = false; - }, - - render: function() { - if(this.entryCount > 0) { - for (var i = 0; i < this.entryCount; i++) - this.index==i ? - Element.addClassName(this.getEntry(i),"selected") : - Element.removeClassName(this.getEntry(i),"selected"); - if(this.hasFocus) { - this.show(); - this.active = true; - } - } else { - this.active = false; - this.hide(); - } - }, - - markPrevious: function() { - if(this.index > 0) this.index--; - else this.index = this.entryCount-1; - this.getEntry(this.index).scrollIntoView(true); - }, - - markNext: function() { - if(this.index < this.entryCount-1) this.index++; - else this.index = 0; - this.getEntry(this.index).scrollIntoView(false); - }, - - getEntry: function(index) { - return this.update.firstChild.childNodes[index]; - }, - - getCurrentEntry: function() { - return this.getEntry(this.index); - }, - - selectEntry: function() { - this.active = false; - this.updateElement(this.getCurrentEntry()); - }, - - updateElement: function(selectedElement) { - if (this.options.updateElement) { - this.options.updateElement(selectedElement); - return; - } - var value = ''; - if (this.options.select) { - var nodes = $(selectedElement).select('.' + this.options.select) || []; - if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); - } else - value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); - - var bounds = this.getTokenBounds(); - if (bounds[0] != -1) { - var newValue = this.element.value.substr(0, bounds[0]); - var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); - if (whitespace) - newValue += whitespace[0]; - this.element.value = newValue + value + this.element.value.substr(bounds[1]); - } else { - this.element.value = value; - } - this.oldElementValue = this.element.value; - this.element.focus(); - - if (this.options.afterUpdateElement) - this.options.afterUpdateElement(this.element, selectedElement); - }, - - updateChoices: function(choices) { - if(!this.changed && this.hasFocus) { - this.update.innerHTML = choices; - Element.cleanWhitespace(this.update); - Element.cleanWhitespace(this.update.down()); - - if(this.update.firstChild && this.update.down().childNodes) { - this.entryCount = - this.update.down().childNodes.length; - for (var i = 0; i < this.entryCount; i++) { - var entry = this.getEntry(i); - entry.autocompleteIndex = i; - this.addObservers(entry); - } - } else { - this.entryCount = 0; - } - - this.stopIndicator(); - this.index = 0; - - if(this.entryCount==1 && this.options.autoSelect) { - this.selectEntry(); - this.hide(); - } else { - this.render(); - } - } - }, - - addObservers: function(element) { - Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); - Event.observe(element, "click", this.onClick.bindAsEventListener(this)); - }, - - onObserverEvent: function() { - this.changed = false; - this.tokenBounds = null; - if(this.getToken().length>=this.options.minChars) { - this.getUpdatedChoices(); - } else { - this.active = false; - this.hide(); - } - this.oldElementValue = this.element.value; - }, - - getToken: function() { - var bounds = this.getTokenBounds(); - return this.element.value.substring(bounds[0], bounds[1]).strip(); - }, - - getTokenBounds: function() { - if (null != this.tokenBounds) return this.tokenBounds; - var value = this.element.value; - if (value.strip().empty()) return [-1, 0]; - var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); - var offset = (diff == this.oldElementValue.length ? 1 : 0); - var prevTokenPos = -1, nextTokenPos = value.length; - var tp; - for (var index = 0, l = this.options.tokens.length; index < l; ++index) { - tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); - if (tp > prevTokenPos) prevTokenPos = tp; - tp = value.indexOf(this.options.tokens[index], diff + offset); - if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; - } - return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); - } -}); - -Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { - var boundary = Math.min(newS.length, oldS.length); - for (var index = 0; index < boundary; ++index) - if (newS[index] != oldS[index]) - return index; - return boundary; -}; - -Ajax.Autocompleter = Class.create(Autocompleter.Base, { - initialize: function(element, update, url, options) { - this.baseInitialize(element, update, options); - this.options.asynchronous = true; - this.options.onComplete = this.onComplete.bind(this); - this.options.defaultParams = this.options.parameters || null; - this.url = url; - }, - - getUpdatedChoices: function() { - this.startIndicator(); - - var entry = encodeURIComponent(this.options.paramName) + '=' + - encodeURIComponent(this.getToken()); - - this.options.parameters = this.options.callback ? - this.options.callback(this.element, entry) : entry; - - if(this.options.defaultParams) - this.options.parameters += '&' + this.options.defaultParams; - - new Ajax.Request(this.url, this.options); - }, - - onComplete: function(request) { - this.updateChoices(request.responseText); - } -}); - -// The local array autocompleter. Used when you'd prefer to -// inject an array of autocompletion options into the page, rather -// than sending out Ajax queries, which can be quite slow sometimes. -// -// The constructor takes four parameters. The first two are, as usual, -// the id of the monitored textbox, and id of the autocompletion menu. -// The third is the array you want to autocomplete from, and the fourth -// is the options block. -// -// Extra local autocompletion options: -// - choices - How many autocompletion choices to offer -// -// - partialSearch - If false, the autocompleter will match entered -// text only at the beginning of strings in the -// autocomplete array. Defaults to true, which will -// match text at the beginning of any *word* in the -// strings in the autocomplete array. If you want to -// search anywhere in the string, additionally set -// the option fullSearch to true (default: off). -// -// - fullSsearch - Search anywhere in autocomplete array strings. -// -// - partialChars - How many characters to enter before triggering -// a partial match (unlike minChars, which defines -// how many characters are required to do any match -// at all). Defaults to 2. -// -// - ignoreCase - Whether to ignore case when autocompleting. -// Defaults to true. -// -// It's possible to pass in a custom function as the 'selector' -// option, if you prefer to write your own autocompletion logic. -// In that case, the other options above will not apply unless -// you support them. - -Autocompleter.Local = Class.create(Autocompleter.Base, { - initialize: function(element, update, array, options) { - this.baseInitialize(element, update, options); - this.options.array = array; - }, - - getUpdatedChoices: function() { - this.updateChoices(this.options.selector(this)); - }, - - setOptions: function(options) { - this.options = Object.extend({ - choices: 10, - partialSearch: true, - partialChars: 2, - ignoreCase: true, - fullSearch: false, - selector: function(instance) { - var ret = []; // Beginning matches - var partial = []; // Inside matches - var entry = instance.getToken(); - var count = 0; - - for (var i = 0; i < instance.options.array.length && - ret.length < instance.options.choices ; i++) { - - var elem = instance.options.array[i]; - var foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase()) : - elem.indexOf(entry); - - while (foundPos != -1) { - if (foundPos == 0 && elem.length != entry.length) { - ret.push("
  • " + elem.substr(0, entry.length) + "" + - elem.substr(entry.length) + "
  • "); - break; - } else if (entry.length >= instance.options.partialChars && - instance.options.partialSearch && foundPos != -1) { - if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { - partial.push("
  • " + elem.substr(0, foundPos) + "" + - elem.substr(foundPos, entry.length) + "" + elem.substr( - foundPos + entry.length) + "
  • "); - break; - } - } - - foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : - elem.indexOf(entry, foundPos + 1); - - } - } - if (partial.length) - ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); - return ""; - } - }, options || { }); - } -}); - -// AJAX in-place editor and collection editor -// Full rewrite by Christophe Porteneuve (April 2007). - -// Use this if you notice weird scrolling problems on some browsers, -// the DOM might be a bit confused when this gets called so do this -// waits 1 ms (with setTimeout) until it does the activation -Field.scrollFreeActivate = function(field) { - setTimeout(function() { - Field.activate(field); - }, 1); -}; - -Ajax.InPlaceEditor = Class.create({ - initialize: function(element, url, options) { - this.url = url; - this.element = element = $(element); - this.prepareOptions(); - this._controls = { }; - arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! - Object.extend(this.options, options || { }); - if (!this.options.formId && this.element.id) { - this.options.formId = this.element.id + '-inplaceeditor'; - if ($(this.options.formId)) - this.options.formId = ''; - } - if (this.options.externalControl) - this.options.externalControl = $(this.options.externalControl); - if (!this.options.externalControl) - this.options.externalControlOnly = false; - this._originalBackground = this.element.getStyle('background-color') || 'transparent'; - this.element.title = this.options.clickToEditText; - this._boundCancelHandler = this.handleFormCancellation.bind(this); - this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); - this._boundFailureHandler = this.handleAJAXFailure.bind(this); - this._boundSubmitHandler = this.handleFormSubmission.bind(this); - this._boundWrapperHandler = this.wrapUp.bind(this); - this.registerListeners(); - }, - checkForEscapeOrReturn: function(e) { - if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; - if (Event.KEY_ESC == e.keyCode) - this.handleFormCancellation(e); - else if (Event.KEY_RETURN == e.keyCode) - this.handleFormSubmission(e); - }, - createControl: function(mode, handler, extraClasses) { - var control = this.options[mode + 'Control']; - var text = this.options[mode + 'Text']; - if ('button' == control) { - var btn = document.createElement('input'); - btn.type = 'submit'; - btn.value = text; - btn.className = 'editor_' + mode + '_button'; - if ('cancel' == mode) - btn.onclick = this._boundCancelHandler; - this._form.appendChild(btn); - this._controls[mode] = btn; - } else if ('link' == control) { - var link = document.createElement('a'); - link.href = '#'; - link.appendChild(document.createTextNode(text)); - link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; - link.className = 'editor_' + mode + '_link'; - if (extraClasses) - link.className += ' ' + extraClasses; - this._form.appendChild(link); - this._controls[mode] = link; - } - }, - createEditField: function() { - var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); - var fld; - if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { - fld = document.createElement('input'); - fld.type = 'text'; - var size = this.options.size || this.options.cols || 0; - if (0 < size) fld.size = size; - } else { - fld = document.createElement('textarea'); - fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); - fld.cols = this.options.cols || 40; - } - fld.name = this.options.paramName; - fld.value = text; // No HTML breaks conversion anymore - fld.className = 'editor_field'; - if (this.options.submitOnBlur) - fld.onblur = this._boundSubmitHandler; - this._controls.editor = fld; - if (this.options.loadTextURL) - this.loadExternalText(); - this._form.appendChild(this._controls.editor); - }, - createForm: function() { - var ipe = this; - function addText(mode, condition) { - var text = ipe.options['text' + mode + 'Controls']; - if (!text || condition === false) return; - ipe._form.appendChild(document.createTextNode(text)); - }; - this._form = $(document.createElement('form')); - this._form.id = this.options.formId; - this._form.addClassName(this.options.formClassName); - this._form.onsubmit = this._boundSubmitHandler; - this.createEditField(); - if ('textarea' == this._controls.editor.tagName.toLowerCase()) - this._form.appendChild(document.createElement('br')); - if (this.options.onFormCustomization) - this.options.onFormCustomization(this, this._form); - addText('Before', this.options.okControl || this.options.cancelControl); - this.createControl('ok', this._boundSubmitHandler); - addText('Between', this.options.okControl && this.options.cancelControl); - this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); - addText('After', this.options.okControl || this.options.cancelControl); - }, - destroy: function() { - if (this._oldInnerHTML) - this.element.innerHTML = this._oldInnerHTML; - this.leaveEditMode(); - this.unregisterListeners(); - }, - enterEditMode: function(e) { - if (this._saving || this._editing) return; - this._editing = true; - this.triggerCallback('onEnterEditMode'); - if (this.options.externalControl) - this.options.externalControl.hide(); - this.element.hide(); - this.createForm(); - this.element.parentNode.insertBefore(this._form, this.element); - if (!this.options.loadTextURL) - this.postProcessEditField(); - if (e) Event.stop(e); - }, - enterHover: function(e) { - if (this.options.hoverClassName) - this.element.addClassName(this.options.hoverClassName); - if (this._saving) return; - this.triggerCallback('onEnterHover'); - }, - getText: function() { - return this.element.innerHTML.unescapeHTML(); - }, - handleAJAXFailure: function(transport) { - this.triggerCallback('onFailure', transport); - if (this._oldInnerHTML) { - this.element.innerHTML = this._oldInnerHTML; - this._oldInnerHTML = null; - } - }, - handleFormCancellation: function(e) { - this.wrapUp(); - if (e) Event.stop(e); - }, - handleFormSubmission: function(e) { - var form = this._form; - var value = $F(this._controls.editor); - this.prepareSubmission(); - var params = this.options.callback(form, value) || ''; - if (Object.isString(params)) - params = params.toQueryParams(); - params.editorId = this.element.id; - if (this.options.htmlResponse) { - var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); - Object.extend(options, { - parameters: params, - onComplete: this._boundWrapperHandler, - onFailure: this._boundFailureHandler - }); - new Ajax.Updater({ success: this.element }, this.url, options); - } else { - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: params, - onComplete: this._boundWrapperHandler, - onFailure: this._boundFailureHandler - }); - new Ajax.Request(this.url, options); - } - if (e) Event.stop(e); - }, - leaveEditMode: function() { - this.element.removeClassName(this.options.savingClassName); - this.removeForm(); - this.leaveHover(); - this.element.style.backgroundColor = this._originalBackground; - this.element.show(); - if (this.options.externalControl) - this.options.externalControl.show(); - this._saving = false; - this._editing = false; - this._oldInnerHTML = null; - this.triggerCallback('onLeaveEditMode'); - }, - leaveHover: function(e) { - if (this.options.hoverClassName) - this.element.removeClassName(this.options.hoverClassName); - if (this._saving) return; - this.triggerCallback('onLeaveHover'); - }, - loadExternalText: function() { - this._form.addClassName(this.options.loadingClassName); - this._controls.editor.disabled = true; - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: 'editorId=' + encodeURIComponent(this.element.id), - onComplete: Prototype.emptyFunction, - onSuccess: function(transport) { - this._form.removeClassName(this.options.loadingClassName); - var text = transport.responseText; - if (this.options.stripLoadedTextTags) - text = text.stripTags(); - this._controls.editor.value = text; - this._controls.editor.disabled = false; - this.postProcessEditField(); - }.bind(this), - onFailure: this._boundFailureHandler - }); - new Ajax.Request(this.options.loadTextURL, options); - }, - postProcessEditField: function() { - var fpc = this.options.fieldPostCreation; - if (fpc) - $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); - }, - prepareOptions: function() { - this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); - Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); - [this._extraDefaultOptions].flatten().compact().each(function(defs) { - Object.extend(this.options, defs); - }.bind(this)); - }, - prepareSubmission: function() { - this._saving = true; - this.removeForm(); - this.leaveHover(); - this.showSaving(); - }, - registerListeners: function() { - this._listeners = { }; - var listener; - $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { - listener = this[pair.value].bind(this); - this._listeners[pair.key] = listener; - if (!this.options.externalControlOnly) - this.element.observe(pair.key, listener); - if (this.options.externalControl) - this.options.externalControl.observe(pair.key, listener); - }.bind(this)); - }, - removeForm: function() { - if (!this._form) return; - this._form.remove(); - this._form = null; - this._controls = { }; - }, - showSaving: function() { - this._oldInnerHTML = this.element.innerHTML; - this.element.innerHTML = this.options.savingText; - this.element.addClassName(this.options.savingClassName); - this.element.style.backgroundColor = this._originalBackground; - this.element.show(); - }, - triggerCallback: function(cbName, arg) { - if ('function' == typeof this.options[cbName]) { - this.options[cbName](this, arg); - } - }, - unregisterListeners: function() { - $H(this._listeners).each(function(pair) { - if (!this.options.externalControlOnly) - this.element.stopObserving(pair.key, pair.value); - if (this.options.externalControl) - this.options.externalControl.stopObserving(pair.key, pair.value); - }.bind(this)); - }, - wrapUp: function(transport) { - this.leaveEditMode(); - // Can't use triggerCallback due to backward compatibility: requires - // binding + direct element - this._boundComplete(transport, this.element); - } -}); - -Object.extend(Ajax.InPlaceEditor.prototype, { - dispose: Ajax.InPlaceEditor.prototype.destroy -}); - -Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { - initialize: function($super, element, url, options) { - this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; - $super(element, url, options); - }, - - createEditField: function() { - var list = document.createElement('select'); - list.name = this.options.paramName; - list.size = 1; - this._controls.editor = list; - this._collection = this.options.collection || []; - if (this.options.loadCollectionURL) - this.loadCollection(); - else - this.checkForExternalText(); - this._form.appendChild(this._controls.editor); - }, - - loadCollection: function() { - this._form.addClassName(this.options.loadingClassName); - this.showLoadingText(this.options.loadingCollectionText); - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: 'editorId=' + encodeURIComponent(this.element.id), - onComplete: Prototype.emptyFunction, - onSuccess: function(transport) { - var js = transport.responseText.strip(); - if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check - throw('Server returned an invalid collection representation.'); - this._collection = eval(js); - this.checkForExternalText(); - }.bind(this), - onFailure: this.onFailure - }); - new Ajax.Request(this.options.loadCollectionURL, options); - }, - - showLoadingText: function(text) { - this._controls.editor.disabled = true; - var tempOption = this._controls.editor.firstChild; - if (!tempOption) { - tempOption = document.createElement('option'); - tempOption.value = ''; - this._controls.editor.appendChild(tempOption); - tempOption.selected = true; - } - tempOption.update((text || '').stripScripts().stripTags()); - }, - - checkForExternalText: function() { - this._text = this.getText(); - if (this.options.loadTextURL) - this.loadExternalText(); - else - this.buildOptionList(); - }, - - loadExternalText: function() { - this.showLoadingText(this.options.loadingText); - var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); - Object.extend(options, { - parameters: 'editorId=' + encodeURIComponent(this.element.id), - onComplete: Prototype.emptyFunction, - onSuccess: function(transport) { - this._text = transport.responseText.strip(); - this.buildOptionList(); - }.bind(this), - onFailure: this.onFailure - }); - new Ajax.Request(this.options.loadTextURL, options); - }, - - buildOptionList: function() { - this._form.removeClassName(this.options.loadingClassName); - this._collection = this._collection.map(function(entry) { - return 2 === entry.length ? entry : [entry, entry].flatten(); - }); - var marker = ('value' in this.options) ? this.options.value : this._text; - var textFound = this._collection.any(function(entry) { - return entry[0] == marker; - }.bind(this)); - this._controls.editor.update(''); - var option; - this._collection.each(function(entry, index) { - option = document.createElement('option'); - option.value = entry[0]; - option.selected = textFound ? entry[0] == marker : 0 == index; - option.appendChild(document.createTextNode(entry[1])); - this._controls.editor.appendChild(option); - }.bind(this)); - this._controls.editor.disabled = false; - Field.scrollFreeActivate(this._controls.editor); - } -}); - -//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** -//**** This only exists for a while, in order to let **** -//**** users adapt to the new API. Read up on the new **** -//**** API and convert your code to it ASAP! **** - -Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { - if (!options) return; - function fallback(name, expr) { - if (name in options || expr === undefined) return; - options[name] = expr; - }; - fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : - options.cancelLink == options.cancelButton == false ? false : undefined))); - fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : - options.okLink == options.okButton == false ? false : undefined))); - fallback('highlightColor', options.highlightcolor); - fallback('highlightEndColor', options.highlightendcolor); -}; - -Object.extend(Ajax.InPlaceEditor, { - DefaultOptions: { - ajaxOptions: { }, - autoRows: 3, // Use when multi-line w/ rows == 1 - cancelControl: 'link', // 'link'|'button'|false - cancelText: 'cancel', - clickToEditText: 'Click to edit', - externalControl: null, // id|elt - externalControlOnly: false, - fieldPostCreation: 'activate', // 'activate'|'focus'|false - formClassName: 'inplaceeditor-form', - formId: null, // id|elt - highlightColor: '#ffff99', - highlightEndColor: '#ffffff', - hoverClassName: '', - htmlResponse: true, - loadingClassName: 'inplaceeditor-loading', - loadingText: 'Loading...', - okControl: 'button', // 'link'|'button'|false - okText: 'ok', - paramName: 'value', - rows: 1, // If 1 and multi-line, uses autoRows - savingClassName: 'inplaceeditor-saving', - savingText: 'Saving...', - size: 0, - stripLoadedTextTags: false, - submitOnBlur: false, - textAfterControls: '', - textBeforeControls: '', - textBetweenControls: '' - }, - DefaultCallbacks: { - callback: function(form) { - return Form.serialize(form); - }, - onComplete: function(transport, element) { - // For backward compatibility, this one is bound to the IPE, and passes - // the element directly. It was too often customized, so we don't break it. - new Effect.Highlight(element, { - startcolor: this.options.highlightColor, keepBackgroundImage: true }); - }, - onEnterEditMode: null, - onEnterHover: function(ipe) { - ipe.element.style.backgroundColor = ipe.options.highlightColor; - if (ipe._effect) - ipe._effect.cancel(); - }, - onFailure: function(transport, ipe) { - alert('Error communication with the server: ' + transport.responseText.stripTags()); - }, - onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. - onLeaveEditMode: null, - onLeaveHover: function(ipe) { - ipe._effect = new Effect.Highlight(ipe.element, { - startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, - restorecolor: ipe._originalBackground, keepBackgroundImage: true - }); - } - }, - Listeners: { - click: 'enterEditMode', - keydown: 'checkForEscapeOrReturn', - mouseover: 'enterHover', - mouseout: 'leaveHover' - } -}); - -Ajax.InPlaceCollectionEditor.DefaultOptions = { - loadingCollectionText: 'Loading options...' -}; - -// Delayed observer, like Form.Element.Observer, -// but waits for delay after last key input -// Ideal for live-search fields - -Form.Element.DelayedObserver = Class.create({ - initialize: function(element, delay, callback) { - this.delay = delay || 0.5; - this.element = $(element); - this.callback = callback; - this.timer = null; - this.lastValue = $F(this.element); - Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); - }, - delayedListener: function(event) { - if(this.lastValue == $F(this.element)) return; - if(this.timer) clearTimeout(this.timer); - this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); - this.lastValue = $F(this.element); - }, - onTimerEvent: function() { - this.timer = null; - this.callback(this.element, $F(this.element)); - } -}); \ No newline at end of file diff --git a/lib/scriptaculous/effects.js b/lib/scriptaculous/effects.js deleted file mode 100644 index 860ddc093..000000000 --- a/lib/scriptaculous/effects.js +++ /dev/null @@ -1,1123 +0,0 @@ -// script.aculo.us effects.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010 - -// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// Contributors: -// Justin Palmer (http://encytemedia.com/) -// Mark Pilgrim (http://diveintomark.org/) -// Martin Bialasinki -// -// script.aculo.us is freely distributable under the terms of an MIT-style license. -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -// converts rgb() and #xxx to #xxxxxx format, -// returns self (or first argument) if not convertable -String.prototype.parseColor = function() { - var color = '#'; - if (this.slice(0,4) == 'rgb(') { - var cols = this.slice(4,this.length-1).split(','); - var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); - } else { - if (this.slice(0,1) == '#') { - if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); - if (this.length==7) color = this.toLowerCase(); - } - } - return (color.length==7 ? color : (arguments[0] || this)); -}; - -/*--------------------------------------------------------------------------*/ - -Element.collectTextNodes = function(element) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); - }).flatten().join(''); -}; - -Element.collectTextNodesIgnoreClass = function(element, className) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? - Element.collectTextNodesIgnoreClass(node, className) : '')); - }).flatten().join(''); -}; - -Element.setContentZoom = function(element, percent) { - element = $(element); - element.setStyle({fontSize: (percent/100) + 'em'}); - if (Prototype.Browser.WebKit) window.scrollBy(0,0); - return element; -}; - -Element.getInlineOpacity = function(element){ - return $(element).style.opacity || ''; -}; - -Element.forceRerendering = function(element) { - try { - element = $(element); - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch(e) { } -}; - -/*--------------------------------------------------------------------------*/ - -var Effect = { - _elementDoesNotExistError: { - name: 'ElementDoesNotExistError', - message: 'The specified DOM element does not exist, but is required for this effect to operate' - }, - Transitions: { - linear: Prototype.K, - sinoidal: function(pos) { - return (-Math.cos(pos*Math.PI)/2) + .5; - }, - reverse: function(pos) { - return 1-pos; - }, - flicker: function(pos) { - var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; - return pos > 1 ? 1 : pos; - }, - wobble: function(pos) { - return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; - }, - pulse: function(pos, pulses) { - return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; - }, - spring: function(pos) { - return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); - }, - none: function(pos) { - return 0; - }, - full: function(pos) { - return 1; - } - }, - DefaultOptions: { - duration: 1.0, // seconds - fps: 100, // 100= assume 66fps max. - sync: false, // true for combining - from: 0.0, - to: 1.0, - delay: 0.0, - queue: 'parallel' - }, - tagifyText: function(element) { - var tagifyStyle = 'position:relative'; - if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; - - element = $(element); - $A(element.childNodes).each( function(child) { - if (child.nodeType==3) { - child.nodeValue.toArray().each( function(character) { - element.insertBefore( - new Element('span', {style: tagifyStyle}).update( - character == ' ' ? String.fromCharCode(160) : character), - child); - }); - Element.remove(child); - } - }); - }, - multiple: function(element, effect) { - var elements; - if (((typeof element == 'object') || - Object.isFunction(element)) && - (element.length)) - elements = element; - else - elements = $(element).childNodes; - - var options = Object.extend({ - speed: 0.1, - delay: 0.0 - }, arguments[2] || { }); - var masterDelay = options.delay; - - $A(elements).each( function(element, index) { - new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); - }); - }, - PAIRS: { - 'slide': ['SlideDown','SlideUp'], - 'blind': ['BlindDown','BlindUp'], - 'appear': ['Appear','Fade'] - }, - toggle: function(element, effect, options) { - element = $(element); - effect = (effect || 'appear').toLowerCase(); - - return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({ - queue: { position:'end', scope:(element.id || 'global'), limit: 1 } - }, options || {})); - } -}; - -Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; - -/* ------------- core effects ------------- */ - -Effect.ScopedQueue = Class.create(Enumerable, { - initialize: function() { - this.effects = []; - this.interval = null; - }, - _each: function(iterator) { - this.effects._each(iterator); - }, - add: function(effect) { - var timestamp = new Date().getTime(); - - var position = Object.isString(effect.options.queue) ? - effect.options.queue : effect.options.queue.position; - - switch(position) { - case 'front': - // move unstarted effects after this effect - this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { - e.startOn += effect.finishOn; - e.finishOn += effect.finishOn; - }); - break; - case 'with-last': - timestamp = this.effects.pluck('startOn').max() || timestamp; - break; - case 'end': - // start effect after last queued effect has finished - timestamp = this.effects.pluck('finishOn').max() || timestamp; - break; - } - - effect.startOn += timestamp; - effect.finishOn += timestamp; - - if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) - this.effects.push(effect); - - if (!this.interval) - this.interval = setInterval(this.loop.bind(this), 15); - }, - remove: function(effect) { - this.effects = this.effects.reject(function(e) { return e==effect }); - if (this.effects.length == 0) { - clearInterval(this.interval); - this.interval = null; - } - }, - loop: function() { - var timePos = new Date().getTime(); - for(var i=0, len=this.effects.length;i= this.startOn) { - if (timePos >= this.finishOn) { - this.render(1.0); - this.cancel(); - this.event('beforeFinish'); - if (this.finish) this.finish(); - this.event('afterFinish'); - return; - } - var pos = (timePos - this.startOn) / this.totalTime, - frame = (pos * this.totalFrames).round(); - if (frame > this.currentFrame) { - this.render(pos); - this.currentFrame = frame; - } - } - }, - cancel: function() { - if (!this.options.sync) - Effect.Queues.get(Object.isString(this.options.queue) ? - 'global' : this.options.queue.scope).remove(this); - this.state = 'finished'; - }, - event: function(eventName) { - if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); - if (this.options[eventName]) this.options[eventName](this); - }, - inspect: function() { - var data = $H(); - for(property in this) - if (!Object.isFunction(this[property])) data.set(property, this[property]); - return '#'; - } -}); - -Effect.Parallel = Class.create(Effect.Base, { - initialize: function(effects) { - this.effects = effects || []; - this.start(arguments[1]); - }, - update: function(position) { - this.effects.invoke('render', position); - }, - finish: function(position) { - this.effects.each( function(effect) { - effect.render(1.0); - effect.cancel(); - effect.event('beforeFinish'); - if (effect.finish) effect.finish(position); - effect.event('afterFinish'); - }); - } -}); - -Effect.Tween = Class.create(Effect.Base, { - initialize: function(object, from, to) { - object = Object.isString(object) ? $(object) : object; - var args = $A(arguments), method = args.last(), - options = args.length == 5 ? args[3] : null; - this.method = Object.isFunction(method) ? method.bind(object) : - Object.isFunction(object[method]) ? object[method].bind(object) : - function(value) { object[method] = value }; - this.start(Object.extend({ from: from, to: to }, options || { })); - }, - update: function(position) { - this.method(position); - } -}); - -Effect.Event = Class.create(Effect.Base, { - initialize: function() { - this.start(Object.extend({ duration: 0 }, arguments[0] || { })); - }, - update: Prototype.emptyFunction -}); - -Effect.Opacity = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - // make this work on IE on elements without 'layout' - if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) - this.element.setStyle({zoom: 1}); - var options = Object.extend({ - from: this.element.getOpacity() || 0.0, - to: 1.0 - }, arguments[1] || { }); - this.start(options); - }, - update: function(position) { - this.element.setOpacity(position); - } -}); - -Effect.Move = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - x: 0, - y: 0, - mode: 'relative' - }, arguments[1] || { }); - this.start(options); - }, - setup: function() { - this.element.makePositioned(); - this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); - this.originalTop = parseFloat(this.element.getStyle('top') || '0'); - if (this.options.mode == 'absolute') { - this.options.x = this.options.x - this.originalLeft; - this.options.y = this.options.y - this.originalTop; - } - }, - update: function(position) { - this.element.setStyle({ - left: (this.options.x * position + this.originalLeft).round() + 'px', - top: (this.options.y * position + this.originalTop).round() + 'px' - }); - } -}); - -// for backwards compatibility -Effect.MoveBy = function(element, toTop, toLeft) { - return new Effect.Move(element, - Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); -}; - -Effect.Scale = Class.create(Effect.Base, { - initialize: function(element, percent) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - scaleX: true, - scaleY: true, - scaleContent: true, - scaleFromCenter: false, - scaleMode: 'box', // 'box' or 'contents' or { } with provided values - scaleFrom: 100.0, - scaleTo: percent - }, arguments[2] || { }); - this.start(options); - }, - setup: function() { - this.restoreAfterFinish = this.options.restoreAfterFinish || false; - this.elementPositioning = this.element.getStyle('position'); - - this.originalStyle = { }; - ['top','left','width','height','fontSize'].each( function(k) { - this.originalStyle[k] = this.element.style[k]; - }.bind(this)); - - this.originalTop = this.element.offsetTop; - this.originalLeft = this.element.offsetLeft; - - var fontSize = this.element.getStyle('font-size') || '100%'; - ['em','px','%','pt'].each( function(fontSizeType) { - if (fontSize.indexOf(fontSizeType)>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = fontSizeType; - } - }.bind(this)); - - this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; - - this.dims = null; - if (this.options.scaleMode=='box') - this.dims = [this.element.offsetHeight, this.element.offsetWidth]; - if (/^content/.test(this.options.scaleMode)) - this.dims = [this.element.scrollHeight, this.element.scrollWidth]; - if (!this.dims) - this.dims = [this.options.scaleMode.originalHeight, - this.options.scaleMode.originalWidth]; - }, - update: function(position) { - var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); - if (this.options.scaleContent && this.fontSize) - this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); - this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); - }, - finish: function(position) { - if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); - }, - setDimensions: function(height, width) { - var d = { }; - if (this.options.scaleX) d.width = width.round() + 'px'; - if (this.options.scaleY) d.height = height.round() + 'px'; - if (this.options.scaleFromCenter) { - var topd = (height - this.dims[0])/2; - var leftd = (width - this.dims[1])/2; - if (this.elementPositioning == 'absolute') { - if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; - if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; - } else { - if (this.options.scaleY) d.top = -topd + 'px'; - if (this.options.scaleX) d.left = -leftd + 'px'; - } - } - this.element.setStyle(d); - } -}); - -Effect.Highlight = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); - this.start(options); - }, - setup: function() { - // Prevent executing on elements not in the layout flow - if (this.element.getStyle('display')=='none') { this.cancel(); return; } - // Disable background image during the effect - this.oldStyle = { }; - if (!this.options.keepBackgroundImage) { - this.oldStyle.backgroundImage = this.element.getStyle('background-image'); - this.element.setStyle({backgroundImage: 'none'}); - } - if (!this.options.endcolor) - this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); - if (!this.options.restorecolor) - this.options.restorecolor = this.element.getStyle('background-color'); - // init color calculations - this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); - this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); - }, - update: function(position) { - this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ - return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); - }, - finish: function() { - this.element.setStyle(Object.extend(this.oldStyle, { - backgroundColor: this.options.restorecolor - })); - } -}); - -Effect.ScrollTo = function(element) { - var options = arguments[1] || { }, - scrollOffsets = document.viewport.getScrollOffsets(), - elementOffsets = $(element).cumulativeOffset(); - - if (options.offset) elementOffsets[1] += options.offset; - - return new Effect.Tween(null, - scrollOffsets.top, - elementOffsets[1], - options, - function(p){ scrollTo(scrollOffsets.left, p.round()); } - ); -}; - -/* ------------- combination effects ------------- */ - -Effect.Fade = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - var options = Object.extend({ - from: element.getOpacity() || 1.0, - to: 0.0, - afterFinishInternal: function(effect) { - if (effect.options.to!=0) return; - effect.element.hide().setStyle({opacity: oldOpacity}); - } - }, arguments[1] || { }); - return new Effect.Opacity(element,options); -}; - -Effect.Appear = function(element) { - element = $(element); - var options = Object.extend({ - from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), - to: 1.0, - // force Safari to render floated elements properly - afterFinishInternal: function(effect) { - effect.element.forceRerendering(); - }, - beforeSetup: function(effect) { - effect.element.setOpacity(effect.options.from).show(); - }}, arguments[1] || { }); - return new Effect.Opacity(element,options); -}; - -Effect.Puff = function(element) { - element = $(element); - var oldStyle = { - opacity: element.getInlineOpacity(), - position: element.getStyle('position'), - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height - }; - return new Effect.Parallel( - [ new Effect.Scale(element, 200, - { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], - Object.extend({ duration: 1.0, - beforeSetupInternal: function(effect) { - Position.absolutize(effect.effects[0].element); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().setStyle(oldStyle); } - }, arguments[1] || { }) - ); -}; - -Effect.BlindUp = function(element) { - element = $(element); - element.makeClipping(); - return new Effect.Scale(element, 0, - Object.extend({ scaleContent: false, - scaleX: false, - restoreAfterFinish: true, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }, arguments[1] || { }) - ); -}; - -Effect.BlindDown = function(element) { - element = $(element); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: 0, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping(); - } - }, arguments[1] || { })); -}; - -Effect.SwitchOff = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - return new Effect.Appear(element, Object.extend({ - duration: 0.4, - from: 0, - transition: Effect.Transitions.flicker, - afterFinishInternal: function(effect) { - new Effect.Scale(effect.element, 1, { - duration: 0.3, scaleFromCenter: true, - scaleX: false, scaleContent: false, restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); - } - }); - } - }, arguments[1] || { })); -}; - -Effect.DropOut = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left'), - opacity: element.getInlineOpacity() }; - return new Effect.Parallel( - [ new Effect.Move(element, {x: 0, y: 100, sync: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 }) ], - Object.extend( - { duration: 0.5, - beforeSetup: function(effect) { - effect.effects[0].element.makePositioned(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); - } - }, arguments[1] || { })); -}; - -Effect.Shake = function(element) { - element = $(element); - var options = Object.extend({ - distance: 20, - duration: 0.5 - }, arguments[1] || {}); - var distance = parseFloat(options.distance); - var split = parseFloat(options.duration) / 10.0; - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left') }; - return new Effect.Move(element, - { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { - effect.element.undoPositioned().setStyle(oldStyle); - }}); }}); }}); }}); }}); }}); -}; - -Effect.SlideDown = function(element) { - element = $(element).cleanWhitespace(); - // SlideDown need to have the content of the element wrapped in a container element with fixed height! - var oldInnerBottom = element.down().getStyle('bottom'); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: window.opera ? 0 : 1, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if (window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().setStyle({height: '0px'}).show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping().undoPositioned(); - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } - }, arguments[1] || { }) - ); -}; - -Effect.SlideUp = function(element) { - element = $(element).cleanWhitespace(); - var oldInnerBottom = element.down().getStyle('bottom'); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, window.opera ? 0 : 1, - Object.extend({ scaleContent: false, - scaleX: false, - scaleMode: 'box', - scaleFrom: 100, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makePositioned(); - effect.element.down().makePositioned(); - if (window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping().show(); - }, - afterUpdateInternal: function(effect) { - effect.element.down().setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().undoPositioned(); - effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); - } - }, arguments[1] || { }) - ); -}; - -// Bug in opera makes the TD containing this element expand for a instance after finish -Effect.Squish = function(element) { - return new Effect.Scale(element, window.opera ? 1 : 0, { - restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping(); - } - }); -}; - -Effect.Grow = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.full - }, arguments[1] || { }); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var initialMoveX, initialMoveY; - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - initialMoveX = initialMoveY = moveX = moveY = 0; - break; - case 'top-right': - initialMoveX = dims.width; - initialMoveY = moveY = 0; - moveX = -dims.width; - break; - case 'bottom-left': - initialMoveX = moveX = 0; - initialMoveY = dims.height; - moveY = -dims.height; - break; - case 'bottom-right': - initialMoveX = dims.width; - initialMoveY = dims.height; - moveX = -dims.width; - moveY = -dims.height; - break; - case 'center': - initialMoveX = dims.width / 2; - initialMoveY = dims.height / 2; - moveX = -dims.width / 2; - moveY = -dims.height / 2; - break; - } - - return new Effect.Move(element, { - x: initialMoveX, - y: initialMoveY, - duration: 0.01, - beforeSetup: function(effect) { - effect.element.hide().makeClipping().makePositioned(); - }, - afterFinishInternal: function(effect) { - new Effect.Parallel( - [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), - new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), - new Effect.Scale(effect.element, 100, { - scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, - sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) - ], Object.extend({ - beforeSetup: function(effect) { - effect.effects[0].element.setStyle({height: '0px'}).show(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); - } - }, options) - ); - } - }); -}; - -Effect.Shrink = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.none - }, arguments[1] || { }); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - moveX = moveY = 0; - break; - case 'top-right': - moveX = dims.width; - moveY = 0; - break; - case 'bottom-left': - moveX = 0; - moveY = dims.height; - break; - case 'bottom-right': - moveX = dims.width; - moveY = dims.height; - break; - case 'center': - moveX = dims.width / 2; - moveY = dims.height / 2; - break; - } - - return new Effect.Parallel( - [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), - new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), - new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) - ], Object.extend({ - beforeStartInternal: function(effect) { - effect.effects[0].element.makePositioned().makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } - }, options) - ); -}; - -Effect.Pulsate = function(element) { - element = $(element); - var options = arguments[1] || { }, - oldOpacity = element.getInlineOpacity(), - transition = options.transition || Effect.Transitions.linear, - reverser = function(pos){ - return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); - }; - - return new Effect.Opacity(element, - Object.extend(Object.extend({ duration: 2.0, from: 0, - afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } - }, options), {transition: reverser})); -}; - -Effect.Fold = function(element) { - element = $(element); - var oldStyle = { - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height }; - element.makeClipping(); - return new Effect.Scale(element, 5, Object.extend({ - scaleContent: false, - scaleX: false, - afterFinishInternal: function(effect) { - new Effect.Scale(element, 1, { - scaleContent: false, - scaleY: false, - afterFinishInternal: function(effect) { - effect.element.hide().undoClipping().setStyle(oldStyle); - } }); - }}, arguments[1] || { })); -}; - -Effect.Morph = Class.create(Effect.Base, { - initialize: function(element) { - this.element = $(element); - if (!this.element) throw(Effect._elementDoesNotExistError); - var options = Object.extend({ - style: { } - }, arguments[1] || { }); - - if (!Object.isString(options.style)) this.style = $H(options.style); - else { - if (options.style.include(':')) - this.style = options.style.parseStyle(); - else { - this.element.addClassName(options.style); - this.style = $H(this.element.getStyles()); - this.element.removeClassName(options.style); - var css = this.element.getStyles(); - this.style = this.style.reject(function(style) { - return style.value == css[style.key]; - }); - options.afterFinishInternal = function(effect) { - effect.element.addClassName(effect.options.style); - effect.transforms.each(function(transform) { - effect.element.style[transform.style] = ''; - }); - }; - } - } - this.start(options); - }, - - setup: function(){ - function parseColor(color){ - if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; - color = color.parseColor(); - return $R(0,2).map(function(i){ - return parseInt( color.slice(i*2+1,i*2+3), 16 ); - }); - } - this.transforms = this.style.map(function(pair){ - var property = pair[0], value = pair[1], unit = null; - - if (value.parseColor('#zzzzzz') != '#zzzzzz') { - value = value.parseColor(); - unit = 'color'; - } else if (property == 'opacity') { - value = parseFloat(value); - if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) - this.element.setStyle({zoom: 1}); - } else if (Element.CSS_LENGTH.test(value)) { - var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); - value = parseFloat(components[1]); - unit = (components.length == 3) ? components[2] : null; - } - - var originalValue = this.element.getStyle(property); - return { - style: property.camelize(), - originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), - targetValue: unit=='color' ? parseColor(value) : value, - unit: unit - }; - }.bind(this)).reject(function(transform){ - return ( - (transform.originalValue == transform.targetValue) || - ( - transform.unit != 'color' && - (isNaN(transform.originalValue) || isNaN(transform.targetValue)) - ) - ); - }); - }, - update: function(position) { - var style = { }, transform, i = this.transforms.length; - while(i--) - style[(transform = this.transforms[i]).style] = - transform.unit=='color' ? '#'+ - (Math.round(transform.originalValue[0]+ - (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + - (Math.round(transform.originalValue[1]+ - (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + - (Math.round(transform.originalValue[2]+ - (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : - (transform.originalValue + - (transform.targetValue - transform.originalValue) * position).toFixed(3) + - (transform.unit === null ? '' : transform.unit); - this.element.setStyle(style, true); - } -}); - -Effect.Transform = Class.create({ - initialize: function(tracks){ - this.tracks = []; - this.options = arguments[1] || { }; - this.addTracks(tracks); - }, - addTracks: function(tracks){ - tracks.each(function(track){ - track = $H(track); - var data = track.values().first(); - this.tracks.push($H({ - ids: track.keys().first(), - effect: Effect.Morph, - options: { style: data } - })); - }.bind(this)); - return this; - }, - play: function(){ - return new Effect.Parallel( - this.tracks.map(function(track){ - var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); - var elements = [$(ids) || $$(ids)].flatten(); - return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); - }).flatten(), - this.options - ); - } -}); - -Element.CSS_PROPERTIES = $w( - 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + - 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + - 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + - 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + - 'fontSize fontWeight height left letterSpacing lineHeight ' + - 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ - 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + - 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + - 'right textIndent top width wordSpacing zIndex'); - -Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; - -String.__parseStyleElement = document.createElement('div'); -String.prototype.parseStyle = function(){ - var style, styleRules = $H(); - if (Prototype.Browser.WebKit) - style = new Element('div',{style:this}).style; - else { - String.__parseStyleElement.innerHTML = '
    '; - style = String.__parseStyleElement.childNodes[0].style; - } - - Element.CSS_PROPERTIES.each(function(property){ - if (style[property]) styleRules.set(property, style[property]); - }); - - if (Prototype.Browser.IE && this.include('opacity')) - styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); - - return styleRules; -}; - -if (document.defaultView && document.defaultView.getComputedStyle) { - Element.getStyles = function(element) { - var css = document.defaultView.getComputedStyle($(element), null); - return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { - styles[property] = css[property]; - return styles; - }); - }; -} else { - Element.getStyles = function(element) { - element = $(element); - var css = element.currentStyle, styles; - styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { - results[property] = css[property]; - return results; - }); - if (!styles.opacity) styles.opacity = element.getOpacity(); - return styles; - }; -} - -Effect.Methods = { - morph: function(element, style) { - element = $(element); - new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); - return element; - }, - visualEffect: function(element, effect, options) { - element = $(element); - var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); - new Effect[klass](element, options); - return element; - }, - highlight: function(element, options) { - element = $(element); - new Effect.Highlight(element, options); - return element; - } -}; - -$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ - 'pulsate shake puff squish switchOff dropOut').each( - function(effect) { - Effect.Methods[effect] = function(element, options){ - element = $(element); - Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); - return element; - }; - } -); - -$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( - function(f) { Effect.Methods[f] = Element[f]; } -); - -Element.addMethods(Effect.Methods); \ No newline at end of file diff --git a/lib/scriptaculous/scriptaculous.js b/lib/scriptaculous/scriptaculous.js deleted file mode 100644 index 0ea5c4457..000000000 --- a/lib/scriptaculous/scriptaculous.js +++ /dev/null @@ -1,68 +0,0 @@ -// script.aculo.us scriptaculous.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010 - -// Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// For details, see the script.aculo.us web site: http://script.aculo.us/ - -var Scriptaculous = { - Version: '1.9.0', - require: function(libraryName) { - try{ - // inserting via DOM fails in Safari 2.0, so brute force approach - document.write('