<commit_before>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule HTMLDOMPropertyConfig
 */

'use strict';

var DOMProperty = require('DOMProperty');

var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
var HAS_POSITIVE_NUMERIC_VALUE =
  DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
var HAS_OVERLOADED_BOOLEAN_VALUE =
  DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;

var HTMLDOMPropertyConfig = {
  isCustomAttribute: RegExp.prototype.test.bind(
    new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')
  ),
  Properties: {
    /**
     * Standard Properties
     */
    accept: 0,
    acceptCharset: 0,
    accessKey: 0,
    action: 0,
    allowFullScreen: HAS_BOOLEAN_VALUE,
    allowTransparency: 0,
    alt: 0,
    async: HAS_BOOLEAN_VALUE,
    autoComplete: 0,
    // autoFocus is polyfilled/normalized by AutoFocusUtils
    // autoFocus: HAS_BOOLEAN_VALUE,
    autoPlay: HAS_BOOLEAN_VALUE,
    capture: HAS_BOOLEAN_VALUE,
    cellPadding: 0,
    cellSpacing: 0,
    charSet: 0,
    challenge: 0,
    checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    cite: 0,
    classID: 0,
    className: 0,
    cols: HAS_POSITIVE_NUMERIC_VALUE,
    colSpan: 0,
    content: 0,
    contentEditable: 0,
    contextMenu: 0,
    controls: HAS_BOOLEAN_VALUE,
    coords: 0,
    crossOrigin: 0,
    data: 0, // For `<object />` acts as `src`.
    dateTime: 0,
    default: HAS_BOOLEAN_VALUE,
    defer: HAS_BOOLEAN_VALUE,
    dir: 0,
    disabled: HAS_BOOLEAN_VALUE,
    download: HAS_OVERLOADED_BOOLEAN_VALUE,
    draggable: 0,
    encType: 0,
    form: 0,
    formAction: 0,
    formEncType: 0,
    formMethod: 0,
    formNoValidate: HAS_BOOLEAN_VALUE,
    formTarget: 0,
    frameBorder: 0,
    headers: 0,
    height: 0,
    hidden: HAS_BOOLEAN_VALUE,
    high: 0,
    href: 0,
    hrefLang: 0,
    htmlFor: 0,
    httpEquiv: 0,
    icon: 0,
    id: 0,
    inputMode: 0,
    integrity: 0,
    is: 0,
    keyParams: 0,
    keyType: 0,
    kind: 0,
    label: 0,
    lang: 0,
    list: 0,
    loop: HAS_BOOLEAN_VALUE,
    low: 0,
    manifest: 0,
    marginHeight: 0,
    marginWidth: 0,
    max: 0,
    maxLength: 0,
    media: 0,
    mediaGroup: 0,
    method: 0,
    min: 0,
    minLength: 0,
    // Caution; `option.selected` is not updated if `select.multiple` is
    // disabled with `removeAttribute`.
    multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    name: 0,
    nonce: 0,
    noValidate: HAS_BOOLEAN_VALUE,
    open: HAS_BOOLEAN_VALUE,
    optimum: 0,
    pattern: 0,
    placeholder: 0,
    poster: 0,
    preload: 0,
    profile: 0,
    radioGroup: 0,
    readOnly: HAS_BOOLEAN_VALUE,
    rel: 0,
    required: HAS_BOOLEAN_VALUE,
    reversed: HAS_BOOLEAN_VALUE,
    role: 0,
    rows: HAS_POSITIVE_NUMERIC_VALUE,
    rowSpan: HAS_NUMERIC_VALUE,
    sandbox: 0,
    scope: 0,
    scoped: HAS_BOOLEAN_VALUE,
    scrolling: 0,
    seamless: HAS_BOOLEAN_VALUE,
    selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    shape: 0,
    size: HAS_POSITIVE_NUMERIC_VALUE,
    sizes: 0,
    span: HAS_POSITIVE_NUMERIC_VALUE,
    spellCheck: 0,
    src: 0,
    srcDoc: 0,
    srcLang: 0,
    srcSet: 0,
    start: HAS_NUMERIC_VALUE,
    step: 0,
    style: 0,
    summary: 0,
    tabIndex: 0,
    target: 0,
    title: 0,
    // Setting .type throws on non-<input> tags
    type: 0,
    useMap: 0,
    value: 0,
    width: 0,
    wmode: 0,
    wrap: 0,

    /**
     * RDFa Properties
     */
    about: 0,
    datatype: 0,
    inlist: 0,
    prefix: 0,
    // property is also supported for OpenGraph in meta tags.
    property: 0,
    resource: 0,
    typeof: 0,
    vocab: 0,

    /**
     * Non-standard Properties
     */
    // autoCapitalize and autoCorrect are supported in Mobile Safari for
    // keyboard hints.
    autoCapitalize: 0,
    autoCorrect: 0,
    // autoSave allows WebKit/Blink to persist values of input fields on page reloads
    autoSave: 0,
    // color is for Safari mask-icon link
    color: 0,
    // itemProp, itemScope, itemType are for
    // Microdata support. See http://schema.org/docs/gs.html
    itemProp: 0,
    itemScope: HAS_BOOLEAN_VALUE,
    itemType: 0,
    // itemID and itemRef are for Microdata support as well but
    // only specified in the WHATWG spec document. See
    // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api
    itemID: 0,
    itemRef: 0,
    // results show looking glass icon and recent searches on input
    // search fields in WebKit/Blink
    results: 0,
    // IE-only attribute that specifies security restrictions on an iframe
    // as an alternative to the sandbox attribute on IE<10
    security: 0,
    // IE-only attribute that controls focus behavior
    unselectable: 0,
  },
  DOMAttributeNames: {
    acceptCharset: 'accept-charset',
    className: 'class',
    htmlFor: 'for',
    httpEquiv: 'http-equiv',
  },
  DOMPropertyNames: {
  },
};

module.exports = HTMLDOMPropertyConfig;
<commit_msg>Add referrerPolicy to HTMLDOMPropertyConfig (#7274)<commit_after>/**
 * Copyright 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule HTMLDOMPropertyConfig
 */

'use strict';

var DOMProperty = require('DOMProperty');

var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
var HAS_POSITIVE_NUMERIC_VALUE =
  DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
var HAS_OVERLOADED_BOOLEAN_VALUE =
  DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;

var HTMLDOMPropertyConfig = {
  isCustomAttribute: RegExp.prototype.test.bind(
    new RegExp('^(data|aria)-[' + DOMProperty.ATTRIBUTE_NAME_CHAR + ']*$')
  ),
  Properties: {
    /**
     * Standard Properties
     */
    accept: 0,
    acceptCharset: 0,
    accessKey: 0,
    action: 0,
    allowFullScreen: HAS_BOOLEAN_VALUE,
    allowTransparency: 0,
    alt: 0,
    async: HAS_BOOLEAN_VALUE,
    autoComplete: 0,
    // autoFocus is polyfilled/normalized by AutoFocusUtils
    // autoFocus: HAS_BOOLEAN_VALUE,
    autoPlay: HAS_BOOLEAN_VALUE,
    capture: HAS_BOOLEAN_VALUE,
    cellPadding: 0,
    cellSpacing: 0,
    charSet: 0,
    challenge: 0,
    checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    cite: 0,
    classID: 0,
    className: 0,
    cols: HAS_POSITIVE_NUMERIC_VALUE,
    colSpan: 0,
    content: 0,
    contentEditable: 0,
    contextMenu: 0,
    controls: HAS_BOOLEAN_VALUE,
    coords: 0,
    crossOrigin: 0,
    data: 0, // For `<object />` acts as `src`.
    dateTime: 0,
    default: HAS_BOOLEAN_VALUE,
    defer: HAS_BOOLEAN_VALUE,
    dir: 0,
    disabled: HAS_BOOLEAN_VALUE,
    download: HAS_OVERLOADED_BOOLEAN_VALUE,
    draggable: 0,
    encType: 0,
    form: 0,
    formAction: 0,
    formEncType: 0,
    formMethod: 0,
    formNoValidate: HAS_BOOLEAN_VALUE,
    formTarget: 0,
    frameBorder: 0,
    headers: 0,
    height: 0,
    hidden: HAS_BOOLEAN_VALUE,
    high: 0,
    href: 0,
    hrefLang: 0,
    htmlFor: 0,
    httpEquiv: 0,
    icon: 0,
    id: 0,
    inputMode: 0,
    integrity: 0,
    is: 0,
    keyParams: 0,
    keyType: 0,
    kind: 0,
    label: 0,
    lang: 0,
    list: 0,
    loop: HAS_BOOLEAN_VALUE,
    low: 0,
    manifest: 0,
    marginHeight: 0,
    marginWidth: 0,
    max: 0,
    maxLength: 0,
    media: 0,
    mediaGroup: 0,
    method: 0,
    min: 0,
    minLength: 0,
    // Caution; `option.selected` is not updated if `select.multiple` is
    // disabled with `removeAttribute`.
    multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    name: 0,
    nonce: 0,
    noValidate: HAS_BOOLEAN_VALUE,
    open: HAS_BOOLEAN_VALUE,
    optimum: 0,
    pattern: 0,
    placeholder: 0,
    poster: 0,
    preload: 0,
    profile: 0,
    radioGroup: 0,
    readOnly: HAS_BOOLEAN_VALUE,
    referrerPolicy: 0,
    rel: 0,
    required: HAS_BOOLEAN_VALUE,
    reversed: HAS_BOOLEAN_VALUE,
    role: 0,
    rows: HAS_POSITIVE_NUMERIC_VALUE,
    rowSpan: HAS_NUMERIC_VALUE,
    sandbox: 0,
    scope: 0,
    scoped: HAS_BOOLEAN_VALUE,
    scrolling: 0,
    seamless: HAS_BOOLEAN_VALUE,
    selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    shape: 0,
    size: HAS_POSITIVE_NUMERIC_VALUE,
    sizes: 0,
    span: HAS_POSITIVE_NUMERIC_VALUE,
    spellCheck: 0,
    src: 0,
    srcDoc: 0,
    srcLang: 0,
    srcSet: 0,
    start: HAS_NUMERIC_VALUE,
    step: 0,
    style: 0,
    summary: 0,
    tabIndex: 0,
    target: 0,
    title: 0,
    // Setting .type throws on non-<input> tags
    type: 0,
    useMap: 0,
    value: 0,
    width: 0,
    wmode: 0,
    wrap: 0,

    /**
     * RDFa Properties
     */
    about: 0,
    datatype: 0,
    inlist: 0,
    prefix: 0,
    // property is also supported for OpenGraph in meta tags.
    property: 0,
    resource: 0,
    typeof: 0,
    vocab: 0,

    /**
     * Non-standard Properties
     */
    // autoCapitalize and autoCorrect are supported in Mobile Safari for
    // keyboard hints.
    autoCapitalize: 0,
    autoCorrect: 0,
    // autoSave allows WebKit/Blink to persist values of input fields on page reloads
    autoSave: 0,
    // color is for Safari mask-icon link
    color: 0,
    // itemProp, itemScope, itemType are for
    // Microdata support. See http://schema.org/docs/gs.html
    itemProp: 0,
    itemScope: HAS_BOOLEAN_VALUE,
    itemType: 0,
    // itemID and itemRef are for Microdata support as well but
    // only specified in the WHATWG spec document. See
    // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api
    itemID: 0,
    itemRef: 0,
    // results show looking glass icon and recent searches on input
    // search fields in WebKit/Blink
    results: 0,
    // IE-only attribute that specifies security restrictions on an iframe
    // as an alternative to the sandbox attribute on IE<10
    security: 0,
    // IE-only attribute that controls focus behavior
    unselectable: 0,
  },
  DOMAttributeNames: {
    acceptCharset: 'accept-charset',
    className: 'class',
    htmlFor: 'for',
    httpEquiv: 'http-equiv',
  },
  DOMPropertyNames: {
  },
};

module.exports = HTMLDOMPropertyConfig;
<|endoftext|>


<commit_before>(function () {
    'use strict';

    var cfg         = require('nconf'),
        when        = require('when'),
        _           = require('underscore'),
        parse       = require('url').parse,
        provider    = require('../../providers').configProvider,
        mapping     = {
            title:'app:title',
            description:'app:description',
            postsPerPage:'app:postsPerPage'
        };

    module.exports.index = function (req, res) {
        var settings = {
                title:          cfg.get(mapping.title),
                description:    cfg.get(mapping.description),
                postsPerPage:   cfg.get(mapping.postsPerPage)
            },
            url = parse(cfg.get('url'));

        settings.host = url.hostname;

        res.json(settings);
    };

    module.exports.create = function (req, res) {
        var promises = [];

        _.each(req.body, function (value, property) {

            console.info('checking  ', property)

            if (property in mapping && cfg.get(mapping[property]) !== value) {
                console.info('updating ', mapping[property])
                promises.push(
                    provider.saveConfig(mapping[property], value)
                        .then(cfg.set.bind(cfg, mapping[property], value))
                );
            }
        });

        when.all(promises).done(
            module.exports.index.bind(null, req, res),
            res.send.bind(res, 500)
        );
    };

}());<commit_msg>API settings improvements<commit_after>(function () {
    'use strict';

    var cfg             = require('nconf'),
        when            = require('when'),
        _               = require('underscore'),
        parse           = require('url').parse,
        provider        = require('../../providers').configProvider,
        mapping         = {
            title:'app:title',
            description:'app:description',
            postsPerPage:'app:postsPerPage'
        },
        allowedSettings = ['app:postUrl', 'app:pageUrl'];

    module.exports.index = function (req, res) {
        var settings = {
                title:          cfg.get(mapping.title),
                description:    cfg.get(mapping.description),
                postsPerPage:   cfg.get(mapping.postsPerPage)
            },
            url = parse(cfg.get('url'));

        settings.host = url.hostname;

        res.json(settings);
    };

    module.exports.show = function (req, res) {
        var response = {
            key: req.params.setting,
            value: req.setting
        };
        return (req.setting) ? res.json(response) : res.send(404);
    };

    module.exports.load = function (id, fn) {
        if (_.contains(allowedSettings, id)) {
            fn(null, cfg.get(id));
        } else {
            fn();
        }
    };

    module.exports.create = function (req, res) {
        var promises = [];

        _.each(req.body, function (value, property) {

            console.info('checking  ', property)

            if (property in mapping && cfg.get(mapping[property]) !== value) {
                console.info('updating ', mapping[property])
                promises.push(
                    provider.saveConfig(mapping[property], value)
                        .then(cfg.set.bind(cfg, mapping[property], value))
                );
            }
        });

        when.all(promises).done(
            module.exports.index.bind(null, req, res),
            res.send.bind(res, 500)
        );
    };

}());<|endoftext|>


<commit_before><commit_msg>示例插件dat-gui支持国际化<commit_after><|endoftext|>


<commit_before>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import {diffAtCaret, diffDeletion} from "./diff";

export default class EditorModel {
    constructor(parts, partCreator, updateCallback) {
        this._parts = parts;
        this._partCreator = partCreator;
        this._activePartIdx = null;
        this._autoComplete = null;
        this._autoCompletePartIdx = null;
        this._updateCallback = updateCallback;
    }

    _insertPart(index, part) {
        this._parts.splice(index, 0, part);
        if (this._activePartIdx >= index) {
            ++this._activePartIdx;
        }
        if (this._autoCompletePartIdx >= index) {
            ++this._autoCompletePartIdx;
        }
    }

    _removePart(index) {
        this._parts.splice(index, 1);
        if (this._activePartIdx >= index) {
            --this._activePartIdx;
        }
        if (this._autoCompletePartIdx >= index) {
            --this._autoCompletePartIdx;
        }
    }

    _replacePart(index, part) {
        this._parts.splice(index, 1, part);
    }

    get parts() {
        return this._parts;
    }

    get autoComplete() {
        if (this._activePartIdx === this._autoCompletePartIdx) {
            return this._autoComplete;
        }
        return null;
    }

    serializeParts() {
        return this._parts.map(({type, text}) => {return {type, text};});
    }

    _diff(newValue, inputType, caret) {
        // handle deleteContentForward (Delete key)
        // and deleteContentBackward (Backspace)
        const previousValue = this.parts.reduce((text, p) => text + p.text, "");
        // can't use caret position with drag and drop
        if (inputType === "deleteByDrag") {
            return diffDeletion(previousValue, newValue);
        } else {
            return diffAtCaret(previousValue, newValue, caret.offset);
        }
    }

    update(newValue, inputType, caret) {
        const diff = this._diff(newValue, inputType, caret);
        const position = this._positionForOffset(diff.at, caret.atNodeEnd);
        console.log("update at", {position, diff, newValue, prevValue: this.parts.reduce((text, p) => text + p.text, "")});
        let removedOffsetDecrease = 0;
        if (diff.removed) {
            removedOffsetDecrease = this._removeText(position, diff.removed.length);
        }
        let addedLen = 0;
        if (diff.added) {
            addedLen = this._addText(position, diff.added);
        }
        this._mergeAdjacentParts();
        const caretOffset = diff.at - removedOffsetDecrease + addedLen;
        const newPosition = this._positionForOffset(caretOffset, true);
        this._setActivePart(newPosition);
        this._updateCallback(newPosition);
    }

    _setActivePart(pos) {
        const {index} = pos;
        const part = this._parts[index];
        if (part) {
            if (index !== this._activePartIdx) {
                this._activePartIdx = index;
                if (this._activePartIdx !== this._autoCompletePartIdx) {
                    // else try to create one
                    const ac = part.createAutoComplete(this._onAutoComplete);
                    if (ac) {
                        // make sure that react picks up the difference between both acs
                        this._autoComplete = ac;
                        this._autoCompletePartIdx = index;
                    }
                }
            }
            // not _autoComplete, only there if active part is autocomplete part
            if (this.autoComplete) {
                this.autoComplete.onPartUpdate(part, pos.offset);
            }
        } else {
            this._activePartIdx = null;
            this._autoComplete = null;
            this._autoCompletePartIdx = null;
        }
    }

    _onAutoComplete = ({replacePart, caretOffset, close}) => {
        if (replacePart) {
            this._replacePart(this._autoCompletePartIdx, replacePart);
        }
        const index = this._autoCompletePartIdx;
        if (close) {
            this._autoComplete = null;
            this._autoCompletePartIdx = null;
        }
        if (caretOffset === undefined) {
            caretOffset = replacePart.text.length;
        }
        this._updateCallback(new DocumentPosition(index, caretOffset));
    }

    /*
    updateCaret(caret) {
        // update active part here as well, hiding/showing autocomplete if needed
    }
    */

    _mergeAdjacentParts(docPos) {
        let prevPart = this._parts[0];
        for (let i = 1; i < this._parts.length; ++i) {
            let part = this._parts[i];
            const isEmpty = !part.text.length;
            const isMerged = !isEmpty && prevPart.merge(part);
            if (isEmpty || isMerged) {
                // remove empty or merged part
                part = prevPart;
                this._removePart(i);
                //repeat this index, as it's removed now
                --i;
            }
            prevPart = part;
        }
    }

    /**
     * removes `len` amount of characters at `pos`.
     * @return {Number} how many characters before pos were also removed,
     * usually because of non-editable parts that can only be removed in their entirety.
     */
    _removeText(pos, len) {
        let {index, offset} = pos;
        let removedOffsetDecrease = 0;
        while (len > 0) {
            // part might be undefined here
            let part = this._parts[index];
            const amount = Math.min(len, part.text.length - offset);
            if (part.canEdit) {
                const replaceWith = part.remove(offset, amount);
                if (typeof replaceWith === "string") {
                    this._replacePart(index, this._partCreator.createDefaultPart(replaceWith));
                }
                part = this._parts[index];
                // remove empty part
                if (!part.text.length) {
                    this._removePart(index);
                } else {
                    index += 1;
                }
            } else {
                removedOffsetDecrease += offset;
                this._removePart(index);
            }
            len -= amount;
            offset = 0;
        }
        return removedOffsetDecrease;
    }

    /**
     * inserts `str` into the model at `pos`.
     * @return {Number} how far from position (in characters) the insertion ended.
     * This can be more than the length of `str` when crossing non-editable parts, which are skipped.
     */
    _addText(pos, str, actions) {
        let {index} = pos;
        const {offset} = pos;
        let addLen = str.length;
        const part = this._parts[index];
        if (part) {
            if (part.canEdit) {
                if (part.insertAll(offset, str)) {
                    str = null;
                } else {
                    const splitPart = part.split(offset);
                    index += 1;
                    this._insertPart(index, splitPart);
                }
            } else {
                // not-editable, insert str after this part
                addLen += part.text.length - offset;
                index += 1;
            }
        }
        while (str) {
            const newPart = this._partCreator.createPartForInput(str);
            str = newPart.appendUntilRejected(str);
            this._insertPart(index, newPart);
            index += 1;
        }
        return addLen;
    }

    _positionForOffset(totalOffset, atPartEnd) {
        let currentOffset = 0;
        const index = this._parts.findIndex(part => {
            const partLen = part.text.length;
            if (
                (atPartEnd && (currentOffset + partLen) >= totalOffset) ||
                (!atPartEnd && (currentOffset + partLen) > totalOffset)
            ) {
                return true;
            }
            currentOffset += partLen;
            return false;
        });

        return new DocumentPosition(index, totalOffset - currentOffset);
    }
}

class DocumentPosition {
    constructor(index, offset) {
        this._index = index;
        this._offset = offset;
    }

    get index() {
        return this._index;
    }

    get offset() {
        return this._offset;
    }
}
<commit_msg>after completion, set caret in next part at start<commit_after>/*
Copyright 2019 New Vector Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import {diffAtCaret, diffDeletion} from "./diff";

export default class EditorModel {
    constructor(parts, partCreator, updateCallback) {
        this._parts = parts;
        this._partCreator = partCreator;
        this._activePartIdx = null;
        this._autoComplete = null;
        this._autoCompletePartIdx = null;
        this._updateCallback = updateCallback;
    }

    _insertPart(index, part) {
        this._parts.splice(index, 0, part);
        if (this._activePartIdx >= index) {
            ++this._activePartIdx;
        }
        if (this._autoCompletePartIdx >= index) {
            ++this._autoCompletePartIdx;
        }
    }

    _removePart(index) {
        this._parts.splice(index, 1);
        if (this._activePartIdx >= index) {
            --this._activePartIdx;
        }
        if (this._autoCompletePartIdx >= index) {
            --this._autoCompletePartIdx;
        }
    }

    _replacePart(index, part) {
        this._parts.splice(index, 1, part);
    }

    get parts() {
        return this._parts;
    }

    get autoComplete() {
        if (this._activePartIdx === this._autoCompletePartIdx) {
            return this._autoComplete;
        }
        return null;
    }

    serializeParts() {
        return this._parts.map(({type, text}) => {return {type, text};});
    }

    _diff(newValue, inputType, caret) {
        // handle deleteContentForward (Delete key)
        // and deleteContentBackward (Backspace)
        const previousValue = this.parts.reduce((text, p) => text + p.text, "");
        // can't use caret position with drag and drop
        if (inputType === "deleteByDrag") {
            return diffDeletion(previousValue, newValue);
        } else {
            return diffAtCaret(previousValue, newValue, caret.offset);
        }
    }

    update(newValue, inputType, caret) {
        const diff = this._diff(newValue, inputType, caret);
        const position = this._positionForOffset(diff.at, caret.atNodeEnd);
        console.log("update at", {position, diff, newValue, prevValue: this.parts.reduce((text, p) => text + p.text, "")});
        let removedOffsetDecrease = 0;
        if (diff.removed) {
            removedOffsetDecrease = this._removeText(position, diff.removed.length);
        }
        let addedLen = 0;
        if (diff.added) {
            addedLen = this._addText(position, diff.added);
        }
        this._mergeAdjacentParts();
        const caretOffset = diff.at - removedOffsetDecrease + addedLen;
        const newPosition = this._positionForOffset(caretOffset, true);
        this._setActivePart(newPosition);
        this._updateCallback(newPosition);
    }

    _setActivePart(pos) {
        const {index} = pos;
        const part = this._parts[index];
        if (part) {
            if (index !== this._activePartIdx) {
                this._activePartIdx = index;
                if (this._activePartIdx !== this._autoCompletePartIdx) {
                    // else try to create one
                    const ac = part.createAutoComplete(this._onAutoComplete);
                    if (ac) {
                        // make sure that react picks up the difference between both acs
                        this._autoComplete = ac;
                        this._autoCompletePartIdx = index;
                    }
                }
            }
            // not _autoComplete, only there if active part is autocomplete part
            if (this.autoComplete) {
                this.autoComplete.onPartUpdate(part, pos.offset);
            }
        } else {
            this._activePartIdx = null;
            this._autoComplete = null;
            this._autoCompletePartIdx = null;
        }
    }

    _onAutoComplete = ({replacePart, caretOffset, close}) => {
        let pos;
        if (replacePart) {
            this._replacePart(this._autoCompletePartIdx, replacePart);
            let index = this._autoCompletePartIdx;
            if (caretOffset === undefined) {
                caretOffset = 0;
                index += 1;
            }
            pos = new DocumentPosition(index, caretOffset);
        }
        if (close) {
            this._autoComplete = null;
            this._autoCompletePartIdx = null;
        }
        // rerender even if editor contents didn't change
        // to make sure the MessageEditor checks
        // model.autoComplete being empty and closes it
        this._updateCallback(pos);
    }

    /*
    updateCaret(caret) {
        // update active part here as well, hiding/showing autocomplete if needed
    }
    */

    _mergeAdjacentParts(docPos) {
        let prevPart = this._parts[0];
        for (let i = 1; i < this._parts.length; ++i) {
            let part = this._parts[i];
            const isEmpty = !part.text.length;
            const isMerged = !isEmpty && prevPart.merge(part);
            if (isEmpty || isMerged) {
                // remove empty or merged part
                part = prevPart;
                this._removePart(i);
                //repeat this index, as it's removed now
                --i;
            }
            prevPart = part;
        }
    }

    /**
     * removes `len` amount of characters at `pos`.
     * @return {Number} how many characters before pos were also removed,
     * usually because of non-editable parts that can only be removed in their entirety.
     */
    _removeText(pos, len) {
        let {index, offset} = pos;
        let removedOffsetDecrease = 0;
        while (len > 0) {
            // part might be undefined here
            let part = this._parts[index];
            const amount = Math.min(len, part.text.length - offset);
            if (part.canEdit) {
                const replaceWith = part.remove(offset, amount);
                if (typeof replaceWith === "string") {
                    this._replacePart(index, this._partCreator.createDefaultPart(replaceWith));
                }
                part = this._parts[index];
                // remove empty part
                if (!part.text.length) {
                    this._removePart(index);
                } else {
                    index += 1;
                }
            } else {
                removedOffsetDecrease += offset;
                this._removePart(index);
            }
            len -= amount;
            offset = 0;
        }
        return removedOffsetDecrease;
    }

    /**
     * inserts `str` into the model at `pos`.
     * @return {Number} how far from position (in characters) the insertion ended.
     * This can be more than the length of `str` when crossing non-editable parts, which are skipped.
     */
    _addText(pos, str, actions) {
        let {index} = pos;
        const {offset} = pos;
        let addLen = str.length;
        const part = this._parts[index];
        if (part) {
            if (part.canEdit) {
                if (part.insertAll(offset, str)) {
                    str = null;
                } else {
                    const splitPart = part.split(offset);
                    index += 1;
                    this._insertPart(index, splitPart);
                }
            } else {
                // not-editable, insert str after this part
                addLen += part.text.length - offset;
                index += 1;
            }
        }
        while (str) {
            const newPart = this._partCreator.createPartForInput(str);
            str = newPart.appendUntilRejected(str);
            this._insertPart(index, newPart);
            index += 1;
        }
        return addLen;
    }

    _positionForOffset(totalOffset, atPartEnd) {
        let currentOffset = 0;
        const index = this._parts.findIndex(part => {
            const partLen = part.text.length;
            if (
                (atPartEnd && (currentOffset + partLen) >= totalOffset) ||
                (!atPartEnd && (currentOffset + partLen) > totalOffset)
            ) {
                return true;
            }
            currentOffset += partLen;
            return false;
        });

        return new DocumentPosition(index, totalOffset - currentOffset);
    }
}

class DocumentPosition {
    constructor(index, offset) {
        this._index = index;
        this._offset = offset;
    }

    get index() {
        return this._index;
    }

    get offset() {
        return this._offset;
    }
}
<|endoftext|>


<commit_before>const ChildProcess = require('child_process')
const Fs = require('fs')
const Path = require('path')
const OS = require('os')
const Message = require('./Message')
const ControlServer = require('./ControlServer')

function launch(config) {
    if (OS.platform !== 'win32') {
        const MockControlServer = require('./test/util/MockControlServer')
        return new Promise(resolve =>
            resolve(
                MockControlServer.createServer(
                    '127.0.0.1',
                    config.controlServerPort
                )
            )
        )
    }

    const normalizedPath = `${Path.normalize(config.foobarPath)}/`

    if (Fs.readdirSync(normalizedPath).indexOf('foobar2000.exe') === -1) {
        throw new Error(
            'Foobar2000.exe was not found in the path specified in configuration'
        )
    }

    // TODO: handle process termination gracefully
    ChildProcess.exec('foobar2000.exe', { cwd: config.foobarPath })
    return ControlServer.probe(config.controlServerPort)
}

function queryTrackInfo(ctx) {
    return ControlServer.sendCommand(ctx, 'trackinfo')
}

function sendCommand(ctx, io, command) {
    ctx.logger.info({ command }, 'Command received')

    if (command === 'launchFoobar') {
        return launch(ctx.config)
            .then(() => io.sockets.emit('foobarStarted'))
            .catch(() => {
                ctx.logger.warn('Could not launch Foobar')
                io.sockets.emit('controlServerError', 'Could not launch Foobar')
            })
    }

    if (command === 'mute') {
        return ControlServer.sendCommand(ctx, 'vol mute')
    }

    if (command.indexOf('vol') !== -1) {
        return ControlServer.sendCommand(ctx, `vol ${command.substring(3)}`)
    }

    return ChildProcess.exec(`foobar2000.exe /${command}`, {
        cwd: ctx.config.foobarPath
    })
}

function onData(ctx, io) {
    return function controlDataHandler(data) {
        const messages = Message.parseControlData(data.toString('utf-8'))

        ctx.logger.info(messages, 'Received data from control server')

        messages.forEach(message => {
            if (message.type === 'statusChange') {
                io.sockets.emit('foobarStatus', message.status)
            }

            if (message.type === 'info') {
                io.sockets.emit('info', message.content)
            }
        })
    }
}

exports.launch = launch
exports.queryTrackInfo = queryTrackInfo
exports.sendCommand = sendCommand
exports.onData = onData
<commit_msg>Fix foobar2000 launch regression<commit_after>const ChildProcess = require('child_process')
const Fs = require('fs')
const Path = require('path')
const OS = require('os')
const Message = require('./Message')
const ControlServer = require('./ControlServer')

function launch(config) {
    if (OS.platform() !== 'win32') {
        const MockControlServer = require('./test/util/MockControlServer')
        return new Promise(resolve =>
            resolve(
                MockControlServer.createServer(
                    '127.0.0.1',
                    config.controlServerPort
                )
            )
        )
    }

    const normalizedPath = `${Path.normalize(config.foobarPath)}/`

    if (Fs.readdirSync(normalizedPath).indexOf('foobar2000.exe') === -1) {
        throw new Error(
            'Foobar2000.exe was not found in the path specified in configuration'
        )
    }

    // TODO: handle process termination gracefully
    ChildProcess.exec('foobar2000.exe', { cwd: config.foobarPath })
    return ControlServer.probe(config.controlServerPort)
}

function queryTrackInfo(ctx) {
    return ControlServer.sendCommand(ctx, 'trackinfo')
}

function sendCommand(ctx, io, command) {
    ctx.logger.info({ command }, 'Command received')

    if (command === 'launchFoobar') {
        return launch(ctx.config)
            .then(() => io.sockets.emit('foobarStarted'))
            .catch(() => {
                ctx.logger.warn('Could not launch Foobar')
                io.sockets.emit('controlServerError', 'Could not launch Foobar')
            })
    }

    if (command === 'mute') {
        return ControlServer.sendCommand(ctx, 'vol mute')
    }

    if (command.indexOf('vol') !== -1) {
        return ControlServer.sendCommand(ctx, `vol ${command.substring(3)}`)
    }

    return ChildProcess.exec(`foobar2000.exe /${command}`, {
        cwd: ctx.config.foobarPath
    })
}

function onData(ctx, io) {
    return function controlDataHandler(data) {
        const messages = Message.parseControlData(data.toString('utf-8'))

        ctx.logger.info(messages, 'Received data from control server')

        messages.forEach(message => {
            if (message.type === 'statusChange') {
                io.sockets.emit('foobarStatus', message.status)
            }

            if (message.type === 'info') {
                io.sockets.emit('info', message.content)
            }
        })
    }
}

exports.launch = launch
exports.queryTrackInfo = queryTrackInfo
exports.sendCommand = sendCommand
exports.onData = onData
<|endoftext|>


<commit_before><commit_msg>Don't replace quotes when JSON-izing. This causes a diff during replay because the Player does not undo this change in the text. Particular case was .innerHTML with strings around attributes; caused handlebar evals to have different source code offsets.<commit_after><|endoftext|>


<commit_before><commit_msg>Now keeps rows from preferences, added determineNextPanePosition<commit_after><|endoftext|>


<commit_before><commit_msg>add documentation for ColorContrastCalc.prototype.findLightnessThreshold()<commit_after><|endoftext|>


<commit_before>var Cell = require('./Cell');

function Virus() {
    Cell.apply(this, Array.prototype.slice.call(arguments));

    this.cellType = 2;
    this.spiked = 1;
    this.fed = 0;
    this.isMotherCell = false; // Not to confuse bots
}

module.exports = Virus;
Virus.prototype = new Cell();

Virus.prototype.calcMove = null; // Only for player controlled movement

Virus.prototype.feed = function(feeder, gameServer) {
    this.setAngle(feeder.getAngle()); // Set direction if the virus explodes
    this.mass += feeder.mass;
    this.fed++; // Increase feed count
    gameServer.removeNode(feeder);

    // Check if the virus is going to explode
    if (this.fed >= gameServer.config.virusFeedAmount) {
        this.mass = gameServer.config.virusStartMass; // Reset mass
        this.fed = 0;
        gameServer.shootVirus(this);
    }

};

// Main Functions

Virus.prototype.getEatingRange = function() {
    return this.getSize() / 3.14; // 0 for ejected cells
};

Virus.prototype.onConsume = function(consumer, gameServer) {
    var client = consumer.owner;

    // Cell consumes mass before any calculation
    consumer.addMass(this.mass);

    var maxSplits = Math.floor(consumer.mass / 16) - 1; // Maximum amount of splits
    var numSplits = gameServer.config.playerMaxCells - client.cells.length; // Get number of splits
    numSplits = Math.min(numSplits, maxSplits);
    var splitMass = Math.min(consumer.mass / (numSplits + 1), 24); // Maximum size of new splits

    // Cell cannot split any further
    if (numSplits <= 0) {
        return;
    }

    var mass = consumer.mass; // Mass of the consumer
    var bigSplits = []; // Big splits

    // Big cells will split into cells larger than 24 mass
    // won't do the regular way unless it can split more than 4 times
    if (numSplits == 1) bigSplits = [mass / 2];
    else if (numSplits == 2) bigSplits = [mass / 4, mass / 4];
    else if (numSplits == 3) bigSplits = [mass / 4, mass / 4, mass / 7];
    else if (numSplits == 4) bigSplits = [mass / 5, mass / 7, mass / 8, mass / 10];
    else {
        var endMass = mass - numSplits * splitMass;
        var m = endMass,
            i = 0;
        if (m > 466) { // Threshold
            // While can split into an even smaller cell (1000 => 500, 250, etc)
            var mult = 3.33;
            while (m / mult > 24) {
                m /= mult;
                mult = 2.5; // First mult 3.33, the next ones 2.5
                bigSplits.push(m >> 0);
                i++;
            }
        }
    }
    numSplits -= bigSplits.length;

    for (var k = 0; k < bigSplits.length; k++) {
        angle = Math.random() * 6.28; // Random directions
        gameServer.createPlayerCell(client, consumer, angle, bigSplits[k]);
    }

    // Splitting
    for (var k = 0; k < numSplits; k++) {
        angle = Math.random() * 6.28; // Random directions
        gameServer.createPlayerCell(client, consumer, angle, splitMass);
    }

    // Prevent consumer cell from merging with other cells
    consumer.calcMergeTime(gameServer.config.playerRecombineTime);
    client.virusMult += 0.6; // Account for anti-teaming
};

Virus.prototype.onAdd = function(gameServer) {
    gameServer.nodesVirus.push(this);
};

Virus.prototype.onRemove = function(gameServer) {
    var index = gameServer.nodesVirus.indexOf(this);
    if (index != -1) {
        gameServer.nodesVirus.splice(index, 1);
    } else {
        console.log("[Warning] Tried to remove a non existing virus!");
    }
};
<commit_msg>Fix virus changing angle when feeding while moving<commit_after>var Cell = require('./Cell');

function Virus() {
    Cell.apply(this, Array.prototype.slice.call(arguments));

    this.cellType = 2;
    this.spiked = 1;
    this.fed = 0;
    this.isMotherCell = false; // Not to confuse bots
}

module.exports = Virus;
Virus.prototype = new Cell();

Virus.prototype.calcMove = null; // Only for player controlled movement

Virus.prototype.feed = function(feeder, gameServer) {
    if (this.moveEngineTicks == 0) this.setAngle(feeder.getAngle()); // Set direction if the virus explodes
    this.mass += feeder.mass;
    this.fed++; // Increase feed count
    gameServer.removeNode(feeder);

    // Check if the virus is going to explode
    if (this.fed >= gameServer.config.virusFeedAmount) {
        this.mass = gameServer.config.virusStartMass; // Reset mass
        this.fed = 0;
        gameServer.shootVirus(this);
    }

};

// Main Functions

Virus.prototype.getEatingRange = function() {
    return this.getSize() / 3.14; // 0 for ejected cells
};

Virus.prototype.onConsume = function(consumer, gameServer) {
    var client = consumer.owner;

    // Cell consumes mass before any calculation
    consumer.addMass(this.mass);

    var maxSplits = Math.floor(consumer.mass / 16) - 1; // Maximum amount of splits
    var numSplits = gameServer.config.playerMaxCells - client.cells.length; // Get number of splits
    numSplits = Math.min(numSplits, maxSplits);
    var splitMass = Math.min(consumer.mass / (numSplits + 1), 24); // Maximum size of new splits

    // Cell cannot split any further
    if (numSplits <= 0) {
        return;
    }

    var mass = consumer.mass; // Mass of the consumer
    var bigSplits = []; // Big splits

    // Big cells will split into cells larger than 24 mass
    // won't do the regular way unless it can split more than 4 times
    if (numSplits == 1) bigSplits = [mass / 2];
    else if (numSplits == 2) bigSplits = [mass / 4, mass / 4];
    else if (numSplits == 3) bigSplits = [mass / 4, mass / 4, mass / 7];
    else if (numSplits == 4) bigSplits = [mass / 5, mass / 7, mass / 8, mass / 10];
    else {
        var endMass = mass - numSplits * splitMass;
        var m = endMass,
            i = 0;
        if (m > 466) { // Threshold
            // While can split into an even smaller cell (1000 => 500, 250, etc)
            var mult = 3.33;
            while (m / mult > 24) {
                m /= mult;
                mult = 2.5; // First mult 3.33, the next ones 2.5
                bigSplits.push(m >> 0);
                i++;
            }
        }
    }
    numSplits -= bigSplits.length;

    for (var k = 0; k < bigSplits.length; k++) {
        angle = Math.random() * 6.28; // Random directions
        gameServer.createPlayerCell(client, consumer, angle, bigSplits[k]);
    }

    // Splitting
    for (var k = 0; k < numSplits; k++) {
        angle = Math.random() * 6.28; // Random directions
        gameServer.createPlayerCell(client, consumer, angle, splitMass);
    }

    // Prevent consumer cell from merging with other cells
    consumer.calcMergeTime(gameServer.config.playerRecombineTime);
    client.virusMult += 0.6; // Account for anti-teaming
};

Virus.prototype.onAdd = function(gameServer) {
    gameServer.nodesVirus.push(this);
};

Virus.prototype.onRemove = function(gameServer) {
    var index = gameServer.nodesVirus.indexOf(this);
    if (index != -1) {
        gameServer.nodesVirus.splice(index, 1);
    } else {
        console.log("[Warning] Tried to remove a non existing virus!");
    }
};
<|endoftext|>


<commit_before><commit_msg>Support for non-profit partner and user ids<commit_after><|endoftext|>


<commit_before>var Cell = require('./Cell');

function Virus() {
    Cell.apply(this, Array.prototype.slice.call(arguments));
    this.cellType = 2;
    this.isSpiked = true;
    this.isMotherCell = false; // Not to confuse bots
    this.setColor({ r: 0x33, g: 0xff, b: 0x33 });
}

module.exports = Virus;
Virus.prototype = new Cell();

// Main Functions

Virus.prototype.canEat = function (cell) {
    return cell.cellType == 3; // virus can eat ejected mass only
};

Virus.prototype.onEat = function (prey) {
    // Called to eat prey cell
    this.setSize(Math.sqrt(this._sizeSquared + prey._sizeSquared));

    if (this._size >= this.gameServer.config.virusMaxSize) {
        this.setSize(this.gameServer.config.virusMinSize); // Reset mass
        this.gameServer.shootVirus(this, prey.boostDirection.angle);
    }
};

Virus.prototype.onEaten = function (c) {
    if (c.owner == null) return;

    var minSize = this.gameServer.config.playerMinSize,
    min = (minSize == 32) ? 30 : minSize, // minimun size of small splits
    cellsLeft = this.gameServer.config.playerMaxCells - c.owner.cells.length,
    numSplits = cellsLeft < (c._mass / 16) ? cellsLeft : (c._mass / 16),
    splitMass = (c._mass / numSplits) < min ? (c._mass / numSplits) : min;

    // Diverse explosion(s)
    var big = [];
    if (numSplits <= 0) return; // can't split anymore
    if (numSplits == 1) big = [c._mass/2];
    else if (numSplits == 2) big = [c._mass/4,c._mass/4];
    else if (numSplits == 3) big = [c._mass/4,c._mass/4,c._mass/7];
    else if (numSplits == 4) big = [c._mass/5,c._mass/7,c._mass/8,c._mass/10];
    else {
        // ckeck size of exploding
        var threshold = c._mass - numSplits * splitMass;
        // Monotone explosion(s)
        if (threshold > 466) {
            // virus explosion multipliers
            var exp = (Math.random() * (4 - 3.33)) + 3.33;
            while (threshold / exp > 24) {
                threshold /= exp;
                exp = 2;
                big.push(threshold >> 0);
            }
        }
    }
    numSplits -= big.length;
    // big splits
    var angle = 0;
    for (var k = 0; k < big.length; k++) {
        angle = 2 * Math.PI * Math.random(); // random directions
        this.gameServer.splitPlayerCell(c.owner, c, angle, big[k]);
    }
    // small splits
    for (var k = 0; k < numSplits; k++) {
        angle = 2 * Math.PI * Math.random(); // random directions
        this.gameServer.splitPlayerCell(c.owner, c, angle, min);
    }
};

Virus.prototype.onAdd = function (gameServer) {
    gameServer.nodesVirus.push(this);
};

Virus.prototype.onRemove = function (gameServer) {
    var index = gameServer.nodesVirus.indexOf(this);
    if (index != -1)
        gameServer.nodesVirus.splice(index, 1);
};
<commit_msg>Update Virus.js<commit_after>var Cell = require('./Cell');

function Virus() {
    Cell.apply(this, Array.prototype.slice.call(arguments));
    this.cellType = 2;
    this.isSpiked = true;
    this.isMotherCell = false; // Not to confuse bots
    this.setColor({ r: 0x33, g: 0xff, b: 0x33 });
}

module.exports = Virus;
Virus.prototype = new Cell();

// Main Functions

Virus.prototype.canEat = function (cell) {
    return cell.cellType == 3; // virus can eat ejected mass only
};

Virus.prototype.onEat = function (prey) {
    // Called to eat prey cell
    this.setSize(Math.sqrt(this._sizeSquared + prey._sizeSquared));

    if (this._size >= this.gameServer.config.virusMaxSize) {
        this.setSize(this.gameServer.config.virusMinSize); // Reset mass
        this.gameServer.shootVirus(this, prey.boostDirection.angle);
    }
};

Virus.prototype.onEaten = function (c) {
    if (c.owner == null) return;

    var minSize = this.gameServer.config.playerMinSize,
    min = (minSize == 32) ? 30 : minSize, // minimun size of small splits
    cellsLeft = this.gameServer.config.playerMaxCells - c.owner.cells.length,
    numSplits = cellsLeft < (c._mass / 16) ? cellsLeft : (c._mass / 16),
    splitMass = (c._mass / numSplits) < min ? (c._mass / numSplits) : min;

    // Diverse explosion(s)
    var big = [];
    if (numSplits <= 0) return; // can't split anymore
    if (numSplits == 1) big = [c._mass/2];
    else if (numSplits == 2) big = [c._mass/4,c._mass/4];
    else if (numSplits == 3) big = [c._mass/4,c._mass/4,c._mass/7];
    else if (numSplits == 4) big = [c._mass/5,c._mass/7,c._mass/8,c._mass/10];
    else {
        // ckeck size of exploding
        var threshold = c._mass - numSplits * splitMass;
        // Monotone explosion(s)
        if (threshold > 466) {
            // virus explosion multipliers
            var exp = (Math.random() * (5 - 3.33)) + 3.33;
            while (threshold / exp > 24) {
                threshold /= exp;
                exp = 2;
                big.push(threshold >> 0);
            }
        }
    }
    numSplits -= big.length;
    // big splits
    var angle = 0;
    for (var k = 0; k < big.length; k++) {
        angle = 2 * Math.PI * Math.random(); // random directions
        this.gameServer.splitPlayerCell(c.owner, c, angle, big[k]);
    }
    // small splits
    for (var k = 0; k < numSplits; k++) {
        angle = 2 * Math.PI * Math.random(); // random directions
        this.gameServer.splitPlayerCell(c.owner, c, angle, min);
    }
};

Virus.prototype.onAdd = function (gameServer) {
    gameServer.nodesVirus.push(this);
};

Virus.prototype.onRemove = function (gameServer) {
    var index = gameServer.nodesVirus.indexOf(this);
    if (index != -1)
        gameServer.nodesVirus.splice(index, 1);
};
<|endoftext|>


<commit_before>// Copyright 2014-2015, Renasar Technologies Inc.
/* jshint node:true */

'use strict';

describe('DHCP API', function () {

    before(function () {
        this.timeout(5000);
        return helper.startServer([
            dihelper.simpleWrapper({
                lookupIpLease: sinon.stub().returns(Q.resolve('00:00:00:00:00:00')),
                peekLeaseTable: sinon.stub().returns(Q.resolve({
                    leases: {
                        "08:00:27:52:d2:a4": {
                            "mac": "08:00:27:52:d2:a4",
                            "ipAddress": "10.1.1.2",
                            "reservationTimer": 30,
                            "reservationExpiresAt": "",
                            "renewalTimer": 21600,
                            "rebindingTimer": 4320,
                            "expirationTimer": 86400,
                            "renewalExpiresAt": 1424149074811,
                            "rebindExpiresAt": 1424131794811,
                            "leaseExpiresAt": 1424213874811,
                            "boundFlag": true,
                            "reservedFlag": false,
                            "reserveTimer": ""
                        },
                        "00:11:22:33:44:55": {
                            "mac": "00:11:22:33:44:55",
                            "ipAddress": "10.1.1.200",
                            "reservationTimer": 30,
                            "reservationExpiresAt": "",
                            "renewalTimer": 21600,
                            "rebindingTimer": 4320,
                            "expirationTimer": 86400,
                            "renewalExpiresAt": 1424149074811,
                            "rebindExpiresAt": 1424131794811,
                            "leaseExpiresAt": 1424213874811,
                            "boundFlag": true,
                            "reservedFlag": false,
                            "reserveTimer": ""
                        }
                    }
                }))
            }, 'Protocol.Dhcp')
        ]);
    });

    beforeEach(function () {
        return helper.reset();
    });

    after(function () {
        return helper.stopServer();
    });

    describe('/api/common/dhcp', function() {
        it('GET should return all the leases peekLeaseTable', function () {
            return helper.request().get('/api/common/dhcp/')
                .expect('Content-Type', /^application\/json/)
                .expect(200)
                .expect(function (res) {
                    expect(res.body).to.have.property('08:00:27:52:d2:a4');
                    expect(res.body).to.have.property('00:11:22:33:44:55');
                });
        });
    });
    describe('/api/common/dhcp/lease/:macaddress', function() {

        it('GET should return the lease detail from peekLeaseTable', function () {
            return helper.request().get('/api/common/dhcp/lease/08:00:27:52:d2:a4')
                .expect('Content-Type', /^application\/json/)
                .expect(200)
                .expect(function (res) {
                    expect(res.body).to.have.property('mac', '08:00:27:52:d2:a4');
                    expect(res.body).to.have.property('ipAddress', '10.1.1.2');
                    expect(res.body).to.have.property('leaseExpiresAt', 1424213874811);
                });
        });

        it('GET should return 404 if the mac isnt in the lease table', function () {
            return helper.request().get('/api/common/dhcp/lease/00:00:00:11:11:11')
                .expect('Content-Type', /^application\/json/)
                .expect(404);
        });
    });

});
<commit_msg>giving the DHCP test setup a touch more time based on what I'm seeing on my vabrant instance<commit_after>// Copyright 2014-2015, Renasar Technologies Inc.
/* jshint node:true */

'use strict';

describe('DHCP API', function () {

    before(function () {
        this.timeout(10000);
        return helper.startServer([
            dihelper.simpleWrapper({
                lookupIpLease: sinon.stub().returns(Q.resolve('00:00:00:00:00:00')),
                peekLeaseTable: sinon.stub().returns(Q.resolve({
                    leases: {
                        "08:00:27:52:d2:a4": {
                            "mac": "08:00:27:52:d2:a4",
                            "ipAddress": "10.1.1.2",
                            "reservationTimer": 30,
                            "reservationExpiresAt": "",
                            "renewalTimer": 21600,
                            "rebindingTimer": 4320,
                            "expirationTimer": 86400,
                            "renewalExpiresAt": 1424149074811,
                            "rebindExpiresAt": 1424131794811,
                            "leaseExpiresAt": 1424213874811,
                            "boundFlag": true,
                            "reservedFlag": false,
                            "reserveTimer": ""
                        },
                        "00:11:22:33:44:55": {
                            "mac": "00:11:22:33:44:55",
                            "ipAddress": "10.1.1.200",
                            "reservationTimer": 30,
                            "reservationExpiresAt": "",
                            "renewalTimer": 21600,
                            "rebindingTimer": 4320,
                            "expirationTimer": 86400,
                            "renewalExpiresAt": 1424149074811,
                            "rebindExpiresAt": 1424131794811,
                            "leaseExpiresAt": 1424213874811,
                            "boundFlag": true,
                            "reservedFlag": false,
                            "reserveTimer": ""
                        }
                    }
                }))
            }, 'Protocol.Dhcp')
        ]);
    });

    beforeEach(function () {
        return helper.reset();
    });

    after(function () {
        return helper.stopServer();
    });

    describe('/api/common/dhcp', function() {
        it('GET should return all the leases peekLeaseTable', function () {
            return helper.request().get('/api/common/dhcp/')
                .expect('Content-Type', /^application\/json/)
                .expect(200)
                .expect(function (res) {
                    expect(res.body).to.have.property('08:00:27:52:d2:a4');
                    expect(res.body).to.have.property('00:11:22:33:44:55');
                });
        });
    });
    describe('/api/common/dhcp/lease/:macaddress', function() {

        it('GET should return the lease detail from peekLeaseTable', function () {
            return helper.request().get('/api/common/dhcp/lease/08:00:27:52:d2:a4')
                .expect('Content-Type', /^application\/json/)
                .expect(200)
                .expect(function (res) {
                    expect(res.body).to.have.property('mac', '08:00:27:52:d2:a4');
                    expect(res.body).to.have.property('ipAddress', '10.1.1.2');
                    expect(res.body).to.have.property('leaseExpiresAt', 1424213874811);
                });
        });

        it('GET should return 404 if the mac isnt in the lease table', function () {
            return helper.request().get('/api/common/dhcp/lease/00:00:00:11:11:11')
                .expect('Content-Type', /^application\/json/)
                .expect(404);
        });
    });

});
<|endoftext|>


<commit_before><commit_msg>Fixed test bug.<commit_after><|endoftext|>


<commit_before>/**
 * ISO Msg
 * @author Sean sean.snow@live.com
 * @date 2015/12/22
 */
import ISOUtil from './ISOUtil';
import ISOComponent from './ISOComponent';
import ISOField from './ISOField';
import ISOHeader from './ISOHeader';
import ISOBasePackager from './ISOBasePackager';
import ISOBinaryFieldPackager from './packer/ISOBinaryFieldPackager';
import ISOBinaryField from './ISOBinaryField';
import BitSet from 'jsdk/util/BitSet';
import ISOBitMap from './ISOBitMap';

class ISOMsg extends ISOComponent {

    fields = {};
    maxField = -1;
    dirty = true;
    maxFieldDirty = true;
    direction = 0;
    header = null;
    trailer = null;
    fieldNumber = -1;
    packager:ISOBasePackager = null;

    setPackager(packager:ISOBasePackager) {
        this.packager = packager;
    }

    setFieldNumber(fieldNumber:Number) {
        this.fieldNumber = fieldNumber;
    }

    setMTI(mti:String) {
        if (this.isInnter()) {
            throw Error('can\'t setMTI on inner message');
        }
        this.set(new ISOField(0, mti));
    }

    isInnter():Boolean {
        return this.fieldNumber > -1;
    }

    set(c) {
        if (c != null) {
            let i = c.getKey();
            this.fields[i] = c;
            if (i > this.maxField) {
                this.maxField = i;
            }
            this.dirty = true;
        }
    }

    unset(fldno:Number) {
        if (this.fields[fldno] != null) {
            this.dirty = this.maxFieldDirty = true;
            delete this.fields[fldno];
        }
    }

    setStrField(fldno:Number, value:String) {
        if (value != null) {
            if (!(this.packager instanceof ISOBasePackager)) {
                this.set(new ISOField(fldno, value));
            } else {
                let obj = this.packager.getFieldPackager(fldno);
                if (obj instanceof ISOBinaryFieldPackager) {
                    this.set(new ISOBinaryField(fldno, ISOUtil.hex2byte(value)));
                } else {
                    this.set(new ISOField(fldno, value));
                }
            }

        } else {
            this.unset(fldno);
        }
    }

    getComposite():ISOComponent {
        //noinspection JSValidateTypes
        return this;
    }

    getChildren():Object {
        return this.fields;
    }

    setHeader(header:ISOHeader) {
        this.header = header;
    }

    getHeader():Array {
        return this.header != null ? this.header.pack() : null;
    }

    getMaxField():Number {
        if (this.maxFieldDirty) {
            this._recalcMaxField();
        }
        return this.maxField;
    }

    pack():Array {
        this._recalcBitMap();
        return this.packager.pack(this);
    }

    unpack(b:Array):Number {
        return this.packager.unpack(this, b);
    }

    _recalcBitMap() {
        if (!this.dirty) {
            return;
        }
        let mf = Math.min(this.getMaxField(), 192);
        let bmap = new BitSet(mf + 62 >> 6 << 6);
        for (let i = 1; i <= mf; i++) {
            if (this.fields[i] != null) {
                bmap.set(i);
            }
        }
        this.set(new ISOBitMap(-1, bmap));
        this.dirty = false;
    }

    /**
     *
     * @private
     */
    _recalcMaxField() {
        this.maxField = 0;
        Object.keys(this.fields).forEach(key => {
            this.maxField = Math.max(this.maxField, Number(key));
        });
        this.maxFieldDirty = false;
    }

}

export default ISOMsg;<commit_msg>setStrField to setField<commit_after>/**
 * ISO Msg
 * @author Sean sean.snow@live.com
 * @date 2015/12/22
 */
import ISOUtil from './ISOUtil';
import ISOComponent from './ISOComponent';
import ISOField from './ISOField';
import ISOHeader from './ISOHeader';
import ISOBasePackager from './ISOBasePackager';
import ISOBinaryFieldPackager from './packer/ISOBinaryFieldPackager';
import ISOBinaryField from './ISOBinaryField';
import BitSet from 'jsdk/util/BitSet';
import ISOBitMap from './ISOBitMap';

class ISOMsg extends ISOComponent {

    fields = {};
    maxField = -1;
    dirty = true;
    maxFieldDirty = true;
    direction = 0;
    header = null;
    trailer = null;
    fieldNumber = -1;
    packager:ISOBasePackager = null;

    setPackager(packager:ISOBasePackager) {
        this.packager = packager;
    }

    setFieldNumber(fieldNumber:Number) {
        this.fieldNumber = fieldNumber;
    }

    setMTI(mti:String) {
        if (this.isInnter()) {
            throw Error('can\'t setMTI on inner message');
        }
        this.set(new ISOField(0, mti));
    }

    isInnter():Boolean {
        return this.fieldNumber > -1;
    }

    set(c) {
        if (c != null) {
            let i = c.getKey();
            this.fields[i] = c;
            if (i > this.maxField) {
                this.maxField = i;
            }
            this.dirty = true;
        }
    }

    unset(fldno:Number) {
        if (this.fields[fldno] != null) {
            this.dirty = this.maxFieldDirty = true;
            delete this.fields[fldno];
        }
    }

    setField(fldno:Number, value) {
        if (value != null) {
            if (!(this.packager instanceof ISOBasePackager)) {
                this.set(new ISOField(fldno, value));
            } else {
                let obj = this.packager.getFieldPackager(fldno);
                if (obj instanceof ISOBinaryFieldPackager) {
                    this.set(new ISOBinaryField(fldno, ISOUtil.hex2byte(value)));
                } else {
                    this.set(new ISOField(fldno, value));
                }
            }

        } else {
            this.unset(fldno);
        }
    }

    getComposite():ISOComponent {
        //noinspection JSValidateTypes
        return this;
    }

    getChildren():Object {
        return this.fields;
    }

    setHeader(header:ISOHeader) {
        this.header = header;
    }

    getHeader():Array {
        return this.header != null ? this.header.pack() : null;
    }

    getMaxField():Number {
        if (this.maxFieldDirty) {
            this._recalcMaxField();
        }
        return this.maxField;
    }

    pack():Array {
        this._recalcBitMap();
        return this.packager.pack(this);
    }

    unpack(b:Array):Number {
        return this.packager.unpack(this, b);
    }

    _recalcBitMap() {
        if (!this.dirty) {
            return;
        }
        let mf = Math.min(this.getMaxField(), 192);
        let bmap = new BitSet(mf + 62 >> 6 << 6);
        for (let i = 1; i <= mf; i++) {
            if (this.fields[i] != null) {
                bmap.set(i);
            }
        }
        this.set(new ISOBitMap(-1, bmap));
        this.dirty = false;
    }

    /**
     *
     * @private
     */
    _recalcMaxField() {
        this.maxField = 0;
        Object.keys(this.fields).forEach(key => {
            this.maxField = Math.max(this.maxField, Number(key));
        });
        this.maxFieldDirty = false;
    }

}

export default ISOMsg;<|endoftext|>


<commit_before>goog.provide('ol.test.rendering.style.RegularShape');

describe('ol.rendering.style.RegularShape', function() {

  var target, map, vectorSource;

  function createMap(renderer) {
    target = createMapDiv(50, 50);

    vectorSource = new ol.source.Vector();
    vectorLayer = new ol.layer.Vector({
      source: vectorSource
    });

    map = new ol.Map({
      target: target,
      renderer: renderer,
      layers: [vectorLayer],
      view: new ol.View({
        projection: 'EPSG:4326',
        center: [0, 0],
        resolution: 1
      })
    });
    return map;
  }

  describe('#render', function() {
    afterEach(function() {
      disposeMap(map);
    });

    function createFeatures() {
      var stroke = new ol.style.Stroke({color: 'black', width: 2});
      var fill = new ol.style.Fill({color: 'red'});

      var feature;
      feature = new ol.Feature({
        geometry: new ol.geom.Point([-15, 15])
      });
      // square
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 4,
          radius: 10,
          angle: Math.PI / 4
        })
      }));
      vectorSource.addFeature(feature);

      feature = new ol.Feature({
        geometry: new ol.geom.Point([8, 15])
      });
      // triangle
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 3,
          radius: 10,
          rotation: Math.PI / 4,
          angle: 0
        })
      }));
      vectorSource.addFeature(feature);

      feature = new ol.Feature({
        geometry: new ol.geom.Point([-10, -8])
      });
      // star
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 5,
          radius: 10,
          radius2: 4,
          angle: 0
        })
      }));
      vectorSource.addFeature(feature);

      feature = new ol.Feature({
        geometry: new ol.geom.Point([12, -8])
      });
      // cross
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 4,
          radius: 10,
          radius2: 0,
          angle: 0
        })
      }));
      vectorSource.addFeature(feature);
    }

    it('tests the canvas renderer', function(done) {
      map = createMap('canvas');
      createFeatures();
      expectResemble(map, 'spec/ol/style/expected/regularshape-canvas.png',
          7.0, done);
    });

    it('tests the WebGL renderer', function(done) {
      assertWebGL();
      map = createMap('webgl');
      createFeatures();
      expectResemble(map, 'spec/ol/style/expected/regularshape-webgl.png',
          8.2, done);
    });
  });
});

goog.require('goog.dispose');
goog.require('ol.Feature');
goog.require('ol.geom.Point');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Fill');
goog.require('ol.style.RegularShape');
goog.require('ol.style.Style');
goog.require('ol.style.Stroke');
<commit_msg>Make regularshape tests pass on Safari on OSX<commit_after>goog.provide('ol.test.rendering.style.RegularShape');

describe('ol.rendering.style.RegularShape', function() {

  var target, map, vectorSource;

  function createMap(renderer) {
    target = createMapDiv(50, 50);

    vectorSource = new ol.source.Vector();
    vectorLayer = new ol.layer.Vector({
      source: vectorSource
    });

    map = new ol.Map({
      target: target,
      renderer: renderer,
      layers: [vectorLayer],
      view: new ol.View({
        projection: 'EPSG:4326',
        center: [0, 0],
        resolution: 1
      })
    });
    return map;
  }

  describe('#render', function() {
    afterEach(function() {
      disposeMap(map);
    });

    function createFeatures() {
      var stroke = new ol.style.Stroke({color: 'black', width: 2});
      var fill = new ol.style.Fill({color: 'red'});

      var feature;
      feature = new ol.Feature({
        geometry: new ol.geom.Point([-15, 15])
      });
      // square
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 4,
          radius: 10,
          angle: Math.PI / 4
        })
      }));
      vectorSource.addFeature(feature);

      feature = new ol.Feature({
        geometry: new ol.geom.Point([8, 15])
      });
      // triangle
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 3,
          radius: 10,
          rotation: Math.PI / 4,
          angle: 0
        })
      }));
      vectorSource.addFeature(feature);

      feature = new ol.Feature({
        geometry: new ol.geom.Point([-10, -8])
      });
      // star
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 5,
          radius: 10,
          radius2: 4,
          angle: 0
        })
      }));
      vectorSource.addFeature(feature);

      feature = new ol.Feature({
        geometry: new ol.geom.Point([12, -8])
      });
      // cross
      feature.setStyle(new ol.style.Style({
        image: new ol.style.RegularShape({
          fill: fill,
          stroke: stroke,
          points: 4,
          radius: 10,
          radius2: 0,
          angle: 0
        })
      }));
      vectorSource.addFeature(feature);
    }

    it('tests the canvas renderer', function(done) {
      map = createMap('canvas');
      createFeatures();
      expectResemble(map, 'spec/ol/style/expected/regularshape-canvas.png',
          9.4, done);
    });

    it('tests the WebGL renderer', function(done) {
      assertWebGL();
      map = createMap('webgl');
      createFeatures();
      expectResemble(map, 'spec/ol/style/expected/regularshape-webgl.png',
          8.2, done);
    });
  });
});

goog.require('goog.dispose');
goog.require('ol.Feature');
goog.require('ol.geom.Point');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Fill');
goog.require('ol.style.RegularShape');
goog.require('ol.style.Style');
goog.require('ol.style.Stroke');
<|endoftext|>


<commit_before>
function openerp_picking_widgets(instance){
    var module = instance.stock;

    module.PickingEditorWidget = instance.web.Widget.extend({
        template: 'PickingEditorWidget',
        init: function(parent,options){
            this._super(parent,options);
        },
        get_header: function(){
            var model = this.getParent();
            return 'Picking: '+model.picking.name;
        },
        get_rows: function(){
            var model = this.getParent();
            var rows = [];

            _.each( model.movelines, function(moveline){
                rows.push({
                    cols: { product: moveline.product_id[1],
                            qty: moveline.product_qty,
                            rem: moveline.remaining_qty,
                            uom: moveline.product_uom[1],
                            loc: moveline.location_id[1],
                            stat: moveline.state
                    },
                    classes: (moveline.qty_remaining < 0 ? 'oe_invalid' : '')
                });
            });

            return rows;
        },
    });

    module.PackageEditorWidget = instance.web.Widget.extend({
        template: 'PackageEditorWidget',
        get_header: function(){
            var model = this.getParent();
            var current_package_id = instance.session.user_context.current_package_id;
            return current_package_id ? 'Current Operations for package: ' + current_package_id[1] : 'Current Operations';
        },
        get_rows: function(){
            var current_package_id = instance.session.user_context.current_package_id;
            var model = this.getParent();
            var rows = [];

            _.each( model.operations, function(op){
                if(current_package_id && op.package_id !== current_package_id){
                    return;
                }
                rows.push({
                    cols: {
                        product: op.product_id[1],
                        uom: op.product_uom ? product_uom[1] : '',
                        qty: op.product_qty,
                    }
                });
            });

            return rows;
        },
    });

    module.PackageSelectorWidget = instance.web.Widget.extend({
        template: 'PackageSelectorWidget',
        get_header: function(){
            return this._header || 'Packages:';
        },
        get_rows: function(){
            var model = this.getParent();
            var rows = [];
            _.each( model.packages, function(pack){
                rows.push({
                    cols:{ pack: pack.name},
                    id: pack.id
                });
            });
            return rows;
        },
    });

    module.PickingMainWidget = instance.web.Widget.extend({
        template: 'PickingMainWidget',
        init: function(parent,params){
            this._super(parent,params);
            var self = this;

            this.picking = null;
            this.movelines = null;
            this.operations = null;
            this.packages = null;

            window.pickwidget = this;

            console.log('Action params:', params);
            console.log('Session:',instance.session);

            this.loaded =  this.load();
        },
        load: function(picking_id){
            var self = this;

            if(picking_id){
                var picking = new instance.web.Model('stock.picking.in').call('read',[[picking_id], []]);
            }else{
                var picking = new instance.web.Model('stock.picking.in').query().first();
            }

            var loaded = picking.then(function(picking){
                    self.picking = picking instanceof Array ? picking[0] : picking;
                    console.log('Picking:',self.picking);

                    return new instance.web.Model('stock.move').call('read',[self.picking.move_lines, []]);
                }).then(function(movelines){
                    self.movelines = movelines;
                    console.log('Move Lines:',movelines);

                    return new instance.web.Model('stock.pack.operation').call('read',[self.picking.pack_operation_ids, []]);
                }).then(function(operations){
                    self.operations = operations;
                    console.log('Operations:',self.operations);

                    var package_ids = [];

                    for(var i = 0; i < operations.length; i++){
                        if(!_.contains(package_ids,operations[i].result_package_id[0])){
                            package_ids.push(operations[i].result_package_id[0]);
                        }
                    }
                    console.log('Package ids:',package_ids);

                    return new instance.web.Model('stock.quant.package').call('read',[package_ids, []]);
                }).then(function(packages){
                    self.packages = packages;
                    console.log('Packages:', self.packages);
                });

            return loaded;
        },
        start: function(){
            var self = this;
            instance.webclient.set_content_full_screen(true);
            this.connect_barcode_scanner();

            this.$('.js_pick_quit').click(function(){ self.quit(); });
            this.$('.js_pick_pack').click(function(){ self.pack(); });
            this.$('.js_pick_done').click(function(){ self.done(); });

            $.when(this.loaded).done(function(){
                self.picking_editor = new module.PickingEditorWidget(self);
                self.picking_editor.replace(self.$('.oe_placeholder_picking_editor'));

                self.package_editor = new module.PackageEditorWidget(self);
                self.package_editor.replace(self.$('.oe_placeholder_package_editor'));

                self.package_selector = new module.PackageSelectorWidget(self);
                self.package_selector.replace(self.$('.oe_placeholder_package_selector'));
            });

            return this._super();
        },
        // reloads the data from the provided picking and refresh the ui.
        // (if no picking_id is provided, gets the first picking in the db)
        refresh_ui: function(picking_id){
            var self = this;
            return this.load(picking_id)
                .then(function(){
                    console.log('Refreshing UI');
                    self.picking_editor.renderElement();
                    self.package_editor.renderElement();
                    self.package_selector.renderElement();
                });
        },
        scan: function(ean){
            var self = this;
            console.log('Scan: ',ean);
            new instance.web.Model('stock.picking')
                .call('get_barcode_and_return_todo_stuff', [self.picking.id, ean])
                .then(function(){
                    return self.refresh_ui(self.picking.id);
                });
        },
        pack: function(){
            var self = this;
            console.log('Pack');
            new instance.web.Model('stock.picking')
                .call('action_pack',[[self.picking.id]])
                .then(function(){
                    instance.session.user_context.current_package_id = false;
                    console.log('Context Reset');

                    return self.refresh_ui(self.picking.id);
                });
        },
        done: function(){
            var self = this;
            console.log('Done');
            new instance.web.Model('stock.picking')
                .call('action_done_from_packing_ui',[[self.picking.id]])
                .then(function(new_picking_id){
                    console.log('New picking id:',new_picking_id);
                });
        },
        connect_barcode_scanner: function(){
            var self =this;
            var code = [];
            var timestamp = 0;
            $('body').delegate('','keyup',function(e){
                if (e.keyCode >= 48 && e.keyCode < 58){
                    if(timestamp + 30 < new Date().getTime()){
                        code = [];
                    }
                    timestamp = new Date().getTime();
                    code.push(e.keyCode - 48);
                    if(code.length === 13){
                        self.scan(code.join(''));
                        code = [];
                    }
                }else{
                    code = [];
                }
            });
        },
        disconnect_barcode_scanner: function(){
            $('body').undelegate('', 'keyup')
        },
        quit: function(){
            console.log('Quit');
            disconnect_barcode_scanner();
            instance.webclient.set_content_full_screen(false);
            window.location = '/'; // FIXME THIS IS SHIT NIV WILL KILL YOU (BY MULTIPLE FACE-STABBING) IF YOU MERGE THIS IN TRUNK
        },
    });
}
<commit_msg>[MERGE] stock.ui: wip: trying to provide context<commit_after>
function openerp_picking_widgets(instance){
    var module = instance.stock;

    module.PickingEditorWidget = instance.web.Widget.extend({
        template: 'PickingEditorWidget',
        init: function(parent,options){
            this._super(parent,options);
        },
        get_header: function(){
            var model = this.getParent();
            return 'Picking: '+model.picking.name;
        },
        get_rows: function(){
            var model = this.getParent();
            var rows = [];

            _.each( model.movelines, function(moveline){
                rows.push({
                    cols: { product: moveline.product_id[1],
                            qty: moveline.product_qty,
                            rem: moveline.remaining_qty,
                            uom: moveline.product_uom[1],
                            loc: moveline.location_id[1],
                            stat: moveline.state
                    },
                    classes: (moveline.qty_remaining < 0 ? 'oe_invalid' : '')
                });
            });

            return rows;
        },
    });

    module.PackageEditorWidget = instance.web.Widget.extend({
        template: 'PackageEditorWidget',
        get_header: function(){
            var model = this.getParent();
            var current_package_id = instance.session.user_context.current_package_id;
            return current_package_id ? 'Current Operations for package: ' + current_package_id[1] : 'Current Operations';
        },
        get_rows: function(){
            var current_package_id = instance.session.user_context.current_package_id;
            var model = this.getParent();
            var rows = [];

            _.each( model.operations, function(op){
                if(current_package_id && op.package_id !== current_package_id){
                    return;
                }
                rows.push({
                    cols: {
                        product: op.product_id[1],
                        uom: op.product_uom ? product_uom[1] : '',
                        qty: op.product_qty,
                    }
                });
            });

            return rows;
        },
    });

    module.PackageSelectorWidget = instance.web.Widget.extend({
        template: 'PackageSelectorWidget',
        get_header: function(){
            return this._header || 'Packages:';
        },
        get_rows: function(){
            var model = this.getParent();
            var rows = [];
            _.each( model.packages, function(pack){
                rows.push({
                    cols:{ pack: pack.name},
                    id: pack.id
                });
            });
            return rows;
        },
    });

    module.PickingMainWidget = instance.web.Widget.extend({
        template: 'PickingMainWidget',
        init: function(parent,params){
            this._super(parent,params);
            var self = this;

            this.picking = null;
            this.movelines = null;
            this.operations = null;
            this.packages = null;

            window.pickwidget = this;

            console.log('Action params:', params);
            console.log('Session:',instance.session);

            this.loaded =  this.load();
        },
        load: function(picking_id){
            var self = this;

            if(picking_id){
                var picking = new instance.web.Model('stock.picking.in').call('read',[[picking_id], []]);
            }else{
                var picking = new instance.web.Model('stock.picking.in').query().first();
            }

            var loaded = picking.then(function(picking){
                    self.picking = picking instanceof Array ? picking[0] : picking;
                    console.log('Picking:',self.picking);
                    console.log('User Context:', instance.session.user_context);
                    console.log('Context:', new instance.web.CompoundContext().eval());

                    return new instance.web.Model('stock.move').call('read',[self.picking.move_lines, [], new instance.web.CompoundContext()]);
                }).then(function(movelines){
                    self.movelines = movelines;
                    console.log('Move Lines:',movelines);

                    return new instance.web.Model('stock.pack.operation').call('read',[self.picking.pack_operation_ids, [], new instance.web.CompoundContext()]);
                }).then(function(operations){
                    self.operations = operations;
                    console.log('Operations:',self.operations);

                    var package_ids = [];

                    for(var i = 0; i < operations.length; i++){
                        if(!_.contains(package_ids,operations[i].result_package_id[0])){
                            package_ids.push(operations[i].result_package_id[0]);
                        }
                    }

                    console.log('Package ids:',package_ids);

                    return new instance.web.Model('stock.quant.package').call('read',[package_ids, [], new instance.web.CompoundContext()]);
                }).then(function(packages){
                    self.packages = packages;
                    console.log('Packages:', self.packages);
                });

            return loaded;
        },
        start: function(){
            var self = this;
            instance.webclient.set_content_full_screen(true);
            this.connect_barcode_scanner();

            this.$('.js_pick_quit').click(function(){ self.quit(); });
            this.$('.js_pick_pack').click(function(){ self.pack(); });
            this.$('.js_pick_done').click(function(){ self.done(); });

            $.when(this.loaded).done(function(){
                self.picking_editor = new module.PickingEditorWidget(self);
                self.picking_editor.replace(self.$('.oe_placeholder_picking_editor'));

                self.package_editor = new module.PackageEditorWidget(self);
                self.package_editor.replace(self.$('.oe_placeholder_package_editor'));

                self.package_selector = new module.PackageSelectorWidget(self);
                self.package_selector.replace(self.$('.oe_placeholder_package_selector'));
            });

            return this._super();
        },
        // reloads the data from the provided picking and refresh the ui.
        // (if no picking_id is provided, gets the first picking in the db)
        refresh_ui: function(picking_id){
            var self = this;
            return this.load(picking_id)
                .then(function(){
                    console.log('Refreshing UI');
                    self.picking_editor.renderElement();
                    self.package_editor.renderElement();
                    self.package_selector.renderElement();
                });
        },
        scan: function(ean){
            var self = this;
            console.log('Scan: ',ean);
            new instance.web.Model('stock.picking')
                .call('get_barcode_and_return_todo_stuff', [self.picking.id, ean])
                .then(function(){
                    return self.refresh_ui(self.picking.id);
                });
        },
        pack: function(){
            var self = this;
            console.log('Pack');
            new instance.web.Model('stock.picking')
                .call('action_pack',[[self.picking.id]])
                .then(function(){
                    instance.session.user_context.current_package_id = false;
                    console.log('Context Reset');

                    return self.refresh_ui(self.picking.id);
                });
        },
        done: function(){
            var self = this;
            console.log('Done');
            new instance.web.Model('stock.picking')
                .call('action_done_from_packing_ui',[[self.picking.id]])
                .then(function(new_picking_id){
                    console.log('New picking id:',new_picking_id);
                });
        },
        connect_barcode_scanner: function(){
            var self =this;
            var code = [];
            var timestamp = 0;
            $('body').delegate('','keyup',function(e){
                if (e.keyCode >= 48 && e.keyCode < 58){
                    if(timestamp + 30 < new Date().getTime()){
                        code = [];
                    }
                    timestamp = new Date().getTime();
                    code.push(e.keyCode - 48);
                    if(code.length === 13){
                        self.scan(code.join(''));
                        code = [];
                    }
                }else{
                    code = [];
                }
            });
        },
        disconnect_barcode_scanner: function(){
            $('body').undelegate('', 'keyup')
        },
        quit: function(){
            console.log('Quit');
            disconnect_barcode_scanner();
            instance.webclient.set_content_full_screen(false);
            window.location = '/'; // FIXME THIS IS SHIT NIV WILL KILL YOU (BY MULTIPLE FACE-STABBING) IF YOU MERGE THIS IN TRUNK
        },
    });
}
<|endoftext|>


<commit_before>define([], function() {
    "use strict";

    /**
     * doc: a DOM document
     * factories: an array of arrays:
     *          [
     *              [
     *                  'css-class-for-widet',
     *                  WidgetConstructor,
     *                  optional further WidgetConstructor_arguments
     *                  , ...
     *              ]
     *          ]
     *      A WidgetConstructor will be called essentially like this:
     *
     *      new WidgetConstructor(domElement,
     *                            pubsub,
     *                            ..., further WidgetConstructor_arguments);
     */
    function initDocumentWidgets(doc, factories, pubsub) {
        var i, l, className, containersForClass, Constructor
         , j, ll, container
         , containers = []
         , args, instance
         ;
        for(i=0,l=factories.length;i<l;i++) {
            className = factories[i][0];
            containersForClass = doc.getElementsByClassName(className);
            if(!containersForClass.length)
                continue;
            Constructor = factories[i][1];
            for(j=0,ll=containersForClass.length;j<ll;j++) {
                container = containersForClass[j];
                containers.push(container);
                args = [container, pubsub];
                Array.prototype.push.apply(args, factories[i].slice(2));
                // this way we can call the Constructor with a
                // dynamic arguments list, i.e. by circumvent the `new`
                // keyword via Object.create.
                instance = Object.create(Constructor.prototype);
                Constructor.apply(instance, args);
            }
        }
        return containers;
    }

    return initDocumentWidgets;
});
<commit_msg>initDocumentWidgets: updating inline comments<commit_after>define([], function() {
    "use strict";

    /**
     * doc: a DOM document
     * factories: an array of arrays:
     *          [
     *              [
     *                  '.css-class-for-widget-container',
     *                  WidgetConstructor,
     *                  optional further WidgetConstructor_arguments
     *                  , ...
     *              ]
     *          ]
     *      A WidgetConstructor will be called essentially like this:
     *
     *      new WidgetConstructor(domContainer,
     *                            pubsub,
     *                            ..., further WidgetConstructor_arguments);
     */
    function initDocumentWidgets(doc, factories, pubsub) {
        var i, l, className, containersForClass, Constructor
         , j, ll, container
         , containers = []
         , args, instance
         ;
        for(i=0,l=factories.length;i<l;i++) {
            className = factories[i][0];
            containersForClass = doc.getElementsByClassName(className);
            if(!containersForClass.length)
                continue;
            Constructor = factories[i][1];
            for(j=0,ll=containersForClass.length;j<ll;j++) {
                container = containersForClass[j];
                containers.push(container);
                args = [container, pubsub];
                Array.prototype.push.apply(args, factories[i].slice(2));
                // this way we can call the Constructor with a
                // dynamic arguments list, i.e. by circumventing the `new`
                // keyword via Object.create.
                instance = Object.create(Constructor.prototype);
                Constructor.apply(instance, args);
            }
        }
        return containers;
    }

    return initDocumentWidgets;
});
<|endoftext|>