<commit_before>// Process [link](<to> "stuff")

'use strict';

var normalizeReference   = require('../common/utils').normalizeReference;
var isSpace              = require('../common/utils').isSpace;

module.exports = function link(state, silent) {
  var attrs,
      code,
      label,
      labelEnd,
      labelStart,
      pos,
      res,
      ref,
      title,
      token,
      href = '',
      oldPos = state.pos,
      max = state.posMax,
      start = state.pos,
      parseReference = true;

  if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false; }

  labelStart = state.pos + 1;
  labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);

  // parser failed to find ']', so it's not a valid link
  if (labelEnd < 0) { return false; }

  pos = labelEnd + 1;
  if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
    //
    // Inline link
    //

    // might have found a valid shortcut link, disable reference parsing
    parseReference = false;

    // [link](  <href>  "title"  )
    //        ^^ skipping these spaces
    pos++;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace(code) && code !== 0x0A) { break; }
    }
    if (pos >= max) { return false; }

    // [link](  <href>  "title"  )
    //          ^^^^^^ parsing link destination
    start = pos;
    res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
    if (res.ok) {
      href = state.md.normalizeLink(res.str);
      if (state.md.validateLink(href)) {
        pos = res.pos;
      } else {
        href = '';
      }
    }

    // [link](  <href>  "title"  )
    //                ^^ skipping these spaces
    start = pos;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace(code) && code !== 0x0A) { break; }
    }

    // [link](  <href>  "title"  )
    //                  ^^^^^^^ parsing link title
    res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
    if (pos < max && start !== pos && res.ok) {
      title = res.str;
      pos = res.pos;

      // [link](  <href>  "title"  )
      //                         ^^ skipping these spaces
      for (; pos < max; pos++) {
        code = state.src.charCodeAt(pos);
        if (!isSpace(code) && code !== 0x0A) { break; }
      }
    } else {
      title = '';
    }

    if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
      // parsing a valid shortcut link failed, fallback to reference
      parseReference = true;
    }
    pos++;
  }

  if (parseReference) {
    //
    // Link reference
    //
    if (typeof state.env.references === 'undefined') { return false; }

    if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
      start = pos + 1;
      pos = state.md.helpers.parseLinkLabel(state, pos);
      if (pos >= 0) {
        label = state.src.slice(start, pos++);
      } else {
        pos = labelEnd + 1;
      }
    } else {
      pos = labelEnd + 1;
    }

    // covers label === '' and label === undefined
    // (collapsed reference link and shortcut reference link respectively)
    if (!label) { label = state.src.slice(labelStart, labelEnd); }

    ref = state.env.references[normalizeReference(label)];
    if (!ref) {
      state.pos = oldPos;
      return false;
    }
    href = ref.href;
    title = ref.title;
  }

  //
  // We found the end of the link, and know for a fact it's a valid link;
  // so all that's left to do is to call tokenizer.
  //
  if (!silent) {
    state.pos = labelStart;
    state.posMax = labelEnd;

    token        = state.push('link_open', 'a', 1);
    token.attrs  = attrs = [ [ 'href', href ] ];
    if (title) {
      attrs.push([ 'title', title ]);
    }

    state.md.inline.tokenize(state);

    token        = state.push('link_close', 'a', -1);
  }

  state.pos = pos;
  state.posMax = max;
  return true;
};
<commit_msg>update return<commit_after>// Process [link](<to> "stuff")

'use strict';

var normalizeReference   = require('../common/utils').normalizeReference;
var isSpace              = require('../common/utils').isSpace;

module.exports = function link(state, silent) {
  var attrs,
      code,
      label,
      labelEnd,
      labelStart,
      pos,
      res,
      ref,
      title,
      token,
      href = '',
      oldPos = state.pos,
      max = state.posMax,
      start = state.pos,
      parseReference = true;

  if (state.src.charCodeAt(state.pos) !== 0x5B/* [ */) { return false; }

  labelStart = state.pos + 1;
  labelEnd = state.md.helpers.parseLinkLabel(state, state.pos, true);

  // parser failed to find ']', so it's not a valid link
  if (labelEnd < 0) { return false; }

  pos = labelEnd + 1;
  if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
    //
    // Inline link
    //

    // might have found a valid shortcut link, disable reference parsing
    parseReference = false;

    // [link](  <href>  "title"  )
    //        ^^ skipping these spaces
    pos++;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace(code) && code !== 0x0A) { break; }
    }
    if (pos >= max) { return false; }

    // [link](  <href>  "title"  )
    //          ^^^^^^ parsing link destination
    start = pos;
    res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
    if (res.ok) {
      href = state.md.normalizeLink(res.str);
      if (state.md.validateLink(href)) {
        pos = res.pos;
      } else {
        href = '';
      }
    }

    // [link](  <href>  "title"  )
    //                ^^ skipping these spaces
    start = pos;
    for (; pos < max; pos++) {
      code = state.src.charCodeAt(pos);
      if (!isSpace(code) && code !== 0x0A) { break; }
    }

    // [link](  <href>  "title"  )
    //                  ^^^^^^^ parsing link title
    res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
    if (pos < max && start !== pos && res.ok) {
      title = res.str;
      pos = res.pos;

      // [link](  <href>  "title"  )
      //                         ^^ skipping these spaces
      for (; pos < max; pos++) {
        code = state.src.charCodeAt(pos);
        if (!isSpace(code) && code !== 0x0A) { break; }
      }
    } else {
      title = '';
    }

    if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
      // parsing a valid shortcut link failed, fallback to reference
      parseReference = true;
    }
    pos++;
  }

  if (parseReference) {
    //
    // Link reference
    //
    if (!state.env || typeof state.env.references === 'undefined') {
      return false;
    }

    if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
      start = pos + 1;
      pos = state.md.helpers.parseLinkLabel(state, pos);
      if (pos >= 0) {
        label = state.src.slice(start, pos++);
      } else {
        pos = labelEnd + 1;
      }
    } else {
      pos = labelEnd + 1;
    }

    // covers label === '' and label === undefined
    // (collapsed reference link and shortcut reference link respectively)
    if (!label) { label = state.src.slice(labelStart, labelEnd); }

    ref = state.env.references[normalizeReference(label)];
    if (!ref) {
      state.pos = oldPos;
      return false;
    }
    href = ref.href;
    title = ref.title;
  }

  //
  // We found the end of the link, and know for a fact it's a valid link;
  // so all that's left to do is to call tokenizer.
  //
  if (!silent) {
    state.pos = labelStart;
    state.posMax = labelEnd;

    token        = state.push('link_open', 'a', 1);
    token.attrs  = attrs = [ [ 'href', href ] ];
    if (title) {
      attrs.push([ 'title', title ]);
    }

    state.md.inline.tokenize(state);

    token        = state.push('link_close', 'a', -1);
  }

  state.pos = pos;
  state.posMax = max;
  return true;
};
<|endoftext|>


<commit_before>import React from 'react'

import { TableRow, TableRowColumn } from 'material-ui/Table'

const DayRate = ({ annualLeave, sickLeave, publicHolidays, weekends, days, salary, kiwisaver, depreciation, phoneContribution, style }) => {

  const total = Object.values(days)
    .filter(value => value < 54) // get rid of the 'thisYear' value
    .reduce((a, b) => a + b) // add up all the remaining values
    - (annualLeave + sickLeave + publicHolidays + weekends)

  const sum = salary + kiwisaver + depreciation + phoneContribution

  console.log({annualLeave, sickLeave, publicHolidays, weekends, days, salary, kiwisaver, depreciation, phoneContribution, style, total, sum});

  return (
    <TableRow>
      <TableRowColumn>

Your day rate is

      </TableRowColumn>
      <TableRowColumn>

          { '$' + (!isNaN(total) && !isNaN(sum) && annualLeave && sickLeave && (sum / total).toFixed(2)) }

      </TableRowColumn>
    </TableRow>
  )
}

export default DayRate
<commit_msg>working validation<commit_after>import React from 'react'

import { TableRow, TableRowColumn } from 'material-ui/Table'

const DayRate = ({ annualLeave, sickLeave, publicHolidays, weekends, days, salary, kiwisaver, depreciation, phoneContribution, style }) => {

  const total = Object.values(days)
    .filter(value => value < 54) // get rid of the 'thisYear' value
    .reduce((a, b) => a + b) // add up all the remaining values
    - (annualLeave + sickLeave + publicHolidays + weekends)

  const sum = salary + kiwisaver + depreciation + phoneContribution
  const output = sum / total
  // (!isNaN(total) && !isNaN(sum) && annualLeave && sickLeave && (sum / total).toFixed(2))
  console.log({annualLeave, sickLeave, publicHolidays, weekends, days, salary, kiwisaver, depreciation, phoneContribution, style, total, sum});

  return (
    <TableRow>
      <TableRowColumn>

Your day rate is

      </TableRowColumn>
      <TableRowColumn>

          { !isNaN(output) && output && '$' + output.toFixed(2) }

      </TableRowColumn>
    </TableRow>
  )
}

export default DayRate
<|endoftext|>


<commit_before>django.jQuery(function($) {
	'use strict';

	// create class handling the client-side part of JumbotronPlugin
	var base_plugins = eval(django.cascade.ring_plugin_bases.JumbotronPlugin),
	    $fileIdInputSelector = $('#id_image_file'),
	    $backgroundInputSize = $('input[name="background_size"]'),
	    $backgroundWidthHeight = $('.form-row.field-background_width_height');

	django.cascade.JumbotronPlugin = ring.create(base_plugins, {
		constructor: function() {
			var self = this;
			this.$super();

			// install event handlers
			$fileIdInputSelector.on('change', function() {
				window.setTimeout(self.fileIdInputChanged);
			});
			$backgroundInputSize.on('change', self.backgroundInputSizeChanged);

			// set defaults
			this.refreshChangeForm();
		},
		fileIdInputChanged: function () {
			var $backgroundHorizontalPosition = $('#id_glossary_background_horizontal_position'),
			    $backgroundVerticalPosition = $('#id_glossary_background_vertical_position'),
			    $backgroundAttachment = $('#id_glossary_background_attachment'),
			    $backgroundRepeat = $('#id_glossary_background_repeat');
			if ($fileIdInputSelector.val()) {
				$backgroundHorizontalPosition.prop('disabled', false);
				$backgroundVerticalPosition.prop('disabled', false);
				$backgroundAttachment.prop('disabled', false);
				$backgroundRepeat.prop('disabled', false);
				$backgroundInputSize.prop('disabled', false);
				$backgroundWidthHeight.find('input').prop('disabled', false);
			} else {
				$backgroundHorizontalPosition.prop('disabled', true);
				$backgroundVerticalPosition.prop('disabled', true);
				$backgroundAttachment.prop('disabled', true);
				$backgroundRepeat.prop('disabled', true);
				$backgroundInputSize.prop('disabled', true);
				$backgroundWidthHeight.find('input').prop('disabled', true);
			}
		},
		backgroundInputSizeChanged: function() {
			var $inputField = $('input[name="background_size"]:checked');
			if ($inputField.val() === 'width/height') {
				$backgroundWidthHeight.show();
			} else {
				$backgroundWidthHeight.hide();
			}
		},
		refreshChangeForm: function() {
			this.fileIdInputChanged();
			this.backgroundInputSizeChanged();
			this.$super && this.$super();
		}

	});
});
<commit_msg>fix HTML selectors after switching to django-entangled<commit_after>django.jQuery(function($) {
	'use strict';

	// create class handling the client-side part of JumbotronPlugin
	var base_plugins = eval(django.cascade.ring_plugin_bases.JumbotronPlugin),
	    $fileIdInputSelector = $('#id_image_file'),
	    $backgroundInputSize = $('input[name="background_size"]'),
	    $backgroundWidthHeight = $('.form-row.field-background_width_height');

	django.cascade.JumbotronPlugin = ring.create(base_plugins, {
		constructor: function() {
			var self = this;
			this.$super();

			// install event handlers
			$fileIdInputSelector.on('change', function() {
				window.setTimeout(self.fileIdInputChanged);
			});
			$backgroundInputSize.on('change', self.backgroundInputSizeChanged);

			// set defaults
			this.refreshChangeForm();
		},
		fileIdInputChanged: function () {
			var $backgroundHorizontalPosition = $('#id_background_horizontal_position'),
			    $backgroundVerticalPosition = $('#id_background_vertical_position'),
			    $backgroundAttachment = $('input[name="background_attachment"]'),
			    $backgroundRepeat = $('input[name="background_repeat"]');
			if ($fileIdInputSelector.val()) {
				$backgroundHorizontalPosition.prop('disabled', false);
				$backgroundVerticalPosition.prop('disabled', false);
				$backgroundAttachment.prop('disabled', false);
				$backgroundRepeat.prop('disabled', false);
				$backgroundInputSize.prop('disabled', false);
				$backgroundWidthHeight.find('input').prop('disabled', false);
			} else {
				$backgroundHorizontalPosition.prop('disabled', true);
				$backgroundVerticalPosition.prop('disabled', true);
				$backgroundAttachment.prop('disabled', true);
				$backgroundRepeat.prop('disabled', true);
				$backgroundInputSize.prop('disabled', true);
				$backgroundWidthHeight.find('input').prop('disabled', true);
			}
		},
		backgroundInputSizeChanged: function() {
			var $inputField = $('input[name="background_size"]:checked');
			if ($inputField.val() === 'width/height') {
				$backgroundWidthHeight.show();
			} else {
				$backgroundWidthHeight.hide();
			}
		},
		refreshChangeForm: function() {
			this.fileIdInputChanged();
			this.backgroundInputSizeChanged();
			this.$super && this.$super();
		}

	});
});
<|endoftext|>


<commit_before>import { helper } from '@ember/component/helper';

import window from 'ember-window-mock';

function newNumberFormat() {
  try {
    return new Intl.NumberFormat(window.navigator.languages || window.navigator.language);
  } catch {
    return new Intl.NumberFormat('en');
  }
}

export function formatNum(value) {
  return newNumberFormat().format(value);
}

export default helper(params => formatNum(params[0]));
<commit_msg>helpers/format-num: Convert to class-based helper<commit_after>import Helper from '@ember/component/helper';

import window from 'ember-window-mock';

function newNumberFormat() {
  try {
    return new Intl.NumberFormat(window.navigator.languages || window.navigator.language);
  } catch {
    return new Intl.NumberFormat('en');
  }
}

export default class FormatNumHelper extends Helper {
  compute([value]) {
    return newNumberFormat().format(value);
  }
}
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

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 React, {useRef, useState} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {Key} from "../../Keyboard";
import sdk from "../../index";
import AccessibleButton from "../views/elements/AccessibleButton";

// Shamelessly ripped off Modal.js.  There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
// pass in a custom control as the actual body.

const ContextualMenuContainerId = "mx_ContextualMenu_Container";

function getOrCreateContainer() {
    let container = document.getElementById(ContextualMenuContainerId);

    if (!container) {
        container = document.createElement("div");
        container.id = ContextualMenuContainerId;
        document.body.appendChild(container);
    }

    return container;
}

const ARIA_MENU_ITEM_ROLES = new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]);
// Generic ContextMenu Portal wrapper
// all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1}
// this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines.
export class ContextMenu extends React.Component {
    propTypes: {
        top: PropTypes.number,
        bottom: PropTypes.number,
        left: PropTypes.number,
        right: PropTypes.number,
        menuWidth: PropTypes.number,
        menuHeight: PropTypes.number,
        chevronOffset: PropTypes.number,
        chevronFace: PropTypes.string, // top, bottom, left, right or none
        // Function to be called on menu close
        onFinished: PropTypes.func.isRequired,
        menuPaddingTop: PropTypes.number,
        menuPaddingRight: PropTypes.number,
        menuPaddingBottom: PropTypes.number,
        menuPaddingLeft: PropTypes.number,
        zIndex: PropTypes.number,

        // If true, insert an invisible screen-sized element behind the
        // menu that when clicked will close it.
        hasBackground: PropTypes.bool,

        // on resize callback
        windowResize: PropTypes.func,
    };

    static defaultProps = {
        hasBackground: true,
    };

    constructor() {
        super();
        this.state = {
            contextMenuElem: null,
        };

        // persist what had focus when we got initialized so we can return it after
        this.initialFocus = document.activeElement;
    }

    componentWillUnmount() {
        // return focus to the thing which had it before us
        this.initialFocus.focus();
    }

    collectContextMenuRect = (element) => {
        // We don't need to clean up when unmounting, so ignore
        if (!element) return;

        let first = element.querySelector('[role^="menuitem"]');
        if (!first) {
            first = element.querySelector('[tab-index]');
        }
        if (first) {
            first.focus();
        }

        this.setState({
            contextMenuElem: element,
        });
    };

    onContextMenu = (e) => {
        if (this.props.onFinished) {
            this.props.onFinished();

            e.preventDefault();
            const x = e.clientX;
            const y = e.clientY;

            // XXX: This isn't pretty but the only way to allow opening a different context menu on right click whilst
            // a context menu and its click-guard are up without completely rewriting how the context menus work.
            setImmediate(() => {
                const clickEvent = document.createEvent('MouseEvents');
                clickEvent.initMouseEvent(
                    'contextmenu', true, true, window, 0,
                    0, 0, x, y, false, false,
                    false, false, 0, null,
                );
                document.elementFromPoint(x, y).dispatchEvent(clickEvent);
            });
        }
    };

    _onMoveFocus = (element, up) => {
        let descending = false; // are we currently descending or ascending through the DOM tree?

        do {
            const child = up ? element.lastElementChild : element.firstElementChild;
            const sibling = up ? element.previousElementSibling : element.nextElementSibling;

            if (descending) {
                if (child) {
                    element = child;
                } else if (sibling) {
                    element = sibling;
                } else {
                    descending = false;
                    element = element.parentElement;
                }
            } else {
                if (sibling) {
                    element = sibling;
                    descending = true;
                } else {
                    element = element.parentElement;
                }
            }

            if (element) {
                if (element.classList.contains("mx_ContextualMenu")) { // we hit the top
                    element = up ? element.lastElementChild : element.firstElementChild;
                    descending = true;
                }
            }
        } while (element && !ARIA_MENU_ITEM_ROLES.has(element.getAttribute("role")));

        if (element) {
            element.focus();
        }
    };

    _onMoveFocusHomeEnd = (element, up) => {
        let results = element.querySelectorAll('[role^="menuitem"]');
        if (!results) {
            results = element.querySelectorAll('[tab-index]');
        }
        if (results && results.length) {
            if (up) {
                results[0].focus();
            } else {
                results[results.length - 1].focus();
            }
        }
    };

    _onKeyDown = (ev) => {
        switch (ev.key) {
            case Key.TAB:
            case Key.ESCAPE:
                this.props.onFinished();
                break;
            case Key.ARROW_UP:
                this._onMoveFocus(ev.target, true);
                break;
            case Key.ARROW_DOWN:
                this._onMoveFocus(ev.target, false);
                break;
            case Key.HOME:
                this._onMoveFocusHomeEnd(this.state.contextMenuElem, true);
                break;
            case Key.END:
                this._onMoveFocusHomeEnd(this.state.contextMenuElem, false);
                break;
        }

        // consume all other keys in context menu
        ev.stopPropagation();
        ev.preventDefault();
    };

    renderMenu(hasBackground=this.props.hasBackground) {
        const position = {};
        let chevronFace = null;
        const props = this.props;

        if (props.top) {
            position.top = props.top;
        } else {
            position.bottom = props.bottom;
        }

        if (props.left) {
            position.left = props.left;
            chevronFace = 'left';
        } else {
            position.right = props.right;
            chevronFace = 'right';
        }

        const contextMenuRect = this.state.contextMenuElem ? this.state.contextMenuElem.getBoundingClientRect() : null;
        const padding = 10;

        const chevronOffset = {};
        if (props.chevronFace) {
            chevronFace = props.chevronFace;
        }
        const hasChevron = chevronFace && chevronFace !== "none";

        if (chevronFace === 'top' || chevronFace === 'bottom') {
            chevronOffset.left = props.chevronOffset;
        } else {
            const target = position.top;

            // By default, no adjustment is made
            let adjusted = target;

            // If we know the dimensions of the context menu, adjust its position
            // such that it does not leave the (padded) window.
            if (contextMenuRect) {
                adjusted = Math.min(position.top, document.body.clientHeight - contextMenuRect.height - padding);
            }

            position.top = adjusted;
            chevronOffset.top = Math.max(props.chevronOffset, props.chevronOffset + target - adjusted);
        }

        let chevron;
        if (hasChevron) {
            chevron =
;
        }

        const menuClasses = classNames({
            'mx_ContextualMenu': true,
            'mx_ContextualMenu_left': !hasChevron && position.left,
            'mx_ContextualMenu_right': !hasChevron && position.right,
            'mx_ContextualMenu_top': !hasChevron && position.top,
            'mx_ContextualMenu_bottom': !hasChevron && position.bottom,
            'mx_ContextualMenu_withChevron_left': chevronFace === 'left',
            'mx_ContextualMenu_withChevron_right': chevronFace === 'right',
            'mx_ContextualMenu_withChevron_top': chevronFace === 'top',
            'mx_ContextualMenu_withChevron_bottom': chevronFace === 'bottom',
        });

        const menuStyle = {};
        if (props.menuWidth) {
            menuStyle.width = props.menuWidth;
        }

        if (props.menuHeight) {
            menuStyle.height = props.menuHeight;
        }

        if (!isNaN(Number(props.menuPaddingTop))) {
            menuStyle["paddingTop"] = props.menuPaddingTop;
        }
        if (!isNaN(Number(props.menuPaddingLeft))) {
            menuStyle["paddingLeft"] = props.menuPaddingLeft;
        }
        if (!isNaN(Number(props.menuPaddingBottom))) {
            menuStyle["paddingBottom"] = props.menuPaddingBottom;
        }
        if (!isNaN(Number(props.menuPaddingRight))) {
            menuStyle["paddingRight"] = props.menuPaddingRight;
        }

        const wrapperStyle = {};
        if (!isNaN(Number(props.zIndex))) {
            menuStyle["zIndex"] = props.zIndex + 1;
            wrapperStyle["zIndex"] = props.zIndex;
        }

        let background;
        if (hasBackground) {
            background = (

            );
        }

        return (

                    { chevron }
                    { props.children }

                { background }

        );
    }

    render() {
        return ReactDOM.createPortal(this.renderMenu(), getOrCreateContainer());
    }
}

// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
export const ContextMenuButton = ({ label, isExpanded, children, ...props }) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} title={label} aria-label={label} aria-haspopup={true} aria-expanded={isExpanded}>
            { children }
        </AccessibleButton>
    );
};
ContextMenuButton.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string.isRequired,
    isExpanded: PropTypes.bool.isRequired, // whether or not the context menu is currently open
};

// Semantic component for representing a role=menuitem
export const MenuItem = ({children, label, ...props}) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} role="menuitem" tabIndex={-1} aria-label={label}>
            { children }
        </AccessibleButton>
    );
};
MenuItem.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string, // optional
    className: PropTypes.string, // optional
    onClick: PropTypes.func.isRequired,
};

// Semantic component for representing a role=group for grouping menu radios/checkboxes
export const MenuGroup = ({children, label, ...props}) => {
    return

        { children }

;
};
MenuGroup.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string.isRequired,
    className: PropTypes.string, // optional
};

// Semantic component for representing a role=menuitemcheckbox
export const MenuItemCheckbox = ({children, label, active=false, disabled=false, ...props}) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} role="menuitemcheckbox" aria-checked={active} aria-disabled={disabled} tabIndex={-1} aria-label={label}>
            { children }
        </AccessibleButton>
    );
};
MenuItemCheckbox.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string, // optional
    active: PropTypes.bool.isRequired,
    disabled: PropTypes.bool, // optional
    className: PropTypes.string, // optional
    onClick: PropTypes.func.isRequired,
};

// Semantic component for representing a role=menuitemradio
export const MenuItemRadio = ({children, label, active=false, disabled=false, ...props}) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} role="menuitemradio" aria-checked={active} aria-disabled={disabled} tabIndex={-1} aria-label={label}>
            { children }
        </AccessibleButton>
    );
};
MenuItemRadio.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string, // optional
    active: PropTypes.bool.isRequired,
    disabled: PropTypes.bool, // optional
    className: PropTypes.string, // optional
    onClick: PropTypes.func.isRequired,
};

// Placement method for <ContextMenu /> to position context menu to right of elementRect with chevronOffset
export const toRightOf = (elementRect, chevronOffset=12) => {
    const left = elementRect.right + window.pageXOffset + 3;
    let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
    top -= chevronOffset + 8; // where 8 is half the height of the chevron
    return {left, top};
};

// Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect
export const aboveLeft = (elementRect, chevronFace="none") => {
    const menuOptions = { chevronFace };

    const buttonRight = elementRect.right + window.pageXOffset;
    const buttonBottom = elementRect.bottom + window.pageYOffset;
    const buttonTop = elementRect.top + window.pageYOffset;
    // Align the right edge of the menu to the right edge of the button
    menuOptions.right = window.innerWidth - buttonRight;
    // Align the menu vertically on whichever side of the button has more space available.
    if (buttonBottom < window.innerHeight / 2) {
        menuOptions.top = buttonBottom;
    } else {
        menuOptions.bottom = window.innerHeight - buttonTop;
    }

    return menuOptions;
};

export const useContextMenu = () => {
    const _button = useRef(null);
    const [isOpen, setIsOpen] = useState(false);
    const open = () => {
        setIsOpen(true);
    };
    const close = () => {
        setIsOpen(false);
    };

    return [isOpen, _button, open, close, setIsOpen];
};

export default class LegacyContextMenu extends ContextMenu {
    render() {
        return this.renderMenu(false);
    }
}

// XXX: Deprecated, used only for dynamic Tooltips. Avoid using at all costs.
export function createMenu(ElementClass, props) {
    const onFinished = function(...args) {
        ReactDOM.unmountComponentAtNode(getOrCreateContainer());

        if (props && props.onFinished) {
            props.onFinished.apply(null, args);
        }
    };

    const menu = <LegacyContextMenu
        {...props}
        onFinished={onFinished} // eslint-disable-line react/jsx-no-bind
        windowResize={onFinished} // eslint-disable-line react/jsx-no-bind
    >
        <ElementClass {...props} onFinished={onFinished} />
    </LegacyContextMenu>;

    ReactDOM.render(menu, getOrCreateContainer());

    return {close: onFinished};
}
<commit_msg>don't consume all keys<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.

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 React, {useRef, useState} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {Key} from "../../Keyboard";
import sdk from "../../index";
import AccessibleButton from "../views/elements/AccessibleButton";

// Shamelessly ripped off Modal.js.  There's probably a better way
// of doing reusable widgets like dialog boxes & menus where we go and
// pass in a custom control as the actual body.

const ContextualMenuContainerId = "mx_ContextualMenu_Container";

function getOrCreateContainer() {
    let container = document.getElementById(ContextualMenuContainerId);

    if (!container) {
        container = document.createElement("div");
        container.id = ContextualMenuContainerId;
        document.body.appendChild(container);
    }

    return container;
}

const ARIA_MENU_ITEM_ROLES = new Set(["menuitem", "menuitemcheckbox", "menuitemradio"]);
// Generic ContextMenu Portal wrapper
// all options inside the menu should be of role=menuitem/menuitemcheckbox/menuitemradiobutton and have tabIndex={-1}
// this will allow the ContextMenu to manage its own focus using arrow keys as per the ARIA guidelines.
export class ContextMenu extends React.Component {
    propTypes: {
        top: PropTypes.number,
        bottom: PropTypes.number,
        left: PropTypes.number,
        right: PropTypes.number,
        menuWidth: PropTypes.number,
        menuHeight: PropTypes.number,
        chevronOffset: PropTypes.number,
        chevronFace: PropTypes.string, // top, bottom, left, right or none
        // Function to be called on menu close
        onFinished: PropTypes.func.isRequired,
        menuPaddingTop: PropTypes.number,
        menuPaddingRight: PropTypes.number,
        menuPaddingBottom: PropTypes.number,
        menuPaddingLeft: PropTypes.number,
        zIndex: PropTypes.number,

        // If true, insert an invisible screen-sized element behind the
        // menu that when clicked will close it.
        hasBackground: PropTypes.bool,

        // on resize callback
        windowResize: PropTypes.func,
    };

    static defaultProps = {
        hasBackground: true,
    };

    constructor() {
        super();
        this.state = {
            contextMenuElem: null,
        };

        // persist what had focus when we got initialized so we can return it after
        this.initialFocus = document.activeElement;
    }

    componentWillUnmount() {
        // return focus to the thing which had it before us
        this.initialFocus.focus();
    }

    collectContextMenuRect = (element) => {
        // We don't need to clean up when unmounting, so ignore
        if (!element) return;

        let first = element.querySelector('[role^="menuitem"]');
        if (!first) {
            first = element.querySelector('[tab-index]');
        }
        if (first) {
            first.focus();
        }

        this.setState({
            contextMenuElem: element,
        });
    };

    onContextMenu = (e) => {
        if (this.props.onFinished) {
            this.props.onFinished();

            e.preventDefault();
            const x = e.clientX;
            const y = e.clientY;

            // XXX: This isn't pretty but the only way to allow opening a different context menu on right click whilst
            // a context menu and its click-guard are up without completely rewriting how the context menus work.
            setImmediate(() => {
                const clickEvent = document.createEvent('MouseEvents');
                clickEvent.initMouseEvent(
                    'contextmenu', true, true, window, 0,
                    0, 0, x, y, false, false,
                    false, false, 0, null,
                );
                document.elementFromPoint(x, y).dispatchEvent(clickEvent);
            });
        }
    };

    _onMoveFocus = (element, up) => {
        let descending = false; // are we currently descending or ascending through the DOM tree?

        do {
            const child = up ? element.lastElementChild : element.firstElementChild;
            const sibling = up ? element.previousElementSibling : element.nextElementSibling;

            if (descending) {
                if (child) {
                    element = child;
                } else if (sibling) {
                    element = sibling;
                } else {
                    descending = false;
                    element = element.parentElement;
                }
            } else {
                if (sibling) {
                    element = sibling;
                    descending = true;
                } else {
                    element = element.parentElement;
                }
            }

            if (element) {
                if (element.classList.contains("mx_ContextualMenu")) { // we hit the top
                    element = up ? element.lastElementChild : element.firstElementChild;
                    descending = true;
                }
            }
        } while (element && !ARIA_MENU_ITEM_ROLES.has(element.getAttribute("role")));

        if (element) {
            element.focus();
        }
    };

    _onMoveFocusHomeEnd = (element, up) => {
        let results = element.querySelectorAll('[role^="menuitem"]');
        if (!results) {
            results = element.querySelectorAll('[tab-index]');
        }
        if (results && results.length) {
            if (up) {
                results[0].focus();
            } else {
                results[results.length - 1].focus();
            }
        }
    };

    _onKeyDown = (ev) => {
        let handled = true;

        switch (ev.key) {
            case Key.TAB:
            case Key.ESCAPE:
                this.props.onFinished();
                break;
            case Key.ARROW_UP:
                this._onMoveFocus(ev.target, true);
                break;
            case Key.ARROW_DOWN:
                this._onMoveFocus(ev.target, false);
                break;
            case Key.HOME:
                this._onMoveFocusHomeEnd(this.state.contextMenuElem, true);
                break;
            case Key.END:
                this._onMoveFocusHomeEnd(this.state.contextMenuElem, false);
                break;
            default:
                handled = false;
        }

        if (handled) {
            // consume all other keys in context menu
            ev.stopPropagation();
            ev.preventDefault();
        }
    };

    renderMenu(hasBackground=this.props.hasBackground) {
        const position = {};
        let chevronFace = null;
        const props = this.props;

        if (props.top) {
            position.top = props.top;
        } else {
            position.bottom = props.bottom;
        }

        if (props.left) {
            position.left = props.left;
            chevronFace = 'left';
        } else {
            position.right = props.right;
            chevronFace = 'right';
        }

        const contextMenuRect = this.state.contextMenuElem ? this.state.contextMenuElem.getBoundingClientRect() : null;
        const padding = 10;

        const chevronOffset = {};
        if (props.chevronFace) {
            chevronFace = props.chevronFace;
        }
        const hasChevron = chevronFace && chevronFace !== "none";

        if (chevronFace === 'top' || chevronFace === 'bottom') {
            chevronOffset.left = props.chevronOffset;
        } else {
            const target = position.top;

            // By default, no adjustment is made
            let adjusted = target;

            // If we know the dimensions of the context menu, adjust its position
            // such that it does not leave the (padded) window.
            if (contextMenuRect) {
                adjusted = Math.min(position.top, document.body.clientHeight - contextMenuRect.height - padding);
            }

            position.top = adjusted;
            chevronOffset.top = Math.max(props.chevronOffset, props.chevronOffset + target - adjusted);
        }

        let chevron;
        if (hasChevron) {
            chevron =
;
        }

        const menuClasses = classNames({
            'mx_ContextualMenu': true,
            'mx_ContextualMenu_left': !hasChevron && position.left,
            'mx_ContextualMenu_right': !hasChevron && position.right,
            'mx_ContextualMenu_top': !hasChevron && position.top,
            'mx_ContextualMenu_bottom': !hasChevron && position.bottom,
            'mx_ContextualMenu_withChevron_left': chevronFace === 'left',
            'mx_ContextualMenu_withChevron_right': chevronFace === 'right',
            'mx_ContextualMenu_withChevron_top': chevronFace === 'top',
            'mx_ContextualMenu_withChevron_bottom': chevronFace === 'bottom',
        });

        const menuStyle = {};
        if (props.menuWidth) {
            menuStyle.width = props.menuWidth;
        }

        if (props.menuHeight) {
            menuStyle.height = props.menuHeight;
        }

        if (!isNaN(Number(props.menuPaddingTop))) {
            menuStyle["paddingTop"] = props.menuPaddingTop;
        }
        if (!isNaN(Number(props.menuPaddingLeft))) {
            menuStyle["paddingLeft"] = props.menuPaddingLeft;
        }
        if (!isNaN(Number(props.menuPaddingBottom))) {
            menuStyle["paddingBottom"] = props.menuPaddingBottom;
        }
        if (!isNaN(Number(props.menuPaddingRight))) {
            menuStyle["paddingRight"] = props.menuPaddingRight;
        }

        const wrapperStyle = {};
        if (!isNaN(Number(props.zIndex))) {
            menuStyle["zIndex"] = props.zIndex + 1;
            wrapperStyle["zIndex"] = props.zIndex;
        }

        let background;
        if (hasBackground) {
            background = (

            );
        }

        return (

                    { chevron }
                    { props.children }

                { background }

        );
    }

    render() {
        return ReactDOM.createPortal(this.renderMenu(), getOrCreateContainer());
    }
}

// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
export const ContextMenuButton = ({ label, isExpanded, children, ...props }) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} title={label} aria-label={label} aria-haspopup={true} aria-expanded={isExpanded}>
            { children }
        </AccessibleButton>
    );
};
ContextMenuButton.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string.isRequired,
    isExpanded: PropTypes.bool.isRequired, // whether or not the context menu is currently open
};

// Semantic component for representing a role=menuitem
export const MenuItem = ({children, label, ...props}) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} role="menuitem" tabIndex={-1} aria-label={label}>
            { children }
        </AccessibleButton>
    );
};
MenuItem.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string, // optional
    className: PropTypes.string, // optional
    onClick: PropTypes.func.isRequired,
};

// Semantic component for representing a role=group for grouping menu radios/checkboxes
export const MenuGroup = ({children, label, ...props}) => {
    return

        { children }

;
};
MenuGroup.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string.isRequired,
    className: PropTypes.string, // optional
};

// Semantic component for representing a role=menuitemcheckbox
export const MenuItemCheckbox = ({children, label, active=false, disabled=false, ...props}) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} role="menuitemcheckbox" aria-checked={active} aria-disabled={disabled} tabIndex={-1} aria-label={label}>
            { children }
        </AccessibleButton>
    );
};
MenuItemCheckbox.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string, // optional
    active: PropTypes.bool.isRequired,
    disabled: PropTypes.bool, // optional
    className: PropTypes.string, // optional
    onClick: PropTypes.func.isRequired,
};

// Semantic component for representing a role=menuitemradio
export const MenuItemRadio = ({children, label, active=false, disabled=false, ...props}) => {
    const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
    return (
        <AccessibleButton {...props} role="menuitemradio" aria-checked={active} aria-disabled={disabled} tabIndex={-1} aria-label={label}>
            { children }
        </AccessibleButton>
    );
};
MenuItemRadio.propTypes = {
    ...AccessibleButton.propTypes,
    label: PropTypes.string, // optional
    active: PropTypes.bool.isRequired,
    disabled: PropTypes.bool, // optional
    className: PropTypes.string, // optional
    onClick: PropTypes.func.isRequired,
};

// Placement method for <ContextMenu /> to position context menu to right of elementRect with chevronOffset
export const toRightOf = (elementRect, chevronOffset=12) => {
    const left = elementRect.right + window.pageXOffset + 3;
    let top = elementRect.top + (elementRect.height / 2) + window.pageYOffset;
    top -= chevronOffset + 8; // where 8 is half the height of the chevron
    return {left, top};
};

// Placement method for <ContextMenu /> to position context menu right-aligned and flowing to the left of elementRect
export const aboveLeft = (elementRect, chevronFace="none") => {
    const menuOptions = { chevronFace };

    const buttonRight = elementRect.right + window.pageXOffset;
    const buttonBottom = elementRect.bottom + window.pageYOffset;
    const buttonTop = elementRect.top + window.pageYOffset;
    // Align the right edge of the menu to the right edge of the button
    menuOptions.right = window.innerWidth - buttonRight;
    // Align the menu vertically on whichever side of the button has more space available.
    if (buttonBottom < window.innerHeight / 2) {
        menuOptions.top = buttonBottom;
    } else {
        menuOptions.bottom = window.innerHeight - buttonTop;
    }

    return menuOptions;
};

export const useContextMenu = () => {
    const _button = useRef(null);
    const [isOpen, setIsOpen] = useState(false);
    const open = () => {
        setIsOpen(true);
    };
    const close = () => {
        setIsOpen(false);
    };

    return [isOpen, _button, open, close, setIsOpen];
};

export default class LegacyContextMenu extends ContextMenu {
    render() {
        return this.renderMenu(false);
    }
}

// XXX: Deprecated, used only for dynamic Tooltips. Avoid using at all costs.
export function createMenu(ElementClass, props) {
    const onFinished = function(...args) {
        ReactDOM.unmountComponentAtNode(getOrCreateContainer());

        if (props && props.onFinished) {
            props.onFinished.apply(null, args);
        }
    };

    const menu = <LegacyContextMenu
        {...props}
        onFinished={onFinished} // eslint-disable-line react/jsx-no-bind
        windowResize={onFinished} // eslint-disable-line react/jsx-no-bind
    >
        <ElementClass {...props} onFinished={onFinished} />
    </LegacyContextMenu>;

    ReactDOM.render(menu, getOrCreateContainer());

    return {close: onFinished};
}
<|endoftext|>


<commit_before>/* @flow */
import React, {PureComponent} from 'react'
import {Icon, Text} from '../common-adapters/index'
import {globalStyles, globalColors} from '../styles'
import {stateColors} from '../util/tracker'

import type {HeaderProps} from './header.render'

type State = {
  showCloseWarning: boolean,
}

export default class HeaderRender extends PureComponent<void, HeaderProps, State> {
  state: State;

  constructor (props: HeaderProps) {
    super(props)
    this.state = {showCloseWarning: false}
  }

  render () {
    const isWarningAboutTrackerShowingUpLater = this.props.loggedIn && !this.props.currentlyFollowing && this.state.showCloseWarning
    const headerText = isWarningAboutTrackerShowingUpLater ? 'You will see this window every time you access this folder.' : this.props.reason

    const trackerStateColors = stateColors(this.props)
    const headerBackgroundColor = isWarningAboutTrackerShowingUpLater ? globalColors.yellow : trackerStateColors.header.background
    const headerTextColor = isWarningAboutTrackerShowingUpLater ? globalColors.brown_60 : trackerStateColors.header.text

    return (

          <Text type='BodySemibold' lineClamp={2} style={{...styleText, color: headerTextColor, ...(isWarningAboutTrackerShowingUpLater ? {zIndex: 2} : {})}}>{headerText}</Text>
          <Icon type='iconfont-close' style={styleClose}
            onClick={() => this.props.onClose()}
            onMouseEnter={() => this.closeMouseEnter()}
            onMouseLeave={() => this.closeMouseLeave()} />

    )
  }

  closeMouseEnter () {
    this.setState({showCloseWarning: true})
  }

  closeMouseLeave () {
    this.setState({showCloseWarning: false})
  }
}

const styleOuter = {
  position: 'relative',
}

const styleHeader = {
  ...globalStyles.windowDragging,
  cursor: 'default',
  position: 'absolute',
  top: 0,
  ...globalStyles.flexBoxRow,
  height: 90,
  width: 320,
}

const styleClose = {
  ...globalStyles.clickable,
  ...globalStyles.windowDraggingClickable,
  zIndex: 2,
  position: 'absolute',
  top: 7,
  right: 9,
}

const styleText = {
  ...globalStyles.flexBoxRow,
  flex: 1,
  alignItems: 'center',
  justifyContent: 'center',
  color: globalColors.white,
  marginLeft: 30,
  marginRight: 30,
  marginBottom: 32,
  fontSize: 14,
  textAlign: 'center',
  lineHeight: 'normal',
}
<commit_msg>Add background color to tracker close warning (#4104)<commit_after>/* @flow */
import React, {PureComponent} from 'react'
import {Icon, Text} from '../common-adapters/index'
import {globalStyles, globalColors, globalMargins} from '../styles'
import {stateColors} from '../util/tracker'

import type {HeaderProps} from './header.render'

type State = {
  showCloseWarning: boolean,
}

export default class HeaderRender extends PureComponent<void, HeaderProps, State> {
  state: State;

  constructor (props: HeaderProps) {
    super(props)
    this.state = {showCloseWarning: false}
  }

  render () {
    const isWarningAboutTrackerShowingUpLater = this.props.loggedIn && !this.props.currentlyFollowing && this.state.showCloseWarning
    const headerText = isWarningAboutTrackerShowingUpLater ? 'You will see this window every time you access this folder.' : this.props.reason

    const trackerStateColors = stateColors(this.props)
    const headerBackgroundColor = isWarningAboutTrackerShowingUpLater ? globalColors.yellow : trackerStateColors.header.background
    const headerTextColor = isWarningAboutTrackerShowingUpLater ? globalColors.brown_60 : trackerStateColors.header.text

    return (

          <Text type='BodySemibold' lineClamp={2} style={{...styleText, backgroundColor: headerBackgroundColor, color: headerTextColor, ...(isWarningAboutTrackerShowingUpLater ? {zIndex: 2} : {})}}>{headerText}</Text>
          <Icon type='iconfont-close' style={styleClose}
            onClick={() => this.props.onClose()}
            onMouseEnter={() => this.closeMouseEnter()}
            onMouseLeave={() => this.closeMouseLeave()} />

    )
  }

  closeMouseEnter () {
    this.setState({showCloseWarning: true})
  }

  closeMouseLeave () {
    this.setState({showCloseWarning: false})
  }
}

const styleOuter = {
  position: 'relative',
}

const styleHeader = {
  ...globalStyles.windowDragging,
  cursor: 'default',
  position: 'absolute',
  top: 0,
  ...globalStyles.flexBoxRow,
  height: 90,
  width: 320,
}

const styleClose = {
  ...globalStyles.clickable,
  ...globalStyles.windowDraggingClickable,
  zIndex: 2,
  position: 'absolute',
  top: 7,
  right: 9,
}

const styleText = {
  ...globalStyles.flexBoxRow,
  flex: 1,
  alignItems: 'center',
  justifyContent: 'center',
  color: globalColors.white,
  paddingLeft: globalMargins.medium,
  paddingRight: globalMargins.medium,
  marginBottom: globalMargins.medium,
  fontSize: 14,
  textAlign: 'center',
  lineHeight: 'normal',
}
<|endoftext|>


<commit_before>'use strict';

/**
 *  消息服务
 */
const {
  user_friendValidationRule,
  stateValidationRule,
} = require('../../validate/user_friend');

module.exports = app => {
  class Controller extends app.Controller {
    async connection() {
      return;
    }

    async login() {
      const obj = this.ctx.args[0];
      const socket = this.ctx.socket;
      const { userid } = obj;
      const userLoginEnds = await app.redis.smembers('chat:user:socket:' + userid);
      if (userLoginEnds && userLoginEnds.length > 0) {
        // 已登录
      } else {
        // 存储登录信息
        await app.redis.sadd('chat:user:socket:' + userid, socket.id);
        await app.redis.set('chat:socket:user:' + socket.id, userid);
        // 加载好友列表并置状态
        const friends = await this.service.findAll(
          { sort: '{"response_time": -1 }' },
          {
            $or: [{ from_userid: userid }, { to_userid: userid }],
            deleted: false,
            state: 2,
          }
        );
        if (friends && friends.lenth > 0) {
          for (let index = 0; index < friends.length; index++) {
            const element = friends[index];
            let fsockets;
            let friendid;
            if (element.from_userid !== userid) {
              fsockets = await app.redis.smembers(
                'chat:user:socket:' + from_userid
              );
              friendid = from_userid;
            } else {
              friendid = to_userid;
              fsockets = await app.redis.smembers(
                'chat:user:socket:' + to_userid
              );
            }
            if (fsockets && fsockets.length > 0) {
              await app.redis.zadd('chat:user:friends:' + userid, 1, friendid);
              let score = await app.redis.zscore(
                'chat:user:friends:' + friendid,
                userid
              );
              if (score === 0) {
                await app.redis.zincrby(
                  'chat:user:friends:' + friendid,
                  1,
                  userid
                );
                 // 向好友终端推送在线消息
                 const friendLoginEnds = await app.redis.smembers('chat:user:socket:' + friendid);
                 if (friendLoginEnds && friendLoginEnds.length > 0) {
                  for (const end of friendLoginEnds) {
                    if (end) {
                      await app.io
                        .of('/chat')
                        .to(end)
                        .emit('friend_online', { userid });
                    }
                  }
                 }
              }
            } else {
              await app.redis.zadd('chat:user:friends:' + userid, 0, friendid);
            }
          }
        }
      }
      return;
    }

    /**
     * 发送消息
     */
    async sendMessage() {
      const obj = this.ctx.args[0];
      /**
       * from:{userid}
       * to:{userid}
       * message:string
       */
      const { from, to } = obj;
      let { message } = obj;
      if (message.length >= 516) {
        message = message.slice(0, 500) + '...(输入太长，系统自动截断)';
      }
      if (message) {
        const to_user_ends = await app.redis.smembers('chat:user:socket:' + to);
        for (const end of to_user_ends) {
          if (end) {
            await app.io
              .of('/chat')
              .to(end)
              .emit('message_received', { from, message });
          }
        }
      }
      return;
    }

    /**
     * 加载好友列表
     */
    async loadOnlineFriendList() {
      const obj = this.ctx.args[0];
      /**
       * userid:string
       */
      const { userid } = obj;
      // 查询所有好友在线列表
      let friends = await app.redis.zrange(
        'chat:user:friends:' + userid,
        0,
        -1,
        'WITHSCORES'
      );
      if (userid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('online_friendlist_received', {
            friendlist: friends,
          });
      }
    }

    /**
     * 发送好友请求
     */
    async requestAddFriend() {
      /**
       * userid:string
       * to:{userid}
       * state:number
       */

      const { ctx, app } = this;
      const obj = ctx.args[0];
      const { from_userid, to_userid } = obj;
      const invalid = app.validator.validate(user_friendValidationRule, {
        from_userid,
        to_userid,
      });
      if (invalid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '请求参数错误！' });
      }

      const isUserExist =
        (await ctx.service.user.hasUser(from_userid)) &&
        (await ctx.service.user.hasUser(to_userid));
      if (!isUserExist) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '用户不存在' });
      }

      if (from_userid === to_userid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '不能添加自己为好友' });
      }

      const user_friend = {
        from_userid,
        to_userid,
        request_time: new Date().valueOf(),
        state: 1,
      };

      await this.service.userFriend.create(user_friend);

      await app.io
        .of('/chat')
        .to(this.socket.id)
        .emit('requestAddFriend_success', {});
    }

    async responseAddFriend() {
      const { ctx, app } = this;
      const obj = ctx.args[0];
      const { recordId, state } = obj;
      const invalid = app.validator.validate(stateValidationRule, {
        recordId,
        state,
      });
      if (invalid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '请求参数不合法！' });
      }
      await ctx.service.userFriend.updateState(recordId, state);
      await app.io
        .of('/chat')
        .to(this.socket.id)
        .emit('responseAddFriend_success', {});
    }

    /**
     * 断开连接
     */
    async disconnect() {
      const socket = this.ctx.socket;
      app.redis.get(socket.id).then(userid => {
        this.ctx.logger.info('userid!', userid);
        if (userid) {
          // 查询所有好友在线列表
          let friends = await app.redis.zrange(
            'chat:user:friends:' + userid,
            0,
            -1,
            'WITHSCORES'
          );

          for (const end of friends) {
            // 好友在线
            if(end[1] === 1){
              let score = await app.redis.zscore(
                'chat:user:friends:' + end[0],
                userid
              );
              if (score !== 0) {
                await app.redis.zincrby(
                  'chat:user:friends:'  + end[0],
                  -1,
                  userid
                );
              }
              // 向好友终端推送离线消息
              const friendLoginEnds = await app.redis.smembers('chat:user:socket:' + end[0]);
                 if (friendLoginEnds && friendLoginEnds.length > 0) {
                  for (const end of friendLoginEnds) {
                    if (end) {
                      await app.io
                        .of('/chat')
                        .to(end)
                        .emit('friend_offline', { userid });
                    }
                  }
                 }
            }
          }

          await app.redis.del(
            'chat:user:friends:' + userid
          );
          await app.redis.srem('chat:user:socket:', userid);
          await app.redis.del('chat:socket:user:' + socket.id);
        }
      });
      return;
    }
  }
  return Controller;
};
<commit_msg>chore: validate user-friends datastructure and refactor a bit code<commit_after>'use strict';

/**
 *  消息服务
 */
const {
  user_friendValidationRule,
  stateValidationRule,
} = require('../../validate/user_friend');

module.exports = app => {
  class Controller extends app.Controller {
    async connection() {
      return;
    }

    async login() {
      const obj = this.ctx.args[0];
      const socket = this.ctx.socket;
      const { userid } = obj;
      if(!userid){
          return '用户编号不合法！';
      }
      // 存储登录信息
      await app.redis.sadd('chat:user:socket:' + userid, socket.id);
      await app.redis.set('chat:socket:user:' + socket.id, userid);
      const userLoginEnds = await app.redis.smembers('chat:user:socket:' + userid);
      if (userLoginEnds && userLoginEnds.length > 0) {
        // TODO:多终端登录或重复登录
      } else {
        // 加载好友列表并置状态
        const friends = await this.service.findAll(
          { sort: '{"response_time": -1 }' },
          {
            $or: [{ from_userid: userid }, { to_userid: userid }],
            deleted: false,
            state: 2,
          }
        );
        if (friends && friends.lenth > 0) {
          for (let index = 0; index < friends.length; index++) {
            const element = friends[index];
            let fsockets;
            let friendid;
            if (element.from_userid !== userid) {
              friendid = from_userid;
            } else {
              friendid = to_userid;
            }
            fsockets = await app.redis.smembers(
              'chat:user:socket:' + friendid
            );
            if (fsockets && fsockets.length > 0) {
              await app.redis.zadd('chat:user:friends:' + userid, 1, friendid);
              let score = await app.redis.zscore(
                'chat:user:friends:' + friendid,
                userid
              );
              // 置用户在线标识
              if (score === 0) {
                await app.redis.zincrby(
                  'chat:user:friends:' + friendid,
                  1,
                  userid
                );
                // 向好友终端推送离线消息
                this.notify(friendid,'friend_online', { userid });
              }
            } else {
              await app.redis.zadd('chat:user:friends:' + userid, 0, friendid);
            }
          }
        }
      }
      return;
    }

    /**
     * 发送消息
     */
    async sendMessage() {
      const obj = this.ctx.args[0];
      /**
       * from:{userid}
       * to:{userid}
       * message:string
       */
      const { from, to } = obj;
      let { message } = obj;
      if (message.length >= 516) {
        message = message.slice(0, 500) + '...(输入太长，系统自动截断)';
      }
      if (message) {
        // 向各个终端推送离线消息
        this.notify(to, 'message_received',{ from, message });
      }
      return;
    }

    /**
     * 加载好友列表
     */
    async loadOnlineFriendList() {
      const obj = this.ctx.args[0];
      /**
       * userid:string
       */
      const { userid } = obj;
      // 查询所有好友在线列表
      let friends = await app.redis.zrange(
        'chat:user:friends:' + userid,
        0,
        -1,
        'WITHSCORES'
      );
      if (userid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('online_friendlist_received', {
            friendlist: friends,
          });
      }
    }

    /**
     * 发送好友请求
     */
    async requestAddFriend() {
      /**
       * userid:string
       * to:{userid}
       * state:number
       */
      const { ctx, app } = this;
      const obj = ctx.args[0];
      const { from_userid, to_userid } = obj;
      if(!from_userid || !to_userid){
        return '用户编号不合法！';
      }
      const invalid = app.validator.validate(user_friendValidationRule, {
        from_userid,
        to_userid,
      });
      if (invalid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '请求参数错误！' });
      }

      const isUserExist =
        (await ctx.service.user.hasUser(from_userid)) &&
        (await ctx.service.user.hasUser(to_userid));
      if (!isUserExist) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '用户不存在' });
      }

      if (from_userid === to_userid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '不能添加自己为好友' });
      }

      const user_friend = {
        from_userid,
        to_userid,
        request_time: new Date().valueOf(),
        state: 1,
      };

      await this.service.userFriend.create(user_friend);

      await app.io
        .of('/chat')
        .to(this.socket.id)
        .emit('requestAddFriend_success', {});
    }

    async responseAddFriend() {
      const { ctx, app } = this;
      const obj = ctx.args[0];
      const { recordId, state } = obj;
      const invalid = app.validator.validate(stateValidationRule, {
        recordId,
        state,
      });
      if (invalid) {
        await app.io
          .of('/chat')
          .to(this.socket.id)
          .emit('fail', { status: 'fail', description: '请求参数不合法！' });
      }
      await ctx.service.userFriend.updateState(recordId, state);
      await app.io
        .of('/chat')
        .to(this.socket.id)
        .emit('responseAddFriend_success', {});
    }

    /**
     * 断开连接
     */
    async disconnect() {
      const socket = this.ctx.socket;
      app.redis.get(socket.id).then(userid => {
        this.ctx.logger.info('userid!', userid);
        if (userid) {
          // 查询所有好友在线列表
          let friends = await app.redis.zrange(
            'chat:user:friends:' + userid,
            0,
            -1,
            'WITHSCORES'
          );

          for (const end of friends) {
            // 好友在线
            // TODO: 格式需要做验证
            if(end[1] === 1){
              let score = await app.redis.zscore(
                'chat:user:friends:' + end[0],
                userid
              );
              if (score !== 0) {
                await app.redis.zincrby(
                  'chat:user:friends:'  + end[0],
                  -1,
                  userid
                );
              }
              // 向好友终端推送离线消息
              this.notify(end[0],'friend_offline', { userid });
            }
          }

          await app.redis.del(
            'chat:user:friends:' + userid
          );
          await app.redis.srem('chat:user:socket:', userid);
          await app.redis.del('chat:socket:user:' + socket.id);
        }
      });
      return;
    }

    /**
     * 辅助方法
     */
    async notify(userid, evtName, message){
      // 向好友终端推送离线消息
      const loginEnds = await app.redis.smembers('chat:user:socket:' + userid);
      if (loginEnds && loginEnds.length > 0) {
        for (const end of loginEnds) {
          if (end) {
            await app.io
              .of('/chat')
              .to(end)
              .emit(evtName, message);
          }
        }
      }
    }
  }
  return Controller;
};
<|endoftext|>


<commit_before>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('added-services-list-item', function() {

  juju.components.AddedServicesListItem = React.createClass({

    /**
      Parses the supplied unit data to return the status color and number
      to display.

      @method _parseStatusData
      @param {Array} units An array of units.
    */
    _parseStatusData: function(units) {
      var unitStatuses = {
        uncommitted: [],
        started: [],
        pending: [],
        error: [],
      };
      var agentState;
      units.forEach(function(unit) {
        agentState = unit.agent_state || 'uncommitted';
        if (!unitStatuses[agentState]) {
          unitStatuses[agentState] = [];
        }
        unitStatuses[agentState].push(unit);
      });
      var top = {
        key: '',
        size: 0
      };
      for (var key in unitStatuses) {
        var size = unitStatuses[key].length;
        if (size > top.size) {
          top.key = key;
          top.size = size;
        }
      }
      top.size = top.size + '';
      return top;
    },

    /**
      Renders and returns the status icon if necessary.

      @method _renderStatusIndicator
      @param {Object} statusData The status data that will be used to generate
        the staus icon.
    */
    _renderStatusIndicator: function(statusData) {
      var shownStatuses = ['uncommitted', 'pending', 'error'];
      var className = 'inspector-view__status--' + statusData.key;
      if (shownStatuses.indexOf(statusData.key) > -1) {
        return (
          {statusData.size}
        );
      }
    },

    render: function() {
      var service = this.props.service.getAttrs();
      var statusData = this._parseStatusData(service.units.toArray());
      var statusIndicator = this._renderStatusIndicator(statusData);
      return (

          {service.unit_count} {service.name}
          {statusIndicator}

      );
    }

  });

}, '0.1.0', { requires: []});
<commit_msg>proporitize error over pending over uncommitted status icons<commit_after>/*
This file is part of the Juju GUI, which lets users view and manage Juju
environments within a graphical interface (https://launchpad.net/juju-gui).
Copyright (C) 2012-2013 Canonical Ltd.

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License version 3, as published by
the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
General Public License for more details.

You should have received a copy of the GNU Affero General Public License along
with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

'use strict';

YUI.add('added-services-list-item', function() {

  juju.components.AddedServicesListItem = React.createClass({

    /**
      Parses the supplied unit data to return the status color and number
      to display.

      @method _parseStatusData
      @param {Array} units An array of units.
    */
    _parseStatusData: function(units) {
      var unitStatuses = {
        uncommitted: { priority: 3, size: 0 },
        started: { priority: 2, size: 0 },
        pending: { priority: 1, size: 0 },
        error: { priority: 0, size: 0 },
      };
      var agentState;
      units.forEach(function(unit) {
        agentState = unit.agent_state || 'uncommitted';
        // If we don't have it in our status list then add it to the end
        // with a very low priority.
        if (!unitStatuses[agentState]) {
          unitStatuses[agentState] = { priority: 99, size: 0 };
        }
        unitStatuses[agentState].size += 1;
      });

      var top = { priority: 99, key: '', size: 0 };
      var status;
      for (var key in unitStatuses) {
        status = unitStatuses[key];
        if (status.priority < top.priority && status.size > 0) {
          top = {
            key: key,
            priority: status.priority,
            size: status.size
          };
        }
      }
      // size needs to be a string for test comparison purposes because react
      // converts this to a string for output but doesn't convert it in
      // the js dom.
      top.size = top.size + '';
      return top;
    },

    /**
      Renders and returns the status icon if necessary.

      @method _renderStatusIndicator
      @param {Object} statusData The status data that will be used to generate
        the staus icon.
    */
    _renderStatusIndicator: function(statusData) {
      var shownStatuses = ['uncommitted', 'pending', 'error'];
      var className = 'inspector-view__status--' + statusData.key;
      if (shownStatuses.indexOf(statusData.key) > -1) {
        return (
          {statusData.size}
        );
      }
    },

    render: function() {
      var service = this.props.service.getAttrs();
      var statusData = this._parseStatusData(service.units.toArray());
      var statusIndicator = this._renderStatusIndicator(statusData);
      return (

          {service.unit_count} {service.name}
          {statusIndicator}

      );
    }

  });

}, '0.1.0', { requires: []});
<|endoftext|>


<commit_before>const PaddedInstruction = require('./PaddedInstruction');

export default class TableSwitchInstruction extends PaddedInstruction {

  constructor(idx, opcode) {
    super(idx, opcode);
    this.defaultOffset = 0;
    this.lowByte = 0;
    this.highByte = 0;
    this.jumpOffsets = [];
  }

  get size() {
    return (super.size + 12) + (4 * this.jumpOffsets.length);
  }

  read(buffer) {
    super.read(buffer);

    this.defaultOffset = buffer.int();
    this.lowByte = buffer.int();
    this.highByte = buffer.int();

    this.jumpOffsets = [];
    let offsetCount = (highByte - lowByte + 1);
    for (let i = 0; i < offsetCount; i++) {
      this.jumpOffsets[i] = buffer.int();
    }
  }
}<commit_msg>fix bug in TableSwitchInstruction<commit_after>const PaddedInstruction = require('./PaddedInstruction');

export default class TableSwitchInstruction extends PaddedInstruction {

  constructor(idx, opcode) {
    super(idx, opcode);
    this.defaultOffset = 0;
    this.lowByte = 0;
    this.highByte = 0;
    this.jumpOffsets = [];
  }

  get size() {
    return (super.size + 12) + (4 * this.jumpOffsets.length);
  }

  read(buffer) {
    super.read(buffer);

    this.defaultOffset = buffer.int();
    this.lowByte = buffer.int();
    this.highByte = buffer.int();

    this.jumpOffsets = [];
    let offsetCount = (this.highByte - this.lowByte + 1);
    for (let i = 0; i < offsetCount; i++) {
      this.jumpOffsets[i] = buffer.int();
    }
  }
}<|endoftext|>


<commit_before>import React from 'react';
import isEmpty from 'lodash.isempty';
import bukovelAPI from './data-access/bukovelAPI';
import CardNumberInput from './components/CardNumberInput';
import TestCardNumber from './components/TestCardNumber';
import LiftsTable from './components/LiftsTable';
import AppBar from 'material-ui/AppBar';
import CircularProgress from 'material-ui/CircularProgress';

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

const muiTheme = getMuiTheme();

class App extends React.Component {
  constructor() {
    super();

    this.state = {
      cardInfo: {
        lifts: []
      },
      cardNumber: '',
      isDataLoads: false
    };
    this.handleCardNumberChange = this.handleCardNumberChange.bind(this);
    this.testCardNumberChange = this.testCardNumberChange.bind(this);
  }

  testCardNumberChange(event, value) {
    this.setState({
      cardNumber: value
    });
  }

  handleCardNumberChange(event) {
    if (event.isValid) {
      let spinnerTimeOut = setTimeout(() => {
        this.setState({
          isDataLoads: true
        });
      }, 100);
      bukovelAPI
        .getCardBalance(event.text)
        .then(data => {
          clearTimeout(spinnerTimeOut);
          this.setState({
            isDataLoads: false,
            cardInfo: data
          });
        });
    }
  }

  renderTable() {
    if (this.state.isDataLoads) {
      return <CircularProgress size={1.5} />;
    } else if (!isEmpty(this.state.cardInfo.lifts)) {
      return <LiftsTable lifts={this.state.cardInfo.lifts} />;
    }
  }

  render() {
    return (
      <MuiThemeProvider muiTheme={muiTheme}>

            <AppBar title='Buka' />

              <CardNumberInput
                id='cardnumber'
                className='buka-cardnumber__input'
                onChange={this.handleCardNumberChange}
                value={this.state.cardNumber} />
              <TestCardNumber onChange={this.testCardNumberChange} />

            {this.renderTable()}

      </MuiThemeProvider>
    );
  }
}

export default App;<commit_msg>Create muiTheme in the App constructor.<commit_after>import React from 'react';
import isEmpty from 'lodash.isempty';
import bukovelAPI from './data-access/bukovelAPI';
import CardNumberInput from './components/CardNumberInput';
import TestCardNumber from './components/TestCardNumber';
import LiftsTable from './components/LiftsTable';
import AppBar from 'material-ui/AppBar';
import CircularProgress from 'material-ui/CircularProgress';

import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

class App extends React.Component {
  constructor() {
    super();

    this.muiTheme = getMuiTheme();

    this.state = {
      cardInfo: {
        lifts: []
      },
      cardNumber: '',
      isDataLoads: false
    };
    this.handleCardNumberChange = this.handleCardNumberChange.bind(this);
    this.testCardNumberChange = this.testCardNumberChange.bind(this);
  }

  testCardNumberChange(event, value) {
    this.setState({
      cardNumber: value
    });
  }

  handleCardNumberChange(event) {
    if (event.isValid) {
      let spinnerTimeOut = setTimeout(() => {
        this.setState({
          isDataLoads: true
        });
      }, 100);
      bukovelAPI
        .getCardBalance(event.text)
        .then(data => {
          clearTimeout(spinnerTimeOut);
          this.setState({
            isDataLoads: false,
            cardInfo: data
          });
        });
    }
  }

  renderTable() {
    if (this.state.isDataLoads) {
      return <CircularProgress size={1.5} />;
    } else if (!isEmpty(this.state.cardInfo.lifts)) {
      return <LiftsTable lifts={this.state.cardInfo.lifts} />;
    }
  }

  render() {
    return (
      <MuiThemeProvider muiTheme={this.muiTheme}>

            <AppBar title='Buka' />

              <CardNumberInput
                id='cardnumber'
                className='buka-cardnumber__input'
                onChange={this.handleCardNumberChange}
                value={this.state.cardNumber} />
              <TestCardNumber onChange={this.testCardNumberChange} />

            {this.renderTable()}

      </MuiThemeProvider>
    );
  }
}

export default App;<|endoftext|>


<commit_before>/*

	Dr ToDo Little
	The main controller

*/
tdapp.controller("MainCtrl",
function(
	$scope,
	$timeout,
	$location,
	$routeParams,
	todoservice
){

	// General Done Filter
	$scope.showdone = false;
	$scope.showdonetext = "Show Done";

	// Keyboard
	$scope.newtodoKeydown = function(e){
		var k = e.keyCode;
		if(k==13){//ret
			e.preventDefault();
			if($scope.newtodotxt!=""){
				var newtodo = {};
				newtodo.topic = $scope.newtodotxt;
				newtodo.done = false;
				$scope.newtodotxt = "";
				todoservice.create(newtodo);
				if($scope.showdone){
					$scope.showdone = false;
					$scope.showdonetext = "Show Done";
				}
				if(newtodo.tag!=undefined){
					$scope.filtertag = newtodo.tag;
				} else {
					$scope.filtertag = "All";
				}
				$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
				window.scrollTo(0,0);
				$("#todotxta").focus();
			}
		} else
		if(k==9){//tab
			e.preventDefault();
		}
	}

	$scope.todolineKeydown = function(e,id){
		var k = e.keyCode;
		if(k==13){//ret
			e.preventDefault();
			var currentTodo = $('#todoid'+id);
			// Correct contenteditable behaviour
			currentTodo.html(currentTodo.html().replace('
',''));
			currentTodo.blur();
			var obj = todoservice.getTodoById(id);
			if(obj!=undefined){
				obj.topic = currentTodo.html();
				todoservice.update(obj);
				var oldtag = obj.tag;
				todoservice.checkForHashtag(obj);
				if(oldtag!=undefined){
					var ttd = todoservice.getTodosByTag(oldtag);
					if(ttd.length<=0){
						todoservice.tags.splice(todoservice.tags.indexOf(oldtag),1);
					}
				}
				$scope.tags = (todoservice.getTags()).sort();
				$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
			}
		}
	}

	$scope.displaytodos = function(tag) {
		$scope.filtertag = tag;
		$scope.todos = todoservice.getTodosByTag(tag,$scope.showdone);
	}

	// Todo functions
	$scope.seltodoline = function(id){
		$("#todoid"+id).focus();
	}

	$scope.deltodo = function(obj){ // No animation
		obj.deleted = true;
		todoservice.delTodo(obj);
		$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
	}

	$scope.togDone = function(item) {
		if (item.done) {
			todoservice.undone(item);
			item.done = false;
		}
		else {
			todoservice.done(item);
			item.done=true;
		}
		$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
	}

	$scope.saveedittodo = function(todo){
		$scope.showedit = false;
		todoservice.update(todo);
	}

	// Filter function

	$scope.togShowdone = function(){
		$scope.showdone = !$scope.showdone;
		if($scope.showdone){
			$scope.showdonetext = "Show Open";
		} else {
			$scope.showdonetext = "Show Done";
		}
		$scope.todos=todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
	}

	// Tags

	$scope.getTodosByTag = todoservice.getTodosByTag;
	todoservice.getTodos().then(function(todos) {
		$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
		$scope.tags = todoservice.getTags();
	});

	// Routeparams
	console.log("routeparams...")
	console.log($routeParams.type)
	console.log($routeParams.id)
	console.log("...done")
	if(
		$routeParams.type!=undefined &&
		$routeParams.id!=undefined &&
		$routeParams.type=="todo"
	){
		var todo = todoservice.getTodoById($routeParams.id)
		if(todo!=undefined){
			var todos = [];
			todos.push(todo);
			$scope.todos = todos;
		} else {
			$scope.todos = [];
		}
	}
	if(
		$routeParams.type!=undefined &&
		$routeParams.id!=undefined &&
		$routeParams.type=="tag"
	){
		$scope.todos = todoservice.getTodosByTag("#"+$routeParams.id,false);
	}

	// Finish
	$("#todotxta").focus();

});
<commit_msg>Bugfix Routeparams.<commit_after>/*

	Dr ToDo Little
	The main controller

*/
tdapp.controller("MainCtrl",
function(
	$scope,
	$timeout,
	$location,
	$routeParams,
	todoservice
){

	// General Done Filter
	$scope.showdone = false;
	$scope.showdonetext = "Show Done";

	// Keyboard
	$scope.newtodoKeydown = function(e){
		var k = e.keyCode;
		if(k==13){//ret
			e.preventDefault();
			if($scope.newtodotxt!=""){
				var newtodo = {};
				newtodo.topic = $scope.newtodotxt;
				newtodo.done = false;
				$scope.newtodotxt = "";
				todoservice.create(newtodo);
				if($scope.showdone){
					$scope.showdone = false;
					$scope.showdonetext = "Show Done";
				}
				if(newtodo.tag!=undefined){
					$scope.filtertag = newtodo.tag;
				} else {
					$scope.filtertag = "All";
				}
				$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
				window.scrollTo(0,0);
				$("#todotxta").focus();
			}
		} else
		if(k==9){//tab
			e.preventDefault();
		}
	}

	$scope.todolineKeydown = function(e,id){
		var k = e.keyCode;
		if(k==13){//ret
			e.preventDefault();
			var currentTodo = $('#todoid'+id);
			// Correct contenteditable behaviour
			currentTodo.html(currentTodo.html().replace('
',''));
			currentTodo.blur();
			var obj = todoservice.getTodoById(id);
			if(obj!=undefined){
				obj.topic = currentTodo.html();
				todoservice.update(obj);
				var oldtag = obj.tag;
				todoservice.checkForHashtag(obj);
				if(oldtag!=undefined){
					var ttd = todoservice.getTodosByTag(oldtag);
					if(ttd.length<=0){
						todoservice.tags.splice(todoservice.tags.indexOf(oldtag),1);
					}
				}
				$scope.tags = (todoservice.getTags()).sort();
				$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
			}
		}
	}

	$scope.displaytodos = function(tag) {
		$scope.filtertag = tag;
		$scope.todos = todoservice.getTodosByTag(tag,$scope.showdone);
	}

	// Todo functions
	$scope.seltodoline = function(id){
		$("#todoid"+id).focus();
	}

	$scope.deltodo = function(obj){ // No animation
		obj.deleted = true;
		todoservice.delTodo(obj);
		$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
	}

	$scope.togDone = function(item) {
		if (item.done) {
			todoservice.undone(item);
			item.done = false;
		}
		else {
			todoservice.done(item);
			item.done=true;
		}
		$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
	}

	$scope.saveedittodo = function(todo){
		$scope.showedit = false;
		todoservice.update(todo);
	}

	// Filter function

	$scope.togShowdone = function(){
		$scope.showdone = !$scope.showdone;
		if($scope.showdone){
			$scope.showdonetext = "Show Open";
		} else {
			$scope.showdonetext = "Show Done";
		}
		$scope.todos=todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
	}

	// Tags

	$scope.getTodosByTag = todoservice.getTodosByTag;
	todoservice.getTodos().then(function(todos) {
		// Normal
		$scope.todos = todoservice.getTodosByTag($scope.filtertag,$scope.showdone);
		$scope.tags = todoservice.getTags();
		// Routeparams
		if(
			$routeParams.type!=undefined &&
			$routeParams.id!=undefined &&
			$routeParams.type=="todo"
		){
			var todo = todoservice.getTodoById($routeParams.id)
			if(todo!=undefined){
				var todos = [];
				todos.push(todo);
				$scope.todos = todos;
			} else {
				$scope.todos = [];
			}
		}
		if(
			$routeParams.type!=undefined &&
			$routeParams.id!=undefined &&
			$routeParams.type=="tag"
		){
			$scope.todos = todoservice.getTodosByTag("#"+$routeParams.id,false);
		}
	});

	// Finish
	$("#todotxta").focus();

});
<|endoftext|>


<commit_before>/*
 * Project Ariana
 * app.js
 *
 * This file contains the AppController, which controls the entire application.
 * It also contain the global configuration settings.
 *
 */

"use strict";

var app = angular.module('ariana', [
    'ui.router',
    'ui.bootstrap',
    'cfp.hotkeys',
    'templates-ariana',
    'ngFileUpload',
    'ngAnimate'
]);

/* The AppController is the main controller of the application. */
app.controller('AppCtrl', ['$scope',
    function($scope) {

        /* The config object contains the current state of the layers, tools,
         * canvas and the mouse. It is accessed by all kinds of controllers. */
        $scope.config = {
            mouse: {
                old: {
                    x : 0,
                    y : 0,
                    global: {
                        x : 0,
                        y : 0,
                    },
                },
                current: {
                    x: 0,
                    y: 0,
                    global: {
                        x : 0,
                        y : 0,
                    },
                },
                button: {
                    1: false, // left button
                    2: false, // middle button
                    3: false, // right button
                }
            },
            canvas: {
                cursor: 'default',
                x: 128,
                y: 128,
                xr: 1,
                yr: 1,
                zoom: 1,
                width: 800,
                height: 600,
                visible: false
            },
            tools: {
                activeTool: 'pan',
                activeToolFunctions: null,
                activeToolset: null,
                colors: {
                    primary: {
                        r: 0,
                        g: 0,
                        b: 0
                    },
                    secondary: {
                        r: 255,
                        g: 255,
                        b: 255
                    }
                }
            },
            layers: {
                numberOfLayers: 0,
                currentLayer: -1,
                layerInfo: [],
            }
        };

        $scope.renderEngine = null;
        $scope.drawEngine = null;
        $scope.editEngine = null;

        /* This function creates the RenderEngine. It requires the canvas to
         * render on. */
        $scope.startEngines = function(renderCanvas, drawCanvas) {
            $scope.renderEngine = new RenderEngine(renderCanvas);
            $scope.drawEngine = new DrawEngine(drawCanvas);
            $scope.editEngine = new EditEngine(drawCanvas);
        };

        /* This function creates a new layer from a given Image-object. The new
         * layer is placed on top. */
        $scope.newLayerFromImage = function(image, index) {
            var layer = $scope.renderEngine.createImageLayer(image);

            var height = layer.getHeight();
            var width  = layer.getWidth();

            layer.setPos(0.5 * width, 0.5 * height);

            if (typeof index === "undefined" || index == null) {
                index = $scope.config.layers.numberOfLayers;
            }
            $scope.renderEngine.insertLayer(layer, index);

            /* set the correct layer info in config. The new layer comes on top
             * and is immediately selected. */
            //$scope.setSelection([$scope.config.layers.numberOfLayers]);
            $scope.config.layers.numberOfLayers += 1;
            $scope.config.layers.currentLayer = index;

            /* Store information about the layers in the config object. */
            $scope.config.layers.layerInfo.splice(index, 0, {
                "name": 'Layer ' + $scope.config.layers.numberOfLayers,
                "x": layer.getPosX(),
                "y": layer.getPosY(),
                "originalWidth": width,
                "originalHeight": height,
                "width": width,
                "height": height,
                "rotation": layer.getRotation(),
            });

            window.requestAnimationFrame(function() {$scope.renderEngine.render();});
            //$scope.renderEngine.render();
        };

        $scope.resizeCanvases = function(width, height) {
            var toolFunctions = $scope.config.tools.activeToolFunctions;

            $scope.config.canvas.width = width;
            $scope.config.canvas.height = height;
            $scope.renderEngine.resize($scope.config.canvas.width, $scope.config.canvas.height);
            $scope.drawEngine.resize($scope.config.canvas.width, $scope.config.canvas.height);
            $scope.editEngine.resize($scope.config.canvas.width, $scope.config.canvas.height);

            if (toolFunctions && toolFunctions.init) {
                toolFunctions.init();
            }

            $scope.config.layers.numberOfLayers = 0;
            $scope.config.layers.currentLayer = -1;
            $scope.config.layers.layerInfo = [];

            if (!$scope.config.canvas.visible) {
                $scope.config.canvas.visible = true;
            }

            window.requestAnimationFrame(function() {$scope.renderEngine.render();});
        };
	}
]);
<commit_msg>removed some lines of dead code<commit_after>/*
 * Project Ariana
 * app.js
 *
 * This file contains the AppController, which controls the entire application.
 * It also contain the global configuration settings.
 *
 */

"use strict";

var app = angular.module('ariana', [
    'ui.router',
    'ui.bootstrap',
    'cfp.hotkeys',
    'templates-ariana',
    'ngFileUpload',
    'ngAnimate'
]);

/* The AppController is the main controller of the application. */
app.controller('AppCtrl', ['$scope',
    function($scope) {

        /* The config object contains the current state of the layers, tools,
         * canvas and the mouse. It is accessed by all kinds of controllers. */
        $scope.config = {
            mouse: {
                old: {
                    x : 0,
                    y : 0,
                    global: {
                        x : 0,
                        y : 0,
                    },
                },
                current: {
                    x: 0,
                    y: 0,
                    global: {
                        x : 0,
                        y : 0,
                    },
                },
                button: {
                    1: false, // left button
                    2: false, // middle button
                    3: false, // right button
                }
            },
            canvas: {
                cursor: 'default',
                x: 128,
                y: 128,
                xr: 1,
                yr: 1,
                zoom: 1,
                width: 800,
                height: 600,
                visible: false
            },
            tools: {
                activeTool: 'pan',
                activeToolFunctions: null,
                activeToolset: null,
                colors: {
                    primary: {
                        r: 0,
                        g: 0,
                        b: 0
                    },
                    secondary: {
                        r: 255,
                        g: 255,
                        b: 255
                    }
                }
            },
            layers: {
                numberOfLayers: 0,
                currentLayer: -1,
                layerInfo: [],
            }
        };

        $scope.renderEngine = null;
        $scope.drawEngine = null;
        $scope.editEngine = null;

        /* This function creates the RenderEngine. It requires the canvas to
         * render on. */
        $scope.startEngines = function(renderCanvas, drawCanvas) {
            $scope.renderEngine = new RenderEngine(renderCanvas);
            $scope.drawEngine = new DrawEngine(drawCanvas);
            $scope.editEngine = new EditEngine(drawCanvas);
        };

        /* This function creates a new layer from a given Image-object. The new
         * layer is placed on top. */
        $scope.newLayerFromImage = function(image, index) {
            var layer = $scope.renderEngine.createImageLayer(image);

            var height = layer.getHeight();
            var width  = layer.getWidth();

            layer.setPos(0.5 * width, 0.5 * height);

            if (typeof index === "undefined" || index == null) {
                index = $scope.config.layers.numberOfLayers;
            }
            $scope.renderEngine.insertLayer(layer, index);

            /* set the correct layer info in config. The new layer comes on top
             * and is immediately selected. */
            $scope.config.layers.numberOfLayers += 1;
            $scope.config.layers.currentLayer = index;

            /* Store information about the layers in the config object. */
            $scope.config.layers.layerInfo.splice(index, 0, {
                "name": 'Layer ' + $scope.config.layers.numberOfLayers,
                "x": layer.getPosX(),
                "y": layer.getPosY(),
                "originalWidth": width,
                "originalHeight": height,
                "width": width,
                "height": height,
                "rotation": layer.getRotation(),
            });

            window.requestAnimationFrame(function() {$scope.renderEngine.render();});
        };

        $scope.resizeCanvases = function(width, height) {
            var toolFunctions = $scope.config.tools.activeToolFunctions;

            $scope.config.canvas.width = width;
            $scope.config.canvas.height = height;
            $scope.renderEngine.resize($scope.config.canvas.width, $scope.config.canvas.height);
            $scope.drawEngine.resize($scope.config.canvas.width, $scope.config.canvas.height);
            $scope.editEngine.resize($scope.config.canvas.width, $scope.config.canvas.height);

            if (toolFunctions && toolFunctions.init) {
                toolFunctions.init();
            }

            $scope.config.layers.numberOfLayers = 0;
            $scope.config.layers.currentLayer = -1;
            $scope.config.layers.layerInfo = [];

            if (!$scope.config.canvas.visible) {
                $scope.config.canvas.visible = true;
            }

            window.requestAnimationFrame(function() {$scope.renderEngine.render();});
        };
	}
]);
<|endoftext|>


<commit_before>import GameMode from './_gamemode';
import config from '../config';
import gamestate from '../gamestate';
import { shakeUpdate } from '../ScreenShake.js'
import * as Cars from '../Cars.js';

import _ from 'lodash';

let lastTime = 0;

export default class Valet extends GameMode {
  static loop(now) {
    const delta = now - lastTime;
    lastTime = now

    shakeUpdate()

    // TODO: Have a gameloop function. Maybe have a seperate one for each gametype
    if (gamestate.playing) {
      // TODO: do initialization better somehow?
      if (!gamestate.player) {
        const car = _.sample(Cars);
        const spawn = _.sample(gamestate.level.spawnPoints);

        gamestate.player =  new car(spawn);
      }
      gamestate.player.update();

      if (p2.vec2.length(gamestate.player.chassisBody.velocity) <= 0.05) {
        gamestate.player.chassisBody.backWheel.setBrakeForce(2);
        gamestate.player.boxShape.collisionGroup = config.CAR;
        gamestate.cars.push(gamestate.player);
        const car = _.sample(Cars);
        const spawn = _.sample(gamestate.level.spawnPoints);
        gamestate.player =  new car(spawn);
      }

      for (let i = gamestate.cars.length - 1; i >= 0; i--) {
        gamestate.cars[i].update()
      }
    }

    requestAnimationFrame(Valet.loop);
    if (gamestate.playing) config.world.step(1/60);
    config.renderer.render(config.stage);
  }
}
<commit_msg>fix(gamemodes): fix linting error<commit_after>import GameMode from './_gamemode';
import config from '../config';
import gamestate from '../gamestate';
import { shakeUpdate } from '../ScreenShake.js'
import * as Cars from '../Cars.js';

import _ from 'lodash';

export default class Valet extends GameMode {
  static loop(now) {

    shakeUpdate()

    // TODO: Have a gameloop function. Maybe have a seperate one for each gametype
    if (gamestate.playing) {
      // TODO: do initialization better somehow?
      if (!gamestate.player) {
        const car = _.sample(Cars);
        const spawn = _.sample(gamestate.level.spawnPoints);

        gamestate.player =  new car(spawn);
      }
      gamestate.player.update();

      if (p2.vec2.length(gamestate.player.chassisBody.velocity) <= 0.05) {
        gamestate.player.chassisBody.backWheel.setBrakeForce(2);
        gamestate.player.boxShape.collisionGroup = config.CAR;
        gamestate.cars.push(gamestate.player);
        const car = _.sample(Cars);
        const spawn = _.sample(gamestate.level.spawnPoints);
        gamestate.player =  new car(spawn);
      }

      for (let i = gamestate.cars.length - 1; i >= 0; i--) {
        gamestate.cars[i].update()
      }
    }

    requestAnimationFrame(Valet.loop);
    if (gamestate.playing) config.world.step(1/60);
    config.renderer.render(config.stage);
  }
}
<|endoftext|>