diff --git a/.gitignore b/.gitignore index da23d0d..9f7eacf 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ build/Release # Deployed apps should consider commenting this line out: # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git node_modules + +# Operating system junk files +.DS_Store diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..7b916fe --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,24 @@ +module.exports = function(grunt) { + grunt.initConfig({ + uglify: { + options: { + report: 'gzip', + sourceMap: true, + preserveComments: 'some', + wrap: 'Talker' + }, + dist: { + files: { + 'dist/talker.min.js': [ + 'src/talker.js' + ] + } + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-uglify'); + + grunt.registerTask('default', ['uglify']); +}; + diff --git a/README.md b/README.md index 87ca9ba..85d0f73 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ talker.js ========= -A tiny, promise-based library for cross-origin communication between frames and windows. +A tiny (under 4kB), promise-based library for cross-origin communication between frames and windows. + +Building +-------- + +``` +npm install -g grunt-cli +npm install +grunt +``` diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..c535569 --- /dev/null +++ b/bower.json @@ -0,0 +1,26 @@ +{ + "name": "talker.js", + "version": "1.0.0", + "homepage": "https://github.com/secondstreet/talker.js", + "author": "Second Street ", + "description": "A tiny, promise-based library for cross-origin communication between frames and windows.", + "main": "dist/talker.js", + "moduleType": [ + "globals" + ], + "keywords": [ + "iframe", + "postMessage", + "cross-domain", + "cross-origin", + "promise" + ], + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ] +} diff --git a/dist/talker.min.js b/dist/talker.min.js new file mode 100644 index 0000000..d84627c --- /dev/null +++ b/dist/talker.min.js @@ -0,0 +1,7 @@ +!function(a,b){b.Talker=a;/*! + * Talker.js 1.0.0 + * Copyright 2014 Second Street + * MIT License + */ +var c="application/x-talkerjs-v1+json",d="timeout",e=f,f={};!function(a){function b(a){return"function"==typeof a}function c(a){"undefined"!=typeof setImmediate?setImmediate(a):"undefined"!=typeof process&&process.nextTick?process.nextTick(a):setTimeout(a,0)}a[0][a[1]]=function d(){function a(a,b){return null==e&&null!=a&&(e=a,f=b,g.length&&c(function(){for(var a=0;a0)return this._flushQueue()}return this._queue},Talker.Message=function(a,b,d){return this.talker=a,this.namespace=b,this.data=d,this.type=c,this},Talker.OutgoingMessage=function(a,b,c,d){Talker.Message.call(this,a,b,c),this.responseToId=d||null,this.id=this.talker._nextId()},Talker.OutgoingMessage.prototype=h(Talker.Message.prototype),Talker.OutgoingMessage.prototype.constructor=Talker.Message,Talker.OutgoingMessage.prototype.toJSON=function(){return{id:this.id,responseToId:this.responseToId,namespace:this.namespace,data:this.data,type:this.type}},Talker.IncomingMessage=function(a,b,c,d){Talker.Message.call(this,a,b,c),this.id=d},Talker.IncomingMessage.prototype=h(Talker.Message.prototype),Talker.IncomingMessage.prototype.constructor=Talker.Message,Talker.IncomingMessage.prototype.respond=function(a){return this.talker.send(null,a,this.id)}}({},function(){return this}()); +//# sourceMappingURL=talker.min.js.map \ No newline at end of file diff --git a/dist/talker.min.js.map b/dist/talker.min.js.map new file mode 100644 index 0000000..a674a95 --- /dev/null +++ b/dist/talker.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"talker.min.js","sources":["?","../src/talker.js"],"names":["exports","global","TALKER_TYPE","TALKER_ERR_TIMEOUT","_module","module","c","f","g","h","setImmediate","process","nextTick","setTimeout","m","l","a","k","b","length","then","n","e","d","TypeError","call","apply","arguments","push","window","pinkySwear","objectCreate","proto","ctor","prototype","Talker","remoteWindow","remoteOrigin","this","timeout","handshaken","handshake","_id","_queue","_sent","_this","addEventListener","messageEvent","_receiveMessage","_sendHandshake","send","namespace","data","responseToId","message","OutgoingMessage","promise","id","_flushQueue","Error","object","isHandshake","JSON","parse","_isSafeMessage","source","origin","type","handshakeConfirmation","_handleHandshake","_handleMessage","safeSource","safeOrigin","safeType","rawObject","IncomingMessage","responseId","_respondToMessage","_broadcastMessage","onMessage","confirmation","handshakeType","_postMessage","_nextId","postMessage","stringify","shift","Message","talker","constructor","toJSON","respond"],"mappings":"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"} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..834ff8d --- /dev/null +++ b/package.json @@ -0,0 +1,30 @@ +{ + "name": "talker.js", + "version": "1.0.0", + "description": "A tiny, promise-based library for cross-origin communication between frames and windows.", + "main": "src/talker.js", + "devDependencies": { + "grunt": "^0.4.5", + "grunt-contrib-uglify": "^0.5.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git://github.com/secondstreet/talker.js.git" + }, + "keywords": [ + "iframe", + "postMessage", + "cross-domain", + "cross-origin", + "promise" + ], + "author": "Second Street ", + "license": "MIT", + "bugs": { + "url": "https://github.com/secondstreet/talker.js/issues" + }, + "homepage": "https://github.com/secondstreet/talker.js" +} diff --git a/src/talker.js b/src/talker.js new file mode 100755 index 0000000..f338584 --- /dev/null +++ b/src/talker.js @@ -0,0 +1,307 @@ +/*! + * Talker.js 1.0.0 + * Copyright 2014 Second Street + * MIT License + */ +//region Constants +var TALKER_TYPE = 'application/x-talkerjs-v1+json'; +var TALKER_ERR_TIMEOUT = 'timeout'; +//endregion Constants + +//region Third-Party Libraries +/** + * PinkySwear.js 2.1 + * License: Public Domain 0) { return this._flushQueue(); } + } + return this._queue; +}; +//endregion Private Methods + +//region Talker Message +/** + * Talker Message + * Used to wrap a message for Talker with some extra metadata and methods + * @param {Talker} talker - A {@link Talker} instance that will be used to send responses + * @param {string} namespace - A namespace to with which to categorize messages + * @param {Object} data - A JSON.stringify-able object + * @property {number} id + * @property {number} responseToId + * @property {string} namespace + * @property {Object} data + * @property {string} type + * @property {Talker} talker + * @returns {Talker.Message} + * @constructor + */ +Talker.Message = function(talker, namespace, data) { + this.talker = talker; + this.namespace = namespace; + this.data = data; + this.type = TALKER_TYPE; + + return this; +}; +//endregion Talker Message + +//region Talker Outgoing Message +/** + * Talker Outgoing Message + * @extends Talker.Message + * @param {Talker} talker - A {@link Talker} instance that will be used to send responses + * @param {string} namespace - A namespace to with which to categorize messages + * @param {Object} data - A JSON.stringify-able object + * @param [responseToId=null] - If this is a response to a previous message, its ID. + * @constructor + */ +Talker.OutgoingMessage = function(talker, namespace, data, responseToId) { + Talker.Message.call(this, talker, namespace, data); + this.responseToId = responseToId || null; + this.id = this.talker._nextId(); +}; +Talker.OutgoingMessage.prototype = objectCreate(Talker.Message.prototype); +Talker.OutgoingMessage.prototype.constructor = Talker.Message; + +/** + * @returns {Object} + * @public + */ +Talker.OutgoingMessage.prototype.toJSON = function() { + return { + id: this.id, + responseToId: this.responseToId, + namespace: this.namespace, + data: this.data, + type: this.type + }; +}; +//endregion Talker Outgoing Message + +//region Talker Incoming Message +/** + * Talker Incoming Message + * @extends Talker.Message + * @param {Talker} talker - A {@link Talker} instance that will be used to send responses + * @param {string} namespace - A namespace to with which to categorize messages + * @param {Object} data - A JSON.stringify-able object + * @param {number} id - The ID received from the other side + * @constructor + */ +Talker.IncomingMessage = function(talker, namespace, data, id) { + Talker.Message.call(this, talker, namespace, data); + this.id = id; +}; +Talker.IncomingMessage.prototype = objectCreate(Talker.Message.prototype); +Talker.IncomingMessage.prototype.constructor = Talker.Message; + +/** + * Respond + * Responds to a message + * @param {Object} data - A JSON.stringify-able object + * @public + * @returns {Promise} - Resolves with a {@link Talker.IncomingMessage}, or rejects with an Error + */ +Talker.IncomingMessage.prototype.respond = function(data) { + return this.talker.send(null, data, this.id); +}; +//endregion Talker Incoming Message