messenger.js 4.1 KB
/**
 *     __  ___
 *    /  |/  /___   _____ _____ ___   ____   ____ _ ___   _____
 *   / /|_/ // _ \ / ___// ___// _ \ / __ \ / __ `// _ \ / ___/
 *  / /  / //  __/(__  )(__  )/  __// / / // /_/ //  __// /
 * /_/  /_/ \___//____//____/ \___//_/ /_/ \__, / \___//_/
 *                                        /____/
 *
 * @description MessengerJS, a common cross-document communicate solution.
 * @author biqing kwok
 * @version 2.0
 * @license release under MIT license
 */

window.Messenger = (function () {

  // 消息前缀, 建议使用自己的项目名, 避免多项目之间的冲突
  // !注意 消息前缀应使用字符串类型
  var prefix = "[PROJECT_NAME]",
    supportPostMessage = 'postMessage' in window;

  // Target 类, 消息对象
  function Target(target, name, prefix) {
    var errMsg = '';
    if (arguments.length < 2) {
      errMsg = 'target error - target and name are both required';
    } else if (typeof target != 'object') {
      errMsg = 'target error - target itself must be window object';
    } else if (typeof name != 'string') {
      errMsg = 'target error - target name must be string type';
    }
    if (errMsg) {
      throw new Error(errMsg);
    }
    this.target = target;
    this.name = name;
    this.prefix = prefix;
  }

  // 往 target 发送消息, 出于安全考虑, 发送消息会带上前缀
  if (supportPostMessage) {
    // IE8+ 以及现代浏览器支持
    Target.prototype.send = function (msg) {
      this.target.postMessage(this.prefix + '|' + this.name + '__Messenger__' + msg, '*');
    };
  } else {
    // 兼容IE 6/7
    Target.prototype.send = function (msg) {
      var targetFunc = window.navigator[this.prefix + this.name];
      if (typeof targetFunc == 'function') {
        targetFunc(this.prefix + msg, window);
      } else {
        throw new Error("target callback function is not defined");
      }
    };
  }

  // 信使类
  // 创建Messenger实例时指定, 必须指定Messenger的名字, (可选)指定项目名, 以避免Mashup类应用中的冲突
  // !注意: 父子页面中projectName必须保持一致, 否则无法匹配
  function Messenger(messengerName, projectName) {
    this.targets = {};
    this.name = messengerName;
    this.listenFunc = [];
    this.prefix = projectName || prefix;
    this.initListen();
  }

  // 添加一个消息对象
  Messenger.prototype.addTarget = function (target, name) {
    var targetObj = new Target(target, name, this.prefix);
    this.targets[name] = targetObj;
  };

  // 初始化消息监听
  Messenger.prototype.initListen = function () {
    var self = this;
    var generalCallback = function (msg) {
      if (typeof msg == 'object' && msg.data) {
        msg = msg.data;
      }

      var msgPairs = msg.split('__Messenger__');
      var msg = msgPairs[1];
      var pairs = msgPairs[0].split('|');
      var prefix = pairs[0];
      var name = pairs[1];

      for (var i = 0; i < self.listenFunc.length; i++) {
        if (prefix + name === self.prefix + self.name) {
          self.listenFunc[i](msg);
        }
      }
    };

    if (supportPostMessage) {
      if ('addEventListener' in document) {
        window.addEventListener('message', generalCallback, false);
      } else if ('attachEvent' in document) {
        window.attachEvent('onmessage', generalCallback);
      }
    } else {
      // 兼容IE 6/7
      window.navigator[this.prefix + this.name] = generalCallback;
    }
  };

  // 监听消息
  Messenger.prototype.listen = function (callback) {
    var i = 0;
    var len = this.listenFunc.length;
    var cbIsExist = false;
    for (; i < len; i++) {
      if (this.listenFunc[i] == callback) {
        cbIsExist = true;
        break;
      }
    }
    if (!cbIsExist) {
      this.listenFunc.push(callback);
    }
  };
  // 注销监听
  Messenger.prototype.clear = function () {
    this.listenFunc = [];
  };
  // 广播消息
  Messenger.prototype.send = function (msg) {
    var targets = this.targets,
      target;
    for (target in targets) {
      if (targets.hasOwnProperty(target)) {
        targets[target].send(msg);
      }
    }
  };

  return Messenger;
})();