<commit_before>import {bindable} from 'aurelia-templating';
import {inject} from 'aurelia-dependency-injection';
import {getLogger} from 'aurelia-logging';
import {bindingMode} from 'aurelia-binding';
import {NodeModel} from './node-model';
import {TreeNode} from './tree-node';
import {fireEvent} from '../common/events';

@inject(Element)
export class TreeView {
  @bindable() expandOnFocus: boolean = false;
  @bindable() selectOnFocus: boolean = false;
  @bindable() nodes: NodeModel[];
  @bindable() multiSelect: boolean = false;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) focused: NodeModel = null;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) selected: NodeModel[] = [];
  subscriptions = [];

  // comparers
  @bindable() compareEquality = null;

  bind() {
    this.expandOnFocus = (this.expandOnFocus === true || this.expandOnFocus === 'true');
    this.multiSelect = (this.multiSelect === true || this.multiSelect === 'true');
    this.selectOnFocus = (this.selectOnFocus === true || this.selectOnFocus === 'true');
  }

  constructor(element) {
    this.element = element;
    this.log = getLogger('tree-view');
    this.compareEquality = (args) => { return args.a === args.b; };

    let templateElement = this.element.querySelector('tree-node-template');
    if (templateElement) {
      this.templateElement = templateElement;
    } else {
      // this.log.warn('ctor - no template element');
    }
  }

  attached() { }

  detached() { }

  created() {
    if (this.templateElement) {
      if (this.templateElement.au) {
        let viewModel = this.templateElement.au.controller.viewModel;
        this.log.debug('viewModel', viewModel);
      } else {
        this.log.warn('no viewmodel found for template', this.templateElement);
      }
    } else {
      // this.log.warn('created - no template element');
    }
  }

  nodesChanged(newValue, oldValue) {
    if (newValue) {
      // && this.templateElement
      this.enhanceNodes(newValue);
      this.preselectNodes(newValue);
    }
  }

  enhanceNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (node.children && typeof node.children !== 'function') {
        this.enhanceNodes(node.children);
      }
      if (this.templateElement) {
        node._template = this.templateElement.au.controller.viewModel.template;
        node._templateModel = this.templateElement.au.controller.viewModel.model;
      }
      // node._tree = this;
      node._tree = {
        focusNode: this.focusNode.bind(this),
        selectNode: this.selectNode.bind(this),
        deselectNode: this.deselectNode.bind(this),
        multiSelect: this.multiSelect
      };
    });
  }

  preselectNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (this.selected.find(n => this.compareEquality({a: node, b: n}))) {
        node.selected = true;
        node.expandNode().then(() => {
          this.preselectNodes(node.children);
        });
      }
    });
  }

  _suspendEvents = false;
  _suspendUpdate = false;
  focusNode(node: NodeModel, modifiers = {}) {
    if (!this._suspendUpdate) {
      if (node !== this.focused) {
        if (this.focused) {
          this._suspendUpdate = true;
          this.focused.focused = false;
          this._suspendUpdate = false;
        }
        this.focused = node;
        fireEvent(this.element, 'focused', { node });
        if (this.expandOnFocus) {
          node.expandNode();
        }
      }
      if (this.selectOnFocus) {
        // node.selected = !node.selected;
        this.selectNode(node);
        if (modifiers['ctrl']) {
          let recurse = !!modifiers['shift'];
          node.selectChildren(recurse);
        }
      }
    }
  }

  selectNode(node: NodeModel) {
    let existing = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (existing === -1) {
      this.log.debug('selecting node', node);
      if (!this.multiSelect) {
        this._suspendEvents = true;
        this.selected.forEach(n => n.selected = false);
        this._suspendEvents = false;
      }
      this.selected.push(node);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  deselectNode(node: NodeModel) {
    let index = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (index === -1) {
      this.log.error('node not found in selected', node);
    } else {
      this.log.debug('deselecting node', node);
      this.selected.splice(index, 1);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  expandOnFocusChanged(newValue) {
    this.expandOnFocus = (newValue === true || newValue === 'true');
  }

  clearSelection() {
    this.selected.forEach(node => {
      node.selected = false;
    });
    if (this.focused) {
      this.focused.focused = false;
    }
  }

  // moveNode(node: TreeNode, target: TreeNode | TreeView) {
  //   console.log('moveNode', node, target);
  //   if (target instanceof TreeNode) {
  //     target.model.children.push(node.model);
  //   }
  //   // target.model.children.push(node.model);
  //   let parent = node.element.parentNode;
  //   let children;
  //   while (parent !== null && parent.tagName !== 'TREE-NODE') {
  //     parent = parent.parentNode;
  //   }
  //   if (parent === null) {
  //     children = this.nodes;
  //   } else {
  //     children = parent.au['tree-node'].viewModel.model.children;
  //   }
  //   let pos = children.indexOf(node.model);
  //   children.splice(pos, 1);
  // }

  findParentNode(node: TreeNode): TreeNode {
    let parent = node.element.parentNode;
    let parentModel = null;
    while (parent !== null && parent.tagName.toUpperCase() !== 'TREE-NODE') {
      if (parent.tagName.toUpperCase() === 'TREE-VIEW') {
        parent = null;
      } else {
        parent = parent.parentNode;
      }
    }
    if (parent) {
      parentModel = parent.au['tree-node'].viewModel;
    }
    return parentModel;
  }

  moveNode(node: TreeNode, target: TreeNode | TreeView, sibling: TreeNode) {
    this.log.debug('moveNode', node, target, sibling);

    // if (sibling) { }
    if (target instanceof TreeNode) {
      target.insertChild(node.model, sibling ? sibling.model : null);
      let parent = this.findParentNode(node);
      if (parent === null) {
        parent = this;
        parent.removeNode(node);
      } else {
        parent.removeChild(node.model);
      }
    } else if (target instanceof TreeView) {
      let posNode = this.nodes.indexOf(node.model);
      let posSibling = sibling
        ? this.nodes.indexOf(sibling.model)
        : this.nodes.length - 1;
      if (posNode > -1 && posSibling > -1) {
        this.nodes.splice(posNode, 1);
        this.nodes.splice(posSibling, 0, node.model);
      } else if (posSibling > -1) {
        // move from node to TreeView
        let parent = this.findParentNode(node);
        // parent.removeNode(node);
        parent.removeChild(node.model);
        this.nodes.splice(posSibling, 0, node.model);
      } else {
        this.log.warn('sibling not found');
      }
    }
  }

  removeNode(node: TreeNode) {
    // console.warn('removeNode not implemented');
    let pos = this.nodes.indexOf(node.model);
    this.nodes.splice(pos, 1);
  }
}
<commit_msg>fix(tree-view): fix preselection focus<commit_after>import {bindable} from 'aurelia-templating';
import {inject} from 'aurelia-dependency-injection';
import {getLogger} from 'aurelia-logging';
import {bindingMode} from 'aurelia-binding';
import {NodeModel} from './node-model';
import {TreeNode} from './tree-node';
import {fireEvent} from '../common/events';

@inject(Element)
export class TreeView {
  @bindable() expandOnFocus: boolean = false;
  @bindable() selectOnFocus: boolean = false;
  @bindable() nodes: NodeModel[];
  @bindable() multiSelect: boolean = false;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) focused: NodeModel = null;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) selected: NodeModel[] = [];
  subscriptions = [];

  // comparers
  @bindable() compareEquality = null;

  bind() {
    this.expandOnFocus = (this.expandOnFocus === true || this.expandOnFocus === 'true');
    this.multiSelect = (this.multiSelect === true || this.multiSelect === 'true');
    this.selectOnFocus = (this.selectOnFocus === true || this.selectOnFocus === 'true');
  }

  constructor(element) {
    this.element = element;
    this.log = getLogger('tree-view');
    this.compareEquality = (args) => { return args.a === args.b; };

    let templateElement = this.element.querySelector('tree-node-template');
    if (templateElement) {
      this.templateElement = templateElement;
    } else {
      // this.log.warn('ctor - no template element');
    }
  }

  attached() { }

  detached() { }

  created() {
    if (this.templateElement) {
      if (this.templateElement.au) {
        let viewModel = this.templateElement.au.controller.viewModel;
        this.log.debug('viewModel', viewModel);
      } else {
        this.log.warn('no viewmodel found for template', this.templateElement);
      }
    } else {
      // this.log.warn('created - no template element');
    }
  }

  nodesChanged(newValue, oldValue) {
    if (newValue) {
      // && this.templateElement
      this.enhanceNodes(newValue);
      this.preselectNodes(newValue);
    }
  }

  enhanceNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (node.children && typeof node.children !== 'function') {
        this.enhanceNodes(node.children);
      }
      if (this.templateElement) {
        node._template = this.templateElement.au.controller.viewModel.template;
        node._templateModel = this.templateElement.au.controller.viewModel.model;
      }
      // node._tree = this;
      node._tree = {
        focusNode: this.focusNode.bind(this),
        selectNode: this.selectNode.bind(this),
        deselectNode: this.deselectNode.bind(this),
        multiSelect: this.multiSelect
      };
    });
  }

  preselectNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (this.selected.find(n => this.compareEquality({a: node, b: n}))) {
        node.selected = true;
        if (!this.multiSelect) {
          node.focused = true;
        }
        node.expandNode().then(() => {
          this.preselectNodes(node.children);
        });
      }
    });
  }

  _suspendEvents = false;
  _suspendUpdate = false;
  focusNode(node: NodeModel, modifiers = {}) {
    if (!this._suspendUpdate) {
      if (node !== this.focused) {
        if (this.focused) {
          this._suspendUpdate = true;
          this.focused.focused = false;
          this._suspendUpdate = false;
        }
        this.focused = node;
        fireEvent(this.element, 'focused', { node });
        if (this.expandOnFocus) {
          node.expandNode();
        }
      }
      if (this.selectOnFocus) {
        // node.selected = !node.selected;
        node.selected = true;
        // this.selectNode(node);
        if (modifiers['ctrl']) {
          let recurse = !!modifiers['shift'];
          node.selectChildren(recurse);
        }
      }
    }
  }

  selectNode(node: NodeModel) {
    let existing = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (existing === -1) {
      this.log.debug('selecting node', node);
      if (!this.multiSelect) {
        this._suspendEvents = true;
        this.selected.forEach(n => n.selected = false);
        this._suspendEvents = false;
      }
      this.selected.push(node);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  deselectNode(node: NodeModel) {
    let index = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (index === -1) {
      this.log.error('node not found in selected', node);
    } else {
      this.log.debug('deselecting node', node);
      this.selected.splice(index, 1);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  expandOnFocusChanged(newValue) {
    this.expandOnFocus = (newValue === true || newValue === 'true');
  }

  clearSelection() {
    this.selected.forEach(node => {
      node.selected = false;
    });
    if (this.focused) {
      this.focused.focused = false;
    }
  }

  // moveNode(node: TreeNode, target: TreeNode | TreeView) {
  //   console.log('moveNode', node, target);
  //   if (target instanceof TreeNode) {
  //     target.model.children.push(node.model);
  //   }
  //   // target.model.children.push(node.model);
  //   let parent = node.element.parentNode;
  //   let children;
  //   while (parent !== null && parent.tagName !== 'TREE-NODE') {
  //     parent = parent.parentNode;
  //   }
  //   if (parent === null) {
  //     children = this.nodes;
  //   } else {
  //     children = parent.au['tree-node'].viewModel.model.children;
  //   }
  //   let pos = children.indexOf(node.model);
  //   children.splice(pos, 1);
  // }

  findParentNode(node: TreeNode): TreeNode {
    let parent = node.element.parentNode;
    let parentModel = null;
    while (parent !== null && parent.tagName.toUpperCase() !== 'TREE-NODE') {
      if (parent.tagName.toUpperCase() === 'TREE-VIEW') {
        parent = null;
      } else {
        parent = parent.parentNode;
      }
    }
    if (parent) {
      parentModel = parent.au['tree-node'].viewModel;
    }
    return parentModel;
  }

  moveNode(node: TreeNode, target: TreeNode | TreeView, sibling: TreeNode) {
    this.log.debug('moveNode', node, target, sibling);

    // if (sibling) { }
    if (target instanceof TreeNode) {
      target.insertChild(node.model, sibling ? sibling.model : null);
      let parent = this.findParentNode(node);
      if (parent === null) {
        parent = this;
        parent.removeNode(node);
      } else {
        parent.removeChild(node.model);
      }
    } else if (target instanceof TreeView) {
      let posNode = this.nodes.indexOf(node.model);
      let posSibling = sibling
        ? this.nodes.indexOf(sibling.model)
        : this.nodes.length - 1;
      if (posNode > -1 && posSibling > -1) {
        this.nodes.splice(posNode, 1);
        this.nodes.splice(posSibling, 0, node.model);
      } else if (posSibling > -1) {
        // move from node to TreeView
        let parent = this.findParentNode(node);
        // parent.removeNode(node);
        parent.removeChild(node.model);
        this.nodes.splice(posSibling, 0, node.model);
      } else {
        this.log.warn('sibling not found');
      }
    }
  }

  removeNode(node: TreeNode) {
    // console.warn('removeNode not implemented');
    let pos = this.nodes.indexOf(node.model);
    this.nodes.splice(pos, 1);
  }
}
<|endoftext|>


<commit_before>var stream = require('stream')

function Serializer() {
  stream.Transform.call(this, { objectMode: true })
}
Serializer.prototype = Object.create(stream.Transform.prototype, { constructor: { value: Serializer } })

Serializer.prototype._transform = function _transform(frame, encoding, done) {
  var payload = this[frame.type](frame)
  frame.length = payload.length
  var header = this.commonHeader(frame)

  this.push(header)
  this.push(payload)
  done()
}

function Deserializer() {
  stream.Transform.call(this, { objectMode: true })
}
Deserializer.prototype = Object.create(stream.Transform.prototype, { constructor: { value: Serializer } })

Deserializer.prototype._transform = function _transform(chunk, encoding, done) {

}

/*
  3.3.1 Frame Header

  HTTP/2.0 frames share a common base format consisting of an 8-byte header followed by 0 to 65535 bytes of data.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |         Length (16)           |   Type (8)    |   Flags (8)   |
  +-+-------------+---------------+-------------------------------+
  |R|                 Stream Identifier (31)                      |
  +-+-------------------------------------------------------------+
  |                     Frame Data (0...)                       ...
  +---------------------------------------------------------------+
*/

var frame_types = []

var frame_flags = {}

Serializer.prototype.commonHeader = function writeCommonHeader(frame) {
  var data = new Buffer(8)

  // Length
  if (payload_size > 65535) throw new Error('Too large frame: ' + frame.length + ' bytes (maximal size: 65535 bytes)')
  data.writeUInt16BE(0, frame.length)

  // Type
  var type_id = frame_types.indexOf(frame.type)
  if (type_id === -1) throw new Error('Unknown frame type: ' + frame.type)
  data.writeUInt8BE (2, type_id)

  // Flags
  var flag_byte = 0
  for (var flag in frame.flags) {
    var position = frame_flags[frame.type].indexOf(flag)
    if (position === -1) throw new Error('Unknown flag for frame type ' + frame.type + ': ' + flag)
    if (frame.flags[flag]) flag_byte |= (1 << position)
  }
  data.writeUInt8BE (3, flag_byte)

  // Stream Identifier
  if (frame.stream > 0x7fffffff) throw new Error('Too large stream ID: ' + frame.stream)
  data.writeUInt32BE(4, frame.stream || 0)

  return data
}

Deserializer.prototype.commonHeader = function readCommonHeader(data) {
  var frame = {}

  frame.length = data.readUInt16BE(0)

  frame.type = frame_types[data.readUInt8BE(2)]

  frame.flags = {}
  var flag_byte = data.readUInt8BE(3)
  var defined_flags = frame_flags[frame.type]
  for (var i = 0; i < defined_flags.length; i++) {
    frame.flags[defined_flags[i]] = Boolean(flag_byte & (1 << i))
  }

  frame.stream = data.readUInt32BE(4) & 0x7fffffff

  return frame
}

/*
  3.8.1 DATA Frames

  DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated with a stream.

  The DATA frame does not define any type-specific flags.
*/

frame_types[0x0] = 'DATA'

frame_flags['DATA'] = []

Serializer.prototype['DATA'] = function writeData(frame) {
  return frame.data
}

Deserializer.prototype['DATA'] = function readData(data) {
  return { data: data }
}

/*
  3.8.2 HEADERS+PRIORITY

  The HEADERS+PRIORITY frame (type=0x1) allows the sender to set header fields and stream priority at the same time.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                   Priority (31)                             |
  +-+-------------------------------------------------------------+
  |                    Header Block (*)                         ...
  +---------------------------------------------------------------+

  The HEADERS+PRIORITY frame is identical to the HEADERS frame (Section 3.8.9), preceded by a single reserved bit and
  a 31-bit priority; see Section 3.4.2.

  HEADERS+PRIORITY uses the same flags as the HEADERS frame, except that a HEADERS+PRIORITY frame with a CONTINUES bit
  MUST be followed by another HEADERS+PRIORITY frame. See HEADERS frame (Section 3.8.9) for any flags.
*/

frame_types[0x1] = 'HEADERS+PRIORITY'

frame_flags['HEADERS+PRIORITY'] = ['CONTINUES']

Serializer.prototype['HEADERS+PRIORITY'] = function writeHeadersPriority(frame) {
  var data = new Buffer(4 + frame.data.length)

  // Priority
  if (frame.priority > 0x7fffffff) throw new Error('Too large priority value: ' + frame.stream)
  data.writeUInt32BE(frame.priority, 0)

  // Header Block
  frame.data.copy(data, 4)

  return data
}

Deserializer.prototype['HEADERS+PRIORITY'] = function readHeadersPriority(data) {
  return {
    priority: data.readUInt32BE(0) & 0x7fffffff,
    data: data.slice(4)
  }
}

/*
  3.8.3 PRIORITY

  The PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                   Priority (31)                             |
  +-+-------------------------------------------------------------+

  The payload of a PRIORITY frame contains a single reserved bit and a 31-bit priority.
*/

frame_types[0x2] = 'PRIORITY'

frame_flags['PRIORITY'] = []

Serializer.prototype['PRIORITY'] = function writePriority(frame) {
  var data = new Buffer(4)
  data.writeUInt32BE(frame.priority, 0)
  return data
}

Deserializer.prototype['PRIORITY'] = function readPriority(data) {
  return {
    priority: data.readUInt32BE(0)
  }
}

/*
  3.8.4 RST_STREAM

  The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                         Error Code (32)                       |
  +---------------------------------------------------------------+

  The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the error code (Section 3.5.3). The error
  code indicates why the stream is being terminated.

  No type-flags are defined.
*/

frame_types[0x3] = 'RST_STREAM'

frame_flags['RST_STREAM'] = []

Serializer.prototype['RST_STREAM'] = function writeRstStream(frame) {
  var data = new Buffer(4)
  data.writeUInt32BE(frame.error, 0)
  return data
}

Deserializer.prototype['RST_STREAM'] = function readRstStream(data) {
  return {
    error: data.readUInt32BE(0)
  }
}

/*
  3.8.5 SETTINGS

  The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints communicate.

  The SETTINGS frame defines the following flag:

    CLEAR_PERSISTED (0x2):
    Bit 2 being set indicates a request to clear any previously persisted settings before processing the settings.
*/

frame_types[0x4] = 'SETTINGS'

frame_flags['SETTINGS'] = ['CLEAR_PERSISTED']

Serializer.prototype['SETTINGS'] = function writeSettings(frame) {

}

Deserializer.prototype['SETTINGS'] = function readSettings(data) {

}

/*
  3.8.6 PUSH_PROMISE

  The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of streams the sender intends to
  initiate. The PUSH_PROMISE frame includes the unsigned 31-bit identifier of the stream the endpoint plans to create
  along with a minimal set of headers that provide additional context for the stream.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                Promised-Stream-ID (31)                      |
  +-+-------------------------------------------------------------+
  |                    Header Block (*)                         ...
  +---------------------------------------------------------------+

  PUSH_PROMISE uses the same flags as the HEADERS frame, except that a PUSH_PROMISE frame with a CONTINUES bit MUST be
  followed by another PUSH_PROMISE frame. See HEADERS frame (Section 3.8.9) for any flags.
*/

frame_types[0x5] = 'PUSH_PROMISE'

frame_flags['PUSH_PROMISE'] = ['CONTINUES']

Serializer.prototype['PUSH_PROMISE'] = function writePushPromise(frame) {
  var data = new Buffer(4 + frame.data.length)
  data.writeUInt32BE(frame.promised_stream & 0x7fffffff, 0)
  frame.data.copy(data, 4)
  return data
}

Deserializer.prototype['PUSH_PROMISE'] = function readPushPromise(data) {
  return {
    promised_stream: data.readUInt32BE(0) & 0x7fffffff,
    data: data.slice(4)
  }
}

/*
  3.8.7 PING

  The PING frame (type=0x6) is a mechanism for measuring a minimal round-trip time from the sender, as well as
  determining whether an idle connection is still functional.

  In addition to the frame header, PING frames MUST contain 8 additional octets of opaque data.

  The PING frame defines one type-specific flag:

    PONG (0x2):
    Bit 2 being set indicates that this PING frame is a PING response.
*/

frame_types[0x6] = 'PING'

frame_flags['PING'] = ['PONG']

Serializer.prototype['PING'] = function writePing(frame) {
  if (!frame.data || frame.data.length !== 8) throw new Error('PING frames must carry an 8 byte length payload.')
  return frame.data
}

Deserializer.prototype['PING'] = function readPing(data) {
  return {
    data: data
  }
}

/*
  3.8.8 GOAWAY

  The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this connection.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                  Last-Stream-ID (31)                        |
  +-+-------------------------------------------------------------+
  |                      Error Code (32)                          |
  +---------------------------------------------------------------+

 The GOAWAY frame does not define any type-specific flags.

 The last stream identifier in the GOAWAY frame contains the highest numbered stream identifier for which the sender of
 the GOAWAY frame has received frames on and might have taken some action on.

 The GOAWAY frame also contains a 32-bit error code (Section 3.5.3) that contains the reason for closing the connection.
*/

frame_types[0x7] = 'GOAWAY'

frame_flags['GOAWAY'] = []

Serializer.prototype['GOAWAY'] = function writeGoaway(frame) {
  var data = new Buffer(8)
  data.writeUInt32BE(frame.last_stream & 0x7fffffff, 0)
  data.writeUInt32BE(frame.error, 4)
  return data
}

Deserializer.prototype['GOAWAY'] = function readGoaway(data) {
  return {
    last_stream: data.readUInt32BE(0) & 0x7fffffff,
    error: data.readUInt32BE(4)
  }
}

/*
  3.8.9 HEADERS

  The HEADERS frame (type=0x8) provides header fields for a stream.

  Additional type-specific flags for the HEADERS frame are:

    CONTINUES (0x2):
    The CONTINUES bit indicates that this frame does not contain the entire payload necessary to provide a complete
    set of headers.

  The payload of a HEADERS frame contains a Headers Block (Section 3.7).
*/

frame_types[0x8] = 'HEADERS'

frame_flags['HEADERS'] = ['CONTINUES']

Serializer.prototype['HEADERS'] = function writeHeaders(frame) {
  return frame.data
}

Deserializer.prototype['HEADERS'] = function readHeaders(data) {
  return { data: data }
}

/*
  3.8.10 WINDOW_UPDATE

  The WINDOW_UPDATE frame (type=0x9) is used to implement flow control.

  The following additional flags are defined for the WINDOW_UPDATE frame:

    END_FLOW_CONTROL (0x2):
    Bit 2 being set indicates that flow control for the identified stream or connection has been ended; subsequent
    frames do not need to be flow controlled.

  The payload of a WINDOW_UPDATE frame is a 32-bit value indicating the additional number of bytes that the sender can
  transmit in addition to the existing flow control window. The legal range for this field is 1 to 2^31 - 1 (0x7fffffff)
  bytes; the most significant bit of this value is reserved.
*/

frame_types[0x9] = 'WINDOW_UPDATE'

frame_flags['WINDOW_UPDATE'] = ['END_FLOW_CONTROL']

Serializer.prototype['WINDOW_UPDATE'] = function writeWindowUpdate(frame) {
  var data = new Buffer(4)
  data.writeUInt32BE(frame.window_size & 0x7fffffff, 0)
  return data
}

Deserializer.prototype['WINDOW_UPDATE'] = function readWindowUpdate(data) {
  return {
    window_size: data.readUInt32BE(0) & 0x7fffffff
  }
}

// The least significant bit (0x1) - the FINAL bit - is defined for all frame types as an indication that this frame
// is the last the endpoint will send for the identified stream.

for (var i = 0; i < frame_flags.length; i++) frame_flags[i].unshift('FINAL')
<commit_msg>Maximal line length: 100 characters.<commit_after>var Transform = require('stream').Transform

function Serializer() {
  Transform.call(this, { objectMode: true })
}
Serializer.prototype = Object.create(Transform.prototype, { constructor: { value: Serializer } })

Serializer.prototype._transform = function _transform(frame, encoding, done) {
  var payload = this[frame.type](frame)
  frame.length = payload.length
  var header = this.commonHeader(frame)

  this.push(header)
  this.push(payload)
  done()
}

function Deserializer() {
  Transform.call(this, { objectMode: true })
}
Deserializer.prototype = Object.create(Transform.prototype, { constructor: { value: Serializer } })

Deserializer.prototype._transform = function _transform(chunk, encoding, done) {

}

/*
  3.3.1 Frame Header

  HTTP/2.0 frames share a common base format consisting of an 8-byte header followed by 0 to 65535
  bytes of data.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |         Length (16)           |   Type (8)    |   Flags (8)   |
  +-+-------------+---------------+-------------------------------+
  |R|                 Stream Identifier (31)                      |
  +-+-------------------------------------------------------------+
  |                     Frame Data (0...)                       ...
  +---------------------------------------------------------------+
*/

var frame_types = []

var frame_flags = {}

Serializer.prototype.commonHeader = function writeCommonHeader(frame) {
  var data = new Buffer(8)

  // Length
  if (payload_size > 65535) throw new Error('Too large frame: ' + frame.length + ' bytes')
  data.writeUInt16BE(0, frame.length)

  // Type
  var type_id = frame_types.indexOf(frame.type)
  if (type_id === -1) throw new Error('Unknown frame type: ' + frame.type)
  data.writeUInt8BE (2, type_id)

  // Flags
  var flag_byte = 0
  for (var flag in frame.flags) {
    var position = frame_flags[frame.type].indexOf(flag)
    if (position === -1) throw new Error('Unknown flag for frame type ' + frame.type + ': ' + flag)
    if (frame.flags[flag]) flag_byte |= (1 << position)
  }
  data.writeUInt8BE (3, flag_byte)

  // Stream Identifier
  if (frame.stream > 0x7fffffff) throw new Error('Too large stream ID: ' + frame.stream)
  data.writeUInt32BE(4, frame.stream || 0)

  return data
}

Deserializer.prototype.commonHeader = function readCommonHeader(data) {
  var frame = {}

  frame.length = data.readUInt16BE(0)

  frame.type = frame_types[data.readUInt8BE(2)]

  frame.flags = {}
  var flag_byte = data.readUInt8BE(3)
  var defined_flags = frame_flags[frame.type]
  for (var i = 0; i < defined_flags.length; i++) {
    frame.flags[defined_flags[i]] = Boolean(flag_byte & (1 << i))
  }

  frame.stream = data.readUInt32BE(4) & 0x7fffffff

  return frame
}

/*
  3.8.1 DATA Frames

  DATA frames (type=0x0) convey arbitrary, variable-length sequences of octets associated with a
  stream.

  The DATA frame does not define any type-specific flags.
*/

frame_types[0x0] = 'DATA'

frame_flags['DATA'] = []

Serializer.prototype['DATA'] = function writeData(frame) {
  return frame.data
}

Deserializer.prototype['DATA'] = function readData(data) {
  return { data: data }
}

/*
  3.8.2 HEADERS+PRIORITY

  The HEADERS+PRIORITY frame (type=0x1) allows the sender to set header fields and stream priority
  at the same time.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                   Priority (31)                             |
  +-+-------------------------------------------------------------+
  |                    Header Block (*)                         ...
  +---------------------------------------------------------------+

  The HEADERS+PRIORITY frame is identical to the HEADERS frame (Section 3.8.9), preceded by a single
  reserved bit and a 31-bit priority; see Section 3.4.2.

  HEADERS+PRIORITY uses the same flags as the HEADERS frame, except that a HEADERS+PRIORITY frame
  with a CONTINUES bit MUST be followed by another HEADERS+PRIORITY frame. See HEADERS frame
  (Section 3.8.9) for any flags.
*/

frame_types[0x1] = 'HEADERS+PRIORITY'

frame_flags['HEADERS+PRIORITY'] = ['CONTINUES']

Serializer.prototype['HEADERS+PRIORITY'] = function writeHeadersPriority(frame) {
  var data = new Buffer(4 + frame.data.length)

  // Priority
  if (frame.priority > 0x7fffffff) throw new Error('Too large priority value: ' + frame.stream)
  data.writeUInt32BE(frame.priority, 0)

  // Header Block
  frame.data.copy(data, 4)

  return data
}

Deserializer.prototype['HEADERS+PRIORITY'] = function readHeadersPriority(data) {
  return {
    priority: data.readUInt32BE(0) & 0x7fffffff,
    data: data.slice(4)
  }
}

/*
  3.8.3 PRIORITY

  The PRIORITY frame (type=0x2) specifies the sender-advised priority of a stream.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                   Priority (31)                             |
  +-+-------------------------------------------------------------+

  The payload of a PRIORITY frame contains a single reserved bit and a 31-bit priority.
*/

frame_types[0x2] = 'PRIORITY'

frame_flags['PRIORITY'] = []

Serializer.prototype['PRIORITY'] = function writePriority(frame) {
  var data = new Buffer(4)
  data.writeUInt32BE(frame.priority, 0)
  return data
}

Deserializer.prototype['PRIORITY'] = function readPriority(data) {
  return {
    priority: data.readUInt32BE(0)
  }
}

/*
  3.8.4 RST_STREAM

  The RST_STREAM frame (type=0x3) allows for abnormal termination of a stream.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |                         Error Code (32)                       |
  +---------------------------------------------------------------+

  The RST_STREAM frame contains a single unsigned, 32-bit integer identifying the error
  code (Section 3.5.3). The error code indicates why the stream is being terminated.

  No type-flags are defined.
*/

frame_types[0x3] = 'RST_STREAM'

frame_flags['RST_STREAM'] = []

Serializer.prototype['RST_STREAM'] = function writeRstStream(frame) {
  var data = new Buffer(4)
  data.writeUInt32BE(frame.error, 0)
  return data
}

Deserializer.prototype['RST_STREAM'] = function readRstStream(data) {
  return {
    error: data.readUInt32BE(0)
  }
}

/*
  3.8.5 SETTINGS

  The SETTINGS frame (type=0x4) conveys configuration parameters that affect how endpoints
  communicate.

  The SETTINGS frame defines the following flag:

    CLEAR_PERSISTED (0x2):
    Bit 2 being set indicates a request to clear any previously persisted settings before processing
    the settings.
*/

frame_types[0x4] = 'SETTINGS'

frame_flags['SETTINGS'] = ['CLEAR_PERSISTED']

Serializer.prototype['SETTINGS'] = function writeSettings(frame) {

}

Deserializer.prototype['SETTINGS'] = function readSettings(data) {

}

/*
  3.8.6 PUSH_PROMISE

  The PUSH_PROMISE frame (type=0x5) is used to notify the peer endpoint in advance of streams the
  sender intends to initiate. The PUSH_PROMISE frame includes the unsigned 31-bit identifier of the
  stream the endpoint plans to create along with a minimal set of headers that provide additional
  context for the stream.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                Promised-Stream-ID (31)                      |
  +-+-------------------------------------------------------------+
  |                    Header Block (*)                         ...
  +---------------------------------------------------------------+

  PUSH_PROMISE uses the same flags as the HEADERS frame, except that a PUSH_PROMISE frame with a
  CONTINUES bit MUST be followed by another PUSH_PROMISE frame. See HEADERS frame (Section 3.8.9)
  for any flags.
*/

frame_types[0x5] = 'PUSH_PROMISE'

frame_flags['PUSH_PROMISE'] = ['CONTINUES']

Serializer.prototype['PUSH_PROMISE'] = function writePushPromise(frame) {
  var data = new Buffer(4 + frame.data.length)
  data.writeUInt32BE(frame.promised_stream & 0x7fffffff, 0)
  frame.data.copy(data, 4)
  return data
}

Deserializer.prototype['PUSH_PROMISE'] = function readPushPromise(data) {
  return {
    promised_stream: data.readUInt32BE(0) & 0x7fffffff,
    data: data.slice(4)
  }
}

/*
  3.8.7 PING

  The PING frame (type=0x6) is a mechanism for measuring a minimal round-trip time from the sender,
  as well as determining whether an idle connection is still functional.

  In addition to the frame header, PING frames MUST contain 8 additional octets of opaque data.

  The PING frame defines one type-specific flag:

    PONG (0x2):
    Bit 2 being set indicates that this PING frame is a PING response.
*/

frame_types[0x6] = 'PING'

frame_flags['PING'] = ['PONG']

Serializer.prototype['PING'] = function writePing(frame) {
  var payload = frame.data
  if (!payload || payload.length !== 8) throw new Error('PING frames must carry an 8 byte payload.')
  return payload
}

Deserializer.prototype['PING'] = function readPing(data) {
  return {
    data: data
  }
}

/*
  3.8.8 GOAWAY

  The GOAWAY frame (type=0x7) informs the remote peer to stop creating streams on this connection.

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |X|                  Last-Stream-ID (31)                        |
  +-+-------------------------------------------------------------+
  |                      Error Code (32)                          |
  +---------------------------------------------------------------+

 The GOAWAY frame does not define any type-specific flags.

 The last stream identifier in the GOAWAY frame contains the highest numbered stream identifier for
 which the sender of the GOAWAY frame has received frames on and might have taken some action on.

 The GOAWAY frame also contains a 32-bit error code (Section 3.5.3) that contains the reason for
 closing the connection.
*/

frame_types[0x7] = 'GOAWAY'

frame_flags['GOAWAY'] = []

Serializer.prototype['GOAWAY'] = function writeGoaway(frame) {
  var data = new Buffer(8)
  data.writeUInt32BE(frame.last_stream & 0x7fffffff, 0)
  data.writeUInt32BE(frame.error, 4)
  return data
}

Deserializer.prototype['GOAWAY'] = function readGoaway(data) {
  return {
    last_stream: data.readUInt32BE(0) & 0x7fffffff,
    error: data.readUInt32BE(4)
  }
}

/*
  3.8.9 HEADERS

  The HEADERS frame (type=0x8) provides header fields for a stream.

  Additional type-specific flags for the HEADERS frame are:

    CONTINUES (0x2):
    The CONTINUES bit indicates that this frame does not contain the entire payload necessary to
    provide a complete set of headers.

  The payload of a HEADERS frame contains a Headers Block (Section 3.7).
*/

frame_types[0x8] = 'HEADERS'

frame_flags['HEADERS'] = ['CONTINUES']

Serializer.prototype['HEADERS'] = function writeHeaders(frame) {
  return frame.data
}

Deserializer.prototype['HEADERS'] = function readHeaders(data) {
  return { data: data }
}

/*
  3.8.10 WINDOW_UPDATE

  The WINDOW_UPDATE frame (type=0x9) is used to implement flow control.

  The following additional flags are defined for the WINDOW_UPDATE frame:

    END_FLOW_CONTROL (0x2):
    Bit 2 being set indicates that flow control for the identified stream or connection has been
    ended; subsequent frames do not need to be flow controlled.

  The payload of a WINDOW_UPDATE frame is a 32-bit value indicating the additional number of bytes
  that the sender can transmit in addition to the existing flow control window. The legal range for
  this field is 1 to 2^31 - 1 (0x7fffffff) bytes; the most significant bit of this value is
  reserved.
*/

frame_types[0x9] = 'WINDOW_UPDATE'

frame_flags['WINDOW_UPDATE'] = ['END_FLOW_CONTROL']

Serializer.prototype['WINDOW_UPDATE'] = function writeWindowUpdate(frame) {
  var data = new Buffer(4)
  data.writeUInt32BE(frame.window_size & 0x7fffffff, 0)
  return data
}

Deserializer.prototype['WINDOW_UPDATE'] = function readWindowUpdate(data) {
  return {
    window_size: data.readUInt32BE(0) & 0x7fffffff
  }
}

// The least significant bit (0x1) - the FINAL bit - is defined for all frame types as an indication
// that this frame is the last the endpoint will send for the identified stream.

for (var i = 0; i < frame_flags.length; i++) frame_flags[i].unshift('FINAL')
<|endoftext|>


<commit_before>'use strict';

var Sandal = (function () {

    var Sandal, _getArgumentNames, _register, _hasCircularDependencies, _callResolvedCallbacks, _createObjectSync, _resolve;

	_register = function (container, name, item) {
		if (name === 'done' || container[name]) {
			throw new Error(name + ' is already registered');
		}
		container[name] = item;
	};

	_getArgumentNames = function(func) {
		var functionString, argumentList;
		functionString = func.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '');
		argumentList = functionString.slice(functionString.indexOf('(')+1, functionString.indexOf(')')).match(/([^\s,]+)/g);
		if(argumentList === null) {
			argumentList = [];
		}
		return argumentList;
	};

	_hasCircularDependencies = function (dependencyNames, resolveChain) {
		var i, j;
		for (var j = 0; j < dependencyNames.length; j++) {
			for (var i = 0; i < resolveChain.length; i++) {
				if (resolveChain[i] === dependencyNames[j]) {
					return true;
				}
			}
		}
		return false;
	};

	_callResolvedCallbacks = function (err, item) {
		for (var i = 0; i < item.resolvedCallbacks.length; i++) {
            item.resolvedCallbacks[i](err);
		}
        item.resolvedCallbacks = [];
        item.isResolving = false;
	};

    _createObjectSync = function (item, dependencies) {
        if (item.ctor) {
            var obj = Object.create(item.ctor.prototype);
            item.ctor.prototype.constructor.apply(obj, dependencies);
            return obj;
        } else {
            return item.factory.apply(null, dependencies);
        }
    };

	_resolve = function(name, container, resolveChain, callback) {

		var i, obj, resolvingDone, isDone, item, dependencyNames, dependencyCount, dependencies, hasDoneCallback, resolvedDependenciesCount;

        resolveChain.push(name);

        item = container[name];

        if (!item) {
            callback(new Error('No implementation registered for ' + name));
            return;
        }

		resolvingDone = function (err, obj) {
            if (!isDone) {
                isDone = true;
                if (item.lifecycle === 'singleton') {
                    item.singleton = obj;
                    _callResolvedCallbacks(err, item);
                } else {
                    callback(err, obj);
                }
            }
        };

        if (item.lifecycle === 'singleton') {

            item.resolvedCallbacks = item.resolvedCallbacks || [];
            item.resolvedCallbacks.push(function(err) {
                callback(err, item.singleton);
            });

            if (item.isResolving) {
                return;
            }
            item.isResolving = true;

            if (item.hasOwnProperty('singleton')) {
				resolvingDone(null, item.singleton);
                return;
            }

        }

		if (!item.ctor && !item.factory) {
			resolvingDone(new Error('No valid implementation registered for ' + name));
			return;
		}

		dependencyNames = _getArgumentNames(item.ctor || item.factory);
		if (_hasCircularDependencies(dependencyNames, resolveChain)) {
			resolvingDone(new Error('There are circular dependencies in resolve chain: ' + resolveChain));
            return;
		}

		dependencyCount = dependencyNames.length;
		if (dependencyCount === 0) {
            try {
                obj = _createObjectSync(item, []);
				resolvingDone(null, obj);
            } catch (err) {
				resolvingDone(err);
            }
			return;
		}

		dependencies = [];
		hasDoneCallback = false;
		resolvedDependenciesCount = 0;
		for(i = 0; i < dependencyCount; i++) {

			(function(index) {

				var dependencyCallback = function (err, dependency) {

                    if (err) {
						resolvingDone(err);
						return;
					}
					dependencies[index] = dependency;
					resolvedDependenciesCount++;

					if (resolvedDependenciesCount === dependencyCount) {

                        try {
                            obj = _createObjectSync(item, dependencies);
                        } catch (err) {
							resolvingDone(err);
                        }

						if (!hasDoneCallback) {
							resolvingDone(null, obj);
						}
					}
				};

                if (dependencyNames[index] === 'done') {
                    hasDoneCallback = true;
					if (item.factory && hasDoneCallback) {
						dependencyCallback(null, resolvingDone);
					} else {
						dependencyCallback(null, function(err) {
							resolvingDone(err, obj);
						});
					}
                    return;
                }

				_resolve(dependencyNames[index], container, resolveChain.slice(0), dependencyCallback);

			})(i);

		}

	};

	Sandal = function() {
		this.clear();
	};

	Sandal.prototype.service = function(name, ctor, transient) {
		if (typeof ctor !== 'function') {
			throw new Error('Service must be a function');
		}
		_register(this.container, name, {
			ctor: ctor,
			lifecycle: transient ? 'transient' : 'singleton'
		});
		return this;
	};

	Sandal.prototype.factory = function(name, factory, transient) {
		if (typeof factory !== 'function') {
			throw new Error('Function required');
		}
		_register(this.container, name, {
			factory: factory,
			lifecycle: transient ? 'transient' : 'singleton'
		});
		return this;
	};

	Sandal.prototype.object = function(name, obj) {
		_register(this.container, name, {
			singleton: obj,
			lifecycle: 'singleton'
		});
		return this;
	};

	Sandal.prototype.resolve = function(arg1, arg2) {

		var that = this, callback, itemNames, itemCount, resolvedCount, resolved, i;

		if (typeof arg1 === 'string') {
            itemNames = [ arg1 ];
			callback = arg2;
		} else if (typeof arg1 === 'function') {
			callback = arg1;
		} else {
            itemNames = arg1;
			callback = arg2;
		}

		if (typeof callback !== 'function') {
			throw new Error('Callback function required');
		}

		if (!itemNames) {
            itemNames = _getArgumentNames(callback);
            itemNames = itemNames.splice(1);
		}

        itemCount = itemNames.length;
        if (itemCount === 0) {
            callback(null);
            return;
        }

		resolvedCount = 0;
		resolved = [];
		for (i = 0; i < itemCount; i++) {
			(function (index) {
				_resolve(itemNames[index], that.container, [], function(err, svc) {
					resolvedCount++;
					resolved[0] = resolved[0] || err;
					resolved[index + 1] = svc;
					if (resolvedCount === itemCount) {
						callback.apply({}, resolved);
					}
				});
			})(i);
		}
		return this;
	};

	Sandal.prototype.remove = function(names) {
		if (!names) {
			return this;
		}
		if (typeof names === 'string') {
			names = [ names ];
		}
		for (var i = 0; i < names.length; i++) {
			if (names[i] === 'sandal' || names[i] === 'done') {
				throw new Error('Removing ' + names[i] + ' is not allowed');
			}
			delete this.container[names[i]];
		}
		return this;
	};

	Sandal.prototype.clear = function() {
		this.container = {
			sandal: {
				singleton: this,
				lifecycle: 'singleton'
			}
		};
		return this;
	};

	return Sandal;

})();

if (typeof module === 'undefined' || typeof module.exports  === 'undefined') {
	this['Sandal'] = Sandal;
} else {
	module.exports = Sandal;
}
<commit_msg>Cleaned up code<commit_after>'use strict';

var Sandal = (function () {

    var Sandal, _getArgumentNames, _register, _hasCircularDependencies, _callResolvedCallbacks, _createObjectSync, _resolve;

	_register = function (container, name, item) {
		if (name === 'done' || container[name]) {
			throw new Error(name + ' is already registered');
		}
		container[name] = item;
	};

	_getArgumentNames = function (func) {
		var functionString, argumentList;
		functionString = func.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '');
		argumentList = functionString.slice(functionString.indexOf('(') + 1, functionString.indexOf(')')).match(/([^\s,]+)/g);
		if (argumentList === null) {
			argumentList = [];
		}
		return argumentList;
	};

	_hasCircularDependencies = function (dependencyNames, resolveChain) {
		var i, j;
		for (j = 0; j < dependencyNames.length; j++) {
			for (i = 0; i < resolveChain.length; i++) {
				if (resolveChain[i] === dependencyNames[j]) {
					return true;
				}
			}
		}
		return false;
	};

	_callResolvedCallbacks = function (err, item) {
		for (var i = 0; i < item.resolvedCallbacks.length; i++) {
            item.resolvedCallbacks[i](err);
		}
        item.resolvedCallbacks = [];
        item.isResolving = false;
	};

    _createObjectSync = function (item, dependencies) {
        if (item.ctor) {
            var obj = Object.create(item.ctor.prototype);
            item.ctor.prototype.constructor.apply(obj, dependencies);
            return obj;
        } else {
            return item.factory.apply(null, dependencies);
        }
    };

	_resolve = function (name, container, resolveChain, callback) {

		var i, obj, resolvingDone, isDone, item, dependencyNames, dependencyCount, dependencies, hasDoneCallback, resolvedDependenciesCount;

        resolveChain.push(name);

        item = container[name];

        if (!item) {
            callback(new Error('No implementation registered for ' + name));
            return;
        }

		resolvingDone = function (err, obj) {
            if (!isDone) {
                isDone = true;
                if (item.lifecycle === 'singleton') {
                    item.singleton = obj;
                    _callResolvedCallbacks(err, item);
                } else {
                    callback(err, obj);
                }
            }
        };

        if (item.lifecycle === 'singleton') {

            item.resolvedCallbacks = item.resolvedCallbacks || [];
            item.resolvedCallbacks.push(function (err) {
                callback(err, item.singleton);
            });

            if (item.isResolving) {
                return;
            }
            item.isResolving = true;

            if (item.hasOwnProperty('singleton')) {
				resolvingDone(null, item.singleton);
                return;
            }

        }

		if (!item.ctor && !item.factory) {
			resolvingDone(new Error('No valid implementation registered for ' + name));
			return;
		}

		dependencyNames = _getArgumentNames(item.ctor || item.factory);
		if (_hasCircularDependencies(dependencyNames, resolveChain)) {
			resolvingDone(new Error('There are circular dependencies in resolve chain: ' + resolveChain));
            return;
		}

		dependencyCount = dependencyNames.length;
		if (dependencyCount === 0) {
            try {
                obj = _createObjectSync(item, []);
				resolvingDone(null, obj);
            } catch (err) {
				resolvingDone(err);
            }
			return;
		}

		dependencies = [];
		hasDoneCallback = false;
		resolvedDependenciesCount = 0;
		for (i = 0; i < dependencyCount; i++) {

			(function (index) {

				var dependencyCallback = function (err, dependency) {

                    if (err) {
						resolvingDone(err);
						return;
					}
					dependencies[index] = dependency;
					resolvedDependenciesCount++;

					if (resolvedDependenciesCount === dependencyCount) {

                        try {
                            obj = _createObjectSync(item, dependencies);
                        } catch (err) {
							resolvingDone(err);
                        }

						if (!hasDoneCallback) {
							resolvingDone(null, obj);
						}
					}
				};

                if (dependencyNames[index] === 'done') {
                    hasDoneCallback = true;
					if (item.factory && hasDoneCallback) {
						dependencyCallback(null, resolvingDone);
					} else {
						dependencyCallback(null, function (err) {
							resolvingDone(err, obj);
						});
					}
                    return;
                }

				_resolve(dependencyNames[index], container, resolveChain.slice(0), dependencyCallback);

			})(i);

		}

	};

	Sandal = function () {
		this.clear();
	};

	Sandal.prototype.service = function (name, ctor, transient) {
		if (typeof ctor !== 'function') {
			throw new Error('Service must be a function');
		}
		_register(this.container, name, {
			ctor: ctor,
			lifecycle: transient ? 'transient' : 'singleton'
		});
		return this;
	};

	Sandal.prototype.factory = function (name, factory, transient) {
		if (typeof factory !== 'function') {
			throw new Error('Function required');
		}
		_register(this.container, name, {
			factory: factory,
			lifecycle: transient ? 'transient' : 'singleton'
		});
		return this;
	};

	Sandal.prototype.object = function (name, obj) {
		_register(this.container, name, {
			singleton: obj,
			lifecycle: 'singleton'
		});
		return this;
	};

	Sandal.prototype.resolve = function (arg1, arg2) {

		var that = this, callback, itemNames, itemCount, resolvedCount, resolved, i;

		if (typeof arg1 === 'string') {
            itemNames = [ arg1 ];
			callback = arg2;
		} else if (typeof arg1 === 'function') {
			callback = arg1;
		} else {
            itemNames = arg1;
			callback = arg2;
		}

		if (typeof callback !== 'function') {
			throw new Error('Callback function required');
		}

		if (!itemNames) {
            itemNames = _getArgumentNames(callback);
            itemNames = itemNames.splice(1);
		}

        itemCount = itemNames.length;
        if (itemCount === 0) {
            callback(null);
            return;
        }

		resolvedCount = 0;
		resolved = [];
		for (i = 0; i < itemCount; i++) {
			(function (index) {
				_resolve(itemNames[index], that.container, [], function (err, svc) {
					resolvedCount++;
					resolved[0] = resolved[0] || err;
					resolved[index + 1] = svc;
					if (resolvedCount === itemCount) {
						callback.apply({}, resolved);
					}
				});
			})(i);
		}
		return this;
	};

	Sandal.prototype.remove = function (names) {
		if (!names) {
			return this;
		}
		if (typeof names === 'string') {
			names = [ names ];
		}
		for (var i = 0; i < names.length; i++) {
			if (names[i] === 'sandal' || names[i] === 'done') {
				throw new Error('Removing ' + names[i] + ' is not allowed');
			}
			delete this.container[names[i]];
		}
		return this;
	};

	Sandal.prototype.clear = function () {
		this.container = {
			sandal: {
				singleton: this,
				lifecycle: 'singleton'
			}
		};
		return this;
	};

	return Sandal;

})();

if (module && module.exports) {
	module.exports = Sandal;
}<|endoftext|>


<commit_before>import React from 'react';
import Reflux from 'reflux';

import ObjectStore from '../../../stores/object';
import ObjectActions from '../../../actions/object';

export let BaseObject = (ComposedComponent, type, status = '') => class BaseObject extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.getState();
  }

  componentDidMount() {
    this.unsubscribe = ObjectStore.listen((name) => {
      this.onUpdate(name);
    });
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  onUpdate(data){
    if(data && data.objects && data.objects[type] &&
      data.objects[type].getValue() !== this.state.state){
        this.setState({
          object: data.objects[type],
          digibord: data.objects.digibord || {},
        });
      }
  }

  getState(){
    return {
      object: ObjectStore.getObject(type)
    };
  }

  render() {
    let classNames = [
      'object',
      type
    ];

    const object = this.state.object;
    if(object) {
      const state = object.state;
      if(object.values) {
        classNames.push(state);
      }
      else if(object.type == 'string' || object.type == 'text')
      {
        classNames.push(state === '' ? 'empty' : 'set');
      }
      else if(object.type == 'int')
      {
        classNames.push('int-' + state);
      }
    }

    return (

        <ComposedComponent { ...this.props } data={ this.state } />

    );
  }
};
<commit_msg>Add naam to object props.<commit_after>import React from 'react';
import Reflux from 'reflux';

import ObjectStore from '../../../stores/object';
import ObjectActions from '../../../actions/object';

export let BaseObject = (ComposedComponent, type, status = '') => class BaseObject extends React.Component {
  constructor(props) {
    super(props);
    this.state = this.getState();
  }

  componentDidMount() {
    this.unsubscribe = ObjectStore.listen((name) => {
      this.onUpdate(name);
    });
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  onUpdate(data){
    if(data && data.objects && data.objects[type] &&
      data.objects[type].getValue() !== this.state.state){
        this.setState({
          object: data.objects[type],
          digibord: data.objects.digibord || {},
          naam: data.objects.naam || {}
        });
      }
  }

  getState(){
    return {
      object: ObjectStore.getObject(type)
    };
  }

  render() {
    let classNames = [
      'object',
      type
    ];

    const object = this.state.object;
    if(object) {
      const state = object.state;
      if(object.values) {
        classNames.push(state);
      }
      else if(object.type == 'string' || object.type == 'text')
      {
        classNames.push(state === '' ? 'empty' : 'set');
      }
      else if(object.type == 'int')
      {
        classNames.push('int-' + state);
      }
    }

    return (

        <ComposedComponent { ...this.props } data={ this.state } />

    );
  }
};
<|endoftext|>


<commit_before>import {bindable} from 'aurelia-templating';
import {inject} from 'aurelia-dependency-injection';
import {getLogger} from 'aurelia-logging';
import {bindingMode} from 'aurelia-binding';
import {NodeModel} from './node-model';
import {TreeNode} from './tree-node';
import {fireEvent} from '../common/events';

@inject(Element)
export class TreeView {
  @bindable() expandOnFocus: boolean = false;
  @bindable() selectOnFocus: boolean = false;
  @bindable() nodes: NodeModel[];
  @bindable() multiSelect: boolean = false;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) focused: NodeModel = null;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) selected: NodeModel[] = [];
  subscriptions = [];

  // comparers
  @bindable() compareEquality = null;

  bind() {
    this.expandOnFocus = (this.expandOnFocus === true || this.expandOnFocus === 'true');
    this.multiSelect = (this.multiSelect === true || this.multiSelect === 'true');
    this.selectOnFocus = (this.selectOnFocus === true || this.selectOnFocus === 'true');
  }

  constructor(element) {
    this.element = element;
    this.log = getLogger('tree-view');
    this.compareEquality = (args) => { return args.a === args.b; };

    let templateElement = this.element.querySelector('tree-node-template');
    if (templateElement) {
      this.templateElement = templateElement;
    } else {
      // this.log.warn('ctor - no template element');
    }
  }

  attached() { }

  detached() { }

  created() {
    if (this.templateElement) {
      if (this.templateElement.au) {
        let viewModel = this.templateElement.au.controller.viewModel;
        this.log.debug('viewModel', viewModel);
      } else {
        this.log.warn('no viewmodel found for template', this.templateElement);
      }
    } else {
      // this.log.warn('created - no template element');
    }
  }

  nodesChanged(newValue, oldValue) {
    if (newValue) {
      // && this.templateElement
      this.enhanceNodes(newValue);
      this.preselectNodes(newValue);
    }
  }

  enhanceNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (node.children && typeof node.children !== 'function') {
        this.enhanceNodes(node.children);
      }
      if (this.templateElement) {
        node._template = this.templateElement.au.controller.viewModel.template;
      }
      // node._tree = this;
      node._tree = {
        focusNode: this.focusNode.bind(this),
        selectNode: this.selectNode.bind(this),
        deselectNode: this.deselectNode.bind(this),
        multiSelect: this.multiSelect
      };
    });
  }

  preselectNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (this.selected.find(n => this.compareEquality({a: node, b: n}))) {
        node.selected = true;
        node.expandNode().then(() => {
          this.preselectNodes(node.children);
        });
      }
    });
  }

  _suspendEvents = false;
  _suspendUpdate = false;
  focusNode(node: NodeModel, modifiers = {}) {
    if (!this._suspendUpdate) {
      if (node !== this.focused) {
        if (this.focused) {
          this._suspendUpdate = true;
          this.focused.focused = false;
          this._suspendUpdate = false;
        }
        this.focused = node;
        fireEvent(this.element, 'focused', { node });
        if (this.expandOnFocus) {
          node.expandNode();
        }
        if (!this.multiSelect) {
          this._suspendEvents = true;
          this.selected.forEach(node => node.selected = false);
          this._suspendEvents = false;
          // this.selected.splice(0);
          // this.selectNode(node);
          node.selected = true;
        }
      }
      if (this.selectOnFocus) {
        node.selected = !node.selected;
        if (modifiers['ctrl']) {
          let recurse = !!modifiers['shift'];
          node.selectChildren(recurse);
        }
      }
    }
  }

  selectNode(node: NodeModel) {
    let existing = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (existing === -1) {
      this.log.debug('selecting node', node);
      this.selected.push(node);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  deselectNode(node: NodeModel) {
    let index = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (index === -1) {
      this.log.error('node not found in selected', node);
    } else {
      this.log.debug('deselecting node', node);
      this.selected.splice(index, 1);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  expandOnFocusChanged(newValue) {
    this.expandOnFocus = (newValue === true || newValue === 'true');
  }

  clearSelection() {
    this.selected.forEach(node => {
      node.selected = false;
    });
    this.focused.focused = false;
  }

  // moveNode(node: TreeNode, target: TreeNode | TreeView) {
  //   console.log('moveNode', node, target);
  //   if (target instanceof TreeNode) {
  //     target.model.children.push(node.model);
  //   }
  //   // target.model.children.push(node.model);
  //   let parent = node.element.parentNode;
  //   let children;
  //   while (parent !== null && parent.tagName !== 'TREE-NODE') {
  //     parent = parent.parentNode;
  //   }
  //   if (parent === null) {
  //     children = this.nodes;
  //   } else {
  //     children = parent.au['tree-node'].viewModel.model.children;
  //   }
  //   let pos = children.indexOf(node.model);
  //   children.splice(pos, 1);
  // }

  moveNode(node: TreeNode, target: TreeNode | TreeView, sibling: TreeNode) {
    this.log.debug('moveNode', node, target, sibling);

    if (target instanceof TreeNode) {
      // target.model.children.push(node.model);
      target.insertChild(node, sibling);
      let parent = node.element.parentNode;
      while (parent !== null && parent.tagName !== 'TREE-NODE') {
        parent = parent.parentNode;
      }
      if (parent === null) {
        parent = this;
        parent.removeNode(node);
      } else {
        parent.au['tree-node'].viewModel.removeChild(node.model);
      }
    }
  }

  removeNode(node: TreeNode) {
    console.warn('removeNode not implemented');
  }
}
<commit_msg>fix(tree-view): fixed an error while clearing selection without a selection<commit_after>import {bindable} from 'aurelia-templating';
import {inject} from 'aurelia-dependency-injection';
import {getLogger} from 'aurelia-logging';
import {bindingMode} from 'aurelia-binding';
import {NodeModel} from './node-model';
import {TreeNode} from './tree-node';
import {fireEvent} from '../common/events';

@inject(Element)
export class TreeView {
  @bindable() expandOnFocus: boolean = false;
  @bindable() selectOnFocus: boolean = false;
  @bindable() nodes: NodeModel[];
  @bindable() multiSelect: boolean = false;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) focused: NodeModel = null;
  @bindable({
    defaultBindingMode: bindingMode.twoWay
  }) selected: NodeModel[] = [];
  subscriptions = [];

  // comparers
  @bindable() compareEquality = null;

  bind() {
    this.expandOnFocus = (this.expandOnFocus === true || this.expandOnFocus === 'true');
    this.multiSelect = (this.multiSelect === true || this.multiSelect === 'true');
    this.selectOnFocus = (this.selectOnFocus === true || this.selectOnFocus === 'true');
  }

  constructor(element) {
    this.element = element;
    this.log = getLogger('tree-view');
    this.compareEquality = (args) => { return args.a === args.b; };

    let templateElement = this.element.querySelector('tree-node-template');
    if (templateElement) {
      this.templateElement = templateElement;
    } else {
      // this.log.warn('ctor - no template element');
    }
  }

  attached() { }

  detached() { }

  created() {
    if (this.templateElement) {
      if (this.templateElement.au) {
        let viewModel = this.templateElement.au.controller.viewModel;
        this.log.debug('viewModel', viewModel);
      } else {
        this.log.warn('no viewmodel found for template', this.templateElement);
      }
    } else {
      // this.log.warn('created - no template element');
    }
  }

  nodesChanged(newValue, oldValue) {
    if (newValue) {
      // && this.templateElement
      this.enhanceNodes(newValue);
      this.preselectNodes(newValue);
    }
  }

  enhanceNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (node.children && typeof node.children !== 'function') {
        this.enhanceNodes(node.children);
      }
      if (this.templateElement) {
        node._template = this.templateElement.au.controller.viewModel.template;
      }
      // node._tree = this;
      node._tree = {
        focusNode: this.focusNode.bind(this),
        selectNode: this.selectNode.bind(this),
        deselectNode: this.deselectNode.bind(this),
        multiSelect: this.multiSelect
      };
    });
  }

  preselectNodes(nodes: NodeModel[]) {
    nodes.forEach(node => {
      if (this.selected.find(n => this.compareEquality({a: node, b: n}))) {
        node.selected = true;
        node.expandNode().then(() => {
          this.preselectNodes(node.children);
        });
      }
    });
  }

  _suspendEvents = false;
  _suspendUpdate = false;
  focusNode(node: NodeModel, modifiers = {}) {
    if (!this._suspendUpdate) {
      if (node !== this.focused) {
        if (this.focused) {
          this._suspendUpdate = true;
          this.focused.focused = false;
          this._suspendUpdate = false;
        }
        this.focused = node;
        fireEvent(this.element, 'focused', { node });
        if (this.expandOnFocus) {
          node.expandNode();
        }
        if (!this.multiSelect) {
          this._suspendEvents = true;
          this.selected.forEach(node => node.selected = false);
          this._suspendEvents = false;
          // this.selected.splice(0);
          // this.selectNode(node);
          node.selected = true;
        }
      }
      if (this.selectOnFocus) {
        node.selected = !node.selected;
        if (modifiers['ctrl']) {
          let recurse = !!modifiers['shift'];
          node.selectChildren(recurse);
        }
      }
    }
  }

  selectNode(node: NodeModel) {
    let existing = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (existing === -1) {
      this.log.debug('selecting node', node);
      this.selected.push(node);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  deselectNode(node: NodeModel) {
    let index = this.selected.findIndex(n => this.compareEquality({a: node, b: n}));
    if (index === -1) {
      this.log.error('node not found in selected', node);
    } else {
      this.log.debug('deselecting node', node);
      this.selected.splice(index, 1);
      if (!this._suspendEvents) {
        fireEvent(this.element, 'selection-changed', { nodes: this.selected });
      }
    }
  }

  expandOnFocusChanged(newValue) {
    this.expandOnFocus = (newValue === true || newValue === 'true');
  }

  clearSelection() {
    this.selected.forEach(node => {
      node.selected = false;
    });
    this.focused && this.focused.focused = false;
  }

  // moveNode(node: TreeNode, target: TreeNode | TreeView) {
  //   console.log('moveNode', node, target);
  //   if (target instanceof TreeNode) {
  //     target.model.children.push(node.model);
  //   }
  //   // target.model.children.push(node.model);
  //   let parent = node.element.parentNode;
  //   let children;
  //   while (parent !== null && parent.tagName !== 'TREE-NODE') {
  //     parent = parent.parentNode;
  //   }
  //   if (parent === null) {
  //     children = this.nodes;
  //   } else {
  //     children = parent.au['tree-node'].viewModel.model.children;
  //   }
  //   let pos = children.indexOf(node.model);
  //   children.splice(pos, 1);
  // }

  moveNode(node: TreeNode, target: TreeNode | TreeView, sibling: TreeNode) {
    this.log.debug('moveNode', node, target, sibling);

    if (target instanceof TreeNode) {
      // target.model.children.push(node.model);
      target.insertChild(node, sibling);
      let parent = node.element.parentNode;
      while (parent !== null && parent.tagName !== 'TREE-NODE') {
        parent = parent.parentNode;
      }
      if (parent === null) {
        parent = this;
        parent.removeNode(node);
      } else {
        parent.au['tree-node'].viewModel.removeChild(node.model);
      }
    }
  }

  removeNode(node: TreeNode) {
    console.warn('removeNode not implemented');
  }
}
<|endoftext|>


<commit_before>///import core
///commands 悬浮工具栏
///commandsName  AutoFloat,autoFloatEnabled
///commandsTitle  悬浮工具栏
/*
 *  modified by chengchao01
 *
 *  注意： 引入此功能后，在IE6下会将body的背景图片覆盖掉！
 */
    UE.plugins['autofloat'] = function() {
        var me = this,
                lang = me.getLang();
        me.setOpt({
            topOffset:0
        });
        var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
        topOffset = me.options.topOffset;

        //如果不固定toolbar的位置，则直接退出
        if(!optsAutoFloatEnabled){
            return;
        }
        var uiUtils = UE.ui.uiUtils,
       		LteIE6 = browser.ie && browser.version <= 6,
            quirks = browser.quirks;

        function checkHasUI(editor){
           if(!editor.ui){
              alert(lang.autofloatMsg);
               return 0;
           }
           return 1;
       }
        function fixIE6FixedPos(){
            var docStyle = document.body.style;
           docStyle.backgroundImage = 'url("about:blank")';
           docStyle.backgroundAttachment = 'fixed';
        }
		var	bakCssText,
			placeHolder = document.createElement('div'),
            toolbarBox,orgTop,
            getPosition,
            flag =true;   //ie7模式下需要偏移
		function setFloating(){
			var toobarBoxPos = domUtils.getXY(toolbarBox),
				origalFloat = domUtils.getComputedStyle(toolbarBox,'position'),
                origalLeft = domUtils.getComputedStyle(toolbarBox,'left');
			toolbarBox.style.width = toolbarBox.offsetWidth + 'px';
            toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
			toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
			if (LteIE6 || (quirks && browser.ie)) {
                if(toolbarBox.style.position != 'absolute'){
                    toolbarBox.style.position = 'absolute';
                }
                toolbarBox.style.top = (document.body.scrollTop||document.documentElement.scrollTop) - orgTop + topOffset  + 'px';
			} else {
                if (browser.ie7Compat && flag) {
                    flag = false;
                    toolbarBox.style.left =  domUtils.getXY(toolbarBox).x - document.documentElement.getBoundingClientRect().left+2  + 'px';
                }
                if(toolbarBox.style.position != 'fixed'){
                    toolbarBox.style.position = 'fixed';
                    toolbarBox.style.top = topOffset +"px";
                    ((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px');
                }
			}
		}
		function unsetFloating(){
            flag = true;
            if(placeHolder.parentNode){
                placeHolder.parentNode.removeChild(placeHolder);
            }
			toolbarBox.style.cssText = bakCssText;
		}

        function updateFloating(){
            var rect3 = getPosition(me.container);
            if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > 0) {
                setFloating();
            }else{
                unsetFloating();
            }
        }
        var defer_updateFloating = utils.defer(function(){
            updateFloating();
        },browser.ie ? 200 : 100,true);

        me.addListener('destroy',function(){
            domUtils.un(window, ['scroll','resize'], updateFloating);
            me.removeListener('keydown', defer_updateFloating);
        });
        me.addListener('ready', function(){
            if(checkHasUI(me)){

                getPosition = uiUtils.getClientRect;
                toolbarBox = me.ui.getDom('toolbarbox');
                orgTop = getPosition(toolbarBox).top;
                bakCssText = toolbarBox.style.cssText;
                placeHolder.style.height = toolbarBox.offsetHeight + 'px';
                if(LteIE6){
                    fixIE6FixedPos();
                }
                me.addListener('autoheightchanged', function (t, enabled){
                    if (enabled) {
                        domUtils.on(window, ['scroll','resize'], updateFloating);
                        me.addListener('keydown', defer_updateFloating);
                    } else {
                        domUtils.un(window, ['scroll','resize'], updateFloating);
                        me.removeListener('keydown', defer_updateFloating);
                    }
                });

                me.addListener('beforefullscreenchange', function (t, enabled){
                    if (enabled) {
                        unsetFloating();
                    }
                });
                me.addListener('fullscreenchanged', function (t, enabled){
                    if (!enabled) {
                        updateFloating();
                    }
                });
                me.addListener('sourcemodechanged', function (t, enabled){
                    setTimeout(function (){
                        updateFloating();
                    },0);
                });
            }
        });
	};
<commit_msg>预览时去除表格框选样式<commit_after>///import core
///commands 悬浮工具栏
///commandsName  AutoFloat,autoFloatEnabled
///commandsTitle  悬浮工具栏
/*
 *  modified by chengchao01
 *
 *  注意： 引入此功能后，在IE6下会将body的背景图片覆盖掉！
 */
    UE.plugins['autofloat'] = function() {
        var me = this,
                lang = me.getLang();
        me.setOpt({
            topOffset:0
        });
        var optsAutoFloatEnabled = me.options.autoFloatEnabled !== false,
        topOffset = me.options.topOffset;

        //如果不固定toolbar的位置，则直接退出
        if(!optsAutoFloatEnabled){
            return;
        }
        var uiUtils = UE.ui.uiUtils,
       		LteIE6 = browser.ie && browser.version <= 6,
            quirks = browser.quirks;

        function checkHasUI(editor){
           if(!editor.ui){
              alert(lang.autofloatMsg);
               return 0;
           }
           return 1;
       }
        function fixIE6FixedPos(){
            var docStyle = document.body.style;
           docStyle.backgroundImage = 'url("about:blank")';
           docStyle.backgroundAttachment = 'fixed';
        }
		var	bakCssText,
			placeHolder = document.createElement('div'),
            toolbarBox,orgTop,
            getPosition,
            flag =true;   //ie7模式下需要偏移
		function setFloating(){
			var toobarBoxPos = domUtils.getXY(toolbarBox),
				origalFloat = domUtils.getComputedStyle(toolbarBox,'position'),
                origalLeft = domUtils.getComputedStyle(toolbarBox,'left');
			toolbarBox.style.width = toolbarBox.offsetWidth + 'px';
            toolbarBox.style.zIndex = me.options.zIndex * 1 + 1;
			toolbarBox.parentNode.insertBefore(placeHolder, toolbarBox);
			if (LteIE6 || (quirks && browser.ie)) {
                if(toolbarBox.style.position != 'absolute'){
                    toolbarBox.style.position = 'absolute';
                }
                toolbarBox.style.top = (document.body.scrollTop||document.documentElement.scrollTop) - orgTop + topOffset  + 'px';
			} else {
                if (browser.ie7Compat && flag) {
                    flag = false;
                    toolbarBox.style.left =  domUtils.getXY(toolbarBox).x - document.documentElement.getBoundingClientRect().left+2  + 'px';
                }
                if(toolbarBox.style.position != 'fixed'){
                    toolbarBox.style.position = 'fixed';
                    toolbarBox.style.top = topOffset +"px";
                    ((origalFloat == 'absolute' || origalFloat == 'relative') && parseFloat(origalLeft)) && (toolbarBox.style.left = toobarBoxPos.x + 'px');
                }
			}
		}
		function unsetFloating(){
            flag = true;
            if(placeHolder.parentNode){
                placeHolder.parentNode.removeChild(placeHolder);
            }
			toolbarBox.style.cssText = bakCssText;
		}

        function updateFloating(){
            var rect3 = getPosition(me.container);
            if (rect3.top < 0 && rect3.bottom - toolbarBox.offsetHeight > 0) {
                setFloating();
            }else{
                unsetFloating();
            }
        }
        var defer_updateFloating = utils.defer(function(){
            updateFloating();
        },browser.ie ? 200 : 100,true);

        me.addListener('destroy',function(){
            domUtils.un(window, ['scroll','resize'], updateFloating);
            me.removeListener('keydown', defer_updateFloating);
        });

        me.addListener('ready', function(){
            if(checkHasUI(me)){

                getPosition = uiUtils.getClientRect;
                toolbarBox = me.ui.getDom('toolbarbox');
                orgTop = getPosition(toolbarBox).top;
                bakCssText = toolbarBox.style.cssText;
                placeHolder.style.height = toolbarBox.offsetHeight + 'px';
                if(LteIE6){
                    fixIE6FixedPos();
                }
                me.addListener('autoheightchanged', function (t, enabled){
                    if (enabled) {
                        domUtils.on(window, ['scroll','resize'], updateFloating);
                        me.addListener('keydown', defer_updateFloating);
                    } else {
                        domUtils.un(window, ['scroll','resize'], updateFloating);
                        me.removeListener('keydown', defer_updateFloating);
                    }
                });

                me.addListener('beforefullscreenchange', function (t, enabled){
                    if (enabled) {
                        unsetFloating();
                    }
                });
                me.addListener('fullscreenchanged', function (t, enabled){
                    if (!enabled) {
                        updateFloating();
                    }
                });
                me.addListener('sourcemodechanged', function (t, enabled){
                    setTimeout(function (){
                        updateFloating();
                    },0);
                });
                me.addListener("clearDoc",function(){
                    setTimeout(function(){
                        updateFloating();
                    },0);

                })
            }
        });
	};
<|endoftext|>


<commit_before>// MIT License / Copyright 2015
"use strict";

const weave = require( '..' )
const garden = require( 'gardens' ).createScope( 'weave:linker' )
const router = require( './router' )

const path = require( 'path' )
const Spirit = require( 'string-spirits' )
const url = require( 'url' )

module.exports = function linkToBinding() {
  // Shortcut, because we kind of use this a lot and it's very verbose.
  const binding = weave._bindings[ this.requestUrl.port ]

  // Check for a direct host match, or a cached wildcard match.
  // If there isn't one, check against wildcards, filtering out hosts
  // that don't contain at least one wildcard since they won't match.
  if ( binding.attachments[ this.requestUrl.hostname ] ) {
    this.app = binding.attachments[ this.requestUrl.hostname ]
  } else if ( binding.cachedMatches[ this.requestUrl.hostname ] ) {
    this.app = binding.cachedMatches[ this.requestUrl.hostname ]
  } else {
    // Check the requested host against all linked hostnames that have a wildcard
    let hostname = Spirit.bestMatch(
      Object.keys( binding.attachments ).filter( hostname => /\*|\?/.test( hostname ) ), this.requestUrl.hostname
    ).toString()

    // If there isn't a linked app then just end the connection.
    if ( !hostname ) {
      // XXX: Should we really do this silently? Or should we report?
      garden.warning( 'Incoming connection rejected. No app found.' )
      return request.connection.destroy()
    }

    // Remember which wildcard best matched this host for next time
    this.app = binding.cachedMatches[ this.requestUrl.hostname ] = binding.attachments[ hostname ]
  }

  // Once we've settled on the root app, check domain requirements, and mounts.
  linkToMounts.call( this )
}

function linkToMounts() {
  // Enforce default domains and secure connections
  let forceDomain = this.behavior( 'forceDomain' )
  let forceSecure = this.behavior( 'forceSecure' )

  let redirectDomain = typeof forceDomain === 'string' && forceDomain !== this.requestUrl.hostname
  let redirectSecure = forceSecure && !this.secure
  if ( redirectDomain || redirectSecure ) {
    return this.redirect( url.format( Object.assign( this.requestUrl, {
      protocol: redirectSecure ? 'https:' : this.requestUrl.protocol,
      hostname: redirectDomain ? forceDomain : this.requestUrl.hostname,
      port: redirectSecure
        ? ( typeof forceSecure === 'number' ? force : 443 )
        : this.requestUrl.port
    }) ) )
  }

  // Check to see if we've already found the configuration for this path.
  // If not check to see if there's a directory with a configuration that
  // matches the URL we're processing and cache it. If there are multiple
  // matches we check it against the longest match to see if it's longer.
  // The longest match should always be the most specific configuration.
  if ( this.app._mountPaths[ this.relativeUrl.pathname ] ) {
    this.app = this.app._mountPaths[ this.relativeUrl.pathname ]
  } else {
    // Search to see if we need to resolve to a mount. If we do, we need to recurse
    // through the function again to check for nested mounts.
    if ( Object.keys( this.app.mounts ).some( pathname => {
      // The 2nd condition ensures that the client is requesting *this*
      // directory, and not a file or directory with a longer, overlapping
      // name. Trailing slashes are sanitized on directory names in weave.App,
      // so the forward slash will always be 1 character after the dir name.
      if ( this.relativeUrl.pathname.startsWith( pathname )
      && ( this.relativeUrl.pathname === pathname || this.relativeUrl.pathname.charAt( pathname.length ) === "/" ) ) {
        this.app = this.app._mountPaths[ this.relativeUrl.pathname ] = this.app.mounts[ pathname ]
        this.relativeUrl.pathname = '/' + path.relative( pathname, this.relativeUrl.pathname )
        return true
      }
    }) ) return linkToMounts.call( this )
  }

  // Refuse access if specified to do so
  if ( Array.isArray( this.app.options.forbidden ) ) {
    if ( this.app.options.forbidden.some( pathname => {
      // XXX: This is the same code as used above, but relative.. Should we factor this out somewhere?
      if ( this.relativeUrl.pathname.startsWith( pathname )
      && ( this.relativeUrl.pathname === pathname || this.relativeUrl.pathname.charAt( pathname.length ) === "/" ) ) {
        this.generateErrorPage( new weave.HttpError( 403, 'Access to this URL has been blocked.' ) )
        return true
      }
    }) ) return
  }

  this.app.emit( 'exchange', this )
  router.call( this )
}
<commit_msg>Nested mounts, but they don't break after the first request.<commit_after>// MIT License / Copyright 2015
"use strict";

const weave = require( '..' )
const garden = require( 'gardens' ).createScope( 'weave:linker' )
const router = require( './router' )

const path = require( 'path' )
const Spirit = require( 'string-spirits' )
const url = require( 'url' )

module.exports = function linkToBinding() {
  // Shortcut, because we kind of use this a lot and it's very verbose.
  const binding = weave._bindings[ this.requestUrl.port ]

  // Check for a direct host match, or a cached wildcard match.
  // If there isn't one, check against wildcards, filtering out hosts
  // that don't contain at least one wildcard since they won't match.
  if ( binding.attachments[ this.requestUrl.hostname ] ) {
    this.app = binding.attachments[ this.requestUrl.hostname ]
  } else if ( binding.cachedMatches[ this.requestUrl.hostname ] ) {
    this.app = binding.cachedMatches[ this.requestUrl.hostname ]
  } else {
    // Check the requested host against all linked hostnames that have a wildcard
    let hostname = Spirit.bestMatch(
      Object.keys( binding.attachments ).filter( hostname => /\*|\?/.test( hostname ) ), this.requestUrl.hostname
    ).toString()

    // If there isn't a linked app then just end the connection.
    if ( !hostname ) {
      // XXX: Should we really do this silently? Or should we report?
      garden.warning( 'Incoming connection rejected. No app found.' )
      return request.connection.destroy()
    }

    // Remember which wildcard best matched this host for next time
    this.app = binding.cachedMatches[ this.requestUrl.hostname ] = binding.attachments[ hostname ]
  }

  // Once we've settled on the root app, check domain requirements, and mounts.
  linkToMounts.call( this )
}

function linkToMounts() {
  // Enforce default domains and secure connections
  let forceDomain = this.behavior( 'forceDomain' )
  let forceSecure = this.behavior( 'forceSecure' )

  let redirectDomain = typeof forceDomain === 'string' && forceDomain !== this.requestUrl.hostname
  let redirectSecure = forceSecure && !this.secure
  if ( redirectDomain || redirectSecure ) {
    return this.redirect( url.format( Object.assign( this.requestUrl, {
      protocol: redirectSecure ? 'https:' : this.requestUrl.protocol,
      hostname: redirectDomain ? forceDomain : this.requestUrl.hostname,
      port: redirectSecure
        ? ( typeof forceSecure === 'number' ? force : 443 )
        : this.requestUrl.port
    }) ) )
  }

  // Check to see if we've already found the mount for this path.
  // If not check to see if there's a mount that matches the URL we're
  // processing and cache it. There should only be one match, because
  // mounts cannot overlap. They should be nested.
  if ( this.app._mountPaths[ this.relativeUrl.pathname ] ) {
    let pathname = this.app._mountPaths[ this.relativeUrl.pathname ]
    this.relativeUrl.pathname = '/' + path.relative( pathname, this.relativeUrl.pathname )
    this.app = this.app.mounts[ pathname ]
    return linkToMounts.call( this )
  } else {
    // Search to see if we need to resolve to a mount. If we do, we need to recurse
    // through the function again to check for nested mounts.
    if ( Object.keys( this.app.mounts ).some( pathname => {
      // The 2nd condition ensures that the client is requesting *this*
      // directory, and not a file or directory with a longer, overlapping
      // name. Trailing slashes are sanitized on directory names in weave.App,
      // so the forward slash will always be 1 character after the dir name.
      if ( this.relativeUrl.pathname.startsWith( pathname )
      && ( this.relativeUrl.pathname === pathname || this.relativeUrl.pathname.charAt( pathname.length ) === "/" ) ) {
        this.app._mountPaths[ this.relativeUrl.pathname ] = pathname
        this.relativeUrl.pathname = '/' + path.relative( pathname, this.relativeUrl.pathname )
        this.app = this.app.mounts[ pathname ]
        return true
      }
    }) ) return linkToMounts.call( this )
  }

  // Refuse access if specified to do so
  if ( Array.isArray( this.app.options.forbidden ) ) {
    if ( this.app.options.forbidden.some( pathname => {
      // XXX: This is the same code as used above, but relative.. Should we factor this out somewhere?
      if ( this.relativeUrl.pathname.startsWith( pathname )
      && ( this.relativeUrl.pathname === pathname || this.relativeUrl.pathname.charAt( pathname.length ) === "/" ) ) {
        this.generateErrorPage( new weave.HttpError( 403, 'Access to this URL has been blocked.' ) )
        return true
      }
    }) ) return
  }

  this.app.emit( 'exchange', this )
  router.call( this )
}
<|endoftext|>