[Libreoffice-commits] online.git: loleaflet/build loleaflet/debug loleaflet/dist loleaflet/src

Pranav Kant pranavk at collabora.com
Mon Mar 7 10:57:17 UTC 2016


 loleaflet/build/build.js                |   12 +
 loleaflet/debug/document/admin.html     |  128 ++++++++++++++
 loleaflet/debug/document/dashboard.html |  120 -------------
 loleaflet/dist/admin.html               |  128 ++++++++++++++
 loleaflet/dist/bootstrap/dashboard.css  |    3 
 loleaflet/src/admin.js                  |  290 ++++++++++++++++++++++++++++++++
 6 files changed, 560 insertions(+), 121 deletions(-)

New commits:
commit cd58f2a49175adb2aa1544d089afeae73f1051c4
Author: Pranav Kant <pranavk at collabora.com>
Date:   Fri Mar 4 21:36:28 2016 +0530

    loleaflet: Better design for Admin console JS files
    
    Lets have a new websocket class for each websocket type we want
    in admin console inheriting from single abstract base class.
    
    This, hopefully, would provide us with extensibility and ease of
    managing files in future. Right now, there is only one class with
    very less complexity, hence all the code is in one file.
    As the complexity increases, we would need to separate all these
    classes in different files, concat and compress them before moving
    to dist/
    
    Also rename dashboard.html to admin.html
    
    Change-Id: I34b9b2817fe4a0e6ee2913c017d2694a17ab978c
    Reviewed-on: https://gerrit.libreoffice.org/22904
    Reviewed-by: Andras Timar <andras.timar at collabora.com>
    Tested-by: Andras Timar <andras.timar at collabora.com>

diff --git a/loleaflet/build/build.js b/loleaflet/build/build.js
index dc05665..59a765d 100644
--- a/loleaflet/build/build.js
+++ b/loleaflet/build/build.js
@@ -105,6 +105,18 @@ exports.build = function (callback, version, compsBase32, buildName) {
 		console.log('\tSaved to ' + srcPath);
 	}
 
+	// Also copy the admin JS files
+	// For the time being, just copy the file, since there is only one
+	var adminCopy = fs.readFileSync('src/admin.js', 'utf-8'),
+	    adminNewSrc = adminCopy,
+	    adminPath = 'dist/admin-src.js',
+	    adminOldSrc = loadSilently(adminPath);
+
+	if (adminNewSrc != adminOldSrc) {
+		fs.writeFileSync(adminPath, adminNewSrc);
+		console.log('\tAdmin files saved to ' + adminPath);
+	}
+
 	var path = pathPart + '.js',
 	    oldCompressed = loadSilently(path),
 	    newCompressed = copy + UglifyJS.minify(newSrc, {
diff --git a/loleaflet/debug/document/dashboard.html b/loleaflet/debug/document/admin.html
similarity index 68%
rename from loleaflet/debug/document/dashboard.html
rename to loleaflet/debug/document/admin.html
index 41a15a6..9b4e03a 100644
--- a/loleaflet/debug/document/dashboard.html
+++ b/loleaflet/debug/document/admin.html
@@ -27,6 +27,20 @@
   </head>
 
   <body>
+    <script src="../../dist/admin-src.js"></script>
+    <script>
+
+	function getParameterByName(name) {
+		name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
+		var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
+		results = regex.exec(location.search);
+		return results === null ? "" : results[1].replace(/\+/g, " ");
+	}
+
+	var host = getParameterByName('host');
+	new AdminSocketOverview(host);
+
+    </script>
 
     <nav class="navbar navbar-inverse navbar-fixed-top">
       <div class="container-fluid">
@@ -66,43 +80,37 @@
         <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
           <h1 class="page-header">Dashboard</h1>
 
-          <div class="row placeholders">
-            <div class="col-xs-6 col-sm-3 placeholder">
-              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
-              <h4>Users online</h4>
-            </div>
-            <div class="col-xs-6 col-sm-3 placeholder">
-              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
-              <h4>Documents opened</h4>
-            </div>
-            <div class="col-xs-6 col-sm-3 placeholder">
-              <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
-              <h4>Memory consumed</h4>
-            </div>
-          </div>
+	  <div class="row placeholders">
+	    <div class="col-xs-6 col-sm-3 placeholder">
+	      <div class="main-data" id="active_users_count">0</div>
+	      <h4>Users online</h4>
+	    </div>
+	    <div class="col-xs-6 col-sm-3 placeholder">
+	      <div class="main-data" id="active_docs_count">0</div>
+	      <h4>Documents opened</h4>
+	    </div>
+	    <div class="col-xs-6 col-sm-3 placeholder">
+	      <div class="main-data" id="total_mem">0</div>
+	      <h4>Memory consumed</h4>
+	    </div>
+	  </div>
 
-          <h2 class="sub-header">Documents opened</h2>
-          <div class="table-responsive">
-            <table class="table table-striped">
-              <thead>
-                <tr>
-                  <th>PID</th>
-                  <th>Document</th>
-                  <th>Number of views</th>
-                  <th>Memory consumed</th>
-                </tr>
-              </thead>
-              <tbody>
-                <tr>
-                  <td>3456</td>
-                  <td>orig.odt</td>
-                  <td>2</td>
-                  <td>25</td>
-                </tr>
-              </tbody>
-            </table>
-          </div>
-        </div>
+	  <h2 class="sub-header">Documents opened</h2>
+	  <div class="table-responsive">
+	    <table class="table table-striped">
+	      <thead>
+		<tr>
+		  <th>PID</th>
+		  <th>Document</th>
+		  <th>Number of views</th>
+		  <th>Memory consumed</th>
+		</tr>
+	      </thead>
+	      <tbody id="doclist">
+	      </tbody>
+	    </table>
+	  </div>
+	</div>
       </div>
     </div>
 
diff --git a/loleaflet/dist/admin.html b/loleaflet/dist/admin.html
new file mode 100644
index 0000000..07bc074
--- /dev/null
+++ b/loleaflet/dist/admin.html
@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
+    <meta name="description" content="">
+    <meta name="author" content="">
+
+    <title>LibreOffice Online - Admin console</title>
+
+    <!-- Bootstrap core CSS -->
+    <link href="/loleaflet/dist/bootstrap/css/bootstrap.min.css" rel="stylesheet">
+
+    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
+    <link href="/loleaflet/dist/bootstrap/assets/css/ie10-viewport-bug-workaround.css" rel="stylesheet">
+
+    <!-- Custom styles for this template -->
+    <link href="/loleaflet/dist/bootstrap/dashboard.css" rel="stylesheet">
+
+    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
+    <!--[if lt IE 9]>
+      <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+    <![endif]-->
+  </head>
+
+  <body>
+    <script src="/loleaflet/dist/admin-src.js"></script>
+    <script>
+
+	function getParameterByName(name) {
+		name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
+		var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
+		results = regex.exec(location.search);
+		return results === null ? "" : results[1].replace(/\+/g, " ");
+	}
+
+	var host = getParameterByName('host');
+	new AdminSocketOverview(host);
+
+    </script>
+
+    <nav class="navbar navbar-inverse navbar-fixed-top">
+      <div class="container-fluid">
+	<div class="navbar-header">
+	  <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
+	    <span class="sr-only">Toggle navigation</span>
+	    <span class="icon-bar"></span>
+	    <span class="icon-bar"></span>
+	    <span class="icon-bar"></span>
+	  </button>
+	  <a class="navbar-brand" href="#">LibreOffice Online - Admin console</a>
+	</div>
+	<div id="navbar" class="navbar-collapse collapse">
+	  <ul class="nav navbar-nav navbar-right">
+	    <li><a href="#">Dashboard</a></li>
+	    <li><a href="#">Settings</a></li>
+	    <li><a href="#">Profile</a></li>
+	    <li><a href="#">Help</a></li>
+	  </ul>
+	  <form class="navbar-form navbar-right">
+	    <input type="text" class="form-control" placeholder="Search...">
+	  </form>
+	</div>
+      </div>
+    </nav>
+
+    <div class="container-fluid">
+      <div class="row">
+	<div class="col-sm-3 col-md-2 sidebar">
+	  <ul class="nav nav-sidebar">
+	    <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
+	    <li><a href="#">Reports</a></li>
+	    <li><a href="#">Analytics</a></li>
+	    <li><a href="#">Export</a></li>
+	  </ul>
+	</div>
+	<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
+	  <h1 class="page-header">Dashboard</h1>
+
+	  <div class="row placeholders">
+	    <div class="col-xs-6 col-sm-3 placeholder">
+	      <div class="main-data">0</div>
+	      <h4>Users online</h4>
+	    </div>
+	    <div class="col-xs-6 col-sm-3 placeholder">
+	      <div class="main-data">0</div>
+	      <h4>Documents opened</h4>
+	    </div>
+	    <div class="col-xs-6 col-sm-3 placeholder">
+	      <div class="main-data">0</div>
+	      <h4>Memory consumed</h4>
+	    </div>
+	  </div>
+
+	  <h2 class="sub-header">Documents opened</h2>
+	  <div class="table-responsive">
+	    <table class="table table-striped">
+	      <thead>
+		<tr>
+		  <th>PID</th>
+		  <th>Document</th>
+		  <th>Number of views</th>
+		  <th>Memory consumed</th>
+		</tr>
+	      </thead>
+	      <tbody id="doclist">
+	      </tbody>
+	    </table>
+	  </div>
+	</div>
+      </div>
+    </div>
+
+    <!-- Bootstrap core JavaScript
+    ================================================== -->
+    <!-- Placed at the end of the document so the pages load faster -->
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
+    <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
+    <script src="../../dist/bootstrap/js/bootstrap.min.js"></script>
+    <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
+    <script src="../../dist/bootstrap/assets/js/vendor/holder.min.js"></script>
+    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
+    <script src="../../dist/bootstrap/assets/js/ie10-viewport-bug-workaround.js"></script>
+  </body>
+</html>
diff --git a/loleaflet/dist/bootstrap/dashboard.css b/loleaflet/dist/bootstrap/dashboard.css
index e0e3632..b698ef8 100644
--- a/loleaflet/dist/bootstrap/dashboard.css
+++ b/loleaflet/dist/bootstrap/dashboard.css
@@ -99,7 +99,8 @@ body {
 .placeholder {
   margin-bottom: 20px;
 }
-.placeholder img {
+.placeholder .main-data {
   display: inline-block;
   border-radius: 50%;
+  font-size: 60px;
 }
diff --git a/loleaflet/src/admin.js b/loleaflet/src/admin.js
new file mode 100644
index 0000000..cfe5ee1
--- /dev/null
+++ b/loleaflet/src/admin.js
@@ -0,0 +1,290 @@
+/*
+	Base.js, version 1.1a
+	Copyright 2006-2010, Dean Edwards
+	License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+var Base = function() {
+	// dummy
+};
+
+Base.extend = function(_instance, _static) { // subclass
+	var extend = Base.prototype.extend;
+
+	// build the prototype
+	Base._prototyping = true;
+	var proto = new this;
+	extend.call(proto, _instance);
+  proto.base = function() {
+    // call this method from any other method to invoke that method's ancestor
+  };
+	delete Base._prototyping;
+
+	// create the wrapper for the constructor function
+	//var constructor = proto.constructor.valueOf(); //-dean
+	var constructor = proto.constructor;
+	var klass = proto.constructor = function() {
+		if (!Base._prototyping) {
+			if (this._constructing || this.constructor == klass) { // instantiation
+				this._constructing = true;
+				constructor.apply(this, arguments);
+				delete this._constructing;
+			} else if (arguments[0] != null) { // casting
+				return (arguments[0].extend || extend).call(arguments[0], proto);
+			}
+		}
+	};
+
+	// build the class interface
+	klass.ancestor = this;
+	klass.extend = this.extend;
+	klass.forEach = this.forEach;
+	klass.implement = this.implement;
+	klass.prototype = proto;
+	klass.toString = this.toString;
+	klass.valueOf = function(type) {
+		//return (type == "object") ? klass : constructor; //-dean
+		return (type == "object") ? klass : constructor.valueOf();
+	};
+	extend.call(klass, _static);
+	// class initialisation
+	if (typeof klass.init == "function") klass.init();
+	return klass;
+};
+
+Base.prototype = {
+	extend: function(source, value) {
+		if (arguments.length > 1) { // extending with a name/value pair
+			var ancestor = this[source];
+			if (ancestor && (typeof value == "function") && // overriding a method?
+				// the valueOf() comparison is to avoid circular references
+				(!ancestor.valueOf || ancestor.valueOf() != value.valueOf()) &&
+				/\bbase\b/.test(value)) {
+				// get the underlying method
+				var method = value.valueOf();
+				// override
+				value = function() {
+					var previous = this.base || Base.prototype.base;
+					this.base = ancestor;
+					var returnValue = method.apply(this, arguments);
+					this.base = previous;
+					return returnValue;
+				};
+				// point to the underlying method
+				value.valueOf = function(type) {
+					return (type == "object") ? value : method;
+				};
+				value.toString = Base.toString;
+			}
+			this[source] = value;
+		} else if (source) { // extending with an object literal
+			var extend = Base.prototype.extend;
+			// if this object has a customised extend method then use it
+			if (!Base._prototyping && typeof this != "function") {
+				extend = this.extend || extend;
+			}
+			var proto = {toSource: null};
+			// do the "toString" and other methods manually
+			var hidden = ["constructor", "toString", "valueOf"];
+			// if we are prototyping then include the constructor
+			var i = Base._prototyping ? 0 : 1;
+			while (key = hidden[i++]) {
+				if (source[key] != proto[key]) {
+					extend.call(this, key, source[key]);
+
+				}
+			}
+			// copy each of the source object's properties to this object
+			for (var key in source) {
+				if (!proto[key]) extend.call(this, key, source[key]);
+			}
+		}
+		return this;
+	}
+};
+
+// initialise
+Base = Base.extend({
+	constructor: function() {
+		this.extend(arguments[0]);
+	}
+}, {
+	ancestor: Object,
+	version: "1.1",
+
+	forEach: function(object, block, context) {
+		for (var key in object) {
+			if (this.prototype[key] === undefined) {
+				block.call(context, object[key], key, object);
+			}
+		}
+	},
+
+	implement: function() {
+		for (var i = 0; i < arguments.length; i++) {
+			if (typeof arguments[i] == "function") {
+				// if it's a function, call it
+				arguments[i](this.prototype);
+			} else {
+				// add the interface using the extend method
+				this.prototype.extend(arguments[i]);
+			}
+		}
+		return this;
+	},
+
+	toString: function() {
+		return String(this.valueOf());
+	}
+});
+
+/*
+	Abstract class
+*/
+var AdminSocketBase = Base.extend({
+	socket: null,
+
+	constructor: function(host) {
+		// because i am abstract
+		if (this.constructor === AdminSocketBase) {
+			throw new Error('Cannot instantiate abstract class');
+		}
+
+		// We do not allow such child class to instantiate websocket that do not implement
+		// onSocketMessage and onSocketOpen.
+		if (typeof this.onSocketMessage === 'function' && typeof this.onSocketOpen === 'function') {
+			this.socket = new WebSocket(host);
+			this.socket.onopen = this.onSocketOpen;
+			this.socket.onclose = this.onSocketClose;
+			this.socket.onmessage = this.onSocketMessage;
+			this.socket.onerror = this.onSocketError;
+			this.socket.binaryType = 'arraybuffer';
+		}
+	},
+
+	onSocketOpen: function() {
+		/* Implemented by child */
+	},
+
+	onSocketMessage: function() {
+		/* Implemented by child */
+	},
+
+	onSocketClose: function() {
+		this.socket.onerror = function() {};
+		this.socket.onclose = function() {};
+		this.socket.onmessage = function() {};
+		this.socket.close();
+	},
+
+	onSocketError: function() {
+		alert('Connection error');
+	}
+});
+
+/*
+	Socket to be intialized on opening the overview page in Admin console
+*/
+var AdminSocketOverview = AdminSocketBase.extend({
+	constructor: function(host) {
+		this.base(host);
+	},
+
+	onSocketOpen: function() {
+		this.send('documents');
+	},
+
+	onSocketMessage: function(e) {
+		var textMsg;
+		if (typeof e.data === 'string') {
+			textMsg = e.data;
+		}
+		else
+			textMsg = '';
+
+		var tableContainer = document.getElementById('doclist');
+		if (textMsg.startsWith('documents')) {
+			var documents = textMsg.substring('documents'.length);
+			documents = documents.trim().split('\n');
+			for (var i = 0; i < documents.length; i++) {
+				if (documents[i] == '')
+					continue;
+				var docProps = documents[i].trim().split(' ');
+				var sPid = docProps[0];
+				var sUrl = docProps[1];
+				var sViews = docProps[2];
+				var sMem = docProps[3];
+				if (sUrl === '0') {
+					continue;
+				}
+				var rowContainer = document.createElement('tr');
+				rowContainer.id = 'doc' + sPid;
+				tableContainer.appendChild(rowContainer);
+
+				var pidEle = document.createElement('td');
+				pidEle.innerHTML = sPid;
+				rowContainer.appendChild(pidEle);
+				var urlEle = document.createElement('td');
+				urlEle.innerHTML = sUrl;
+				rowContainer.appendChild(urlEle);
+				var viewsEle = document.createElement('td');
+				viewsEle.id = 'docview' + sPid;
+				viewsEle.innerHTML = sViews;
+				rowContainer.appendChild(viewsEle);
+				var memEle = document.createElement('td');
+				memEle.innerHTML = sMem;
+				rowContainer.appendChild(memEle);
+			}
+		}
+		else if (textMsg.startsWith('addview')) {
+			var sPid = textMsg.substring('addview'.length).trim().split(' ')[0];
+			var nViews = parseInt(document.getElementById('docview' + sPid).innerHTML);
+			document.getElementById('docview' + sPid).innerHTML = nViews + 1;
+		}
+		else if (textMsg.startsWith('rmview')) {
+			var sPid = textMsg.substring('addview'.length).trim().split(' ')[0];
+			var nViews = parseInt(document.getElementById('docview' + sPid).innerHTML);
+			document.getElementById('docview' + sPid).innerHTML = nViews - 1;
+		}
+		else if (textMsg.startsWith('document')) {
+			textMsg = textMsg.substring('document'.length);
+			var docProps = textMsg.trim().split(' ');
+			var sPid = docProps[0];
+			var sUrl = docProps[1];
+			var sMem = docProps[2];
+			var docEle = document.getElementById('doc' + sPid);
+			if (docEle) {
+				tableContainer.removeChild(docEle);
+			}
+			if (sUrl === '0') {
+				return;
+			}
+			var rowContainer = document.createElement('tr');
+			rowContainer.id = 'doc' + docProps[0];
+			tableContainer.appendChild(rowContainer);
+
+			var pidEle = document.createElement('td');
+			pidEle.innerHTML = docProps[0];
+			rowContainer.appendChild(pidEle);
+			var urlEle = document.createElement('td');
+			urlEle.innerHTML = docProps[1];
+			rowContainer.appendChild(urlEle);
+			var viewsEle = document.createElement('td');
+			viewsEle.innerHTML = 0;
+			viewsEle.id = 'docview' + docProps[0];
+			rowContainer.appendChild(viewsEle);
+			var memEle = document.createElement('td');
+			memEle.innerHTML = sMem;
+			rowContainer.appendChild(memEle);
+		}
+		else if (textMsg.startsWith('rmdoc')) {
+			textMsg = textMsg.substring('rmdoc'.length);
+			var docProps = textMsg.trim().split(' ');
+			var sPid = docProps[0];
+			var docEle = document.getElementById('doc' + sPid);
+			if (docEle) {
+				tableContainer.removeChild(docEle);
+			}
+		}
+	}
+});


More information about the Libreoffice-commits mailing list