/soc/2015/igor.gajowiak/chatlog: 975639850201: Refactor Template...
Igor Gajowiak
igor.gajowiak at gmail.com
Sat Jun 6 16:40:12 EDT 2015
Changeset: 9756398502012874940852ddb5bd78b89968969d
Author: Igor Gajowiak <igor.gajowiak at gmail.com>
Date: 2015-06-06 22:39 +0200
Branch: default
URL: https://hg.pidgin.im/soc/2015/igor.gajowiak/chatlog/rev/975639850201
Description:
Refactor Template.html
diffstat:
pidgin/themes/Contents/Resources/Incoming/Content.html | 1 -
pidgin/themes/Template.html | 410 +++++-----------
2 files changed, 125 insertions(+), 286 deletions(-)
diffs (truncated from 476 to 300 lines):
diff --git a/pidgin/themes/Contents/Resources/Incoming/Content.html b/pidgin/themes/Contents/Resources/Incoming/Content.html
--- a/pidgin/themes/Contents/Resources/Incoming/Content.html
+++ b/pidgin/themes/Contents/Resources/Incoming/Content.html
@@ -5,4 +5,3 @@
</span>
<span class="x-message">%message%</span>
</div>
-<div id="insert"></div>
diff --git a/pidgin/themes/Template.html b/pidgin/themes/Template.html
--- a/pidgin/themes/Template.html
+++ b/pidgin/themes/Template.html
@@ -3,293 +3,152 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<base href="%@">
+
<script type="text/javascript" defer="defer">
- // NOTE:
- // Any percent signs in this file must be escaped!
- // Use two escape signs (%%) to display it, this is passed through a format call!
- var PURPLE_IMAGE_STORE_PROTOCOL = 'purple-image:';
+ function DeferredInvoker(timeout, maxStackSize) {
+ var self = this;
+ this.timerID = 0;
+ this.stackSize = 0;
- function appendHTML(html) {
- var node = document.getElementById("Chat");
- var range = document.createRange();
- range.selectNode(node);
- var documentFragment = range.createContextualFragment(html);
- node.appendChild(documentFragment);
- }
+ this.invokeDeferred = function (func) {
+ window.clearTimeout(self.timerID);
+ ++self.stackSize;
- // a coalesced HTML object buffers and outputs DOM objects en masse.
- // saves A LOT of CSS recalculation time when loading many messages.
- // (ex. a long twitter timeline)
- function CoalescedHTML() {
- var self = this;
- this.fragment = document.createDocumentFragment();
- this.timeoutID = 0;
- this.coalesceRounds = 0;
- this.isCoalescing = false;
- this.isConsecutive = undefined;
- this.shouldScroll = undefined;
-
- var appendElement = function (elem) {
- document.getElementById("Chat").appendChild(elem);
- };
-
- function outputHTML() {
- var insert = document.getElementById("insert");
- if(!!insert && self.isConsecutive) {
- insert.parentNode.replaceChild(self.fragment, insert);
- } else {
- if(insert)
- insert.parentNode.removeChild(insert);
- // insert the documentFragment into the live DOM
- appendElement(self.fragment);
- }
- alignChat(self.shouldScroll);
-
- // reset state to empty/non-coalescing
- self.shouldScroll = undefined;
- self.isConsecutive = undefined;
- self.isCoalescing = false;
- self.coalesceRounds = 0;
- }
-
- // creates and returns a new documentFragment, containing all content nodes
- // which can be inserted as a single node.
- function createHTMLNode(html) {
- var range = document.createRange();
- range.selectNode(document.getElementById("Chat"));
- return range.createContextualFragment(html);
- }
-
- // removes first insert node from the internal fragment.
- function rmInsertNode() {
- var insert = self.fragment.querySelector("#insert");
- if(insert)
- insert.parentNode.removeChild(insert);
- }
-
- function setShouldScroll(flag) {
- if(flag && undefined === self.shouldScroll)
- self.shouldScroll = flag;
- }
-
- // hook in a custom method to append new data
- // to the chat.
- this.setAppendElementMethod = function (func) {
- if(typeof func === 'function')
- appendElement = func;
- }
-
- // (re)start the coalescing timer.
- // we wait 25ms for a new message to come in.
- // If we get one, restart the timer and wait another 10ms.
- // If not, run outputHTML()
- // We do this a maximum of 400 times, for 10s max that can be spent
- // coalescing input, since this will block display.
- this.coalesce = function() {
- window.clearTimeout(self.timeoutID);
- self.timeoutID = window.setTimeout(outputHTML, 25);
- self.isCoalescing = true;
- self.coalesceRounds += 1;
- if(400 < self.coalesceRounds)
- self.cancel();
- }
-
- // if we need to append content into an insertion div,
- // we need to clear the buffer and cancel the timeout.
- this.cancel = function() {
- if(self.isCoalescing) {
- window.clearTimeout(self.timeoutID);
- outputHTML();
- }
- }
-
-
- // coalased analogs to the global functions
-
- this.append = function(html, shouldScroll) {
- // if we started this fragment with a consecuative message,
- // cancel and output before we continue
- if(self.isConsecutive) {
- self.cancel();
- }
- self.isConsecutive = false;
- rmInsertNode();
- var node = createHTMLNode(html);
- self.fragment.appendChild(node);
-
- node = null;
-
- setShouldScroll(shouldScroll);
- self.coalesce();
- }
-
- this.appendNext = function(html, shouldScroll) {
- if(undefined === self.isConsecutive)
- self.isConsecutive = true;
- var node = createHTMLNode(html);
- var insert = self.fragment.querySelector("#insert");
- if(insert) {
- insert.parentNode.replaceChild(node, insert);
- } else {
- self.fragment.appendChild(node);
- }
- node = null;
- setShouldScroll(shouldScroll);
- self.coalesce();
- }
-
- this.replaceLast = function (html, shouldScroll) {
- rmInsertNode();
- var node = createHTMLNode(html);
- var lastMessage = self.fragment.lastChild;
- lastMessage.parentNode.replaceChild(node, lastMessage);
- node = null;
- setShouldScroll(shouldScroll);
- }
- }
- var coalescedHTML;
-
- //Appending new content to the message view
- function appendMessage(html) {
- var shouldScroll;
-
- // Only call nearBottom() if should scroll is undefined.
- if(undefined === coalescedHTML.shouldScroll) {
- shouldScroll = nearBottom();
- } else {
- shouldScroll = coalescedHTML.shouldScroll;
- }
- appendMessageNoScroll(html, shouldScroll);
- }
-
- function appendMessageNoScroll(html, shouldScroll) {
- shouldScroll = shouldScroll || false;
- // always try to coalesce new, non-griuped, messages
- coalescedHTML.append(html, shouldScroll)
- }
-
- function appendNextMessage(html){
- var shouldScroll;
- if(undefined === coalescedHTML.shouldScroll) {
- shouldScroll = nearBottom();
- } else {
- shouldScroll = coalescedHTML.shouldScroll;
- }
- appendNextMessageNoScroll(html, shouldScroll);
- }
-
- function appendNextMessageNoScroll(html, shouldScroll){
- shouldScroll = shouldScroll || false;
- // only group next messages if we're already coalescing input
- coalescedHTML.appendNext(html, shouldScroll);
- }
-
- function replaceLastMessage(html){
- var shouldScroll;
- // only replace messages if we're already coalescing
- if(coalescedHTML.isCoalescing){
- if(undefined === coalescedHTML.shouldScroll) {
- shouldScroll = nearBottom();
- } else {
- shouldScroll = coalescedHTML.shouldScroll;
- }
- coalescedHTML.replaceLast(html, shouldScroll);
- } else {
- shouldScroll = nearBottom();
- //Retrieve the current insertion point, then remove it
- //This requires that there have been an insertion point... is there a better way to retrieve the last element? -evands
- var insert = document.getElementById("insert");
- if(insert){
- var parentNode = insert.parentNode;
- parentNode.removeChild(insert);
- var lastMessage = document.getElementById("Chat").lastChild;
- document.getElementById("Chat").removeChild(lastMessage);
+ if (self.stackSize >= maxStackSize) {
+ func();
+ self.stackSize = 0;
+ return;
}
- //Now append the message itself
- appendHTML(html);
-
- alignChat(shouldScroll);
+ self.timerID = window.setTimeout(
+ function () { func(); self.stackSize = 0; },
+ timeout);
}
}
- var SCROLLMODE_UNKNOWN = 0;
- var SCROLLMODE_WEBKIT1 = 1;
- var SCROLLMODE_WEBKIT2 = 2;
- var scroll_mode = SCROLLMODE_UNKNOWN;
+ function Scroller() {
+ var self = this;
+ var SCROLLMODE_UNKNOWN = 0;
+ var SCROLLMODE_WEBKIT1 = 1;
+ var SCROLLMODE_WEBKIT2 = 2;
- function detectWebkitScrolling() {
- if (scroll_mode != SCROLLMODE_UNKNOWN)
- return scroll_mode;
- if (document.body.scrollTop > 0)
- scroll_mode = SCROLLMODE_WEBKIT1;
- if (document.documentElement.scrollTop > 0)
- scroll_mode = SCROLLMODE_WEBKIT2;
- return scroll_mode;
- }
-
- var stickyscroll_just_scrolled = false;
- var stickyscroll_just_scrolled_more = false;
- var stickyscroll_to_bottom = true;
- var stickyscroll_to_bottom_new = true;
-
- function windowDidScroll(ev) {
- if (stickyscroll_just_scrolled) {
- stickyscroll_just_scrolled_more = true;
- return;
+ function detectWebkitScrollingMode() {
+ if (document.body.scrollTop > 0)
+ scroll_mode = SCROLLMODE_WEBKIT1;
+ if (document.documentElement.scrollTop > 0)
+ scroll_mode = SCROLLMODE_WEBKIT2;
+ return SCROLLMODE_UNKNOWN;
}
- stickyscroll_just_scrolled = true;
- var update_to_bottom = function() {
- stickyscroll_to_bottom = stickyscroll_to_bottom_new;
+ this.nearBottom = undefined;
+ this.scrollToBottom = undefined;
- var mode = detectWebkitScrolling();
- if (mode == SCROLLMODE_UNKNOWN || mode == SCROLLMODE_WEBKIT1) {
- stickyscroll_to_bottom_new = ( document.body.scrollTop >=
+ // Initialize nearBottom and scrollToBottom
+ var mode = detectWebkitScrollingMode();
+ if (mode == SCROLLMODE_UNKNOWN || mode == SCROLLMODE_WEBKIT1) {
+ this.nearBottom = function () {
+ return ( document.body.scrollTop >=
( document.body.offsetHeight - (window.innerHeight + 20) ) );
- } else { /* SCROLLMODE_WEBKIT2 */
- stickyscroll_to_bottom_new = ( document.documentElement.scrollTop >=
+ }
+ this.scrollToBottom = function() {
+ document.body.scrollTop = document.body.offsetHeight;
+ };
+ }
More information about the Commits
mailing list