Home Reference Source

src/core/core.js

'use strict'

import { eachEntry } from '../core/util.js'

/**
 * Core
 */
class Core {
  /**
   * Create a Core.
   */
  constructor() {
    const dp = {};
    eachEntry(this._privates(), ([key, value]) => {
      dp[key] = { value }
    })
    Object.defineProperties(this, dp)
  }

  /**
   * Return non-enumerable attribute definitions.
   *
   * @access private
   */
  _privates() {
    return { _F_obs: new Map() }
  }

  /**
   * Add handler or listener for saying message
   *
   * @param {string|Object} nameOrObj - message name, '*' specify any listener.
   * @param {Function} handler - handler called on message received or listener.
   * @example
   * core.listened('*', function(){});
   * core.listened('evtName1', function(){});
   * core.listened({ evtName2: function(){}, evtName3: function(){} })
   */
  listened(nameOrObj, handler) {
    if (handler) {
      this._listened(nameOrObj, handler);
    } else {
      eachEntry(nameOrObj, ([name, handler]) => this._listened(name, handler));
    }
  }

  /**
   * Remove handler or listener
   *
   * @param {string} name - message name, '*' specify any listener.
   * @param {Function} - handler registered or listener registered. all registered handler will be removed if not specified.
   */
  unlistened(name, handler) {
    const set = this._F_obs.get(name);
    if (set) {
      if (handler) {
        set.delete(handler)
      } else {
        set.clear()
      }
    }
  }

  /**
   * Unescape HTML
   * @param  {String} escaped HTML string
   * @return {String}         raw HTML string
   */
  unescapeHtml(escaped) {
    const doc = new DOMParser().parseFromString(escaped, "text/html");
    return doc.documentElement.textContent;
  }

  /**
   * Cast a message to the listeners
   *
   * @param {string} name - message name
   * @param {*} ctx - passing value
   */
  say(name, ctx) {
    this._say(name, name, ctx);
    this._say('*', name, ctx);
  }

  // protected scope

  _listened(name, handler) {
    const set = this._F_obs.get(name);
    if (set) {
      set.add(handler);
    } else {
      this._F_obs.set(name, new Set([handler]));
    }
  }

  _say(targetName, name, ctx) {
    const handlers = this._F_obs.get(targetName);
    if (handlers === undefined) return;

    handlers.forEach(it => {
      if (this._isFn(it)) {
        it.call(this, ctx);
        return;
      }

      let method = it[name];
      if (this._isFn(method)) {
        method.call(it, ctx);
      }
    });
  }

  _callR(args, target, method, methodOwner) {
    let t = methodOwner ? this[methodOwner] : this;
    if (t) t = t[method];
    if (t) t.apply(this, args);

    const children = this[target];
    if (!children) return;

    for (let name in children){
      const c = children[name];
      if (c._callR) c._callR(args, target, method, methodOwner);
    }
  }

  _isStr(v) {
    return (typeof v === 'string')
  }

  _isFn(f) {
    return (typeof f === 'function')
  }
}

export default Core