aboutsummaryrefslogtreecommitdiffstats
path: root/client-website/js/symple.js
diff options
context:
space:
mode:
Diffstat (limited to 'client-website/js/symple.js')
-rw-r--r--client-website/js/symple.js385
1 files changed, 385 insertions, 0 deletions
diff --git a/client-website/js/symple.js b/client-website/js/symple.js
new file mode 100644
index 0000000..8a3171c
--- /dev/null
+++ b/client-website/js/symple.js
@@ -0,0 +1,385 @@
+// -----------------------------------------------------------------------------
+// HTML5 video streaming server
+// - Uses WebSockets, C++, Node.js and HTML5 JavaScript
+//
+var Symple = {
+
+ // Return an array of nested objects matching
+ // the given key/value strings.
+ filterObject: function(obj, key, value) { // (Object[, String, String])
+ var r = []
+ for (var k in obj) {
+ if (obj.hasOwnProperty(k)) {
+ var v = obj[k];
+ if ((!key || k == key) &&
+ (!value || v == value)) {
+ r.push(obj)
+ }
+ else if (typeof v === 'object') {
+ var a = Symple.filterObject(v, key, value);
+ if (a) r = r.concat(a);
+ }
+ }
+ }
+ return r;
+ },
+
+ // Delete nested objects with properties
+ // that match the given key/value strings.
+ deleteNested: function(obj, key, value) { // (Object[, String, String])
+ for (var k in obj) {
+ var v = obj[k];
+ if ((!key || k == key) &&
+ (!value || v == value)) {
+ delete obj[k];
+ }
+ else if (typeof v === 'object')
+ Symple.deleteNested(v, key);
+ }
+ },
+
+ // Count nested object properties which
+ // match the given key/value strings.
+ countNested: function(obj, key, value, count) {
+ if (count === undefined) count = 0;
+ for (var k in obj) {
+ if (obj.hasOwnProperty(k)) {
+ var v = obj[k];
+ if ((!key || k == key) &&
+ (!value || v == value)) {
+ count++;
+ }
+ else if (typeof(v) === 'object') {
+ //else if (v instanceof Object) {
+ count = Symple.countNested(v, key, value, count);
+ }
+ }
+ }
+ return count;
+ },
+
+ // Traverse an objects nested properties
+ traverse: function(obj, fn) { // (Object, Function)
+ for (var k in obj) {
+ if (obj.hasOwnProperty(k)) {
+ var v = obj[k];
+ fn(k, v);
+ if (typeof v === 'object')
+ Symple.traverse(v, fn);
+ }
+ }
+ },
+
+ // Generate a random string
+ randomString: function(n) {
+ return Math.random().toString(36).slice(2) //Math.random().toString(36).substring(n || 7);
+ },
+
+ // Recursively merge object properties of r into l
+ merge: function(l, r) { // (Object, Object)
+ for (var p in r) {
+ try {
+ // Property in destination object set; update its value.
+ //if (typeof r[p] == "object") {
+ if (r[p].constructor == Object) {
+ l[p] = merge(l[p], r[p]);
+ } else {
+ l[p] = r[p];
+ }
+ } catch(e) {
+ // Property in destination object not set;
+ // create it and set its value.
+ l[p] = r[p];
+ }
+ }
+ return l;
+ },
+
+ // Object extend functionality
+ extend: function() {
+ var process = function(destination, source) {
+ for (var key in source) {
+ if (hasOwnProperty.call(source, key)) {
+ destination[key] = source[key];
+ }
+ }
+ return destination;
+ };
+ var result = arguments[0];
+ for(var i=1; i<arguments.length; i++) {
+ result = process(result, arguments[i]);
+ }
+ return result;
+ },
+
+ // Run a vendor prefixed method from W3C standard method.
+ runVendorMethod: function(obj, method) {
+ var p = 0, m, t, pfx = ["webkit", "moz", "ms", "o", ""];
+ while (p < pfx.length && !obj[m]) {
+ m = method;
+ if (pfx[p] == "") {
+ m = m.substr(0,1).toLowerCase() + m.substr(1);
+ }
+ m = pfx[p] + m;
+ t = typeof obj[m];
+ if (t != "undefined") {
+ pfx = [pfx[p]];
+ return (t == "function" ? obj[m]() : obj[m]);
+ }
+ p++;
+ }
+ },
+
+ //
+ // Date parseing for ISO 8601
+ // Based on https://github.com/csnover/js-iso8601
+ //
+ // Parses dates like:
+ // 2001-02-03T04:05:06.007+06:30
+ // 2001-02-03T04:05:06.007Z
+ // 2001-02-03T04:05:06Z
+ //
+ parseISODate: function (date) { // (String)
+
+ // ISO8601 dates were introduced with ECMAScript v5,
+ // try to parse it natively first...
+ var timestamp = Date.parse(date)
+ if (isNaN(timestamp)) {
+ var struct,
+ minutesOffset = 0,
+ numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
+
+ // ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date
+ // Time String Format string before falling back to any implementation-specific
+ // date parsing, so that's what we do, even if native implementations could be faster
+ //
+ // 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm
+ if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
+ // Avoid NaN timestamps caused by "undefined" values being passed to Date.UTC
+ for (var i = 0, k; (k = numericKeys[i]); ++i)
+ struct[k] = +struct[k] || 0;
+
+ // Allow undefined days and months
+ struct[2] = (+struct[2] || 1) - 1;
+ struct[3] = +struct[3] || 1;
+
+ if (struct[8] !== 'Z' && struct[9] !== undefined) {
+ minutesOffset = struct[10] * 60 + struct[11];
+ if (struct[9] === '+')
+ minutesOffset = 0 - minutesOffset;
+ }
+
+ timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]);
+ }
+ }
+
+ return new Date(timestamp);
+ },
+
+ isMobileDevice: function() {
+ return 'ontouchstart' in document.documentElement;
+ },
+
+ // Returns the current iOS version, or false if not iOS
+ iOSVersion: function(l, r) {
+ return parseFloat(('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0,''])[1])
+ .replace('undefined', '3_2').replace('_', '.').replace('_', '')) || false;
+ },
+
+ // Match the object properties of l with r
+ match: function(l, r) { // (Object, Object)
+ var res = true;
+ for (var prop in l) {
+ if (!l.hasOwnProperty(prop) ||
+ !r.hasOwnProperty(prop) ||
+ r[prop] != l[prop]) {
+ res = false;
+ break;
+ }
+ }
+ return res
+ },
+
+ formatTime: function(date) {
+ function pad(n) { return n < 10 ? ('0' + n) : n }
+ return pad(date.getHours()).toString() + ':' +
+ pad(date.getMinutes()).toString() + ':' +
+ pad(date.getSeconds()).toString() + ' ' +
+ pad(date.getDate()).toString() + '/' +
+ pad(date.getMonth()).toString();
+ },
+
+ // Debug logger
+ log: function () {
+ if (typeof console != "undefined" &&
+ typeof console.log != "undefined") {
+ console.log.apply(console, arguments);
+ }
+ }
+};
+
+
+// -----------------------------------------------------------------------------
+// OOP Base Class
+// Simple JavaScript Inheritance By John Resig
+//
+(function(Symple) {
+ var initializing = false,
+ fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
+
+ // The base Class implementation (does nothing)
+ Symple.Class = function(){};
+
+ // Create a new Class that inherits from this class
+ Symple.Class.extend = function(prop) {
+ var _super = this.prototype;
+
+ // Instantiate a base class (but only create the instance,
+ // don't run the init constructor)
+ initializing = true;
+ var prototype = new this();
+ initializing = false;
+
+ // Copy the properties over onto the new prototype
+ for (var name in prop) {
+ // Check if we're overwriting an existing function
+ prototype[name] = typeof prop[name] == "function" &&
+ typeof _super[name] == "function" && fnTest.test(prop[name]) ?
+ (function(name, fn){
+ return function() {
+ var tmp = this._super;
+
+ // Add a new ._super() method that is the same method
+ // but on the super-class
+ this._super = _super[name];
+
+ // The method only need to be bound temporarily, so we
+ // remove it when we're done executing
+ var ret = fn.apply(this, arguments);
+ this._super = tmp;
+
+ return ret;
+ };
+ })(name, prop[name]) :
+ prop[name];
+ }
+
+ // The dummy class constructor
+ function Class() {
+ // All construction is actually done in the init method
+ if (!initializing && this.init)
+ this.init.apply(this, arguments);
+ }
+
+ // Populate our constructed prototype object
+ Class.prototype = prototype;
+
+ // Enforce the constructor to be what we expect
+ Class.prototype.constructor = Class;
+
+ // And make this class extendable
+ Class.extend = arguments.callee;
+
+ return Class;
+ };
+})(Symple);
+
+
+// -----------------------------------------------------------------------------
+// Dispatcher
+//
+Symple.Dispatcher = Symple.Class.extend({
+ init: function() {
+ this.listeners = {};
+ },
+
+ on: function(event, fn) {
+ if (typeof this.listeners[event] == 'undefined')
+ this.listeners[event] = [];
+ if (typeof fn != 'undefined' && fn.constructor == Function)
+ this.listeners[event].push(fn);
+ },
+
+ clear: function(event, fn) {
+ if (typeof this.listeners[event] != 'undefined') {
+ for (var i = 0; i < this.listeners[event].length; i++) {
+ if (this.listeners[event][i] == fn) {
+ this.listeners[event].splice(i, 1);
+ }
+ }
+ }
+ },
+
+ dispatch: function() {
+ //Symple.log('Dispatching: ', arguments);
+ var event = arguments[0];
+ var args = Array.prototype.slice.call(arguments, 1);
+ if (typeof this.listeners[event] != 'undefined') {
+ for (var i = 0; i < this.listeners[event].length; i++) {
+ //Symple.log('Dispatching: Function: ', this.listeners[event][i]);
+ if (this.listeners[event][i].constructor == Function)
+ this.listeners[event][i].apply(this, args);
+ }
+ }
+ }
+});
+
+
+// -----------------------------------------------------------------------------
+// Manager
+//
+Symple.Manager = Symple.Class.extend({
+ init: function(options) {
+ this.options = options || {};
+ this.key = this.options.key || 'id';
+ this.store = [];
+ },
+
+ add: function(value) {
+ this.store.push(value);
+ },
+
+ remove: function(key) {
+ var res = null;
+ for (var i = 0; i < this.store.length; i++) {
+ if (this.store[i][this.key] == key) {
+ res = this.store[i];
+ this.store.splice(i, 1);
+ break;
+ }
+ }
+ return res;
+ },
+
+ get: function(key) {
+ for (var i = 0; i < this.store.length; i++) {
+ if (this.store[i][this.key] == key) {
+ return this.store[i];
+ }
+ }
+ return null;
+ },
+
+ find: function(params) {
+ var res = [];
+ for (var i = 0; i < this.store.length; i++) {
+ if (Symple.match(params, this.store[i])) {
+ res.push(this.store[i])
+ }
+ }
+ return res;
+ },
+
+ findOne: function(params) {
+ var res = this.find(params);
+ return res.length ? res[0] : undefined;
+ },
+
+ last: function() {
+ return this.store[this.store.length - 1];
+ },
+
+ size: function() {
+ return this.store.length;
+ }
+});