From 4faf92561e3bf2d2e8ff3282ec7df15c2210a8f7 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 25 Apr 2015 00:41:07 -0400 Subject: [PATCH 01/46] Started massive restructuring: - msngr.extend can now accept a method which it automatically executes passing in an external and an internal interface - Internal interface is only accessible within msngr - Added debug property when flagged exposes the internal interface for testing and debugging - Moved entire memory store to use interface interface - Moved all references to utilities down a level (so msngr.utils.exist() is now msngr.exist()) - Changed msngr to be a function rather than a pure object; not yet implemented but will seed the future of the API - Set version to 2.0.0 - Added additional unit tests to cover a new changes --- Gruntfile.js | 8 +- msngr.js | 842 ++++++++++++++++++---------------- msngr.min.js | 2 +- package.json | 2 +- src/actions/action.js | 10 +- src/actions/dom.js | 26 +- src/builders/message.js | 4 +- src/main.aspec.js | 29 ++ src/main.js | 59 ++- src/messengers/bind.js | 34 +- src/messengers/mitter.js | 91 ++-- src/module.exports.js | 5 + src/store/memory.aspec.js | 155 +++---- src/store/memory.js | 215 ++++----- src/utils/converters.aspec.js | 12 +- src/utils/converters.js | 16 +- src/utils/dom.cspec.js | 146 +++--- src/utils/dom.js | 156 ++++--- src/utils/misc.aspec.js | 32 +- src/utils/misc.js | 58 ++- src/utils/validation.aspec.js | 546 +++++++++++----------- src/utils/validation.cspec.js | 8 +- src/utils/validation.js | 168 ++++--- 23 files changed, 1381 insertions(+), 1243 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index a63f297..b745e7c 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -83,11 +83,11 @@ module.exports = (function (grunt) { var pkg = grunt.file.readJSON('package.json'); var main = fs.readFileSync("src/main.js", { encoding: "utf8" }); - var indexOfVersion = main.indexOf("version: "); - var indexOfNextComma = main.indexOf(",", indexOfVersion); + var indexOfVersion = main.indexOf("external.version = "); + var indexOfNextSemiColon = main.indexOf(";", indexOfVersion); var ified = main.substring(0, indexOfVersion); - ified = ified + "version: \"" + pkg.version + "\""; - ified = ified + main.substring(indexOfNextComma, main.length); + ified = ified + "external.version = \"" + pkg.version + "\""; + ified = ified + main.substring(indexOfNextSemiColon, main.length); fs.writeFileSync("src/main.js", ified, { encoding: "utf8" }); }); diff --git a/msngr.js b/msngr.js index 786203d..e0e8047 100644 --- a/msngr.js +++ b/msngr.js @@ -1,148 +1,169 @@ +/* + main.js + The main entry point for msngr.js. Covers internal and external interface generation, + versioning (for programmatic access) and the core extend method. +*/ var msngr = msngr || (function () { "use strict"; - return { - version: "1.1.0", - extend: function (obj, target) { - target = (target || msngr); - if (Object.prototype.toString.call(obj) === "[object Object]") { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - if (Object.prototype.toString.call(obj[key]) === "[object Object]") { - if (target[key] === undefined) { - target[key] = { }; - } - target[key] = msngr.extend(obj[key], target[key]); - } else if (Object.prototype.toString.call(obj[key]) === "[object Array]") { - target[key] = (target[key] || []).concat(obj[key]); - } else { - target[key] = obj[key]; + var internal = { }; + var external = function ( input ) { }; + + external.version = "2.0.0"; + + external.extend = function (obj, target) { + target = (target || external); + if (Object.prototype.toString.call(obj) === "[object Function]") { + obj = obj.apply(this, [external, internal]); + } + + if (Object.prototype.toString.call(obj) === "[object Object]") { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (Object.prototype.toString.call(obj[key]) === "[object Object]") { + if (target[key] === undefined) { + target[key] = { }; } + target[key] = external.extend(obj[key], target[key]); + } else if (Object.prototype.toString.call(obj[key]) === "[object Array]") { + target[key] = (target[key] || []).concat(obj[key]); + } else { + target[key] = obj[key]; } } } - return target; } + return target; }; + + // Create a debug property to allow explicit exposure to the internal object structure. + // This should only be used during unit test runs and debugging. + Object.defineProperty(external, "debug", { + set: function (value) { + if (value === true) { + external.internal = internal; + } else if (value === false) { + delete external.internal; + } + } + }); + + return external; }()); -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { - utils: { - argumentsToArray: function (args) { - if (msngr.utils.isArray(args)) { - return args; - } - - return Array.prototype.slice.call(args, 0); + argumentsToArray: function (args) { + if (external.isArray(args)) { + return args; } + + return Array.prototype.slice.call(args, 0); } }; -}())); +})); -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { - utils: { - isHtmlElement: function (obj) { - var t = this.getType(obj); - return (t.indexOf("[object HTML") === 0) || (t.indexOf("[object global]") === 0); - }, - isNodeList: function (obj) { - return (this.getType(obj) === "[object NodeList]"); - }, - findElement: function (element, root) { - var elms = msngr.utils.findElements(element); - if (elms !== undefined && elms.length > 0) { - return elms[0]; - } + isHtmlElement: function (obj) { + var t = this.getType(obj); + return (t.indexOf("[object HTML") === 0) || (t.indexOf("[object global]") === 0); + }, + isNodeList: function (obj) { + return (this.getType(obj) === "[object NodeList]"); + }, + findElement: function (element, root) { + var elms = external.findElements(element); + if (elms !== undefined && elms.length > 0) { + return elms[0]; + } - return elms; - }, - findElements: function (selector, root) { - var elm; - if (msngr.utils.isHtmlElement(selector)) { - elm = selector; - } + return elms; + }, + findElements: function (selector, root) { + var elm; + if (external.isHtmlElement(selector)) { + elm = selector; + } - if (elm === undefined && msngr.utils.isString(selector)) { - var doc = root || document; - var result = doc.querySelectorAll(selector); - if (result !== null) { - elm = result; - } + if (elm === undefined && external.isString(selector)) { + var doc = root || document; + var result = doc.querySelectorAll(selector); + if (result !== null) { + elm = result; } + } - return elm; - }, - getDomPath: function (element) { - var node = msngr.utils.isHtmlElement(element) ? element : undefined; - if (node === undefined) { - return undefined; - } + return elm; + }, + getDomPath: function (element) { + var node = external.isHtmlElement(element) ? element : undefined; + if (node === undefined) { + return undefined; + } - if (node.id === undefined) { - node.id = msngr.utils.id(); - } + if (node.id === undefined) { + node.id = external.id(); + } - return "#" + node.id; - }, - querySelectorAllWithEq: function (selector, root) { - if (selector === undefined) { - return null; + return "#" + node.id; + }, + querySelectorAllWithEq: function (selector, root) { + if (selector === undefined) { + return null; + } + var doc = root || document; + var queue = []; + var process = function (input) { + if (input.indexOf(":eq(") === -1) { + return undefined; } - var doc = root || document; - var queue = []; - var process = function (input) { - if (input.indexOf(":eq(") === -1) { - return undefined; - } - - var eqlLoc = input.indexOf(":eq("); - var sel = input.substring(0, eqlLoc); - var ind = input.substring((eqlLoc + 4), input.indexOf(")", eqlLoc)); - selector = input.substring(input.indexOf(")", eqlLoc) + 1, input.length); - if (sel.charAt(0) === ">") { - sel = sel.substring(1, sel.length); - } + var eqlLoc = input.indexOf(":eq("); + var sel = input.substring(0, eqlLoc); + var ind = input.substring((eqlLoc + 4), input.indexOf(")", eqlLoc)); + selector = input.substring(input.indexOf(")", eqlLoc) + 1, input.length); - if (selector.charAt(0) === ">") { - selector = selector.substring(1, selector.length); - } - - queue.push({ - selector: sel, - index: parseInt(ind, 10) - }); - } - while (selector.indexOf(":eq") !== -1) { - process(selector); + if (sel.charAt(0) === ">") { + sel = sel.substring(1, sel.length); } - var result; - while (queue.length > 0) { - var item = queue.shift(); - result = (result || doc).querySelectorAll(item.selector)[item.index]; + if (selector.charAt(0) === ">") { + selector = selector.substring(1, selector.length); } - if (selector.trim().length > 0) { - return (result || doc).querySelectorAll(selector); - } - return [result]; - }, - querySelectorWithEq: function (selector) { - return msngr.utils.querySelectorAllWithEq(selector)[0]; + queue.push({ + selector: sel, + index: parseInt(ind, 10) + }); } + while (selector.indexOf(":eq") !== -1) { + process(selector); + } + + var result; + while (queue.length > 0) { + var item = queue.shift(); + result = (result || doc).querySelectorAll(item.selector)[item.index]; + } + + if (selector.trim().length > 0) { + return (result || doc).querySelectorAll(selector); + } + return [result]; + }, + querySelectorWithEq: function (selector) { + return external.querySelectorAllWithEq(selector)[0]; } }; -}())); +})); -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; var nowPerformance = function () { @@ -162,138 +183,134 @@ msngr.extend((function () { var lastNow = undefined; return { - utils: { - id: function () { - var d = msngr.utils.now(); - var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = (d + Math.random()*16)%16 | 0; - d = Math.floor(d/16); - return (c=='x' ? r : (r&0x3|0x8)).toString(16); - }); - return uuid; - }, - now: function (noDuplicate) { - if (nowExec === undefined) { - if (typeof performance !== "undefined") { - nowExec = nowPerformance; - nowExecDebugLabel = "performance"; - } else if (typeof process !== "undefined") { - nowExec = nowNode; - nowExecDebugLabel = "node"; - } else { - nowExec = nowLegacy; - nowExecDebugLabel = "legacy"; - } - } - var now = nowExec(); - if (noDuplicate === true && lastNow === now) { - return msngr.utils.now(noDuplicate); + id: function () { + var d = external.now(); + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = (d + Math.random()*16)%16 | 0; + d = Math.floor(d/16); + return (c=='x' ? r : (r&0x3|0x8)).toString(16); + }); + return uuid; + }, + now: function (noDuplicate) { + if (nowExec === undefined) { + if (typeof performance !== "undefined") { + nowExec = nowPerformance; + nowExecDebugLabel = "performance"; + } else if (typeof process !== "undefined") { + nowExec = nowNode; + nowExecDebugLabel = "node"; + } else { + nowExec = nowLegacy; + nowExecDebugLabel = "legacy"; } - lastNow = now; - return now; } + var now = nowExec(); + if (noDuplicate === true && lastNow === now) { + return external.now(noDuplicate); + } + lastNow = now; + return now; } }; -}())); +})); -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { - utils: { - getType: function (obj) { - if (!msngr.utils.exist(obj)) { - return "" + obj; + getType: function (obj) { + if (!external.exist(obj)) { + return "" + obj; + } + return Object.prototype.toString.call(obj); + }, + isArguments: function (obj) { + return (external.getType(obj) === "[object Arguments]"); + }, + areArguments: function () { + return external.reiterativeValidation(external.isArguments, external.argumentsToArray(arguments)); + }, + isNullOrUndefined: function (obj) { + return (obj === undefined || obj === null); + }, + exist: function (obj) { + return !external.isNullOrUndefined(obj); + }, + exists: function () { + return external.reiterativeValidation(external.exist, external.argumentsToArray(arguments)); + }, + isString: function (str) { + return (external.getType(str) === "[object String]"); + }, + areStrings: function () { + return external.reiterativeValidation(external.isString, external.argumentsToArray(arguments)); + }, + isDate: function (obj) { + return (external.getType(obj) === "[object Date]"); + }, + areDates: function () { + return external.reiterativeValidation(external.isDate, external.argumentsToArray(arguments)); + }, + isArray: function (obj) { + return (external.getType(obj) === "[object Array]"); + }, + areArrays: function () { + return external.reiterativeValidation(external.isArray, external.argumentsToArray(arguments)); + }, + isNumber: function (obj) { + return (external.getType(obj) === "[object Number]"); + }, + areNumbers: function () { + return external.reiterativeValidation(external.isNumber, external.argumentsToArray(arguments)); + }, + isObject: function (obj) { + return (external.getType(obj) === "[object Object]"); + }, + areObjects: function () { + return external.reiterativeValidation(external.isObject, external.argumentsToArray(arguments)); + }, + isFunction: function (func) { + return (external.getType(func) === "[object Function]"); + }, + areFunctions: function () { + return external.reiterativeValidation(external.isFunction, external.argumentsToArray(arguments)); + }, + isEmptyString: function (str) { + var isStr = external.isString(str); + if (str === undefined || str === null || (isStr && str.toString().trim().length === 0)) { + return true; + } + return false; + }, + areEmptyStrings: function () { + return external.reiterativeValidation(external.isEmptyString, external.argumentsToArray(arguments)); + }, + hasWildCard: function (str) { + return (str.indexOf("*") !== -1); + }, + reiterativeValidation: function (validationMethod, inputs) { + var result = false; + if (external.exist(validationMethod) && external.exist(inputs)) { + if (!external.isArray(inputs)) { + inputs = [inputs]; } - return Object.prototype.toString.call(obj); - }, - isArguments: function (obj) { - return (msngr.utils.getType(obj) === "[object Arguments]"); - }, - areArguments: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isArguments, msngr.utils.argumentsToArray(arguments)); - }, - isNullOrUndefined: function (obj) { - return (obj === undefined || obj === null); - }, - exist: function (obj) { - return !msngr.utils.isNullOrUndefined(obj); - }, - exists: function () { - return msngr.utils.reiterativeValidation(msngr.utils.exist, msngr.utils.argumentsToArray(arguments)); - }, - isString: function (str) { - return (msngr.utils.getType(str) === "[object String]"); - }, - areStrings: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isString, msngr.utils.argumentsToArray(arguments)); - }, - isDate: function (obj) { - return (msngr.utils.getType(obj) === "[object Date]"); - }, - areDates: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isDate, msngr.utils.argumentsToArray(arguments)); - }, - isArray: function (obj) { - return (msngr.utils.getType(obj) === "[object Array]"); - }, - areArrays: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isArray, msngr.utils.argumentsToArray(arguments)); - }, - isNumber: function (obj) { - return (msngr.utils.getType(obj) === "[object Number]"); - }, - areNumbers: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isNumber, msngr.utils.argumentsToArray(arguments)); - }, - isObject: function (obj) { - return (msngr.utils.getType(obj) === "[object Object]"); - }, - areObjects: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isObject, msngr.utils.argumentsToArray(arguments)); - }, - isFunction: function (func) { - return (msngr.utils.getType(func) === "[object Function]"); - }, - areFunctions: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isFunction, msngr.utils.argumentsToArray(arguments)); - }, - isEmptyString: function (str) { - var isStr = msngr.utils.isString(str); - if (str === undefined || str === null || (isStr && str.toString().trim().length === 0)) { - return true; - } - return false; - }, - areEmptyStrings: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isEmptyString, msngr.utils.argumentsToArray(arguments)); - }, - hasWildCard: function (str) { - return (str.indexOf("*") !== -1); - }, - reiterativeValidation: function (validationMethod, inputs) { - var result = false; - if (msngr.utils.exist(validationMethod) && msngr.utils.exist(inputs)) { - if (!msngr.utils.isArray(inputs)) { - inputs = [inputs]; - } - for (var i = 0; i < inputs.length; ++i) { - result = validationMethod.apply(this, [inputs[i]]); - if (result === false) { - break; - } + for (var i = 0; i < inputs.length; ++i) { + result = validationMethod.apply(this, [inputs[i]]); + if (result === false) { + break; } } - return result; } - } + return result; + } }; -}())); +})); /* ./src/builders/message.js */ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { @@ -323,9 +340,9 @@ msngr.extend((function () { } } }; -}())); +})); -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; // Index for id to message objects @@ -353,142 +370,143 @@ msngr.extend((function () { arr.pop(); }; - return { - store: { - index: function (message) { - if (msngr.utils.exist(message) && msngr.utils.exist(message.topic)) { - var uuid = msngr.utils.id(); - id_to_message[uuid] = message; + internal.store = { + index: function (message) { + if (external.exist(message) && external.exist(message.topic)) { + var uuid = external.id(); + id_to_message[uuid] = message; + + if (direct_index.topic_to_id[message.topic] === undefined) { + direct_index.topic_to_id[message.topic] = []; + } + direct_index.topic_to_id[message.topic].push(uuid); - if (direct_index.topic_to_id[message.topic] === undefined) { - direct_index.topic_to_id[message.topic] = []; + if (external.exist(message.category)) { + if (direct_index.topic_cat_to_id[message.topic] === undefined) { + direct_index.topic_cat_to_id[message.topic] = { }; } - direct_index.topic_to_id[message.topic].push(uuid); - if (msngr.utils.exist(message.category)) { - if (direct_index.topic_cat_to_id[message.topic] === undefined) { - direct_index.topic_cat_to_id[message.topic] = { }; - } + if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_to_id[message.topic][message.category] = []; + } + + direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); + } - if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_to_id[message.topic][message.category] = []; - } + if (external.exist(message.dataType)) { + if (direct_index.topic_type_to_id[message.topic] === undefined) { + direct_index.topic_type_to_id[message.topic] = { }; + } - direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); + if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { + direct_index.topic_type_to_id[message.topic][message.dataType] = []; } - if (msngr.utils.exist(message.dataType)) { - if (direct_index.topic_type_to_id[message.topic] === undefined) { - direct_index.topic_type_to_id[message.topic] = { }; - } + direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); + } - if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { - direct_index.topic_type_to_id[message.topic][message.dataType] = []; - } + if (external.exist(message.category) && external.exist(message.dataType)) { + if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { + direct_index.topic_cat_type_to_id[message.topic] = { }; + } - direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); + if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; } - if (msngr.utils.exist(message.category) && msngr.utils.exist(message.dataType)) { - if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { - direct_index.topic_cat_type_to_id[message.topic] = { }; - } + if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; + } - if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; - } + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); + } - if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; - } + index_count++; - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); - } + return uuid; + } + return undefined; + }, + delete: function (uuid) { + if (external.exist(uuid) && external.exist(id_to_message[uuid])) { + var message = id_to_message[uuid]; - index_count++; + if (external.exist(message.topic)) { + deleteValueFromArray(direct_index.topic_to_id[message.topic], uuid); - return uuid; - } - return undefined; - }, - delete: function (uuid) { - if (msngr.utils.exist(uuid) && msngr.utils.exist(id_to_message[uuid])) { - var message = id_to_message[uuid]; - - if (msngr.utils.exist(message.topic)) { - deleteValueFromArray(direct_index.topic_to_id[message.topic], uuid); - - if (msngr.utils.exist(message.category)) { - deleteValueFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); - } - - if (msngr.utils.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); - } - - if (msngr.utils.exist(message.category) && msngr.utils.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); - } + if (external.exist(message.category)) { + deleteValueFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); } - delete id_to_message[uuid]; - index_count--; + if (external.exist(message.dataType)) { + deleteValueFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); + } - return true; - } - return false; - }, - query: function (message) { - if (msngr.utils.exist(message)) { - if (msngr.utils.exist(message.topic)) { - // Topic Only Results - if (!msngr.utils.exist(message.category) && !msngr.utils.exist(message.dataType)) { - return direct_index.topic_to_id[message.topic] || []; - } - - // Topic + Category Results - if (msngr.utils.exist(message.category) && !msngr.utils.exist(message.dataType)) { - return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; - } - - // Topic + Data Type Results - if (msngr.utils.exist(message.dataType) && !msngr.utils.exist(message.category)) { - return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; - } - - // Topic + Category + Data Type Results - if (msngr.utils.exist(message.category) && msngr.utils.exist(message.dataType)) { - return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; - } + if (external.exist(message.category) && external.exist(message.dataType)) { + deleteValueFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); } } - return []; - }, - clear: function () { - // Index for id to message objects - id_to_message = { }; + delete id_to_message[uuid]; + index_count--; - // Direct index (no partials) for message - direct_index = { - topic_to_id: { }, - topic_cat_to_id: { }, - topic_type_to_id: { }, - topic_cat_type_to_id: { } - }; + return true; + } + return false; + }, + query: function (message) { + if (external.exist(message)) { + if (external.exist(message.topic)) { + // Topic Only Results + if (!external.exist(message.category) && !external.exist(message.dataType)) { + return direct_index.topic_to_id[message.topic] || []; + } - index_count = 0; + // Topic + Category Results + if (external.exist(message.category) && !external.exist(message.dataType)) { + return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; + } - return true; - }, - count: function () { - return index_count; + // Topic + Data Type Results + if (external.exist(message.dataType) && !external.exist(message.category)) { + return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; + } + + // Topic + Category + Data Type Results + if (external.exist(message.category) && external.exist(message.dataType)) { + return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; + } + } } + + return []; + }, + clear: function () { + // Index for id to message objects + id_to_message = { }; + + // Direct index (no partials) for message + direct_index = { + topic_to_id: { }, + topic_cat_to_id: { }, + topic_type_to_id: { }, + topic_cat_type_to_id: { } + }; + + index_count = 0; + + return true; + }, + count: function () { + return index_count; } }; -}())); -msngr.extend((function () { + // This is an internal extension; do not export explicitly. + return { }; +})); + +msngr.extend((function (external, internal) { "use strict"; // Throw statements @@ -511,10 +529,10 @@ msngr.extend((function () { var listener = function (event) { var node = this; - var path = msngr.utils.getDomPath(node); + var path = external.getDomPath(node); - if (msngr.utils.exist(registerdPaths[path])) { - if (msngr.utils.exist(registerdPaths[path][event.type])) { + if (external.exist(registerdPaths[path])) { + if (external.exist(registerdPaths[path][event.type])) { return msngr.emit(registerdPaths[path][event.type], event); } } @@ -525,32 +543,32 @@ msngr.extend((function () { return { bind: function (element, event, topic, category, dataType) { - if (!msngr.utils.exist(element) || !msngr.utils.exist(event) || !msngr.utils.exist(topic)) { + if (!external.exist(element) || !external.exist(event) || !external.exist(topic)) { throw InvalidParametersException("bind"); } - if (msngr.utils.isObject(topic) && !msngr.utils.exist(topic.topic)) { + if (external.isObject(topic) && !external.exist(topic.topic)) { throw InvalidParametersException("bind"); } - var node = msngr.utils.findElement(element); - var path = msngr.utils.getDomPath(node); + var node = external.findElement(element); + var path = external.getDomPath(node); - if (!msngr.utils.exist(registerdPaths[path])) { + if (!external.exist(registerdPaths[path])) { registerdPaths[path] = { }; } var message = undefined; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; } else { message = { }; message.topic = topic; - if (msngr.utils.exist(category)) { + if (external.exist(category)) { message.category = category; } - if (msngr.utils.exist(dataType)) { + if (external.exist(dataType)) { message.dataType = dataType; } } @@ -564,11 +582,11 @@ msngr.extend((function () { return msngr; }, unbind: function (element, event) { - var node = msngr.utils.findElement(element); - var path = msngr.utils.getDomPath(node); + var node = external.findElement(element); + var path = external.getDomPath(node); - if (msngr.utils.exist(registerdPaths[path])) { - if (msngr.utils.exist(registerdPaths[path][event])) { + if (external.exist(registerdPaths[path])) { + if (external.exist(registerdPaths[path][event])) { node.removeEventListener(event, listener); delete registerdPaths[path][event]; @@ -583,9 +601,9 @@ msngr.extend((function () { return registerdEvents; } }; -}())); +})); -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; // Throw statements @@ -626,12 +644,12 @@ msngr.extend((function () { }; var _emit = function (message, payload, callback) { - var uuids = msngr.store.query(message); + var uuids = internal.store.query(message); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var del = delegates[uuids[i]]; var params = []; - if (msngr.utils.exist(payload || message.payload)) { + if (external.exist(payload || message.payload)) { params.push(payload || message.payload); } execute(del.callback, del.context, params, message); @@ -642,7 +660,7 @@ msngr.extend((function () { }; var _on = function (message, callback) { - var uuid = msngr.store.index(message); + var uuid = internal.store.index(message); delegates[uuid] = { callback: callback, context: (message.context || this), @@ -654,22 +672,22 @@ msngr.extend((function () { }; var _drop = function (message, func) { - var uuids = msngr.store.query(message); + var uuids = internal.store.query(message); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var uuid = uuids[i]; - if (msngr.utils.exist(func)) { + if (external.exist(func)) { if (delegates[uuid].callback === func) { delete delegates[uuid]; delegateCount--; - msngr.store.delete(uuid); + internal.store.delete(uuid); } } else { delete delegates[uuid]; delegateCount--; - msngr.store.delete(uuid); + internal.store.delete(uuid); } } } @@ -678,30 +696,61 @@ msngr.extend((function () { }; return { + msg: function (topic, category, dataType) { + if (!external.exist(topic)) { + throw InvalidParameters("topic"); + } + + var message; + if (external.isObject(topic)) { + message = topic; + } else { + message = { + topic: topic, + category: category, + dataType: dataType + }; + } + + return { + emit: function (payload) { + + }, + on: function (callback) { + + }, + drop: function (callback) { + + }, + dropAll: function () { + + } + }; + }, emit: function (topic, category, dataType, payload, callback) { - if (!msngr.utils.exist(topic)) { + if (!external.exist(topic)) { throw InvalidParameters("emit"); } var message; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; - if (!msngr.utils.exist(payload) && msngr.utils.exist(category)) { + if (!external.exist(payload) && external.exist(category)) { payload = category; } - if (!msngr.utils.exist(callback) && msngr.utils.exist(dataType) && msngr.utils.isFunction(dataType)) { + if (!external.exist(callback) && external.exist(dataType) && external.isFunction(dataType)) { callback = dataType; } return _emit(message, payload, callback); } message = { }; - var args = msngr.utils.argumentsToArray(arguments); + var args = external.argumentsToArray(arguments); message.topic = args.shift(); - if (!msngr.utils.exist(payload)) { - if (args.length > 0 && msngr.utils.isObject(args[0])) { + if (!external.exist(payload)) { + if (args.length > 0 && external.isObject(args[0])) { payload = args.shift(); return _emit(message, payload); @@ -710,7 +759,7 @@ msngr.extend((function () { message.category = args.shift(); - if (args.length > 0 && msngr.utils.isObject(args[0])) { + if (args.length > 0 && external.isObject(args[0])) { payload = args.shift(); return _emit(message, payload); @@ -720,21 +769,21 @@ msngr.extend((function () { return _emit(message, payload); }, on: function (topic, category, dataType, callback) { - if (!msngr.utils.exist(topic)) { + if (!external.exist(topic)) { throw InvalidParameters("on"); } var message; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; - if (!msngr.utils.exist(callback) && msngr.utils.exist(category)) { + if (!external.exist(callback) && external.exist(category)) { callback = category; } return _on(message, callback); } if (arguments.length > 1) { message = { }; - var args = msngr.utils.argumentsToArray(arguments); + var args = external.argumentsToArray(arguments); message.topic = args.shift(); @@ -743,13 +792,13 @@ msngr.extend((function () { callback = callback || args.pop(); - if (msngr.utils.isFunction(message.category) && !msngr.utils.exist(message.dataType)) { + if (external.isFunction(message.category) && !external.exist(message.dataType)) { callback = message.category; delete message.category; delete message.dataType; } - if (msngr.utils.isFunction(message.dataType) && msngr.utils.exist(message.category)) { + if (external.isFunction(message.dataType) && external.exist(message.category)) { callback = message.dataType; delete message.dataType; } @@ -760,21 +809,21 @@ msngr.extend((function () { throw InvalidParameters("on"); }, drop: function (topic, category, dataType, callback) { - if (!msngr.utils.exist(topic)) { + if (!external.exist(topic)) { throw InvalidParameters("drop"); } var message; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; - if (!msngr.utils.exist(callback) && msngr.utils.exist(category)) { + if (!external.exist(callback) && external.exist(category)) { callback = category; } return _drop(message, callback); } if (arguments.length > 0) { message = { }; - var args = msngr.utils.argumentsToArray(arguments); + var args = external.argumentsToArray(arguments); message.topic = args.shift(); @@ -783,13 +832,13 @@ msngr.extend((function () { callback = callback || args.pop(); - if (msngr.utils.isFunction(message.category) && !msngr.utils.exist(message.dataType)) { + if (external.isFunction(message.category) && !external.exist(message.dataType)) { callback = message.category; delete message.category; delete message.dataType; } - if (msngr.utils.isFunction(message.dataType) && msngr.utils.exist(message.category)) { + if (external.isFunction(message.dataType) && external.exist(message.category)) { callback = message.dataType; delete message.dataType; } @@ -802,7 +851,7 @@ msngr.extend((function () { dropAll: function () { delegates = { }; delegateCount = 0; - msngr.store.clear(); + internal.store.clear(); return msngr; }, @@ -810,9 +859,9 @@ msngr.extend((function () { return delegateCount; } }; -}())); +})); -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; // Throw statements @@ -838,7 +887,7 @@ msngr.extend((function () { return { action: function (property, handler) { - if (!msngr.utils.exist(property) || !msngr.utils.exist(handler)) { + if (!external.exist(property) || !external.exist(handler)) { throw InvalidParameters("action"); } @@ -850,7 +899,7 @@ msngr.extend((function () { actionsCount++; }, inaction: function (property) { - if (!msngr.utils.exist(property)) { + if (!external.exist(property)) { throw InvalidParameters("inaction"); } @@ -858,7 +907,7 @@ msngr.extend((function () { actionsCount--; }, act: function (message, superWrap) { - if (!msngr.utils.exist(message) || !msngr.utils.exist(superWrap)) { + if (!external.exist(message) || !external.exist(superWrap)) { throw InvalidParameters("act"); } @@ -891,46 +940,46 @@ msngr.extend((function () { return Object.keys(actions); } }; -}())); +})); msngr.action("dom", function (message, wrap) { "use strict"; - if (msngr.utils.exist(message.dom)) { + if (msngr.exist(message.dom)) { var norm = { gather: undefined, doc: undefined }; - if (!msngr.utils.isObject(message.dom)) { - if (msngr.utils.isArray(message.dom)) { + if (!msngr.isObject(message.dom)) { + if (msngr.isArray(message.dom)) { norm.gather = message.dom; - } else if (msngr.utils.isString(message.dom)) { + } else if (msngr.isString(message.dom)) { norm.gather = [message.dom]; } } else { - if (msngr.utils.exist(message.dom.gather)) { - norm.gather = (msngr.utils.isArray(message.dom.gather) ? message.dom.gather : [message.dom.gather]); + if (msngr.exist(message.dom.gather)) { + norm.gather = (msngr.isArray(message.dom.gather) ? message.dom.gather : [message.dom.gather]); } - if (msngr.utils.exist(message.dom.root || message.dom.doc)) { + if (msngr.exist(message.dom.root || message.dom.doc)) { norm.doc = message.dom.root || message.dom.doc; } } - if (msngr.utils.exist(norm.gather) && norm.gather.length > 0) { - if (!msngr.utils.isObject(wrap.payload)) { + if (msngr.exist(norm.gather) && norm.gather.length > 0) { + if (!msngr.isObject(wrap.payload)) { wrap.payload = { }; } for (var i = 0; i < norm.gather.length; ++i) { - var elms = msngr.utils.findElements(norm.gather[i], message.dom.root); - if (msngr.utils.exist(elms) && elms.length > 0) { + var elms = msngr.findElements(norm.gather[i], message.dom.root); + if (msngr.exist(elms) && elms.length > 0) { for (var j = 0; j < elms.length; ++j) { var elm = elms[j]; var prop; - if (msngr.utils.exist(elm.getAttribute("name")) && !msngr.utils.isEmptyString(elm.getAttribute("name"))) { + if (msngr.exist(elm.getAttribute("name")) && !msngr.isEmptyString(elm.getAttribute("name"))) { prop = elm.getAttribute("name"); - } else if (msngr.utils.exist(elm.id) && !msngr.utils.isEmptyString(elm.id)) { + } else if (msngr.exist(elm.id) && !msngr.isEmptyString(elm.id)) { prop = elm.getAttribute("id"); console.log(elm.id); } else { @@ -947,6 +996,11 @@ msngr.action("dom", function (message, wrap) { return msngr; }); +/* + module.exports.js + + If we're running in a node.js / io.js context then export msngr otherwise do nothing. +*/ if (typeof module !== "undefined" && typeof module.exports !== "undefined") { module.exports = msngr; } diff --git a/msngr.min.js b/msngr.min.js index 476f8f4..65f06f3 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";return{version:"1.1.0",extend:function(obj,target){if(target=target||msngr,"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=msngr.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target}}}();msngr.extend(function(){"use strict";return{utils:{argumentsToArray:function(args){return msngr.utils.isArray(args)?args:Array.prototype.slice.call(args,0)}}}}()),msngr.extend(function(){"use strict";return{utils:{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=msngr.utils.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(msngr.utils.isHtmlElement(selector)&&(elm=selector),void 0===elm&&msngr.utils.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=msngr.utils.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=msngr.utils.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return msngr.utils.querySelectorAllWithEq(selector)[0]}}}}()),msngr.extend(function(){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{utils:{id:function(){var d=msngr.utils.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?msngr.utils.now(noDuplicate):(lastNow=now,now)}}}}()),msngr.extend(function(){"use strict";return{utils:{getType:function(obj){return msngr.utils.exist(obj)?Object.prototype.toString.call(obj):""+obj},isArguments:function(obj){return"[object Arguments]"===msngr.utils.getType(obj)},areArguments:function(){return msngr.utils.reiterativeValidation(msngr.utils.isArguments,msngr.utils.argumentsToArray(arguments))},isNullOrUndefined:function(obj){return void 0===obj||null===obj},exist:function(obj){return!msngr.utils.isNullOrUndefined(obj)},exists:function(){return msngr.utils.reiterativeValidation(msngr.utils.exist,msngr.utils.argumentsToArray(arguments))},isString:function(str){return"[object String]"===msngr.utils.getType(str)},areStrings:function(){return msngr.utils.reiterativeValidation(msngr.utils.isString,msngr.utils.argumentsToArray(arguments))},isDate:function(obj){return"[object Date]"===msngr.utils.getType(obj)},areDates:function(){return msngr.utils.reiterativeValidation(msngr.utils.isDate,msngr.utils.argumentsToArray(arguments))},isArray:function(obj){return"[object Array]"===msngr.utils.getType(obj)},areArrays:function(){return msngr.utils.reiterativeValidation(msngr.utils.isArray,msngr.utils.argumentsToArray(arguments))},isNumber:function(obj){return"[object Number]"===msngr.utils.getType(obj)},areNumbers:function(){return msngr.utils.reiterativeValidation(msngr.utils.isNumber,msngr.utils.argumentsToArray(arguments))},isObject:function(obj){return"[object Object]"===msngr.utils.getType(obj)},areObjects:function(){return msngr.utils.reiterativeValidation(msngr.utils.isObject,msngr.utils.argumentsToArray(arguments))},isFunction:function(func){return"[object Function]"===msngr.utils.getType(func)},areFunctions:function(){return msngr.utils.reiterativeValidation(msngr.utils.isFunction,msngr.utils.argumentsToArray(arguments))},isEmptyString:function(str){var isStr=msngr.utils.isString(str);return void 0===str||null===str||isStr&&0===str.toString().trim().length?!0:!1},areEmptyStrings:function(){return msngr.utils.reiterativeValidation(msngr.utils.isEmptyString,msngr.utils.argumentsToArray(arguments))},hasWildCard:function(str){return-1!==str.indexOf("*")},reiterativeValidation:function(validationMethod,inputs){var result=!1;if(msngr.utils.exist(validationMethod)&&msngr.utils.exist(inputs)){msngr.utils.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0&&msngr.utils.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.category=args.shift(),args.length>0&&msngr.utils.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.dataType=args.shift(),_emit(message,payload)))},on:function(topic,category,dataType,callback){if(!msngr.utils.exist(topic))throw InvalidParameters("on");var message;if(msngr.utils.isObject(topic))return message=topic,!msngr.utils.exist(callback)&&msngr.utils.exist(category)&&(callback=category),_on(message,callback);if(arguments.length>1){message={};var args=msngr.utils.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),msngr.utils.isFunction(message.category)&&!msngr.utils.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),msngr.utils.isFunction(message.dataType)&&msngr.utils.exist(message.category)&&(callback=message.dataType,delete message.dataType),_on(message,callback)}throw InvalidParameters("on")},drop:function(topic,category,dataType,callback){if(!msngr.utils.exist(topic))throw InvalidParameters("drop");var message;if(msngr.utils.isObject(topic))return message=topic,!msngr.utils.exist(callback)&&msngr.utils.exist(category)&&(callback=category),_drop(message,callback);if(arguments.length>0){message={};var args=msngr.utils.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),msngr.utils.isFunction(message.category)&&!msngr.utils.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),msngr.utils.isFunction(message.dataType)&&msngr.utils.exist(message.category)&&(callback=message.dataType,delete message.dataType),_drop(message,callback)}throw InvalidParameters("drop")},dropAll:function(){return delegates={},delegateCount=0,msngr.store.clear(),msngr},getMessageCount:function(){return delegateCount}}}()),msngr.extend(function(){"use strict";var InvalidParameters=function(str){return{name:"InvalidParameters",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},ReservedKeywords=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},reservedProperties=["topic","category","dataType","payload"],actions={},actionsCount=0;return{action:function(property,handler){if(!msngr.utils.exist(property)||!msngr.utils.exist(handler))throw InvalidParameters("action");if(-1!==reservedProperties.indexOf(property))throw ReservedKeywords(property);actions[property]=handler,actionsCount++},inaction:function(property){if(!msngr.utils.exist(property))throw InvalidParameters("inaction");delete actions[property],actionsCount--},act:function(message,superWrap){if(!msngr.utils.exist(message)||!msngr.utils.exist(superWrap))throw InvalidParameters("act");!function(msg,sw){if(actionsCount>0){var wrap={preventDefault:function(){sw.preventDefault()},payload:sw.payload};for(var key in msg)msg.hasOwnProperty(key)&&-1===reservedProperties.indexOf(key)&&void 0!==actions[key]&&actions[key].apply(this,[msg,wrap]);sw.payload=wrap.payload}return sw.done()}(message,superWrap)},getActionCount:function(){return actionsCount},getAvailableActions:function(){return Object.keys(actions)}}}()),msngr.action("dom",function(message,wrap){"use strict";if(msngr.utils.exist(message.dom)){var norm={gather:void 0,doc:void 0};if(msngr.utils.isObject(message.dom)?(msngr.utils.exist(message.dom.gather)&&(norm.gather=msngr.utils.isArray(message.dom.gather)?message.dom.gather:[message.dom.gather]),msngr.utils.exist(message.dom.root||message.dom.doc)&&(norm.doc=message.dom.root||message.dom.doc)):msngr.utils.isArray(message.dom)?norm.gather=message.dom:msngr.utils.isString(message.dom)&&(norm.gather=[message.dom]),msngr.utils.exist(norm.gather)&&norm.gather.length>0){msngr.utils.isObject(wrap.payload)||(wrap.payload={});for(var i=0;i0)for(var j=0;j0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)}}}),msngr.extend(function(external,internal){"use strict";return{getType:function(obj){return external.exist(obj)?Object.prototype.toString.call(obj):""+obj},isArguments:function(obj){return"[object Arguments]"===external.getType(obj)},areArguments:function(){return external.reiterativeValidation(external.isArguments,external.argumentsToArray(arguments))},isNullOrUndefined:function(obj){return void 0===obj||null===obj},exist:function(obj){return!external.isNullOrUndefined(obj)},exists:function(){return external.reiterativeValidation(external.exist,external.argumentsToArray(arguments))},isString:function(str){return"[object String]"===external.getType(str)},areStrings:function(){return external.reiterativeValidation(external.isString,external.argumentsToArray(arguments))},isDate:function(obj){return"[object Date]"===external.getType(obj)},areDates:function(){return external.reiterativeValidation(external.isDate,external.argumentsToArray(arguments))},isArray:function(obj){return"[object Array]"===external.getType(obj)},areArrays:function(){return external.reiterativeValidation(external.isArray,external.argumentsToArray(arguments))},isNumber:function(obj){return"[object Number]"===external.getType(obj)},areNumbers:function(){return external.reiterativeValidation(external.isNumber,external.argumentsToArray(arguments))},isObject:function(obj){return"[object Object]"===external.getType(obj)},areObjects:function(){return external.reiterativeValidation(external.isObject,external.argumentsToArray(arguments))},isFunction:function(func){return"[object Function]"===external.getType(func)},areFunctions:function(){return external.reiterativeValidation(external.isFunction,external.argumentsToArray(arguments))},isEmptyString:function(str){var isStr=external.isString(str);return void 0===str||null===str||isStr&&0===str.toString().trim().length?!0:!1},areEmptyStrings:function(){return external.reiterativeValidation(external.isEmptyString,external.argumentsToArray(arguments))},hasWildCard:function(str){return-1!==str.indexOf("*")},reiterativeValidation:function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.category=args.shift(),args.length>0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.dataType=args.shift(),_emit(message,payload)))},on:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("on");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_on(message,callback);if(arguments.length>1){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_on(message,callback)}throw InvalidParameters("on")},drop:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("drop");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_drop(message,callback);if(arguments.length>0){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_drop(message,callback)}throw InvalidParameters("drop")},dropAll:function(){return delegates={},delegateCount=0,internal.store.clear(),msngr},getMessageCount:function(){return delegateCount}}}),msngr.extend(function(external,internal){"use strict";var InvalidParameters=function(str){return{name:"InvalidParameters",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},ReservedKeywords=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},reservedProperties=["topic","category","dataType","payload"],actions={},actionsCount=0;return{action:function(property,handler){if(!external.exist(property)||!external.exist(handler))throw InvalidParameters("action");if(-1!==reservedProperties.indexOf(property))throw ReservedKeywords(property);actions[property]=handler,actionsCount++},inaction:function(property){if(!external.exist(property))throw InvalidParameters("inaction");delete actions[property],actionsCount--},act:function(message,superWrap){if(!external.exist(message)||!external.exist(superWrap))throw InvalidParameters("act");!function(msg,sw){if(actionsCount>0){var wrap={preventDefault:function(){sw.preventDefault()},payload:sw.payload};for(var key in msg)msg.hasOwnProperty(key)&&-1===reservedProperties.indexOf(key)&&void 0!==actions[key]&&actions[key].apply(this,[msg,wrap]);sw.payload=wrap.payload}return sw.done()}(message,superWrap)},getActionCount:function(){return actionsCount},getAvailableActions:function(){return Object.keys(actions)}}}),msngr.action("dom",function(message,wrap){"use strict";if(msngr.exist(message.dom)){var norm={gather:void 0,doc:void 0};if(msngr.isObject(message.dom)?(msngr.exist(message.dom.gather)&&(norm.gather=msngr.isArray(message.dom.gather)?message.dom.gather:[message.dom.gather]),msngr.exist(message.dom.root||message.dom.doc)&&(norm.doc=message.dom.root||message.dom.doc)):msngr.isArray(message.dom)?norm.gather=message.dom:msngr.isString(message.dom)&&(norm.gather=[message.dom]),msngr.exist(norm.gather)&&norm.gather.length>0){msngr.isObject(wrap.payload)||(wrap.payload={});for(var i=0;i0)for(var j=0;j 0) { - if (!msngr.utils.isObject(wrap.payload)) { + if (msngr.exist(norm.gather) && norm.gather.length > 0) { + if (!msngr.isObject(wrap.payload)) { wrap.payload = { }; } for (var i = 0; i < norm.gather.length; ++i) { - var elms = msngr.utils.findElements(norm.gather[i], message.dom.root); - if (msngr.utils.exist(elms) && elms.length > 0) { + var elms = msngr.findElements(norm.gather[i], message.dom.root); + if (msngr.exist(elms) && elms.length > 0) { for (var j = 0; j < elms.length; ++j) { var elm = elms[j]; var prop; - if (msngr.utils.exist(elm.getAttribute("name")) && !msngr.utils.isEmptyString(elm.getAttribute("name"))) { + if (msngr.exist(elm.getAttribute("name")) && !msngr.isEmptyString(elm.getAttribute("name"))) { prop = elm.getAttribute("name"); - } else if (msngr.utils.exist(elm.id) && !msngr.utils.isEmptyString(elm.id)) { + } else if (msngr.exist(elm.id) && !msngr.isEmptyString(elm.id)) { prop = elm.getAttribute("id"); console.log(elm.id); } else { diff --git a/src/builders/message.js b/src/builders/message.js index 82208f8..22ac185 100644 --- a/src/builders/message.js +++ b/src/builders/message.js @@ -1,7 +1,7 @@ /* ./src/builders/message.js */ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { @@ -31,4 +31,4 @@ msngr.extend((function () { } } }; -}())); +})); diff --git a/src/main.aspec.js b/src/main.aspec.js index a55fe35..a459852 100644 --- a/src/main.aspec.js +++ b/src/main.aspec.js @@ -71,4 +71,33 @@ describe("./main.js", function () { expect(obj2.this.is.a.test.yup).to.exist; expect(obj2.this.is.a.test.yup()).to.equal("yup!"); }); + + it("msngr.extend(func, target) - extends a method with properties", function () { + var myTest = function () { + return 15; + }; + + var func2 = function (external, internal) { + expect(external).to.exist; + expect(internal).to.exist; + + return { + val: 12 + }; + }; + + msngr.extend(func2, myTest); + + expect(myTest.val).to.exist; + expect(myTest.val).to.equal(12); + expect(myTest()).to.equal(15); + }); + + it("msngr.debug - property setting exports internal object for testing and debugging", function () { + expect(msngr.internal).to.not.exist; + msngr.debug = true; + expect(msngr.internal).to.exist; + msngr.debug = false; + expect(msngr.internal).to.not.exist; + }); }); diff --git a/src/main.js b/src/main.js index d0d22a5..9175564 100644 --- a/src/main.js +++ b/src/main.js @@ -1,28 +1,53 @@ +/* + main.js + The main entry point for msngr.js. Covers internal and external interface generation, + versioning (for programmatic access) and the core extend method. +*/ var msngr = msngr || (function () { "use strict"; - return { - version: "1.1.0", - extend: function (obj, target) { - target = (target || msngr); - if (Object.prototype.toString.call(obj) === "[object Object]") { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - if (Object.prototype.toString.call(obj[key]) === "[object Object]") { - if (target[key] === undefined) { - target[key] = { }; - } - target[key] = msngr.extend(obj[key], target[key]); - } else if (Object.prototype.toString.call(obj[key]) === "[object Array]") { - target[key] = (target[key] || []).concat(obj[key]); - } else { - target[key] = obj[key]; + var internal = { }; + var external = function ( input ) { }; + + external.version = "2.0.0"; + + external.extend = function (obj, target) { + target = (target || external); + if (Object.prototype.toString.call(obj) === "[object Function]") { + obj = obj.apply(this, [external, internal]); + } + + if (Object.prototype.toString.call(obj) === "[object Object]") { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (Object.prototype.toString.call(obj[key]) === "[object Object]") { + if (target[key] === undefined) { + target[key] = { }; } + target[key] = external.extend(obj[key], target[key]); + } else if (Object.prototype.toString.call(obj[key]) === "[object Array]") { + target[key] = (target[key] || []).concat(obj[key]); + } else { + target[key] = obj[key]; } } } - return target; } + return target; }; + + // Create a debug property to allow explicit exposure to the internal object structure. + // This should only be used during unit test runs and debugging. + Object.defineProperty(external, "debug", { + set: function (value) { + if (value === true) { + external.internal = internal; + } else if (value === false) { + delete external.internal; + } + } + }); + + return external; }()); diff --git a/src/messengers/bind.js b/src/messengers/bind.js index 51cc4b3..3336f3d 100644 --- a/src/messengers/bind.js +++ b/src/messengers/bind.js @@ -1,4 +1,4 @@ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; // Throw statements @@ -21,10 +21,10 @@ msngr.extend((function () { var listener = function (event) { var node = this; - var path = msngr.utils.getDomPath(node); + var path = external.getDomPath(node); - if (msngr.utils.exist(registerdPaths[path])) { - if (msngr.utils.exist(registerdPaths[path][event.type])) { + if (external.exist(registerdPaths[path])) { + if (external.exist(registerdPaths[path][event.type])) { return msngr.emit(registerdPaths[path][event.type], event); } } @@ -35,32 +35,32 @@ msngr.extend((function () { return { bind: function (element, event, topic, category, dataType) { - if (!msngr.utils.exist(element) || !msngr.utils.exist(event) || !msngr.utils.exist(topic)) { + if (!external.exist(element) || !external.exist(event) || !external.exist(topic)) { throw InvalidParametersException("bind"); } - if (msngr.utils.isObject(topic) && !msngr.utils.exist(topic.topic)) { + if (external.isObject(topic) && !external.exist(topic.topic)) { throw InvalidParametersException("bind"); } - var node = msngr.utils.findElement(element); - var path = msngr.utils.getDomPath(node); + var node = external.findElement(element); + var path = external.getDomPath(node); - if (!msngr.utils.exist(registerdPaths[path])) { + if (!external.exist(registerdPaths[path])) { registerdPaths[path] = { }; } var message = undefined; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; } else { message = { }; message.topic = topic; - if (msngr.utils.exist(category)) { + if (external.exist(category)) { message.category = category; } - if (msngr.utils.exist(dataType)) { + if (external.exist(dataType)) { message.dataType = dataType; } } @@ -74,11 +74,11 @@ msngr.extend((function () { return msngr; }, unbind: function (element, event) { - var node = msngr.utils.findElement(element); - var path = msngr.utils.getDomPath(node); + var node = external.findElement(element); + var path = external.getDomPath(node); - if (msngr.utils.exist(registerdPaths[path])) { - if (msngr.utils.exist(registerdPaths[path][event])) { + if (external.exist(registerdPaths[path])) { + if (external.exist(registerdPaths[path][event])) { node.removeEventListener(event, listener); delete registerdPaths[path][event]; @@ -93,4 +93,4 @@ msngr.extend((function () { return registerdEvents; } }; -}())); +})); diff --git a/src/messengers/mitter.js b/src/messengers/mitter.js index 9ab6772..8d4748f 100644 --- a/src/messengers/mitter.js +++ b/src/messengers/mitter.js @@ -1,4 +1,4 @@ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; // Throw statements @@ -39,12 +39,12 @@ msngr.extend((function () { }; var _emit = function (message, payload, callback) { - var uuids = msngr.store.query(message); + var uuids = internal.store.query(message); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var del = delegates[uuids[i]]; var params = []; - if (msngr.utils.exist(payload || message.payload)) { + if (external.exist(payload || message.payload)) { params.push(payload || message.payload); } execute(del.callback, del.context, params, message); @@ -55,7 +55,7 @@ msngr.extend((function () { }; var _on = function (message, callback) { - var uuid = msngr.store.index(message); + var uuid = internal.store.index(message); delegates[uuid] = { callback: callback, context: (message.context || this), @@ -67,22 +67,22 @@ msngr.extend((function () { }; var _drop = function (message, func) { - var uuids = msngr.store.query(message); + var uuids = internal.store.query(message); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var uuid = uuids[i]; - if (msngr.utils.exist(func)) { + if (external.exist(func)) { if (delegates[uuid].callback === func) { delete delegates[uuid]; delegateCount--; - msngr.store.delete(uuid); + internal.store.delete(uuid); } } else { delete delegates[uuid]; delegateCount--; - msngr.store.delete(uuid); + internal.store.delete(uuid); } } } @@ -91,30 +91,61 @@ msngr.extend((function () { }; return { + msg: function (topic, category, dataType) { + if (!external.exist(topic)) { + throw InvalidParameters("topic"); + } + + var message; + if (external.isObject(topic)) { + message = topic; + } else { + message = { + topic: topic, + category: category, + dataType: dataType + }; + } + + return { + emit: function (payload) { + + }, + on: function (callback) { + + }, + drop: function (callback) { + + }, + dropAll: function () { + + } + }; + }, emit: function (topic, category, dataType, payload, callback) { - if (!msngr.utils.exist(topic)) { + if (!external.exist(topic)) { throw InvalidParameters("emit"); } var message; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; - if (!msngr.utils.exist(payload) && msngr.utils.exist(category)) { + if (!external.exist(payload) && external.exist(category)) { payload = category; } - if (!msngr.utils.exist(callback) && msngr.utils.exist(dataType) && msngr.utils.isFunction(dataType)) { + if (!external.exist(callback) && external.exist(dataType) && external.isFunction(dataType)) { callback = dataType; } return _emit(message, payload, callback); } message = { }; - var args = msngr.utils.argumentsToArray(arguments); + var args = external.argumentsToArray(arguments); message.topic = args.shift(); - if (!msngr.utils.exist(payload)) { - if (args.length > 0 && msngr.utils.isObject(args[0])) { + if (!external.exist(payload)) { + if (args.length > 0 && external.isObject(args[0])) { payload = args.shift(); return _emit(message, payload); @@ -123,7 +154,7 @@ msngr.extend((function () { message.category = args.shift(); - if (args.length > 0 && msngr.utils.isObject(args[0])) { + if (args.length > 0 && external.isObject(args[0])) { payload = args.shift(); return _emit(message, payload); @@ -133,21 +164,21 @@ msngr.extend((function () { return _emit(message, payload); }, on: function (topic, category, dataType, callback) { - if (!msngr.utils.exist(topic)) { + if (!external.exist(topic)) { throw InvalidParameters("on"); } var message; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; - if (!msngr.utils.exist(callback) && msngr.utils.exist(category)) { + if (!external.exist(callback) && external.exist(category)) { callback = category; } return _on(message, callback); } if (arguments.length > 1) { message = { }; - var args = msngr.utils.argumentsToArray(arguments); + var args = external.argumentsToArray(arguments); message.topic = args.shift(); @@ -156,13 +187,13 @@ msngr.extend((function () { callback = callback || args.pop(); - if (msngr.utils.isFunction(message.category) && !msngr.utils.exist(message.dataType)) { + if (external.isFunction(message.category) && !external.exist(message.dataType)) { callback = message.category; delete message.category; delete message.dataType; } - if (msngr.utils.isFunction(message.dataType) && msngr.utils.exist(message.category)) { + if (external.isFunction(message.dataType) && external.exist(message.category)) { callback = message.dataType; delete message.dataType; } @@ -173,21 +204,21 @@ msngr.extend((function () { throw InvalidParameters("on"); }, drop: function (topic, category, dataType, callback) { - if (!msngr.utils.exist(topic)) { + if (!external.exist(topic)) { throw InvalidParameters("drop"); } var message; - if (msngr.utils.isObject(topic)) { + if (external.isObject(topic)) { message = topic; - if (!msngr.utils.exist(callback) && msngr.utils.exist(category)) { + if (!external.exist(callback) && external.exist(category)) { callback = category; } return _drop(message, callback); } if (arguments.length > 0) { message = { }; - var args = msngr.utils.argumentsToArray(arguments); + var args = external.argumentsToArray(arguments); message.topic = args.shift(); @@ -196,13 +227,13 @@ msngr.extend((function () { callback = callback || args.pop(); - if (msngr.utils.isFunction(message.category) && !msngr.utils.exist(message.dataType)) { + if (external.isFunction(message.category) && !external.exist(message.dataType)) { callback = message.category; delete message.category; delete message.dataType; } - if (msngr.utils.isFunction(message.dataType) && msngr.utils.exist(message.category)) { + if (external.isFunction(message.dataType) && external.exist(message.category)) { callback = message.dataType; delete message.dataType; } @@ -215,7 +246,7 @@ msngr.extend((function () { dropAll: function () { delegates = { }; delegateCount = 0; - msngr.store.clear(); + internal.store.clear(); return msngr; }, @@ -223,4 +254,4 @@ msngr.extend((function () { return delegateCount; } }; -}())); +})); diff --git a/src/module.exports.js b/src/module.exports.js index 83a7958..d373d94 100644 --- a/src/module.exports.js +++ b/src/module.exports.js @@ -1,3 +1,8 @@ +/* + module.exports.js + + If we're running in a node.js / io.js context then export msngr otherwise do nothing. +*/ if (typeof module !== "undefined" && typeof module.exports !== "undefined") { module.exports = msngr; } diff --git a/src/store/memory.aspec.js b/src/store/memory.aspec.js index b045e71..7fef5ec 100644 --- a/src/store/memory.aspec.js +++ b/src/store/memory.aspec.js @@ -14,230 +14,231 @@ describe("./stores/memory.js", function () { "use strict"; beforeEach(function() { - msngr.store.clear(); + msngr.debug = true; + msngr.internal.store.clear(); }); - it("msngr.store.index(message) - indexes a message with only a topic", function () { + it("msngr.internal.store.index(message) - indexes a message with only a topic", function () { var message = { topic: "TestTopic1" }; - expect(msngr.store.count()).to.equal(0); - var id = msngr.store.index(message); + expect(msngr.internal.store.count()).to.equal(0); + var id = msngr.internal.store.index(message); expect(id).to.exist; - expect(msngr.store.count()).to.equal(1); + expect(msngr.internal.store.count()).to.equal(1); }); - it("msngr.store.index(message) - indexes a message with a topic and category", function () { + it("msngr.internal.store.index(message) - indexes a message with a topic and category", function () { var message = { topic: "TestTopic1", category: "TestCategory1" }; - expect(msngr.store.count()).to.equal(0); - var id = msngr.store.index(message); + expect(msngr.internal.store.count()).to.equal(0); + var id = msngr.internal.store.index(message); expect(id).to.exist; - expect(msngr.store.count()).to.equal(1); + expect(msngr.internal.store.count()).to.equal(1); }); - it("msngr.store.index(message) - indexes a message with a topic and dataType", function () { + it("msngr.internal.store.index(message) - indexes a message with a topic and dataType", function () { var message = { topic: "TestTopic1", dataType: "TestDataType1" }; - expect(msngr.store.count()).to.equal(0); - var id = msngr.store.index(message); + expect(msngr.internal.store.count()).to.equal(0); + var id = msngr.internal.store.index(message); expect(id).to.exist; - expect(msngr.store.count()).to.equal(1); + expect(msngr.internal.store.count()).to.equal(1); }); - it("msngr.store.index(message) - indexes a message with a topic, category and dataType", function () { + it("msngr.internal.store.index(message) - indexes a message with a topic, category and dataType", function () { var message = { topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }; - expect(msngr.store.count()).to.equal(0); - var id = msngr.store.index(message); + expect(msngr.internal.store.count()).to.equal(0); + var id = msngr.internal.store.index(message); expect(id).to.exist; - expect(msngr.store.count()).to.equal(1); + expect(msngr.internal.store.count()).to.equal(1); }); - it("msngr.store.index(message) - invalid message shouldn't index", function () { + it("msngr.internal.store.index(message) - invalid message shouldn't index", function () { var message = { cookie: "monster" }; - expect(msngr.store.count()).to.equal(0); - var id = msngr.store.index(message); + expect(msngr.internal.store.count()).to.equal(0); + var id = msngr.internal.store.index(message); expect(id).to.not.exist; - expect(msngr.store.count()).to.equal(0); + expect(msngr.internal.store.count()).to.equal(0); }); - it("msngr.store.delete(uuid) - deletes a valid uuid", function () { + it("msngr.internal.store.delete(uuid) - deletes a valid uuid", function () { var message = { topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }; - var id = msngr.store.index(message); + var id = msngr.internal.store.index(message); expect(id).to.exist; - var result = msngr.store.delete(id); + var result = msngr.internal.store.delete(id); expect(result).to.exist; expect(result).to.equal(true); - expect(msngr.store.count()).to.equal(0); + expect(msngr.internal.store.count()).to.equal(0); }); - it("msngr.store.delete(uuid) - doesn't delete an invalid uuid", function () { - var result = msngr.store.delete("sldfjslkfjlwrjlskdfjs"); + it("msngr.internal.store.delete(uuid) - doesn't delete an invalid uuid", function () { + var result = msngr.internal.store.delete("sldfjslkfjlwrjlskdfjs"); expect(result).to.exist; expect(result).to.equal(false); - expect(msngr.store.count()).to.equal(0); + expect(msngr.internal.store.count()).to.equal(0); }); - it("msngr.store.query(message) - Correctly gets one result for a query on a topic", function () { + it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic", function () { var message = { topic: "TestTopic1" }; - var id = msngr.store.index(message); + var id = msngr.internal.store.index(message); expect(id).to.exist; - var result = msngr.store.query({ topic: "TestTopic1" }); + var result = msngr.internal.store.query({ topic: "TestTopic1" }); expect(result).to.exist; expect(result.length).to.equal(1); }); - it("msngr.store.query(message) - Correctly gets zero results for a query on a topic that doesn't exist", function () { - var result = msngr.store.query({ topic: "TestTopic1" }); + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic that doesn't exist", function () { + var result = msngr.internal.store.query({ topic: "TestTopic1" }); expect(result).to.exist; expect(result.length).to.equal(0); }); - it("msngr.store.query(message) - Correctly gets one result for a query on a topic and category", function () { + it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic and category", function () { var message = { topic: "TestTopic1", category: "TestCategory1" }; - var id = msngr.store.index(message); + var id = msngr.internal.store.index(message); expect(id).to.exist; - var result = msngr.store.query({ topic: "TestTopic1", category: "TestCategory1" }); + var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1" }); expect(result).to.exist; expect(result.length).to.equal(1); }); - it("msngr.store.query(message) - Correctly gets zero results for a query on a topic and category that doesn't exist", function () { - var result = msngr.store.query({ topic: "TestTopic1", category: "TestCategory1" }); + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic and category that doesn't exist", function () { + var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1" }); expect(result).to.exist; expect(result.length).to.equal(0); }); - it("msngr.store.query(message) - Correctly gets one result for a query on a topic, category and dataType", function () { + it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic, category and dataType", function () { var message = { topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }; - var id = msngr.store.index(message); + var id = msngr.internal.store.index(message); expect(id).to.exist; - var result = msngr.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); + var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); expect(result).to.exist; expect(result.length).to.equal(1); }); - it("msngr.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType that doesn't exist", function () { - var result = msngr.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType that doesn't exist", function () { + var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); expect(result).to.exist; expect(result.length).to.equal(0); }); - it("msngr.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where category doesn't exist", function () { + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where category doesn't exist", function () { var message = { topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }; - var id = msngr.store.index(message); + var id = msngr.internal.store.index(message); expect(id).to.exist; - var result = msngr.store.query({ topic: "TestTopic1", category: "TestCategory2", dataType: "TestDataType1" }); + var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory2", dataType: "TestDataType1" }); expect(result).to.exist; expect(result.length).to.equal(0); }); - it("msngr.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where dataType doesn't exist", function () { + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where dataType doesn't exist", function () { var message = { topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }; - var id = msngr.store.index(message); + var id = msngr.internal.store.index(message); expect(id).to.exist; - var result = msngr.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType2" }); + var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType2" }); expect(result).to.exist; expect(result.length).to.equal(0); }); - it("msngr.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where topic doesn't exist", function () { + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where topic doesn't exist", function () { var message = { topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }; - var id = msngr.store.index(message); + var id = msngr.internal.store.index(message); expect(id).to.exist; - var result = msngr.store.query({ topic: "TestTopic2", category: "TestCategory1", dataType: "TestDataType1" }); + var result = msngr.internal.store.query({ topic: "TestTopic2", category: "TestCategory1", dataType: "TestDataType1" }); expect(result).to.exist; expect(result.length).to.equal(0); }); - it("msngr.store.clear() - Clears all indexed messages", function () { + it("msngr.internal.store.clear() - Clears all indexed messages", function () { var ids = []; - ids.push(msngr.store.index({ topic: "chicken" })); - ids.push(msngr.store.index({ topic: "table", category: "50" })); - ids.push(msngr.store.index({ topic: "stairs", category: "10", dataType: "food" })); - ids.push(msngr.store.index({ topic: "whatevea", dataType: "punk" })); - - expect(msngr.store.count()).to.equal(4); - expect(msngr.store.clear()).to.equal(true); - expect(msngr.store.query({ topic: "chicken" }).length).to.equal(0); - expect(msngr.store.query({ topic: "stairs", category: "10", dataType: "food" }).length).to.equal(0); - }); - - it("msngr.store.count() - Returns a correct count", function () { - expect(msngr.store.count()).to.equal(0); - msngr.store.index({ topic: "chicken" }); - expect(msngr.store.count()).to.equal(1); - msngr.store.index({ topic: "table", category: "50" }); - expect(msngr.store.count()).to.equal(2); - msngr.store.index({ topic: "stairs", category: "10", dataType: "food" }); - expect(msngr.store.count()).to.equal(3); - expect(msngr.store.clear()).to.equal(true); - expect(msngr.store.count()).to.equal(0); - msngr.store.index({ topic: "whatevea", dataType: "punk" }); - expect(msngr.store.count()).to.equal(1); - + ids.push(msngr.internal.store.index({ topic: "chicken" })); + ids.push(msngr.internal.store.index({ topic: "table", category: "50" })); + ids.push(msngr.internal.store.index({ topic: "stairs", category: "10", dataType: "food" })); + ids.push(msngr.internal.store.index({ topic: "whatevea", dataType: "punk" })); + + expect(msngr.internal.store.count()).to.equal(4); + expect(msngr.internal.store.clear()).to.equal(true); + expect(msngr.internal.store.query({ topic: "chicken" }).length).to.equal(0); + expect(msngr.internal.store.query({ topic: "stairs", category: "10", dataType: "food" }).length).to.equal(0); + }); + + it("msngr.internal.store.count() - Returns a correct count", function () { + expect(msngr.internal.store.count()).to.equal(0); + msngr.internal.store.index({ topic: "chicken" }); + expect(msngr.internal.store.count()).to.equal(1); + msngr.internal.store.index({ topic: "table", category: "50" }); + expect(msngr.internal.store.count()).to.equal(2); + msngr.internal.store.index({ topic: "stairs", category: "10", dataType: "food" }); + expect(msngr.internal.store.count()).to.equal(3); + expect(msngr.internal.store.clear()).to.equal(true); + expect(msngr.internal.store.count()).to.equal(0); + msngr.internal.store.index({ topic: "whatevea", dataType: "punk" }); + expect(msngr.internal.store.count()).to.equal(1); + }); }); diff --git a/src/store/memory.js b/src/store/memory.js index 79188a0..c290630 100644 --- a/src/store/memory.js +++ b/src/store/memory.js @@ -1,4 +1,4 @@ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; // Index for id to message objects @@ -26,137 +26,138 @@ msngr.extend((function () { arr.pop(); }; - return { - store: { - index: function (message) { - if (msngr.utils.exist(message) && msngr.utils.exist(message.topic)) { - var uuid = msngr.utils.id(); - id_to_message[uuid] = message; + internal.store = { + index: function (message) { + if (external.exist(message) && external.exist(message.topic)) { + var uuid = external.id(); + id_to_message[uuid] = message; - if (direct_index.topic_to_id[message.topic] === undefined) { - direct_index.topic_to_id[message.topic] = []; + if (direct_index.topic_to_id[message.topic] === undefined) { + direct_index.topic_to_id[message.topic] = []; + } + direct_index.topic_to_id[message.topic].push(uuid); + + if (external.exist(message.category)) { + if (direct_index.topic_cat_to_id[message.topic] === undefined) { + direct_index.topic_cat_to_id[message.topic] = { }; } - direct_index.topic_to_id[message.topic].push(uuid); - if (msngr.utils.exist(message.category)) { - if (direct_index.topic_cat_to_id[message.topic] === undefined) { - direct_index.topic_cat_to_id[message.topic] = { }; - } + if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_to_id[message.topic][message.category] = []; + } - if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_to_id[message.topic][message.category] = []; - } + direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); + } - direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); + if (external.exist(message.dataType)) { + if (direct_index.topic_type_to_id[message.topic] === undefined) { + direct_index.topic_type_to_id[message.topic] = { }; } - if (msngr.utils.exist(message.dataType)) { - if (direct_index.topic_type_to_id[message.topic] === undefined) { - direct_index.topic_type_to_id[message.topic] = { }; - } + if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { + direct_index.topic_type_to_id[message.topic][message.dataType] = []; + } - if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { - direct_index.topic_type_to_id[message.topic][message.dataType] = []; - } + direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); + } - direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); + if (external.exist(message.category) && external.exist(message.dataType)) { + if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { + direct_index.topic_cat_type_to_id[message.topic] = { }; } - if (msngr.utils.exist(message.category) && msngr.utils.exist(message.dataType)) { - if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { - direct_index.topic_cat_type_to_id[message.topic] = { }; - } + if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; + } - if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; - } + if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; + } - if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; - } + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); + } - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); - } + index_count++; - index_count++; + return uuid; + } + return undefined; + }, + delete: function (uuid) { + if (external.exist(uuid) && external.exist(id_to_message[uuid])) { + var message = id_to_message[uuid]; - return uuid; - } - return undefined; - }, - delete: function (uuid) { - if (msngr.utils.exist(uuid) && msngr.utils.exist(id_to_message[uuid])) { - var message = id_to_message[uuid]; - - if (msngr.utils.exist(message.topic)) { - deleteValueFromArray(direct_index.topic_to_id[message.topic], uuid); - - if (msngr.utils.exist(message.category)) { - deleteValueFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); - } - - if (msngr.utils.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); - } - - if (msngr.utils.exist(message.category) && msngr.utils.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); - } + if (external.exist(message.topic)) { + deleteValueFromArray(direct_index.topic_to_id[message.topic], uuid); + + if (external.exist(message.category)) { + deleteValueFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); } - delete id_to_message[uuid]; - index_count--; + if (external.exist(message.dataType)) { + deleteValueFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); + } - return true; - } - return false; - }, - query: function (message) { - if (msngr.utils.exist(message)) { - if (msngr.utils.exist(message.topic)) { - // Topic Only Results - if (!msngr.utils.exist(message.category) && !msngr.utils.exist(message.dataType)) { - return direct_index.topic_to_id[message.topic] || []; - } - - // Topic + Category Results - if (msngr.utils.exist(message.category) && !msngr.utils.exist(message.dataType)) { - return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; - } - - // Topic + Data Type Results - if (msngr.utils.exist(message.dataType) && !msngr.utils.exist(message.category)) { - return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; - } - - // Topic + Category + Data Type Results - if (msngr.utils.exist(message.category) && msngr.utils.exist(message.dataType)) { - return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; - } + if (external.exist(message.category) && external.exist(message.dataType)) { + deleteValueFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); } } - return []; - }, - clear: function () { - // Index for id to message objects - id_to_message = { }; + delete id_to_message[uuid]; + index_count--; - // Direct index (no partials) for message - direct_index = { - topic_to_id: { }, - topic_cat_to_id: { }, - topic_type_to_id: { }, - topic_cat_type_to_id: { } - }; + return true; + } + return false; + }, + query: function (message) { + if (external.exist(message)) { + if (external.exist(message.topic)) { + // Topic Only Results + if (!external.exist(message.category) && !external.exist(message.dataType)) { + return direct_index.topic_to_id[message.topic] || []; + } - index_count = 0; + // Topic + Category Results + if (external.exist(message.category) && !external.exist(message.dataType)) { + return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; + } - return true; - }, - count: function () { - return index_count; + // Topic + Data Type Results + if (external.exist(message.dataType) && !external.exist(message.category)) { + return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; + } + + // Topic + Category + Data Type Results + if (external.exist(message.category) && external.exist(message.dataType)) { + return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; + } + } } + + return []; + }, + clear: function () { + // Index for id to message objects + id_to_message = { }; + + // Direct index (no partials) for message + direct_index = { + topic_to_id: { }, + topic_cat_to_id: { }, + topic_type_to_id: { }, + topic_cat_type_to_id: { } + }; + + index_count = 0; + + return true; + }, + count: function () { + return index_count; } }; -}())); + + // This is an internal extension; do not export explicitly. + return { }; +})); diff --git a/src/utils/converters.aspec.js b/src/utils/converters.aspec.js index 9ca0bba..914a0a8 100644 --- a/src/utils/converters.aspec.js +++ b/src/utils/converters.aspec.js @@ -13,27 +13,27 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { describe("./utils/converters.js", function () { "use strict"; - it("msngr.utils.argumentsToArray(args) - 0 arguments", function () { + it("msngr.argumentsToArray(args) - 0 arguments", function () { var func = function () { - var args = msngr.utils.argumentsToArray(arguments); + var args = msngr.argumentsToArray(arguments); expect(args.length).to.equal(0); } func(); }); - it("msngr.utils.argumentsToArray(args) - 3 arguments", function () { + it("msngr.argumentsToArray(args) - 3 arguments", function () { var func = function () { - var args = msngr.utils.argumentsToArray(arguments); + var args = msngr.argumentsToArray(arguments); expect(args.length).to.equal(3); } func(1, 2, 3); }); - it("msngr.utils.argumentsToArray(args) - 15 arguments", function () { + it("msngr.argumentsToArray(args) - 15 arguments", function () { var func = function () { - var args = msngr.utils.argumentsToArray(arguments); + var args = msngr.argumentsToArray(arguments); expect(args.length).to.equal(15); } diff --git a/src/utils/converters.js b/src/utils/converters.js index 8f4ace8..610e4e0 100644 --- a/src/utils/converters.js +++ b/src/utils/converters.js @@ -1,15 +1,13 @@ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { - utils: { - argumentsToArray: function (args) { - if (msngr.utils.isArray(args)) { - return args; - } - - return Array.prototype.slice.call(args, 0); + argumentsToArray: function (args) { + if (external.isArray(args)) { + return args; } + + return Array.prototype.slice.call(args, 0); } }; -}())); +})); diff --git a/src/utils/dom.cspec.js b/src/utils/dom.cspec.js index 461d4ba..40fc80d 100644 --- a/src/utils/dom.cspec.js +++ b/src/utils/dom.cspec.js @@ -13,65 +13,65 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { describe("./utils/dom.js", function () { "use strict"; - it("msngr.utils.isHtmlElement(obj) - obj is a function", function () { - expect(msngr.utils.isHtmlElement(function () {})).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is a function", function () { + expect(msngr.isHtmlElement(function () {})).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is a string", function () { - expect(msngr.utils.isHtmlElement("test")).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is a string", function () { + expect(msngr.isHtmlElement("test")).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is an empty string", function () { - expect(msngr.utils.isHtmlElement("")).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is an empty string", function () { + expect(msngr.isHtmlElement("")).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is undefined", function () { - expect(msngr.utils.isHtmlElement(undefined)).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is undefined", function () { + expect(msngr.isHtmlElement(undefined)).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is null", function () { - expect(msngr.utils.isHtmlElement(null)).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is null", function () { + expect(msngr.isHtmlElement(null)).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is an object", function () { - expect(msngr.utils.isHtmlElement({})).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is an object", function () { + expect(msngr.isHtmlElement({})).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is a number", function () { - expect(msngr.utils.isHtmlElement(7)).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is a number", function () { + expect(msngr.isHtmlElement(7)).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is an array", function () { - expect(msngr.utils.isHtmlElement([])).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is an array", function () { + expect(msngr.isHtmlElement([])).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is a date", function () { - expect(msngr.utils.isHtmlElement(new Date())).to.equal(false); + it("msngr.isHtmlElement(obj) - obj is a date", function () { + expect(msngr.isHtmlElement(new Date())).to.equal(false); }); - it("msngr.utils.isHtmlElement(obj) - obj is a div element", function () { - expect(msngr.utils.isHtmlElement(document.createElement("div"))).to.equal(true); + it("msngr.isHtmlElement(obj) - obj is a div element", function () { + expect(msngr.isHtmlElement(document.createElement("div"))).to.equal(true); }); - it("msngr.utils.isHtmlElement(obj) - obj is an input element", function () { - expect(msngr.utils.isHtmlElement(document.createElement("input"))).to.equal(true); + it("msngr.isHtmlElement(obj) - obj is an input element", function () { + expect(msngr.isHtmlElement(document.createElement("input"))).to.equal(true); }); - it("msngr.utils.isHtmlElement(obj) - obj is a body element", function () { - expect(msngr.utils.isHtmlElement(document.createElement("body"))).to.equal(true); + it("msngr.isHtmlElement(obj) - obj is a body element", function () { + expect(msngr.isHtmlElement(document.createElement("body"))).to.equal(true); }); - it("msngr.utils.isHtmlElement(obj) - obj is a canvas element", function () { - expect(msngr.utils.isHtmlElement(document.createElement("canvas"))).to.equal(true); + it("msngr.isHtmlElement(obj) - obj is a canvas element", function () { + expect(msngr.isHtmlElement(document.createElement("canvas"))).to.equal(true); }); - it("msngr.utils.isNodeList(obj) - obj is a single div element", function () { + it("msngr.isNodeList(obj) - obj is a single div element", function () { var div = document.createElement("div"); - expect(msngr.utils.isNodeList(div)).to.equal(false); + expect(msngr.isNodeList(div)).to.equal(false); }); - it("msngr.utils.isNodeList(obj) - obj is a nodelist", function () { + it("msngr.isNodeList(obj) - obj is a nodelist", function () { var div1 = document.createElement("div"); var div2 = document.createElement("div"); var div3 = document.createElement("div"); @@ -79,36 +79,36 @@ describe("./utils/dom.js", function () { div1.appendChild(div2); div1.appendChild(div3); - expect(msngr.utils.isNodeList(div1.childNodes)).to.equal(true); + expect(msngr.isNodeList(div1.childNodes)).to.equal(true); }); - it("msngr.utils.findElement(obj) - obj is an HTMLElement", function () { - expect(msngr.utils.isHtmlElement(msngr.utils.findElement(document.createElement("div")))).to.equal(true); + it("msngr.findElement(obj) - obj is an HTMLElement", function () { + expect(msngr.isHtmlElement(msngr.findElement(document.createElement("div")))).to.equal(true); }); - it("msngr.utils.findElement(obj) - obj is an HTMLElement with root specified", function () { - expect(msngr.utils.isHtmlElement(msngr.utils.findElement(document.createElement("div"), document))).to.equal(true); + it("msngr.findElement(obj) - obj is an HTMLElement with root specified", function () { + expect(msngr.isHtmlElement(msngr.findElement(document.createElement("div"), document))).to.equal(true); }); - it("msngr.utils.findElement(obj) - obj is an id selector (#MyID)", function () { + it("msngr.findElement(obj) - obj is an id selector (#MyID)", function () { var div = document.createElement("div"); div.setAttribute("id", "TestID1"); document.body.appendChild(div); - expect(msngr.utils.isHtmlElement(msngr.utils.findElement("#TestID1"))).to.equal(true); + expect(msngr.isHtmlElement(msngr.findElement("#TestID1"))).to.equal(true); document.body.removeChild(div); - expect(msngr.utils.isHtmlElement(msngr.utils.findElement("#TestID1"))).to.equal(false); + expect(msngr.isHtmlElement(msngr.findElement("#TestID1"))).to.equal(false); }); - it("msngr.utils.findElement(obj) - obj is a class selector (.TestClass)", function () { + it("msngr.findElement(obj) - obj is a class selector (.TestClass)", function () { var div = document.createElement("div"); div.setAttribute("class", "TestClass"); document.body.appendChild(div); - expect(msngr.utils.isHtmlElement(msngr.utils.findElement(".TestClass"))).to.equal(true); + expect(msngr.isHtmlElement(msngr.findElement(".TestClass"))).to.equal(true); document.body.removeChild(div); - expect(msngr.utils.isHtmlElement(msngr.utils.findElement(".TestClass"))).to.equal(false); + expect(msngr.isHtmlElement(msngr.findElement(".TestClass"))).to.equal(false); }); - it("msngr.utils.findElement(obj) - obj is a html target selector", function () { + it("msngr.findElement(obj) - obj is a html target selector", function () { var div = document.createElement("div"); var div2 = document.createElement("div"); var p = document.createElement("p"); @@ -117,23 +117,23 @@ describe("./utils/dom.js", function () { div.appendChild(div2); document.body.appendChild(div); - expect(msngr.utils.isHtmlElement(msngr.utils.findElement("div div p"))).to.equal(true); + expect(msngr.isHtmlElement(msngr.findElement("div div p"))).to.equal(true); document.body.removeChild(div); - expect(msngr.utils.isHtmlElement(msngr.utils.findElement("div div p"))).to.equal(false); + expect(msngr.isHtmlElement(msngr.findElement("div div p"))).to.equal(false); }); - it("msngr.utils.findElements(obj) - obj is an id selector (#MyID)", function () { + it("msngr.findElements(obj) - obj is an id selector (#MyID)", function () { var div = document.createElement("div"); div.setAttribute("id", "TestID1"); document.body.appendChild(div); - expect(msngr.utils.isNodeList(msngr.utils.findElements("#TestID1"))).to.equal(true); - expect(msngr.utils.findElements("#TestID1").length).to.equal(1); + expect(msngr.isNodeList(msngr.findElements("#TestID1"))).to.equal(true); + expect(msngr.findElements("#TestID1").length).to.equal(1); document.body.removeChild(div); - expect(msngr.utils.isNodeList(msngr.utils.findElement("#TestID1"))).to.equal(true); - expect(msngr.utils.findElements("#TestID1").length).to.equal(0); + expect(msngr.isNodeList(msngr.findElement("#TestID1"))).to.equal(true); + expect(msngr.findElements("#TestID1").length).to.equal(0); }); - it("msngr.utils.findElements(obj) - obj is a class selector (.TestClass)", function () { + it("msngr.findElements(obj) - obj is a class selector (.TestClass)", function () { var div = document.createElement("div"); div.setAttribute("class", "TestClass"); @@ -141,15 +141,15 @@ describe("./utils/dom.js", function () { div2.setAttribute("class", "TestClass"); document.body.appendChild(div); document.body.appendChild(div2); - expect(msngr.utils.isNodeList(msngr.utils.findElements(".TestClass"))).to.equal(true); - expect(msngr.utils.findElements(".TestClass").length).to.equal(2); + expect(msngr.isNodeList(msngr.findElements(".TestClass"))).to.equal(true); + expect(msngr.findElements(".TestClass").length).to.equal(2); document.body.removeChild(div); document.body.removeChild(div2); - expect(msngr.utils.isNodeList(msngr.utils.findElements(".TestClass"))).to.equal(true); - expect(msngr.utils.findElements(".TestClass").length).to.equal(0); + expect(msngr.isNodeList(msngr.findElements(".TestClass"))).to.equal(true); + expect(msngr.findElements(".TestClass").length).to.equal(0); }); - it("msngr.utils.findElement(obj) - obj is a html target selector", function () { + it("msngr.findElement(obj) - obj is a html target selector", function () { var div = document.createElement("div"); var div2 = document.createElement("div"); var p = document.createElement("p"); @@ -158,14 +158,14 @@ describe("./utils/dom.js", function () { div.appendChild(div2); document.body.appendChild(div); - expect(msngr.utils.isNodeList(msngr.utils.findElements("div div p"))).to.equal(true); - expect(msngr.utils.findElements("div div p").length).to.equal(1); + expect(msngr.isNodeList(msngr.findElements("div div p"))).to.equal(true); + expect(msngr.findElements("div div p").length).to.equal(1); document.body.removeChild(div); - expect(msngr.utils.isNodeList(msngr.utils.findElements("div div p"))).to.equal(true); - expect(msngr.utils.findElements("div div p").length).to.equal(0); + expect(msngr.isNodeList(msngr.findElements("div div p"))).to.equal(true); + expect(msngr.findElements("div div p").length).to.equal(0); }); - it("msngr.utils.getDomPath(element) - element is a tested HTMLElement", function () { + it("msngr.getDomPath(element) - element is a tested HTMLElement", function () { var div = document.createElement("div"); div.style.display = "none"; @@ -175,12 +175,12 @@ describe("./utils/dom.js", function () { div.appendChild(p); document.body.appendChild(div); - var path = msngr.utils.getDomPath(msngr.utils.findElement("#TestID2")); - expect(msngr.utils.querySelectorAllWithEq(path)[0].id).to.equal("TestID2"); + var path = msngr.getDomPath(msngr.findElement("#TestID2")); + expect(msngr.querySelectorAllWithEq(path)[0].id).to.equal("TestID2"); document.body.removeChild(div); }); - it("msngr.utils.querySelectorAllWithEq(selector) - selector uses eq to target specific indexes", function () { + it("msngr.querySelectorAllWithEq(selector) - selector uses eq to target specific indexes", function () { var div = document.createElement("div"); div.style.display = "none"; @@ -204,13 +204,13 @@ describe("./utils/dom.js", function () { document.body.appendChild(div); - expect(msngr.utils.querySelectorAllWithEq("div#TestID3 > p:eq(0)")[0].id).to.equal("TestID3p1"); - expect(msngr.utils.querySelectorAllWithEq("div#TestID3 > p:eq(1)")[0].id).to.equal("TestID3p2"); - expect(msngr.utils.querySelectorAllWithEq("div#TestID3 > p:eq(2)")[0].id).to.equal("TestID3p3"); + expect(msngr.querySelectorAllWithEq("div#TestID3 > p:eq(0)")[0].id).to.equal("TestID3p1"); + expect(msngr.querySelectorAllWithEq("div#TestID3 > p:eq(1)")[0].id).to.equal("TestID3p2"); + expect(msngr.querySelectorAllWithEq("div#TestID3 > p:eq(2)")[0].id).to.equal("TestID3p3"); }); - it("msngr.utils.querySelectorAllWithEq(selector) - selector uses eq to target specific indexes and works with specific root", function () { + it("msngr.querySelectorAllWithEq(selector) - selector uses eq to target specific indexes and works with specific root", function () { var div = document.createElement("div"); div.style.display = "none"; @@ -234,13 +234,13 @@ describe("./utils/dom.js", function () { document.body.appendChild(div); - expect(msngr.utils.querySelectorAllWithEq("div#TestID3 > p:eq(0)", document)[0].id).to.equal("TestID3p1"); - expect(msngr.utils.querySelectorAllWithEq("div#TestID3 > p:eq(1)", document)[0].id).to.equal("TestID3p2"); - expect(msngr.utils.querySelectorAllWithEq("div#TestID3 > p:eq(2)", document)[0].id).to.equal("TestID3p3"); + expect(msngr.querySelectorAllWithEq("div#TestID3 > p:eq(0)", document)[0].id).to.equal("TestID3p1"); + expect(msngr.querySelectorAllWithEq("div#TestID3 > p:eq(1)", document)[0].id).to.equal("TestID3p2"); + expect(msngr.querySelectorAllWithEq("div#TestID3 > p:eq(2)", document)[0].id).to.equal("TestID3p3"); }); - it("msngr.utils.querySelectorWithEq(selector) - selector uses eq to target specific indexes", function () { + it("msngr.querySelectorWithEq(selector) - selector uses eq to target specific indexes", function () { var div = document.createElement("div"); div.style.display = "none"; @@ -264,9 +264,9 @@ describe("./utils/dom.js", function () { document.body.appendChild(div); - expect(msngr.utils.querySelectorWithEq("div#TestID3 > p:eq(0)").id).to.equal("TestID3p1"); - expect(msngr.utils.querySelectorWithEq("div#TestID3 > p:eq(1)").id).to.equal("TestID3p2"); - expect(msngr.utils.querySelectorWithEq("div#TestID3 > p:eq(2)").id).to.equal("TestID3p3"); + expect(msngr.querySelectorWithEq("div#TestID3 > p:eq(0)").id).to.equal("TestID3p1"); + expect(msngr.querySelectorWithEq("div#TestID3 > p:eq(1)").id).to.equal("TestID3p2"); + expect(msngr.querySelectorWithEq("div#TestID3 > p:eq(2)").id).to.equal("TestID3p3"); }); }); diff --git a/src/utils/dom.js b/src/utils/dom.js index 9e4e500..95d32c6 100644 --- a/src/utils/dom.js +++ b/src/utils/dom.js @@ -1,98 +1,96 @@ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { - utils: { - isHtmlElement: function (obj) { - var t = this.getType(obj); - return (t.indexOf("[object HTML") === 0) || (t.indexOf("[object global]") === 0); - }, - isNodeList: function (obj) { - return (this.getType(obj) === "[object NodeList]"); - }, - findElement: function (element, root) { - var elms = msngr.utils.findElements(element); - if (elms !== undefined && elms.length > 0) { - return elms[0]; - } + isHtmlElement: function (obj) { + var t = this.getType(obj); + return (t.indexOf("[object HTML") === 0) || (t.indexOf("[object global]") === 0); + }, + isNodeList: function (obj) { + return (this.getType(obj) === "[object NodeList]"); + }, + findElement: function (element, root) { + var elms = external.findElements(element); + if (elms !== undefined && elms.length > 0) { + return elms[0]; + } - return elms; - }, - findElements: function (selector, root) { - var elm; - if (msngr.utils.isHtmlElement(selector)) { - elm = selector; - } + return elms; + }, + findElements: function (selector, root) { + var elm; + if (external.isHtmlElement(selector)) { + elm = selector; + } - if (elm === undefined && msngr.utils.isString(selector)) { - var doc = root || document; - var result = doc.querySelectorAll(selector); - if (result !== null) { - elm = result; - } + if (elm === undefined && external.isString(selector)) { + var doc = root || document; + var result = doc.querySelectorAll(selector); + if (result !== null) { + elm = result; } + } - return elm; - }, - getDomPath: function (element) { - var node = msngr.utils.isHtmlElement(element) ? element : undefined; - if (node === undefined) { - return undefined; - } + return elm; + }, + getDomPath: function (element) { + var node = external.isHtmlElement(element) ? element : undefined; + if (node === undefined) { + return undefined; + } - if (node.id === undefined) { - node.id = msngr.utils.id(); - } + if (node.id === undefined) { + node.id = external.id(); + } - return "#" + node.id; - }, - querySelectorAllWithEq: function (selector, root) { - if (selector === undefined) { - return null; + return "#" + node.id; + }, + querySelectorAllWithEq: function (selector, root) { + if (selector === undefined) { + return null; + } + var doc = root || document; + var queue = []; + var process = function (input) { + if (input.indexOf(":eq(") === -1) { + return undefined; } - var doc = root || document; - var queue = []; - var process = function (input) { - if (input.indexOf(":eq(") === -1) { - return undefined; - } - - var eqlLoc = input.indexOf(":eq("); - var sel = input.substring(0, eqlLoc); - var ind = input.substring((eqlLoc + 4), input.indexOf(")", eqlLoc)); - selector = input.substring(input.indexOf(")", eqlLoc) + 1, input.length); - if (sel.charAt(0) === ">") { - sel = sel.substring(1, sel.length); - } + var eqlLoc = input.indexOf(":eq("); + var sel = input.substring(0, eqlLoc); + var ind = input.substring((eqlLoc + 4), input.indexOf(")", eqlLoc)); + selector = input.substring(input.indexOf(")", eqlLoc) + 1, input.length); - if (selector.charAt(0) === ">") { - selector = selector.substring(1, selector.length); - } - - queue.push({ - selector: sel, - index: parseInt(ind, 10) - }); - } - while (selector.indexOf(":eq") !== -1) { - process(selector); + if (sel.charAt(0) === ">") { + sel = sel.substring(1, sel.length); } - var result; - while (queue.length > 0) { - var item = queue.shift(); - result = (result || doc).querySelectorAll(item.selector)[item.index]; + if (selector.charAt(0) === ">") { + selector = selector.substring(1, selector.length); } - if (selector.trim().length > 0) { - return (result || doc).querySelectorAll(selector); - } - return [result]; - }, - querySelectorWithEq: function (selector) { - return msngr.utils.querySelectorAllWithEq(selector)[0]; + queue.push({ + selector: sel, + index: parseInt(ind, 10) + }); + } + while (selector.indexOf(":eq") !== -1) { + process(selector); + } + + var result; + while (queue.length > 0) { + var item = queue.shift(); + result = (result || doc).querySelectorAll(item.selector)[item.index]; + } + + if (selector.trim().length > 0) { + return (result || doc).querySelectorAll(selector); } + return [result]; + }, + querySelectorWithEq: function (selector) { + return external.querySelectorAllWithEq(selector)[0]; } }; -}())); +})); diff --git a/src/utils/misc.aspec.js b/src/utils/misc.aspec.js index 3067d9c..5b33bba 100644 --- a/src/utils/misc.aspec.js +++ b/src/utils/misc.aspec.js @@ -15,14 +15,14 @@ describe("./utils/misc.js", function () { this.timeout(60000); - it("msngr.utils.id() - generate 1 id", function () { - expect(msngr.utils.id()).to.not.equal(undefined); + it("msngr.id() - generate 1 id", function () { + expect(msngr.id()).to.not.equal(undefined); }); - it("msngr.utils.id() - generate 100 unique ids", function () { + it("msngr.id() - generate 100 unique ids", function () { var ids = []; for (var i = 0; i < 100; ++i) { - var d = msngr.utils.id(); + var d = msngr.id(); if (ids.indexOf(d) === -1) { ids.push(d); } @@ -31,10 +31,10 @@ describe("./utils/misc.js", function () { expect(ids.length).to.equal(100); }); - it("msngr.utils.id() - generate 10000 unique ids", function () { + it("msngr.id() - generate 10000 unique ids", function () { var ids = []; for (var i = 0; i < 10000; ++i) { - var d = msngr.utils.id(); + var d = msngr.id(); if (ids.indexOf(d) === -1) { ids.push(d); } @@ -43,16 +43,16 @@ describe("./utils/misc.js", function () { expect(ids.length).to.equal(10000); }); - it("msngr.utils.now() - generates a value", function () { - expect(msngr.utils.now()).to.exist; + it("msngr.now() - generates a value", function () { + expect(msngr.now()).to.exist; }); - it("msngr.utils.now(true) - 5 consecutive calls have unique values", function () { - var t1 = msngr.utils.now(true); - var t2 = msngr.utils.now(true); - var t3 = msngr.utils.now(true); - var t4 = msngr.utils.now(true); - var t5 = msngr.utils.now(true); + it("msngr.now(true) - 5 consecutive calls have unique values", function () { + var t1 = msngr.now(true); + var t2 = msngr.now(true); + var t3 = msngr.now(true); + var t4 = msngr.now(true); + var t5 = msngr.now(true); expect(t1).to.exist; expect(t2).to.exist; @@ -66,8 +66,8 @@ describe("./utils/misc.js", function () { expect(t5).to.not.equal(t4); }); - it("msngr.utils.now('sdfkjsdfl') - Correctly handles invalid input", function () { - var t = msngr.utils.now("sdfkjsdfl"); + it("msngr.now('sdfkjsdfl') - Correctly handles invalid input", function () { + var t = msngr.now("sdfkjsdfl"); expect(t).to.exist; }); diff --git a/src/utils/misc.js b/src/utils/misc.js index 9c0f42e..587dba3 100644 --- a/src/utils/misc.js +++ b/src/utils/misc.js @@ -1,4 +1,4 @@ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; var nowPerformance = function () { @@ -18,36 +18,34 @@ msngr.extend((function () { var lastNow = undefined; return { - utils: { - id: function () { - var d = msngr.utils.now(); - var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = (d + Math.random()*16)%16 | 0; - d = Math.floor(d/16); - return (c=='x' ? r : (r&0x3|0x8)).toString(16); - }); - return uuid; - }, - now: function (noDuplicate) { - if (nowExec === undefined) { - if (typeof performance !== "undefined") { - nowExec = nowPerformance; - nowExecDebugLabel = "performance"; - } else if (typeof process !== "undefined") { - nowExec = nowNode; - nowExecDebugLabel = "node"; - } else { - nowExec = nowLegacy; - nowExecDebugLabel = "legacy"; - } + id: function () { + var d = external.now(); + var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = (d + Math.random()*16)%16 | 0; + d = Math.floor(d/16); + return (c=='x' ? r : (r&0x3|0x8)).toString(16); + }); + return uuid; + }, + now: function (noDuplicate) { + if (nowExec === undefined) { + if (typeof performance !== "undefined") { + nowExec = nowPerformance; + nowExecDebugLabel = "performance"; + } else if (typeof process !== "undefined") { + nowExec = nowNode; + nowExecDebugLabel = "node"; + } else { + nowExec = nowLegacy; + nowExecDebugLabel = "legacy"; } - var now = nowExec(); - if (noDuplicate === true && lastNow === now) { - return msngr.utils.now(noDuplicate); - } - lastNow = now; - return now; } + var now = nowExec(); + if (noDuplicate === true && lastNow === now) { + return external.now(noDuplicate); + } + lastNow = now; + return now; } }; -}())); +})); diff --git a/src/utils/validation.aspec.js b/src/utils/validation.aspec.js index f88dd21..71bec3e 100644 --- a/src/utils/validation.aspec.js +++ b/src/utils/validation.aspec.js @@ -13,549 +13,549 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { describe("./utils/validation.js", function () { "use strict"; - it("msngr.utils.getType(obj) - obj is a function", function () { - expect(msngr.utils.getType(function () {})).to.equal("[object Function]"); + it("msngr.getType(obj) - obj is a function", function () { + expect(msngr.getType(function () {})).to.equal("[object Function]"); }); - it("msngr.utils.getType(obj) - obj is a string", function () { - expect(msngr.utils.getType("test")).to.equal("[object String]"); + it("msngr.getType(obj) - obj is a string", function () { + expect(msngr.getType("test")).to.equal("[object String]"); }); - it("msngr.utils.getType(obj) - obj is a number", function () { - expect(msngr.utils.getType(42)).to.equal("[object Number]"); + it("msngr.getType(obj) - obj is a number", function () { + expect(msngr.getType(42)).to.equal("[object Number]"); }); - it("msngr.utils.getType(obj) - obj is an array", function () { - expect(msngr.utils.getType([])).to.equal("[object Array]"); + it("msngr.getType(obj) - obj is an array", function () { + expect(msngr.getType([])).to.equal("[object Array]"); }); - it("msngr.utils.getType(obj) - obj is an object", function () { - expect(msngr.utils.getType({ })).to.equal("[object Object]"); + it("msngr.getType(obj) - obj is an object", function () { + expect(msngr.getType({ })).to.equal("[object Object]"); }); - it("msngr.utils.getType(obj) - obj is undefined", function () { - expect(msngr.utils.getType(undefined)).to.equal("undefined"); + it("msngr.getType(obj) - obj is undefined", function () { + expect(msngr.getType(undefined)).to.equal("undefined"); }); - it("msngr.utils.getType(obj) - obj is null", function () { - expect(msngr.utils.getType(null)).to.equal("null"); + it("msngr.getType(obj) - obj is null", function () { + expect(msngr.getType(null)).to.equal("null"); }); // isArguments - it("msngr.utils.isArguments(obj) - obj is a function", function () { - expect(msngr.utils.isArguments(function () {})).to.equal(false); + it("msngr.isArguments(obj) - obj is a function", function () { + expect(msngr.isArguments(function () {})).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is a string with content", function () { - expect(msngr.utils.isArguments("test")).to.equal(false); + it("msngr.isArguments(obj) - obj is a string with content", function () { + expect(msngr.isArguments("test")).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is an empty string", function () { - expect(msngr.utils.isArguments("")).to.equal(false); + it("msngr.isArguments(obj) - obj is an empty string", function () { + expect(msngr.isArguments("")).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is a string with only whitespace", function () { - expect(msngr.utils.isArguments(" ")).to.equal(false); + it("msngr.isArguments(obj) - obj is a string with only whitespace", function () { + expect(msngr.isArguments(" ")).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is undefined", function () { - expect(msngr.utils.isArguments(undefined)).to.equal(false); + it("msngr.isArguments(obj) - obj is undefined", function () { + expect(msngr.isArguments(undefined)).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is null", function () { - expect(msngr.utils.isArguments(null)).to.equal(false); + it("msngr.isArguments(obj) - obj is null", function () { + expect(msngr.isArguments(null)).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is an object", function () { - expect(msngr.utils.isArguments({})).to.equal(false); + it("msngr.isArguments(obj) - obj is an object", function () { + expect(msngr.isArguments({})).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is a number", function () { - expect(msngr.utils.isArguments(7)).to.equal(false); + it("msngr.isArguments(obj) - obj is a number", function () { + expect(msngr.isArguments(7)).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is an array", function () { - expect(msngr.utils.isArguments([])).to.equal(false); + it("msngr.isArguments(obj) - obj is an array", function () { + expect(msngr.isArguments([])).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is a Date", function () { - expect(msngr.utils.isArguments(new Date())).to.equal(false); + it("msngr.isArguments(obj) - obj is a Date", function () { + expect(msngr.isArguments(new Date())).to.equal(false); }); - it("msngr.utils.isArguments(obj) - obj is an Arguments object", function () { + it("msngr.isArguments(obj) - obj is an Arguments object", function () { var tFunc = function () { - expect(msngr.utils.isArguments(arguments)).to.equal(true); + expect(msngr.isArguments(arguments)).to.equal(true); } tFunc("something", 15, "weee"); }); // isNullOrUndefined(obj) - it("msngr.utils.isNullOrUndefined(obj) - obj is a function", function () { - expect(msngr.utils.isNullOrUndefined(function () {})).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is a function", function () { + expect(msngr.isNullOrUndefined(function () {})).to.equal(false); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is a string with content", function () { - expect(msngr.utils.isNullOrUndefined("test")).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is a string with content", function () { + expect(msngr.isNullOrUndefined("test")).to.equal(false); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is an empty string", function () { - expect(msngr.utils.isNullOrUndefined("")).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is an empty string", function () { + expect(msngr.isNullOrUndefined("")).to.equal(false); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is a string with only whitespace", function () { - expect(msngr.utils.isNullOrUndefined(" ")).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is a string with only whitespace", function () { + expect(msngr.isNullOrUndefined(" ")).to.equal(false); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is undefined", function () { - expect(msngr.utils.isNullOrUndefined(undefined)).to.equal(true); + it("msngr.isNullOrUndefined(obj) - obj is undefined", function () { + expect(msngr.isNullOrUndefined(undefined)).to.equal(true); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is null", function () { - expect(msngr.utils.isNullOrUndefined(null)).to.equal(true); + it("msngr.isNullOrUndefined(obj) - obj is null", function () { + expect(msngr.isNullOrUndefined(null)).to.equal(true); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is an object", function () { - expect(msngr.utils.isNullOrUndefined({})).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is an object", function () { + expect(msngr.isNullOrUndefined({})).to.equal(false); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is a number", function () { - expect(msngr.utils.isNullOrUndefined(7)).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is a number", function () { + expect(msngr.isNullOrUndefined(7)).to.equal(false); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is an array", function () { - expect(msngr.utils.isNullOrUndefined([])).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is an array", function () { + expect(msngr.isNullOrUndefined([])).to.equal(false); }); - it("msngr.utils.isNullOrUndefined(obj) - obj is a Date", function () { - expect(msngr.utils.isNullOrUndefined(new Date())).to.equal(false); + it("msngr.isNullOrUndefined(obj) - obj is a Date", function () { + expect(msngr.isNullOrUndefined(new Date())).to.equal(false); }); // exist(obj) - it("msngr.utils.exist(obj) - obj is a function", function () { - expect(msngr.utils.exist(function () {})).to.equal(true); + it("msngr.exist(obj) - obj is a function", function () { + expect(msngr.exist(function () {})).to.equal(true); }); - it("msngr.utils.exist(obj) - obj is a string with content", function () { - expect(msngr.utils.exist("test")).to.equal(true); + it("msngr.exist(obj) - obj is a string with content", function () { + expect(msngr.exist("test")).to.equal(true); }); - it("msngr.utils.exist(obj) - obj is an empty string", function () { - expect(msngr.utils.exist("")).to.equal(true); + it("msngr.exist(obj) - obj is an empty string", function () { + expect(msngr.exist("")).to.equal(true); }); - it("msngr.utils.exist(obj) - obj is a string with only whitespace", function () { - expect(msngr.utils.exist(" ")).to.equal(true); + it("msngr.exist(obj) - obj is a string with only whitespace", function () { + expect(msngr.exist(" ")).to.equal(true); }); - it("msngr.utils.exist(obj) - obj is undefined", function () { - expect(msngr.utils.exist(undefined)).to.equal(false); + it("msngr.exist(obj) - obj is undefined", function () { + expect(msngr.exist(undefined)).to.equal(false); }); - it("msngr.utils.exist(obj) - obj is null", function () { - expect(msngr.utils.exist(null)).to.equal(false); + it("msngr.exist(obj) - obj is null", function () { + expect(msngr.exist(null)).to.equal(false); }); - it("msngr.utils.exist(obj) - obj is an object", function () { - expect(msngr.utils.exist({})).to.equal(true); + it("msngr.exist(obj) - obj is an object", function () { + expect(msngr.exist({})).to.equal(true); }); - it("msngr.utils.exist(obj) - obj is a number", function () { - expect(msngr.utils.exist(7)).to.equal(true); + it("msngr.exist(obj) - obj is a number", function () { + expect(msngr.exist(7)).to.equal(true); }); - it("msngr.utils.exist(obj) - obj is an array", function () { - expect(msngr.utils.exist([])).to.equal(true); + it("msngr.exist(obj) - obj is an array", function () { + expect(msngr.exist([])).to.equal(true); }); - it("msngr.utils.exist(obj) - obj is a Date", function () { - expect(msngr.utils.exist(new Date())).to.equal(true); + it("msngr.exist(obj) - obj is a Date", function () { + expect(msngr.exist(new Date())).to.equal(true); }); // exists() - it("msngr.utils.exists(...) - arguments are of various types", function () { - expect(msngr.utils.exists("whatever", 15, true, false, { })).to.equal(true); + it("msngr.exists(...) - arguments are of various types", function () { + expect(msngr.exists("whatever", 15, true, false, { })).to.equal(true); }); - it("msngr.utils.exists(...) - arguments are of various types with an undefined item", function () { - expect(msngr.utils.exists("whatever", 15, undefined, false, { })).to.equal(false); + it("msngr.exists(...) - arguments are of various types with an undefined item", function () { + expect(msngr.exists("whatever", 15, undefined, false, { })).to.equal(false); }); - it("msngr.utils.exists(...) - arguments are of various types with a null item", function () { - expect(msngr.utils.exists(null, 15, true, false, { })).to.equal(false); + it("msngr.exists(...) - arguments are of various types with a null item", function () { + expect(msngr.exists(null, 15, true, false, { })).to.equal(false); }); // isString(str) - it("msngr.utils.isString(str) - obj is a function", function () { - expect(msngr.utils.isString(function () {})).to.equal(false); + it("msngr.isString(str) - obj is a function", function () { + expect(msngr.isString(function () {})).to.equal(false); }); - it("msngr.utils.isString(str) - obj is a string with content", function () { - expect(msngr.utils.isString("test")).to.equal(true); + it("msngr.isString(str) - obj is a string with content", function () { + expect(msngr.isString("test")).to.equal(true); }); - it("msngr.utils.isString(str) - obj is an empty string", function () { - expect(msngr.utils.isString("")).to.equal(true); + it("msngr.isString(str) - obj is an empty string", function () { + expect(msngr.isString("")).to.equal(true); }); - it("msngr.utils.isString(str) - obj is a string with only whitespace", function () { - expect(msngr.utils.isString(" ")).to.equal(true); + it("msngr.isString(str) - obj is a string with only whitespace", function () { + expect(msngr.isString(" ")).to.equal(true); }); - it("msngr.utils.isString(str) - obj is undefined", function () { - expect(msngr.utils.isString(undefined)).to.equal(false); + it("msngr.isString(str) - obj is undefined", function () { + expect(msngr.isString(undefined)).to.equal(false); }); - it("msngr.utils.isString(str) - obj is null", function () { - expect(msngr.utils.isString(null)).to.equal(false); + it("msngr.isString(str) - obj is null", function () { + expect(msngr.isString(null)).to.equal(false); }); - it("msngr.utils.isString(str) - obj is an object", function () { - expect(msngr.utils.isString({})).to.equal(false); + it("msngr.isString(str) - obj is an object", function () { + expect(msngr.isString({})).to.equal(false); }); - it("msngr.utils.isString(str) - obj is a number", function () { - expect(msngr.utils.isString(7)).to.equal(false); + it("msngr.isString(str) - obj is a number", function () { + expect(msngr.isString(7)).to.equal(false); }); - it("msngr.utils.isString(str) - obj is an array", function () { - expect(msngr.utils.isString([])).to.equal(false); + it("msngr.isString(str) - obj is an array", function () { + expect(msngr.isString([])).to.equal(false); }); - it("msngr.utils.isString(str) - obj is a Date", function () { - expect(msngr.utils.isString(new Date())).to.equal(false); + it("msngr.isString(str) - obj is a Date", function () { + expect(msngr.isString(new Date())).to.equal(false); }); // isDate(obj) - it("msngr.utils.isDate(obj) - obj is a function", function () { - expect(msngr.utils.isDate(function () {})).to.equal(false); + it("msngr.isDate(obj) - obj is a function", function () { + expect(msngr.isDate(function () {})).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is a string with content", function () { - expect(msngr.utils.isDate("test")).to.equal(false); + it("msngr.isDate(obj) - obj is a string with content", function () { + expect(msngr.isDate("test")).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is an empty string", function () { - expect(msngr.utils.isDate("")).to.equal(false); + it("msngr.isDate(obj) - obj is an empty string", function () { + expect(msngr.isDate("")).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is a string with only whitespace", function () { - expect(msngr.utils.isDate(" ")).to.equal(false); + it("msngr.isDate(obj) - obj is a string with only whitespace", function () { + expect(msngr.isDate(" ")).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is undefined", function () { - expect(msngr.utils.isDate(undefined)).to.equal(false); + it("msngr.isDate(obj) - obj is undefined", function () { + expect(msngr.isDate(undefined)).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is null", function () { - expect(msngr.utils.isDate(null)).to.equal(false); + it("msngr.isDate(obj) - obj is null", function () { + expect(msngr.isDate(null)).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is an object", function () { - expect(msngr.utils.isDate({})).to.equal(false); + it("msngr.isDate(obj) - obj is an object", function () { + expect(msngr.isDate({})).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is a number", function () { - expect(msngr.utils.isDate(7)).to.equal(false); + it("msngr.isDate(obj) - obj is a number", function () { + expect(msngr.isDate(7)).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is an array", function () { - expect(msngr.utils.isDate([])).to.equal(false); + it("msngr.isDate(obj) - obj is an array", function () { + expect(msngr.isDate([])).to.equal(false); }); - it("msngr.utils.isDate(obj) - obj is a Date", function () { - expect(msngr.utils.isDate(new Date())).to.equal(true); + it("msngr.isDate(obj) - obj is a Date", function () { + expect(msngr.isDate(new Date())).to.equal(true); }); // isArray(obj) - it("msngr.utils.isArray(obj) - obj is a function", function () { - expect(msngr.utils.isArray(function () {})).to.equal(false); + it("msngr.isArray(obj) - obj is a function", function () { + expect(msngr.isArray(function () {})).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is a string with content", function () { - expect(msngr.utils.isArray("test")).to.equal(false); + it("msngr.isArray(obj) - obj is a string with content", function () { + expect(msngr.isArray("test")).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is an empty string", function () { - expect(msngr.utils.isArray("")).to.equal(false); + it("msngr.isArray(obj) - obj is an empty string", function () { + expect(msngr.isArray("")).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is a string with only whitespace", function () { - expect(msngr.utils.isArray(" ")).to.equal(false); + it("msngr.isArray(obj) - obj is a string with only whitespace", function () { + expect(msngr.isArray(" ")).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is undefined", function () { - expect(msngr.utils.isArray(undefined)).to.equal(false); + it("msngr.isArray(obj) - obj is undefined", function () { + expect(msngr.isArray(undefined)).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is null", function () { - expect(msngr.utils.isArray(null)).to.equal(false); + it("msngr.isArray(obj) - obj is null", function () { + expect(msngr.isArray(null)).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is an object", function () { - expect(msngr.utils.isArray({})).to.equal(false); + it("msngr.isArray(obj) - obj is an object", function () { + expect(msngr.isArray({})).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is a number", function () { - expect(msngr.utils.isArray(7)).to.equal(false); + it("msngr.isArray(obj) - obj is a number", function () { + expect(msngr.isArray(7)).to.equal(false); }); - it("msngr.utils.isArray(obj) - obj is an array", function () { - expect(msngr.utils.isArray([])).to.equal(true); + it("msngr.isArray(obj) - obj is an array", function () { + expect(msngr.isArray([])).to.equal(true); }); - it("msngr.utils.isArray(obj) - obj is a Date", function () { - expect(msngr.utils.isArray(new Date())).to.equal(false); + it("msngr.isArray(obj) - obj is a Date", function () { + expect(msngr.isArray(new Date())).to.equal(false); }); // isNumber(obj) - it("msngr.utils.isNumber(obj) - obj is a function", function () { - expect(msngr.utils.isNumber(function () {})).to.equal(false); + it("msngr.isNumber(obj) - obj is a function", function () { + expect(msngr.isNumber(function () {})).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is a string with content", function () { - expect(msngr.utils.isNumber("test")).to.equal(false); + it("msngr.isNumber(obj) - obj is a string with content", function () { + expect(msngr.isNumber("test")).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is an empty string", function () { - expect(msngr.utils.isNumber("")).to.equal(false); + it("msngr.isNumber(obj) - obj is an empty string", function () { + expect(msngr.isNumber("")).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is a string with only whitespace", function () { - expect(msngr.utils.isNumber(" ")).to.equal(false); + it("msngr.isNumber(obj) - obj is a string with only whitespace", function () { + expect(msngr.isNumber(" ")).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is undefined", function () { - expect(msngr.utils.isNumber(undefined)).to.equal(false); + it("msngr.isNumber(obj) - obj is undefined", function () { + expect(msngr.isNumber(undefined)).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is null", function () { - expect(msngr.utils.isNumber(null)).to.equal(false); + it("msngr.isNumber(obj) - obj is null", function () { + expect(msngr.isNumber(null)).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is an object", function () { - expect(msngr.utils.isNumber({})).to.equal(false); + it("msngr.isNumber(obj) - obj is an object", function () { + expect(msngr.isNumber({})).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is a number", function () { - expect(msngr.utils.isNumber(7)).to.equal(true); + it("msngr.isNumber(obj) - obj is a number", function () { + expect(msngr.isNumber(7)).to.equal(true); }); - it("msngr.utils.isNumber(obj) - obj is an array", function () { - expect(msngr.utils.isNumber([])).to.equal(false); + it("msngr.isNumber(obj) - obj is an array", function () { + expect(msngr.isNumber([])).to.equal(false); }); - it("msngr.utils.isNumber(obj) - obj is a Date", function () { - expect(msngr.utils.isNumber(new Date())).to.equal(false); + it("msngr.isNumber(obj) - obj is a Date", function () { + expect(msngr.isNumber(new Date())).to.equal(false); }); // isObject(obj) - it("msngr.utils.isObject(obj) - obj is a function", function () { - expect(msngr.utils.isObject(function () {})).to.equal(false); + it("msngr.isObject(obj) - obj is a function", function () { + expect(msngr.isObject(function () {})).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is a string with content", function () { - expect(msngr.utils.isObject("test")).to.equal(false); + it("msngr.isObject(obj) - obj is a string with content", function () { + expect(msngr.isObject("test")).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is an empty string", function () { - expect(msngr.utils.isObject("")).to.equal(false); + it("msngr.isObject(obj) - obj is an empty string", function () { + expect(msngr.isObject("")).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is a string with only whitespace", function () { - expect(msngr.utils.isObject(" ")).to.equal(false); + it("msngr.isObject(obj) - obj is a string with only whitespace", function () { + expect(msngr.isObject(" ")).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is undefined", function () { - expect(msngr.utils.isObject(undefined)).to.equal(false); + it("msngr.isObject(obj) - obj is undefined", function () { + expect(msngr.isObject(undefined)).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is null", function () { - expect(msngr.utils.isObject(null)).to.equal(false); + it("msngr.isObject(obj) - obj is null", function () { + expect(msngr.isObject(null)).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is an object", function () { - expect(msngr.utils.isObject({})).to.equal(true); + it("msngr.isObject(obj) - obj is an object", function () { + expect(msngr.isObject({})).to.equal(true); }); - it("msngr.utils.isObject(obj) - obj is a number", function () { - expect(msngr.utils.isObject(7)).to.equal(false); + it("msngr.isObject(obj) - obj is a number", function () { + expect(msngr.isObject(7)).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is an array", function () { - expect(msngr.utils.isObject([])).to.equal(false); + it("msngr.isObject(obj) - obj is an array", function () { + expect(msngr.isObject([])).to.equal(false); }); - it("msngr.utils.isObject(obj) - obj is a Date", function () { - expect(msngr.utils.isObject(new Date())).to.equal(false); + it("msngr.isObject(obj) - obj is a Date", function () { + expect(msngr.isObject(new Date())).to.equal(false); }); // isFunction(func) - it("msngr.utils.isFunction(func) - obj is a function", function () { - expect(msngr.utils.isFunction(function () {})).to.equal(true); + it("msngr.isFunction(func) - obj is a function", function () { + expect(msngr.isFunction(function () {})).to.equal(true); }); - it("msngr.utils.isFunction(func) - obj is a string with content", function () { - expect(msngr.utils.isFunction("test")).to.equal(false); + it("msngr.isFunction(func) - obj is a string with content", function () { + expect(msngr.isFunction("test")).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is an empty string", function () { - expect(msngr.utils.isFunction("")).to.equal(false); + it("msngr.isFunction(func) - obj is an empty string", function () { + expect(msngr.isFunction("")).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is a string with only whitespace", function () { - expect(msngr.utils.isFunction(" ")).to.equal(false); + it("msngr.isFunction(func) - obj is a string with only whitespace", function () { + expect(msngr.isFunction(" ")).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is undefined", function () { - expect(msngr.utils.isFunction(undefined)).to.equal(false); + it("msngr.isFunction(func) - obj is undefined", function () { + expect(msngr.isFunction(undefined)).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is null", function () { - expect(msngr.utils.isFunction(null)).to.equal(false); + it("msngr.isFunction(func) - obj is null", function () { + expect(msngr.isFunction(null)).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is an object", function () { - expect(msngr.utils.isFunction({})).to.equal(false); + it("msngr.isFunction(func) - obj is an object", function () { + expect(msngr.isFunction({})).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is a number", function () { - expect(msngr.utils.isFunction(7)).to.equal(false); + it("msngr.isFunction(func) - obj is a number", function () { + expect(msngr.isFunction(7)).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is an array", function () { - expect(msngr.utils.isFunction([])).to.equal(false); + it("msngr.isFunction(func) - obj is an array", function () { + expect(msngr.isFunction([])).to.equal(false); }); - it("msngr.utils.isFunction(func) - obj is a Date", function () { - expect(msngr.utils.isFunction(new Date())).to.equal(false); + it("msngr.isFunction(func) - obj is a Date", function () { + expect(msngr.isFunction(new Date())).to.equal(false); }); // isEmptyString(str) - it("msngr.utils.isEmptyString(str) - str is a function", function () { - expect(msngr.utils.isEmptyString(function () {})).to.equal(false); + it("msngr.isEmptyString(str) - str is a function", function () { + expect(msngr.isEmptyString(function () {})).to.equal(false); }); - it("msngr.utils.isEmptyString(str) - str is a string with content", function () { - expect(msngr.utils.isEmptyString("test")).to.equal(false); + it("msngr.isEmptyString(str) - str is a string with content", function () { + expect(msngr.isEmptyString("test")).to.equal(false); }); - it("msngr.utils.isEmptyString(str) - str is an empty string", function () { - expect(msngr.utils.isEmptyString("")).to.equal(true); + it("msngr.isEmptyString(str) - str is an empty string", function () { + expect(msngr.isEmptyString("")).to.equal(true); }); - it("msngr.utils.isEmptyString(str) - str is a string with only whitespace", function () { - expect(msngr.utils.isEmptyString(" ")).to.equal(true); + it("msngr.isEmptyString(str) - str is a string with only whitespace", function () { + expect(msngr.isEmptyString(" ")).to.equal(true); }); - it("msngr.utils.isEmptyString(str) - str is undefined", function () { - expect(msngr.utils.isEmptyString(undefined)).to.equal(true); + it("msngr.isEmptyString(str) - str is undefined", function () { + expect(msngr.isEmptyString(undefined)).to.equal(true); }); - it("msngr.utils.isEmptyString(str) - str is null", function () { - expect(msngr.utils.isEmptyString(null)).to.equal(true); + it("msngr.isEmptyString(str) - str is null", function () { + expect(msngr.isEmptyString(null)).to.equal(true); }); - it("msngr.utils.isEmptyString(str) - str is an object", function () { - expect(msngr.utils.isEmptyString({})).to.equal(false); + it("msngr.isEmptyString(str) - str is an object", function () { + expect(msngr.isEmptyString({})).to.equal(false); }); - it("msngr.utils.isEmptyString(str) - str is a number", function () { - expect(msngr.utils.isEmptyString(7)).to.equal(false); + it("msngr.isEmptyString(str) - str is a number", function () { + expect(msngr.isEmptyString(7)).to.equal(false); }); - it("msngr.utils.isEmptyString(str) - str is an array", function () { - expect(msngr.utils.isEmptyString([])).to.equal(false); + it("msngr.isEmptyString(str) - str is an array", function () { + expect(msngr.isEmptyString([])).to.equal(false); }); - it("msngr.utils.isEmptyString(str) - str is a Date", function () { - expect(msngr.utils.isEmptyString(new Date())).to.equal(false); + it("msngr.isEmptyString(str) - str is a Date", function () { + expect(msngr.isEmptyString(new Date())).to.equal(false); }); // hasWildCard(str) - it("msngr.utils.hasWildCard(str)", function () { - expect(msngr.utils.hasWildCard("whatever")).to.equal(false); - expect(msngr.utils.hasWildCard("")).to.equal(false); - expect(msngr.utils.hasWildCard("what*")).to.equal(true); + it("msngr.hasWildCard(str)", function () { + expect(msngr.hasWildCard("whatever")).to.equal(false); + expect(msngr.hasWildCard("")).to.equal(false); + expect(msngr.hasWildCard("what*")).to.equal(true); }); // reiterativeValidation(func, inputs) - it("msngr.utils.reiterativeValidation(func, inputs) - func is undefined", function () { - expect(msngr.utils.reiterativeValidation(undefined, [true, false, 15, "534"])).to.equal(false); + it("msngr.reiterativeValidation(func, inputs) - func is undefined", function () { + expect(msngr.reiterativeValidation(undefined, [true, false, 15, "534"])).to.equal(false); }); - it("msngr.utils.reiterativeValidation(func, inputs) - inputs is undefined", function () { - expect(msngr.utils.reiterativeValidation(msngr.utils.exists, undefined)).to.equal(false); + it("msngr.reiterativeValidation(func, inputs) - inputs is undefined", function () { + expect(msngr.reiterativeValidation(msngr.exists, undefined)).to.equal(false); }); - it("msngr.utils.reiterativeValidation(func, inputs) - func is msngr.utils.exists and inputs is a single value", function () { - expect(msngr.utils.reiterativeValidation(msngr.utils.exists, true)).to.equal(true); - expect(msngr.utils.reiterativeValidation(msngr.utils.exists, undefined)).to.equal(false); - expect(msngr.utils.reiterativeValidation(msngr.utils.exists, null)).to.equal(false); + it("msngr.reiterativeValidation(func, inputs) - func is msngr.exists and inputs is a single value", function () { + expect(msngr.reiterativeValidation(msngr.exists, true)).to.equal(true); + expect(msngr.reiterativeValidation(msngr.exists, undefined)).to.equal(false); + expect(msngr.reiterativeValidation(msngr.exists, null)).to.equal(false); }); - it("msngr.utils.reiterativeValidation(func, inputs) - func is msngr.utils.exists and inputs are various values", function () { - expect(msngr.utils.reiterativeValidation(msngr.utils.exists, [true, false, 15, "534"])).to.equal(true); - expect(msngr.utils.reiterativeValidation(msngr.utils.exists, [undefined, false, 15, "534"])).to.equal(false); - expect(msngr.utils.reiterativeValidation(msngr.utils.exists, [true, undefined, 15, "534"])).to.equal(false); + it("msngr.reiterativeValidation(func, inputs) - func is msngr.exists and inputs are various values", function () { + expect(msngr.reiterativeValidation(msngr.exists, [true, false, 15, "534"])).to.equal(true); + expect(msngr.reiterativeValidation(msngr.exists, [undefined, false, 15, "534"])).to.equal(false); + expect(msngr.reiterativeValidation(msngr.exists, [true, undefined, 15, "534"])).to.equal(false); }); // exists() - it("msngr.utils.exists()", function () { - expect(msngr.utils.exists({}, [], "something", 12)).to.equal(true); - expect(msngr.utils.exists({}, null, "something", 12)).to.equal(false); - expect(msngr.utils.exists({}, [], undefined, 12)).to.equal(false); - expect(msngr.utils.exists(null, undefined, null)).to.equal(false); + it("msngr.exists()", function () { + expect(msngr.exists({}, [], "something", 12)).to.equal(true); + expect(msngr.exists({}, null, "something", 12)).to.equal(false); + expect(msngr.exists({}, [], undefined, 12)).to.equal(false); + expect(msngr.exists(null, undefined, null)).to.equal(false); }); // areStrings() - it("msngr.utils.areStrings()", function () { - expect(msngr.utils.areStrings("Whatever", "Totes!", "Chickens")).to.equal(true); - expect(msngr.utils.areStrings("Whatever", undefined, "Chickens")).to.equal(false); - expect(msngr.utils.areStrings("Whatever", null, "Chickens")).to.equal(false); - expect(msngr.utils.areStrings("Whatever", "Totes!", 5)).to.equal(false); + it("msngr.areStrings()", function () { + expect(msngr.areStrings("Whatever", "Totes!", "Chickens")).to.equal(true); + expect(msngr.areStrings("Whatever", undefined, "Chickens")).to.equal(false); + expect(msngr.areStrings("Whatever", null, "Chickens")).to.equal(false); + expect(msngr.areStrings("Whatever", "Totes!", 5)).to.equal(false); }); // areDates() - it("msngr.utils.areDates()", function () { - expect(msngr.utils.areDates((new Date()), (new Date()))).to.equal(true); - expect(msngr.utils.areDates((new Date()), undefined, "Chickens")).to.equal(false); - expect(msngr.utils.areDates((new Date()), null, "Chickens")).to.equal(false); - expect(msngr.utils.areDates((new Date()), "Totes!", 5)).to.equal(false); + it("msngr.areDates()", function () { + expect(msngr.areDates((new Date()), (new Date()))).to.equal(true); + expect(msngr.areDates((new Date()), undefined, "Chickens")).to.equal(false); + expect(msngr.areDates((new Date()), null, "Chickens")).to.equal(false); + expect(msngr.areDates((new Date()), "Totes!", 5)).to.equal(false); }); // areNumbers() - it("msngr.utils.areNumbers()", function () { - expect(msngr.utils.areNumbers(15, 12, 90000, -1)).to.equal(true); - expect(msngr.utils.areNumbers(15, undefined, 90000, -1)).to.equal(false); - expect(msngr.utils.areNumbers(15, 12, "whatever", -1)).to.equal(false); + it("msngr.areNumbers()", function () { + expect(msngr.areNumbers(15, 12, 90000, -1)).to.equal(true); + expect(msngr.areNumbers(15, undefined, 90000, -1)).to.equal(false); + expect(msngr.areNumbers(15, 12, "whatever", -1)).to.equal(false); }); // areArrays() - it("msngr.utils.areArrays()", function () { - expect(msngr.utils.areArrays([], [15, 45], ["test"])).to.equal(true); - expect(msngr.utils.areArrays([], [15, 45], undefined)).to.equal(false); - expect(msngr.utils.areArrays([], 0, ["test"])).to.equal(false); + it("msngr.areArrays()", function () { + expect(msngr.areArrays([], [15, 45], ["test"])).to.equal(true); + expect(msngr.areArrays([], [15, 45], undefined)).to.equal(false); + expect(msngr.areArrays([], 0, ["test"])).to.equal(false); }); // areObjects() - it("msngr.utils.areObjects()", function () { - expect(msngr.utils.areObjects({}, { k: true })).to.equal(true); - expect(msngr.utils.areObjects({}, "CHICKENS FOR SALE")).to.equal(false); - expect(msngr.utils.areObjects(null, { k: true })).to.equal(false); + it("msngr.areObjects()", function () { + expect(msngr.areObjects({}, { k: true })).to.equal(true); + expect(msngr.areObjects({}, "CHICKENS FOR SALE")).to.equal(false); + expect(msngr.areObjects(null, { k: true })).to.equal(false); }); // areFunctions() - it("msngr.utils.areFunctions()", function () { - expect(msngr.utils.areFunctions(function () {}, function () {})).to.equal(true); - expect(msngr.utils.areFunctions("yup()", function () {})).to.equal(false); - expect(msngr.utils.areFunctions(function () {}, undefined)).to.equal(false); + it("msngr.areFunctions()", function () { + expect(msngr.areFunctions(function () {}, function () {})).to.equal(true); + expect(msngr.areFunctions("yup()", function () {})).to.equal(false); + expect(msngr.areFunctions(function () {}, undefined)).to.equal(false); }); // areEmptyStrings() - it("msngr.utils.areEmptyStrings()", function () { - expect(msngr.utils.areEmptyStrings("", undefined, " ")).to.equal(true); - expect(msngr.utils.areEmptyStrings("", undefined, " a ")).to.equal(false); - expect(msngr.utils.areEmptyStrings({ }, undefined, " ")).to.equal(false); + it("msngr.areEmptyStrings()", function () { + expect(msngr.areEmptyStrings("", undefined, " ")).to.equal(true); + expect(msngr.areEmptyStrings("", undefined, " a ")).to.equal(false); + expect(msngr.areEmptyStrings({ }, undefined, " ")).to.equal(false); }); }); diff --git a/src/utils/validation.cspec.js b/src/utils/validation.cspec.js index afe30cf..c27f026 100644 --- a/src/utils/validation.cspec.js +++ b/src/utils/validation.cspec.js @@ -13,12 +13,12 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { describe("./utils/validation.js", function () { "use strict"; - it("msngr.utils.getType(obj) - obj is a HTMLDivElement", function () { - expect(msngr.utils.getType(document.createElement("div"))).to.equal("[object HTMLDivElement]"); + it("msngr.getType(obj) - obj is a HTMLDivElement", function () { + expect(msngr.getType(document.createElement("div"))).to.equal("[object HTMLDivElement]"); }); - it("msngr.utils.getType(obj) - obj is a HTMLInputElement", function () { - expect(msngr.utils.getType(document.createElement("input"))).to.equal("[object HTMLInputElement]"); + it("msngr.getType(obj) - obj is a HTMLInputElement", function () { + expect(msngr.getType(document.createElement("input"))).to.equal("[object HTMLInputElement]"); }); }); diff --git a/src/utils/validation.js b/src/utils/validation.js index 646fd75..80c8244 100644 --- a/src/utils/validation.js +++ b/src/utils/validation.js @@ -1,93 +1,91 @@ -msngr.extend((function () { +msngr.extend((function (external, internal) { "use strict"; return { - utils: { - getType: function (obj) { - if (!msngr.utils.exist(obj)) { - return "" + obj; + getType: function (obj) { + if (!external.exist(obj)) { + return "" + obj; + } + return Object.prototype.toString.call(obj); + }, + isArguments: function (obj) { + return (external.getType(obj) === "[object Arguments]"); + }, + areArguments: function () { + return external.reiterativeValidation(external.isArguments, external.argumentsToArray(arguments)); + }, + isNullOrUndefined: function (obj) { + return (obj === undefined || obj === null); + }, + exist: function (obj) { + return !external.isNullOrUndefined(obj); + }, + exists: function () { + return external.reiterativeValidation(external.exist, external.argumentsToArray(arguments)); + }, + isString: function (str) { + return (external.getType(str) === "[object String]"); + }, + areStrings: function () { + return external.reiterativeValidation(external.isString, external.argumentsToArray(arguments)); + }, + isDate: function (obj) { + return (external.getType(obj) === "[object Date]"); + }, + areDates: function () { + return external.reiterativeValidation(external.isDate, external.argumentsToArray(arguments)); + }, + isArray: function (obj) { + return (external.getType(obj) === "[object Array]"); + }, + areArrays: function () { + return external.reiterativeValidation(external.isArray, external.argumentsToArray(arguments)); + }, + isNumber: function (obj) { + return (external.getType(obj) === "[object Number]"); + }, + areNumbers: function () { + return external.reiterativeValidation(external.isNumber, external.argumentsToArray(arguments)); + }, + isObject: function (obj) { + return (external.getType(obj) === "[object Object]"); + }, + areObjects: function () { + return external.reiterativeValidation(external.isObject, external.argumentsToArray(arguments)); + }, + isFunction: function (func) { + return (external.getType(func) === "[object Function]"); + }, + areFunctions: function () { + return external.reiterativeValidation(external.isFunction, external.argumentsToArray(arguments)); + }, + isEmptyString: function (str) { + var isStr = external.isString(str); + if (str === undefined || str === null || (isStr && str.toString().trim().length === 0)) { + return true; + } + return false; + }, + areEmptyStrings: function () { + return external.reiterativeValidation(external.isEmptyString, external.argumentsToArray(arguments)); + }, + hasWildCard: function (str) { + return (str.indexOf("*") !== -1); + }, + reiterativeValidation: function (validationMethod, inputs) { + var result = false; + if (external.exist(validationMethod) && external.exist(inputs)) { + if (!external.isArray(inputs)) { + inputs = [inputs]; } - return Object.prototype.toString.call(obj); - }, - isArguments: function (obj) { - return (msngr.utils.getType(obj) === "[object Arguments]"); - }, - areArguments: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isArguments, msngr.utils.argumentsToArray(arguments)); - }, - isNullOrUndefined: function (obj) { - return (obj === undefined || obj === null); - }, - exist: function (obj) { - return !msngr.utils.isNullOrUndefined(obj); - }, - exists: function () { - return msngr.utils.reiterativeValidation(msngr.utils.exist, msngr.utils.argumentsToArray(arguments)); - }, - isString: function (str) { - return (msngr.utils.getType(str) === "[object String]"); - }, - areStrings: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isString, msngr.utils.argumentsToArray(arguments)); - }, - isDate: function (obj) { - return (msngr.utils.getType(obj) === "[object Date]"); - }, - areDates: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isDate, msngr.utils.argumentsToArray(arguments)); - }, - isArray: function (obj) { - return (msngr.utils.getType(obj) === "[object Array]"); - }, - areArrays: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isArray, msngr.utils.argumentsToArray(arguments)); - }, - isNumber: function (obj) { - return (msngr.utils.getType(obj) === "[object Number]"); - }, - areNumbers: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isNumber, msngr.utils.argumentsToArray(arguments)); - }, - isObject: function (obj) { - return (msngr.utils.getType(obj) === "[object Object]"); - }, - areObjects: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isObject, msngr.utils.argumentsToArray(arguments)); - }, - isFunction: function (func) { - return (msngr.utils.getType(func) === "[object Function]"); - }, - areFunctions: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isFunction, msngr.utils.argumentsToArray(arguments)); - }, - isEmptyString: function (str) { - var isStr = msngr.utils.isString(str); - if (str === undefined || str === null || (isStr && str.toString().trim().length === 0)) { - return true; - } - return false; - }, - areEmptyStrings: function () { - return msngr.utils.reiterativeValidation(msngr.utils.isEmptyString, msngr.utils.argumentsToArray(arguments)); - }, - hasWildCard: function (str) { - return (str.indexOf("*") !== -1); - }, - reiterativeValidation: function (validationMethod, inputs) { - var result = false; - if (msngr.utils.exist(validationMethod) && msngr.utils.exist(inputs)) { - if (!msngr.utils.isArray(inputs)) { - inputs = [inputs]; - } - for (var i = 0; i < inputs.length; ++i) { - result = validationMethod.apply(this, [inputs[i]]); - if (result === false) { - break; - } + for (var i = 0; i < inputs.length; ++i) { + result = validationMethod.apply(this, [inputs[i]]); + if (result === false) { + break; } } - return result; } - } + return result; + } }; -}())); +})); From bacbfbf13caa77ae7cd5bc871d3f90baefcc6196 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 25 Apr 2015 09:58:27 -0400 Subject: [PATCH 02/46] Moved reiterativeValidation into the internal interface --- msngr.js | 49 ++++++++++++++++++----------------- msngr.min.js | 2 +- src/utils/validation.aspec.js | 28 +++++++++++--------- src/utils/validation.js | 49 ++++++++++++++++++----------------- 4 files changed, 67 insertions(+), 61 deletions(-) diff --git a/msngr.js b/msngr.js index e0e8047..e754798 100644 --- a/msngr.js +++ b/msngr.js @@ -218,6 +218,22 @@ msngr.extend((function (external, internal) { msngr.extend((function (external, internal) { "use strict"; + internal.reiterativeValidation = function (validationMethod, inputs) { + var result = false; + if (external.exist(validationMethod) && external.exist(inputs)) { + if (!external.isArray(inputs)) { + inputs = [inputs]; + } + for (var i = 0; i < inputs.length; ++i) { + result = validationMethod.apply(this, [inputs[i]]); + if (result === false) { + break; + } + } + } + return result; + }; + return { getType: function (obj) { if (!external.exist(obj)) { @@ -229,7 +245,7 @@ msngr.extend((function (external, internal) { return (external.getType(obj) === "[object Arguments]"); }, areArguments: function () { - return external.reiterativeValidation(external.isArguments, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isArguments, external.argumentsToArray(arguments)); }, isNullOrUndefined: function (obj) { return (obj === undefined || obj === null); @@ -238,43 +254,43 @@ msngr.extend((function (external, internal) { return !external.isNullOrUndefined(obj); }, exists: function () { - return external.reiterativeValidation(external.exist, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.exist, external.argumentsToArray(arguments)); }, isString: function (str) { return (external.getType(str) === "[object String]"); }, areStrings: function () { - return external.reiterativeValidation(external.isString, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isString, external.argumentsToArray(arguments)); }, isDate: function (obj) { return (external.getType(obj) === "[object Date]"); }, areDates: function () { - return external.reiterativeValidation(external.isDate, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isDate, external.argumentsToArray(arguments)); }, isArray: function (obj) { return (external.getType(obj) === "[object Array]"); }, areArrays: function () { - return external.reiterativeValidation(external.isArray, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isArray, external.argumentsToArray(arguments)); }, isNumber: function (obj) { return (external.getType(obj) === "[object Number]"); }, areNumbers: function () { - return external.reiterativeValidation(external.isNumber, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isNumber, external.argumentsToArray(arguments)); }, isObject: function (obj) { return (external.getType(obj) === "[object Object]"); }, areObjects: function () { - return external.reiterativeValidation(external.isObject, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isObject, external.argumentsToArray(arguments)); }, isFunction: function (func) { return (external.getType(func) === "[object Function]"); }, areFunctions: function () { - return external.reiterativeValidation(external.isFunction, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isFunction, external.argumentsToArray(arguments)); }, isEmptyString: function (str) { var isStr = external.isString(str); @@ -284,25 +300,10 @@ msngr.extend((function (external, internal) { return false; }, areEmptyStrings: function () { - return external.reiterativeValidation(external.isEmptyString, external.argumentsToArray(arguments)); + return internal.reiterativeValidation(external.isEmptyString, external.argumentsToArray(arguments)); }, hasWildCard: function (str) { return (str.indexOf("*") !== -1); - }, - reiterativeValidation: function (validationMethod, inputs) { - var result = false; - if (external.exist(validationMethod) && external.exist(inputs)) { - if (!external.isArray(inputs)) { - inputs = [inputs]; - } - for (var i = 0; i < inputs.length; ++i) { - result = validationMethod.apply(this, [inputs[i]]); - if (result === false) { - break; - } - } - } - return result; } }; })); diff --git a/msngr.min.js b/msngr.min.js index 65f06f3..eadd8ac 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={},external=function(input){};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:Array.prototype.slice.call(args,0)}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)}}}),msngr.extend(function(external,internal){"use strict";return{getType:function(obj){return external.exist(obj)?Object.prototype.toString.call(obj):""+obj},isArguments:function(obj){return"[object Arguments]"===external.getType(obj)},areArguments:function(){return external.reiterativeValidation(external.isArguments,external.argumentsToArray(arguments))},isNullOrUndefined:function(obj){return void 0===obj||null===obj},exist:function(obj){return!external.isNullOrUndefined(obj)},exists:function(){return external.reiterativeValidation(external.exist,external.argumentsToArray(arguments))},isString:function(str){return"[object String]"===external.getType(str)},areStrings:function(){return external.reiterativeValidation(external.isString,external.argumentsToArray(arguments))},isDate:function(obj){return"[object Date]"===external.getType(obj)},areDates:function(){return external.reiterativeValidation(external.isDate,external.argumentsToArray(arguments))},isArray:function(obj){return"[object Array]"===external.getType(obj)},areArrays:function(){return external.reiterativeValidation(external.isArray,external.argumentsToArray(arguments))},isNumber:function(obj){return"[object Number]"===external.getType(obj)},areNumbers:function(){return external.reiterativeValidation(external.isNumber,external.argumentsToArray(arguments))},isObject:function(obj){return"[object Object]"===external.getType(obj)},areObjects:function(){return external.reiterativeValidation(external.isObject,external.argumentsToArray(arguments))},isFunction:function(func){return"[object Function]"===external.getType(func)},areFunctions:function(){return external.reiterativeValidation(external.isFunction,external.argumentsToArray(arguments))},isEmptyString:function(str){var isStr=external.isString(str);return void 0===str||null===str||isStr&&0===str.toString().trim().length?!0:!1},areEmptyStrings:function(){return external.reiterativeValidation(external.isEmptyString,external.argumentsToArray(arguments))},hasWildCard:function(str){return-1!==str.indexOf("*")},reiterativeValidation:function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.category=args.shift(),args.length>0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.dataType=args.shift(),_emit(message,payload)))},on:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("on");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_on(message,callback);if(arguments.length>1){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_on(message,callback)}throw InvalidParameters("on")},drop:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("drop");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_drop(message,callback);if(arguments.length>0){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_drop(message,callback)}throw InvalidParameters("drop")},dropAll:function(){return delegates={},delegateCount=0,internal.store.clear(),msngr},getMessageCount:function(){return delegateCount}}}),msngr.extend(function(external,internal){"use strict";var InvalidParameters=function(str){return{name:"InvalidParameters",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},ReservedKeywords=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},reservedProperties=["topic","category","dataType","payload"],actions={},actionsCount=0;return{action:function(property,handler){if(!external.exist(property)||!external.exist(handler))throw InvalidParameters("action");if(-1!==reservedProperties.indexOf(property))throw ReservedKeywords(property);actions[property]=handler,actionsCount++},inaction:function(property){if(!external.exist(property))throw InvalidParameters("inaction");delete actions[property],actionsCount--},act:function(message,superWrap){if(!external.exist(message)||!external.exist(superWrap))throw InvalidParameters("act");!function(msg,sw){if(actionsCount>0){var wrap={preventDefault:function(){sw.preventDefault()},payload:sw.payload};for(var key in msg)msg.hasOwnProperty(key)&&-1===reservedProperties.indexOf(key)&&void 0!==actions[key]&&actions[key].apply(this,[msg,wrap]);sw.payload=wrap.payload}return sw.done()}(message,superWrap)},getActionCount:function(){return actionsCount},getAvailableActions:function(){return Object.keys(actions)}}}),msngr.action("dom",function(message,wrap){"use strict";if(msngr.exist(message.dom)){var norm={gather:void 0,doc:void 0};if(msngr.isObject(message.dom)?(msngr.exist(message.dom.gather)&&(norm.gather=msngr.isArray(message.dom.gather)?message.dom.gather:[message.dom.gather]),msngr.exist(message.dom.root||message.dom.doc)&&(norm.doc=message.dom.root||message.dom.doc)):msngr.isArray(message.dom)?norm.gather=message.dom:msngr.isString(message.dom)&&(norm.gather=[message.dom]),msngr.exist(norm.gather)&&norm.gather.length>0){msngr.isObject(wrap.payload)||(wrap.payload={});for(var i=0;i0)for(var j=0;j0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.category=args.shift(),args.length>0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.dataType=args.shift(),_emit(message,payload)))},on:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("on");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_on(message,callback);if(arguments.length>1){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_on(message,callback)}throw InvalidParameters("on")},drop:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("drop");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_drop(message,callback);if(arguments.length>0){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_drop(message,callback)}throw InvalidParameters("drop")},dropAll:function(){return delegates={},delegateCount=0,internal.store.clear(),msngr},getMessageCount:function(){return delegateCount}}}),msngr.extend(function(external,internal){"use strict";var InvalidParameters=function(str){return{name:"InvalidParameters",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},ReservedKeywords=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},reservedProperties=["topic","category","dataType","payload"],actions={},actionsCount=0;return{action:function(property,handler){if(!external.exist(property)||!external.exist(handler))throw InvalidParameters("action");if(-1!==reservedProperties.indexOf(property))throw ReservedKeywords(property);actions[property]=handler,actionsCount++},inaction:function(property){if(!external.exist(property))throw InvalidParameters("inaction");delete actions[property],actionsCount--},act:function(message,superWrap){if(!external.exist(message)||!external.exist(superWrap))throw InvalidParameters("act");!function(msg,sw){if(actionsCount>0){var wrap={preventDefault:function(){sw.preventDefault()},payload:sw.payload};for(var key in msg)msg.hasOwnProperty(key)&&-1===reservedProperties.indexOf(key)&&void 0!==actions[key]&&actions[key].apply(this,[msg,wrap]);sw.payload=wrap.payload}return sw.done()}(message,superWrap)},getActionCount:function(){return actionsCount},getAvailableActions:function(){return Object.keys(actions)}}}),msngr.action("dom",function(message,wrap){"use strict";if(msngr.exist(message.dom)){var norm={gather:void 0,doc:void 0};if(msngr.isObject(message.dom)?(msngr.exist(message.dom.gather)&&(norm.gather=msngr.isArray(message.dom.gather)?message.dom.gather:[message.dom.gather]),msngr.exist(message.dom.root||message.dom.doc)&&(norm.doc=message.dom.root||message.dom.doc)):msngr.isArray(message.dom)?norm.gather=message.dom:msngr.isString(message.dom)&&(norm.gather=[message.dom]),msngr.exist(norm.gather)&&norm.gather.length>0){msngr.isObject(wrap.payload)||(wrap.payload={});for(var i=0;i0)for(var j=0;j Date: Sat, 25 Apr 2015 10:20:33 -0400 Subject: [PATCH 03/46] Tweaks to testing internal interface stuff --- src/main.aspec.js | 1 + src/store/memory.aspec.js | 9 ++++++++- src/utils/validation.aspec.js | 12 ++++++++---- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main.aspec.js b/src/main.aspec.js index a459852..07250cd 100644 --- a/src/main.aspec.js +++ b/src/main.aspec.js @@ -94,6 +94,7 @@ describe("./main.js", function () { }); it("msngr.debug - property setting exports internal object for testing and debugging", function () { + msngr.debug = false; expect(msngr.internal).to.not.exist; msngr.debug = true; expect(msngr.internal).to.exist; diff --git a/src/store/memory.aspec.js b/src/store/memory.aspec.js index 7fef5ec..e847829 100644 --- a/src/store/memory.aspec.js +++ b/src/store/memory.aspec.js @@ -13,8 +13,15 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { describe("./stores/memory.js", function () { "use strict"; - beforeEach(function() { + before(function () { msngr.debug = true; + }); + + after(function () { + msngr.debug = false; + }); + + beforeEach(function() { msngr.internal.store.clear(); }); diff --git a/src/utils/validation.aspec.js b/src/utils/validation.aspec.js index 3917b28..ed2d349 100644 --- a/src/utils/validation.aspec.js +++ b/src/utils/validation.aspec.js @@ -13,6 +13,14 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { describe("./utils/validation.js", function () { "use strict"; + before(function () { + msngr.debug = true; + }); + + after(function () { + msngr.debug = false; + }); + it("msngr.getType(obj) - obj is a function", function () { expect(msngr.getType(function () {})).to.equal("[object Function]"); }); @@ -481,24 +489,20 @@ describe("./utils/validation.js", function () { // reiterativeValidation(func, inputs) it("msngr.internal.reiterativeValidation(func, inputs) - func is undefined", function () { - msngr.debug = true; expect(msngr.internal.reiterativeValidation(undefined, [true, false, 15, "534"])).to.equal(false); }); it("msngr.internal.reiterativeValidation(func, inputs) - inputs is undefined", function () { - msngr.debug = true; expect(msngr.internal.reiterativeValidation(msngr.exists, undefined)).to.equal(false); }); it("msngr.internal.reiterativeValidation(func, inputs) - func is msngr.exists and inputs is a single value", function () { - msngr.debug = true; expect(msngr.internal.reiterativeValidation(msngr.exists, true)).to.equal(true); expect(msngr.internal.reiterativeValidation(msngr.exists, undefined)).to.equal(false); expect(msngr.internal.reiterativeValidation(msngr.exists, null)).to.equal(false); }); it("msngr.internal.reiterativeValidation(func, inputs) - func is msngr.exists and inputs are various values", function () { - msngr.debug = true; expect(msngr.internal.reiterativeValidation(msngr.exists, [true, false, 15, "534"])).to.equal(true); expect(msngr.internal.reiterativeValidation(msngr.exists, [undefined, false, 15, "534"])).to.equal(false); expect(msngr.internal.reiterativeValidation(msngr.exists, [true, undefined, 15, "534"])).to.equal(false); From 9fdac55a62a637f6e7d7cd8b7a0eee0b228a91dc Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 25 Apr 2015 10:27:47 -0400 Subject: [PATCH 04/46] Created exceptional utility hooked to the internal interface Removed duplicative exception generators to consolidate them into one place --- src/actions/action.js | 25 ++++--------------------- src/main.aspec.js | 8 ++++++++ src/messengers/mitter.js | 20 ++++++-------------- src/utils/exceptional.aspec.js | 24 ++++++++++++++++++++++++ src/utils/exceptional.js | 22 ++++++++++++++++++++++ 5 files changed, 64 insertions(+), 35 deletions(-) create mode 100644 src/utils/exceptional.aspec.js create mode 100644 src/utils/exceptional.js diff --git a/src/actions/action.js b/src/actions/action.js index a172d4d..8660cbf 100644 --- a/src/actions/action.js +++ b/src/actions/action.js @@ -1,23 +1,6 @@ msngr.extend((function (external, internal) { "use strict"; - // Throw statements - var InvalidParameters = function (str) { - return { - name: "InvalidParameters", - severity: "unrecoverable", - message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) - }; - }; - - var ReservedKeywords = function (keyword) { - return { - name: "ReservedKeywordsException", - severity: "unrecoverable", - message: ("Reserved keyword {keyword} supplied as action.".replace("{keyword}", keyword)) - }; - }; - var reservedProperties = ["topic", "category", "dataType", "payload"]; var actions = { }; var actionsCount = 0; @@ -25,11 +8,11 @@ msngr.extend((function (external, internal) { return { action: function (property, handler) { if (!external.exist(property) || !external.exist(handler)) { - throw InvalidParameters("action"); + throw internal.InvalidParametersException("action"); } if (reservedProperties.indexOf(property) !== -1) { - throw ReservedKeywords(property); + throw internal.ReservedKeywordsException(property); } actions[property] = handler; @@ -37,7 +20,7 @@ msngr.extend((function (external, internal) { }, inaction: function (property) { if (!external.exist(property)) { - throw InvalidParameters("inaction"); + throw internal.InvalidParametersException("inaction"); } delete actions[property]; @@ -45,7 +28,7 @@ msngr.extend((function (external, internal) { }, act: function (message, superWrap) { if (!external.exist(message) || !external.exist(superWrap)) { - throw InvalidParameters("act"); + throw internal.InvalidParametersException("act"); } (function (msg, sw) { diff --git a/src/main.aspec.js b/src/main.aspec.js index 07250cd..2d4fdc1 100644 --- a/src/main.aspec.js +++ b/src/main.aspec.js @@ -93,6 +93,14 @@ describe("./main.js", function () { expect(myTest()).to.equal(15); }); + it("msngr.extend(undefined, target) - extending undefined value is simply ignored", function () { + var myTest = { }; + msngr.extend(undefined, myTest); + + expect(myTest).to.exist; + expect(Object.keys(myTest).length).to.equal(0); + }); + it("msngr.debug - property setting exports internal object for testing and debugging", function () { msngr.debug = false; expect(msngr.internal).to.not.exist; diff --git a/src/messengers/mitter.js b/src/messengers/mitter.js index 8d4748f..a07a912 100644 --- a/src/messengers/mitter.js +++ b/src/messengers/mitter.js @@ -1,14 +1,6 @@ msngr.extend((function (external, internal) { "use strict"; - // Throw statements - var InvalidParameters = function (str) { - return { - severity: "unrecoverable", - message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) - }; - }; - var delegates = { }; var delegateCount = 0; @@ -93,7 +85,7 @@ msngr.extend((function (external, internal) { return { msg: function (topic, category, dataType) { if (!external.exist(topic)) { - throw InvalidParameters("topic"); + throw internal.InvalidParametersException("topic"); } var message; @@ -124,7 +116,7 @@ msngr.extend((function (external, internal) { }, emit: function (topic, category, dataType, payload, callback) { if (!external.exist(topic)) { - throw InvalidParameters("emit"); + throw internal.InvalidParametersException("emit"); } var message; @@ -165,7 +157,7 @@ msngr.extend((function (external, internal) { }, on: function (topic, category, dataType, callback) { if (!external.exist(topic)) { - throw InvalidParameters("on"); + throw internal.InvalidParametersException("on"); } var message; @@ -201,11 +193,11 @@ msngr.extend((function (external, internal) { return _on(message, callback); } - throw InvalidParameters("on"); + throw internal.InvalidParametersException("on"); }, drop: function (topic, category, dataType, callback) { if (!external.exist(topic)) { - throw InvalidParameters("drop"); + throw internal.InvalidParametersException("drop"); } var message; @@ -241,7 +233,7 @@ msngr.extend((function (external, internal) { return _drop(message, callback); } - throw InvalidParameters("drop"); + throw internal.InvalidParametersException("drop"); }, dropAll: function () { delegates = { }; diff --git a/src/utils/exceptional.aspec.js b/src/utils/exceptional.aspec.js new file mode 100644 index 0000000..3e0016d --- /dev/null +++ b/src/utils/exceptional.aspec.js @@ -0,0 +1,24 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../../msngr"); +} + +describe("./utils/exceptional.js", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + after(function () { + msngr.debug = false; + }); + +}); diff --git a/src/utils/exceptional.js b/src/utils/exceptional.js new file mode 100644 index 0000000..eaf0362 --- /dev/null +++ b/src/utils/exceptional.js @@ -0,0 +1,22 @@ +msngr.extend((function (external, internal) { + "use strict"; + + internal.InvalidParametersException = function (str) { + return { + name: "InvalidParametersException", + severity: "unrecoverable", + message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) + }; + }; + + internal.ReservedKeywordsException = function (keyword) { + return { + name: "ReservedKeywordsException", + severity: "unrecoverable", + message: ("Reserved keyword {keyword} supplied as action.".replace("{keyword}", keyword)) + }; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); From abf56eaba86d9ca3aa38770d003f660702266243 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 28 Apr 2015 04:23:32 -0400 Subject: [PATCH 05/46] - Removed builders as deprecated now - Added message object for handling emit, persist, on, bind, unbind, drop and dropAll - Added executer object for better handling of async execution tasks (including synd and async aggregation of results) - Removed mitter files as part of transition - Created unit tests for message and executer objects - Commented out / removed / skipped some code and tests related to actions and binding as part of the process to transition to the new object model --- Gruntfile.js | 2 +- msngr.js | 544 ++++++++++++++------------------- msngr.min.js | 2 +- specRunner.min.html | 18 +- src/actions/action.aspec.js | 2 +- src/actions/action.js | 3 +- src/actions/dom.cspec.js | 2 +- src/actions/dom.js | 3 +- src/builders/message.aspec.js | 61 ---- src/builders/message.js | 34 --- src/main.js | 4 +- src/messengers/bind.cspec.js | 2 +- src/messengers/mitter.aspec.js | 327 -------------------- src/messengers/mitter.js | 249 --------------- src/objects/executer.aspec.js | 119 ++++++++ src/objects/executer.js | 67 ++++ src/objects/message.aspec.js | 226 ++++++++++++++ src/objects/message.js | 133 ++++++++ src/utils/converters.js | 6 +- 19 files changed, 806 insertions(+), 998 deletions(-) delete mode 100644 src/builders/message.aspec.js delete mode 100644 src/builders/message.js delete mode 100644 src/messengers/mitter.aspec.js delete mode 100644 src/messengers/mitter.js create mode 100644 src/objects/executer.aspec.js create mode 100644 src/objects/executer.js create mode 100644 src/objects/message.aspec.js create mode 100644 src/objects/message.js diff --git a/Gruntfile.js b/Gruntfile.js index b745e7c..63585ba 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,7 +17,7 @@ module.exports = (function (grunt) { var paths = [ "src/main.js", "src/utils/*.js", - "src/builders/*.js", + "src/objects/*.js", "src/store/*.js", "src/messengers/*.js", "src/actions/*.js", diff --git a/msngr.js b/msngr.js index e754798..2030ef5 100644 --- a/msngr.js +++ b/msngr.js @@ -8,7 +8,9 @@ var msngr = msngr || (function () { "use strict"; var internal = { }; - var external = function ( input ) { }; + var external = function (topic, category, dataType) { + return internal.objects.message(topic, category, dataType); + }; external.version = "2.0.0"; @@ -60,8 +62,10 @@ msngr.extend((function (external, internal) { if (external.isArray(args)) { return args; } - - return Array.prototype.slice.call(args, 0); + if (external.isArguments(args)) { + return Array.prototype.slice.call(args, 0); + } + return [args]; } }; })); @@ -163,6 +167,29 @@ msngr.extend((function (external, internal) { }; })); +msngr.extend((function (external, internal) { + "use strict"; + + internal.InvalidParametersException = function (str) { + return { + name: "InvalidParametersException", + severity: "unrecoverable", + message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) + }; + }; + + internal.ReservedKeywordsException = function (keyword) { + return { + name: "ReservedKeywordsException", + severity: "unrecoverable", + message: ("Reserved keyword {keyword} supplied as action.".replace("{keyword}", keyword)) + }; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); + msngr.extend((function (external, internal) { "use strict"; @@ -308,39 +335,201 @@ msngr.extend((function (external, internal) { }; })); -/* - ./src/builders/message.js -*/ msngr.extend((function (external, internal) { - "use strict"; + "use strict"; - return { - builders: { - msg: function () { - return (function () { - var message = { }; - var props = ["topic", "category", "dataType", "payload"].concat(msngr.getAvailableActions()); - - var obj = { - build: function () { - return message; - } - }; - - for (var i = 0; i < props.length; ++i) { - (function (key) { - obj[key] = function (input) { - message[key] = input; - return obj; - }; - }(props[i])); - } + internal.objects = internal.objects || { }; + internal.objects.executer = function (methods, payload, context) { - return obj; - }()); - } - } - }; + if (external.isFunction(methods)) { + methods = [methods]; + } + + if (!external.exist(methods) || !external.isArray(methods)) { + throw internal.InvalidParametersException("executor"); + } + + var exec = function (method, pay, ctx, done) { + setTimeout(function () { + var async = false; + var async = function () { + async = true; + return function (result) { + done.apply(ctx, [result]); + }; + } + var syncResult = method.apply(ctx || this, [pay, async]); + if (async !== true) { + done.apply(ctx, [syncResult]); + } + }, 0); + }; + + return { + execute: function (done) { + if (methods.length === 0 && external.exist(done)) { + return done.apply(context, [[]]); + } + return exec(methods[0], payload, context, done); + }, + parallel: function (done) { + var results = []; + var executed = 0; + + if (methods.length === 0 && external.exist(done)) { + return done.apply(context, [[]]); + } + + for (var i = 0; i < methods.length; ++i) { + (function (m, p, c) { + exec(m, p, c, function (result) { + if (external.exist(result)) { + results.push(result); + } + + ++executed; + + if (executed === methods.length && external.exist(done)) { + done.apply(context, [results]); + } + }); + }(methods[i], payload, context)); + } + } + }; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); + +msngr.extend((function (external, internal) { + "use strict"; + + internal.objects = internal.objects || { }; + + var handlers = { }; + var handlerCount = 0; + + Object.defineProperty(external, "handlerCount", { + get: function () { + return handlerCount; + } + }); + + internal.reset = function () { + handlers = { }; + handlerCount = 0; + internal.store.clear(); + }; + + internal.objects.message = function (topic, category, dataType) { + var msg = undefined; + if (!external.exist(topic)) { + throw internal.InvalidParametersException("msngr"); + } + + if (!external.isObject(topic) && !external.isString(topic)) { + throw internal.InvalidParametersException("msngr"); + } + + if (external.isEmptyString(topic)) { + throw internal.InvalidParametersException("msngr"); + } + + if (external.isObject(topic)) { + msg = topic; + } else { + msg = { }; + msg.topic = topic; + + if (!external.isEmptyString(category)) { + msg.category = category; + } + + if (!external.isEmptyString(dataType)) { + msg.dataType = dataType; + } + } + + var msgObj = { + emit: function (payload, callback) { + var uuids = internal.store.query(msg); + if (uuids.length > 0) { + var methods = []; + for (var i = 0; i < uuids.length; ++i) { + var obj = handlers[uuids[i]]; + methods.push(obj.handler); + } + var execs = internal.objects.executer(methods, payload, (msg.context || this)); + + execs.parallel(callback); + } + + return msgObj; + }, + persist: function (payload) { + + }, + on: function (handler) { + var uuid = internal.store.index(msg); + handlers[uuid] = { + handler: handler, + context: (msg.context || this) + }; + handlerCount++; + + return msgObj; + }, + bind: function (element, event) { + + }, + drop: function (handler) { + var uuids = internal.store.query(msg); + if (uuids.length > 0) { + for (var i = 0; i < uuids.length; ++i) { + var uuid = uuids[i]; + if (handlers[uuid].handler === handler) { + delete handlers[uuid]; + handlerCount--; + + internal.store.delete(uuid); + } + } + } + + return msgObj; + }, + unbind: function (element, event) { + + }, + dropAll: function () { + var uuids = internal.store.query(msg); + if (uuids.length > 0) { + for (var i = 0; i < uuids.length; ++i) { + var uuid = uuids[i]; + delete handlers[uuid]; + handlerCount--; + + internal.store.delete(uuid); + } + } + + return msgObj; + } + }; + + Object.defineProperty(msgObj, "message", { + get: function () { + return msg; + } + }); + + return msgObj; + }; + + // This is an internal extension; do not export explicitly. + return { }; })); msngr.extend((function (external, internal) { @@ -604,284 +793,9 @@ msngr.extend((function (external, internal) { }; })); -msngr.extend((function (external, internal) { - "use strict"; - - // Throw statements - var InvalidParameters = function (str) { - return { - severity: "unrecoverable", - message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) - }; - }; - - var delegates = { }; - var delegateCount = 0; - - var executeSync = function (method, context, params, message) { - (function (m, c, p, msg) { - var cont = true; - var wrap = { - preventDefault: function () { - cont = false; - }, - payload: p[0], - done: function () { - if (cont === true) { - m.apply(c, [wrap.payload]); - } - } - }; - msngr.act(msg, wrap); - }(method, context, params, message)); - }; - - var execute = function (method, context, params, message) { - (function (m, c, p, msg) { - setTimeout(function () { - executeSync(m, c, p, msg); - }, 0); - }(method, context, params, message)); - }; - - var _emit = function (message, payload, callback) { - var uuids = internal.store.query(message); - if (uuids.length > 0) { - for (var i = 0; i < uuids.length; ++i) { - var del = delegates[uuids[i]]; - var params = []; - if (external.exist(payload || message.payload)) { - params.push(payload || message.payload); - } - execute(del.callback, del.context, params, message); - } - } - - return msngr; - }; - - var _on = function (message, callback) { - var uuid = internal.store.index(message); - delegates[uuid] = { - callback: callback, - context: (message.context || this), - onedMessage: message - }; - delegateCount++; - - return msngr; - }; - - var _drop = function (message, func) { - var uuids = internal.store.query(message); - if (uuids.length > 0) { - for (var i = 0; i < uuids.length; ++i) { - var uuid = uuids[i]; - if (external.exist(func)) { - if (delegates[uuid].callback === func) { - delete delegates[uuid]; - delegateCount--; - - internal.store.delete(uuid); - } - } else { - delete delegates[uuid]; - delegateCount--; - - internal.store.delete(uuid); - } - } - } - - return msngr; - }; - - return { - msg: function (topic, category, dataType) { - if (!external.exist(topic)) { - throw InvalidParameters("topic"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - } else { - message = { - topic: topic, - category: category, - dataType: dataType - }; - } - - return { - emit: function (payload) { - - }, - on: function (callback) { - - }, - drop: function (callback) { - - }, - dropAll: function () { - - } - }; - }, - emit: function (topic, category, dataType, payload, callback) { - if (!external.exist(topic)) { - throw InvalidParameters("emit"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - if (!external.exist(payload) && external.exist(category)) { - payload = category; - } - if (!external.exist(callback) && external.exist(dataType) && external.isFunction(dataType)) { - callback = dataType; - } - return _emit(message, payload, callback); - } - - message = { }; - var args = external.argumentsToArray(arguments); - - message.topic = args.shift(); - - if (!external.exist(payload)) { - if (args.length > 0 && external.isObject(args[0])) { - payload = args.shift(); - - return _emit(message, payload); - } - } - - message.category = args.shift(); - - if (args.length > 0 && external.isObject(args[0])) { - payload = args.shift(); - - return _emit(message, payload); - } - message.dataType = args.shift(); - - return _emit(message, payload); - }, - on: function (topic, category, dataType, callback) { - if (!external.exist(topic)) { - throw InvalidParameters("on"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - if (!external.exist(callback) && external.exist(category)) { - callback = category; - } - return _on(message, callback); - } - if (arguments.length > 1) { - message = { }; - var args = external.argumentsToArray(arguments); - - message.topic = args.shift(); - - message.category = args.shift(); - message.dataType = args.shift(); - - callback = callback || args.pop(); - - if (external.isFunction(message.category) && !external.exist(message.dataType)) { - callback = message.category; - delete message.category; - delete message.dataType; - } - - if (external.isFunction(message.dataType) && external.exist(message.category)) { - callback = message.dataType; - delete message.dataType; - } - - return _on(message, callback); - } - - throw InvalidParameters("on"); - }, - drop: function (topic, category, dataType, callback) { - if (!external.exist(topic)) { - throw InvalidParameters("drop"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - if (!external.exist(callback) && external.exist(category)) { - callback = category; - } - return _drop(message, callback); - } - if (arguments.length > 0) { - message = { }; - var args = external.argumentsToArray(arguments); - - message.topic = args.shift(); - - message.category = args.shift(); - message.dataType = args.shift(); - - callback = callback || args.pop(); - - if (external.isFunction(message.category) && !external.exist(message.dataType)) { - callback = message.category; - delete message.category; - delete message.dataType; - } - - if (external.isFunction(message.dataType) && external.exist(message.category)) { - callback = message.dataType; - delete message.dataType; - } - - return _drop(message, callback); - } - - throw InvalidParameters("drop"); - }, - dropAll: function () { - delegates = { }; - delegateCount = 0; - internal.store.clear(); - - return msngr; - }, - getMessageCount: function () { - return delegateCount; - } - }; -})); - -msngr.extend((function (external, internal) { +/*msngr.extend((function (external, internal) { "use strict"; - // Throw statements - var InvalidParameters = function (str) { - return { - name: "InvalidParameters", - severity: "unrecoverable", - message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) - }; - }; - - var ReservedKeywords = function (keyword) { - return { - name: "ReservedKeywordsException", - severity: "unrecoverable", - message: ("Reserved keyword {keyword} supplied as action.".replace("{keyword}", keyword)) - }; - }; - var reservedProperties = ["topic", "category", "dataType", "payload"]; var actions = { }; var actionsCount = 0; @@ -889,11 +803,11 @@ msngr.extend((function (external, internal) { return { action: function (property, handler) { if (!external.exist(property) || !external.exist(handler)) { - throw InvalidParameters("action"); + throw internal.InvalidParametersException("action"); } if (reservedProperties.indexOf(property) !== -1) { - throw ReservedKeywords(property); + throw internal.ReservedKeywordsException(property); } actions[property] = handler; @@ -901,7 +815,7 @@ msngr.extend((function (external, internal) { }, inaction: function (property) { if (!external.exist(property)) { - throw InvalidParameters("inaction"); + throw internal.InvalidParametersException("inaction"); } delete actions[property]; @@ -909,7 +823,7 @@ msngr.extend((function (external, internal) { }, act: function (message, superWrap) { if (!external.exist(message) || !external.exist(superWrap)) { - throw InvalidParameters("act"); + throw internal.InvalidParametersException("act"); } (function (msg, sw) { @@ -942,8 +856,9 @@ msngr.extend((function (external, internal) { } }; })); +*/ -msngr.action("dom", function (message, wrap) { +/*msngr.action("dom", function (message, wrap) { "use strict"; if (msngr.exist(message.dom)) { @@ -996,6 +911,7 @@ msngr.action("dom", function (message, wrap) { return msngr; }); +*/ /* module.exports.js diff --git a/msngr.min.js b/msngr.min.js index eadd8ac..d725040 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={},external=function(input){};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:Array.prototype.slice.call(args,0)}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.category=args.shift(),args.length>0&&external.isObject(args[0])?(payload=args.shift(),_emit(message,payload)):(message.dataType=args.shift(),_emit(message,payload)))},on:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("on");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_on(message,callback);if(arguments.length>1){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_on(message,callback)}throw InvalidParameters("on")},drop:function(topic,category,dataType,callback){if(!external.exist(topic))throw InvalidParameters("drop");var message;if(external.isObject(topic))return message=topic,!external.exist(callback)&&external.exist(category)&&(callback=category),_drop(message,callback);if(arguments.length>0){message={};var args=external.argumentsToArray(arguments);return message.topic=args.shift(),message.category=args.shift(),message.dataType=args.shift(),callback=callback||args.pop(),external.isFunction(message.category)&&!external.exist(message.dataType)&&(callback=message.category,delete message.category,delete message.dataType),external.isFunction(message.dataType)&&external.exist(message.category)&&(callback=message.dataType,delete message.dataType),_drop(message,callback)}throw InvalidParameters("drop")},dropAll:function(){return delegates={},delegateCount=0,internal.store.clear(),msngr},getMessageCount:function(){return delegateCount}}}),msngr.extend(function(external,internal){"use strict";var InvalidParameters=function(str){return{name:"InvalidParameters",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},ReservedKeywords=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},reservedProperties=["topic","category","dataType","payload"],actions={},actionsCount=0;return{action:function(property,handler){if(!external.exist(property)||!external.exist(handler))throw InvalidParameters("action");if(-1!==reservedProperties.indexOf(property))throw ReservedKeywords(property);actions[property]=handler,actionsCount++},inaction:function(property){if(!external.exist(property))throw InvalidParameters("inaction");delete actions[property],actionsCount--},act:function(message,superWrap){if(!external.exist(message)||!external.exist(superWrap))throw InvalidParameters("act");!function(msg,sw){if(actionsCount>0){var wrap={preventDefault:function(){sw.preventDefault()},payload:sw.payload};for(var key in msg)msg.hasOwnProperty(key)&&-1===reservedProperties.indexOf(key)&&void 0!==actions[key]&&actions[key].apply(this,[msg,wrap]);sw.payload=wrap.payload}return sw.done()}(message,superWrap)},getActionCount:function(){return actionsCount},getAvailableActions:function(){return Object.keys(actions)}}}),msngr.action("dom",function(message,wrap){"use strict";if(msngr.exist(message.dom)){var norm={gather:void 0,doc:void 0};if(msngr.isObject(message.dom)?(msngr.exist(message.dom.gather)&&(norm.gather=msngr.isArray(message.dom.gather)?message.dom.gather:[message.dom.gather]),msngr.exist(message.dom.root||message.dom.doc)&&(norm.doc=message.dom.root||message.dom.doc)):msngr.isArray(message.dom)?norm.gather=message.dom:msngr.isString(message.dom)&&(norm.gather=[message.dom]),msngr.exist(norm.gather)&&norm.gather.length>0){msngr.isObject(wrap.payload)||(wrap.payload={});for(var i=0;i0)for(var j=0;j0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0){for(var methods=[],i=0;i0)for(var i=0;i0)for(var i=0;i - - - + + + + + + + + + + + + + + +
diff --git a/src/actions/action.aspec.js b/src/actions/action.aspec.js index 1682e46..a62a853 100644 --- a/src/actions/action.aspec.js +++ b/src/actions/action.aspec.js @@ -10,7 +10,7 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { var msngr = require("../../msngr"); } -describe("./actions/action.js", function () { +describe.skip("./actions/action.js", function () { "use strict"; beforeEach(function (done) { diff --git a/src/actions/action.js b/src/actions/action.js index 8660cbf..842e103 100644 --- a/src/actions/action.js +++ b/src/actions/action.js @@ -1,4 +1,4 @@ -msngr.extend((function (external, internal) { +/*msngr.extend((function (external, internal) { "use strict"; var reservedProperties = ["topic", "category", "dataType", "payload"]; @@ -61,3 +61,4 @@ msngr.extend((function (external, internal) { } }; })); +*/ diff --git a/src/actions/dom.cspec.js b/src/actions/dom.cspec.js index ac518b5..3c5c7a9 100644 --- a/src/actions/dom.cspec.js +++ b/src/actions/dom.cspec.js @@ -10,7 +10,7 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { var msngr = require("../../msngr"); } -describe("./actions/dom.js", function () { +describe.skip("./actions/dom.js", function () { "use strict"; beforeEach(function (done) { diff --git a/src/actions/dom.js b/src/actions/dom.js index e56d9d2..13ed420 100644 --- a/src/actions/dom.js +++ b/src/actions/dom.js @@ -1,4 +1,4 @@ -msngr.action("dom", function (message, wrap) { +/*msngr.action("dom", function (message, wrap) { "use strict"; if (msngr.exist(message.dom)) { @@ -51,3 +51,4 @@ msngr.action("dom", function (message, wrap) { return msngr; }); +*/ diff --git a/src/builders/message.aspec.js b/src/builders/message.aspec.js deleted file mode 100644 index 0f76c6c..0000000 --- a/src/builders/message.aspec.js +++ /dev/null @@ -1,61 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../../msngr"); -} - -describe("./builders/message.js", function () { - "use strict"; - - it("msngr.builders.msg() - Builds basic message", function () { - var message = msngr.builders.msg() - .topic("TestTopic1") - .category("TestCategory1") - .dataType("TestDataType1") - .payload({ data: 1 }) - .build(); - - expect(message.topic).to.equal("TestTopic1"); - expect(message.category).to.equal("TestCategory1"); - expect(message.dataType).to.equal("TestDataType1"); - expect(message.payload.data).to.equal(1); - }); - - it("msngr.builders.msg() - Builds a message with an action", function () { - var message = msngr.builders.msg() - .topic("TestTopic1") - .dom(true) - .build(); - - expect(message.topic).to.equal("TestTopic1"); - expect(message.dom).to.equal(true); - }); - - it("msngr.builders.msg() - Builds multiple messages while maintaining separate instances", function () { - var build1 = msngr.builders.msg(); - var build2 = msngr.builders.msg(); - var build3 = msngr.builders.msg(); - - build1.topic("ChickenFeet"); - build2.category("Beer"); - build3.topic("Floating"); - build2.topic("Something"); - build1.category("Fowl"); - - build1 = build1.build(); - build2 = build2.build(); - build3 = build3.build(); - - expect(build1.topic).to.equal("ChickenFeet"); - expect(build1.category).to.equal("Fowl"); - expect(build2.topic).to.equal("Something"); - expect(build2.category).to.equal("Beer"); - expect(build3.topic).to.equal("Floating"); - }); -}); diff --git a/src/builders/message.js b/src/builders/message.js deleted file mode 100644 index 22ac185..0000000 --- a/src/builders/message.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - ./src/builders/message.js -*/ -msngr.extend((function (external, internal) { - "use strict"; - - return { - builders: { - msg: function () { - return (function () { - var message = { }; - var props = ["topic", "category", "dataType", "payload"].concat(msngr.getAvailableActions()); - - var obj = { - build: function () { - return message; - } - }; - - for (var i = 0; i < props.length; ++i) { - (function (key) { - obj[key] = function (input) { - message[key] = input; - return obj; - }; - }(props[i])); - } - - return obj; - }()); - } - } - }; -})); diff --git a/src/main.js b/src/main.js index 9175564..a256b3a 100644 --- a/src/main.js +++ b/src/main.js @@ -8,7 +8,9 @@ var msngr = msngr || (function () { "use strict"; var internal = { }; - var external = function ( input ) { }; + var external = function (topic, category, dataType) { + return internal.objects.message(topic, category, dataType); + }; external.version = "2.0.0"; diff --git a/src/messengers/bind.cspec.js b/src/messengers/bind.cspec.js index 94aa7a7..83885f6 100644 --- a/src/messengers/bind.cspec.js +++ b/src/messengers/bind.cspec.js @@ -10,7 +10,7 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { var msngr = require("../../msngr"); } -describe("./messengers/bind.js", function () { +describe.skip("./messengers/bind.js", function () { beforeEach(function (done) { msngr.dropAll(); diff --git a/src/messengers/mitter.aspec.js b/src/messengers/mitter.aspec.js deleted file mode 100644 index a89d107..0000000 --- a/src/messengers/mitter.aspec.js +++ /dev/null @@ -1,327 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../../msngr"); -} - -describe("./messengers/mitter.js", function () { - "use strict"; - - beforeEach(function (done) { - msngr.dropAll(); - done(); - }); - - it("msngr.emit('TestTopic', { str: 'Hello, World Payload!' }) is received by msngr.on('TestTopic', function (payload))", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on("TestTopic", function (payload) { - expect(payload).to.exist; - expect(payload.str).to.equal("Hello, World Payload!"); - - done(); - }); - - msngr.emit("TestTopic", { str: "Hello, World Payload!" }); - }); - - it("msngr.emit('TestTopic', 'TestCategory', { str: 'MyPayload' }) is received by msngr.on('TestTopic', 'TestCategory', function (payload))", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on("TestTopic", "TestCategory", function (payload) { - expect(payload).to.exist; - expect(payload.str).to.equal("MyPayload"); - - done(); - }); - - msngr.emit("TestTopic", "TestCategory", { str: "MyPayload" }); - }); - - it("msngr.emit('TestTopic', 'TestCategory', 'TestDataType', { str: 'AnotherPayload' }) is received by msngr.on('TestTopic', 'TestCategory', 'TestDataType', function (payload))", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on("TestTopic", "TestCategory", "TestDataType", function (payload) { - expect(payload).to.exist; - expect(payload.str).to.equal("AnotherPayload"); - - done(); - }); - - msngr.emit("TestTopic", "TestCategory", "TestDataType", { str: "AnotherPayload" }); - }); - - it("msngr.emit({ topic: 'TestTopic' }, 'WeePayload') is received by msngr.on({ topic: 'TestTopic' }, function (payload))", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on({ topic: "TestTopic" }, function (payload) { - expect(payload).to.exist; - expect(payload).to.equal("WeePayload"); - - done(); - }); - - msngr.emit({ topic: "TestTopic" }, "WeePayload"); - }); - - it("msngr.emit({ topic: 'TestTopic', category: 'TestCategory' }, 'PayloadWUT') is received by msngr.on({ topic: 'TestTopic', category: 'TestCategory' }, function (payload))", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on({ topic: "TestTopic", category: "TestCategory" }, function (payload) { - expect(payload).to.exist; - expect(payload).to.equal("PayloadWUT"); - - done(); - }); - - msngr.emit({ topic: "TestTopic", category: "TestCategory" }, "PayloadWUT"); - }); - - it("msngr.emit({ topic: 'TestTopic', category: 'TestCategory', dataType: 'TestType' }, 'MY PAYLOAD') is received by msngr.on({ topic: 'TestTopic', category: 'TestCategory', dataType: 'TestType' }, function (payload))", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on({ topic: "TestTopic", category: "TestCategory", dataType: "TestType" }, function (payload) { - expect(payload).to.exist; - expect(payload).to.equal("MY PAYLOAD"); - - done(); - }); - - msngr.emit({ topic: "TestTopic", category: "TestCategory", dataType: "TestType" }, "MY PAYLOAD"); - }); - - it("msngr.emit('TestTopic1') is received by msngr.on('TestTopic1') and not msngr.on('TestTopic2')", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - var counter = 0; - var cat1 = undefined; - var cat2 = undefined; - - msngr.on("TestTopic1", function () { - counter++; - cat1 = true; - }); - - msngr.on("TestTopic2", function () { - counter++; - cat2 = true; - }); - - msngr.emit("TestTopic1"); - - setTimeout(function () { - expect(cat1).to.equal(true); - expect(cat2).to.equal(undefined); - expect(counter).to.equal(1); - done(); - }, 250); - }); - - it("msngr.emit('TestTopic1', 'TestCategory1') is received by msngr.on('TestTopic1', 'TestCategory1') and not msngr.on('TestTopic1', 'TestCategory2')", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - var counter = 0; - var cat1 = undefined; - var cat2 = undefined; - - msngr.on("TestTopic1", "TestCategory1", function () { - counter++; - cat1 = true; - }); - - msngr.on("TestTopic1", "TestCategory2", function () { - counter++; - cat2 = true; - }); - - msngr.emit("TestTopic1", "TestCategory1"); - - setTimeout(function () { - expect(cat1).to.equal(true); - expect(cat2).to.equal(undefined); - expect(counter).to.equal(1); - done(); - }, 250); - }); - - it("msngr.emit('TestTopic1', undefined, 'DataType1') is received by msngr.on('TestTopic1', undefined, 'DataType1') and not msngr.on('TestTopic1', undefined, 'DataType2')", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - var counter = 0; - var cat1 = undefined; - var cat2 = undefined; - - msngr.on("TestTopic1", undefined, "DataType1", function () { - counter++; - cat1 = true; - }); - - msngr.on("TestTopic2", undefined, "DataType2", function () { - counter++; - cat2 = true; - }); - - msngr.emit("TestTopic1", undefined, "DataType1"); - - setTimeout(function () { - expect(cat1).to.equal(true); - expect(cat2).to.equal(undefined); - expect(counter).to.equal(1); - done(); - }, 250); - }); - - it("msngr.emit('TestTopic1', 'TestCategory1', 'TestDataType1') is received by msngr.on('TestTopic1', 'TestCategory1', 'TestDataType1') and not msngr.on('TestTopic1', 'TestCategory1', 'TestDataType2')", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - var counter = 0; - var cat1 = undefined; - var cat2 = undefined; - - msngr.on("TestTopic1", "TestCategory1", "TestDataType1", function () { - counter++; - cat1 = true; - }); - - msngr.on("TestTopic1", "TestCategory1", "TestDataType2", function () { - counter++; - cat2 = true; - }); - - msngr.emit("TestTopic1", "TestCategory1", "TestDataType1"); - - setTimeout(function () { - expect(cat1).to.equal(true); - expect(cat2).to.equal(undefined); - expect(counter).to.equal(1); - done(); - }, 250); - }); - - it("msngr.emit('TestTopic1') is received by multiple msngr.on('TestTopic1')", function (done) { - var count = 0; - var hits = { one: undefined, two: undefined, three: undefined }; - - msngr.on("TestTopic1", function () { - count++; - hits.one = true; - }); - - msngr.on("TestTopic1", function () { - count++; - hits.two = true; - }); - - msngr.on("TestTopic1", function () { - count++; - hits.three = true; - }); - - msngr.emit("TestTopic1"); - - setTimeout(function () { - expect(count).to.equal(3); - expect(hits.one).to.exist; - expect(hits.two).to.exist; - expect(hits.three).to.exist; - done(); - }, 250); - }); - - it("msngr.drop('TestTopic') drops msngr.on('TestTopic')", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on("TestTopic", function () { }); - - expect(msngr.getMessageCount()).to.equal(1); - - msngr.drop("TestTopic"); - - expect(msngr.getMessageCount()).to.equal(0); - - done(); - }); - - it("msngr.drop('TestTopic', 'TestCategory') drops msngr.on('TestTopic', 'TestCategory')", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on("TestTopic", "TestCategory", function () { }); - - expect(msngr.getMessageCount()).to.equal(1); - - msngr.drop("TestTopic", "TestCategory"); - - expect(msngr.getMessageCount()).to.equal(0); - - done(); - }); - - it("msngr.drop('TestTopic', 'TestCategory', 'TestDataType') drops msngr.on('TestTopic', 'TestCategory', 'TestDataType')", function (done) { - expect(msngr.getMessageCount()).to.exist; - expect(msngr.getMessageCount()).to.equal(0); - - msngr.on("TestTopic", "TestCategory", "TestDataType", function () { }); - - expect(msngr.getMessageCount()).to.equal(1); - - msngr.drop("TestTopic", "TestCategory", "TestDataType"); - - expect(msngr.getMessageCount()).to.equal(0); - - done(); - }); - - it("msngr.drop('TestTopic', callback) drops specific callbacks and not the entire message", function (done) { - var func1Ran = false; - var func2Ran = false; - - var func1 = function () { - func1Ran = true; - } - - var func2 = function () { - func2Ran = true; - } - - msngr.on("TestTopic", func1); - msngr.on("TestTopic", func2); - - msngr.emit("TestTopic"); - - setTimeout(function () { - expect(func1Ran).to.equal(true); - expect(func2Ran).to.equal(true); - - func1Ran = false; - func2Ran = false; - - msngr.drop("TestTopic", func2); - - msngr.emit("TestTopic"); - - setTimeout(function () { - expect(func1Ran).to.equal(true); - expect(func2Ran).to.equal(false); - done(); - }, 250); - }, 250); - }); -}); diff --git a/src/messengers/mitter.js b/src/messengers/mitter.js deleted file mode 100644 index a07a912..0000000 --- a/src/messengers/mitter.js +++ /dev/null @@ -1,249 +0,0 @@ -msngr.extend((function (external, internal) { - "use strict"; - - var delegates = { }; - var delegateCount = 0; - - var executeSync = function (method, context, params, message) { - (function (m, c, p, msg) { - var cont = true; - var wrap = { - preventDefault: function () { - cont = false; - }, - payload: p[0], - done: function () { - if (cont === true) { - m.apply(c, [wrap.payload]); - } - } - }; - msngr.act(msg, wrap); - }(method, context, params, message)); - }; - - var execute = function (method, context, params, message) { - (function (m, c, p, msg) { - setTimeout(function () { - executeSync(m, c, p, msg); - }, 0); - }(method, context, params, message)); - }; - - var _emit = function (message, payload, callback) { - var uuids = internal.store.query(message); - if (uuids.length > 0) { - for (var i = 0; i < uuids.length; ++i) { - var del = delegates[uuids[i]]; - var params = []; - if (external.exist(payload || message.payload)) { - params.push(payload || message.payload); - } - execute(del.callback, del.context, params, message); - } - } - - return msngr; - }; - - var _on = function (message, callback) { - var uuid = internal.store.index(message); - delegates[uuid] = { - callback: callback, - context: (message.context || this), - onedMessage: message - }; - delegateCount++; - - return msngr; - }; - - var _drop = function (message, func) { - var uuids = internal.store.query(message); - if (uuids.length > 0) { - for (var i = 0; i < uuids.length; ++i) { - var uuid = uuids[i]; - if (external.exist(func)) { - if (delegates[uuid].callback === func) { - delete delegates[uuid]; - delegateCount--; - - internal.store.delete(uuid); - } - } else { - delete delegates[uuid]; - delegateCount--; - - internal.store.delete(uuid); - } - } - } - - return msngr; - }; - - return { - msg: function (topic, category, dataType) { - if (!external.exist(topic)) { - throw internal.InvalidParametersException("topic"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - } else { - message = { - topic: topic, - category: category, - dataType: dataType - }; - } - - return { - emit: function (payload) { - - }, - on: function (callback) { - - }, - drop: function (callback) { - - }, - dropAll: function () { - - } - }; - }, - emit: function (topic, category, dataType, payload, callback) { - if (!external.exist(topic)) { - throw internal.InvalidParametersException("emit"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - if (!external.exist(payload) && external.exist(category)) { - payload = category; - } - if (!external.exist(callback) && external.exist(dataType) && external.isFunction(dataType)) { - callback = dataType; - } - return _emit(message, payload, callback); - } - - message = { }; - var args = external.argumentsToArray(arguments); - - message.topic = args.shift(); - - if (!external.exist(payload)) { - if (args.length > 0 && external.isObject(args[0])) { - payload = args.shift(); - - return _emit(message, payload); - } - } - - message.category = args.shift(); - - if (args.length > 0 && external.isObject(args[0])) { - payload = args.shift(); - - return _emit(message, payload); - } - message.dataType = args.shift(); - - return _emit(message, payload); - }, - on: function (topic, category, dataType, callback) { - if (!external.exist(topic)) { - throw internal.InvalidParametersException("on"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - if (!external.exist(callback) && external.exist(category)) { - callback = category; - } - return _on(message, callback); - } - if (arguments.length > 1) { - message = { }; - var args = external.argumentsToArray(arguments); - - message.topic = args.shift(); - - message.category = args.shift(); - message.dataType = args.shift(); - - callback = callback || args.pop(); - - if (external.isFunction(message.category) && !external.exist(message.dataType)) { - callback = message.category; - delete message.category; - delete message.dataType; - } - - if (external.isFunction(message.dataType) && external.exist(message.category)) { - callback = message.dataType; - delete message.dataType; - } - - return _on(message, callback); - } - - throw internal.InvalidParametersException("on"); - }, - drop: function (topic, category, dataType, callback) { - if (!external.exist(topic)) { - throw internal.InvalidParametersException("drop"); - } - - var message; - if (external.isObject(topic)) { - message = topic; - if (!external.exist(callback) && external.exist(category)) { - callback = category; - } - return _drop(message, callback); - } - if (arguments.length > 0) { - message = { }; - var args = external.argumentsToArray(arguments); - - message.topic = args.shift(); - - message.category = args.shift(); - message.dataType = args.shift(); - - callback = callback || args.pop(); - - if (external.isFunction(message.category) && !external.exist(message.dataType)) { - callback = message.category; - delete message.category; - delete message.dataType; - } - - if (external.isFunction(message.dataType) && external.exist(message.category)) { - callback = message.dataType; - delete message.dataType; - } - - return _drop(message, callback); - } - - throw internal.InvalidParametersException("drop"); - }, - dropAll: function () { - delegates = { }; - delegateCount = 0; - internal.store.clear(); - - return msngr; - }, - getMessageCount: function () { - return delegateCount; - } - }; -})); diff --git a/src/objects/executer.aspec.js b/src/objects/executer.aspec.js new file mode 100644 index 0000000..f2d288a --- /dev/null +++ b/src/objects/executer.aspec.js @@ -0,0 +1,119 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../../msngr"); +} + +describe("./objects/executer.js", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + after(function () { + msngr.debug = false; + }); + + + it("msngr.internal.objects.executer(method, payload, context).execute(done) - executes and returns a result from a sync method", function (done) { + var myFunc = function (payload, async) { + return 15; + }; + + msngr.internal.objects.executer(myFunc, undefined, this).execute(function (result) { + expect(result).to.exist; + expect(result).to.equal(15); + done(); + }); + }); + + it("msngr.internal.objects.executer(method, payload, context).execute(done) - executes and returns a result from an async method", function (done) { + var myFunc = function (payload, async) { + var d = async(); + d(42); + }; + + msngr.internal.objects.executer(myFunc, undefined, this).execute(function (result) { + expect(result).to.existl + expect(result).to.equal(42); + done(); + }); + }); + + it("msngr.internal.objects.executer(method, payload, context).execute(done) - done is executed even with no methods", function (done) { + msngr.internal.objects.executer([], undefined, this).execute(function (result) { + expect(result).to.exist; + expect(result.length).to.equal(0); + done(); + }); + }); + + it("msngr.internal.objects.executer(method, payload, context).parallel(done) - done is executed even with no methods", function (done) { + msngr.internal.objects.executer([], undefined, this).parallel(function (result) { + expect(result).to.exist; + expect(result.length).to.equal(0); + done(); + }); + }); + + it("msngr.internal.objects.executer(methods, payload, context).parallel(done) - executes multiple methods and aggregates results", function (done) { + var func1 = function (payload, async) { + expect(payload.t).to.exist; + expect(payload.t).to.equal(false); + return 1; + } + + var func2 = function (payload, async) { + expect(payload.t).to.exist; + expect(payload.t).to.equal(false); + return "test"; + } + + var func3 = function (payload, async) { + expect(payload.t).to.exist; + expect(payload.t).to.equal(false); + var d = async(); + d("whatever!"); + } + + var func4 = function (payload, async) { + expect(payload.t).to.exist; + expect(payload.t).to.equal(false); + return 97; + } + + var func5 = function (payload, async) { + expect(payload.t).to.exist; + expect(payload.t).to.equal(false); + return 100; + } + + var func6 = function (payload, async) { + expect(payload.t).to.exist; + expect(payload.t).to.equal(false); + return true; + } + + var executer = msngr.internal.objects.executer([func1, func2, func3, func4, func5, func6], { t: false }, this); + executer.parallel(function (results) { + expect(results).to.exist; + expect(results.length).to.equal(6); + expect(results.indexOf(1)).to.not.equal(-1); + expect(results.indexOf("test")).to.not.equal(-1); + expect(results.indexOf("whatever!")).to.not.equal(-1); + expect(results.indexOf(97)).to.not.equal(-1); + expect(results.indexOf(100)).to.not.equal(-1); + expect(results.indexOf(true)).to.not.equal(-1); + + done(); + }); + }); + +}); diff --git a/src/objects/executer.js b/src/objects/executer.js new file mode 100644 index 0000000..e5f50b8 --- /dev/null +++ b/src/objects/executer.js @@ -0,0 +1,67 @@ +msngr.extend((function (external, internal) { + "use strict"; + + internal.objects = internal.objects || { }; + internal.objects.executer = function (methods, payload, context) { + + if (external.isFunction(methods)) { + methods = [methods]; + } + + if (!external.exist(methods) || !external.isArray(methods)) { + throw internal.InvalidParametersException("executor"); + } + + var exec = function (method, pay, ctx, done) { + setTimeout(function () { + var async = false; + var async = function () { + async = true; + return function (result) { + done.apply(ctx, [result]); + }; + } + var syncResult = method.apply(ctx || this, [pay, async]); + if (async !== true) { + done.apply(ctx, [syncResult]); + } + }, 0); + }; + + return { + execute: function (done) { + if (methods.length === 0 && external.exist(done)) { + return done.apply(context, [[]]); + } + return exec(methods[0], payload, context, done); + }, + parallel: function (done) { + var results = []; + var executed = 0; + + if (methods.length === 0 && external.exist(done)) { + return done.apply(context, [[]]); + } + + for (var i = 0; i < methods.length; ++i) { + (function (m, p, c) { + exec(m, p, c, function (result) { + if (external.exist(result)) { + results.push(result); + } + + ++executed; + + if (executed === methods.length && external.exist(done)) { + done.apply(context, [results]); + } + }); + }(methods[i], payload, context)); + } + } + }; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js new file mode 100644 index 0000000..57878de --- /dev/null +++ b/src/objects/message.aspec.js @@ -0,0 +1,226 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../../msngr"); +} + +describe("./objects/message.js", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); + + it("msngr.internal.objects.message - handles a message object as expected", function () { + var m = msngr.internal.objects.message({ topic: "MyTopic", category: "MyCategory", dataType: "MyDataType" }); + expect(m).to.exist; + expect(m.message).to.exist; + expect(m.message.topic).to.exist; + expect(m.message.topic).to.equal("MyTopic"); + expect(m.message.category).to.exist; + expect(m.message.category).to.equal("MyCategory"); + expect(m.message.dataType).to.exist; + expect(m.message.dataType).to.equal("MyDataType"); + }); + + it("msngr.internal.objects.message() - converts single string into message object with a topic", function () { + var m = msngr.internal.objects.message("MyTopic"); + expect(m).to.exist; + expect(m.message).to.exist; + expect(m.message.topic).to.exist; + expect(m.message.topic).to.equal("MyTopic"); + }); + + it("msngr.internal.objects.message() - converts two strings into message object with a topic and category", function () { + var m = msngr.internal.objects.message("MyTopic", "MyCategory"); + expect(m).to.exist; + expect(m.message).to.exist; + expect(m.message.topic).to.exist; + expect(m.message.topic).to.equal("MyTopic"); + expect(m.message.category).to.exist; + expect(m.message.category).to.equal("MyCategory"); + }); + + it("msngr.internal.objects.message() - converts three strings into message object with a topic, category and dataType", function () { + var m = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + expect(m).to.exist; + expect(m.message).to.exist; + expect(m.message.topic).to.exist; + expect(m.message.topic).to.equal("MyTopic"); + expect(m.message.category).to.exist; + expect(m.message.category).to.equal("MyCategory"); + expect(m.message.dataType).to.exist; + expect(m.message.dataType).to.equal("MyDataType"); + }); + + it("msngr.internal.objects.message() - multiple copies do not share message objects", function () { + var m1 = msngr.internal.objects.message("MyTopic1"); + var m2 = msngr.internal.objects.message("MyTopic2", "MyCategory2"); + var m3 = msngr.internal.objects.message("MyTopic3", "MyCategory3", "MyDataType3"); + var m4 = msngr.internal.objects.message("MyTopic4", "MyCategory4"); + var m5 = msngr.internal.objects.message("MyTopic5"); + + expect(m1).to.exist; + expect(m2).to.exist; + expect(m3).to.exist; + expect(m4).to.exist; + expect(m5).to.exist; + + expect(m1.message.topic).to.not.equal(m2.message.topic); + expect(m2.message.topic).to.not.equal(m3.message.topic); + expect(m3.message.topic).to.not.equal(m4.message.topic); + expect(m4.message.topic).to.not.equal(m5.message.topic); + expect(m5.message.topic).to.not.equal(m1.message.topic); + + expect(m2.message.category).to.not.equal(m3.message.category); + expect(m3.message.dataType).to.not.equal(m4.message.dataType); + }); + + it("msngr.internal.objects.message().emit() / on() - Successfully emits and handles a topic only message", function (done) { + var msg = msngr.internal.objects.message("MyTopic"); + msg.on(function (payload) { + expect(payload).to.exist; + expect(payload).to.equal("MyPayload"); + done(); + }); + + msg.emit("MyPayload"); + }); + + it("msngr.internal.objects.message().emit() / on() - Successfully emits and handles a topic and category message", function (done) { + var msg = msngr.internal.objects.message("MyTopic", "MyCategory"); + msg.on(function (payload) { + expect(payload).to.exist; + expect(payload).to.equal("AnotherPayload"); + done(); + }); + + msg.emit("AnotherPayload"); + }); + + it("msngr.internal.objects.message().emit() / on() - Successfully emits and handles a topic, category and dataType message", function (done) { + var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + msg.on(function (payload) { + expect(payload).to.exist; + expect(payload).to.equal("WeePayloads!"); + done(); + }); + + msg.emit("WeePayloads!"); + }); + + it("msngr.internal.objects.message().emit() / on() - Setup three handlers, both receive emit payload", function (done) { + var handled = 0; + + var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + msg.on(function (payload) { + ++handled; + expect(payload).to.exist; + expect(payload).to.equal("ThreeHandlers"); + }); + + msg.on(function (payload) { + ++handled; + expect(payload).to.exist; + expect(payload).to.equal("ThreeHandlers"); + }); + + msg.on(function (payload) { + ++handled; + expect(payload).to.exist; + expect(payload).to.equal("ThreeHandlers"); + }); + + msg.emit("ThreeHandlers"); + + setTimeout(function () { + expect(handled).to.equal(3); + done(); + }, 250); + }); + + it("msngr.internal.objects.message().emit() / on() - Setup two handlers, delete one and the other still receives", function (done) { + var handled = 0; + var answer = undefined; + var onHandler1 = function (payload) { + ++handled; + answer = 1; + expect(payload).to.exist; + expect(payload).to.equal("TwoThenOne"); + }; + + var onHandler2 = function (payload) { + ++handled; + answer = 5; + expect(payload).to.exist; + expect(payload).to.equal("TwoThenOne"); + }; + + var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + + msg.on(onHandler1); + msg.on(onHandler2); + + msg.drop(onHandler1); + + msg.emit("TwoThenOne"); + + setTimeout(function () { + expect(handled).to.equal(1); + expect(answer).to.exist; + expect(answer).to.equal(5); + done(); + }, 250); + }); + + it("msngr.internal.objects.message().emit() / on() - Multiple handlers, callback on emit aggregates results", function (done) { + var handled = 0; + + var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + msg.on(function (payload) { + ++handled; + expect(payload).to.exist; + expect(payload).to.equal("ThreeHandlers"); + return "testering"; + }); + + msg.on(function (payload, async) { + var finished = async(); + ++handled; + expect(payload).to.exist; + expect(payload).to.equal("ThreeHandlers"); + finished(42); + }); + + msg.on(function (payload) { + ++handled; + expect(payload).to.exist; + expect(payload).to.equal("ThreeHandlers"); + return true; + }); + + msg.emit("ThreeHandlers", function (results) { + expect(handled).to.equal(3); + expect(results).to.exist; + expect(results.length).to.equal(3); + expect(results.indexOf("testering")).to.not.equal(-1); + expect(results.indexOf(42)).to.not.equal(-1); + expect(results.indexOf(true)).to.not.equal(-1); + done(); + }); + }); +}); diff --git a/src/objects/message.js b/src/objects/message.js new file mode 100644 index 0000000..d2d03b9 --- /dev/null +++ b/src/objects/message.js @@ -0,0 +1,133 @@ +/* + ./objects/message.js + + The primary object of msngr; handles all message sending, receiving and binding. +*/ +msngr.extend((function (external, internal) { + "use strict"; + + internal.objects = internal.objects || { }; + + var handlers = { }; + var handlerCount = 0; + + Object.defineProperty(external, "handlerCount", { + get: function () { + return handlerCount; + } + }); + + internal.reset = function () { + handlers = { }; + handlerCount = 0; + internal.store.clear(); + }; + + internal.objects.message = function (topic, category, dataType) { + var msg = undefined; + if (!external.exist(topic)) { + throw internal.InvalidParametersException("msngr"); + } + + if (!external.isObject(topic) && !external.isString(topic)) { + throw internal.InvalidParametersException("msngr"); + } + + if (external.isEmptyString(topic)) { + throw internal.InvalidParametersException("msngr"); + } + + if (external.isObject(topic)) { + msg = topic; + } else { + msg = { }; + msg.topic = topic; + + if (!external.isEmptyString(category)) { + msg.category = category; + } + + if (!external.isEmptyString(dataType)) { + msg.dataType = dataType; + } + } + + var msgObj = { + emit: function (payload, callback) { + var uuids = internal.store.query(msg); + if (uuids.length > 0) { + var methods = []; + for (var i = 0; i < uuids.length; ++i) { + var obj = handlers[uuids[i]]; + methods.push(obj.handler); + } + var execs = internal.objects.executer(methods, payload, (msg.context || this)); + + execs.parallel(callback); + } + + return msgObj; + }, + persist: function (payload) { + + }, + on: function (handler) { + var uuid = internal.store.index(msg); + handlers[uuid] = { + handler: handler, + context: (msg.context || this) + }; + handlerCount++; + + return msgObj; + }, + bind: function (element, event) { + + }, + drop: function (handler) { + var uuids = internal.store.query(msg); + if (uuids.length > 0) { + for (var i = 0; i < uuids.length; ++i) { + var uuid = uuids[i]; + if (handlers[uuid].handler === handler) { + delete handlers[uuid]; + handlerCount--; + + internal.store.delete(uuid); + } + } + } + + return msgObj; + }, + unbind: function (element, event) { + + }, + dropAll: function () { + var uuids = internal.store.query(msg); + if (uuids.length > 0) { + for (var i = 0; i < uuids.length; ++i) { + var uuid = uuids[i]; + delete handlers[uuid]; + handlerCount--; + + internal.store.delete(uuid); + } + } + + return msgObj; + } + }; + + Object.defineProperty(msgObj, "message", { + get: function () { + return msg; + } + }); + + return msgObj; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); diff --git a/src/utils/converters.js b/src/utils/converters.js index 610e4e0..d8e122e 100644 --- a/src/utils/converters.js +++ b/src/utils/converters.js @@ -6,8 +6,10 @@ msngr.extend((function (external, internal) { if (external.isArray(args)) { return args; } - - return Array.prototype.slice.call(args, 0); + if (external.isArguments(args)) { + return Array.prototype.slice.call(args, 0); + } + return [args]; } }; })); From 0987a497a86c92368ac95f3421d58156d6866347 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Mon, 4 May 2015 02:30:39 -0400 Subject: [PATCH 06/46] The full translation of the 1.x API to the new 2.x paradigm is complete. Actions are now options. Options can now be executed in sync or async. --- Gruntfile.js | 4 +- msngr.js | 752 +++++++++++++------------- msngr.min.js | 2 +- specRunner.min.html | 9 +- src/actions/action.aspec.js | 112 ---- src/actions/action.js | 64 --- src/actions/dom.js | 54 -- src/messengers/bind.cspec.js | 165 ------ src/messengers/bind.js | 96 ---- src/objects/executer.js | 11 +- src/objects/memory.aspec.js | 283 ++++++++++ src/objects/memory.js | 161 ++++++ src/objects/message.aspec.js | 81 ++- src/objects/message.cspec.js | 131 +++++ src/objects/message.js | 138 ++++- src/{actions => options}/dom.cspec.js | 33 +- src/options/dom.js | 74 +++ src/store/memory.aspec.js | 251 --------- src/store/memory.js | 163 ------ src/utils/exceptional.js | 8 + src/utils/misc.aspec.js | 15 + src/utils/misc.js | 10 + 22 files changed, 1275 insertions(+), 1342 deletions(-) delete mode 100644 src/actions/action.aspec.js delete mode 100644 src/actions/action.js delete mode 100644 src/actions/dom.js delete mode 100644 src/messengers/bind.cspec.js delete mode 100644 src/messengers/bind.js create mode 100644 src/objects/memory.aspec.js create mode 100644 src/objects/memory.js create mode 100644 src/objects/message.cspec.js rename src/{actions => options}/dom.cspec.js (82%) create mode 100644 src/options/dom.js delete mode 100644 src/store/memory.aspec.js delete mode 100644 src/store/memory.js diff --git a/Gruntfile.js b/Gruntfile.js index 63585ba..e68624d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,10 +17,10 @@ module.exports = (function (grunt) { var paths = [ "src/main.js", "src/utils/*.js", - "src/objects/*.js", "src/store/*.js", + "src/objects/*.js", "src/messengers/*.js", - "src/actions/*.js", + "src/options/*.js", "src/module.exports.js", "!**/*.aspec.js", "!**/*.cspec.js", diff --git a/msngr.js b/msngr.js index 2030ef5..d1672db 100644 --- a/msngr.js +++ b/msngr.js @@ -186,6 +186,14 @@ msngr.extend((function (external, internal) { }; }; + internal.MangledException = function (variable, method) { + return { + name: "MangledException", + severity: "unrecoverable", + message: ("The {variable} was unexpectedly mangled in {method}.".replace("{variable}", variable).replace("{method}", method)) + }; + }; + // This is an internal extension; do not export explicitly. return { }; })); @@ -238,6 +246,16 @@ msngr.extend((function (external, internal) { } lastNow = now; return now; + }, + removeFromArray: function (arr, value) { + var inx = arr.indexOf(value); + var endIndex = arr.length - 1; + if (inx !== endIndex) { + var temp = arr[endIndex]; + arr[endIndex] = arr[inx]; + arr[inx] = temp; + } + arr.pop(); } }; })); @@ -358,7 +376,16 @@ msngr.extend((function (external, internal) { done.apply(ctx, [result]); }; } - var syncResult = method.apply(ctx || this, [pay, async]); + + var params = undefined; + if (external.isArray(pay)) { + params = pay; + } else { + params = [pay]; + } + params.push(async); + + var syncResult = method.apply(ctx || this, params); if (async !== true) { done.apply(ctx, [syncResult]); } @@ -407,20 +434,239 @@ msngr.extend((function (external, internal) { "use strict"; internal.objects = internal.objects || { }; + internal.objects.memory = function () { + + // Index for id to message objects + var id_to_message = { }; + + // Direct index (no partials) for message + var direct_index = { + topic_to_id: { }, + topic_cat_to_id: { }, + topic_type_to_id: { }, + topic_cat_type_to_id: { } + }; + + // Message index count + var index_count = 0; + + var mem = { + index: function (message) { + if (external.exist(message) && external.exist(message.topic)) { + var uuid = external.id(); + id_to_message[uuid] = message; + + if (direct_index.topic_to_id[message.topic] === undefined) { + direct_index.topic_to_id[message.topic] = []; + } + direct_index.topic_to_id[message.topic].push(uuid); + + if (external.exist(message.category)) { + if (direct_index.topic_cat_to_id[message.topic] === undefined) { + direct_index.topic_cat_to_id[message.topic] = { }; + } + + if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_to_id[message.topic][message.category] = []; + } + + direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); + } + + if (external.exist(message.dataType)) { + if (direct_index.topic_type_to_id[message.topic] === undefined) { + direct_index.topic_type_to_id[message.topic] = { }; + } + + if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { + direct_index.topic_type_to_id[message.topic][message.dataType] = []; + } + + direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); + } + + if (external.exist(message.category) && external.exist(message.dataType)) { + if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { + direct_index.topic_cat_type_to_id[message.topic] = { }; + } + + if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; + } + + if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; + } + + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); + } + + index_count++; + + return uuid; + } + return undefined; + }, + delete: function (uuid) { + if (external.exist(uuid) && external.exist(id_to_message[uuid])) { + var message = id_to_message[uuid]; + + if (external.exist(message.topic)) { + external.removeFromArray(direct_index.topic_to_id[message.topic], uuid); + + if (external.exist(message.category)) { + external.removeFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); + } + + if (external.exist(message.dataType)) { + external.removeFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); + } + + if (external.exist(message.category) && external.exist(message.dataType)) { + external.removeFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); + } + } + + delete id_to_message[uuid]; + index_count--; + + return true; + } + return false; + }, + query: function (message) { + if (external.exist(message)) { + if (external.exist(message.topic)) { + // Topic Only Results + if (!external.exist(message.category) && !external.exist(message.dataType)) { + return direct_index.topic_to_id[message.topic] || []; + } + + // Topic + Category Results + if (external.exist(message.category) && !external.exist(message.dataType)) { + return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; + } + + // Topic + Data Type Results + if (external.exist(message.dataType) && !external.exist(message.category)) { + return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; + } + + // Topic + Category + Data Type Results + if (external.exist(message.category) && external.exist(message.dataType)) { + return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; + } + } + } + + return []; + }, + clear: function () { + // Index for id to message objects + id_to_message = { }; + + // Direct index (no partials) for message + direct_index = { + topic_to_id: { }, + topic_cat_to_id: { }, + topic_type_to_id: { }, + topic_cat_type_to_id: { } + }; + + index_count = 0; + + return true; + } + }; + + Object.defineProperty(mem, "count", { + get: function () { + return index_count; + } + }); + + return mem; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); + +/* + ./objects/message.js + + The primary object of msngr; handles all message sending, receiving and binding. +*/ +msngr.extend((function (external, internal) { + "use strict"; + + internal.objects = internal.objects || { }; + + var messageIndex = internal.objects.memory(); var handlers = { }; var handlerCount = 0; - Object.defineProperty(external, "handlerCount", { + var boundDOMPaths = { }; + var boundCount = 0; + + Object.defineProperty(internal, "handlerCount", { get: function () { return handlerCount; } }); + Object.defineProperty(internal, "boundCount", { + get: function () { + return boundCount; + } + }); + internal.reset = function () { handlers = { }; + boundDOMPaths = { }; handlerCount = 0; - internal.store.clear(); + boundCount = 0; + messageIndex.clear(); + }; + + internal.processOpts = function (opts, message, payload, callback) { + payload = payload || { }; + var optProcessors = []; + for (var key in opts) { + if (opts.hasOwnProperty(key) && external.exist(internal.options[key])) { + optProcessors.push(internal.options[key]); + } + } + + // Short circuit for no options + if (optProcessors.length === 0) { + return callback.apply(this, [payload]); + } + + // Long circuit to do stuff (du'h) + var execs = internal.objects.executer(optProcessors, [message, payload, opts], this); + + execs.parallel(function (results) { + var result = payload; + if (external.exist(results) && results.length > 0) { + for (var i = 0; i < results.length; ++i) { + result = external.extend(results[i], result); + } + } + callback.apply(this, [result]); + }); + }; + + internal.domListener = function (event) { + var node = this; + var path = external.getDomPath(node); + + if (external.exist(boundDOMPaths[path])) { + if (external.exist(boundDOMPaths[path][event.type])) { + return internal.objects.message(boundDOMPaths[path][event.type]).emit(event); + } + } }; internal.objects.message = function (topic, category, dataType) { @@ -452,40 +698,87 @@ msngr.extend((function (external, internal) { } } + var options = { }; + var msgObj = { + option: function (key, value) { + options[key] = value; + + return msgObj; + }, + options: function (obj) { + external.extend(obj, options); + + return msgObj; + }, emit: function (payload, callback) { - var uuids = internal.store.query(msg); + var uuids = messageIndex.query(msg); if (uuids.length > 0) { var methods = []; + var toDrop = []; for (var i = 0; i < uuids.length; ++i) { var obj = handlers[uuids[i]]; methods.push(obj.handler); + + if (obj.once === true) { + toDrop.push(obj.handler); + } } - var execs = internal.objects.executer(methods, payload, (msg.context || this)); - execs.parallel(callback); + internal.processOpts(options, msg, payload, function (result) { + var execs = internal.objects.executer(methods, result, (msg.context || this)); + + for (var i = 0; i < toDrop.length; ++i) { + msgObj.drop(toDrop[i]); + } + + execs.parallel(callback); + + }); } return msgObj; }, - persist: function (payload) { + on: function (handler) { + var uuid = messageIndex.index(msg); + handlers[uuid] = { + handler: handler, + context: (msg.context || this), + once: false + }; + handlerCount++; + return msgObj; }, - on: function (handler) { - var uuid = internal.store.index(msg); + once: function (handler) { + var uuid = messageIndex.index(msg); handlers[uuid] = { handler: handler, - context: (msg.context || this) + context: (msg.context || this), + once: true }; handlerCount++; return msgObj; }, bind: function (element, event) { + var node = external.findElement(element); + var path = external.getDomPath(node); + if (!external.exist(boundDOMPaths[path])) { + boundDOMPaths[path] = { }; + } + + boundDOMPaths[path][event] = msg; + + node.addEventListener(event, internal.domListener); + + ++boundCount; + + return msgObj; }, drop: function (handler) { - var uuids = internal.store.query(msg); + var uuids = messageIndex.query(msg); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var uuid = uuids[i]; @@ -493,7 +786,7 @@ msngr.extend((function (external, internal) { delete handlers[uuid]; handlerCount--; - internal.store.delete(uuid); + messageIndex.delete(uuid); } } } @@ -501,17 +794,30 @@ msngr.extend((function (external, internal) { return msgObj; }, unbind: function (element, event) { + var node = external.findElement(element); + var path = external.getDomPath(node); + + if (external.exist(boundDOMPaths[path])) { + if (external.exist(boundDOMPaths[path][event])) { + node.removeEventListener(event, internal.domListener); + + delete boundDOMPaths[path][event]; + --boundCount; + } + } + + return msgObj; }, dropAll: function () { - var uuids = internal.store.query(msg); + var uuids = messageIndex.query(msg); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var uuid = uuids[i]; delete handlers[uuid]; handlerCount--; - internal.store.delete(uuid); + messageIndex.delete(uuid); } } @@ -532,386 +838,80 @@ msngr.extend((function (external, internal) { return { }; })); -msngr.extend((function (external, internal) { - "use strict"; - - // Index for id to message objects - var id_to_message = { }; - - // Direct index (no partials) for message - var direct_index = { - topic_to_id: { }, - topic_cat_to_id: { }, - topic_type_to_id: { }, - topic_cat_type_to_id: { } - }; - - // Message index count - var index_count = 0; - - var deleteValueFromArray = function (arr, value) { - var inx = arr.indexOf(value); - var endIndex = arr.length - 1; - if (inx !== endIndex) { - var temp = arr[endIndex]; - arr[endIndex] = arr[inx]; - arr[inx] = temp; - } - arr.pop(); - }; - - internal.store = { - index: function (message) { - if (external.exist(message) && external.exist(message.topic)) { - var uuid = external.id(); - id_to_message[uuid] = message; - - if (direct_index.topic_to_id[message.topic] === undefined) { - direct_index.topic_to_id[message.topic] = []; - } - direct_index.topic_to_id[message.topic].push(uuid); - - if (external.exist(message.category)) { - if (direct_index.topic_cat_to_id[message.topic] === undefined) { - direct_index.topic_cat_to_id[message.topic] = { }; - } - - if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_to_id[message.topic][message.category] = []; - } - - direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); - } - - if (external.exist(message.dataType)) { - if (direct_index.topic_type_to_id[message.topic] === undefined) { - direct_index.topic_type_to_id[message.topic] = { }; - } - - if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { - direct_index.topic_type_to_id[message.topic][message.dataType] = []; - } - - direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); - } - - if (external.exist(message.category) && external.exist(message.dataType)) { - if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { - direct_index.topic_cat_type_to_id[message.topic] = { }; - } - - if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; - } - - if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; - } - - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); - } - - index_count++; - - return uuid; - } - return undefined; - }, - delete: function (uuid) { - if (external.exist(uuid) && external.exist(id_to_message[uuid])) { - var message = id_to_message[uuid]; - - if (external.exist(message.topic)) { - deleteValueFromArray(direct_index.topic_to_id[message.topic], uuid); - - if (external.exist(message.category)) { - deleteValueFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); - } - - if (external.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); - } - - if (external.exist(message.category) && external.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); - } - } - - delete id_to_message[uuid]; - index_count--; - - return true; - } - return false; - }, - query: function (message) { - if (external.exist(message)) { - if (external.exist(message.topic)) { - // Topic Only Results - if (!external.exist(message.category) && !external.exist(message.dataType)) { - return direct_index.topic_to_id[message.topic] || []; - } - - // Topic + Category Results - if (external.exist(message.category) && !external.exist(message.dataType)) { - return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; - } - - // Topic + Data Type Results - if (external.exist(message.dataType) && !external.exist(message.category)) { - return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; - } - - // Topic + Category + Data Type Results - if (external.exist(message.category) && external.exist(message.dataType)) { - return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; - } - } - } - - return []; - }, - clear: function () { - // Index for id to message objects - id_to_message = { }; - - // Direct index (no partials) for message - direct_index = { - topic_to_id: { }, - topic_cat_to_id: { }, - topic_type_to_id: { }, - topic_cat_type_to_id: { } - }; - - index_count = 0; - - return true; - }, - count: function () { - return index_count; - } - }; - - // This is an internal extension; do not export explicitly. - return { }; -})); +/* + ./options/dom.js + The primary object of msngr; handles all message sending, receiving and binding. +*/ msngr.extend((function (external, internal) { "use strict"; - // Throw statements - var InvalidParametersException = function (str) { - return { - severity: "unrecoverable", - message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) - }; - }; - - var UnexpectedException = function (str) { - return { - severity: "unrecoverable", - message: ("An unexpected exception occured in the {method} method".replace("{method}", str)) - }; - }; - - var registerdPaths = { }; - var registerdEvents = 0; - - var listener = function (event) { - var node = this; - var path = external.getDomPath(node); - - if (external.exist(registerdPaths[path])) { - if (external.exist(registerdPaths[path][event.type])) { - return msngr.emit(registerdPaths[path][event.type], event); - } + internal.options = internal.options || { }; + + internal.options.dom = function (message, payload, options, async) { + // Normalize all of the inputs + options = options || { }; + options = options.dom || { }; + var doc = options.doc || options.document || document; + + var selectors = undefined; + if (external.isObject(options) && external.exist(options.selectors) && external.isString(options.selectors)) { + selectors = [options.selectors]; + } else if (external.isString(options)) { + selectors = [options]; + } else if (external.isArray(options)) { + selectors = options; } - // How did we get here? Must be a memory leak or something. Ugh - return msngr; - }; - - return { - bind: function (element, event, topic, category, dataType) { - if (!external.exist(element) || !external.exist(event) || !external.exist(topic)) { - throw InvalidParametersException("bind"); - } - if (external.isObject(topic) && !external.exist(topic.topic)) { - throw InvalidParametersException("bind"); - } - - var node = external.findElement(element); - var path = external.getDomPath(node); + if (!external.exist(doc) || !external.exist(selectors) || selectors.length === 0) { + return undefined; + } - if (!external.exist(registerdPaths[path])) { - registerdPaths[path] = { }; + // Process all selectors and put them into a single array + var elements = []; + var selLength = selectors.length; + for (var i = 0; i < selLength; ++i) { + var found = external.findElements(selectors[i], doc); + if (found.length > 0) { + elements = elements.concat(Array.prototype.slice.call(found)); } + } - var message = undefined; - if (external.isObject(topic)) { - message = topic; + // Iterate through found elements and aggregate the results + var resultMap = undefined; + var elmLength = elements.length; + var unnamedTags = 0; + for (var i = 0; i < elmLength; ++i) { + var key = undefined, value = undefined; + var elm = elements[i]; + + var nameAttr = elm.getAttribute("name"); + var idAttr = elm.id; + var tagName = elm.tagName.toLowerCase(); + var val = elm.value; + + if (external.exist(nameAttr) && !external.isEmptyString(nameAttr)) { + key = nameAttr; + } else if (external.exist(idAttr) && !external.isEmptyString(idAttr)) { + key = idAttr; } else { - message = { }; - message.topic = topic; - - if (external.exist(category)) { - message.category = category; - } - - if (external.exist(dataType)) { - message.dataType = dataType; - } + key = (tagName + unnamedTags); + unnamedTags++; } - registerdPaths[path][event] = message; - - node.addEventListener(event, listener); - - registerdEvents++; - - return msngr; - }, - unbind: function (element, event) { - var node = external.findElement(element); - var path = external.getDomPath(node); - - if (external.exist(registerdPaths[path])) { - if (external.exist(registerdPaths[path][event])) { - node.removeEventListener(event, listener); - - delete registerdPaths[path][event]; - - registerdEvents--; - } + if (resultMap === undefined) { + resultMap = { }; } - - return msngr; - }, - getBindCount: function () { - return registerdEvents; + resultMap[key] = val; } - }; -})); -/*msngr.extend((function (external, internal) { - "use strict"; - - var reservedProperties = ["topic", "category", "dataType", "payload"]; - var actions = { }; - var actionsCount = 0; + return resultMap; - return { - action: function (property, handler) { - if (!external.exist(property) || !external.exist(handler)) { - throw internal.InvalidParametersException("action"); - } - - if (reservedProperties.indexOf(property) !== -1) { - throw internal.ReservedKeywordsException(property); - } - - actions[property] = handler; - actionsCount++; - }, - inaction: function (property) { - if (!external.exist(property)) { - throw internal.InvalidParametersException("inaction"); - } - - delete actions[property]; - actionsCount--; - }, - act: function (message, superWrap) { - if (!external.exist(message) || !external.exist(superWrap)) { - throw internal.InvalidParametersException("act"); - } - - (function (msg, sw) { - if (actionsCount > 0) { - var wrap = { - preventDefault: function () { - sw.preventDefault(); - }, - payload: sw.payload - }; - for (var key in msg) { - if (msg.hasOwnProperty(key)) { - if (reservedProperties.indexOf(key) === -1) { - if (actions[key] !== undefined) { - actions[key].apply(this, [msg, wrap]); - } - } - } - } - sw.payload = wrap.payload; - } - return sw.done(); - }(message, superWrap)); - }, - getActionCount: function () { - return actionsCount; - }, - getAvailableActions: function () { - return Object.keys(actions); - } }; -})); -*/ - -/*msngr.action("dom", function (message, wrap) { - "use strict"; - - if (msngr.exist(message.dom)) { - var norm = { - gather: undefined, - doc: undefined - }; - if (!msngr.isObject(message.dom)) { - if (msngr.isArray(message.dom)) { - norm.gather = message.dom; - } else if (msngr.isString(message.dom)) { - norm.gather = [message.dom]; - } - } else { - if (msngr.exist(message.dom.gather)) { - norm.gather = (msngr.isArray(message.dom.gather) ? message.dom.gather : [message.dom.gather]); - } - if (msngr.exist(message.dom.root || message.dom.doc)) { - norm.doc = message.dom.root || message.dom.doc; - } - } - - if (msngr.exist(norm.gather) && norm.gather.length > 0) { - if (!msngr.isObject(wrap.payload)) { - wrap.payload = { }; - } - - for (var i = 0; i < norm.gather.length; ++i) { - var elms = msngr.findElements(norm.gather[i], message.dom.root); - if (msngr.exist(elms) && elms.length > 0) { - for (var j = 0; j < elms.length; ++j) { - var elm = elms[j]; - - var prop; - if (msngr.exist(elm.getAttribute("name")) && !msngr.isEmptyString(elm.getAttribute("name"))) { - prop = elm.getAttribute("name"); - } else if (msngr.exist(elm.id) && !msngr.isEmptyString(elm.id)) { - prop = elm.getAttribute("id"); - console.log(elm.id); - } else { - prop = elm.tagName.toLowerCase() + j; - } - - wrap.payload[prop] = elm.value; - } - } - } - } - } - return msngr; -}); -*/ + // This is an internal extension; do not export explicitly. + return { }; +})); /* module.exports.js diff --git a/msngr.min.js b/msngr.min.js index d725040..37a0644 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0){for(var methods=[],i=0;i0)for(var i=0;i0)for(var i=0;i0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/specRunner.min.html b/specRunner.min.html index 5205fa1..2256f6d 100644 --- a/specRunner.min.html +++ b/specRunner.min.html @@ -11,13 +11,12 @@ - - - - + + - + + diff --git a/src/actions/action.aspec.js b/src/actions/action.aspec.js deleted file mode 100644 index a62a853..0000000 --- a/src/actions/action.aspec.js +++ /dev/null @@ -1,112 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../../msngr"); -} - -describe.skip("./actions/action.js", function () { - "use strict"; - - beforeEach(function (done) { - msngr.dropAll(); - done(); - }); - - it("msngr.action(property, function () { }) - adds an action which successfully acts on a message payload", function (done) { - msngr.on("TestTopic", function (payload) { - expect(payload).to.exist; - expect(payload).to.equal("Payload Poke!"); - - expect(msngr.getActionCount()).to.exist; - var c = msngr.getActionCount(); - msngr.inaction("poke"); - expect(msngr.getActionCount()).to.equal(c - 1); - - done(); - }); - - expect(msngr.getActionCount()).to.exist; - msngr.action("poke", function (message, wrap) { - wrap.payload = wrap.payload + " Poke!"; - }); - - msngr.emit({ topic: "TestTopic" , poke: true }, "Payload"); - }); - - it("msngr.action(property, function () { }) - adds multiple actions which all successfully act on a message payload", function (done) { - msngr.on("TestTopic", function (payload) { - expect(payload).to.exist; - expect(payload.numbers).to.exist; - expect(payload.numbers.length).to.equal(3); - expect(payload.words).to.exist; - expect(payload.words.length).to.equal(3); - expect(payload.original).to.exist; - expect(payload.original).to.equal("TestBorg"); - - msngr.inaction("numbers"); - msngr.inaction("words"); - - done(); - }); - - var start = msngr.getActionCount(); - expect(start).to.exist; - msngr.action("numbers", function (message, wrap) { - wrap.payload.numbers = [12, 15, 97]; - }); - - msngr.action("words", function (message, wrap) { - wrap.payload.words = ["float", "chicken", "springs"]; - }); - expect(msngr.getActionCount()).to.equal(start + 2); - - msngr.emit({ topic: "TestTopic" , numbers: true, words: true }, { original: "TestBorg" }); - }); - - it("msngr.action(property, function () { }) - adds multiple actions but only one acts on a message payload", function (done) { - msngr.on("TestTopic", function (payload) { - expect(payload).to.exist; - expect(payload.numbers).to.exist; - expect(payload.numbers.length).to.equal(3); - expect(payload.words).to.not.exist; - expect(payload.original).to.exist; - expect(payload.original).to.equal("TestBorg"); - - msngr.inaction("numbers"); - msngr.inaction("words"); - - done(); - }); - - var start = msngr.getActionCount(); - expect(start).to.exist; - msngr.action("numbers", function (message, wrap) { - wrap.payload.numbers = [12, 15, 97]; - }); - - msngr.action("words", function (message, wrap) { - wrap.payload.words = ["float", "chicken", "springs"]; - }); - expect(msngr.getActionCount()).to.equal(start + 2); - - msngr.emit({ topic: "TestTopic" , numbers: true }, { original: "TestBorg" }); - }); - - it("msngr.getActionCount() - Returns the correct amount of actions", function () { - var start = msngr.getActionCount(); - - msngr.action("chicken", function (message, wrap) { - // Nothing here necessary - }); - - expect(msngr.getActionCount()).to.equal(start + 1); - msngr.inaction("chicken"); - expect(msngr.getActionCount()).to.equal(start); - }); -}); diff --git a/src/actions/action.js b/src/actions/action.js deleted file mode 100644 index 842e103..0000000 --- a/src/actions/action.js +++ /dev/null @@ -1,64 +0,0 @@ -/*msngr.extend((function (external, internal) { - "use strict"; - - var reservedProperties = ["topic", "category", "dataType", "payload"]; - var actions = { }; - var actionsCount = 0; - - return { - action: function (property, handler) { - if (!external.exist(property) || !external.exist(handler)) { - throw internal.InvalidParametersException("action"); - } - - if (reservedProperties.indexOf(property) !== -1) { - throw internal.ReservedKeywordsException(property); - } - - actions[property] = handler; - actionsCount++; - }, - inaction: function (property) { - if (!external.exist(property)) { - throw internal.InvalidParametersException("inaction"); - } - - delete actions[property]; - actionsCount--; - }, - act: function (message, superWrap) { - if (!external.exist(message) || !external.exist(superWrap)) { - throw internal.InvalidParametersException("act"); - } - - (function (msg, sw) { - if (actionsCount > 0) { - var wrap = { - preventDefault: function () { - sw.preventDefault(); - }, - payload: sw.payload - }; - for (var key in msg) { - if (msg.hasOwnProperty(key)) { - if (reservedProperties.indexOf(key) === -1) { - if (actions[key] !== undefined) { - actions[key].apply(this, [msg, wrap]); - } - } - } - } - sw.payload = wrap.payload; - } - return sw.done(); - }(message, superWrap)); - }, - getActionCount: function () { - return actionsCount; - }, - getAvailableActions: function () { - return Object.keys(actions); - } - }; -})); -*/ diff --git a/src/actions/dom.js b/src/actions/dom.js deleted file mode 100644 index 13ed420..0000000 --- a/src/actions/dom.js +++ /dev/null @@ -1,54 +0,0 @@ -/*msngr.action("dom", function (message, wrap) { - "use strict"; - - if (msngr.exist(message.dom)) { - var norm = { - gather: undefined, - doc: undefined - }; - if (!msngr.isObject(message.dom)) { - if (msngr.isArray(message.dom)) { - norm.gather = message.dom; - } else if (msngr.isString(message.dom)) { - norm.gather = [message.dom]; - } - } else { - if (msngr.exist(message.dom.gather)) { - norm.gather = (msngr.isArray(message.dom.gather) ? message.dom.gather : [message.dom.gather]); - } - if (msngr.exist(message.dom.root || message.dom.doc)) { - norm.doc = message.dom.root || message.dom.doc; - } - } - - if (msngr.exist(norm.gather) && norm.gather.length > 0) { - if (!msngr.isObject(wrap.payload)) { - wrap.payload = { }; - } - - for (var i = 0; i < norm.gather.length; ++i) { - var elms = msngr.findElements(norm.gather[i], message.dom.root); - if (msngr.exist(elms) && elms.length > 0) { - for (var j = 0; j < elms.length; ++j) { - var elm = elms[j]; - - var prop; - if (msngr.exist(elm.getAttribute("name")) && !msngr.isEmptyString(elm.getAttribute("name"))) { - prop = elm.getAttribute("name"); - } else if (msngr.exist(elm.id) && !msngr.isEmptyString(elm.id)) { - prop = elm.getAttribute("id"); - console.log(elm.id); - } else { - prop = elm.tagName.toLowerCase() + j; - } - - wrap.payload[prop] = elm.value; - } - } - } - } - } - - return msngr; -}); -*/ diff --git a/src/messengers/bind.cspec.js b/src/messengers/bind.cspec.js deleted file mode 100644 index 83885f6..0000000 --- a/src/messengers/bind.cspec.js +++ /dev/null @@ -1,165 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../../msngr"); -} - -describe.skip("./messengers/bind.js", function () { - - beforeEach(function (done) { - msngr.dropAll(); - done(); - }); - - it("msngr.bind(element, event, topic) - Binds and sends with just a topic", function (done) { - var div = document.createElement("div"); - - msngr.bind(div, "testEvent", "MyTopic"); - - msngr.on("MyTopic", function (payload) { - expect(payload).to.exist; - done(); - }); - - var testEvent = document.createEvent("CustomEvent"); - testEvent.initCustomEvent("testEvent", false, false, null); - div.dispatchEvent(testEvent); - }); - - it("msngr.bind(element, event, topic, category) - Binds and sends with a topic and category", function (done) { - var div = document.createElement("div"); - - msngr.bind(div, "testEvent", "MyTopic", "MyCategory"); - - msngr.on("MyTopic", "MyCategory", function (payload) { - expect(payload).to.exist; - done(); - }); - - var testEvent = document.createEvent("CustomEvent"); - testEvent.initCustomEvent("testEvent", false, false, null); - div.dispatchEvent(testEvent); - }); - - it("msngr.bind(element, event, topic, category, dataType) - Binds and sends with a topic, category and dataType", function (done) { - var div = document.createElement("div"); - - msngr.bind(div, "testEvent", "MyTopic", "MyCategory", "MyDataType"); - - msngr.on("MyTopic", "MyCategory", "MyDataType", function (payload) { - expect(payload).to.exist; - done(); - }); - - var testEvent = document.createEvent("CustomEvent"); - testEvent.initCustomEvent("testEvent", false, false, null); - div.dispatchEvent(testEvent); - }); - - it("msngr.bind(element, event, message) - Binds and sends with a message object with a topic, category and dataType", function (done) { - var div = document.createElement("div"); - - msngr.bind(div, "testEvent", { topic: "MyTopic", category: "MyCategory", dataType: "MyDataType" }); - - msngr.on("MyTopic", "MyCategory", "MyDataType", function (payload) { - expect(payload).to.exist; - done(); - }); - - var testEvent = document.createEvent("CustomEvent"); - testEvent.initCustomEvent("testEvent", false, false, null); - div.dispatchEvent(testEvent); - }); - - it("msngr.bind(element, event, topic, category) - Binds and sends with a topic and category", function (done) { - var div = document.createElement("div"); - - msngr.bind(div, "testEvent", "MyTopic", "MyCategory"); - - msngr.on("MyTopic", "MyCategory", function (payload) { - expect(payload).to.exist; - done(); - }); - - var testEvent = document.createEvent("CustomEvent"); - testEvent.initCustomEvent("testEvent", false, false, null); - div.dispatchEvent(testEvent); - }); - - it("msngr.bind(element, event, topic, category) - Bind then remove doesn't emit message", function (done) { - var div = document.createElement("div"); - - msngr.bind(div, "testEvent", "MyTopic", "MyCategory"); - var flag = false; - msngr.on("MyTopic", "MyCategory", function (payload) { - flag = true; - expect(flag).to.equal(false); - done(); - }); - - var testEvent = document.createEvent("CustomEvent"); - testEvent.initCustomEvent("testEvent", false, false, null); - - msngr.unbind(div, "testEvent"); - - div.dispatchEvent(testEvent); - - setTimeout(function () { - expect(flag).to.equal(false); - done(); - }, 250); - }); - - it("msngr.unbind(element, event) - Unbind and ensure the message originally bound does not get sent", function (done) { - var div = document.createElement("div"); - - msngr.bind(div, "testEvent1", "MyTopic1", "MyCategory1"); - msngr.bind(div, "testEvent2", "MyTopic2", "MyCategory2"); - var flag = false; - - msngr.on("MyTopic1", "MyCategory1", function () { - flag = true; - }); - - msngr.on("MyTopic2", "MyCategory2", function () { - flag = true; - }); - - var testEvent1 = document.createEvent("CustomEvent"); - testEvent1.initCustomEvent("testEven1", false, false, null); - - var testEvent2 = document.createEvent("CustomEvent"); - testEvent2.initCustomEvent("testEven1", false, false, null); - - msngr.unbind(div, "testEvent1"); - msngr.unbind(div, "testEvent2"); - - div.dispatchEvent(testEvent1); - div.dispatchEvent(testEvent2); - - setTimeout(function () { - expect(flag).to.equal(false); - done(); - }, 250); - }); - - it("msngr.getBindCount() - Accurately tracks the bind count", function () { - var div = document.createElement("div"); - - var start = msngr.getBindCount(); - msngr.bind(div, "testEvent1", "MyTopic1", "MyCategory1"); - msngr.bind(div, "testEvent2", "MyTopic2", "MyCategory2"); - - expect(msngr.getBindCount()).to.equal(start + 2); - - msngr.unbind(div, "testEvent1"); - - expect(msngr.getBindCount()).to.equal(start + 1); - }); -}); diff --git a/src/messengers/bind.js b/src/messengers/bind.js deleted file mode 100644 index 3336f3d..0000000 --- a/src/messengers/bind.js +++ /dev/null @@ -1,96 +0,0 @@ -msngr.extend((function (external, internal) { - "use strict"; - - // Throw statements - var InvalidParametersException = function (str) { - return { - severity: "unrecoverable", - message: ("Invalid parameters supplied to the {method} method".replace("{method}", str)) - }; - }; - - var UnexpectedException = function (str) { - return { - severity: "unrecoverable", - message: ("An unexpected exception occured in the {method} method".replace("{method}", str)) - }; - }; - - var registerdPaths = { }; - var registerdEvents = 0; - - var listener = function (event) { - var node = this; - var path = external.getDomPath(node); - - if (external.exist(registerdPaths[path])) { - if (external.exist(registerdPaths[path][event.type])) { - return msngr.emit(registerdPaths[path][event.type], event); - } - } - - // How did we get here? Must be a memory leak or something. Ugh - return msngr; - }; - - return { - bind: function (element, event, topic, category, dataType) { - if (!external.exist(element) || !external.exist(event) || !external.exist(topic)) { - throw InvalidParametersException("bind"); - } - if (external.isObject(topic) && !external.exist(topic.topic)) { - throw InvalidParametersException("bind"); - } - - var node = external.findElement(element); - var path = external.getDomPath(node); - - if (!external.exist(registerdPaths[path])) { - registerdPaths[path] = { }; - } - - var message = undefined; - if (external.isObject(topic)) { - message = topic; - } else { - message = { }; - message.topic = topic; - - if (external.exist(category)) { - message.category = category; - } - - if (external.exist(dataType)) { - message.dataType = dataType; - } - } - - registerdPaths[path][event] = message; - - node.addEventListener(event, listener); - - registerdEvents++; - - return msngr; - }, - unbind: function (element, event) { - var node = external.findElement(element); - var path = external.getDomPath(node); - - if (external.exist(registerdPaths[path])) { - if (external.exist(registerdPaths[path][event])) { - node.removeEventListener(event, listener); - - delete registerdPaths[path][event]; - - registerdEvents--; - } - } - - return msngr; - }, - getBindCount: function () { - return registerdEvents; - } - }; -})); diff --git a/src/objects/executer.js b/src/objects/executer.js index e5f50b8..31f06d8 100644 --- a/src/objects/executer.js +++ b/src/objects/executer.js @@ -21,7 +21,16 @@ msngr.extend((function (external, internal) { done.apply(ctx, [result]); }; } - var syncResult = method.apply(ctx || this, [pay, async]); + + var params = undefined; + if (external.isArray(pay)) { + params = pay; + } else { + params = [pay]; + } + params.push(async); + + var syncResult = method.apply(ctx || this, params); if (async !== true) { done.apply(ctx, [syncResult]); } diff --git a/src/objects/memory.aspec.js b/src/objects/memory.aspec.js new file mode 100644 index 0000000..8b43be2 --- /dev/null +++ b/src/objects/memory.aspec.js @@ -0,0 +1,283 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../../msngr"); +} + +describe("./objects/memory.js", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + after(function () { + msngr.debug = false; + }); + + it("memory.index(message) - indexes a message with only a topic", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1" + }; + + expect(memory.count).to.equal(0); + var id = memory.index(message); + expect(id).to.exist; + expect(memory.count).to.equal(1); + }); + + it("memory.index(message) - indexes a message with a topic and category", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1" + }; + + expect(memory.count).to.equal(0); + var id = memory.index(message); + expect(id).to.exist; + expect(memory.count).to.equal(1); + }); + + it("memory.index(message) - indexes a message with a topic and dataType", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + dataType: "TestDataType1" + }; + + expect(memory.count).to.equal(0); + var id = memory.index(message); + expect(id).to.exist; + expect(memory.count).to.equal(1); + }); + + it("memory.index(message) - indexes a message with a topic, category and dataType", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1", + dataType: "TestDataType1" + }; + + expect(memory.count).to.equal(0); + var id = memory.index(message); + expect(id).to.exist; + expect(memory.count).to.equal(1); + }); + + it("memory.index(message) - invalid message shouldn't index", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + cookie: "monster" + }; + + expect(memory.count).to.equal(0); + var id = memory.index(message); + expect(id).to.not.exist; + expect(memory.count).to.equal(0); + }); + + it("memory.delete(uuid) - deletes a valid uuid", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1", + dataType: "TestDataType1" + }; + + var id = memory.index(message); + expect(id).to.exist; + + var result = memory.delete(id); + expect(result).to.exist; + expect(result).to.equal(true); + expect(memory.count).to.equal(0); + }); + + it("memory.delete(uuid) - doesn't delete an invalid uuid", function () { + var memory = msngr.internal.objects.memory(); + + var result = memory.delete("sldfjslkfjlwrjlskdfjs"); + expect(result).to.exist; + expect(result).to.equal(false); + expect(memory.count).to.equal(0); + }); + + it("memory.query(message) - Correctly gets one result for a query on a topic", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1" + }; + + var id = memory.index(message); + expect(id).to.exist; + + var result = memory.query({ topic: "TestTopic1" }); + + expect(result).to.exist; + expect(result.length).to.equal(1); + }); + + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic that doesn't exist", function () { + var memory = msngr.internal.objects.memory(); + + var result = memory.query({ topic: "TestTopic1" }); + + expect(result).to.exist; + expect(result.length).to.equal(0); + }); + + it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic and category", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1" + }; + + var id = memory.index(message); + expect(id).to.exist; + + var result = memory.query({ topic: "TestTopic1", category: "TestCategory1" }); + + expect(result).to.exist; + expect(result.length).to.equal(1); + }); + + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic and category that doesn't exist", function () { + var memory = msngr.internal.objects.memory(); + + var result = memory.query({ topic: "TestTopic1", category: "TestCategory1" }); + + expect(result).to.exist; + expect(result.length).to.equal(0); + }); + + it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic, category and dataType", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1", + dataType: "TestDataType1" + }; + + var id = memory.index(message); + expect(id).to.exist; + + var result = memory.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); + + expect(result).to.exist; + expect(result.length).to.equal(1); + }); + + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType that doesn't exist", function () { + var memory = msngr.internal.objects.memory(); + + var result = memory.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); + + expect(result).to.exist; + expect(result.length).to.equal(0); + }); + + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where category doesn't exist", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1", + dataType: "TestDataType1" + }; + + var id = memory.index(message); + expect(id).to.exist; + + var result = memory.query({ topic: "TestTopic1", category: "TestCategory2", dataType: "TestDataType1" }); + + expect(result).to.exist; + expect(result.length).to.equal(0); + }); + + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where dataType doesn't exist", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1", + dataType: "TestDataType1" + }; + + var id = memory.index(message); + expect(id).to.exist; + + var result = memory.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType2" }); + + expect(result).to.exist; + expect(result.length).to.equal(0); + }); + + it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where topic doesn't exist", function () { + var memory = msngr.internal.objects.memory(); + + var message = { + topic: "TestTopic1", + category: "TestCategory1", + dataType: "TestDataType1" + }; + + var id = memory.index(message); + expect(id).to.exist; + + var result = memory.query({ topic: "TestTopic2", category: "TestCategory1", dataType: "TestDataType1" }); + + expect(result).to.exist; + expect(result.length).to.equal(0); + }); + + it("msngr.internal.store.clear() - Clears all indexed messages", function () { + var memory = msngr.internal.objects.memory(); + + var ids = []; + ids.push(memory.index({ topic: "chicken" })); + ids.push(memory.index({ topic: "table", category: "50" })); + ids.push(memory.index({ topic: "stairs", category: "10", dataType: "food" })); + ids.push(memory.index({ topic: "whatevea", dataType: "punk" })); + + expect(memory.count).to.equal(4); + expect(memory.clear()).to.equal(true); + expect(memory.query({ topic: "chicken" }).length).to.equal(0); + expect(memory.query({ topic: "stairs", category: "10", dataType: "food" }).length).to.equal(0); + }); + + it("msngr.internal.store.count - Returns a correct count", function () { + var memory = msngr.internal.objects.memory(); + + expect(memory.count).to.equal(0); + memory.index({ topic: "chicken" }); + expect(memory.count).to.equal(1); + memory.index({ topic: "table", category: "50" }); + expect(memory.count).to.equal(2); + memory.index({ topic: "stairs", category: "10", dataType: "food" }); + expect(memory.count).to.equal(3); + expect(memory.clear()).to.equal(true); + expect(memory.count).to.equal(0); + memory.index({ topic: "whatevea", dataType: "punk" }); + expect(memory.count).to.equal(1); + + }); +}); diff --git a/src/objects/memory.js b/src/objects/memory.js new file mode 100644 index 0000000..23c0d1a --- /dev/null +++ b/src/objects/memory.js @@ -0,0 +1,161 @@ +msngr.extend((function (external, internal) { + "use strict"; + + internal.objects = internal.objects || { }; + internal.objects.memory = function () { + + // Index for id to message objects + var id_to_message = { }; + + // Direct index (no partials) for message + var direct_index = { + topic_to_id: { }, + topic_cat_to_id: { }, + topic_type_to_id: { }, + topic_cat_type_to_id: { } + }; + + // Message index count + var index_count = 0; + + var mem = { + index: function (message) { + if (external.exist(message) && external.exist(message.topic)) { + var uuid = external.id(); + id_to_message[uuid] = message; + + if (direct_index.topic_to_id[message.topic] === undefined) { + direct_index.topic_to_id[message.topic] = []; + } + direct_index.topic_to_id[message.topic].push(uuid); + + if (external.exist(message.category)) { + if (direct_index.topic_cat_to_id[message.topic] === undefined) { + direct_index.topic_cat_to_id[message.topic] = { }; + } + + if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_to_id[message.topic][message.category] = []; + } + + direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); + } + + if (external.exist(message.dataType)) { + if (direct_index.topic_type_to_id[message.topic] === undefined) { + direct_index.topic_type_to_id[message.topic] = { }; + } + + if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { + direct_index.topic_type_to_id[message.topic][message.dataType] = []; + } + + direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); + } + + if (external.exist(message.category) && external.exist(message.dataType)) { + if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { + direct_index.topic_cat_type_to_id[message.topic] = { }; + } + + if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; + } + + if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; + } + + direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); + } + + index_count++; + + return uuid; + } + return undefined; + }, + delete: function (uuid) { + if (external.exist(uuid) && external.exist(id_to_message[uuid])) { + var message = id_to_message[uuid]; + + if (external.exist(message.topic)) { + external.removeFromArray(direct_index.topic_to_id[message.topic], uuid); + + if (external.exist(message.category)) { + external.removeFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); + } + + if (external.exist(message.dataType)) { + external.removeFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); + } + + if (external.exist(message.category) && external.exist(message.dataType)) { + external.removeFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); + } + } + + delete id_to_message[uuid]; + index_count--; + + return true; + } + return false; + }, + query: function (message) { + if (external.exist(message)) { + if (external.exist(message.topic)) { + // Topic Only Results + if (!external.exist(message.category) && !external.exist(message.dataType)) { + return direct_index.topic_to_id[message.topic] || []; + } + + // Topic + Category Results + if (external.exist(message.category) && !external.exist(message.dataType)) { + return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; + } + + // Topic + Data Type Results + if (external.exist(message.dataType) && !external.exist(message.category)) { + return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; + } + + // Topic + Category + Data Type Results + if (external.exist(message.category) && external.exist(message.dataType)) { + return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; + } + } + } + + return []; + }, + clear: function () { + // Index for id to message objects + id_to_message = { }; + + // Direct index (no partials) for message + direct_index = { + topic_to_id: { }, + topic_cat_to_id: { }, + topic_type_to_id: { }, + topic_cat_type_to_id: { } + }; + + index_count = 0; + + return true; + } + }; + + Object.defineProperty(mem, "count", { + get: function () { + return index_count; + } + }); + + return mem; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index 57878de..6c9992c 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -25,8 +25,8 @@ describe("./objects/message.js", function () { msngr.debug = false; }); - it("msngr.internal.objects.message - handles a message object as expected", function () { - var m = msngr.internal.objects.message({ topic: "MyTopic", category: "MyCategory", dataType: "MyDataType" }); + it("msngr - handles a message object as expected", function () { + var m = msngr({ topic: "MyTopic", category: "MyCategory", dataType: "MyDataType" }); expect(m).to.exist; expect(m.message).to.exist; expect(m.message.topic).to.exist; @@ -37,16 +37,16 @@ describe("./objects/message.js", function () { expect(m.message.dataType).to.equal("MyDataType"); }); - it("msngr.internal.objects.message() - converts single string into message object with a topic", function () { - var m = msngr.internal.objects.message("MyTopic"); + it("msngr() - converts single string into message object with a topic", function () { + var m = msngr("MyTopic"); expect(m).to.exist; expect(m.message).to.exist; expect(m.message.topic).to.exist; expect(m.message.topic).to.equal("MyTopic"); }); - it("msngr.internal.objects.message() - converts two strings into message object with a topic and category", function () { - var m = msngr.internal.objects.message("MyTopic", "MyCategory"); + it("msngr() - converts two strings into message object with a topic and category", function () { + var m = msngr("MyTopic", "MyCategory"); expect(m).to.exist; expect(m.message).to.exist; expect(m.message.topic).to.exist; @@ -55,8 +55,8 @@ describe("./objects/message.js", function () { expect(m.message.category).to.equal("MyCategory"); }); - it("msngr.internal.objects.message() - converts three strings into message object with a topic, category and dataType", function () { - var m = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + it("msngr() - converts three strings into message object with a topic, category and dataType", function () { + var m = msngr("MyTopic", "MyCategory", "MyDataType"); expect(m).to.exist; expect(m.message).to.exist; expect(m.message.topic).to.exist; @@ -67,12 +67,21 @@ describe("./objects/message.js", function () { expect(m.message.dataType).to.equal("MyDataType"); }); - it("msngr.internal.objects.message() - multiple copies do not share message objects", function () { - var m1 = msngr.internal.objects.message("MyTopic1"); - var m2 = msngr.internal.objects.message("MyTopic2", "MyCategory2"); - var m3 = msngr.internal.objects.message("MyTopic3", "MyCategory3", "MyDataType3"); - var m4 = msngr.internal.objects.message("MyTopic4", "MyCategory4"); - var m5 = msngr.internal.objects.message("MyTopic5"); + it("msngr.internal.handlerCount - returns the correct count of registered messages", function () { + expect(msngr.internal.handlerCount).to.exist; + expect(msngr.internal.handlerCount).to.equal(0); + msngr("MyTopic").on(function () { }); + expect(msngr.internal.handlerCount).to.equal(1); + msngr("AnotherTopic").on(function () { }); + expect(msngr.internal.handlerCount).to.equal(2); + }); + + it("msngr() - multiple copies do not share message objects", function () { + var m1 = msngr("MyTopic1"); + var m2 = msngr("MyTopic2", "MyCategory2"); + var m3 = msngr("MyTopic3", "MyCategory3", "MyDataType3"); + var m4 = msngr("MyTopic4", "MyCategory4"); + var m5 = msngr("MyTopic5"); expect(m1).to.exist; expect(m2).to.exist; @@ -90,8 +99,8 @@ describe("./objects/message.js", function () { expect(m3.message.dataType).to.not.equal(m4.message.dataType); }); - it("msngr.internal.objects.message().emit() / on() - Successfully emits and handles a topic only message", function (done) { - var msg = msngr.internal.objects.message("MyTopic"); + it("msngr().emit() / on() - Successfully emits and handles a topic only message", function (done) { + var msg = msngr("MyTopic"); msg.on(function (payload) { expect(payload).to.exist; expect(payload).to.equal("MyPayload"); @@ -101,8 +110,8 @@ describe("./objects/message.js", function () { msg.emit("MyPayload"); }); - it("msngr.internal.objects.message().emit() / on() - Successfully emits and handles a topic and category message", function (done) { - var msg = msngr.internal.objects.message("MyTopic", "MyCategory"); + it("msngr().emit() / on() - Successfully emits and handles a topic and category message", function (done) { + var msg = msngr("MyTopic", "MyCategory"); msg.on(function (payload) { expect(payload).to.exist; expect(payload).to.equal("AnotherPayload"); @@ -112,8 +121,8 @@ describe("./objects/message.js", function () { msg.emit("AnotherPayload"); }); - it("msngr.internal.objects.message().emit() / on() - Successfully emits and handles a topic, category and dataType message", function (done) { - var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + it("msngr().emit() / on() - Successfully emits and handles a topic, category and dataType message", function (done) { + var msg = msngr("MyTopic", "MyCategory", "MyDataType"); msg.on(function (payload) { expect(payload).to.exist; expect(payload).to.equal("WeePayloads!"); @@ -123,10 +132,10 @@ describe("./objects/message.js", function () { msg.emit("WeePayloads!"); }); - it("msngr.internal.objects.message().emit() / on() - Setup three handlers, both receive emit payload", function (done) { + it("msngr().emit() / on() - Setup three handlers, both receive emit payload", function (done) { var handled = 0; - var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + var msg = msngr("MyTopic", "MyCategory", "MyDataType"); msg.on(function (payload) { ++handled; expect(payload).to.exist; @@ -153,7 +162,7 @@ describe("./objects/message.js", function () { }, 250); }); - it("msngr.internal.objects.message().emit() / on() - Setup two handlers, delete one and the other still receives", function (done) { + it("msngr().emit() / on() - Setup two handlers, delete one and the other still receives", function (done) { var handled = 0; var answer = undefined; var onHandler1 = function (payload) { @@ -170,7 +179,7 @@ describe("./objects/message.js", function () { expect(payload).to.equal("TwoThenOne"); }; - var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + var msg = msngr("MyTopic", "MyCategory", "MyDataType"); msg.on(onHandler1); msg.on(onHandler2); @@ -187,10 +196,10 @@ describe("./objects/message.js", function () { }, 250); }); - it("msngr.internal.objects.message().emit() / on() - Multiple handlers, callback on emit aggregates results", function (done) { + it("msngr().emit() / on() - Multiple handlers, callback on emit aggregates results", function (done) { var handled = 0; - var msg = msngr.internal.objects.message("MyTopic", "MyCategory", "MyDataType"); + var msg = msngr("MyTopic", "MyCategory", "MyDataType"); msg.on(function (payload) { ++handled; expect(payload).to.exist; @@ -223,4 +232,24 @@ describe("./objects/message.js", function () { done(); }); }); + + it("msngr().emit() / once() - once is only called one time for handling the same message", function (done) { + var handledCount = 0; + + var msg = msngr("MyTopicTest"); + msg.once(function (payload) { + ++handledCount; + }); + + msg.emit(); + msg.emit(); + msg.emit(); + msg.emit(); + + setTimeout(function () { + expect(handledCount).to.equal(1); + done(); + }, 250); + }); + }); diff --git a/src/objects/message.cspec.js b/src/objects/message.cspec.js new file mode 100644 index 0000000..dd64365 --- /dev/null +++ b/src/objects/message.cspec.js @@ -0,0 +1,131 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../../msngr"); +} + +describe("./objects/message.js", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); + + it("msngr(topic).bind(element, event) - Binds and sends with just a topic", function (done) { + var div = document.createElement("div"); + + msngr("MyTopic").bind(div, "testEvent").on(function (payload) { + expect(payload).to.exist; + done(); + }); + + var testEvent = document.createEvent("CustomEvent"); + testEvent.initCustomEvent("testEvent", false, false, null); + div.dispatchEvent(testEvent); + }); + + it("msngr(topic, category).bind(element, event) - Binds and sends with a topic and category", function (done) { + var div = document.createElement("div"); + + msngr("MyTopic", "MyCategory").bind(div, "testEvent").on(function (payload) { + expect(payload).to.exist; + done(); + }); + + var testEvent = document.createEvent("CustomEvent"); + testEvent.initCustomEvent("testEvent", false, false, null); + div.dispatchEvent(testEvent); + }); + + it("msngr(topic, category, dataType).bind(element, event) - Binds and sends with a topic, category and dataType", function (done) { + var div = document.createElement("div"); + + msngr("MyTopic", "MyCategory", "MyDataType").bind(div, "testEvent").on(function (payload) { + expect(payload).to.exist; + done(); + }); + + var testEvent = document.createEvent("CustomEvent"); + testEvent.initCustomEvent("testEvent", false, false, null); + div.dispatchEvent(testEvent); + }); + + it("msngr(topic, category).bind(element, event) - Bind then remove doesn't emit message", function (done) { + var div = document.createElement("div"); + var flag = false; + + msngr("MyTopic", "MyCategory").bind(div, "testEvent").on(function (payload) { + flag = true; + expect(flag).to.equal(false); + done(); + }); + + var testEvent = document.createEvent("CustomEvent"); + testEvent.initCustomEvent("testEvent", false, false, null); + + msngr("MyTopic", "MyCategory").unbind(div, "testEvent"); + + div.dispatchEvent(testEvent); + + setTimeout(function () { + expect(flag).to.equal(false); + done(); + }, 250); + }); + + it("msngr(topic, category).unbind(element, event) - Unbind and ensure the message originally bound does not get sent", function (done) { + var div = document.createElement("div"); + var flag = false; + + msngr("MyTopic1", "MyCategory1").bind(div, "testEvent1").on(function () { + flag = true; + }).unbind(div, "testEvent1"); + + msngr("MyTopic2", "MyCategory2").bind(div, "testEvent2").on(function () { + flag = true; + }).unbind(div, "testEvent2"); + + var testEvent1 = document.createEvent("CustomEvent"); + testEvent1.initCustomEvent("testEven1", false, false, null); + + var testEvent2 = document.createEvent("CustomEvent"); + testEvent2.initCustomEvent("testEven1", false, false, null); + + div.dispatchEvent(testEvent1); + div.dispatchEvent(testEvent2); + + setTimeout(function () { + expect(flag).to.equal(false); + done(); + }, 250); + }); + + it("msngr.internal.boundCount - Accurately tracks the bind count", function () { + var div = document.createElement("div"); + + var start = msngr.internal.boundCount; + msngr("MyTopic1", "MyCategory1").bind(div, "testEvent1"); + msngr("MyTopic2", "MyCategory2").bind(div, "testEvent2"); + + expect(msngr.internal.boundCount).to.equal(start + 2); + + msngr("MyTopic1", "MyCategory1").unbind(div, "testEvent1"); + + expect(msngr.internal.boundCount).to.equal(start + 1); + }); + +}); diff --git a/src/objects/message.js b/src/objects/message.js index d2d03b9..f3422dc 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -8,19 +8,71 @@ msngr.extend((function (external, internal) { internal.objects = internal.objects || { }; + var messageIndex = internal.objects.memory(); + var handlers = { }; var handlerCount = 0; - Object.defineProperty(external, "handlerCount", { + var boundDOMPaths = { }; + var boundCount = 0; + + Object.defineProperty(internal, "handlerCount", { get: function () { return handlerCount; } }); + Object.defineProperty(internal, "boundCount", { + get: function () { + return boundCount; + } + }); + internal.reset = function () { handlers = { }; + boundDOMPaths = { }; handlerCount = 0; - internal.store.clear(); + boundCount = 0; + messageIndex.clear(); + }; + + internal.processOpts = function (opts, message, payload, callback) { + payload = payload || { }; + var optProcessors = []; + for (var key in opts) { + if (opts.hasOwnProperty(key) && external.exist(internal.options[key])) { + optProcessors.push(internal.options[key]); + } + } + + // Short circuit for no options + if (optProcessors.length === 0) { + return callback.apply(this, [payload]); + } + + // Long circuit to do stuff (du'h) + var execs = internal.objects.executer(optProcessors, [message, payload, opts], this); + + execs.parallel(function (results) { + var result = payload; + if (external.exist(results) && results.length > 0) { + for (var i = 0; i < results.length; ++i) { + result = external.extend(results[i], result); + } + } + callback.apply(this, [result]); + }); + }; + + internal.domListener = function (event) { + var node = this; + var path = external.getDomPath(node); + + if (external.exist(boundDOMPaths[path])) { + if (external.exist(boundDOMPaths[path][event.type])) { + return internal.objects.message(boundDOMPaths[path][event.type]).emit(event); + } + } }; internal.objects.message = function (topic, category, dataType) { @@ -52,40 +104,87 @@ msngr.extend((function (external, internal) { } } + var options = { }; + var msgObj = { + option: function (key, value) { + options[key] = value; + + return msgObj; + }, + options: function (obj) { + external.extend(obj, options); + + return msgObj; + }, emit: function (payload, callback) { - var uuids = internal.store.query(msg); + var uuids = messageIndex.query(msg); if (uuids.length > 0) { var methods = []; + var toDrop = []; for (var i = 0; i < uuids.length; ++i) { var obj = handlers[uuids[i]]; methods.push(obj.handler); + + if (obj.once === true) { + toDrop.push(obj.handler); + } } - var execs = internal.objects.executer(methods, payload, (msg.context || this)); - execs.parallel(callback); + internal.processOpts(options, msg, payload, function (result) { + var execs = internal.objects.executer(methods, result, (msg.context || this)); + + for (var i = 0; i < toDrop.length; ++i) { + msgObj.drop(toDrop[i]); + } + + execs.parallel(callback); + + }); } return msgObj; }, - persist: function (payload) { + on: function (handler) { + var uuid = messageIndex.index(msg); + handlers[uuid] = { + handler: handler, + context: (msg.context || this), + once: false + }; + handlerCount++; + return msgObj; }, - on: function (handler) { - var uuid = internal.store.index(msg); + once: function (handler) { + var uuid = messageIndex.index(msg); handlers[uuid] = { handler: handler, - context: (msg.context || this) + context: (msg.context || this), + once: true }; handlerCount++; return msgObj; }, bind: function (element, event) { + var node = external.findElement(element); + var path = external.getDomPath(node); + + if (!external.exist(boundDOMPaths[path])) { + boundDOMPaths[path] = { }; + } + + boundDOMPaths[path][event] = msg; + node.addEventListener(event, internal.domListener); + + ++boundCount; + + return msgObj; }, drop: function (handler) { - var uuids = internal.store.query(msg); + var uuids = messageIndex.query(msg); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var uuid = uuids[i]; @@ -93,7 +192,7 @@ msngr.extend((function (external, internal) { delete handlers[uuid]; handlerCount--; - internal.store.delete(uuid); + messageIndex.delete(uuid); } } } @@ -101,17 +200,30 @@ msngr.extend((function (external, internal) { return msgObj; }, unbind: function (element, event) { + var node = external.findElement(element); + var path = external.getDomPath(node); + if (external.exist(boundDOMPaths[path])) { + if (external.exist(boundDOMPaths[path][event])) { + node.removeEventListener(event, internal.domListener); + + delete boundDOMPaths[path][event]; + + --boundCount; + } + } + + return msgObj; }, dropAll: function () { - var uuids = internal.store.query(msg); + var uuids = messageIndex.query(msg); if (uuids.length > 0) { for (var i = 0; i < uuids.length; ++i) { var uuid = uuids[i]; delete handlers[uuid]; handlerCount--; - internal.store.delete(uuid); + messageIndex.delete(uuid); } } diff --git a/src/actions/dom.cspec.js b/src/options/dom.cspec.js similarity index 82% rename from src/actions/dom.cspec.js rename to src/options/dom.cspec.js index 3c5c7a9..3fb8860 100644 --- a/src/actions/dom.cspec.js +++ b/src/options/dom.cspec.js @@ -10,15 +10,22 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { var msngr = require("../../msngr"); } -describe.skip("./actions/dom.js", function () { +describe("./options/dom.js", function () { "use strict"; - beforeEach(function (done) { - msngr.dropAll(); - done(); + before(function () { + msngr.debug = true; }); - it("dom action - gathers multiple values with a selector that matches multiple elements with no IDs or names", function (done) { + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); + + it("dom option - gathers multiple values with a selector that matches multiple elements with no IDs or names", function (done) { var input1 = document.createElement("input"); input1.value = "Kris"; @@ -28,7 +35,7 @@ describe.skip("./actions/dom.js", function () { document.body.appendChild(input1); document.body.appendChild(input2); - msngr.on("TestTopic", function (payload) { + msngr("TestTopic").on(function (payload) { expect(payload).to.exist; expect(payload["input0"]).to.exist; expect(payload["input0"]).to.equal("Kris"); @@ -41,7 +48,7 @@ describe.skip("./actions/dom.js", function () { done(); }); - msngr.emit({ topic: "TestTopic", dom: ["input"] }); + msngr("TestTopic").option("dom", ["input"]).emit(); }); it("dom action - gathers multiple values with a selector that matches multiple elements", function (done) { @@ -56,7 +63,7 @@ describe.skip("./actions/dom.js", function () { document.body.appendChild(input1); document.body.appendChild(input2); - msngr.on("TestTopic", function (payload) { + msngr("TestTopic").on(function (payload) { expect(payload).to.exist; expect(payload["Name"]).to.exist; expect(payload["Name"]).to.equal("Kris"); @@ -69,7 +76,7 @@ describe.skip("./actions/dom.js", function () { done(); }); - msngr.emit({ topic: "TestTopic", dom: ["input"] }); + msngr("TestTopic").option("dom", ["input"]).emit(); }); it("dom action - gathers multiple values with multiple selectors that each match an element 1:1", function (done) { @@ -84,7 +91,7 @@ describe.skip("./actions/dom.js", function () { document.body.appendChild(input1); document.body.appendChild(input2); - msngr.on("TestTopic", function (payload) { + msngr("TestTopic").on(function (payload) { expect(payload).to.exist; expect(payload["Name"]).to.exist; expect(payload["Name"]).to.equal("Kris"); @@ -97,7 +104,7 @@ describe.skip("./actions/dom.js", function () { done(); }); - msngr.emit({ topic: "TestTopic", dom: ["input[name=Name]", "input[name=Email]"] }); + msngr("TestTopic").option("dom", ["input[name=Name]", "input[name=Email]"]).emit(); }); it("dom action - gathers multiple values with multiple IDs that each match an element 1:1", function (done) { @@ -114,7 +121,7 @@ describe.skip("./actions/dom.js", function () { document.body.appendChild(input1); document.body.appendChild(input2); - msngr.on("TestTopic", function (payload) { + msngr("TestTopic").on(function (payload) { expect(payload).to.exist; expect(payload["Name"]).to.exist; expect(payload["Name"]).to.equal("Kris"); @@ -127,6 +134,6 @@ describe.skip("./actions/dom.js", function () { done(); }); - msngr.emit({ topic: "TestTopic", dom: ["#Name", "#Email"] }); + msngr("TestTopic").option("dom", ["#Name", "#Email"]).emit(); }); }); diff --git a/src/options/dom.js b/src/options/dom.js new file mode 100644 index 0000000..a3fe054 --- /dev/null +++ b/src/options/dom.js @@ -0,0 +1,74 @@ +/* + ./options/dom.js + + The primary object of msngr; handles all message sending, receiving and binding. +*/ +msngr.extend((function (external, internal) { + "use strict"; + + internal.options = internal.options || { }; + + internal.options.dom = function (message, payload, options, async) { + // Normalize all of the inputs + options = options || { }; + options = options.dom || { }; + var doc = options.doc || options.document || document; + + var selectors = undefined; + if (external.isObject(options) && external.exist(options.selectors) && external.isString(options.selectors)) { + selectors = [options.selectors]; + } else if (external.isString(options)) { + selectors = [options]; + } else if (external.isArray(options)) { + selectors = options; + } + + if (!external.exist(doc) || !external.exist(selectors) || selectors.length === 0) { + return undefined; + } + + // Process all selectors and put them into a single array + var elements = []; + var selLength = selectors.length; + for (var i = 0; i < selLength; ++i) { + var found = external.findElements(selectors[i], doc); + if (found.length > 0) { + elements = elements.concat(Array.prototype.slice.call(found)); + } + } + + // Iterate through found elements and aggregate the results + var resultMap = undefined; + var elmLength = elements.length; + var unnamedTags = 0; + for (var i = 0; i < elmLength; ++i) { + var key = undefined, value = undefined; + var elm = elements[i]; + + var nameAttr = elm.getAttribute("name"); + var idAttr = elm.id; + var tagName = elm.tagName.toLowerCase(); + var val = elm.value; + + if (external.exist(nameAttr) && !external.isEmptyString(nameAttr)) { + key = nameAttr; + } else if (external.exist(idAttr) && !external.isEmptyString(idAttr)) { + key = idAttr; + } else { + key = (tagName + unnamedTags); + unnamedTags++; + } + + if (resultMap === undefined) { + resultMap = { }; + } + resultMap[key] = val; + } + + return resultMap; + + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); diff --git a/src/store/memory.aspec.js b/src/store/memory.aspec.js deleted file mode 100644 index e847829..0000000 --- a/src/store/memory.aspec.js +++ /dev/null @@ -1,251 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../../msngr"); -} - -describe("./stores/memory.js", function () { - "use strict"; - - before(function () { - msngr.debug = true; - }); - - after(function () { - msngr.debug = false; - }); - - beforeEach(function() { - msngr.internal.store.clear(); - }); - - it("msngr.internal.store.index(message) - indexes a message with only a topic", function () { - var message = { - topic: "TestTopic1" - }; - - expect(msngr.internal.store.count()).to.equal(0); - var id = msngr.internal.store.index(message); - expect(id).to.exist; - expect(msngr.internal.store.count()).to.equal(1); - }); - - it("msngr.internal.store.index(message) - indexes a message with a topic and category", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1" - }; - - expect(msngr.internal.store.count()).to.equal(0); - var id = msngr.internal.store.index(message); - expect(id).to.exist; - expect(msngr.internal.store.count()).to.equal(1); - }); - - it("msngr.internal.store.index(message) - indexes a message with a topic and dataType", function () { - var message = { - topic: "TestTopic1", - dataType: "TestDataType1" - }; - - expect(msngr.internal.store.count()).to.equal(0); - var id = msngr.internal.store.index(message); - expect(id).to.exist; - expect(msngr.internal.store.count()).to.equal(1); - }); - - it("msngr.internal.store.index(message) - indexes a message with a topic, category and dataType", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1", - dataType: "TestDataType1" - }; - - expect(msngr.internal.store.count()).to.equal(0); - var id = msngr.internal.store.index(message); - expect(id).to.exist; - expect(msngr.internal.store.count()).to.equal(1); - }); - - it("msngr.internal.store.index(message) - invalid message shouldn't index", function () { - var message = { - cookie: "monster" - }; - - expect(msngr.internal.store.count()).to.equal(0); - var id = msngr.internal.store.index(message); - expect(id).to.not.exist; - expect(msngr.internal.store.count()).to.equal(0); - }); - - it("msngr.internal.store.delete(uuid) - deletes a valid uuid", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1", - dataType: "TestDataType1" - }; - - var id = msngr.internal.store.index(message); - expect(id).to.exist; - - var result = msngr.internal.store.delete(id); - expect(result).to.exist; - expect(result).to.equal(true); - expect(msngr.internal.store.count()).to.equal(0); - }); - - it("msngr.internal.store.delete(uuid) - doesn't delete an invalid uuid", function () { - var result = msngr.internal.store.delete("sldfjslkfjlwrjlskdfjs"); - expect(result).to.exist; - expect(result).to.equal(false); - expect(msngr.internal.store.count()).to.equal(0); - }); - - it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic", function () { - var message = { - topic: "TestTopic1" - }; - - var id = msngr.internal.store.index(message); - expect(id).to.exist; - - var result = msngr.internal.store.query({ topic: "TestTopic1" }); - - expect(result).to.exist; - expect(result.length).to.equal(1); - }); - - it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic that doesn't exist", function () { - var result = msngr.internal.store.query({ topic: "TestTopic1" }); - - expect(result).to.exist; - expect(result.length).to.equal(0); - }); - - it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic and category", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1" - }; - - var id = msngr.internal.store.index(message); - expect(id).to.exist; - - var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1" }); - - expect(result).to.exist; - expect(result.length).to.equal(1); - }); - - it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic and category that doesn't exist", function () { - var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1" }); - - expect(result).to.exist; - expect(result.length).to.equal(0); - }); - - it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic, category and dataType", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1", - dataType: "TestDataType1" - }; - - var id = msngr.internal.store.index(message); - expect(id).to.exist; - - var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); - - expect(result).to.exist; - expect(result.length).to.equal(1); - }); - - it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType that doesn't exist", function () { - var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType1" }); - - expect(result).to.exist; - expect(result.length).to.equal(0); - }); - - it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where category doesn't exist", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1", - dataType: "TestDataType1" - }; - - var id = msngr.internal.store.index(message); - expect(id).to.exist; - - var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory2", dataType: "TestDataType1" }); - - expect(result).to.exist; - expect(result.length).to.equal(0); - }); - - it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where dataType doesn't exist", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1", - dataType: "TestDataType1" - }; - - var id = msngr.internal.store.index(message); - expect(id).to.exist; - - var result = msngr.internal.store.query({ topic: "TestTopic1", category: "TestCategory1", dataType: "TestDataType2" }); - - expect(result).to.exist; - expect(result.length).to.equal(0); - }); - - it("msngr.internal.store.query(message) - Correctly gets zero results for a query on a topic, category and dataType where topic doesn't exist", function () { - var message = { - topic: "TestTopic1", - category: "TestCategory1", - dataType: "TestDataType1" - }; - - var id = msngr.internal.store.index(message); - expect(id).to.exist; - - var result = msngr.internal.store.query({ topic: "TestTopic2", category: "TestCategory1", dataType: "TestDataType1" }); - - expect(result).to.exist; - expect(result.length).to.equal(0); - }); - - it("msngr.internal.store.clear() - Clears all indexed messages", function () { - var ids = []; - ids.push(msngr.internal.store.index({ topic: "chicken" })); - ids.push(msngr.internal.store.index({ topic: "table", category: "50" })); - ids.push(msngr.internal.store.index({ topic: "stairs", category: "10", dataType: "food" })); - ids.push(msngr.internal.store.index({ topic: "whatevea", dataType: "punk" })); - - expect(msngr.internal.store.count()).to.equal(4); - expect(msngr.internal.store.clear()).to.equal(true); - expect(msngr.internal.store.query({ topic: "chicken" }).length).to.equal(0); - expect(msngr.internal.store.query({ topic: "stairs", category: "10", dataType: "food" }).length).to.equal(0); - }); - - it("msngr.internal.store.count() - Returns a correct count", function () { - expect(msngr.internal.store.count()).to.equal(0); - msngr.internal.store.index({ topic: "chicken" }); - expect(msngr.internal.store.count()).to.equal(1); - msngr.internal.store.index({ topic: "table", category: "50" }); - expect(msngr.internal.store.count()).to.equal(2); - msngr.internal.store.index({ topic: "stairs", category: "10", dataType: "food" }); - expect(msngr.internal.store.count()).to.equal(3); - expect(msngr.internal.store.clear()).to.equal(true); - expect(msngr.internal.store.count()).to.equal(0); - msngr.internal.store.index({ topic: "whatevea", dataType: "punk" }); - expect(msngr.internal.store.count()).to.equal(1); - - }); -}); diff --git a/src/store/memory.js b/src/store/memory.js deleted file mode 100644 index c290630..0000000 --- a/src/store/memory.js +++ /dev/null @@ -1,163 +0,0 @@ -msngr.extend((function (external, internal) { - "use strict"; - - // Index for id to message objects - var id_to_message = { }; - - // Direct index (no partials) for message - var direct_index = { - topic_to_id: { }, - topic_cat_to_id: { }, - topic_type_to_id: { }, - topic_cat_type_to_id: { } - }; - - // Message index count - var index_count = 0; - - var deleteValueFromArray = function (arr, value) { - var inx = arr.indexOf(value); - var endIndex = arr.length - 1; - if (inx !== endIndex) { - var temp = arr[endIndex]; - arr[endIndex] = arr[inx]; - arr[inx] = temp; - } - arr.pop(); - }; - - internal.store = { - index: function (message) { - if (external.exist(message) && external.exist(message.topic)) { - var uuid = external.id(); - id_to_message[uuid] = message; - - if (direct_index.topic_to_id[message.topic] === undefined) { - direct_index.topic_to_id[message.topic] = []; - } - direct_index.topic_to_id[message.topic].push(uuid); - - if (external.exist(message.category)) { - if (direct_index.topic_cat_to_id[message.topic] === undefined) { - direct_index.topic_cat_to_id[message.topic] = { }; - } - - if (direct_index.topic_cat_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_to_id[message.topic][message.category] = []; - } - - direct_index.topic_cat_to_id[message.topic][message.category].push(uuid); - } - - if (external.exist(message.dataType)) { - if (direct_index.topic_type_to_id[message.topic] === undefined) { - direct_index.topic_type_to_id[message.topic] = { }; - } - - if (direct_index.topic_type_to_id[message.topic][message.dataType] === undefined) { - direct_index.topic_type_to_id[message.topic][message.dataType] = []; - } - - direct_index.topic_type_to_id[message.topic][message.dataType].push(uuid); - } - - if (external.exist(message.category) && external.exist(message.dataType)) { - if (direct_index.topic_cat_type_to_id[message.topic] === undefined) { - direct_index.topic_cat_type_to_id[message.topic] = { }; - } - - if (direct_index.topic_cat_type_to_id[message.topic][message.category] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category] = { }; - } - - if (direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] === undefined) { - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType] = []; - } - - direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType].push(uuid); - } - - index_count++; - - return uuid; - } - return undefined; - }, - delete: function (uuid) { - if (external.exist(uuid) && external.exist(id_to_message[uuid])) { - var message = id_to_message[uuid]; - - if (external.exist(message.topic)) { - deleteValueFromArray(direct_index.topic_to_id[message.topic], uuid); - - if (external.exist(message.category)) { - deleteValueFromArray(direct_index.topic_cat_to_id[message.topic][message.category], uuid); - } - - if (external.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_type_to_id[message.topic][message.dataType], uuid); - } - - if (external.exist(message.category) && external.exist(message.dataType)) { - deleteValueFromArray(direct_index.topic_cat_type_to_id[message.topic][message.category][message.dataType], uuid); - } - } - - delete id_to_message[uuid]; - index_count--; - - return true; - } - return false; - }, - query: function (message) { - if (external.exist(message)) { - if (external.exist(message.topic)) { - // Topic Only Results - if (!external.exist(message.category) && !external.exist(message.dataType)) { - return direct_index.topic_to_id[message.topic] || []; - } - - // Topic + Category Results - if (external.exist(message.category) && !external.exist(message.dataType)) { - return (direct_index.topic_cat_to_id[message.topic] || { })[message.category] || []; - } - - // Topic + Data Type Results - if (external.exist(message.dataType) && !external.exist(message.category)) { - return (direct_index.topic_type_to_id[message.topic] || { })[message.dataType] || []; - } - - // Topic + Category + Data Type Results - if (external.exist(message.category) && external.exist(message.dataType)) { - return ((direct_index.topic_cat_type_to_id[message.topic] || { })[message.category] || { })[message.dataType] || []; - } - } - } - - return []; - }, - clear: function () { - // Index for id to message objects - id_to_message = { }; - - // Direct index (no partials) for message - direct_index = { - topic_to_id: { }, - topic_cat_to_id: { }, - topic_type_to_id: { }, - topic_cat_type_to_id: { } - }; - - index_count = 0; - - return true; - }, - count: function () { - return index_count; - } - }; - - // This is an internal extension; do not export explicitly. - return { }; -})); diff --git a/src/utils/exceptional.js b/src/utils/exceptional.js index eaf0362..49204e5 100644 --- a/src/utils/exceptional.js +++ b/src/utils/exceptional.js @@ -17,6 +17,14 @@ msngr.extend((function (external, internal) { }; }; + internal.MangledException = function (variable, method) { + return { + name: "MangledException", + severity: "unrecoverable", + message: ("The {variable} was unexpectedly mangled in {method}.".replace("{variable}", variable).replace("{method}", method)) + }; + }; + // This is an internal extension; do not export explicitly. return { }; })); diff --git a/src/utils/misc.aspec.js b/src/utils/misc.aspec.js index 5b33bba..15504f7 100644 --- a/src/utils/misc.aspec.js +++ b/src/utils/misc.aspec.js @@ -71,4 +71,19 @@ describe("./utils/misc.js", function () { expect(t).to.exist; }); + + it("msngr.removeFromArray - removes a value from an array", function () { + var arr = ["something", "another", "test", "weee"]; + + expect(arr[1]).to.equal("another"); + expect(arr.length).to.equal(4); + + msngr.removeFromArray(arr, "another"); + expect(arr[1]).to.equal("weee"); + expect(arr.length).to.equal(3); + + msngr.removeFromArray(arr, "test"); + expect(arr[1]).to.equal("weee"); + expect(arr.length).to.equal(2); + }); }); diff --git a/src/utils/misc.js b/src/utils/misc.js index 587dba3..b337497 100644 --- a/src/utils/misc.js +++ b/src/utils/misc.js @@ -46,6 +46,16 @@ msngr.extend((function (external, internal) { } lastNow = now; return now; + }, + removeFromArray: function (arr, value) { + var inx = arr.indexOf(value); + var endIndex = arr.length - 1; + if (inx !== endIndex) { + var temp = arr[endIndex]; + arr[endIndex] = arr[inx]; + arr[inx] = temp; + } + arr.pop(); } }; })); From 2e71b94680ccfbb8e31ce796aef4e9d2b022a77e Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Mon, 4 May 2015 02:31:50 -0400 Subject: [PATCH 07/46] Copy pasta failure --- src/options/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options/dom.js b/src/options/dom.js index a3fe054..b4eac71 100644 --- a/src/options/dom.js +++ b/src/options/dom.js @@ -1,7 +1,7 @@ /* ./options/dom.js - The primary object of msngr; handles all message sending, receiving and binding. + The dom option; provides value gathering from supplied selectors */ msngr.extend((function (external, internal) { "use strict"; From dee1740fe6d4f752cfe0e3335c6db034524282f9 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Mon, 4 May 2015 02:36:03 -0400 Subject: [PATCH 08/46] Added short circuit --- msngr.js | 7 ++++++- msngr.min.js | 2 +- src/options/dom.js | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/msngr.js b/msngr.js index d1672db..8e8a80c 100644 --- a/msngr.js +++ b/msngr.js @@ -841,7 +841,7 @@ msngr.extend((function (external, internal) { /* ./options/dom.js - The primary object of msngr; handles all message sending, receiving and binding. + The dom option; provides value gathering from supplied selectors */ msngr.extend((function (external, internal) { "use strict"; @@ -877,6 +877,11 @@ msngr.extend((function (external, internal) { } } + // Short circuit because no elements + if (elements.length === 0) { + return undefined; + } + // Iterate through found elements and aggregate the results var resultMap = undefined; var elmLength = elements.length; diff --git a/msngr.min.js b/msngr.min.js index 37a0644..a162a84 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/src/options/dom.js b/src/options/dom.js index b4eac71..7f794f8 100644 --- a/src/options/dom.js +++ b/src/options/dom.js @@ -37,6 +37,11 @@ msngr.extend((function (external, internal) { } } + // Short circuit because no elements + if (elements.length === 0) { + return undefined; + } + // Iterate through found elements and aggregate the results var resultMap = undefined; var elmLength = elements.length; From f07ad3d3c15b7574faea7a6fdc6b37991d89a7a2 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Mon, 4 May 2015 02:37:21 -0400 Subject: [PATCH 09/46] Update chai dev dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2471007..aef5d75 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "mocha": "2.2.4", "grunt-mocha-phantomjs": "0.6.1", "grunt-available-tasks": "0.5.7", - "chai": "2.2.0" + "chai": "2.3.0" }, "scripts": { "test": "grunt test" From 014eae3152564ffa38ce5d2431120e5ba0530361 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Mon, 4 May 2015 03:06:18 -0400 Subject: [PATCH 10/46] Documentation templates; initial rewrite in README. --- README.md | 170 ++++------------------------------ docs/binding and the dom.md | 1 + docs/extending and hacking.md | 1 + docs/messaging patterns.md | 1 + 4 files changed, 23 insertions(+), 150 deletions(-) create mode 100644 docs/binding and the dom.md create mode 100644 docs/extending and hacking.md create mode 100644 docs/messaging patterns.md diff --git a/README.md b/README.md index 8724f83..9073c84 100644 --- a/README.md +++ b/README.md @@ -1,165 +1,35 @@ # msngr.js [![npm version](https://badge.fury.io/js/msngr.svg)](http://badge.fury.io/js/msngr) [![Bower version](https://badge.fury.io/bo/msngr.js.svg)](http://badge.fury.io/bo/msngr.js) [![Build Status](https://travis-ci.org/KrisSiegel/msngr.js.svg)](https://travis-ci.org/KrisSiegel/msngr.js/) [![Dependency Status](https://gemnasium.com/KrisSiegel/msngr.js.svg)](https://gemnasium.com/KrisSiegel/msngr.js) -msngr.js is a small library to manage messages between components with the goal of isolating business logic from a user interface or server framework. For example messages can be bound directly to DOM elements and activities can gather values allowing the handling of click events to know absolutely zero about the user interface itself. +## What is msngr.js? +msngr.js is a small library for facilitating communication between components through messages. Messages can be sent and received between any JavaScript code within the browser or node. Messages can also be bound to DOM elements and their specific events to allow for loose coupling of the user interface to your application logic. -What does that mean, exactly? Read on. Want to just jump right in? Check out [this jsfiddle](http://jsfiddle.net/jnjaosfz/) page with msngr.js already included with a "Hello, World!" example. - -## Quick Start -Installation can occur via bower or npm (alternatively just download msngr.js or msngr.min.js). - -```batch -bower install msngr.js -``` - -```batch -npm install msngr -``` - -Once installed simply include it into your project. -```html - -``` - -```javascript -var msngr = require("msngr"); -``` - -Now you're ready to start messaging! - -### Binding messages to DOM elements -One of the most handy things msngr.js can do is bind a message directly to a DOM element. Let's look at the following example. - -index.html -```html - -
- -
- -``` - -userinterface.js -```javascript -msngr.bind("input[type=submit]", "click", "Profile", "Save"); -``` - -business.js -```javascript -msngr.on("Profile", "Save", function () { - console.log("The profile has been saved!"); -}); -``` - -As you can see ```msngr.bind()``` can accept typical selectors, an event and then a message which can be made up of a topic, category and dataType (omit the ones you do not want to use). - -So this is cool, the UI and the frontend can be separated, right? Well how do you get those name and email values? Put DOM accessing code in business.js? Heck no! You can use the DOM activity to specify what values should be grabbed. - -index.html -```html - -
- -
- -``` - -userinterface.js -```javascript -msngr.bind("input[type=submit]", "click", { - topic: "Profile", - category: "Save", - dom: ["input[name=Name]", "input[name=Email]"]} -); -``` - -business.js -```javascript -msngr.on("Profile", "Save", function (payload) { - console.log(payload.Name); - console.log(payload.Email); -}); -``` - -Now the payload will include an object with the values of each input specified. You can even simplify the selector even more to get the same data back like so: - -```javascript -msngr.bind("input[type=submit]", "click", { - topic: "Profile", - category: "Save", - dom: ["input"] -}); -``` - -Aggregated values are always stored with their name as the key. If the name doesn't exist then it uses an id. Should an id not exist then it defaults to tagname + count (so "input0", "input1"); - -### What about JavaScript that doesn't touch the DOM? -So msngr.js can also be used outside of situations that involve the DOM and be just as handy! A common example is abstracting away a specific library through the use of messages. An example is outlined below. - -elasticsearch.js -```javascript -msngr.on("Profile", "Save", "application/json", function (payload) { - // Save profile object into ElasticSearch -}); +The following example shows how to bind a message to a click event of a DOM element while gathering up the values in the related inputs for payload delivery. +```HTML + + + ``` -business.js ```javascript -msngr.emit("Profile", "Save", "application/json", profile); +msngr("User", "Save") + .bind("button", "click") + .option("dom", ["input"]) + .on(function (payload) { + console.log(payload.Username); // Prints "Kris" + console.log(payload.Password); // Prints "hunter2" + }); ``` -So in the example above we can save a Profile object without actually knowing who or what is going to save this. This let's us to, later on, use a configuration to allow alternative data stores such as a Mock store without changing the business.js file. So that may look like: - -mock.js -```javascript -msngr.on("Profile", "Save", "application/json", function (payload) { - // Save profile object into a mock data store -}); -``` - -### So what are activities anyway? -An activity is simply a registered method, executed synchronously, designed to be called before payload delivery should any properties within the message object match the registered method's property. - -For example the built-in DOM activity is registered with the 'dom' property. Therefore anytime someone emits a message with the 'dom' property the registered method is called before being delivered. This allows extending msngr.js in various ways without changing any method signatures. - -For instance if you want to create an activity that added two numbers together. - -```javascript -msngr.action("add", function (message, wrap) { - wrap.payload.result = wrap.payload.number1 + wrap.payload.number2; -}); - -msngr.on("Addition", function (payload) { - console.log(payload.result); // Outputs 7 -}); - -msngr.emit({ topic: "Addition", add: { } }, { number1: 5, number2: 2 }); -``` - -Note that what is typically supplied to the action's property in the message object is any related options the particular action may need. In this add example nothing was necessary so an empty object was passed in but for others, such as the dom action, you would pass in an array of html selectors. - -## API -Below are the methods exposed via the msngr object, their parameters and return values. - -#### msngr.on(message, function) / msngr.on(topic, category, dataType, function) -This method accepts a JavaScript object with the properties "topic", "category" and "dataType" or simply fill in the first 3 parameters with those values. The function is a callback that's executed when a matching message is received and provides a payload parameter. - -#### msngr.emit(message, payload) / msngr.emit(topic, category, dataType, payload) -This method sends a message by either providing a JavaScript object with the properties "topic", "category" and "dataType" or by simply entering each values as a parameter. The payload can be anything you want to send to a receiving callback. - -#### msngr.drop(message, handler) / msngr.drop(topic, category, dataType, handler) -This method removes a message from being executed. Specify the handler to remove or drop all handlers by specifying undefined. +## Would you like to know more? +While msngr.js isn't very large the documentation has been split up for easy reading. -#### msngr.bind(element, event, message) / msngr.bind(element, event, topic, category, dataType) -This method takes an HTML element (can be an element or selector), an event and a message then binds all 3 together. When the specified event occurs on the element the message will be emitted. Optionally add the 'dom' property to the message object to supply selectors you wish msngr would gather values from and return in the payload. +[Messaging patterns](docs/messaging patterns.md) - Explains how to use the basic messaging features of msngr.js with some typical patterns. -#### msngr.unbind(element, event) / msngr.unbind(element, event) -This method stops an element's event from emitting a previously bound message. +[Binding and the DOM](docs/binding and the dom.md) - This covers binding msngr.js to elements and events, unbinding them and how to gather up values from various types of elements. -#### msngr.action(property, function) -This method provides a way of extending msngr. The property is anything (except for 'topic', 'category' or 'dataType') that is supplied within a message object. If a message is emitted with a matching property the function is called with the message and an object that allows stopping the emitting entirely (via calling ```obj.preventDefault()```) or modifying the payload itself. +[Extending and hacking](docs/extending and hacking.md) - Want to extend the capabilities of msngr.js? It's actually quite easy and this document covers it. Using msngr.js deep in a production system then suddenly find *something* that you need to change to avoid catastrophe? Hacking msngr.js is also covered for those times when you need *unorthodox* solutions :) -#### msngr.inaction(property) -This method removes the action being called on a property. +Follow me [@KrisSiegel](https://twitter.com/KrisSiegel) Copyright © 2014-2015 Kris Siegel diff --git a/docs/binding and the dom.md b/docs/binding and the dom.md new file mode 100644 index 0000000..fae3db4 --- /dev/null +++ b/docs/binding and the dom.md @@ -0,0 +1 @@ +# Binding and the DOM diff --git a/docs/extending and hacking.md b/docs/extending and hacking.md new file mode 100644 index 0000000..193bafd --- /dev/null +++ b/docs/extending and hacking.md @@ -0,0 +1 @@ +# Extending and hacking diff --git a/docs/messaging patterns.md b/docs/messaging patterns.md new file mode 100644 index 0000000..6e182f1 --- /dev/null +++ b/docs/messaging patterns.md @@ -0,0 +1 @@ +# Messaging patterns From dc7ddf164482cd27888f4e84f18f21c7c6f3ffe8 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Mon, 4 May 2015 03:10:07 -0400 Subject: [PATCH 11/46] Documentation tweaks --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9073c84..77ec209 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![npm version](https://badge.fury.io/js/msngr.svg)](http://badge.fury.io/js/msngr) [![Bower version](https://badge.fury.io/bo/msngr.js.svg)](http://badge.fury.io/bo/msngr.js) [![Build Status](https://travis-ci.org/KrisSiegel/msngr.js.svg)](https://travis-ci.org/KrisSiegel/msngr.js/) [![Dependency Status](https://gemnasium.com/KrisSiegel/msngr.js.svg)](https://gemnasium.com/KrisSiegel/msngr.js) ## What is msngr.js? -msngr.js is a small library for facilitating communication between components through messages. Messages can be sent and received between any JavaScript code within the browser or node. Messages can also be bound to DOM elements and their specific events to allow for loose coupling of the user interface to your application logic. +msngr.js is a small library for facilitating communication between components through messages. Messages can be sent and received between any JavaScript code within the browser or server-side with node or io.js. Messages can also be bound to DOM elements and their specific events to allow for loose coupling of the user interface to your application logic. The following example shows how to bind a message to a click event of a DOM element while gathering up the values in the related inputs for payload delivery. ```HTML @@ -30,6 +30,6 @@ While msngr.js isn't very large the documentation has been split up for easy rea [Extending and hacking](docs/extending and hacking.md) - Want to extend the capabilities of msngr.js? It's actually quite easy and this document covers it. Using msngr.js deep in a production system then suddenly find *something* that you need to change to avoid catastrophe? Hacking msngr.js is also covered for those times when you need *unorthodox* solutions :) -Follow me [@KrisSiegel](https://twitter.com/KrisSiegel) +For questions, news, and whatever else that doesn't fit in GitHub issues you can follow me [@KrisSiegel](https://twitter.com/KrisSiegel) Copyright © 2014-2015 Kris Siegel From 28b2915a831c40430470dab38a9c39ae26bb9bdc Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 10 May 2015 01:10:02 -0400 Subject: [PATCH 12/46] Added support for testing files in directories other than ./src/ Added unit test for the README.md file to test all examples within the file (ensure correctness) Fixed bug where options were not being handled properly in binding situations (now cache msngr object versus raw msg object) Renaming wrongly named unit tests for memory object Added persist and cease methods to msngr object and appropriate unit tests --- Gruntfile.js | 23 +++++---- README.cspec.js | 62 +++++++++++++++++++++++++ msngr.js | 90 ++++++++++++++++++++++++++---------- msngr.min.js | 2 +- specRunner.min.html | 4 +- src/objects/memory.aspec.js | 16 +++---- src/objects/message.aspec.js | 33 ++++++++++++- src/objects/message.js | 90 ++++++++++++++++++++++++++---------- 8 files changed, 252 insertions(+), 68 deletions(-) create mode 100644 README.cspec.js diff --git a/Gruntfile.js b/Gruntfile.js index e68624d..1914eb6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -122,17 +122,22 @@ module.exports = (function (grunt) { }; var fs = require("fs"); var path = require("path"); - var tests = []; - var dirs = fs.readdirSync("./src/"); - for (var i = 0; i < dirs.length; ++i) { - if (fs.statSync("./src/" + dirs[i]).isDirectory()) { - var files = fs.readdirSync("./src/" + dirs[i]); - for (var j = 0; j < files.length; ++j) { - tests.push(path.join("./", "./src/", dirs[i], files[j])); + var tests = []; + var testPaths = ["./", "./src/", "./docs/"]; + + for (var k = 0; k < testPaths.length; ++k) { + var dirs = fs.readdirSync(testPaths[k]); + + for (var i = 0; i < dirs.length; ++i) { + if (fs.statSync(testPaths[k] + dirs[i]).isDirectory()) { + var files = fs.readdirSync(testPaths[k] + dirs[i]); + for (var j = 0; j < files.length; ++j) { + tests.push(path.join("./", testPaths[k], dirs[i], files[j])); + } + } else { + tests.push(path.join("./", testPaths[k], dirs[i])); } - } else { - tests.push(path.join("./", "./src/", dirs[i])); } } diff --git a/README.cspec.js b/README.cspec.js new file mode 100644 index 0000000..1296465 --- /dev/null +++ b/README.cspec.js @@ -0,0 +1,62 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../../msngr"); +} + +describe("./README.md", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); + + it("Example 1 of DOM binding", function (done) { + var userInput = document.createElement("input"); + userInput.setAttribute("name", "Username"); + userInput.value = "Kris"; + + var passwordInput = document.createElement("input"); + passwordInput.setAttribute("name", "Password"); + passwordInput.value = "hunter2"; + + var button = document.createElement("button"); + button.appendChild(document.createTextNode("Submit")); + + document.body.appendChild(userInput); + document.body.appendChild(passwordInput); + document.body.appendChild(button); + + msngr("User", "Save") + .bind("button", "click") + .option("dom", ["input"]) + .on(function (payload) { + expect(payload.Username).to.equal("Kris"); + expect(payload.Password).to.equal("hunter2"); + + document.body.removeChild(userInput); + document.body.removeChild(passwordInput); + document.body.removeChild(button); + + done(); + }); + + var me = document.createEvent("MouseEvents"); + me.initEvent("click", true, false); + button.dispatchEvent(me); + }); +}); diff --git a/msngr.js b/msngr.js index 8e8a80c..4d85dfb 100644 --- a/msngr.js +++ b/msngr.js @@ -603,10 +603,14 @@ msngr.extend((function (external, internal) { internal.objects = internal.objects || { }; var messageIndex = internal.objects.memory(); + var payloadIndex = internal.objects.memory(); var handlers = { }; var handlerCount = 0; + var payloads = { }; + var payloadCount = 0; + var boundDOMPaths = { }; var boundCount = 0; @@ -622,12 +626,21 @@ msngr.extend((function (external, internal) { } }); + Object.defineProperty(internal, "payloadCount", { + get: function () { + return payloadCount; + } + }); + internal.reset = function () { handlers = { }; boundDOMPaths = { }; handlerCount = 0; boundCount = 0; messageIndex.clear(); + payloadIndex.clear(); + payloads = { }; + payloadCount = 0; }; internal.processOpts = function (opts, message, payload, callback) { @@ -664,7 +677,7 @@ msngr.extend((function (external, internal) { if (external.exist(boundDOMPaths[path])) { if (external.exist(boundDOMPaths[path][event.type])) { - return internal.objects.message(boundDOMPaths[path][event.type]).emit(event); + return boundDOMPaths[path][event.type].emit(); } } }; @@ -700,41 +713,64 @@ msngr.extend((function (external, internal) { var options = { }; + var explicitEmit = function (payload, uuids, callback) { + var uuids = uuids || messageIndex.query(msg); + if (uuids.length > 0) { + var methods = []; + var toDrop = []; + for (var i = 0; i < uuids.length; ++i) { + var obj = handlers[uuids[i]]; + methods.push(obj.handler); + + if (obj.once === true) { + toDrop.push(obj.handler); + } + } + + internal.processOpts(options, msg, payload, function (result) { + var execs = internal.objects.executer(methods, result, (msg.context || this)); + + for (var i = 0; i < toDrop.length; ++i) { + msgObj.drop(toDrop[i]); + } + + execs.parallel(callback); + + }); + } + }; + var msgObj = { option: function (key, value) { options[key] = value; return msgObj; }, - options: function (obj) { - external.extend(obj, options); + emit: function (payload, callback) { + explicitEmit(payload, undefined, callback); return msgObj; }, - emit: function (payload, callback) { - var uuids = messageIndex.query(msg); + persist: function (payload) { + var uuids = payloadIndex.query(msg); + var uuid; if (uuids.length > 0) { - var methods = []; - var toDrop = []; - for (var i = 0; i < uuids.length; ++i) { - var obj = handlers[uuids[i]]; - methods.push(obj.handler); - - if (obj.once === true) { - toDrop.push(obj.handler); - } - } - - internal.processOpts(options, msg, payload, function (result) { - var execs = internal.objects.executer(methods, result, (msg.context || this)); + uuid = uuids[0]; + } else { + uuid = payloadIndex.index(msg); + } - for (var i = 0; i < toDrop.length; ++i) { - msgObj.drop(toDrop[i]); - } + payloads[uuid] = payload; + ++payloadCount; - execs.parallel(callback); + return msgObj.emit(payload); + }, + cease: function () { + var uuids = payloadIndex.query(msg); - }); + for (var i = 0; i < uuids.length; ++i) { + delete payloads[uuids[i]]; + --payloadCount; } return msgObj; @@ -748,6 +784,12 @@ msngr.extend((function (external, internal) { }; handlerCount++; + var payloadId = payloadIndex.query(msg); + var payload = payloads[payloadId]; + if (external.exist(payload)) { + explicitEmit(payload, [uuid], undefined); + } + return msgObj; }, once: function (handler) { @@ -769,7 +811,7 @@ msngr.extend((function (external, internal) { boundDOMPaths[path] = { }; } - boundDOMPaths[path][event] = msg; + boundDOMPaths[path][event] = msgObj; node.addEventListener(event, internal.domListener); diff --git a/msngr.min.js b/msngr.min.js index a162a84..0ec6b75 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0?uuids[0]:payloadIndex.index(msg),payloads[uuid]=payload,++payloadCount,msgObj.emit(payload)},cease:function(){for(var uuids=payloadIndex.query(msg),i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/specRunner.min.html b/specRunner.min.html index 2256f6d..51a99ec 100644 --- a/specRunner.min.html +++ b/specRunner.min.html @@ -11,7 +11,9 @@ - + + + diff --git a/src/objects/memory.aspec.js b/src/objects/memory.aspec.js index 8b43be2..a9289b2 100644 --- a/src/objects/memory.aspec.js +++ b/src/objects/memory.aspec.js @@ -21,7 +21,7 @@ describe("./objects/memory.js", function () { msngr.debug = false; }); - it("memory.index(message) - indexes a message with only a topic", function () { + it("msngr.internal.store.index(message) - indexes a message with only a topic", function () { var memory = msngr.internal.objects.memory(); var message = { @@ -34,7 +34,7 @@ describe("./objects/memory.js", function () { expect(memory.count).to.equal(1); }); - it("memory.index(message) - indexes a message with a topic and category", function () { + it("msngr.internal.store.index(message) - indexes a message with a topic and category", function () { var memory = msngr.internal.objects.memory(); var message = { @@ -48,7 +48,7 @@ describe("./objects/memory.js", function () { expect(memory.count).to.equal(1); }); - it("memory.index(message) - indexes a message with a topic and dataType", function () { + it("msngr.internal.store.index(message) - indexes a message with a topic and dataType", function () { var memory = msngr.internal.objects.memory(); var message = { @@ -62,7 +62,7 @@ describe("./objects/memory.js", function () { expect(memory.count).to.equal(1); }); - it("memory.index(message) - indexes a message with a topic, category and dataType", function () { + it("msngr.internal.store.index(message) - indexes a message with a topic, category and dataType", function () { var memory = msngr.internal.objects.memory(); var message = { @@ -77,7 +77,7 @@ describe("./objects/memory.js", function () { expect(memory.count).to.equal(1); }); - it("memory.index(message) - invalid message shouldn't index", function () { + it("msngr.internal.store.index(message) - invalid message shouldn't index", function () { var memory = msngr.internal.objects.memory(); var message = { @@ -90,7 +90,7 @@ describe("./objects/memory.js", function () { expect(memory.count).to.equal(0); }); - it("memory.delete(uuid) - deletes a valid uuid", function () { + it("msngr.internal.store.delete(uuid) - deletes a valid uuid", function () { var memory = msngr.internal.objects.memory(); var message = { @@ -108,7 +108,7 @@ describe("./objects/memory.js", function () { expect(memory.count).to.equal(0); }); - it("memory.delete(uuid) - doesn't delete an invalid uuid", function () { + it("msngr.internal.store.delete(uuid) - doesn't delete an invalid uuid", function () { var memory = msngr.internal.objects.memory(); var result = memory.delete("sldfjslkfjlwrjlskdfjs"); @@ -117,7 +117,7 @@ describe("./objects/memory.js", function () { expect(memory.count).to.equal(0); }); - it("memory.query(message) - Correctly gets one result for a query on a topic", function () { + it("msngr.internal.store.query(message) - Correctly gets one result for a query on a topic", function () { var memory = msngr.internal.objects.memory(); var message = { diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index 6c9992c..400376c 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -251,5 +251,36 @@ describe("./objects/message.js", function () { done(); }, 250); }); - + + it("msngr().persist().on() - persist stores and re-emits data with new on registrations", function (done) { + var handledCount = 0; + + var msg = msngr("AnotherTopic"); + msg.persist("PayloadTwo"); + msg.on(function (payload) { + ++handledCount; + expect(payload).to.exist; + expect(payload).to.equal("PayloadTwo"); + expect(handledCount).to.equal(1); + done(); + }); + msg.cease(); + }); + + it("msngr().on().persist() - registers handler then receives persisted payload", function (done) { + var handledCount = 0; + + var msg = msngr("MyTestingTopic"); + msg.on(function (payload) { + ++handledCount; + expect(payload).to.exist; + expect(payload).to.equal("MyPayload"); + expect(handledCount).to.equal(1); + done(); + }); + msg.persist("MyPayload"); + msg.cease(); + + }); + }); diff --git a/src/objects/message.js b/src/objects/message.js index f3422dc..b1e1cda 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -9,10 +9,14 @@ msngr.extend((function (external, internal) { internal.objects = internal.objects || { }; var messageIndex = internal.objects.memory(); + var payloadIndex = internal.objects.memory(); var handlers = { }; var handlerCount = 0; + var payloads = { }; + var payloadCount = 0; + var boundDOMPaths = { }; var boundCount = 0; @@ -28,12 +32,21 @@ msngr.extend((function (external, internal) { } }); + Object.defineProperty(internal, "payloadCount", { + get: function () { + return payloadCount; + } + }); + internal.reset = function () { handlers = { }; boundDOMPaths = { }; handlerCount = 0; boundCount = 0; messageIndex.clear(); + payloadIndex.clear(); + payloads = { }; + payloadCount = 0; }; internal.processOpts = function (opts, message, payload, callback) { @@ -70,7 +83,7 @@ msngr.extend((function (external, internal) { if (external.exist(boundDOMPaths[path])) { if (external.exist(boundDOMPaths[path][event.type])) { - return internal.objects.message(boundDOMPaths[path][event.type]).emit(event); + return boundDOMPaths[path][event.type].emit(); } } }; @@ -106,41 +119,64 @@ msngr.extend((function (external, internal) { var options = { }; + var explicitEmit = function (payload, uuids, callback) { + var uuids = uuids || messageIndex.query(msg); + if (uuids.length > 0) { + var methods = []; + var toDrop = []; + for (var i = 0; i < uuids.length; ++i) { + var obj = handlers[uuids[i]]; + methods.push(obj.handler); + + if (obj.once === true) { + toDrop.push(obj.handler); + } + } + + internal.processOpts(options, msg, payload, function (result) { + var execs = internal.objects.executer(methods, result, (msg.context || this)); + + for (var i = 0; i < toDrop.length; ++i) { + msgObj.drop(toDrop[i]); + } + + execs.parallel(callback); + + }); + } + }; + var msgObj = { option: function (key, value) { options[key] = value; return msgObj; }, - options: function (obj) { - external.extend(obj, options); + emit: function (payload, callback) { + explicitEmit(payload, undefined, callback); return msgObj; }, - emit: function (payload, callback) { - var uuids = messageIndex.query(msg); + persist: function (payload) { + var uuids = payloadIndex.query(msg); + var uuid; if (uuids.length > 0) { - var methods = []; - var toDrop = []; - for (var i = 0; i < uuids.length; ++i) { - var obj = handlers[uuids[i]]; - methods.push(obj.handler); - - if (obj.once === true) { - toDrop.push(obj.handler); - } - } - - internal.processOpts(options, msg, payload, function (result) { - var execs = internal.objects.executer(methods, result, (msg.context || this)); + uuid = uuids[0]; + } else { + uuid = payloadIndex.index(msg); + } - for (var i = 0; i < toDrop.length; ++i) { - msgObj.drop(toDrop[i]); - } + payloads[uuid] = payload; + ++payloadCount; - execs.parallel(callback); + return msgObj.emit(payload); + }, + cease: function () { + var uuids = payloadIndex.query(msg); - }); + for (var i = 0; i < uuids.length; ++i) { + delete payloads[uuids[i]]; + --payloadCount; } return msgObj; @@ -154,6 +190,12 @@ msngr.extend((function (external, internal) { }; handlerCount++; + var payloadId = payloadIndex.query(msg); + var payload = payloads[payloadId]; + if (external.exist(payload)) { + explicitEmit(payload, [uuid], undefined); + } + return msgObj; }, once: function (handler) { @@ -175,7 +217,7 @@ msngr.extend((function (external, internal) { boundDOMPaths[path] = { }; } - boundDOMPaths[path][event] = msg; + boundDOMPaths[path][event] = msgObj; node.addEventListener(event, internal.domListener); From 99e620c51f1c8532c520af1073751a9e71bd1bca Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 10 May 2015 01:12:00 -0400 Subject: [PATCH 13/46] Added unit test to cover cease correctly --- src/objects/message.aspec.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index 400376c..d52e8d3 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -283,4 +283,21 @@ describe("./objects/message.js", function () { }); + it("msngr().persist().cease().on() - registers a payload, unregisters a payload then registers a handler", function (done) { + var handledCount = 0; + + var msg = msngr("MyTestingTopic"); + msg.persist("MyPayload"); + msg.cease(); + msg.on(function (payload) { + ++handledCount; + }); + + setTimeout(function () { + expect(handledCount).to.equal(0); + done(); + }, 250); + + }); + }); From d555a0cdf2f85265c9107ec662e3c86f277b592b Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 02:23:46 -0400 Subject: [PATCH 14/46] Fixed duplication of certain tests for phantomjs --- Gruntfile.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 1914eb6..d598b59 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -133,15 +133,22 @@ module.exports = (function (grunt) { if (fs.statSync(testPaths[k] + dirs[i]).isDirectory()) { var files = fs.readdirSync(testPaths[k] + dirs[i]); for (var j = 0; j < files.length; ++j) { - tests.push(path.join("./", testPaths[k], dirs[i], files[j])); + var p = path.join("./", testPaths[k], dirs[i], files[j]); + if (tests.indexOf(p) === -1) { + tests.push(p); + } } } else { - tests.push(path.join("./", testPaths[k], dirs[i])); + var p = path.join("./", testPaths[k], dirs[i]); + if (tests.indexOf(p) === -1) { + tests.push(p); + } } } } var scriptHtml = ""; + if (tests !== undefined && tests.length > 0) { var file = tests.shift(); while (tests.length > 0) { From c9b48ab9c3ce41757f9ba9c870bf4831a6682b7e Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 02:24:02 -0400 Subject: [PATCH 15/46] Added a warning property to disable warnings --- src/main.aspec.js | 10 +++++++++- src/main.js | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/main.aspec.js b/src/main.aspec.js index 2d4fdc1..30b1a2f 100644 --- a/src/main.aspec.js +++ b/src/main.aspec.js @@ -96,7 +96,7 @@ describe("./main.js", function () { it("msngr.extend(undefined, target) - extending undefined value is simply ignored", function () { var myTest = { }; msngr.extend(undefined, myTest); - + expect(myTest).to.exist; expect(Object.keys(myTest).length).to.equal(0); }); @@ -104,9 +104,17 @@ describe("./main.js", function () { it("msngr.debug - property setting exports internal object for testing and debugging", function () { msngr.debug = false; expect(msngr.internal).to.not.exist; + expect(msngr.debug).to.equal(false); msngr.debug = true; expect(msngr.internal).to.exist; + expect(msngr.debug).to.equal(true); msngr.debug = false; expect(msngr.internal).to.not.exist; }); + + it("msngr.warnings - can set the property to true or false", function () { + expect(msngr.warnings).to.equal(true); + msngr.warnings = false; + expect(msngr.warnings).to.equal(false); + }); }); diff --git a/src/main.js b/src/main.js index a256b3a..ea52cee 100644 --- a/src/main.js +++ b/src/main.js @@ -7,7 +7,10 @@ var msngr = msngr || (function () { "use strict"; - var internal = { }; + var internal = { + warnings: true + }; + var external = function (topic, category, dataType) { return internal.objects.message(topic, category, dataType); }; @@ -48,6 +51,19 @@ var msngr = msngr || (function () { } else if (value === false) { delete external.internal; } + }, + get: function () { + return (external.internal !== undefined) + } + }); + + // This governs warning messages that some methods may spit into the console when warranted (du'h). + Object.defineProperty(external, "warnings", { + set: function (value) { + internal.warnings = value; + }, + get: function () { + return internal.warnings; } }); From b5e954bafd8ec1b171e899d534b09474784f42f9 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 03:28:47 -0400 Subject: [PATCH 16/46] Add ability to merge strings with extend() (merging a string into an object is awkward however so...just STRINGIFY for now, lol) --- src/main.aspec.js | 8 ++++++++ src/main.js | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/main.aspec.js b/src/main.aspec.js index 30b1a2f..4bcbca2 100644 --- a/src/main.aspec.js +++ b/src/main.aspec.js @@ -101,6 +101,14 @@ describe("./main.js", function () { expect(Object.keys(myTest).length).to.equal(0); }); + it("msngr.extend(string1, string2) - Property extends a string with another string", function () { + var t = "something"; + var result = msngr.extend("whatever", t); + expect(result).to.exist; + expect(msngr.getType(result)).to.equal("[object String]"); + expect(result).to.equal("somethingwhatever"); + }); + it("msngr.debug - property setting exports internal object for testing and debugging", function () { msngr.debug = false; expect(msngr.internal).to.not.exist; diff --git a/src/main.js b/src/main.js index ea52cee..0334993 100644 --- a/src/main.js +++ b/src/main.js @@ -23,6 +23,16 @@ var msngr = msngr || (function () { obj = obj.apply(this, [external, internal]); } + if (Object.prototype.toString.call(obj) === "[object String]") { + if (Object.prototype.toString.call(target) === "[object String]") { + // Simple string concat operation + target = target + obj; + } else { + // Hmm what's the right move here? STRINGIFY! + target = JSON.stringify(target) + obj; + } + } + if (Object.prototype.toString.call(obj) === "[object Object]") { for (var key in obj) { if (obj.hasOwnProperty(key)) { From 433326e672ec22f2a30560a6cbf4f1b59cbeadff Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 03:29:32 -0400 Subject: [PATCH 17/46] Add internal method call counting on success Revising payloads to merge allowing multiple payloads per message Add payload capability to once --- src/objects/message.aspec.js | 48 ++++++++++++++++++++++++ src/objects/message.js | 72 ++++++++++++++++++++++++++++++++---- 2 files changed, 112 insertions(+), 8 deletions(-) diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index d52e8d3..696cf1c 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -283,6 +283,22 @@ describe("./objects/message.js", function () { }); + it("msngr().once().persist() - registers handler then receives persisted payload", function (done) { + var handledCount = 0; + + var msg = msngr("MyTestingTopic"); + msg.once(function (payload) { + ++handledCount; + expect(payload).to.exist; + expect(payload).to.equal("MyPayload"); + expect(handledCount).to.equal(1); + done(); + }); + msg.persist("MyPayload"); + msg.cease(); + + }); + it("msngr().persist().cease().on() - registers a payload, unregisters a payload then registers a handler", function (done) { var handledCount = 0; @@ -300,4 +316,36 @@ describe("./objects/message.js", function () { }); + it("msngr().persist() - complex merging of persisted objects for ultimate ready status", function (done) { + var msg = msngr("MyCoolTopic", "MyCat"); + var d = false; + msg.on(function (payload) { + // Check to make sure ready state is across the board + expect(payload).to.exist; + if (payload.ready1 === true && payload.ready2 === true && payload.ready3 === true && payload.ready4 === true && d === false) { + // All statuses have come in ready! + d = true; + done(); + } + }); + + msg.persist({ ready1: true }); + msg.persist({ ready2: true }); + msg.persist({ ready3: true }); + msg.persist({ ready4: true }); + }); + + it("msngr().counts - when debug mode is enabled returns a counts object otherwise is undefined", function () { + msngr.debug = true; + var msg = msngr("test"); + expect(msg.counts).to.exist; + expect(msg.counts.emits).to.equal(0); + msg.emit(); + expect(msg.counts.emits).to.equal(1); + + msngr.debug = false; + var msg2 = msngr("another"); + expect(msg2.counts).to.not.exist; + }); + }); diff --git a/src/objects/message.js b/src/objects/message.js index b1e1cda..e4b5f42 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -119,6 +119,15 @@ msngr.extend((function (external, internal) { var options = { }; + var counts = { + emits: 0, + persists: 0, + options: 0, + ons: 0, + onces: 0, + binds: 0 + }; + var explicitEmit = function (payload, uuids, callback) { var uuids = uuids || messageIndex.query(msg); if (uuids.length > 0) { @@ -146,30 +155,58 @@ msngr.extend((function (external, internal) { } }; + var fetchPersisted = function () { + var uuids = payloadIndex.query(msg); + + var fpay; + + if (uuids.length === 0) { + return undefined; + } + + if (uuids.length === 1) { + return payloads[uuids[0]]; + } + + for (var i = 0; i < uuids.length; ++i) { + fpay = external.extend(innerPay, fpay); + } + + return fpay; + }; + var msgObj = { option: function (key, value) { options[key] = value; + counts.options = counts.options + 1; return msgObj; }, emit: function (payload, callback) { explicitEmit(payload, undefined, callback); + counts.emits = counts.emits + 1; return msgObj; }, persist: function (payload) { var uuids = payloadIndex.query(msg); - var uuid; - if (uuids.length > 0) { - uuid = uuids[0]; + if (uuids.length === 0) { + var uuid = payloadIndex.index(msg); + payloads[uuid] = payload; + uuids = [uuid]; } else { - uuid = payloadIndex.index(msg); + for (var i = 0; i < uuids.length; ++i) { + payloads[uuids[i]] = external.extend(payload, payloads[uuids[i]]); + } } - payloads[uuid] = payload; + var fpay = fetchPersisted(); + ++payloadCount; - return msgObj.emit(payload); + counts.persists = counts.persists + 1; + + return msgObj.emit(fpay); }, cease: function () { var uuids = payloadIndex.query(msg); @@ -190,11 +227,11 @@ msngr.extend((function (external, internal) { }; handlerCount++; - var payloadId = payloadIndex.query(msg); - var payload = payloads[payloadId]; + var payload = fetchPersisted(); if (external.exist(payload)) { explicitEmit(payload, [uuid], undefined); } + counts.ons = counts.ons + 1; return msgObj; }, @@ -207,6 +244,12 @@ msngr.extend((function (external, internal) { }; handlerCount++; + var payload = fetchPersisted(); + if (external.exist(payload)) { + explicitEmit(payload, [uuid], undefined); + } + counts.onces = counts.onces + 1; + return msgObj; }, bind: function (element, event) { @@ -222,6 +265,7 @@ msngr.extend((function (external, internal) { node.addEventListener(event, internal.domListener); ++boundCount; + counts.binds = counts.binds + 1; return msgObj; }, @@ -273,12 +317,24 @@ msngr.extend((function (external, internal) { } }; + // Expose the raw message object itself via a message property. + // Do not allow modification. Object.defineProperty(msgObj, "message", { get: function () { return msg; } }); + // If debug mode is enabled then let's expose the internal method hit counts. + // These counts are only good if a method is called and succeeds. + if (external.debug === true) { + Object.defineProperty(msgObj, "counts", { + get: function () { + return counts; + } + }); + } + return msgObj; }; From f746088229f2eee1acc9d8f10247dda1fcab0c6c Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 03:29:42 -0400 Subject: [PATCH 18/46] mocha version++ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aef5d75..64e7bca 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "grunt-contrib-concat": "0.5.1", "grunt-contrib-clean": "0.6.0", "grunt-mocha-test": "0.12.7", - "mocha": "2.2.4", + "mocha": "2.2.5", "grunt-mocha-phantomjs": "0.6.1", "grunt-available-tasks": "0.5.7", "chai": "2.3.0" From 6dd78a950b60f4f8849469e1d33afb0297e6d577 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 03:29:51 -0400 Subject: [PATCH 19/46] Latest generated files --- msngr.js | 100 ++++++++++++++++++++++++++++++++++++++++++++++----- msngr.min.js | 2 +- 2 files changed, 92 insertions(+), 10 deletions(-) diff --git a/msngr.js b/msngr.js index 4d85dfb..c0bbda9 100644 --- a/msngr.js +++ b/msngr.js @@ -7,7 +7,10 @@ var msngr = msngr || (function () { "use strict"; - var internal = { }; + var internal = { + warnings: true + }; + var external = function (topic, category, dataType) { return internal.objects.message(topic, category, dataType); }; @@ -20,6 +23,16 @@ var msngr = msngr || (function () { obj = obj.apply(this, [external, internal]); } + if (Object.prototype.toString.call(obj) === "[object String]") { + if (Object.prototype.toString.call(target) === "[object String]") { + // Simple string concat operation + target = target + obj; + } else { + // Hmm what's the right move here? STRINGIFY! + target = JSON.stringify(target) + obj; + } + } + if (Object.prototype.toString.call(obj) === "[object Object]") { for (var key in obj) { if (obj.hasOwnProperty(key)) { @@ -48,6 +61,19 @@ var msngr = msngr || (function () { } else if (value === false) { delete external.internal; } + }, + get: function () { + return (external.internal !== undefined) + } + }); + + // This governs warning messages that some methods may spit into the console when warranted (du'h). + Object.defineProperty(external, "warnings", { + set: function (value) { + internal.warnings = value; + }, + get: function () { + return internal.warnings; } }); @@ -713,6 +739,15 @@ msngr.extend((function (external, internal) { var options = { }; + var counts = { + emits: 0, + persists: 0, + options: 0, + ons: 0, + onces: 0, + binds: 0 + }; + var explicitEmit = function (payload, uuids, callback) { var uuids = uuids || messageIndex.query(msg); if (uuids.length > 0) { @@ -740,30 +775,58 @@ msngr.extend((function (external, internal) { } }; + var fetchPersisted = function () { + var uuids = payloadIndex.query(msg); + + var fpay; + + if (uuids.length === 0) { + return undefined; + } + + if (uuids.length === 1) { + return payloads[uuids[0]]; + } + + for (var i = 0; i < uuids.length; ++i) { + fpay = external.extend(innerPay, fpay); + } + + return fpay; + }; + var msgObj = { option: function (key, value) { options[key] = value; + counts.options = counts.options + 1; return msgObj; }, emit: function (payload, callback) { explicitEmit(payload, undefined, callback); + counts.emits = counts.emits + 1; return msgObj; }, persist: function (payload) { var uuids = payloadIndex.query(msg); - var uuid; - if (uuids.length > 0) { - uuid = uuids[0]; + if (uuids.length === 0) { + var uuid = payloadIndex.index(msg); + payloads[uuid] = payload; + uuids = [uuid]; } else { - uuid = payloadIndex.index(msg); + for (var i = 0; i < uuids.length; ++i) { + payloads[uuids[i]] = external.extend(payload, payloads[uuids[i]]); + } } - payloads[uuid] = payload; + var fpay = fetchPersisted(); + ++payloadCount; - return msgObj.emit(payload); + counts.persists = counts.persists + 1; + + return msgObj.emit(fpay); }, cease: function () { var uuids = payloadIndex.query(msg); @@ -784,11 +847,11 @@ msngr.extend((function (external, internal) { }; handlerCount++; - var payloadId = payloadIndex.query(msg); - var payload = payloads[payloadId]; + var payload = fetchPersisted(); if (external.exist(payload)) { explicitEmit(payload, [uuid], undefined); } + counts.ons = counts.ons + 1; return msgObj; }, @@ -801,6 +864,12 @@ msngr.extend((function (external, internal) { }; handlerCount++; + var payload = fetchPersisted(); + if (external.exist(payload)) { + explicitEmit(payload, [uuid], undefined); + } + counts.onces = counts.onces + 1; + return msgObj; }, bind: function (element, event) { @@ -816,6 +885,7 @@ msngr.extend((function (external, internal) { node.addEventListener(event, internal.domListener); ++boundCount; + counts.binds = counts.binds + 1; return msgObj; }, @@ -867,12 +937,24 @@ msngr.extend((function (external, internal) { } }; + // Expose the raw message object itself via a message property. + // Do not allow modification. Object.defineProperty(msgObj, "message", { get: function () { return msg; } }); + // If debug mode is enabled then let's expose the internal method hit counts. + // These counts are only good if a method is called and succeeds. + if (external.debug === true) { + Object.defineProperty(msgObj, "counts", { + get: function () { + return counts; + } + }); + } + return msgObj; }; diff --git a/msngr.min.js b/msngr.min.js index 0ec6b75..31ff6db 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0?uuids[0]:payloadIndex.index(msg),payloads[uuid]=payload,++payloadCount,msgObj.emit(payload)},cease:function(){for(var uuids=payloadIndex.query(msg),i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file From 9281ec4296e5f6c6b7e7bec4a575f7ad901eed38 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 04:02:42 -0400 Subject: [PATCH 20/46] Added ability to handle an empty persist call to allow persisting emit messages regardless of payload content. Undefined payloads are still ignored. --- msngr.js | 8 ++++++-- msngr.min.js | 2 +- src/objects/message.aspec.js | 23 +++++++++++++++++++++++ src/objects/message.js | 8 ++++++-- 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/msngr.js b/msngr.js index c0bbda9..287be58 100644 --- a/msngr.js +++ b/msngr.js @@ -809,6 +809,10 @@ msngr.extend((function (external, internal) { return msgObj; }, persist: function (payload) { + if (payload === undefined) { + payload = null; + } + var uuids = payloadIndex.query(msg); if (uuids.length === 0) { var uuid = payloadIndex.index(msg); @@ -848,7 +852,7 @@ msngr.extend((function (external, internal) { handlerCount++; var payload = fetchPersisted(); - if (external.exist(payload)) { + if (payload !== undefined) { explicitEmit(payload, [uuid], undefined); } counts.ons = counts.ons + 1; @@ -865,7 +869,7 @@ msngr.extend((function (external, internal) { handlerCount++; var payload = fetchPersisted(); - if (external.exist(payload)) { + if (payload !== undefined) { explicitEmit(payload, [uuid], undefined); } counts.onces = counts.onces + 1; diff --git a/msngr.min.js b/msngr.min.js index 31ff6db..b26c200 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index 696cf1c..0288717 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -335,6 +335,29 @@ describe("./objects/message.js", function () { msg.persist({ ready4: true }); }); + it("msngr().persist() - passing in nothing still conducts a proper persisting of message execution in later 'on's", function (done) { + msngr("Server", "Ready").persist(); + + var calls = 0; + + msngr("Server", "Ready").on(function () { + ++calls; + }); + + msngr("Server", "Ready").on(function () { + ++calls; + }); + + msngr("Server", "Ready").on(function () { + ++calls; + }); + + setTimeout(function () { + expect(calls).to.equal(3); + done(); + }, 250); + }); + it("msngr().counts - when debug mode is enabled returns a counts object otherwise is undefined", function () { msngr.debug = true; var msg = msngr("test"); diff --git a/src/objects/message.js b/src/objects/message.js index e4b5f42..b061baf 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -189,6 +189,10 @@ msngr.extend((function (external, internal) { return msgObj; }, persist: function (payload) { + if (payload === undefined) { + payload = null; + } + var uuids = payloadIndex.query(msg); if (uuids.length === 0) { var uuid = payloadIndex.index(msg); @@ -228,7 +232,7 @@ msngr.extend((function (external, internal) { handlerCount++; var payload = fetchPersisted(); - if (external.exist(payload)) { + if (payload !== undefined) { explicitEmit(payload, [uuid], undefined); } counts.ons = counts.ons + 1; @@ -245,7 +249,7 @@ msngr.extend((function (external, internal) { handlerCount++; var payload = fetchPersisted(); - if (external.exist(payload)) { + if (payload !== undefined) { explicitEmit(payload, [uuid], undefined); } counts.onces = counts.onces + 1; From 926a55645dd19ec7ba68eccdb4f3ae8dbacdc979 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 04:11:48 -0400 Subject: [PATCH 21/46] All emit to take only return handler when no payload is desired --- msngr.js | 4 ++++ msngr.min.js | 2 +- src/objects/message.aspec.js | 12 ++++++++++++ src/objects/message.js | 4 ++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/msngr.js b/msngr.js index 287be58..d10a1c6 100644 --- a/msngr.js +++ b/msngr.js @@ -803,6 +803,10 @@ msngr.extend((function (external, internal) { return msgObj; }, emit: function (payload, callback) { + if (external.isFunction(payload)) { + callback = payload; + payload = undefined; + } explicitEmit(payload, undefined, callback); counts.emits = counts.emits + 1; diff --git a/msngr.min.js b/msngr.min.js index b26c200..105b75c 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index 0288717..c0975f7 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -252,6 +252,18 @@ describe("./objects/message.js", function () { }, 250); }); + it("msngr().emit(func) - if a method is passed in as first argument then that is used as callback", function (done) { + var msg = msngr("TestTopical"); + var hitOn = false; + msg.on(function () { + hitOn = true; + }); + msg.emit(function () { + expect(hitOn).to.equal(true); + done(); + }); + }); + it("msngr().persist().on() - persist stores and re-emits data with new on registrations", function (done) { var handledCount = 0; diff --git a/src/objects/message.js b/src/objects/message.js index b061baf..d9daa13 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -183,6 +183,10 @@ msngr.extend((function (external, internal) { return msgObj; }, emit: function (payload, callback) { + if (external.isFunction(payload)) { + callback = payload; + payload = undefined; + } explicitEmit(payload, undefined, callback); counts.emits = counts.emits + 1; From a9812cfafeb769751a5b845cf7a5dc8b1ddaa7b5 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 04:22:52 -0400 Subject: [PATCH 22/46] Partial first draft --- docs/messaging patterns.md | 75 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/docs/messaging patterns.md b/docs/messaging patterns.md index 6e182f1..ef3633a 100644 --- a/docs/messaging patterns.md +++ b/docs/messaging patterns.md @@ -1 +1,76 @@ # Messaging patterns +So at this point you've hopefully come to the *right* side of thinking that messaging is the best pattern (**S**uperior **A**bstraction **L**ayer comes to mind) when developing software. No? Okay well that's fine since there is no single way of writing software that is better than all others but let's talk some messaging patterns you can use with msngr.js in your server or client code. + +## Separation of concerns +Some abstraction strategies lean to the 'block boxing' approach in which messaging can be quite handy. So let's look at an example of using messaging to save a user's preferences. + +```javascript +// BusinessLogic.js +msngr("Preferences", "Save", "application/json") + .on(function(preferences) { + // Save these + console.log(preferences); + }); +``` +```javascript +// RestLayer.js +msngr("Preferences", "Save", "application/json") + .emit(request.params.preferences, function () { + console.log("Saved"); + }); +``` + +In the example above we're saying when we receive a message with a topic of "Preferences", a category of "Save" and a dataType of "application/json" that we should act on it and "save" them (or in this case dump to console). The restful layer sends the preferences and once the on is finished executing it will execute the emit's callback letting it know it's done. + +So a simple way of separating things. One can envision creating multiple versions of 'BusinessLogic.js' where one saves to a local storage mechanism (memory perhaps?), another to MySQL, etc. This allows you to swap out backends depending on environment. + +But this is too simple; msngr is *way* cooler than this! + +## A better separation +Let's take a look at a more complex example. + +```javascript +// Server.js +// Boilerplate server code here +msngr("Server", "Ready").persist(); +``` +```javascript +// RestfulEndpoints.js +msngr("Server", "Ready").on(function () { + // Server is ready; setup restful endpoints + router.get("/Users/", function (req, res) { + msngr("Users", "List").emit(function (result) { + res.json(result); + }); + }); +}); +``` +```javascript +// MySQLBackend.js +msngr("Server", "Ready").on(function () { + // Server is ready; setup backend message handlers + msngr("Users", "List").on(function (payload, async) { + var done = async(); + // async call to MySQL for relevant data + done(results); + }); +}); +``` +```javascript +// MemoryBackend.js +msngr("Server", "Ready").on(function () { + var users = { }; + // Server is ready; setup backend message handlers + msngr("Users", "List").on(function (payload) { + return users; + }); +}); +``` +In the above example there are a several things to take note of. First the usage of ```persist()``` can persist a specific payload or just a message itself. By using persist in this way it doesn't matter what order the scripts run because they will all get the ready event from the server to let them setup themselves. + +After that, using an environment configuration, you can choose to load ```MySQLBackend.js``` or ```MemoryBackend.js```. Both use the exact same messaging handlers, one works asynchronously and the other synchronously but the receiving end (the callback specified in emit) gets the data in the same way regardless. + +Neat, right? + +## Persisted merging +Alright so we have the idea that we can separate logic and implementation, we can bring results back via ```emit()``` and we can persist messages or data via ```persist()```. But what happens if you persist multiple things under the same message? What if you persist multiple things under multiple messages then setup a handler that gets hit by multiple persists? Why we merge is what we do! So let's check out an example. From 99f40873c3beac720d842fca34ee2d0e5f38a4da Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Fri, 22 May 2015 04:23:59 -0400 Subject: [PATCH 23/46] typeo --- docs/messaging patterns.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/messaging patterns.md b/docs/messaging patterns.md index ef3633a..62438c2 100644 --- a/docs/messaging patterns.md +++ b/docs/messaging patterns.md @@ -2,7 +2,7 @@ So at this point you've hopefully come to the *right* side of thinking that messaging is the best pattern (**S**uperior **A**bstraction **L**ayer comes to mind) when developing software. No? Okay well that's fine since there is no single way of writing software that is better than all others but let's talk some messaging patterns you can use with msngr.js in your server or client code. ## Separation of concerns -Some abstraction strategies lean to the 'block boxing' approach in which messaging can be quite handy. So let's look at an example of using messaging to save a user's preferences. +Some abstraction strategies lean to the 'black boxing' approach in which messaging can be quite handy. So let's look at an example of using messaging to save a user's preferences. ```javascript // BusinessLogic.js From f8611de5f481fcf4efa9839fe05e96987678b61f Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 23 May 2015 15:59:33 -0400 Subject: [PATCH 24/46] More documentation in progress --- README.md | 2 ++ docs/api.md | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 docs/api.md diff --git a/README.md b/README.md index 77ec209..3bd27b1 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ While msngr.js isn't very large the documentation has been split up for easy rea [Extending and hacking](docs/extending and hacking.md) - Want to extend the capabilities of msngr.js? It's actually quite easy and this document covers it. Using msngr.js deep in a production system then suddenly find *something* that you need to change to avoid catastrophe? Hacking msngr.js is also covered for those times when you need *unorthodox* solutions :) +[Just give me the damn API](docs/api.md) - So you just want what method(s) are exposed and the parameters required to make them go? Fine don't read my witty and informative documentation and just look at this. I won't be upset... + For questions, news, and whatever else that doesn't fit in GitHub issues you can follow me [@KrisSiegel](https://twitter.com/KrisSiegel) Copyright © 2014-2015 Kris Siegel diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..118975b --- /dev/null +++ b/docs/api.md @@ -0,0 +1,47 @@ +#msngr.js API +This document outlines the exposed msngr.js API. It does not cover anything internal that isn't expected to be used by typical developers. + +## ```msngr(topic, category, dataType)``` +```topic (required)``` - a string to signify the topic of the message. + +```category (optional)``` - a string to signify the category of the message. + +```dataType (optional)``` - a string to signify the dataType of the message. + +```returns``` a msngr object + +```javascript +var msg = msngr("MyTopic", "MyCategory", "MyDataType"); +``` + +## ```msngr object``` +The methods below are part of a ```msngr``` object returned from the ```msngr()``` method. + +### ```.emit(payload, callback)``` +```payload (optional)``` - the payload to send to a receiver. + +```callback (optional)``` - the callback to execute when all handlers finish executing. Provides a result object as a first parameter to the callback with an aggregation of all synchronously or asynchronously returned data. The ```payload``` parameter can be omitted while just a ```callback``` is passed into ```.emit()```. + +```javascript +var msg = msngr("MyTopic"); +msg.emit(function (result) { + console.log(result); +}); +``` + +### ```.on(callback)``` +```callback (required)``` - registers a method to handle the previously supplied message. The value returned is then sent to the emit callback. If a return value needs to be asynchronous then the second parameter supplied to the callback can be used. + +```javascript +var msg = msngr("MyTopic"); +msg.on(function (payload, async) { + var done = async(); + done("Somevalue"); +}); +msg.emit(function (result) { + console.log(result); // Prints ["Somevalue"] +}); +``` + +### ```.once(callback)``` +```callback (required)``` - registers a method to handle the previously supplied message. The value returned is then sent to the emit callback. If a return value needs to be asynchronous then the second parameter supplied to the callback can be used. From 1a1f9b4a1bbef562fc38776091a2dfb34d2df72e Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 26 May 2015 01:07:03 -0400 Subject: [PATCH 25/46] Tons more documentation. --- docs/api.md | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/docs/api.md b/docs/api.md index 118975b..082b734 100644 --- a/docs/api.md +++ b/docs/api.md @@ -2,6 +2,8 @@ This document outlines the exposed msngr.js API. It does not cover anything internal that isn't expected to be used by typical developers. ## ```msngr(topic, category, dataType)``` +The main msngr method takes in 3 strings to generate a message object from which all other actions are derived. + ```topic (required)``` - a string to signify the topic of the message. ```category (optional)``` - a string to signify the category of the message. @@ -18,6 +20,8 @@ var msg = msngr("MyTopic", "MyCategory", "MyDataType"); The methods below are part of a ```msngr``` object returned from the ```msngr()``` method. ### ```.emit(payload, callback)``` +Sends a payload to all registered handlers to the specified message. The optional callback is executed when all handlers are finished executing. + ```payload (optional)``` - the payload to send to a receiver. ```callback (optional)``` - the callback to execute when all handlers finish executing. Provides a result object as a first parameter to the callback with an aggregation of all synchronously or asynchronously returned data. The ```payload``` parameter can be omitted while just a ```callback``` is passed into ```.emit()```. @@ -29,7 +33,19 @@ msg.emit(function (result) { }); ``` +### ```.persist(payload)``` +Registers a payload to be sent to all matching handlers regardless of when they are registered (now or in the future). + +```payload (optional)``` - the payload to send to a receiver. + +```javascript +var msg = msngr("MyTopic"); +msg.persist("My data"); +``` + ### ```.on(callback)``` +Registers a handler to handle all emissions of the specified message. The callback can take a result either synchronously or asynchronously to supply back to an emit callback. + ```callback (required)``` - registers a method to handle the previously supplied message. The value returned is then sent to the emit callback. If a return value needs to be asynchronous then the second parameter supplied to the callback can be used. ```javascript @@ -44,4 +60,124 @@ msg.emit(function (result) { ``` ### ```.once(callback)``` +The same as the ```.on(callback)``` except the handler is automatically unregistered after one execution. + ```callback (required)``` - registers a method to handle the previously supplied message. The value returned is then sent to the emit callback. If a return value needs to be asynchronous then the second parameter supplied to the callback can be used. + +```javascript +var msg = msngr("MyTopic"); +msg.once(function (payload, async) { + var done = async(); + done("Somevalue"); +}); +msg.emit(function (result) { + console.log(result); // Prints ["Somevalue"] +}); +``` + +### ```.option(key, value)``` +Options are extensions added into msngr and are executed on payloads before being sent to any registered handlers. Options are comprised of a key to enable a specific option and a value consisting of any necessary configuration needed to execute the option. + +```key (required)``` - a registered option key (e.g. "dom" is bundled into msngr). + +```value (required)``` - any configuration options that are needed for a specific option. + +```javascript +var msg = msngr("MyTopic"); +msg.option("dom", ["input[name=Name]"]); +msg.bind("button", "click"); +msg.on(function (payload) { + console.log(payload.Name); // returns the gathered input's value +}); +``` + +### ```.bind(element, event)``` +Binds an HTML element and event to the specified message. Payload consists of aggregated input values when the 'dom' option is specified with an array of selectors. + +```element (required)``` - an HTML node or selector. + +```event (required)``` - an event to bind a message to. + +```javascript +var msg = msngr("MyTopic"); +msg.option("dom", ["input[name=Name]"]); +msg.bind("button", "click"); +msg.on(function (payload) { + console.log(payload.Name); // returns the gathered input's value +}); +``` + +### ```.cease()``` +Ceases all payloads being persisted based on the specified message. + +### ```.drop(handler)``` +Drops a specific handler that was registered via ```.on()```. + +```handler (required)``` - the handler to drop. + +### ```.unbind(element, event)``` +Unbinds the specified message from an element's event. + +```element (required)``` - an HTML node or selector. + +```event (required)``` - an event to unbind the message. + +### ```.dropAll()``` +Drops all handlers registered via ```.on()```. + +## ```misc utilities``` +There are multiple utility methods included in msngr. Some are used internally and some are exposed for external use by others. + +### ```msngr.exist(obj)``` +Returns false if obj is undefined or null otherwise true. + +```javascript +console.log(msngr.exist(undefined)); // Outputs false +``` + +### ```msngr.exists(...)``` +Accepts n number of arguments. Returns false if all arguments are undefined or null otherwise true. + +```javascript +console.log(msngr.exists({ }, [], "whatever")); // Outputs true +``` + +### ```msngr.isString(obj)``` +Returns true if obj is a string otherwise false. + +```javascript +console.log(msngr.isString("something")); // Outputs true +``` + +### ```msngr.areStrings(...)``` +Accepts n number of arguments. Returns true if all arguments are a string otherwise false. + +```javascript +console.log(msngr.areStrings("something", "another", "")); // Outputs true +``` + +### ```msngr.isArguments(obj)``` +Returns true if obj is an arguments object otherwise false. + +### ```msngr.areArguments(...)``` +Accepts n number of arguments. Returns true if all arguments are an arguments object otherwise false. + +### ```msngr.id()``` +Returns a random UUID. + +### ```msngr.now(noDuplicates)``` +Uses feature detection to find the highest time resolution available in its running environment (performance.now(), process.hrtime() or getTime()). Once the best feature is cached the method will always return the time in milliseconds. + +```noDuplicates (optional)``` - only useful when the best available time resolution is getTime() (which kinda sucks); this flag, when set to ```true```, will force it to return a unique value even if the resolution isn't good enough to do so (hence the result will be slightly inaccurate but still useful). + +### ```msngr.removeFromArray(arr, value)``` +Removes a value from an array. Optimized for better performance in larger arrays as it will reorder the item to be removed (thus not preserving order) to increase performance. + +```arr (required)``` - the array to remove a value from. + +```value (required)``` - the value from remove from the previously specified array. + +### ```msngr.argumentsToArray(args)``` +Converts an arguments object to an array object. + +```args (required)``` - the arguments object to convert to an array. From acd5357109524eda79a4dba8a0f294869249fbe5 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 26 May 2015 01:13:28 -0400 Subject: [PATCH 26/46] Finally added some minor unit tests for the exceptional utilities. --- src/utils/exceptional.aspec.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/utils/exceptional.aspec.js b/src/utils/exceptional.aspec.js index 3e0016d..940692b 100644 --- a/src/utils/exceptional.aspec.js +++ b/src/utils/exceptional.aspec.js @@ -21,4 +21,28 @@ describe("./utils/exceptional.js", function () { msngr.debug = false; }); + it("internal.InvalidParametersException - throws an exception", function () { + var myfunc = function () { + throw internal.InvalidParametersException("MyParameter"); + }; + + expect(myfunc).to.throw(); + }); + + it("internal.ReservedKeywordsException - throws an exception", function () { + var myfunc = function () { + throw internal.ReservedKeywordsException("MyKeyword"); + }; + + expect(myfunc).to.throw(); + }); + + it("internal.MangledException - throws an exception", function () { + var myfunc = function () { + throw internal.MangledException("MyVariable", "MyFunc"); + }; + + expect(myfunc).to.throw(); + }); + }); From b00ec5abaf6d3892b19975df154b3740c0e3f620 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 26 May 2015 01:51:55 -0400 Subject: [PATCH 27/46] Added unit tests for invalid input --- src/objects/message.aspec.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index c0975f7..13414d7 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -25,7 +25,15 @@ describe("./objects/message.js", function () { msngr.debug = false; }); - it("msngr - handles a message object as expected", function () { + it("msngr() - throws an exception for invalid input", function () { + expect(msngr.bind([])).to.throw(); + expect(msngr.bind()).to.throw(); + expect(msngr.bind("")).to.throw(); + expect(msngr.bind(123)).to.throw(); + expect(msngr.bind((new Date()))).to.throw(); + }); + + it("msngr() - handles a message object as expected", function () { var m = msngr({ topic: "MyTopic", category: "MyCategory", dataType: "MyDataType" }); expect(m).to.exist; expect(m.message).to.exist; From 2c6ef5c6bc6ff60c1173bcd6831c35f2887db365 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 26 May 2015 03:31:10 -0400 Subject: [PATCH 28/46] Documentation update Added unit test files for all documentation files --- README.cspec.js | 2 +- README.md | 4 ++-- docs/api.aspec.js | 27 +++++++++++++++++++++++++++ docs/api.cspec.js | 27 +++++++++++++++++++++++++++ docs/binding and the dom.cspec.js | 27 +++++++++++++++++++++++++++ docs/extending and hacking.aspec.js | 27 +++++++++++++++++++++++++++ docs/messaging patterns.aspec.js | 27 +++++++++++++++++++++++++++ 7 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 docs/api.aspec.js create mode 100644 docs/api.cspec.js create mode 100644 docs/binding and the dom.cspec.js create mode 100644 docs/extending and hacking.aspec.js create mode 100644 docs/messaging patterns.aspec.js diff --git a/README.cspec.js b/README.cspec.js index 1296465..37dc37b 100644 --- a/README.cspec.js +++ b/README.cspec.js @@ -7,7 +7,7 @@ if (typeof expect === "undefined") { } if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../../msngr"); + var msngr = require("./msngr"); } describe("./README.md", function () { diff --git a/README.md b/README.md index 3bd27b1..285fa24 100644 --- a/README.md +++ b/README.md @@ -24,14 +24,14 @@ msngr("User", "Save") ## Would you like to know more? While msngr.js isn't very large the documentation has been split up for easy reading. +[Full API](docs/api.md) - This is the full, exposed API that msngr makes available. This includes the methods that can be used (it does not cover internal methods or objects since those are subject to change) and examples for each. + [Messaging patterns](docs/messaging patterns.md) - Explains how to use the basic messaging features of msngr.js with some typical patterns. [Binding and the DOM](docs/binding and the dom.md) - This covers binding msngr.js to elements and events, unbinding them and how to gather up values from various types of elements. [Extending and hacking](docs/extending and hacking.md) - Want to extend the capabilities of msngr.js? It's actually quite easy and this document covers it. Using msngr.js deep in a production system then suddenly find *something* that you need to change to avoid catastrophe? Hacking msngr.js is also covered for those times when you need *unorthodox* solutions :) -[Just give me the damn API](docs/api.md) - So you just want what method(s) are exposed and the parameters required to make them go? Fine don't read my witty and informative documentation and just look at this. I won't be upset... - For questions, news, and whatever else that doesn't fit in GitHub issues you can follow me [@KrisSiegel](https://twitter.com/KrisSiegel) Copyright © 2014-2015 Kris Siegel diff --git a/docs/api.aspec.js b/docs/api.aspec.js new file mode 100644 index 0000000..c44ef76 --- /dev/null +++ b/docs/api.aspec.js @@ -0,0 +1,27 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../msngr"); +} + +describe("./docs/api.md", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); +}); diff --git a/docs/api.cspec.js b/docs/api.cspec.js new file mode 100644 index 0000000..c44ef76 --- /dev/null +++ b/docs/api.cspec.js @@ -0,0 +1,27 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../msngr"); +} + +describe("./docs/api.md", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); +}); diff --git a/docs/binding and the dom.cspec.js b/docs/binding and the dom.cspec.js new file mode 100644 index 0000000..c7b8d9b --- /dev/null +++ b/docs/binding and the dom.cspec.js @@ -0,0 +1,27 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../msngr"); +} + +describe("./docs/binding and the dom.md", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); +}); diff --git a/docs/extending and hacking.aspec.js b/docs/extending and hacking.aspec.js new file mode 100644 index 0000000..1ae9ed3 --- /dev/null +++ b/docs/extending and hacking.aspec.js @@ -0,0 +1,27 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../msngr"); +} + +describe("./docs/extending and hacking.md", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); +}); diff --git a/docs/messaging patterns.aspec.js b/docs/messaging patterns.aspec.js new file mode 100644 index 0000000..b092310 --- /dev/null +++ b/docs/messaging patterns.aspec.js @@ -0,0 +1,27 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../msngr"); +} + +describe("./docs/messaging patterns.md", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); +}); From 915e35ca75102f29027cf997ae6c4112e73033eb Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 26 May 2015 04:15:53 -0400 Subject: [PATCH 29/46] Fixes where root wasn't passed into bigger methods --- src/utils/dom.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/dom.js b/src/utils/dom.js index 95d32c6..930ecff 100644 --- a/src/utils/dom.js +++ b/src/utils/dom.js @@ -10,7 +10,7 @@ msngr.extend((function (external, internal) { return (this.getType(obj) === "[object NodeList]"); }, findElement: function (element, root) { - var elms = external.findElements(element); + var elms = external.findElements(element, root); if (elms !== undefined && elms.length > 0) { return elms[0]; } @@ -89,8 +89,8 @@ msngr.extend((function (external, internal) { } return [result]; }, - querySelectorWithEq: function (selector) { - return external.querySelectorAllWithEq(selector)[0]; + querySelectorWithEq: function (selector, root) { + return external.querySelectorAllWithEq(selector, root)[0]; } }; })); From dcfa0609263a8c66b38bef279286a2cb14b20616 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 26 May 2015 04:27:43 -0400 Subject: [PATCH 30/46] Added contributors documentation --- README.md | 2 ++ docs/contributing.md | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 docs/contributing.md diff --git a/README.md b/README.md index 285fa24..b9b932f 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ While msngr.js isn't very large the documentation has been split up for easy rea [Extending and hacking](docs/extending and hacking.md) - Want to extend the capabilities of msngr.js? It's actually quite easy and this document covers it. Using msngr.js deep in a production system then suddenly find *something* that you need to change to avoid catastrophe? Hacking msngr.js is also covered for those times when you need *unorthodox* solutions :) +[Contributing](docs/contributing.md) - Want to contributed to msngr.js? There are a couple of things you should know before you submit that pull request to better ensure it gets accepted :) + For questions, news, and whatever else that doesn't fit in GitHub issues you can follow me [@KrisSiegel](https://twitter.com/KrisSiegel) Copyright © 2014-2015 Kris Siegel diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..7343745 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,24 @@ +# Contributing +To contribute to msngr.js there are a few rules I expect every developer to follow to ensure the best quality library possible. There are no "zero-tolerance" rules because, well, those are dumb in almost every single case in existence (I'm sure someone will find a reason where my rules should be ignored). + +The goal of this short document isn't to be annoying but to ensure quality. I will work with anyone who wishes to submit a pull request. + +## Checklists +The checklists should serve as a guide for submitting your pull request. + +### Bug fixing +When fixing a bug these apply: + +- A unit test *must* be included that cover the bug to ensure proper regression testing during future updates. +- If an API change is required to fix a bug the API change cannot break current compatibility. Should it break compatibility then a discussion should happen before submission of the fix. + +### Feature changes and additions +The following should be done when changing or adding features: + +- Ensure proper discussion is done within GitHub issues to ensure it will be accepted (naturally forks are not a problem; if it's not desired to put into msngr.js's main repository then feel free to keep the fork!). +- All API compatibility breaks must have a new major version number. +- All documentation [and accompanying unit tests] must be updated to comply with the new changes. If there are additions then the documentation needs to be amended along with unit tests to cover *all* documentation examples (see existing unit tests for each current document). +- All unit tests must pass when run against node, phantomjs, Internet Explorer 10+, Firefox and Chrome browsers in their expanded and minified versions. + +## Have fun! +Writing msngr.js has been a treat for me as it personally solves multiple issues for me. I'm not sure if it will be the same for anyone else or not but I hope others will find it useful and if so will help me in continuing to make it better! From a522bf73d7779e5229c287c4557053e3f6c4ae02 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Tue, 26 May 2015 04:27:59 -0400 Subject: [PATCH 31/46] Added more documentation especially covering the cool DOM utilities included in msngr! --- docs/api.md | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 211 insertions(+), 3 deletions(-) diff --git a/docs/api.md b/docs/api.md index 082b734..703a467 100644 --- a/docs/api.md +++ b/docs/api.md @@ -16,7 +16,7 @@ The main msngr method takes in 3 strings to generate a message object from which var msg = msngr("MyTopic", "MyCategory", "MyDataType"); ``` -## ```msngr object``` +## msngr object The methods below are part of a ```msngr``` object returned from the ```msngr()``` method. ### ```.emit(payload, callback)``` @@ -110,11 +110,26 @@ msg.on(function (payload) { ### ```.cease()``` Ceases all payloads being persisted based on the specified message. +```javascript +var msg = msngr("MyTopic"); +msg.persist("Cookies!!!"); +msg.cease(); // Gets rid of "Cookies!!!" :( +``` + ### ```.drop(handler)``` Drops a specific handler that was registered via ```.on()```. ```handler (required)``` - the handler to drop. +```javascript +var msg = msngr("MyTopic"); +var myHandler = function (payload) { + console.log(payload); +}; +msg.on(myHandler); +msg.drop(myHandler); +``` + ### ```.unbind(element, event)``` Unbinds the specified message from an element's event. @@ -122,10 +137,99 @@ Unbinds the specified message from an element's event. ```event (required)``` - an event to unbind the message. +```javascript +var msg = msngr("MyTopic"); +msg.bind("input[name=password]", "change"); +msg.unbind("input[name=password]", "change"); +``` + ### ```.dropAll()``` Drops all handlers registered via ```.on()```. -## ```misc utilities``` +```javascript +var msg = msngr("MyTopic"); +msg.dropAll(); // Drops all handlers even outside of 'MyTopic'!!! +``` + +## Handy DOM utilities +In implementing the binding and dom option features of msngr some handy DOM utilities had to be created. Why not expose them? + +### ```isHtmlElement(obj)``` +Determines whether a passed in object is a node within the DOM or something else. + +```obj (required)``` - the object to test. + +```javascript +console.log(msngr.isHtmlElement(5)); // Outputs false +console.log(msngr.isHtmlElement(document.createElement("div"))); // Outputs true +``` + +### ```isNodeList(obj)``` +Determines whether a passed in object is a NodeList within the DOM or something else. + +```obj (required)``` - the object to test. + +```javascript +console.log(msngr.isNodeList("chickens")); // Outputs false +console.log(msngr.isNodeList(document.querySelectorAll("div"))); // Outputs true +``` + +### ```findElement(selector, root)``` +Finds a single element via selector. + +```selector (required)``` - a standard DOM selector to find an element. + +```root (optional)``` - a root position to begin querying. Defaults to document. Handy when dealing with ShadowDom. + +```javascript +var elm = msngr.findElement("div"); +``` + +### ```findElements(selector, root)``` +Finds multiple elements via selector. + +```selector (required)``` - a standard DOM selector to find an element. + +```root (optional)``` - a root position to begin querying. Defaults to document. Handy when dealing with ShadowDom. + +```javascript +var elms = msngr.findElements("div"); +``` + +### ```getDomPath(element)``` +Takes an element and determines the path to accessing it via the DOM and generates an appropriate selector. This is useful when binding against elements that have no unique characteristics. + +```element (required)``` - the element to generate a path for. + +```javascript +var elm = msngr.findElement("div"); +var path = msngr.getDomPath(elm); +var found = msngr.findElement(path); // Same object as elm +``` + +### ```querySelectorWithEq(selector, root)``` +The native querySelector does not support the :eq(n) notation that jQuery has popularized therefore it was implemented here :). + +```selector (required)``` - a standard DOM selector to find an element. + +```root (optional)``` - a root position to begin querying. Defaults to document. Handy when dealing with ShadowDom. + +```javascript +var elm = msngr.querySelectorWithEq("div:eq(1)"); +``` + +### ```querySelectorAllWithEq(selector, root)``` +The native querySelectorAll does not support the :eq(n) notation that jQuery has popularized therefore it was implemented here :). + +```selector (required)``` - a standard DOM selector to find an element. + +```root (optional)``` - a root position to begin querying. Defaults to document. Handy when dealing with ShadowDom. + +```javascript +var elms = msngr.querySelectorAllWithEq("div:eq(1) > input"); +``` + +## Miscellaneous utilities There are multiple utility methods included in msngr. Some are used internally and some are exposed for external use by others. ### ```msngr.exist(obj)``` @@ -150,26 +254,115 @@ console.log(msngr.isString("something")); // Outputs true ``` ### ```msngr.areStrings(...)``` -Accepts n number of arguments. Returns true if all arguments are a string otherwise false. +Accepts n number of arguments. Returns true if all arguments are strings otherwise false. ```javascript console.log(msngr.areStrings("something", "another", "")); // Outputs true ``` +### ```msngr.isObject(obj)``` +Returns true if obj is an object otherwise false. + +```javascript +console.log(msngr.isObject({ })); // Outputs true +``` + +### ```msngr.areObjects(...)``` +Accepts n number of arguments. Returns true if all arguments are objects otherwise false. + +```javascript +console.log(msngr.areObjects({ }, { })); // Outputs true +``` + +### ```msngr.isNumber(obj)``` +Returns true if obj is a number otherwise false. + +```javascript +console.log(msngr.isNumber(5)); // Outputs true +``` + +### ```msngr.areNumbers(...)``` +Accepts n number of arguments. Returns true if all arguments are numbers otherwise false. + +```javascript +console.log(msngr.areNumbers(1, 5, 7, 9, 42)); // Outputs true +``` + +### ```msngr.isArray(obj)``` +Returns true if obj is an array otherwise false. + +```javascript +console.log(msngr.isArray([5, 10, 15])); // Outputs true +``` + +### ```msngr.areArrays(...)``` +Accepts n number of arguments. Returns true if all arguments are arrays otherwise false. + +```javascript +console.log(msngr.areArrays([1, 2], [5], [19, 37, 42])); // Outputs true +``` + +### ```msngr.isFunction(obj)``` +Returns true if obj is a function otherwise false. + +```javascript +console.log(msngr.isFunction(function () { })); // Outputs true +``` + +### ```msngr.areFunctions(...)``` +Accepts n number of arguments. Returns true if all arguments are functions otherwise false. + +```javascript +console.log(msngr.areFunctions(function () { }, function () { })); // Outputs true +``` + +### ```msngr.isEmptyString(obj)``` +Returns true if obj is an empty string otherwise false. + +```javascript +console.log(msngr.isEmptyString("")); // Outputs true +``` + +### ```msngr.areEmptyStrings(...)``` +Accepts n number of arguments. Returns true if all arguments are empty strings otherwise false. + +```javascript +console.log(msngr.areEmptyStrings("", " ", " ")); // Outputs true +``` + ### ```msngr.isArguments(obj)``` Returns true if obj is an arguments object otherwise false. +```javascript +console.log(msngr.isArguments(arguments)); // Outputs true +``` + ### ```msngr.areArguments(...)``` Accepts n number of arguments. Returns true if all arguments are an arguments object otherwise false. +```javascript +console.log(msngr.areArguments(arguments, [])); // Outputs false +``` + ### ```msngr.id()``` Returns a random UUID. +```javascript +console.log(msngr.id()); // Outputs UUID +``` + ### ```msngr.now(noDuplicates)``` Uses feature detection to find the highest time resolution available in its running environment (performance.now(), process.hrtime() or getTime()). Once the best feature is cached the method will always return the time in milliseconds. ```noDuplicates (optional)``` - only useful when the best available time resolution is getTime() (which kinda sucks); this flag, when set to ```true```, will force it to return a unique value even if the resolution isn't good enough to do so (hence the result will be slightly inaccurate but still useful). +```javascript +var start = msngr.now(); +// Some computation +var end = msngr.now(); +console.log("Started at {0} and ended at {1}.".replace("{0}", start).replace("{1}", end)); +``` + ### ```msngr.removeFromArray(arr, value)``` Removes a value from an array. Optimized for better performance in larger arrays as it will reorder the item to be removed (thus not preserving order) to increase performance. @@ -177,7 +370,22 @@ Removes a value from an array. Optimized for better performance in larger arrays ```value (required)``` - the value from remove from the previously specified array. +```javascript +var myArray = [5, 17, 42, 97]; +console.log(myArray); // Outputs [5, 17, 42, 97] +msngr.removeFromArray(myArray, 42); +console.log(myArray); // Outputs [5, 17, 97]; +``` + ### ```msngr.argumentsToArray(args)``` Converts an arguments object to an array object. ```args (required)``` - the arguments object to convert to an array. + +```javascript +var myFunction = function () { + console.log(msngr.argumentsToArray(arguments)); +}; + +myFunction(15, 27); +``` From 3512aac3cf92e78fd6d183a7359e9186625934ca Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Wed, 27 May 2015 05:26:35 -0400 Subject: [PATCH 32/46] Rough prototype of cross-window option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a cross-window option. This is a rough prototype as it doesn’t entirely work :) --- msngr.js | 53 ++++++++++++++++++++++++++++++++++--- msngr.min.js | 2 +- src/objects/message.js | 4 ++- src/options/cross-window.js | 42 +++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 src/options/cross-window.js diff --git a/msngr.js b/msngr.js index d10a1c6..4584547 100644 --- a/msngr.js +++ b/msngr.js @@ -108,7 +108,7 @@ msngr.extend((function (external, internal) { return (this.getType(obj) === "[object NodeList]"); }, findElement: function (element, root) { - var elms = external.findElements(element); + var elms = external.findElements(element, root); if (elms !== undefined && elms.length > 0) { return elms[0]; } @@ -187,8 +187,8 @@ msngr.extend((function (external, internal) { } return [result]; }, - querySelectorWithEq: function (selector) { - return external.querySelectorAllWithEq(selector)[0]; + querySelectorWithEq: function (selector, root) { + return external.querySelectorAllWithEq(selector, root)[0]; } }; })); @@ -690,7 +690,9 @@ msngr.extend((function (external, internal) { var result = payload; if (external.exist(results) && results.length > 0) { for (var i = 0; i < results.length; ++i) { - result = external.extend(results[i], result); + if (external.exist(results[i])) { + result = external.extend(results[i], result); + } } } callback.apply(this, [result]); @@ -970,6 +972,49 @@ msngr.extend((function (external, internal) { return { }; })); +/* + ./options/cross-window.js + + The cross-window option; provides the ability to emit and receive messages across + mupltiple browser tabs / windows within the same web browser. +*/ +msngr.extend((function (external, internal) { + "use strict"; + + var channelName = "__msngr_cross-window"; + + internal.options = internal.options || { }; + + // Let's check if localstorage is even available. If it isn't we shouldn't register + if (typeof localStorage === "undefined" || typeof window === "undefined") { + return { }; + } + + window.addEventListener("storage", function (event) { + if (event.key === channelName) { + // New message data. Respond? + + internal.objects.message(event.newValue.message).emit(event.newValue.payload); + } + }); + + internal.options["cross-window"] = function (message, payload, options, async) { + // Normalize all of the inputs + options = options || { }; + options = options["cross-window"] || { }; + + localStorage.setItem(channelName, { + message: message, + payload: payload + }); + + return undefined; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); + /* ./options/dom.js diff --git a/msngr.min.js b/msngr.min.js index 105b75c..723ebd7 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector){return external.querySelectorAllWithEq(selector)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element,root);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector,root){return external.querySelectorAllWithEq(selector,root)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/src/objects/message.js b/src/objects/message.js index d9daa13..26435e0 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -70,7 +70,9 @@ msngr.extend((function (external, internal) { var result = payload; if (external.exist(results) && results.length > 0) { for (var i = 0; i < results.length; ++i) { - result = external.extend(results[i], result); + if (external.exist(results[i])) { + result = external.extend(results[i], result); + } } } callback.apply(this, [result]); diff --git a/src/options/cross-window.js b/src/options/cross-window.js new file mode 100644 index 0000000..8e558fc --- /dev/null +++ b/src/options/cross-window.js @@ -0,0 +1,42 @@ +/* + ./options/cross-window.js + + The cross-window option; provides the ability to emit and receive messages across + mupltiple browser tabs / windows within the same web browser. +*/ +msngr.extend((function (external, internal) { + "use strict"; + + var channelName = "__msngr_cross-window"; + + internal.options = internal.options || { }; + + // Let's check if localstorage is even available. If it isn't we shouldn't register + if (typeof localStorage === "undefined" || typeof window === "undefined") { + return { }; + } + + window.addEventListener("storage", function (event) { + if (event.key === channelName) { + // New message data. Respond? + + internal.objects.message(event.newValue.message).emit(event.newValue.payload); + } + }); + + internal.options["cross-window"] = function (message, payload, options, async) { + // Normalize all of the inputs + options = options || { }; + options = options["cross-window"] || { }; + + localStorage.setItem(channelName, { + message: message, + payload: payload + }); + + return undefined; + }; + + // This is an internal extension; do not export explicitly. + return { }; +})); From 83e91095cc28a50202108acf4dfc51ab5fc20d75 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 30 May 2015 00:25:01 -0400 Subject: [PATCH 33/46] Tweak to specRunner files --- specRunner.html | 1 + specRunner.min.html | 18 +++--------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/specRunner.html b/specRunner.html index 9224635..3811e6e 100644 --- a/specRunner.html +++ b/specRunner.html @@ -8,6 +8,7 @@ diff --git a/specRunner.min.html b/specRunner.min.html index 51a99ec..75fcdb8 100644 --- a/specRunner.min.html +++ b/specRunner.min.html @@ -8,24 +8,12 @@ - - - - - - - - - - - - - - - + +
From 48f09b02f9ee6a6d6e986064231a5931caf270a3 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 30 May 2015 00:40:22 -0400 Subject: [PATCH 34/46] Fixed stupid mistake --- specRunner.html | 2 +- specRunner.min.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/specRunner.html b/specRunner.html index 3811e6e..bff8a5e 100644 --- a/specRunner.html +++ b/specRunner.html @@ -8,7 +8,7 @@ diff --git a/specRunner.min.html b/specRunner.min.html index 75fcdb8..cdd5ca1 100644 --- a/specRunner.min.html +++ b/specRunner.min.html @@ -8,7 +8,7 @@ From 97d3b1c8959eba248d40bb445eeee4f65d7251a6 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 30 May 2015 00:42:11 -0400 Subject: [PATCH 35/46] Added support for cross-window communication using the 'cross-window' option. Added necessary spec files for unit testing cross-window communication. --- crossWindowVerifier.html | 17 +++++++++ crossWindowVerifier.min.html | 17 +++++++++ msngr.js | 55 +++++++++++++++++------------ msngr.min.js | 2 +- src/objects/message.js | 34 +++++++++--------- src/options/cross-window.cspec.js | 58 +++++++++++++++++++++++++++++++ src/options/cross-window.js | 21 ++++++++--- 7 files changed, 157 insertions(+), 47 deletions(-) create mode 100644 crossWindowVerifier.html create mode 100644 crossWindowVerifier.min.html create mode 100644 src/options/cross-window.cspec.js diff --git a/crossWindowVerifier.html b/crossWindowVerifier.html new file mode 100644 index 0000000..a4f038e --- /dev/null +++ b/crossWindowVerifier.html @@ -0,0 +1,17 @@ + + + Cross-Window Verifier + + + + + + + + diff --git a/crossWindowVerifier.min.html b/crossWindowVerifier.min.html new file mode 100644 index 0000000..d52fbac --- /dev/null +++ b/crossWindowVerifier.min.html @@ -0,0 +1,17 @@ + + + Cross-Window Verifier + + + + + + + + diff --git a/msngr.js b/msngr.js index 4584547..6eb2e65 100644 --- a/msngr.js +++ b/msngr.js @@ -751,30 +751,28 @@ msngr.extend((function (external, internal) { }; var explicitEmit = function (payload, uuids, callback) { - var uuids = uuids || messageIndex.query(msg); - if (uuids.length > 0) { - var methods = []; - var toDrop = []; - for (var i = 0; i < uuids.length; ++i) { - var obj = handlers[uuids[i]]; - methods.push(obj.handler); + var uuids = uuids || messageIndex.query(msg) || []; + var methods = []; + var toDrop = []; + for (var i = 0; i < uuids.length; ++i) { + var obj = handlers[uuids[i]]; + methods.push(obj.handler); - if (obj.once === true) { - toDrop.push(obj.handler); - } + if (obj.once === true) { + toDrop.push(obj.handler); } + } - internal.processOpts(options, msg, payload, function (result) { - var execs = internal.objects.executer(methods, result, (msg.context || this)); + internal.processOpts(options, msg, payload, function (result) { + var execs = internal.objects.executer(methods, result, (msg.context || this)); - for (var i = 0; i < toDrop.length; ++i) { - msgObj.drop(toDrop[i]); - } + for (var i = 0; i < toDrop.length; ++i) { + msgObj.drop(toDrop[i]); + } - execs.parallel(callback); + execs.parallel(callback); - }); - } + }); }; var fetchPersisted = function () { @@ -992,9 +990,15 @@ msngr.extend((function (external, internal) { window.addEventListener("storage", function (event) { if (event.key === channelName) { - // New message data. Respond? - - internal.objects.message(event.newValue.message).emit(event.newValue.payload); + // New message data. Respond! + var obj; + try { + obj = JSON.parse(event.newValue); + } catch (ex) { console.log(ex); } + + if (obj !== undefined && external.isObject(obj)) { + internal.objects.message(obj.message).emit(obj.payload); + } } }); @@ -1003,10 +1007,15 @@ msngr.extend((function (external, internal) { options = options || { }; options = options["cross-window"] || { }; - localStorage.setItem(channelName, { + var obj = { message: message, payload: payload - }); + }; + + try { + console.log(obj); + localStorage.setItem(channelName, JSON.stringify(obj)); + } catch (ex) { console.log(ex); } return undefined; }; diff --git a/msngr.min.js b/msngr.min.js index 723ebd7..2573520 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element,root);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector,root){return external.querySelectorAllWithEq(selector,root)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0){for(var methods=[],toDrop=[],i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element,root);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector,root){return external.querySelectorAllWithEq(selector,root)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/src/objects/message.js b/src/objects/message.js index 26435e0..f0c5993 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -131,30 +131,28 @@ msngr.extend((function (external, internal) { }; var explicitEmit = function (payload, uuids, callback) { - var uuids = uuids || messageIndex.query(msg); - if (uuids.length > 0) { - var methods = []; - var toDrop = []; - for (var i = 0; i < uuids.length; ++i) { - var obj = handlers[uuids[i]]; - methods.push(obj.handler); + var uuids = uuids || messageIndex.query(msg) || []; + var methods = []; + var toDrop = []; + for (var i = 0; i < uuids.length; ++i) { + var obj = handlers[uuids[i]]; + methods.push(obj.handler); - if (obj.once === true) { - toDrop.push(obj.handler); - } + if (obj.once === true) { + toDrop.push(obj.handler); } + } - internal.processOpts(options, msg, payload, function (result) { - var execs = internal.objects.executer(methods, result, (msg.context || this)); + internal.processOpts(options, msg, payload, function (result) { + var execs = internal.objects.executer(methods, result, (msg.context || this)); - for (var i = 0; i < toDrop.length; ++i) { - msgObj.drop(toDrop[i]); - } + for (var i = 0; i < toDrop.length; ++i) { + msgObj.drop(toDrop[i]); + } - execs.parallel(callback); + execs.parallel(callback); - }); - } + }); }; var fetchPersisted = function () { diff --git a/src/options/cross-window.cspec.js b/src/options/cross-window.cspec.js new file mode 100644 index 0000000..0a05f51 --- /dev/null +++ b/src/options/cross-window.cspec.js @@ -0,0 +1,58 @@ +if (typeof chai === "undefined" && typeof window === "undefined") { + var chai = require("chai"); +} + +if (typeof expect === "undefined") { + var expect = chai.expect; +} + +if (typeof msngr === "undefined" && typeof window === "undefined") { + var msngr = require("../../msngr"); +} + +describe("./options/cross-window.js", function () { + "use strict"; + + before(function () { + msngr.debug = true; + }); + + beforeEach(function () { + msngr.internal.reset(); + }); + + after(function () { + msngr.debug = false; + }); + + it("msngr().option('cross-window') - sends a message between different tabs or windows", function (done) { + var crossWindowVerifierPath = (window.specRunner.indexOf(".min.html") === -1) ? "crossWindowVerifier.html" : "crossWindowVerifier.min.html"; + var test1 = false; + var test2 = false; + var test3 = false; + + var iframe = document.createElement("iframe"); + var msg = msngr("CrossWindow", "Message"); + msg.on(function (payload) { + if (payload === "VerificationCrossTest1") { + test1 = true; + } + + if (payload === "VerificationCrossTest2") { + test2 = true; + } + + if (payload === "VerificationCrossTest3") { + test3 = true; + } + + if (test1 && test2 && test3) { + document.querySelector("body").removeChild(iframe); + done(); + } + }); + + iframe.setAttribute("src", crossWindowVerifierPath); + document.querySelector("body").appendChild(iframe); + }); +}); diff --git a/src/options/cross-window.js b/src/options/cross-window.js index 8e558fc..d7057ae 100644 --- a/src/options/cross-window.js +++ b/src/options/cross-window.js @@ -18,9 +18,15 @@ msngr.extend((function (external, internal) { window.addEventListener("storage", function (event) { if (event.key === channelName) { - // New message data. Respond? - - internal.objects.message(event.newValue.message).emit(event.newValue.payload); + // New message data. Respond! + var obj; + try { + obj = JSON.parse(event.newValue); + } catch (ex) { console.log(ex); } + + if (obj !== undefined && external.isObject(obj)) { + internal.objects.message(obj.message).emit(obj.payload); + } } }); @@ -29,10 +35,15 @@ msngr.extend((function (external, internal) { options = options || { }; options = options["cross-window"] || { }; - localStorage.setItem(channelName, { + var obj = { message: message, payload: payload - }); + }; + + try { + console.log(obj); + localStorage.setItem(channelName, JSON.stringify(obj)); + } catch (ex) { console.log(ex); } return undefined; }; From 81c6144c491beab0c8036bdebdde39b2428174dd Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 30 May 2015 00:43:27 -0400 Subject: [PATCH 36/46] Remove console.log() --- msngr.js | 1 - msngr.min.js | 2 +- src/options/cross-window.js | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/msngr.js b/msngr.js index 6eb2e65..1570836 100644 --- a/msngr.js +++ b/msngr.js @@ -1013,7 +1013,6 @@ msngr.extend((function (external, internal) { }; try { - console.log(obj); localStorage.setItem(channelName, JSON.stringify(obj)); } catch (ex) { console.log(ex); } diff --git a/msngr.min.js b/msngr.min.js index 2573520..4fe74dc 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element,root);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector,root){return external.querySelectorAllWithEq(selector,root)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element,root);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector,root){return external.querySelectorAllWithEq(selector,root)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/src/options/cross-window.js b/src/options/cross-window.js index d7057ae..a75ba71 100644 --- a/src/options/cross-window.js +++ b/src/options/cross-window.js @@ -41,7 +41,6 @@ msngr.extend((function (external, internal) { }; try { - console.log(obj); localStorage.setItem(channelName, JSON.stringify(obj)); } catch (ex) { console.log(ex); } From a280ea6f5e59cb39c53ecaac0d17569e54c44919 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 30 May 2015 11:37:41 -0400 Subject: [PATCH 37/46] Comment tweak --- src/options/cross-window.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options/cross-window.js b/src/options/cross-window.js index a75ba71..0e927ff 100644 --- a/src/options/cross-window.js +++ b/src/options/cross-window.js @@ -2,7 +2,7 @@ ./options/cross-window.js The cross-window option; provides the ability to emit and receive messages across - mupltiple browser tabs / windows within the same web browser. + multiple browser tabs / windows within the same web browser. */ msngr.extend((function (external, internal) { "use strict"; From da39f0a64cbf61aa74a39b2c372c42e561862e42 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sat, 30 May 2015 23:50:13 -0400 Subject: [PATCH 38/46] Re-wrote how msngr.extend() works by adding an msngr.merge() method that handles vairous ways of merging data. Revised and added unit tests to properly cover msngr.merge() msngr.extend() unit tests currently lacking Added throw command for invalid options Made payloads no longer be required to NOT be undefined when processing options --- msngr.js | 118 +++++++++++++++++++++++------ msngr.min.js | 2 +- src/main.aspec.js | 143 +++++++++++++++++++++++++---------- src/main.js | 109 ++++++++++++++++++++------ src/objects/message.aspec.js | 28 +++++++ src/objects/message.cspec.js | 3 - src/objects/message.js | 7 +- 7 files changed, 316 insertions(+), 94 deletions(-) diff --git a/msngr.js b/msngr.js index 1570836..36dd0d5 100644 --- a/msngr.js +++ b/msngr.js @@ -17,41 +17,106 @@ var msngr = msngr || (function () { external.version = "2.0.0"; - external.extend = function (obj, target) { - target = (target || external); - if (Object.prototype.toString.call(obj) === "[object Function]") { - obj = obj.apply(this, [external, internal]); + var twoMerge = function (input1, input2) { + if (input1 === undefined || input1 === null) { + return input2; } - if (Object.prototype.toString.call(obj) === "[object String]") { - if (Object.prototype.toString.call(target) === "[object String]") { - // Simple string concat operation - target = target + obj; - } else { - // Hmm what's the right move here? STRINGIFY! - target = JSON.stringify(target) + obj; - } + if (input2 === undefined || input2 === null) { + return input1; } - if (Object.prototype.toString.call(obj) === "[object Object]") { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - if (Object.prototype.toString.call(obj[key]) === "[object Object]") { - if (target[key] === undefined) { - target[key] = { }; + var result; + var type1 = Object.prototype.toString.call(input1); + var type2 = Object.prototype.toString.call(input2); + + if (type1 === "[object Object]" && type2 === "[object Object]") { + // Object merging time! + result = { }; + // Copy input1 into result + for (var key in input1) { + if (input1.hasOwnProperty(key)) { + result[key] = input1[key]; + } + } + for (var key in input2) { + if (input2.hasOwnProperty(key)) { + if (Object.prototype.toString.call(input2[key]) === "[object Object]") { + if (result[key] === undefined) { + result[key] = { }; } - target[key] = external.extend(obj[key], target[key]); - } else if (Object.prototype.toString.call(obj[key]) === "[object Array]") { - target[key] = (target[key] || []).concat(obj[key]); + result[key] = external.merge(input1[key], input2[key]); + } else if (Object.prototype.toString.call(input1[key]) === "[object Array]" && Object.prototype.toString.call(input2[key]) === "[object Array]") { + result[key] = (input1[key] || []).concat(input2[key]); } else { - target[key] = obj[key]; + result[key] = input2[key]; + } + } + } + return result; + } + + if (type1 === "[object String]" && type2 === "[object String]") { + result = input1 + input2; + return result; + } + + if (type1 === "[object Array]" && type2 === "[object Array]") { + result = input1.concat(input2); + return result; + } + + if (type1 === "[object Function]" && type2 === "[object Function]") { + return (function (i1, i2, args) { + return function () { + return external.merge(i1.apply(this, args), i2.apply(this, args)); + }; + }(input1, input2, arguments)); + } + + var similarObjectTypes = ["[object Function]", "[object Object]"]; + + if (similarObjectTypes.indexOf(type1) !== -1 && similarObjectTypes.indexOf(type2) !== -1) { + var method = (type1 === "[object Function]") ? input1 : input2; + var props = (type1 === "[object Object]") ? input1 : input2; + + if (method !== undefined && props !== undefined) { + for (var key in props) { + if (props.hasOwnProperty(key)) { + method[key] = props[key]; } } } + result = method; + return result; } + + return result; + }; + + external.extend = function (obj, target) { + target = (target || external); + + if (Object.prototype.toString.call(obj) === "[object Function]") { + obj = obj.apply(this, [external, internal]); + } + + target = external.merge(obj, target); + return target; }; + external.merge = function () { + var result; + if (arguments.length > 0) { + for (var i = 0; i < arguments.length; ++i) { + result = twoMerge(result, arguments[i]); + } + } + + return result; + }; + // Create a debug property to allow explicit exposure to the internal object structure. // This should only be used during unit test runs and debugging. Object.defineProperty(external, "debug", { @@ -670,7 +735,6 @@ msngr.extend((function (external, internal) { }; internal.processOpts = function (opts, message, payload, callback) { - payload = payload || { }; var optProcessors = []; for (var key in opts) { if (opts.hasOwnProperty(key) && external.exist(internal.options[key])) { @@ -691,7 +755,7 @@ msngr.extend((function (external, internal) { if (external.exist(results) && results.length > 0) { for (var i = 0; i < results.length; ++i) { if (external.exist(results[i])) { - result = external.extend(results[i], result); + result = external.merge(results[i], result); } } } @@ -797,6 +861,10 @@ msngr.extend((function (external, internal) { var msgObj = { option: function (key, value) { + if (!external.exist(key) || !external.isString(key)) { + throw internal.InvalidParametersException("option"); + } + options[key] = value; counts.options = counts.options + 1; @@ -974,7 +1042,7 @@ msngr.extend((function (external, internal) { ./options/cross-window.js The cross-window option; provides the ability to emit and receive messages across - mupltiple browser tabs / windows within the same web browser. + multiple browser tabs / windows within the same web browser. */ msngr.extend((function (external, internal) { "use strict"; diff --git a/msngr.min.js b/msngr.min.js index 4fe74dc..43ccd23 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};return external.version="2.0.0",external.extend=function(obj,target){if(target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),"[object String]"===Object.prototype.toString.call(obj)&&("[object String]"===Object.prototype.toString.call(target)?target+=obj:target=JSON.stringify(target)+obj),"[object Object]"===Object.prototype.toString.call(obj))for(var key in obj)obj.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(obj[key])?(void 0===target[key]&&(target[key]={}),target[key]=external.extend(obj[key],target[key])):target[key]="[object Array]"===Object.prototype.toString.call(obj[key])?(target[key]||[]).concat(obj[key]):obj[key]);return target},Object.defineProperty(external,"debug",{set:function(value){value===!0?external.internal=internal:value===!1&&delete external.internal},get:function(){return void 0!==external.internal}}),Object.defineProperty(external,"warnings",{set:function(value){internal.warnings=value},get:function(){return internal.warnings}}),external}();msngr.extend(function(external,internal){"use strict";return{argumentsToArray:function(args){return external.isArray(args)?args:external.isArguments(args)?Array.prototype.slice.call(args,0):[args]}}}),msngr.extend(function(external,internal){"use strict";return{isHtmlElement:function(obj){var t=this.getType(obj);return 0===t.indexOf("[object HTML")||0===t.indexOf("[object global]")},isNodeList:function(obj){return"[object NodeList]"===this.getType(obj)},findElement:function(element,root){var elms=external.findElements(element,root);return void 0!==elms&&elms.length>0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector,root){return external.querySelectorAllWithEq(selector,root)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var internal={warnings:!0},external=function(topic,category,dataType){return internal.objects.message(topic,category,dataType)};external.version="2.0.0";var twoMerge=function(input1,input2){if(void 0===input1||null===input1)return input2;if(void 0===input2||null===input2)return input1;var result,type1=Object.prototype.toString.call(input1),type2=Object.prototype.toString.call(input2);if("[object Object]"===type1&&"[object Object]"===type2){result={};for(var key in input1)input1.hasOwnProperty(key)&&(result[key]=input1[key]);for(var key in input2)input2.hasOwnProperty(key)&&("[object Object]"===Object.prototype.toString.call(input2[key])?(void 0===result[key]&&(result[key]={}),result[key]=external.merge(input1[key],input2[key])):result[key]="[object Array]"===Object.prototype.toString.call(input1[key])&&"[object Array]"===Object.prototype.toString.call(input2[key])?(input1[key]||[]).concat(input2[key]):input2[key]);return result}if("[object String]"===type1&&"[object String]"===type2)return result=input1+input2;if("[object Array]"===type1&&"[object Array]"===type2)return result=input1.concat(input2);if("[object Function]"===type1&&"[object Function]"===type2)return function(i1,i2,args){return function(){return external.merge(i1.apply(this,args),i2.apply(this,args))}}(input1,input2,arguments);var similarObjectTypes=["[object Function]","[object Object]"];if(-1!==similarObjectTypes.indexOf(type1)&&-1!==similarObjectTypes.indexOf(type2)){var method="[object Function]"===type1?input1:input2,props="[object Object]"===type1?input1:input2;if(void 0!==method&&void 0!==props)for(var key in props)props.hasOwnProperty(key)&&(method[key]=props[key]);return result=method}return result};return external.extend=function(obj,target){return target=target||external,"[object Function]"===Object.prototype.toString.call(obj)&&(obj=obj.apply(this,[external,internal])),target=external.merge(obj,target)},external.merge=function(){var result;if(arguments.length>0)for(var i=0;i0?elms[0]:elms},findElements:function(selector,root){var elm;if(external.isHtmlElement(selector)&&(elm=selector),void 0===elm&&external.isString(selector)){var doc=root||document,result=doc.querySelectorAll(selector);null!==result&&(elm=result)}return elm},getDomPath:function(element){var node=external.isHtmlElement(element)?element:void 0;return void 0===node?void 0:(void 0===node.id&&(node.id=external.id()),"#"+node.id)},querySelectorAllWithEq:function(selector,root){if(void 0===selector)return null;for(var doc=root||document,queue=[],process=function(input){if(-1===input.indexOf(":eq("))return void 0;var eqlLoc=input.indexOf(":eq("),sel=input.substring(0,eqlLoc),ind=input.substring(eqlLoc+4,input.indexOf(")",eqlLoc));selector=input.substring(input.indexOf(")",eqlLoc)+1,input.length),">"===sel.charAt(0)&&(sel=sel.substring(1,sel.length)),">"===selector.charAt(0)&&(selector=selector.substring(1,selector.length)),queue.push({selector:sel,index:parseInt(ind,10)})};-1!==selector.indexOf(":eq");)process(selector);for(var result;queue.length>0;){var item=queue.shift();result=(result||doc).querySelectorAll(item.selector)[item.index]}return selector.trim().length>0?(result||doc).querySelectorAll(selector):[result]},querySelectorWithEq:function(selector,root){return external.querySelectorAllWithEq(selector,root)[0]}}}),msngr.extend(function(external,internal){"use strict";return internal.InvalidParametersException=function(str){return{name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",str)}},internal.ReservedKeywordsException=function(keyword){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",keyword)}},internal.MangledException=function(variable,method){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",variable).replace("{method}",method)}},{}}),msngr.extend(function(external,internal){"use strict";var nowPerformance=function(){return performance.now()},nowNode=function(){return process.hrtime()[1]/1e6},nowLegacy=function(){return(new Date).getTime()},nowExec=void 0,nowExecDebugLabel="",lastNow=void 0;return{id:function(){var d=external.now(),uuid="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(c){var r=(d+16*Math.random())%16|0;return d=Math.floor(d/16),("x"==c?r:3&r|8).toString(16)});return uuid},now:function(noDuplicate){void 0===nowExec&&("undefined"!=typeof performance?(nowExec=nowPerformance,nowExecDebugLabel="performance"):"undefined"!=typeof process?(nowExec=nowNode,nowExecDebugLabel="node"):(nowExec=nowLegacy,nowExecDebugLabel="legacy"));var now=nowExec();return noDuplicate===!0&&lastNow===now?external.now(noDuplicate):(lastNow=now,now)},removeFromArray:function(arr,value){var inx=arr.indexOf(value),endIndex=arr.length-1;if(inx!==endIndex){var temp=arr[endIndex];arr[endIndex]=arr[inx],arr[inx]=temp}arr.pop()}}}),msngr.extend(function(external,internal){"use strict";return internal.reiterativeValidation=function(validationMethod,inputs){var result=!1;if(external.exist(validationMethod)&&external.exist(inputs)){external.isArray(inputs)||(inputs=[inputs]);for(var i=0;i0)for(var i=0;i0)for(var i=0;i0)for(var i=0;ii;++i){var found=external.findElements(selectors[i],doc);found.length>0&&(elements=elements.concat(Array.prototype.slice.call(found)))}if(0===elements.length)return void 0;for(var resultMap=void 0,elmLength=elements.length,unnamedTags=0,i=0;elmLength>i;++i){var key=void 0,elm=elements[i],nameAttr=elm.getAttribute("name"),idAttr=elm.id,tagName=elm.tagName.toLowerCase(),val=elm.value;external.exist(nameAttr)&&!external.isEmptyString(nameAttr)?key=nameAttr:external.exist(idAttr)&&!external.isEmptyString(idAttr)?key=idAttr:(key=tagName+unnamedTags,unnamedTags++),void 0===resultMap&&(resultMap={}),resultMap[key]=val}return resultMap},{}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/src/main.aspec.js b/src/main.aspec.js index 4bcbca2..3daa697 100644 --- a/src/main.aspec.js +++ b/src/main.aspec.js @@ -21,28 +21,32 @@ describe("./main.js", function () { expect(msngr.extend).to.exist; }); - it("msngr.extend(obj, target) - merges arrays from obj and target", function () { + it("msngr.merge(input1, input2) - expect method to exist", function () { + expect(msngr.merge).to.exist; + }); + + it("msngr.merge(input1, input2) - merges arrays from input1 and input2", function () { var obj1 = { test: [1, 2] }; var obj2 = { test: [3, 4] }; - msngr.extend(obj1, obj2); + var merged = msngr.merge(obj1, obj2); - expect(obj2.test).to.exist; - expect(obj2.test.length).to.equal(4); + expect(merged.test).to.exist; + expect(merged.test.length).to.equal(4); }); - it("msngr.extend(obj, target) - expect properties to merge from obj and target", function () { + it("msngr.merge(input1, input2) - expect properties to merge from input1 and input2", function () { var obj1 = { prop: "something" }; var obj2 = { some: "thing" }; - msngr.extend(obj1, obj2); + var merged = msngr.merge(obj1, obj2); - expect(obj2.some).to.exist; - expect(obj2.prop).to.exist; - expect(obj2.prop).to.equal("something"); + expect(merged.some).to.exist; + expect(merged.prop).to.exist; + expect(merged.prop).to.equal("something"); }); - it("msngr.extend(obj, target) - expect deeply nested methods to merge from obj and target", function () { + it("msngr.merge(input1, input2) - expect deeply nested methods to merge from input1 and input2", function () { var obj1 = { this: { is: { @@ -59,54 +63,111 @@ describe("./main.js", function () { whatever: function () { return "whatever"; } }; - msngr.extend(obj1, obj2); + var merged = msngr.merge(obj1, obj2); + + expect(merged.whatever).to.exist; + expect(merged.whatever()).to.equal("whatever"); - expect(obj2.whatever).to.exist; - expect(obj2.whatever()).to.equal("whatever"); + expect(merged.this).to.exist; + expect(merged.this.is).to.exist; + expect(merged.this.is.a).to.exist; + expect(merged.this.is.a.test).to.exist; + expect(merged.this.is.a.test.yup).to.exist; + expect(merged.this.is.a.test.yup()).to.equal("yup!"); + }); + + it("msngr.merge(input1, input2) - merges two methods together", function () { + var func1 = function () { return "test" }; + var func2 = function () { return "again" }; - expect(obj2.this).to.exist; - expect(obj2.this.is).to.exist; - expect(obj2.this.is.a).to.exist; - expect(obj2.this.is.a.test).to.exist; - expect(obj2.this.is.a.test.yup).to.exist; - expect(obj2.this.is.a.test.yup()).to.equal("yup!"); + var merged = msngr.merge(func1, func2); + expect(merged).to.exist; + expect(merged()).to.equal("testagain"); }); - it("msngr.extend(func, target) - extends a method with properties", function () { - var myTest = function () { + it("msngr.merge(input1, input2) - merges a method with properties", function () { + var myFunc = function () { return 15; }; - var func2 = function (external, internal) { - expect(external).to.exist; - expect(internal).to.exist; - - return { - val: 12 - }; + var myProps = { + something: "yup", + life: 42 }; - msngr.extend(func2, myTest); + var merged = msngr.merge(myFunc, myProps); - expect(myTest.val).to.exist; - expect(myTest.val).to.equal(12); - expect(myTest()).to.equal(15); + expect(merged).to.exist; + expect(merged.something).to.exist; + expect(merged.life).to.exist; + expect(merged.something).to.equal("yup"); + expect(merged.life).to.equal(42); + expect(merged()).to.equal(15); }); - it("msngr.extend(undefined, target) - extending undefined value is simply ignored", function () { + it("msngr.merge(input1, input2) - merging undefined value is simply ignored", function () { var myTest = { }; - msngr.extend(undefined, myTest); + var merged = msngr.merge(undefined, myTest); - expect(myTest).to.exist; - expect(Object.keys(myTest).length).to.equal(0); + expect(merged).to.exist; + expect(Object.keys(merged).length).to.equal(0); }); - it("msngr.extend(string1, string2) - Property extends a string with another string", function () { + it("msngr.merge(input1, input2) - Property extends a string with another string", function () { var t = "something"; - var result = msngr.extend("whatever", t); - expect(result).to.exist; - expect(msngr.getType(result)).to.equal("[object String]"); - expect(result).to.equal("somethingwhatever"); + var merged = msngr.merge("whatever", t); + expect(merged).to.exist; + expect(msngr.getType(merged)).to.equal("[object String]"); + expect(merged).to.equal("whateversomething"); + }); + + it("msngr.merge(input1, input2) - Overwrites properly", function () { + var first = { val1: "stuff" }; + var second = { val1: 17 }; + + var merged = msngr.merge(first, second); + expect(merged).to.exist; + expect(merged.val1).to.exist; + expect(merged.val1).to.equal(17); + }); + + it("msngr.merge(input1, input2, input3, input4, input5, input6, input7, input8) - Overwrites properly with multiple parameters", function () { + var first = { val1: "stuff" }; + var second = { val1: 17 }; + var third = { val1: "chicken nuggets" }; + var fourth = { val1: function () { } }; + var fifth = { val1: null }; + var sixth = { val1: 1 }; + var seventh = { val1: [0, 1, 2] }; + var eighth = { val1: "hockey" }; + + var merged1 = msngr.merge(first, second, third); + var merged2 = msngr.merge(first, second, third, fourth); + var merged3 = msngr.merge(first, second, third, fourth, fifth); + var merged4 = msngr.merge(first, second, third, fourth, fifth, sixth); + var merged5 = msngr.merge(first, second, third, fourth, fifth, sixth, seventh); + var merged6 = msngr.merge(first, second, third, fourth, fifth, sixth, seventh, eighth); + + expect(merged1).to.exist; + expect(merged2).to.exist; + expect(merged3).to.exist; + expect(merged4).to.exist; + expect(merged5).to.exist; + expect(merged6).to.exist; + + expect(merged1.val1).to.exist; + expect(merged2.val1).to.exist; + expect(merged3.val1).to.not.exist; + expect(merged4.val1).to.exist; + expect(merged5.val1).to.exist; + expect(merged6.val1).to.exist; + + expect(merged1.val1).to.equal("chicken nuggets"); + expect(msngr.getType(merged2.val1)).to.equal("[object Function]"); + expect(merged3.val1).to.equal(null); + expect(merged4.val1).to.equal(1); + expect(merged5.val1.length).to.equal(3); + expect(merged6.val1).to.equal("hockey"); }); it("msngr.debug - property setting exports internal object for testing and debugging", function () { diff --git a/src/main.js b/src/main.js index 0334993..0df06b5 100644 --- a/src/main.js +++ b/src/main.js @@ -17,41 +17,106 @@ var msngr = msngr || (function () { external.version = "2.0.0"; - external.extend = function (obj, target) { - target = (target || external); - if (Object.prototype.toString.call(obj) === "[object Function]") { - obj = obj.apply(this, [external, internal]); + var twoMerge = function (input1, input2) { + if (input1 === undefined || input1 === null) { + return input2; } - if (Object.prototype.toString.call(obj) === "[object String]") { - if (Object.prototype.toString.call(target) === "[object String]") { - // Simple string concat operation - target = target + obj; - } else { - // Hmm what's the right move here? STRINGIFY! - target = JSON.stringify(target) + obj; - } + if (input2 === undefined || input2 === null) { + return input1; } - if (Object.prototype.toString.call(obj) === "[object Object]") { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - if (Object.prototype.toString.call(obj[key]) === "[object Object]") { - if (target[key] === undefined) { - target[key] = { }; + var result; + var type1 = Object.prototype.toString.call(input1); + var type2 = Object.prototype.toString.call(input2); + + if (type1 === "[object Object]" && type2 === "[object Object]") { + // Object merging time! + result = { }; + // Copy input1 into result + for (var key in input1) { + if (input1.hasOwnProperty(key)) { + result[key] = input1[key]; + } + } + for (var key in input2) { + if (input2.hasOwnProperty(key)) { + if (Object.prototype.toString.call(input2[key]) === "[object Object]") { + if (result[key] === undefined) { + result[key] = { }; } - target[key] = external.extend(obj[key], target[key]); - } else if (Object.prototype.toString.call(obj[key]) === "[object Array]") { - target[key] = (target[key] || []).concat(obj[key]); + result[key] = external.merge(input1[key], input2[key]); + } else if (Object.prototype.toString.call(input1[key]) === "[object Array]" && Object.prototype.toString.call(input2[key]) === "[object Array]") { + result[key] = (input1[key] || []).concat(input2[key]); } else { - target[key] = obj[key]; + result[key] = input2[key]; } } } + return result; + } + + if (type1 === "[object String]" && type2 === "[object String]") { + result = input1 + input2; + return result; } + + if (type1 === "[object Array]" && type2 === "[object Array]") { + result = input1.concat(input2); + return result; + } + + if (type1 === "[object Function]" && type2 === "[object Function]") { + return (function (i1, i2, args) { + return function () { + return external.merge(i1.apply(this, args), i2.apply(this, args)); + }; + }(input1, input2, arguments)); + } + + var similarObjectTypes = ["[object Function]", "[object Object]"]; + + if (similarObjectTypes.indexOf(type1) !== -1 && similarObjectTypes.indexOf(type2) !== -1) { + var method = (type1 === "[object Function]") ? input1 : input2; + var props = (type1 === "[object Object]") ? input1 : input2; + + if (method !== undefined && props !== undefined) { + for (var key in props) { + if (props.hasOwnProperty(key)) { + method[key] = props[key]; + } + } + } + result = method; + return result; + } + + return result; + }; + + external.extend = function (obj, target) { + target = (target || external); + + if (Object.prototype.toString.call(obj) === "[object Function]") { + obj = obj.apply(this, [external, internal]); + } + + target = external.merge(obj, target); + return target; }; + external.merge = function () { + var result; + if (arguments.length > 0) { + for (var i = 0; i < arguments.length; ++i) { + result = twoMerge(result, arguments[i]); + } + } + + return result; + }; + // Create a debug property to allow explicit exposure to the internal object structure. // This should only be used during unit test runs and debugging. Object.defineProperty(external, "debug", { diff --git a/src/objects/message.aspec.js b/src/objects/message.aspec.js index 13414d7..cb97c62 100644 --- a/src/objects/message.aspec.js +++ b/src/objects/message.aspec.js @@ -107,6 +107,34 @@ describe("./objects/message.js", function () { expect(m3.message.dataType).to.not.equal(m4.message.dataType); }); + it("msngr().option() - handles invalid input correctly", function () { + expect(msngr("TestTopic").option.bind({})).to.throw; + expect(msngr("TestTopic").option.bind(7)).to.throw; + expect(msngr("TestTopic").option.bind()).to.throw; + }); + + it("msngr().option() - custom option processor works as expected", function (done) { + msngr.internal.options["testsync"] = function (message, payload, options, async) { + return "synced!"; + }; + + var msg = msngr("MyTopic").option("testsync").on(function (payload) { + expect(payload).to.exist; + expect(payload).to.equal("synced!"); + + msngr.internal.options["testasync"] = function (message, payload, options, async) { + var d = async(); + d({ words: "asynced!" }); + }; + + var msg2 = msngr("AnotherTopic").option("testasync").on(function (payload2) { + expect(payload2).to.exist; + expect(payload2.words).to.equal("asynced!"); + done(); + }).emit(); + }).emit(); + }); + it("msngr().emit() / on() - Successfully emits and handles a topic only message", function (done) { var msg = msngr("MyTopic"); msg.on(function (payload) { diff --git a/src/objects/message.cspec.js b/src/objects/message.cspec.js index dd64365..5c6ea64 100644 --- a/src/objects/message.cspec.js +++ b/src/objects/message.cspec.js @@ -29,7 +29,6 @@ describe("./objects/message.js", function () { var div = document.createElement("div"); msngr("MyTopic").bind(div, "testEvent").on(function (payload) { - expect(payload).to.exist; done(); }); @@ -42,7 +41,6 @@ describe("./objects/message.js", function () { var div = document.createElement("div"); msngr("MyTopic", "MyCategory").bind(div, "testEvent").on(function (payload) { - expect(payload).to.exist; done(); }); @@ -55,7 +53,6 @@ describe("./objects/message.js", function () { var div = document.createElement("div"); msngr("MyTopic", "MyCategory", "MyDataType").bind(div, "testEvent").on(function (payload) { - expect(payload).to.exist; done(); }); diff --git a/src/objects/message.js b/src/objects/message.js index f0c5993..bc44269 100644 --- a/src/objects/message.js +++ b/src/objects/message.js @@ -50,7 +50,6 @@ msngr.extend((function (external, internal) { }; internal.processOpts = function (opts, message, payload, callback) { - payload = payload || { }; var optProcessors = []; for (var key in opts) { if (opts.hasOwnProperty(key) && external.exist(internal.options[key])) { @@ -71,7 +70,7 @@ msngr.extend((function (external, internal) { if (external.exist(results) && results.length > 0) { for (var i = 0; i < results.length; ++i) { if (external.exist(results[i])) { - result = external.extend(results[i], result); + result = external.merge(results[i], result); } } } @@ -177,6 +176,10 @@ msngr.extend((function (external, internal) { var msgObj = { option: function (key, value) { + if (!external.exist(key) || !external.isString(key)) { + throw internal.InvalidParametersException("option"); + } + options[key] = value; counts.options = counts.options + 1; From b3fe2e4e8a4782270c1438a2b770c1c202ec254c Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 02:14:36 -0400 Subject: [PATCH 39/46] Added unit test for extend --- src/main.aspec.js | 23 +++++++++++++++++++---- src/main.js | 3 +++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/main.aspec.js b/src/main.aspec.js index 3daa697..0fc824f 100644 --- a/src/main.aspec.js +++ b/src/main.aspec.js @@ -17,10 +17,6 @@ describe("./main.js", function () { expect(msngr).to.exist; }); - it("msngr.extend(obj, target) - expect method to exist", function () { - expect(msngr.extend).to.exist; - }); - it("msngr.merge(input1, input2) - expect method to exist", function () { expect(msngr.merge).to.exist; }); @@ -170,6 +166,25 @@ describe("./main.js", function () { expect(merged6.val1).to.equal("hockey"); }); + it("msngr.extend(obj, target) - expect method to exist", function () { + expect(msngr.extend).to.exist; + }); + + it("msngr.extend(obj, target) - extend msngr", function () { + msngr.extend((function (external, internal) { + return { + sayHello: function () { + return "hello"; + } + }; + })); + + expect(msngr.sayHello).to.exist; + expect(msngr.sayHello()).to.equal("hello"); + + delete msngr.sayHello; + }); + it("msngr.debug - property setting exports internal object for testing and debugging", function () { msngr.debug = false; expect(msngr.internal).to.not.exist; diff --git a/src/main.js b/src/main.js index 0df06b5..526274d 100644 --- a/src/main.js +++ b/src/main.js @@ -7,16 +7,19 @@ var msngr = msngr || (function () { "use strict"; + // Defaults for some internal functions var internal = { warnings: true }; + // The main method for msngr uses the message object var external = function (topic, category, dataType) { return internal.objects.message(topic, category, dataType); }; external.version = "2.0.0"; + // Merge two inputs into one var twoMerge = function (input1, input2) { if (input1 === undefined || input1 === null) { return input2; From 68996e8477efe5a6fad7e8ac0068d3f06a985a1c Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 02:14:55 -0400 Subject: [PATCH 40/46] Improved unit tests for cross-window testing --- crossWindowVerifier.html | 21 ++++++++++++++++++--- crossWindowVerifier.min.html | 21 ++++++++++++++++++--- msngr.js | 3 +++ src/options/cross-window.cspec.js | 29 ++++++++++++++--------------- 4 files changed, 53 insertions(+), 21 deletions(-) diff --git a/crossWindowVerifier.html b/crossWindowVerifier.html index a4f038e..416e7ef 100644 --- a/crossWindowVerifier.html +++ b/crossWindowVerifier.html @@ -6,9 +6,24 @@ diff --git a/crossWindowVerifier.min.html b/crossWindowVerifier.min.html index d52fbac..dbd9d61 100644 --- a/crossWindowVerifier.min.html +++ b/crossWindowVerifier.min.html @@ -6,9 +6,24 @@ diff --git a/msngr.js b/msngr.js index 36dd0d5..2ac2534 100644 --- a/msngr.js +++ b/msngr.js @@ -7,16 +7,19 @@ var msngr = msngr || (function () { "use strict"; + // Defaults for some internal functions var internal = { warnings: true }; + // The main method for msngr uses the message object var external = function (topic, category, dataType) { return internal.objects.message(topic, category, dataType); }; external.version = "2.0.0"; + // Merge two inputs into one var twoMerge = function (input1, input2) { if (input1 === undefined || input1 === null) { return input2; diff --git a/src/options/cross-window.cspec.js b/src/options/cross-window.cspec.js index 0a05f51..5bdfa40 100644 --- a/src/options/cross-window.cspec.js +++ b/src/options/cross-window.cspec.js @@ -13,6 +13,8 @@ if (typeof msngr === "undefined" && typeof window === "undefined") { describe("./options/cross-window.js", function () { "use strict"; + this.timeout(60000); + before(function () { msngr.debug = true; }); @@ -25,28 +27,25 @@ describe("./options/cross-window.js", function () { msngr.debug = false; }); - it("msngr().option('cross-window') - sends a message between different tabs or windows", function (done) { + it("msngr().option('cross-window') - sends a 100 messages between different tabs or windows", function (done) { var crossWindowVerifierPath = (window.specRunner.indexOf(".min.html") === -1) ? "crossWindowVerifier.html" : "crossWindowVerifier.min.html"; - var test1 = false; - var test2 = false; - var test3 = false; + var testCounts = 0; + var observedTests = { }; var iframe = document.createElement("iframe"); var msg = msngr("CrossWindow", "Message"); msg.on(function (payload) { - if (payload === "VerificationCrossTest1") { - test1 = true; - } - - if (payload === "VerificationCrossTest2") { - test2 = true; - } - - if (payload === "VerificationCrossTest3") { - test3 = true; + expect(payload).to.exist; + expect(payload.data.meaningOfLife).to.equal(42); + expect(payload.data.OPDelivers).to.equal(false); + expect(payload.data.text).to.equal("something"); + + if (observedTests[payload.id] === undefined) { + testCounts++; + observedTests[payload.id] = payload; } - if (test1 && test2 && test3) { + if (testCounts === 100) { document.querySelector("body").removeChild(iframe); done(); } From a712a91c6621b0968b2c32e535429b9a22cc5c45 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 02:22:37 -0400 Subject: [PATCH 41/46] Documented msngr.extend()and msngr.merge() --- docs/api.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/api.md b/docs/api.md index 703a467..2a3881f 100644 --- a/docs/api.md +++ b/docs/api.md @@ -232,6 +232,34 @@ var elms = msngr.querySelectorAllWithEq("div:eq(1) > input"); ## Miscellaneous utilities There are multiple utility methods included in msngr. Some are used internally and some are exposed for external use by others. +### ```msngr.extend(obj, target)``` +Extends either the msngr object or a specified target object. + +```obj (required)``` - The object used to extend a target. If it's a method it is executed and passed in the external and interface interfaces of msngr. + +```target (optional)``` - The target of the extend. If not specified it is assumed you are extending the msngr object. + +```javascript +msngr.extend({ + sayHello: function () { + return "Hello!"; + } +}); + +console.log(msngr.sayHello()); +``` + +### ```msngr.merge(input1, input2, ..., inputN)``` +Merges an n number of inputs together. Combines objects with other objects (the merging overwrites in order should conflict arrise), functions with objects, strings and strings and arrays. + +```inputn (required)``` - Specify as many parameters as necessary for merging. + +```javascript +var merged = msngr.merge({ val1: "test" }, { val2: "whatever!" }, { val2: "no!" }); +console.log(merged.val1); // Prints "test" +console.log(merged.val2); // Prints "no!" +``` + ### ```msngr.exist(obj)``` Returns false if obj is undefined or null otherwise true. From 7d7e6b88b7b516da214c0f975ab5635d9e04f4d3 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 03:32:19 -0400 Subject: [PATCH 42/46] TONS of documentation --- README.md | 21 +++++++- docs/api.aspec.js | 27 ----------- docs/api.cspec.js | 27 ----------- docs/binding and the dom.cspec.js | 27 ----------- docs/binding and the dom.md | 1 - docs/extending and hacking.aspec.js | 27 ----------- docs/extending and hacking.md | 74 +++++++++++++++++++++++++++++ docs/messaging patterns.aspec.js | 27 ----------- docs/messaging patterns.md | 3 -- docs/web browser niceties.md | 70 +++++++++++++++++++++++++++ 10 files changed, 163 insertions(+), 141 deletions(-) delete mode 100644 docs/api.aspec.js delete mode 100644 docs/api.cspec.js delete mode 100644 docs/binding and the dom.cspec.js delete mode 100644 docs/binding and the dom.md delete mode 100644 docs/extending and hacking.aspec.js delete mode 100644 docs/messaging patterns.aspec.js create mode 100644 docs/web browser niceties.md diff --git a/README.md b/README.md index b9b932f..3904888 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![npm version](https://badge.fury.io/js/msngr.svg)](http://badge.fury.io/js/msngr) [![Bower version](https://badge.fury.io/bo/msngr.js.svg)](http://badge.fury.io/bo/msngr.js) [![Build Status](https://travis-ci.org/KrisSiegel/msngr.js.svg)](https://travis-ci.org/KrisSiegel/msngr.js/) [![Dependency Status](https://gemnasium.com/KrisSiegel/msngr.js.svg)](https://gemnasium.com/KrisSiegel/msngr.js) ## What is msngr.js? -msngr.js is a small library for facilitating communication between components through messages. Messages can be sent and received between any JavaScript code within the browser or server-side with node or io.js. Messages can also be bound to DOM elements and their specific events to allow for loose coupling of the user interface to your application logic. +msngr.js is a small library for facilitating communication between components through abstract messages within the same application be it server or client side. It also provides binding messages directly to DOM elements and even sending payloads between browser tabs / windows. The following example shows how to bind a message to a click event of a DOM element while gathering up the values in the related inputs for payload delivery. ```HTML @@ -28,12 +28,29 @@ While msngr.js isn't very large the documentation has been split up for easy rea [Messaging patterns](docs/messaging patterns.md) - Explains how to use the basic messaging features of msngr.js with some typical patterns. -[Binding and the DOM](docs/binding and the dom.md) - This covers binding msngr.js to elements and events, unbinding them and how to gather up values from various types of elements. +[Web browser niceties](docs/web browser niceties.md) - This covers binding msngr.js to elements and events, unbinding them, how to gather up values from various types of elements and cross-window communication. [Extending and hacking](docs/extending and hacking.md) - Want to extend the capabilities of msngr.js? It's actually quite easy and this document covers it. Using msngr.js deep in a production system then suddenly find *something* that you need to change to avoid catastrophe? Hacking msngr.js is also covered for those times when you need *unorthodox* solutions :) [Contributing](docs/contributing.md) - Want to contributed to msngr.js? There are a couple of things you should know before you submit that pull request to better ensure it gets accepted :) +## Roadmap +The current release of msngr.js works in node.js for server-side messaging as well as the web browser. The web browser has some extra features like messaging between windows and binding to DOM elements but future features will receive more focus on the core of msngr.js with more node.js fun! + +### What's Next? +Below is what's being worked on for future 2.x releases. + +* Web Socket Messaging - Easy web socket communication with messages between a server and client. + +* Feature detection - Support verifying what certain features can work in the environment they're in (e.g. older web browsers). When they cannot log a warning and disable the feature (warnings will be toggle-able). + +* Better browser support - Currently msngr.js should work in most current web browsers but some features may not work well in older versions of Internet Explorer and really old versions of Firefox. Additional testing and tweaking needs to be conducted for older browser support and to provide a baseline for what is or isn't supported. + +* Benchmarking and optimization - Now that the majority of msngr.js's structure is written and fairly solidified we need to begin benchmarking along with profiling and optimization. Optimization had previously been ignored while the API was finalized and while msngr.js is really fast it needs to be *scientifically* fast. + +### What's Next Next? +At this point further planning will occur once more community feedback comes through. I have a few ideas involving integration into other messaging systems, some streaming ideas and a few optional extensions that provide message based APIs for other libraries but I'm hesitant to *only* go in one direction should other needs arise. + For questions, news, and whatever else that doesn't fit in GitHub issues you can follow me [@KrisSiegel](https://twitter.com/KrisSiegel) Copyright © 2014-2015 Kris Siegel diff --git a/docs/api.aspec.js b/docs/api.aspec.js deleted file mode 100644 index c44ef76..0000000 --- a/docs/api.aspec.js +++ /dev/null @@ -1,27 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../msngr"); -} - -describe("./docs/api.md", function () { - "use strict"; - - before(function () { - msngr.debug = true; - }); - - beforeEach(function () { - msngr.internal.reset(); - }); - - after(function () { - msngr.debug = false; - }); -}); diff --git a/docs/api.cspec.js b/docs/api.cspec.js deleted file mode 100644 index c44ef76..0000000 --- a/docs/api.cspec.js +++ /dev/null @@ -1,27 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../msngr"); -} - -describe("./docs/api.md", function () { - "use strict"; - - before(function () { - msngr.debug = true; - }); - - beforeEach(function () { - msngr.internal.reset(); - }); - - after(function () { - msngr.debug = false; - }); -}); diff --git a/docs/binding and the dom.cspec.js b/docs/binding and the dom.cspec.js deleted file mode 100644 index c7b8d9b..0000000 --- a/docs/binding and the dom.cspec.js +++ /dev/null @@ -1,27 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../msngr"); -} - -describe("./docs/binding and the dom.md", function () { - "use strict"; - - before(function () { - msngr.debug = true; - }); - - beforeEach(function () { - msngr.internal.reset(); - }); - - after(function () { - msngr.debug = false; - }); -}); diff --git a/docs/binding and the dom.md b/docs/binding and the dom.md deleted file mode 100644 index fae3db4..0000000 --- a/docs/binding and the dom.md +++ /dev/null @@ -1 +0,0 @@ -# Binding and the DOM diff --git a/docs/extending and hacking.aspec.js b/docs/extending and hacking.aspec.js deleted file mode 100644 index 1ae9ed3..0000000 --- a/docs/extending and hacking.aspec.js +++ /dev/null @@ -1,27 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../msngr"); -} - -describe("./docs/extending and hacking.md", function () { - "use strict"; - - before(function () { - msngr.debug = true; - }); - - beforeEach(function () { - msngr.internal.reset(); - }); - - after(function () { - msngr.debug = false; - }); -}); diff --git a/docs/extending and hacking.md b/docs/extending and hacking.md index 193bafd..dc71ebd 100644 --- a/docs/extending and hacking.md +++ b/docs/extending and hacking.md @@ -1 +1,75 @@ # Extending and hacking +A big part of my development background has been dealing with other people's libraries. Sometimes they're great and sometimes they're not. Regardless of how great (or not great) they are I've been in multiple situations where I need to make a critical change and it's difficult or impossible to do without modifying the original source (which is sometimes hosted on a CDN that can't change). + +With this in mind I tried to make msngr.js approachable to extend or hack. Hopefully I did a good enough job :) + +## Two ways of extending / enhancing +There are two ways of extending msngr.js depending on what you want to do and they both use the same msngr.extend() method. + +### Extending top level methods of msngr.js +The msngr.extend() method allows you to specify an object to mix with msngr. This is pretty straight forward and a basic way to get new methods into the top level of the msngr object. + +```javascript +msngr.extend({ + sayHello: function () { + console.log("Hello, msngr.js!"); + } +}); + +msngr.sayHello(); // Prints "Hello, msngr.js!" +``` + +### Adding options +You can also supply a method which is provided the external and internal interfaces of msngr as arguments then takes the result and mixes it with the msngr object. This is how you can add additional options to msngr to use on a message object. Note that this is pretty raw as it exposes you to the internal interface of msngr. + +```javascript +msngr.extend(function (external, internal) { + internal.options["my option"] = function (message, payload, options, async) { + var config = options["my option"]; + var done = async(); + // Do something here + done("My Result"); + }; + + return { }; // Optionally return an object that gets mixed with the msngr object +}); + +var msg = msngr("MyTopic"); +msg.option("my option", { configurationValue: true }); +msg.on(function (payload) { + console.log(payload); // Prints "My Result"; +}); +msg.emit(); +``` + +So first we passed in a method to msngr.extend(). This automatically gives us access to two parameters: ```external``` and ```internal```. + +```external``` provides access to all top level msngr methods without requiring the name 'msngr' should it later need to be changed due to the environment (such as multiple versions of msngr). + +```internal``` is a raw object with a set of objects, methods, properties and other items that are internally accessible to all msngr components. Here we add our new option method to an options object where, upon each execution, we receive a message, the payload, an optional configuration object (which includes configurations for *all* options to be executed for this message, not just your option) and an async method that allows a return value to be returned asynchronously. + +So what happens when your option returns a value? This value is taken and merged with the payload that is already being sent to the handler. So take caution that you're not doing anything funny with the payload. + +## Okay so what about 'hacking'? +So if you look at the ways of extending msngr.js you will notice that you can access the internal interface really easily. This lets you do *anything* to msngr.js. + +So let's say you want have the memory indexer that msngr uses to index messages and you want to replace it. You could change code and submit a pull request but let's say you find an issue you need to fix NOW and you're in an environment where msngr is already approved and you can't change its code. What do you do!? + +It's actually kinda easy :) + + +```javascript +msngr.extend(function (external, internal) { + internal.objects.memory = function () { + return { + // API goes here + }; + }; +}); +``` + +So the example isn't filled out but you just replaced the memory indexer with an empty JavaScript object. Obviously this will break msngr.js pretty badly but you could now write your own indexer and drop it in here. + +You can do this with many other things in the internal interface, too. There is a message object that handles all messaging you could modify, extend or even replace. + +Enjoy! diff --git a/docs/messaging patterns.aspec.js b/docs/messaging patterns.aspec.js deleted file mode 100644 index b092310..0000000 --- a/docs/messaging patterns.aspec.js +++ /dev/null @@ -1,27 +0,0 @@ -if (typeof chai === "undefined" && typeof window === "undefined") { - var chai = require("chai"); -} - -if (typeof expect === "undefined") { - var expect = chai.expect; -} - -if (typeof msngr === "undefined" && typeof window === "undefined") { - var msngr = require("../msngr"); -} - -describe("./docs/messaging patterns.md", function () { - "use strict"; - - before(function () { - msngr.debug = true; - }); - - beforeEach(function () { - msngr.internal.reset(); - }); - - after(function () { - msngr.debug = false; - }); -}); diff --git a/docs/messaging patterns.md b/docs/messaging patterns.md index 62438c2..575a996 100644 --- a/docs/messaging patterns.md +++ b/docs/messaging patterns.md @@ -71,6 +71,3 @@ In the above example there are a several things to take note of. First the usage After that, using an environment configuration, you can choose to load ```MySQLBackend.js``` or ```MemoryBackend.js```. Both use the exact same messaging handlers, one works asynchronously and the other synchronously but the receiving end (the callback specified in emit) gets the data in the same way regardless. Neat, right? - -## Persisted merging -Alright so we have the idea that we can separate logic and implementation, we can bring results back via ```emit()``` and we can persist messages or data via ```persist()```. But what happens if you persist multiple things under the same message? What if you persist multiple things under multiple messages then setup a handler that gets hit by multiple persists? Why we merge is what we do! So let's check out an example. diff --git a/docs/web browser niceties.md b/docs/web browser niceties.md new file mode 100644 index 0000000..7f3cee6 --- /dev/null +++ b/docs/web browser niceties.md @@ -0,0 +1,70 @@ +# Web browser niceties +While msngr.js has plenty of generic capability that can run under node.js and a web browser it includes a few nice features that only work in web browsers. + +## Cross window communication +Have you ever used a web browser where you had multiple instances of a web application open? There are many use-cases where this may happen but what do you do if a change happens in window 1 then you look at window 2? You could setup a one-off call using postMessage or make your web app revolve around the data inside of localStorage and listen to its events. But that can be annoying especially if you didn't realize your users even want this until it's too late to make such structural changes. + +With msngr.js you can use the same interfaces already available for messaging and send them across windows! Let's just jump into an example. + +```javascript +// Window 1 +var msg = msngr("Notifications", "Count"); +msg.option("cross-window"); +msg.on(function (payload) { + var notificationElm = document.querySelector("#NotificationCount"); + notificationElm.innerHTML = payload; +}); + +msg.emit(5); +``` + +```javascript +// Window 2 +var msg = msngr("Notifications", "Count"); +msg.option("cross-window"); +msg.on(function (payload) { + var notificationElm = document.querySelector("#NotificationCount"); + notificationElm.innerHTML = payload; +}); +``` + +Both windows use the same code and message to update a notification count. Window 1 decides its time to update the notification count to 5. Both windows will receive this value within these handlers. Neat, right? + +## Binding messages to DOM elements +We can take a message and bind it directly to an element's event letting you keep your code separate from even dealing with an object's eventing directly. + +```html + + +``` + +```javascript +var msg = msngr("User", "Save"); +msg.bind("button[name=save]", "click"); +msg.on(function (payload) { + // The user clicked the payload button +}); +``` + +So this lets you take a message, a message's handler and bind it directly to an element's event. This is helpful in keeping your code separate and you can even unit test by directly emitting to the same handler! + +But you still have to get that username so your code still has to hit the dom thus ruining your true code separation of presentation and business logic. Right? + +## The DOM option +Adding options to your messages allow you to take advantage of additional extensions within msngr.js. The 'dom' option allows the specifying of selectors which, upon being emitted, are used to gather and aggrevate values. Take a look at this example: + +```html + + +``` + +```javascript +var msg = msngr("User", "Save"); +msg.bind("button[name=save]", "click"); +msg.option("dom", ["input[name=username]"]); +msg.on(function (payload) { + console.log(payload.username); // The value in the username field +}); +``` + +The 'dom' option takes an array of selectors which then grab a value and puts it in the payload either by the name of the element or it generates a property itself with a tag name. Pretty handy, right? Now you can write code that handles a click event on a form and have *ZERO* DOM code in the actual handler. From 3ad8512deefb0801dc66b144deeed2a3107c6ba1 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 03:35:27 -0400 Subject: [PATCH 43/46] Tweak --- docs/web browser niceties.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/web browser niceties.md b/docs/web browser niceties.md index 7f3cee6..4822157 100644 --- a/docs/web browser niceties.md +++ b/docs/web browser niceties.md @@ -1,5 +1,5 @@ # Web browser niceties -While msngr.js has plenty of generic capability that can run under node.js and a web browser it includes a few nice features that only work in web browsers. +While msngr.js has plenty of generic capability that can run under node.js and a web browser it also includes a few nice features that only work in web browsers. ## Cross window communication Have you ever used a web browser where you had multiple instances of a web application open? There are many use-cases where this may happen but what do you do if a change happens in window 1 then you look at window 2? You could setup a one-off call using postMessage or make your web app revolve around the data inside of localStorage and listen to its events. But that can be annoying especially if you didn't realize your users even want this until it's too late to make such structural changes. From d71febb76044d1f51c2529184f83aeaaba198365 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 03:42:24 -0400 Subject: [PATCH 44/46] Fixed sentence being terrible --- docs/extending and hacking.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/extending and hacking.md b/docs/extending and hacking.md index dc71ebd..06cfd92 100644 --- a/docs/extending and hacking.md +++ b/docs/extending and hacking.md @@ -53,7 +53,7 @@ So what happens when your option returns a value? This value is taken and merged ## Okay so what about 'hacking'? So if you look at the ways of extending msngr.js you will notice that you can access the internal interface really easily. This lets you do *anything* to msngr.js. -So let's say you want have the memory indexer that msngr uses to index messages and you want to replace it. You could change code and submit a pull request but let's say you find an issue you need to fix NOW and you're in an environment where msngr is already approved and you can't change its code. What do you do!? +So let's say you want to change the memory indexer that msngr uses to index messages by replacing it. You could change code and submit a pull request but let's say you find an issue you need to fix NOW and you're in an environment where msngr is already approved and you can't change its code. What do you do!? It's actually kinda easy :) From aa5db4118570f1ca3deb7c128d8a4360e44daa4e Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 03:42:48 -0400 Subject: [PATCH 45/46] Let's drop io.js support in travis; it's going away anyway --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 003243e..cea39f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,4 @@ node_js: - "0.12" - "0.11" - "0.10" - - "iojs" before_install: npm install -g grunt-cli mocha-phantomjs phantomjs From 72b5112a01badcbdf0c9cc7b8c84f79d96907752 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Sun, 31 May 2015 03:46:48 -0400 Subject: [PATCH 46/46] Ignore crossWindowVerifier files Remove devDependency badge --- .gitignore | 2 ++ README.md | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fd5ce69..d86b63d 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ node_modules # msngr.js specific specRunner.html specRunner.min.html +crossWindowVerifier.html +crossWindowVerifier.min.html diff --git a/README.md b/README.md index 3904888..8fc8cb5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # msngr.js -[![npm version](https://badge.fury.io/js/msngr.svg)](http://badge.fury.io/js/msngr) [![Bower version](https://badge.fury.io/bo/msngr.js.svg)](http://badge.fury.io/bo/msngr.js) [![Build Status](https://travis-ci.org/KrisSiegel/msngr.js.svg)](https://travis-ci.org/KrisSiegel/msngr.js/) [![Dependency Status](https://gemnasium.com/KrisSiegel/msngr.js.svg)](https://gemnasium.com/KrisSiegel/msngr.js) +[![npm version](https://badge.fury.io/js/msngr.svg)](http://badge.fury.io/js/msngr) [![Bower version](https://badge.fury.io/bo/msngr.js.svg)](http://badge.fury.io/bo/msngr.js) [![Build Status](https://travis-ci.org/KrisSiegel/msngr.js.svg)](https://travis-ci.org/KrisSiegel/msngr.js/) ## What is msngr.js? msngr.js is a small library for facilitating communication between components through abstract messages within the same application be it server or client side. It also provides binding messages directly to DOM elements and even sending payloads between browser tabs / windows.