/soc/2015/igor.gajowiak/chatlog: 975639850201: Refactor Template...

Igor Gajowiak <[email protected]>
Newsgroups gmane.comp.gnome.gaim.cvs
Message-ID <[email protected]>
Changeset: 9756398502012874940852ddb5bd78b89968969d
Author:	 Igor Gajowiak <[email protected]>
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;
+				};
+			}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.