mixins/Locker.js

'use strict';

const lockedItem = Symbol('lockedItem');

/**
 * The Locker mixin allows a class to obtain and release a lock on an item.
 *
 * @private
 * @memberof module:mixins
 *
 * @mixin
 */
const Locker = (superclass) =>
  class Locker extends superclass {
    /**
     * The internally stored reference to the locked item. For access use the
     * external getter. There is no external setter provided. The nature of
     * Symbols makes this interal reference technically accessible, but it still
     * should not be set directly.
     *
     * @name [@@lockedItem]
     * @type {?module:mixins.Lockable}
     * @default undefined
     * @memberof module:mixins.Locker
     */

    /**
     * External getter for the locked item. There is no setter available.
     *
     * @memberof module:mixins.Locker
     *
     * @type {module:mixins.Lockable}
     */
    get lockedItem() {
      return this[lockedItem];
    }

    /**
     * Clear the locked item. Shortcuts the releaseLockedItem() approach and just
     * sets the locked item to null. Use with caution!
     *
     * @memberof module:mixins.Locker
     * @private
     */
    clearLockedItem() {
      this[lockedItem] = null;
    }

    /**
     * Set the locked item. Use with caution!
     *
     * @memberof module:mixins.Locker
     * @private
     *
     * @param {module:mixins.Lockable} item - The item to lock down.
     */
    setLockedItem(item) {
      this[lockedItem] = item;
    }

    /**
     * Obtain a lock on the given item for this view.
     *
     * @memberof module:mixins.Locker
     *
     * @param {module:mixins.Lockable} item - The item to lock down.
     * @returns {boolean} True if the lock was obtained, false otherwise.
     */
    obtainLockOnItem(item) {
      if (item.isLocked()) {
        return false;
      }
      if (this[lockedItem]) this[lockedItem].unlock();
      item.lock(this);
      this.setLockedItem(item);
      return true;
    }

    /**
     * Release the view's item lock.
     *
     * @memberof module:mixins.Locker
     */
    releaseLockedItem() {
      if (this[lockedItem]) this[lockedItem].unlock();
      this.clearLockedItem();
    }
  };

module.exports = Locker;