3

I created one js library(MessageBus.js) and made it compatible with requirejs. Now I want to use the same lib without requirejs i.e. by creating object(new MessageBus()).

I am attaching my lib with this post.

define([], function () {

var MessageBus = function () {
    this.channelCallBackMap = {};
    this.alreadyRegistred = false;
}

MessageBus.prototype = {
    publish: function (channel, message) {
        //Put original message and channel in the envelope and send it
        var envelope = {
            channel: channel,
            message: message
        };
        var domain = location.protocol + '//' + location.host;
        //Send message to all sibling iframes in the parent document
        $("iframe", parent.document.body).each(function (i, frame) {
            frame.contentWindow.postMessage(JSON.stringify(envelope), domain);
        });


    },

    subscribe: function (channels, callbacks) {
        var self = this;
        if ($.isArray(channels) && $.isArray(callbacks)) {
            $.each(channels, function (i, channel) {
                self.channelCallBackMap[channel] = callbacks[i];
            });
        }
        else if ($.isArray(channels)) {
            $.each(channels, function (i, channel) {
                self.channelCallBackMap[channel] = callbacks;
            });
        } else if (!$.isArray(callbacks)) {
            this.channelCallBackMap[channels] = callbacks;
        }

        if (!this.alreadyRegistred) {
            $(window).on('message', function (event) {
                //Get the envelope, and from it get the original message as well as the channel
                var domain = location.protocol + '//' + location.host;
                if (event.originalEvent.origin !== domain) {
                    return;
                }
                var envelope = $.parseJSON(event.originalEvent.data);
                if ($.inArray(envelope.channel, self.channels()) > -1) {
                    //Now it calls call-back function
                    self.channelCallBackMap[envelope.channel](envelope.channel, envelope.message);
                }
            });
        }
        this.alreadyRegistred = true;
    },

    channels: function () {
        var keys = $.map(this.channelCallBackMap, function (value, key) {
            return key;
        });
        return keys;
    }
}

return MessageBus;

});
Liam George Betsworth
  • 18,373
  • 5
  • 39
  • 42

2 Answers2

6

Try something like this:

!function (name, definition) {
    if (typeof define == 'function' && define.amd) {
        define(definition);
    } else if (typeof module != 'undefined') {
        module.exports = definition();
    } else {
        this[name] = definition();
    }
}('MessageBus', function() {

    var MessageBus = function () {
        this.channelCallBackMap = {};
        this.alreadyRegistred = false;
    };

    // Rest of the object

    return MessageBus;
});

This is a common syntax as it also supports CommonJS too. See an example in this library - https://github.com/ded/klass/blob/master/klass.js

Simon Smith
  • 8,024
  • 2
  • 30
  • 40
0

Not sure why you write this as AMD module when you dont wanna use as one.

This isn't a good idea at all but you can have your add your own method before the MessageBus.js will that will set MessageBus in the global context:

function define(dep, func)(
  window.MessageBus = func()
)

A better way would to have two different versions. You could have the normal JS version and build the other one wiht a grunt task using the grunt-combine task

combine: {
  amd: {
    input: "amdContainer.js",
    output: "MessageBus-amd.js",
    tokens: [
      {
        token: "%MessageBus%",
        file: "MessageBus.js"
      }
    ]
  }

amdContainer.js

define([], function () {
  %MessageBus%
  return MessageBus;
});

MessageBus.js

var MessageBus = function () {
    this.channelCallBackMap = {};
    this.alreadyRegistred = false;
}

MessageBus.prototype = {
    publish: function (channel, message) {
        //Put original message and channel in the envelope and send it
        var envelope = {
            channel: channel,
            message: message
        };
        var domain = location.protocol + '//' + location.host;
        //Send message to all sibling iframes in the parent document
        $("iframe", parent.document.body).each(function (i, frame) {
            frame.contentWindow.postMessage(JSON.stringify(envelope), domain);
        });


    },

    subscribe: function (channels, callbacks) {
        var self = this;
        if ($.isArray(channels) && $.isArray(callbacks)) {
            $.each(channels, function (i, channel) {
                self.channelCallBackMap[channel] = callbacks[i];
            });
        }
        else if ($.isArray(channels)) {
            $.each(channels, function (i, channel) {
                self.channelCallBackMap[channel] = callbacks;
            });
        } else if (!$.isArray(callbacks)) {
            this.channelCallBackMap[channels] = callbacks;
        }

        if (!this.alreadyRegistred) {
            $(window).on('message', function (event) {
                //Get the envelope, and from it get the original message as well as the channel
                var domain = location.protocol + '//' + location.host;
                if (event.originalEvent.origin !== domain) {
                    return;
                }
                var envelope = $.parseJSON(event.originalEvent.data);
                if ($.inArray(envelope.channel, self.channels()) > -1) {
                    //Now it calls call-back function
                    self.channelCallBackMap[envelope.channel](envelope.channel, envelope.message);
                }
            });
        }
        this.alreadyRegistred = true;
    },

    channels: function () {
        var keys = $.map(this.channelCallBackMap, function (value, key) {
            return key;
        });
        return keys;
    }
}
Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
  • This lib used by many people sometime with requirejs and some time without. – Nilesh Thete Mar 14 '13 at 13:30
  • Then just build two versions, a normal and one that wrapped in AMD. Will update my answer – Andreas Köberle Mar 14 '13 at 13:37
  • Actually instead using two version, there is another way by which one version can work, but I am not sure how to use it. I have one example for this way. !(function (factory) { //CommonJS if (typeof require === "function" && typeof exports === "object" && typeof module === "object") { factory(require("Knockout"), exports); //AMD } else if (typeof define === "function" && define.amd) { define(["Knockout", "exports"], factory); //normal script tag } else { factory(ko, ko.postbox = {}); } } – Nilesh Thete Mar 14 '13 at 13:45
  • Creating two versions of the library is not necessary. It's trivial to add a small wrapper. Answer added with an example – Simon Smith Mar 14 '13 at 13:50