diff --git a/app-showcase/directors-console/director.js b/app-showcase/directors-console/director.js index 6c15b5e2..a8f46cc3 100644 --- a/app-showcase/directors-console/director.js +++ b/app-showcase/directors-console/director.js @@ -1,7 +1,7 @@ (function(){ var p = PUBNUB.init({ publish_key: 'demo', subscribe_key : 'demo' }) - , channel = 'my_channel'; + , channel = 'my_directors_channel'; p.bind( 'mousedown,touchstart', p.$('buttons'), function(e) { var target = e.target || e.srcElement; diff --git a/javascript/3.4/README.md b/javascript/3.4/README.md new file mode 100644 index 00000000..df605a0e --- /dev/null +++ b/javascript/3.4/README.md @@ -0,0 +1,153 @@ +# YOU MUST HAVE A PUBNUB ACCOUNT TO USE THE API. +http://www.pubnub.com/account + +## TESTLING - (OPTIONAL) +PubNub JavaScript API for Web Browsers +uses Testling Cloud Service for QA and Deployment. +http://www.testling.com/ + +You need this to run './test.sh' unit test. +This is completely optional, however we love Testling. + + +## PubNub 3.3.1 Real-time Cloud Push API - JAVASCRIPT +http://www.pubnub.com - PubNub Real-time Push Service in the Cloud. +http://www.pubnub.com/tutorial/javascript-push-api + +PubNub is a blazingly fast cloud-hosted messaging service for building +real-time web and mobile apps. Hundreds of apps and thousands of developers +rely on PubNub for delivering human-perceptive real-time +experiences that scale to millions of users worldwide. PubNub delivers +the infrastructure needed to build amazing MMO games, social apps, +business collaborative solutions, and more. + +## SIMPLE EXAMPLE +```html +
+ + +``` + +## ADVANCED STYLE +```html +
+ + + +Click Me for Here Now! // here_now() example (see console for logged output.) +
+Click Me for History! // detailedHistory() example (see console for logged output.) + + + +``` + +## SSL MODE + +```html +
+ + +``` + +## Using the PUBNUB init() Function + +Sometimes you want to use create a PubNub Instance directly in JavaScript +and pass the PubNub API Keys without using a DOM element. +To do this, simply follow this `init` example: + +```html + + +``` \ No newline at end of file diff --git a/javascript/3.4/comet.swf b/javascript/3.4/comet.swf new file mode 100644 index 00000000..1209542d Binary files /dev/null and b/javascript/3.4/comet.swf differ diff --git a/javascript/3.4/crossdomain.xml b/javascript/3.4/crossdomain.xml new file mode 100644 index 00000000..8fb3c522 --- /dev/null +++ b/javascript/3.4/crossdomain.xml @@ -0,0 +1,4 @@ + + + + diff --git a/javascript/3.4/crypto.js b/javascript/3.4/crypto.js new file mode 100644 index 00000000..e69de29b diff --git a/javascript/3.4/json.js b/javascript/3.4/json.js new file mode 100644 index 00000000..5802af65 --- /dev/null +++ b/javascript/3.4/json.js @@ -0,0 +1,155 @@ +/* =-====================================================================-= */ +/* =-====================================================================-= */ +/* =-========================= JSON =============================-= */ +/* =-====================================================================-= */ +/* =-====================================================================-= */ + +(window['JSON'] && window['JSON']['stringify']) || (function () { + window['JSON'] || (window['JSON'] = {}); + + if (typeof String.prototype.toJSON !== 'function') { + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + function quote(string) { + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + return String(value); + + case 'object': + + if (!value) { + return 'null'; + } + + gap += indent; + partial = []; + + if (Object.prototype.toString.apply(value) === '[object Array]') { + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + + if (typeof JSON['stringify'] !== 'function') { + JSON['stringify'] = function (value, replacer, space) { + var i; + gap = ''; + indent = ''; + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + } else if (typeof space === 'string') { + indent = space; + } + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + return str('', {'': value}); + }; + } + + if (typeof JSON['parse'] !== 'function') { + // JSON is parsed on the server for security. + JSON['parse'] = function (text) {return eval('('+text+')')}; + } +}()); diff --git a/javascript/3.4/pubnub-3.4.js b/javascript/3.4/pubnub-3.4.js new file mode 100644 index 00000000..12b0dfcb --- /dev/null +++ b/javascript/3.4/pubnub-3.4.js @@ -0,0 +1,946 @@ +/* --------------------------------------------------------------------------- +WAIT! - This file depends on instructions from the PUBNUB Cloud. +http://www.pubnub.com/account-javascript-api-include +--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- +PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks +Copyright (c) 2011 PubNub Inc. +http://www.pubnub.com/ +http://www.pubnub.com/terms +--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- +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. +--------------------------------------------------------------------------- */ + +/* =-====================================================================-= */ +/* =-====================================================================-= */ +/* =-========================= UTIL =============================-= */ +/* =-====================================================================-= */ +/* =-====================================================================-= */ + +window['PUBNUB'] || (function() { + +/** + * UTIL LOCALS + */ +var NOW = 1 +, SWF = 'https://dh15atwfs066y.cloudfront.net/pubnub.swf' +, REPL = /{([\w\-]+)}/g +, ASYNC = 'async' +, URLBIT = '/' +, PARAMSBIT = '&' +, SUB_TIMEOUT = 310000 +, DEF_TIMEOUT = 10000 +, SECOND = 1000 +, PRESENCE_SUFFIX = '-pnpres' +, UA = navigator.userAgent +, XORIGN = UA.indexOf('MSIE 6') == -1; + +/** + * CONSOLE COMPATIBILITY + */ +window.console||(window.console=window.console||{}); +console.log||(console.log=((window.opera||{}).postError||function(){})); + +/** + * UTILITIES + */ +function unique() { return'x'+ ++NOW+''+(+new Date) } +function rnow() { return+new Date } + +/** + * LOCAL STORAGE OR COOKIE + */ +var db = (function(){ + var ls = window['localStorage']; + return { + 'get' : function(key) { + try { + if (ls) return ls.getItem(key); + if (document.cookie.indexOf(key) == -1) return null; + return ((document.cookie||'').match( + RegExp(key+'=([^;]+)') + )||[])[1] || null; + } catch(e) { return } + }, + 'set' : function( key, value ) { + try { + if (ls) return ls.setItem( key, value ) && 0; + document.cookie = key + '=' + value + + '; expires=Thu, 1 Aug 2030 20:00:00 UTC; path=/'; + } catch(e) { return } + } + }; +})(); + +/** + * NEXTORIGIN + * ========== + * var next_origin = nextorigin(); + */ +var nextorigin = (function() { + var max = 100 + , ori = Math.floor(Math.random() * max); + return function(origin) { + return origin.indexOf('pubsub') > 0 + && origin.replace( + 'pubsub', 'ps' + (++ori < max? ori : ori=1) + ) || origin; + } +})(); + +/** + * UPDATER + * ====== + * var timestamp = unique(); + */ +function updater( fun, rate ) { + var timeout + , last = 0 + , runnit = function() { + if (last + rate > rnow()) { + clearTimeout(timeout); + timeout = setTimeout( runnit, rate ); + } + else { + last = rnow(); + fun(); + } + }; + + return runnit; +} + +/** + * $ + * = + * var div = $('divid'); + */ +function $(id) { return document.getElementById(id) } + +/** + * LOG + * === + * log('message'); + */ +function log(message) { console['log'](message) } + +/** + * SEARCH + * ====== + * var elements = search('a div span'); + */ +function search( elements, start ) { + var list = []; + each( elements.split(/\s+/), function(el) { + each( (start || document).getElementsByTagName(el), function(node) { + list.push(node); + } ); + } ); + return list; +} + +/** + * EACH + * ==== + * each( [1,2,3], function(item) { console.log(item) } ) + */ +function each( o, f ) { + if ( !o || !f ) return; + + if ( typeof o[0] != 'undefined' ) + for ( var i = 0, l = o.length; i < l; ) + f.call( o[i], o[i], i++ ); + else + for ( var i in o ) + o.hasOwnProperty && + o.hasOwnProperty(i) && + f.call( o[i], i, o[i] ); +} + +/** + * MAP + * === + * var list = map( [1,2,3], function(item) { return item + 1 } ) + */ +function map( list, fun ) { + var fin = []; + each( list || [], function( k, v ) { fin.push(fun( k, v )) } ); + return fin; +} + +/** + * GREP + * ==== + * var list = grep( [1,2,3], function(item) { return item % 2 } ) + */ +function grep( list, fun ) { + var fin = []; + each( list || [], function(l) { fun(l) && fin.push(l) } ); + return fin +} + +/** + * SUPPLANT + * ======== + * var text = supplant( 'Hello {name}!', { name : 'John' } ) + */ +function supplant( str, values ) { + return str.replace( REPL, function( _, match ) { + return values[match] || _ + } ); +} + +/** + * BIND + * ==== + * bind( 'keydown', search('a')[0], function(element) { + * console.log( element, '1st anchor' ) + * } ); + */ +function bind( type, el, fun ) { + each( type.split(','), function(etype) { + var rapfun = function(e) { + if (!e) e = window.event; + if (!fun(e)) { + e.cancelBubble = true; + e.returnValue = false; + e.preventDefault && e.preventDefault(); + e.stopPropagation && e.stopPropagation(); + } + }; + + if ( el.addEventListener ) el.addEventListener( etype, rapfun, false ); + else if ( el.attachEvent ) el.attachEvent( 'on' + etype, rapfun ); + else el[ 'on' + etype ] = rapfun; + } ); +} + +/** + * UNBIND + * ====== + * unbind( 'keydown', search('a')[0] ); + */ +function unbind( type, el, fun ) { + if ( el.removeEventListener ) el.removeEventListener( type, false ); + else if ( el.detachEvent ) el.detachEvent( 'on' + type, false ); + else el[ 'on' + type ] = null; +} + +/** + * HEAD + * ==== + * head().appendChild(elm); + */ +function head() { return search('head')[0] } + +/** + * ATTR + * ==== + * var attribute = attr( node, 'attribute' ); + */ +function attr( node, attribute, value ) { + if (value) node.setAttribute( attribute, value ); + else return node && node.getAttribute && node.getAttribute(attribute); +} + +/** + * CSS + * === + * var obj = create('div'); + */ +function css( element, styles ) { + for (var style in styles) if (styles.hasOwnProperty(style)) + try {element.style[style] = styles[style] + ( + '|width|height|top|left|'.indexOf(style) > 0 && + typeof styles[style] == 'number' + ? 'px' : '' + )}catch(e){} +} + +/** + * CREATE + * ====== + * var obj = create('div'); + */ +function create(element) { return document.createElement(element) } + +/** + * timeout + * ======= + * timeout( function(){}, 100 ); + */ +function timeout( fun, wait ) { + return setTimeout( fun, wait ); +} + +/** + * jsonp_cb + * ======== + * var callback = jsonp_cb(); + */ +function jsonp_cb() { return XORIGN || FDomainRequest() ? 0 : unique() } + +/** + * ENCODE + * ====== + * var encoded_path = encode('path'); + */ +function encode(path) { + return map( (encodeURIComponent(path)).split(''), function(chr) { + return "-_.!~*'()".indexOf(chr) < 0 ? chr : + "%"+chr.charCodeAt(0).toString(16).toUpperCase() + } ).join(''); +} + +/** + * EVENTS + * ====== + * PUBNUB.events.bind( 'you-stepped-on-flower', function(message) { + * // Do Stuff with message + * } ); + * + * PUBNUB.events.fire( 'you-stepped-on-flower', "message-data" ); + * PUBNUB.events.fire( 'you-stepped-on-flower', {message:"data"} ); + * PUBNUB.events.fire( 'you-stepped-on-flower', [1,2,3] ); + * + */ +var events = { + 'list' : {}, + 'unbind' : function( name ) { events.list[name] = [] }, + 'bind' : function( name, fun ) { + (events.list[name] = events.list[name] || []).push(fun); + }, + 'fire' : function( name, data ) { + each( + events.list[name] || [], + function(fun) { fun(data) } + ); + } +}; + +/** + * XDR Cross Domain Request + * ======================== + * xdr({ + * url : ['http://www.blah.com/url'], + * success : function(response) {}, + * fail : function() {} + * }); + */ +function xdr( setup ) { + if (XORIGN || FDomainRequest()) return ajax(setup); + + var script = create('script') + , callback = setup.callback + , id = unique() + , finished = 0 + , xhrtme = setup.timeout || DEF_TIMEOUT + , timer = timeout( function(){done(1)}, xhrtme ) + , fail = setup.fail || function(){} + , success = setup.success || function(){} + + , append = function() { + head().appendChild(script); + } + + , done = function( failed, response ) { + if (finished) return; + finished = 1; + + failed || success(response); + script.onerror = null; + clearTimeout(timer); + + timeout( function() { + failed && fail(); + var s = $(id) + , p = s && s.parentNode; + p && p.removeChild(s); + }, SECOND ); + }; + + window[callback] = function(response) { + done( 0, response ); + }; + + if (!setup.blocking) script[ASYNC] = ASYNC; + + script.onerror = function() { done(1) }; + script.src = setup.url.join(URLBIT); + + if (setup.data) { + var params = []; + script.src += "?"; + for (key in setup.data) { + params.push(key+"="+setup.data[key]); + } + script.src += params.join(PARAMSBIT); + } + attr( script, 'id', id ); + + append(); + return done; +} + +/** + * CORS XHR Request + * ================ + * xdr({ + * url : ['http://www.blah.com/url'], + * success : function(response) {}, + * fail : function() {} + * }); + */ +function ajax( setup ) { + var xhr, response + , finished = function() { + if (loaded) return; + loaded = 1; + + clearTimeout(timer); + + try { response = JSON['parse'](xhr.responseText); } + catch (r) { return done(1); } + + success(response); + } + , complete = 0 + , loaded = 0 + , xhrtme = setup.timeout || DEF_TIMEOUT + , timer = timeout( function(){done(1)}, xhrtme ) + , fail = setup.fail || function(){} + , success = setup.success || function(){} + , done = function(failed) { + if (complete) return; + complete = 1; + + clearTimeout(timer); + + if (xhr) { + xhr.onerror = xhr.onload = null; + xhr.abort && xhr.abort(); + xhr = null; + } + + failed && fail(); + }; + + // Send + try { + xhr = FDomainRequest() || + window.XDomainRequest && + new XDomainRequest() || + new XMLHttpRequest(); + + xhr.onerror = xhr.onabort = function(){ done(1) }; + xhr.onload = xhr.onloadend = finished; + xhr.timeout = xhrtme; + + var url = setup.url.join(URLBIT); + if (setup.data) { + var params = []; + var key; + url += "?"; + for (key in setup.data) params.push(key+"="+setup.data[key]); + url += params.join(PARAMSBIT); + } + + xhr.open( 'GET', url, typeof setup.blocking == 'undefined' ); + xhr.send(); + } + catch(eee) { + done(0); + XORIGN = 0; + return xdr(setup); + } + + // Return 'done' + return done; +} + +/** + * Generate Subscription Channel List + * ================================== + * generate_channel_list(channels_object); + */ +function generate_channel_list(channels) { + var list = []; + each( channels, function( channel, status ) { + if (status.connected) list.push(channel); + } ); + return list.sort().join(','); +} + +/* =-====================================================================-= */ +/* =-====================================================================-= */ +/* =-========================= PUBNUB ===========================-= */ +/* =-====================================================================-= */ +/* =-====================================================================-= */ + +var PDIV = $('pubnub') || {} +, READY = 0 +, READY_BUFFER = [] +, CREATE_PUBNUB = function(setup) { + var CHANNELS = {} + , SUB_RECEIVER = null + , TIMETOKEN = 0 + , DISCONNECTED = 0 + , CONNECTED = 0 + , PUBLISH_KEY = setup['publish_key'] || '' + , SUBSCRIBE_KEY = setup['subscribe_key'] || '' + , SSL = setup['ssl'] ? 's' : '' + , UUID = setup['uuid'] || db.get(SUBSCRIBE_KEY+'uuid') || '' + , ORIGIN = 'http'+SSL+'://'+(setup['origin']||'pubsub.pubnub.com') + , LEAVE = function(){} + , CONNECT = function(){} + , SELF = { + /* + PUBNUB.history({ + channel : 'my_chat_channel', + limit : 100, + callback : function(messages) { console.log(messages) } + }); + */ + 'history' : function( args, callback ) { + var callback = args['callback'] || callback + , count = args['count'] || args['limit'] || 100 + , reverse = args['reverse'] || "false" + , channel = args['channel'] + , start = args['start'] + , end = args['end'] + , params = {} + , jsonp = jsonp_cb(); + + // Make sure we have a Channel + if (!channel) return log('Missing Channel'); + if (!callback) return log('Missing Callback'); + if (!SUBSCRIBE_KEY) return log('Missing Subscribe Key'); + + params["count"] = count; + params["reverse"] = reverse; + + if (start) params["start"] = start; + if (end) params["end"] = end; + + // Send Message + xdr({ + callback : jsonp, + data : params, + success : function(response) { callback(response) }, + fail : function(response) { log(response) }, + url : [ + ORIGIN, 'v2', 'history', + 'sub-key', SUBSCRIBE_KEY, 'channel', encode(channel) + ] + }); + }, + + /* + PUBNUB.time(function(time){ console.log(time) }); + */ + 'time' : function(callback) { + var jsonp = jsonp_cb() + , origin = nextorigin(ORIGIN); + + xdr({ + callback : jsonp, + url : [origin, 'time', jsonp], + success : function(response) { callback(response[0]) }, + fail : function() { callback(0) } + }); + }, + + /* + PUBNUB.uuid(function(uuid) { console.log(uuid) }); + */ + 'uuid' : function(callback) { + var u = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, + function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); + if (callback) callback(u); + return u; + }, + + /* + PUBNUB.publish({ + channel : 'my_chat_channel', + message : 'hello!' + }); + */ + 'publish' : function( args, callback ) { + var callback = callback || args['callback'] || function(){} + , message = args['message'] + , channel = args['channel'] + , jsonp = jsonp_cb() + , origin = nextorigin(ORIGIN) + , url; + + if (!message) return log('Missing Message'); + if (!channel) return log('Missing Channel'); + if (!PUBLISH_KEY) return log('Missing Publish Key'); + if (!SUBSCRIBE_KEY) return log('Missing Subscribe Key'); + + // If trying to send Object + message = JSON['stringify'](message); + + // Create URL + url = [ + origin, 'publish', + PUBLISH_KEY, SUBSCRIBE_KEY, + 0, encode(channel), + jsonp, encode(message) + ]; + + // Send Message + xdr({ + callback : jsonp, + success : function(response) { callback(response) }, + fail : function() { callback([ 0, 'Disconnected' ]) }, + url : url, + data : { uuid: UUID } + }); + }, + /* + PUBNUB.unsubscribe({ channel : 'my_chat' }); + */ + 'unsubscribe' : function(args) { + // Unsubscribe from both the Channel and the Presence Channel + unsubscribe(args['channel']); + unsubscribe(args['channel'] + PRESENCE_SUFFIX); + + // Announce Leave + LEAVE(args['channel']); + + // Open Connection if Any Channels Left + CONNECT(); + + function unsubscribe(channel) { + // Leave if there never was a channel. + if (!(channel in CHANNELS)) return; + + // Disable Channel + CHANNELS[channel].connected = 0; + + // Abort and/or Remove Script + SUB_RECEIVER && SUB_RECEIVER() + } + }, + + /* + PUBNUB.subscribe({ + channel : 'my_chat' + callback : function(message) { console.log(message) } + }); + */ + 'subscribe' : function( args, callback ) { + var channel = args['channel'] + , callback = callback || args['callback'] + , subscribe_key = args['subscribe_key'] || SUBSCRIBE_KEY + , error = args['error'] || function(){} + , connect = args['connect'] || function(){} + , reconnect = args['reconnect'] || function(){} + , disconnect = args['disconnect'] || function(){} + , presence = args['presence'] || function(){} + , restore = args['restore'] + , origin = nextorigin(ORIGIN); + + // Reduce Status Flicker + if (!READY) return READY_BUFFER.push([ args, callback, SELF ]); + + // Make sure we have a Channel + if (!channel) return log('Missing Channel'); + if (!callback) return log('Missing Callback'); + if (!SUBSCRIBE_KEY) return log('Missing Subscribe Key'); + + // If is an Array + if (channel.join) channel = channel.join(','); + + // If User used Commas in Channels + if (channel.indexOf(',') > 0) { + each( channel.split(','), function(channel) { + args['channel'] = channel; + SELF['subscribe']( args, callback ); + } ); + return; + } + + if (!(channel in CHANNELS)) CHANNELS[channel] = {}; + + // Make sure we have a Channel + if (CHANNELS[channel].connected) return log('Already Connected'); + CHANNELS[channel].connected = 1; + + // Register Callback + CHANNELS[channel].callback = callback; + + // Evented Subscribe + function _connect() { + var jsonp = jsonp_cb(); + + // Stop Connection + if (!CHANNELS[channel].connected) return; + + // Connect to PubNub Subscribe Servers + SUB_RECEIVER = xdr({ + timeout : SUB_TIMEOUT, + callback : jsonp, + data : { uuid: UUID }, + url : [ + origin, + 'subscribe', + subscribe_key, + encode(generate_channel_list(CHANNELS)), + jsonp, + TIMETOKEN + ], + fail : function() { + // Disconnect + if (!DISCONNECTED) { + DISCONNECTED = 1; + disconnect(); + leave(); + } + timeout( _connect, SECOND ); + SELF['time'](function(success){ + // Reconnect + if (success && DISCONNECTED) { + DISCONNECTED = 0; + reconnect(); + } + else { + error(); + } + }); + }, + success : function(messages) { + if (!CHANNELS[channel].connected) return; + + // Connect + if (!CONNECTED) { + CONNECTED = 1; + connect(); + } + + // Reconnect + if (DISCONNECTED) { + DISCONNECTED = 0; + reconnect(); + } + + // Restore Previous Connection Point if Needed + // Also Update Timetoken + restore = db.set( + SUBSCRIBE_KEY, + TIMETOKEN = restore && db.get( + subscribe_key + channel + ) || messages[1] + ); + + var next_callback = (function() { + var channels = (messages.length > 2 ? messages[2] : '') + , list = channels.split(','); + + return function() { + var channel = list.shift(); + return channel in CHANNELS && + CHANNELS[channel].callback || + callback; + }; + })(); + + each( messages[0], function(msg) { + next_callback()( msg, messages ); + } ); + + timeout( _connect, 10 ); + } + }); + } + + // Announce Leave Event + function leave(chan) { + var data = { uuid : UUID } + , jsonp = jsonp_cb(); + + // Prevent Leaving a Presence Channel + if ( channel.indexOf(PRESENCE_SUFFIX) === + channel.length - PRESENCE_SUFFIX.length + ) return true; + + if (jsonp != '0') data['callback'] = jsonp; + + xdr({ + blocking : 1, + timeout : 2000, + callback : jsonp, + data : data, + url : [ + origin, 'v2', 'presence', + 'sub_key', SUBSCRIBE_KEY, + 'channel', encode(channel), + 'leave' + ] + }); + + return true; + } + + LEAVE = leave; + + // onBeforeUnload + bind( 'beforeunload', window, leave ); + + // Presence Subscribe + if (args['presence']) SELF.subscribe({ + channel : args['channel'] + PRESENCE_SUFFIX, + callback : presence, + restore : args['restore'], + disconnect : leave + }); + + // Close Previous Subscribe Connection + SUB_RECEIVER && SUB_RECEIVER(); + + // Begin Recursive Subscribe + (CONNECT = _connect)(); + }, + + 'here_now' : function( args, callback ) { + var callback = args['callback'] || callback + , channel = args['channel'] + , jsonp = jsonp_cb() + , data = {} + , origin = nextorigin(ORIGIN); + + // Make sure we have a Channel + if (!channel) return log('Missing Channel'); + if (!callback) return log('Missing Callback'); + if (!SUBSCRIBE_KEY) return log('Missing Subscribe Key'); + + if (jsonp != '0') data['callback'] = jsonp; + + xdr({ + callback : jsonp, + data : data, + success : function(response) { callback(response) }, + fail : function(response) { log(response) }, + url : [ + origin, 'v2', 'presence', + 'sub_key', SUBSCRIBE_KEY, + 'channel', encode(channel) + ] + }); + }, + + // Expose PUBNUB Functions + 'xdr' : xdr, + 'ready' : ready, + 'db' : db, + 'each' : each, + 'map' : map, + 'grep' : grep, + 'css' : css, + '$' : $, + 'create' : create, + 'bind' : bind, + 'supplant' : supplant, + 'head' : head, + 'search' : search, + 'attr' : attr, + 'now' : rnow, + 'unique' : unique, + 'events' : events, + 'updater' : updater, + 'init' : CREATE_PUBNUB + }; + + if (!UUID) UUID = SELF.uuid(); + db.set( SUBSCRIBE_KEY + 'uuid', UUID ); + + return SELF; +}; + +// CREATE A PUBNUB GLOBAL OBJECT +PUBNUB = CREATE_PUBNUB({ + 'publish_key' : attr( PDIV, 'pub-key' ), + 'subscribe_key' : attr( PDIV, 'sub-key' ), + 'ssl' : !document.location.href.indexOf('https') || attr( PDIV, 'ssl' ) == 'on', + 'origin' : attr( PDIV, 'origin' ), + 'uuid' : attr( PDIV, 'uuid' ) +}); + +// PUBNUB Flash Socket +css( PDIV, { 'position' : 'absolute', 'top' : -SECOND } ); + +if ('opera' in window || attr( PDIV, 'flash' )) PDIV['innerHTML'] = + ''; + +var pubnubs = $('pubnubs') || {}; + +// PUBNUB READY TO CONNECT +function ready() { PUBNUB['time'](rnow); +PUBNUB['time'](function(t){ timeout( function() { + if (READY) return; + READY = 1; + each( READY_BUFFER, function(sub) { + sub[2]['subscribe']( sub[0], sub[1] ) + } ); +}, SECOND ); }); } + +// Bind for PUBNUB Readiness to Subscribe +bind( 'load', window, function(){ timeout( ready, 0 ) } ); + +// Create Interface for Opera Flash +PUBNUB['rdx'] = function( id, data ) { + if (!data) return FDomainRequest[id]['onerror'](); + FDomainRequest[id]['responseText'] = unescape(data); + FDomainRequest[id]['onload'](); +}; + +function FDomainRequest() { + if (!pubnubs['get']) return 0; + + var fdomainrequest = { + 'id' : FDomainRequest['id']++, + 'send' : function() {}, + 'abort' : function() { fdomainrequest['id'] = {} }, + 'open' : function( method, url ) { + FDomainRequest[fdomainrequest['id']] = fdomainrequest; + pubnubs['get']( fdomainrequest['id'], url ); + } + }; + + return fdomainrequest; +} +FDomainRequest['id'] = SECOND; + +// jQuery Interface +window['jQuery'] && (window['jQuery']['PUBNUB'] = PUBNUB); + +// For Testling.js - http://testling.com/ +typeof module !== 'undefined' && (module.exports = PUBNUB) && ready(); + +})(); diff --git a/javascript/3.4/pubnub.as b/javascript/3.4/pubnub.as new file mode 100644 index 00000000..a10e9985 --- /dev/null +++ b/javascript/3.4/pubnub.as @@ -0,0 +1,47 @@ +package { + import flash.external.ExternalInterface; + import flash.display.Sprite; + import flash.net.URLLoader; + import flash.net.URLRequest; + import flash.events.Event; + import flash.events.IOErrorEvent; + import flash.events.SecurityErrorEvent; + import flash.system.Security; + import flash.utils.setTimeout; + + public class pubnub extends Sprite { + + Security.allowDomain("*"); + Security.allowInsecureDomain("*"); + + ExternalInterface.addCallback( "get", function( + id:Number, + url:String + ):void { + function handler(e:Event):void { + var loader:URLLoader = URLLoader(e.target) + , data:String = loader.data + , timeout:int = 1; + + if (e.type == 'securityError') { + data = '[1,"S"]'; + timeout = 1000; + } + + setTimeout( function delayed():void { + ExternalInterface.call( "PUBNUB.rdx", id, escape(data) ); + loader.close(); + }, timeout ); + } + + var loader:URLLoader = new URLLoader(); + + loader.addEventListener( Event.COMPLETE, handler ); + loader.addEventListener( IOErrorEvent.IO_ERROR, handler ); + loader.addEventListener( + SecurityErrorEvent.SECURITY_ERROR, handler + ); + loader.load(new URLRequest(url)); + }); + } +} diff --git a/javascript/3.4/pubnub.swf b/javascript/3.4/pubnub.swf new file mode 100644 index 00000000..1fce400b Binary files /dev/null and b/javascript/3.4/pubnub.swf differ diff --git a/javascript/3.4/tests/head-test.htm b/javascript/3.4/tests/head-test.htm new file mode 100644 index 00000000..36f1e257 --- /dev/null +++ b/javascript/3.4/tests/head-test.htm @@ -0,0 +1,40 @@ + + + + PubNub JavaScript HEAD INIT TEST + + + + +
+ +

Head Test

+
Wait here for an alert() message.
+ +
+
+ diff --git a/javascript/3.4/tests/head.load.min.js b/javascript/3.4/tests/head.load.min.js new file mode 100644 index 00000000..6242b0fa --- /dev/null +++ b/javascript/3.4/tests/head.load.min.js @@ -0,0 +1,8 @@ +/** + Head JS The only script in your + Copyright Tero Piirainen (tipiirai) + License MIT / http://bit.ly/mit-license + Version 0.96 + + http://headjs.com +*/(function(a){function z(){d||(d=!0,s(e,function(a){p(a)}))}function y(c,d){var e=a.createElement("script");e.type="text/"+(c.type||"javascript"),e.src=c.src||c,e.async=!1,e.onreadystatechange=e.onload=function(){var a=e.readyState;!d.done&&(!a||/loaded|complete/.test(a))&&(d.done=!0,d())},(a.body||b).appendChild(e)}function x(a,b){if(a.state==o)return b&&b();if(a.state==n)return k.ready(a.name,b);if(a.state==m)return a.onpreload.push(function(){x(a,b)});a.state=n,y(a.url,function(){a.state=o,b&&b(),s(g[a.name],function(a){p(a)}),u()&&d&&s(g.ALL,function(a){p(a)})})}function w(a,b){a.state===undefined&&(a.state=m,a.onpreload=[],y({src:a.url,type:"cache"},function(){v(a)}))}function v(a){a.state=l,s(a.onpreload,function(a){a.call()})}function u(a){a=a||h;var b;for(var c in a){if(a.hasOwnProperty(c)&&a[c].state!=o)return!1;b=!0}return b}function t(a){return Object.prototype.toString.call(a)=="[object Function]"}function s(a,b){if(!!a){typeof a=="object"&&(a=[].slice.call(a));for(var c=0;c + + + PubNub JavaScript MailTO Fix + + +
+ + +
+ × +

PubNub MailTO Test for JavaScript on Mobile and Desktop Web Browser

+
+ + + +
0
+ +
+ + +
+ diff --git a/javascript/3.4/tests/multiplexing.html b/javascript/3.4/tests/multiplexing.html new file mode 100644 index 00000000..984964e0 --- /dev/null +++ b/javascript/3.4/tests/multiplexing.html @@ -0,0 +1,61 @@ + + + + + PubNub JavaScript Multiplexing Test + + + + +
+ +
...
+ +
+ + + +
+ diff --git a/javascript/3.4/tests/presence-ssl.html b/javascript/3.4/tests/presence-ssl.html new file mode 100644 index 00000000..4482b921 --- /dev/null +++ b/javascript/3.4/tests/presence-ssl.html @@ -0,0 +1,60 @@ + + + + + PubNub Presence SSL Test + + + + + + + +
+ Open the + Developers Console + and watch the presence events section to ensure join/leave. +
+ + + + +
+ + + + + diff --git a/javascript/3.4/tests/ssl-test.html b/javascript/3.4/tests/ssl-test.html new file mode 100644 index 00000000..c8f125cf --- /dev/null +++ b/javascript/3.4/tests/ssl-test.html @@ -0,0 +1,52 @@ + + + +
+ +
+ + + + diff --git a/javascript/3.4/tests/test.js b/javascript/3.4/tests/test.js new file mode 100644 index 00000000..0b925cfd --- /dev/null +++ b/javascript/3.4/tests/test.js @@ -0,0 +1,81 @@ +var test = require('testling'); +var PUBNUB = require('../pubnub-3.4'); +var channel = 'unit-test-pubnub-channel'; + +test('PUBNUB JavaScript API', function (test) { + var pubnub = PUBNUB.init({ + publish_key : 'demo', + subscribe_key : 'demo' + }); + + test.plan(14); + + test.ok(PUBNUB); + + test.ok(pubnub); + test.ok(pubnub.publish); + test.ok(pubnub.subscribe); + test.ok(pubnub.history); + test.ok(pubnub.detailedHistory); + test.ok(pubnub.time); + + function publish_test() { + pubnub.publish({ + channel : channel, + message : { test : "test" }, + callback : function(response) { + test.ok(response[0]); + test.equal( response[1], 'Sent' ); + } + }); + } + + function time_test() { + pubnub.time(function(time){ + test.ok(time); + uuid_test(); + }); + } + + function uuid_test() { + pubnub.uuid(function(uuid){ + test.ok(uuid); + history_test(); + }); + } + + function history_test(history) { + pubnub.history({ + limit : 1, + channel : channel, + callback : function(messages) { + test.ok(messages); + test.equal( messages[0].test, "test" ); + test.end(); + } + }); + } + + function detailedHistory_test(history) { + pubnub.detailedHistory({ + count : 1, + channel : channel, + callback : function(messages) { + test.ok(messages); + test.equal( messages[0][0].test, "test" ); + test.end(); + } + }); + } + pubnub.subscribe({ + channel : channel, + connect : publish_test, + callback : function(message) { + test.ok(message); + test.equal( message.test, "test" ); + time_test(); + } + }); + +}); + diff --git a/javascript/3.4/tests/test.sh b/javascript/3.4/tests/test.sh new file mode 100755 index 00000000..4636b293 --- /dev/null +++ b/javascript/3.4/tests/test.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +## ------------------------------------------------ +## PubNub 3.4 Real-time Cloud Push API - JAVASCRIPT +## ------------------------------------------------ + +## ---------------------------------------------------- +## +## TESTLING - PubNub JavaScript API for Web Browsers +## uses Testling Cloud Service +## for QA and Deployment. +## +## http://www.testling.com/ +## You need this to run './test.sh' unit test. +## +## ---------------------------------------------------- + +if [ -z "$1" ] +then + echo -e "\n\tUSER:PASSWD Required: http://testling.com/\n" + exit +fi + +browsers='firefox/3.6' +browsers=$browsers',firefox/9.0' +browsers=$browsers',firefox/10.0' +browsers=$browsers',chrome/16.0' +browsers=$browsers',chrome/17.0' +browsers=$browsers',iexplore/7.0' +browsers=$browsers',iexplore/8.0' +browsers=$browsers',iexplore/9.0' +browsers=$browsers',safari/5.1' + +echo -e "Testing: $browsers" + +noinstrument='pubnub-3.4.js,test.js' + +tar -cf- test.js ../pubnub-3.4.js | \ + curl -u $1 -sSNT- \ + "testling.com/?noinstrument=$noinstrument&browsers=$browsers" + diff --git a/javascript/3.4/tests/unit-test.html b/javascript/3.4/tests/unit-test.html new file mode 100644 index 00000000..b6504383 --- /dev/null +++ b/javascript/3.4/tests/unit-test.html @@ -0,0 +1,246 @@ + + + + + PubNub JavaScript Unit Test + + + + +
+ + +
+ × +

PubNub Unit Tests for JavaScript on Mobile and Desktop Web Browser

+
+ + +
+ + + 100% Successful + Finished With Errors + ... +
+ + + +
Pass/FailTest Ready +
+ + + + +
+ + +
+