<commit_before>/*
 * Kuzzle, a backend software, self-hostable and ready to use
 * to power modern apps
 *
 * Copyright 2015-2020 Kuzzle
 * mailto: support AT kuzzle.io
 * website: http://kuzzle.io
 *
 * 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
 *
 * https://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.
 */

'use strict';

const kerror = require('../../kerror');
const { has, isPlainObject } = require('../../util/safeObject');
const { binarySearch } = require('../../util/array');

const assertionError = kerror.wrap('api', 'assert');

/**
 * @class Role
 */
class Role {
  constructor () {
    this.controllers = {};
  }

  /**
   * @param {Request} request
   * @returns {boolean}
   */
  isActionAllowed (request) {
    if (!global.kuzzle) {
      throw kerror.get('security', 'role', 'uninitialized', this._id);
    }

    if (this.controllers === undefined || this.controllers === null) {
      return false;
    }

    let controllerRights;

    // @deprecated - the "memoryStorage" alias should be removed in the next
    // major version
    // Handles the memory storage controller aliases: ms, memoryStorage
    if ((request.input.controller === 'ms' || request.input.controller === 'memoryStorage')
      && (this.controllers.ms || this.controllers.memoryStorage)
    ) {
      controllerRights = this.controllers.ms || this.controllers.memoryStorage;
    }
    else if (has(this.controllers, request.input.controller)) {
      controllerRights = this.controllers[request.input.controller];
    }
    else if (this.controllers['*'] !== undefined) {
      controllerRights = this.controllers['*'];
    }
    else {
      return false;
    }

    if (controllerRights.actions === undefined) {
      return false;
    }

    let actionRights;

    if (has(controllerRights.actions, request.input.action)) {
      actionRights = controllerRights.actions[request.input.action];
    }
    else if (controllerRights.actions['*'] !== undefined) {
      actionRights = controllerRights.actions['*'];
    }
    else {
      return false;
    }

    if (typeof actionRights !== 'boolean' || !actionRights) {
      return false;
    }

    return true;
  }

  /**
   * @returns {Promise}
   */
  async validateDefinition () {
    if (this.controllers === undefined || this.controllers === null) {
      throw assertionError.get('missing_argument', 'controllers');
    }

    if (!isPlainObject(this.controllers)) {
      throw assertionError.get('invalid_type', 'controllers', 'object');
    }

    if (Object.keys(this.controllers).length === 0) {
      throw assertionError.get('empty_argument', 'controllers');
    }

    Object
      .entries(this.controllers)
      .forEach(entry => this.validateControllerRights(...entry));
  }

  /**
   * @param {String} index
   * @param {String} collection
   * @param {Map<string, string[]>} restrictedTo Restricted indexes
   * @returns {Boolean} resolves to a Boolean value
   */
  checkRestrictions(index, collection, restrictedTo) {
    // If no restrictions, we allow the action:
    if (! restrictedTo || restrictedTo.size === 0) {
      return true;
    }

    // If the request's action does not refer to an index, restrictions are
    // useless for this action (=> ignore them)
    if (!index) {
      return true;
    }

    // If the index is not in the restrictions, the action is not allowed
    if (! restrictedTo.has(index)) {
      return false;
    }

    const collections = restrictedTo.get(index);

    // if no collections given on the restriction, the action is allowed for all
    // collections:
    if (!collections || collections.length === 0) {
      return true;
    }

    // Find collection index in array
    // If the collection is not in the array, the action is not allowed
    // The array must be sorted for binary search to work
    const indexOfCollection = binarySearch(collections, (collectionName) => {
      if (collection > collectionName) {
        return 1;
      }
      return collection < collectionName
        ? -1
        : 0;
    });

    return indexOfCollection > -1; // Collection found
  }

  /**
   * Verifies that a controller rights definition is correct
   *
   * @param  {Array.<string, Object>}
   * @throws If the controller definition is invalid
   */
  validateControllerRights (name, controller) {
    if (!isPlainObject(controller)) {
      throw assertionError.get('invalid_type', name, 'object');
    }

    if (Object.keys(controller).length === 0) {
      throw assertionError.get('empty_argument', name);
    }

    if (!has(controller, 'actions')) {
      throw assertionError.get('missing_argument', name);
    }

    if (!isPlainObject(controller.actions)) {
      throw assertionError.get('invalid_type', `${name}.actions`, 'object');
    }

    if (Object.keys(controller.actions).length === 0) {
      throw assertionError.get('empty_argument', `${name}.actions`);
    }

    for (const [actionName, action] of Object.entries(controller.actions)) {
      if (typeof action !== 'boolean') {
        throw assertionError.get('invalid_type', `${name}.actions.${actionName}`, 'boolean');
      }
    }
  }

  /**
   * Checks if current role allows to log in
   *
   * @returns {boolean}
   */
  canLogIn () {
    for (const controllerKey of ['auth', '*']) {
      if (this.controllers[controllerKey]) {
        const controller = this.controllers[controllerKey];

        for (const actionKey of ['login', '*']) {
          const action = controller.actions[actionKey];

          if (typeof action === 'boolean' && action) {
            return true;
          }
        }
      }
    }

    return false;
  }
}

module.exports = Role;
<commit_msg>convert role.js to typescript<commit_after><|endoftext|>


<commit_before>define([
    'jquery',
    'var/default_options',
    'var/emojioneSupportMode'
],
function($, default_options, emojioneSupportMode) {
    return function(options) {
        options = $.extend({}, default_options, options);

        if (emojioneSupportMode > 0) {
            options.filters.people.emoji = options.filters.people.emoji
                .replace(",writing_hand,", ",");
            options.filters.travel.emoji = options.filters.travel.emoji
                .replace(",contruction_site,", ",construction_site,");
            options.filters.objects_symbols.emoji = options.filters.objects_symbols.emoji
                .replace(",keycap_ten,", ",ten,")
                .replace(",cross_heavy,", ",cross,");
        }

        return options;
    }
});<commit_msg>Fixed: setting filters in options<commit_after>define([
    'jquery',
    'var/default_options',
    'var/emojioneSupportMode'
],
function($, default_options, emojioneSupportMode) {
    return function(options) {
        if (options['filters']) {
            var filters = default_options.filters;
            $.each(options['filters'], function(filter, data) {
                if (typeof data !== 'object' || $.isEmptyObject(data)) {
                    delete filters[filter];
                    return;
                }
                $.each(data, function(key, val) {
                    filters[filter][key] = val;
                });
            });
            options['filters'] = filters;
        }
        options = $.extend({}, default_options, options);

        if (emojioneSupportMode > 0) {
            options.filters.people.emoji = options.filters.people.emoji
                .replace(",writing_hand,", ",");
            options.filters.travel.emoji = options.filters.travel.emoji
                .replace(",contruction_site,", ",construction_site,");
            options.filters.objects_symbols.emoji = options.filters.objects_symbols.emoji
                .replace(",keycap_ten,", ",ten,")
                .replace(",cross_heavy,", ",cross,");
        }

        return options;
    }
});<|endoftext|>


<commit_before>var tCase = require('t-case');
var _ = require('underscore');

module.exports = exports = Node;
function Node(data) {
  this.childNodes = data.childNodes || [];
  this.urlName = data.system.name || '';
  this.system = data.system;
  this.title = tCase.titleCase(data.system.name || '');
  _.extend(this, data.fields);
  if(this.hidden || this.webRoot) {
    this.urlName = '';
  }
}

Node.create = function create(weave, data, done) {
  try {
    var node = new Node(data);
    done(null, node);
  } catch(ex) {
    done(ex);
  }
}

Node.prototype.url = function url(closest) {
  if(this.hidden && !closest) return '/';
  if(!this.parentNode || this.webRoot || this.parentNode.root) { return '/'; }
  var parentUrl = this.parentNode.url(true).replace(/\/+$/, '');
  return parentUrl + '/' + this.urlName;
}

Node.prototype.isParentOf = function isParentOf(other) {
  return other.parentNode === this;
}

Node.prototype.isAncestorOf = function isAncestorOf(other, orSelf) {
  if(!orSelf && other) other = other.parentNode;
  while(other) {
    if(other === this) return true;
    other = other.parentNode;
  }
  return false;
}

Node.prototype.ancestors = function ancestors() {
  var node = this, result = [];
  while(node && (node = node.parentNode)) {
    if(node.hidden) continue;
    result.push(node);
  }
  return result;
}

Node.prototype.breadcrumb = function breadcrumb() {
  var result = this.ancestors().reverse();
  if(!this.hidden) result.push(this);
  return result;
}

<commit_msg>default fields<commit_after>var tCase = require('t-case');
var _ = require('underscore');

module.exports = exports = Node;
function Node(data) {
  this.childNodes = data.childNodes || [];
  _.defaults(this, data.fields);
  if(!this.title) this.title = tCase.titleCase(data.system.name || '');
  if(!this.urlName) this.urlName = tCase.separatorCase(this.title || '', '-');
  this.system = data.system;
  this.fields = data.fields;
  if(this.hidden || this.webRoot) {
    this.urlName = '';
  }
}

Node.create = function create(weave, data, done) {
  try {
    var node = new Node(data);
    done(null, node);
  } catch(ex) {
    done(ex);
  }
}

Node.prototype.url = function url(closest) {
  if(this.hidden && !closest) return '/';
  if(!this.parentNode || this.webRoot || this.parentNode.root) { return '/'; }
  if(this.fields.url) return this.fields.url;
  var parentUrl = this.parentNode.url(true).replace(/\/+$/, '');
  return parentUrl + '/' + this.urlName;
}

Node.prototype.isParentOf = function isParentOf(other) {
  return other.parentNode === this;
}

Node.prototype.isAncestorOf = function isAncestorOf(other, orSelf) {
  if(!orSelf && other) other = other.parentNode;
  while(other) {
    if(other === this) return true;
    other = other.parentNode;
  }
  return false;
}

Node.prototype.ancestors = function ancestors() {
  var node = this, result = [];
  while(node && (node = node.parentNode)) {
    if(node.hidden) continue;
    result.push(node);
  }
  return result;
}

Node.prototype.breadcrumb = function breadcrumb() {
  var result = this.ancestors().reverse();
  if(!this.hidden) result.push(this);
  return result;
}

<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import './DemoPage.less';
import ComponentRenderer from '../ComponentRenderer';
import FilterSidebar from '../FilterSidebar';
import DemoPageComponentShortInfo from '../DemoPageComponentShortInfo';
import Rcslider from 'rc-slider';
import ToolApplicationHeader from '../ToolApplicationHeader';
import queryString from 'query-string';
import { spring, Motion } from 'react-motion';
import find from 'lodash/find';

export default
class DemoPage extends Component {
  constructor(props) {
    super(props);
    let query = queryString.parse(location.search);
    this.state = {
      showSidebar: (query.showSidebar === 'true') && !props.isScreenSmall,
      packagesInfo: [],
      componentsInfo: [],
      currentComponentId: '',
      currentComponent: null,
      options: {
        maxContainerWidth: (query.maxContainerWidth) || '40%',
        isShowContainerBorders: false,
        isContentCentered: query.forceCentering === 'true',
        isUseScope: typeof query.isUseScope === 'undefined' ? true : query.isUseScope
      }
    };
    this.handleHistoryPopState = this.handleHistoryPopState.bind(this);
  }

  componentWillMount() {
    this.getComponentsInfo();
    this.getPackagesInfo();
    window.addEventListener('popstate', this.handleHistoryPopState);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.componentsInfo !== prevState.componentsInfo) {
      this.initCurrentComponentId();
    }
  }

  componentWillUnmount() {
    clearTimeout(this._getComponentTimeout);
    window.removeEventListener('popstate', this.handleHistoryPopState);
  }

  initCurrentComponentId() {
    let idFromQueryString = queryString.parse(location.search).currentComponentId;
    let id = idFromQueryString ?
      idFromQueryString :
      (this.state.componentsInfo[0] && this.state.componentsInfo[0].id);
    this.handleComponentSelection(this.state.componentsInfo, id || 0);
  }

  handleHistoryPopState(event) {
    this.initCurrentComponentId();
    this.initOptions();
  }

  parseQueryParameters() {
    return queryString.parse(location.search);
  }

  getPackagesInfo() {
    this.props.loader.getPackagesInfo(data => {
      this.setState({ packagesInfo: data });
    });
  }

  getCurrentComponentInfo() {
    return this.state.componentsInfo.filter(componentInfo =>
      componentInfo.id === this.state.currentComponentId
    )[0]
  }

  getComponentsInfo() {
    this.props.loader.getComponentsInfo(data => {
      let preparedComponentsInfo = this.prepareComponentsInfo(data);
      let idFromQueryString = queryString.parse(location.search).currentComponentId;
      let id = idFromQueryString || preparedComponentsInfo[0].id;
      this.handleComponentSelection(preparedComponentsInfo, id);
      this.setState({ componentsInfo: preparedComponentsInfo });
    });
  }

  prepareComponentsInfo(components) {
    let preparedComponentsInfo = components.map(component => ({
      ...component,
      id: `${component.package}/${component.version}/${component.name}`
    }));
    return preparedComponentsInfo;
  }

  setQueryStringParam(name, value) {
    let prevQueryString = this.parseQueryParameters();
    let nextQueryString = queryString.stringify({ ...prevQueryString, [name]: value });
    history.pushState({}, '', `${location.origin}${location.pathname || ''}?${nextQueryString}`);
  }

  getComponent(componentInfo) {
    this.props.loader.getComponent(componentInfo, this.onComponentReady.bind(this));
  }

  onComponentReady(componentData) {
    let componentInfo = this.state.componentsInfo.filter(
      componentInfo => componentInfo.id === this.state.currentComponentId
    )[0];
    this.setState({ currentComponent: { ...componentData, componentInfo } });
  }

  handleToggleSidebar(show) {
    this.setQueryStringParam('showSidebar', !this.state.showSidebar);
    this.setState({ showSidebar: typeof show !== 'undefined' ? show : !this.state.showSidebar });
  }

  handleToggleForceCentering() {
    let { options } = this.state;
    this.setOption('isContentCentered', !options.isContentCentered);
    this.setQueryStringParam('forceCentering', !options.isContentCentered);
  }

  handleToggleUseScope() {
    let { options } = this.state;
    this.setOption('isUseScope', !options.isUseScope);
    this.setQueryStringParam('isUseScope', !options.isUseScope);
  }

  setOption(name, value) {
    this.setState({
      options: {
        ...this.state.options,
        [name]: value
      }
    });
  }

  handleComponentSelection(componentsInfo, id) {
    let componentInfo = componentsInfo.filter(info => info.id === id)[0];
    this.setState({ currentComponentId: id });
    /* this._getComponentTimeout: ugly hack to resolve problems with component selection with synchronous loaders.
    *   if you fix it in normal way, don't forget to remove timeout clear within componentWillUnmount.
    *   Not 0 because IE */
    this._getComponentTimeout = setTimeout(() => this.getComponent(componentInfo), 16);
    this.setQueryStringParam('currentComponentId', id);
  }

  handleContainerWidthChange(value) {
    let nextMaxContainerWidth = `${value}%`;
    this.setOption('maxContainerWidth', nextMaxContainerWidth);
    this.setQueryStringParam('maxContainerWidth', nextMaxContainerWidth);
  }

  render() {
    let { isScreenSmall } = this.props;
    let { options, packagesInfo } = this.state;
    let isMobileScreen = window.innerWidth <= 1200;
    let currentComponentInfo = this.getCurrentComponentInfo();
    let componentRenderer = this.state.currentComponent ? (
      <ComponentRenderer
        component={this.state.currentComponent}
        componentInfo={currentComponentInfo}
        maxContainerWidth={options.maxContainerWidth}
        isScreenSmall={this.props.isScreenSmall}
        isUseScope={options.isUseScope}
        options={options}
      />
    ) : null;

    let sidebar = (
      <Motion
        defaultStyle={{ x: this.state.showSidebar ? 0 : 100 }}
        style={{ x: this.state.showSidebar ? (isMobileScreen ? spring(0) : 0) : (isMobileScreen ? spring(100) : 100) }}
      >
        {interpolatedStyle =>
          <div
            className={`demo-page__filter-sidebar ${isMobileScreen ? 'demo-page__filter-sidebar--mobile' : ' '}`}
            style={{
              boxShadow: this.props.isScreenSmall ? '0 0 12px rgba(0, 0, 0, 0.65)' : '',
              transform: `translate(-${interpolatedStyle.x}%, 0)`
            }}
          >
            <FilterSidebar
              componentsInfo={this.state.componentsInfo}
              currentComponent={this.state.currentComponent}
              onComponentChange={this.handleComponentSelection.bind(this, this.state.componentsInfo)}
              hideOnOutsideClick={this.props.isScreenSmall}
              onHide={() => this.handleToggleSidebar.call(this, false)}
            />

        }
      </Motion>
    );

    let toggleSidebarBtn = (
      <button
        className="demo-page__primary-btn"
        onClick={() => this.handleToggleSidebar.call(this)}
        type="button"
      >
        SIDEBAR
      </button>
    );

    let maxWidthSlider = !isMobileScreen ? (

          Max width:

        <Rcslider
          className="demo-page__max-container-width-slider"
          onChange={this.handleContainerWidthChange.bind(this)}
          defaultValue={parseInt(options.maxContainerWidth, 10)}
          tipFormatter={null}
        />

          {options.maxContainerWidth}

    ) : null;

    let componentPackage = find(
      packagesInfo,
      packageInfo => packageInfo.info.name === currentComponentInfo.package
    ) || {};

    let forceCenteringToggler = (

        Force Centering

    );

    let useScopeToggler = (

        Use scope

    );

    let repositoryUrl = null;
    if (componentPackage.info && componentPackage.info.repository) {
      repositoryUrl = componentPackage.info.repository.url || componentPackage.info.repository;
    };

    return (

        {sidebar}

              <ToolApplicationHeader
                applicationName="Showroom"
                repositoryUrl="https://github.com/OpusCapita/react-showroom-client"
                contacts={[
                  { name: 'alexey.sergeev@jcatalog.com', email: 'alexey.sergeev@jcatalog.com' },
                  { name: 'kirill.volkovich@jcatalog.com', email: 'kirill.volkovich@jcatalog.com' }
                ]}
              />

                {toggleSidebarBtn}

 this.setOption('isShowContainerBorders', true)}
                onMouseLeave={() => this.setOption('isShowContainerBorders', false)}
              >
                {maxWidthSlider}
                {forceCenteringToggler}
                {useScopeToggler}

            <DemoPageComponentShortInfo
              packageName={currentComponentInfo && currentComponentInfo.package}
              packageJson={componentPackage.info}
              componentName={currentComponentInfo && currentComponentInfo.name}
              version={currentComponentInfo && currentComponentInfo.version}
              repositoryUrl={repositoryUrl}
              gitHead={componentPackage.info && componentPackage.info.gitHead}
              isMobileScreen={isMobileScreen}
            />

            {componentRenderer}

    )
  }
}

DemoPage.propTypes = {
  loader: PropTypes.object.isRequired,
  isScreenSmall: PropTypes.bool
};
<commit_msg>Fix repositoryUrl<commit_after>import React, { Component, PropTypes } from 'react';
import './DemoPage.less';
import ComponentRenderer from '../ComponentRenderer';
import FilterSidebar from '../FilterSidebar';
import DemoPageComponentShortInfo from '../DemoPageComponentShortInfo';
import Rcslider from 'rc-slider';
import ToolApplicationHeader from '../ToolApplicationHeader';
import queryString from 'query-string';
import { spring, Motion } from 'react-motion';
import find from 'lodash/find';

export default
class DemoPage extends Component {
  constructor(props) {
    super(props);
    let query = queryString.parse(location.search);
    this.state = {
      showSidebar: (query.showSidebar === 'true') && !props.isScreenSmall,
      packagesInfo: [],
      componentsInfo: [],
      currentComponentId: '',
      currentComponent: null,
      options: {
        maxContainerWidth: (query.maxContainerWidth) || '40%',
        isShowContainerBorders: false,
        isContentCentered: query.forceCentering === 'true',
        isUseScope: typeof query.isUseScope === 'undefined' ? true : query.isUseScope
      }
    };
    this.handleHistoryPopState = this.handleHistoryPopState.bind(this);
  }

  componentWillMount() {
    this.getComponentsInfo();
    this.getPackagesInfo();
    window.addEventListener('popstate', this.handleHistoryPopState);
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.state.componentsInfo !== prevState.componentsInfo) {
      this.initCurrentComponentId();
    }
  }

  componentWillUnmount() {
    clearTimeout(this._getComponentTimeout);
    window.removeEventListener('popstate', this.handleHistoryPopState);
  }

  initCurrentComponentId() {
    let idFromQueryString = queryString.parse(location.search).currentComponentId;
    let id = idFromQueryString ?
      idFromQueryString :
      (this.state.componentsInfo[0] && this.state.componentsInfo[0].id);
    this.handleComponentSelection(this.state.componentsInfo, id || 0);
  }

  handleHistoryPopState(event) {
    this.initCurrentComponentId();
    this.initOptions();
  }

  parseQueryParameters() {
    return queryString.parse(location.search);
  }

  getPackagesInfo() {
    this.props.loader.getPackagesInfo(data => {
      this.setState({ packagesInfo: data });
    });
  }

  getCurrentComponentInfo() {
    return this.state.componentsInfo.filter(componentInfo =>
      componentInfo.id === this.state.currentComponentId
    )[0]
  }

  getComponentsInfo() {
    this.props.loader.getComponentsInfo(data => {
      let preparedComponentsInfo = this.prepareComponentsInfo(data);
      let idFromQueryString = queryString.parse(location.search).currentComponentId;
      let id = idFromQueryString || preparedComponentsInfo[0].id;
      this.handleComponentSelection(preparedComponentsInfo, id);
      this.setState({ componentsInfo: preparedComponentsInfo });
    });
  }

  prepareComponentsInfo(components) {
    let preparedComponentsInfo = components.map(component => ({
      ...component,
      id: `${component.package}/${component.version}/${component.name}`
    }));
    return preparedComponentsInfo;
  }

  setQueryStringParam(name, value) {
    let prevQueryString = this.parseQueryParameters();
    let nextQueryString = queryString.stringify({ ...prevQueryString, [name]: value });
    history.pushState({}, '', `${location.origin}${location.pathname || ''}?${nextQueryString}`);
  }

  getComponent(componentInfo) {
    this.props.loader.getComponent(componentInfo, this.onComponentReady.bind(this));
  }

  onComponentReady(componentData) {
    let componentInfo = this.state.componentsInfo.filter(
      componentInfo => componentInfo.id === this.state.currentComponentId
    )[0];
    this.setState({ currentComponent: { ...componentData, componentInfo } });
  }

  handleToggleSidebar(show) {
    this.setQueryStringParam('showSidebar', !this.state.showSidebar);
    this.setState({ showSidebar: typeof show !== 'undefined' ? show : !this.state.showSidebar });
  }

  handleToggleForceCentering() {
    let { options } = this.state;
    this.setOption('isContentCentered', !options.isContentCentered);
    this.setQueryStringParam('forceCentering', !options.isContentCentered);
  }

  handleToggleUseScope() {
    let { options } = this.state;
    this.setOption('isUseScope', !options.isUseScope);
    this.setQueryStringParam('isUseScope', !options.isUseScope);
  }

  setOption(name, value) {
    this.setState({
      options: {
        ...this.state.options,
        [name]: value
      }
    });
  }

  handleComponentSelection(componentsInfo, id) {
    let componentInfo = componentsInfo.filter(info => info.id === id)[0];
    this.setState({ currentComponentId: id });
    /* this._getComponentTimeout: ugly hack to resolve problems with component selection with synchronous loaders.
    *   if you fix it in normal way, don't forget to remove timeout clear within componentWillUnmount.
    *   Not 0 because IE */
    this._getComponentTimeout = setTimeout(() => this.getComponent(componentInfo), 16);
    this.setQueryStringParam('currentComponentId', id);
  }

  handleContainerWidthChange(value) {
    let nextMaxContainerWidth = `${value}%`;
    this.setOption('maxContainerWidth', nextMaxContainerWidth);
    this.setQueryStringParam('maxContainerWidth', nextMaxContainerWidth);
  }

  render() {
    let { isScreenSmall } = this.props;
    let { options, packagesInfo } = this.state;
    let isMobileScreen = window.innerWidth <= 1200;
    let currentComponentInfo = this.getCurrentComponentInfo();
    let componentRenderer = this.state.currentComponent ? (
      <ComponentRenderer
        component={this.state.currentComponent}
        componentInfo={currentComponentInfo}
        maxContainerWidth={options.maxContainerWidth}
        isScreenSmall={this.props.isScreenSmall}
        isUseScope={options.isUseScope}
        options={options}
      />
    ) : null;

    let sidebar = (
      <Motion
        defaultStyle={{ x: this.state.showSidebar ? 0 : 100 }}
        style={{ x: this.state.showSidebar ? (isMobileScreen ? spring(0) : 0) : (isMobileScreen ? spring(100) : 100) }}
      >
        {interpolatedStyle =>
          <div
            className={`demo-page__filter-sidebar ${isMobileScreen ? 'demo-page__filter-sidebar--mobile' : ' '}`}
            style={{
              boxShadow: this.props.isScreenSmall ? '0 0 12px rgba(0, 0, 0, 0.65)' : '',
              transform: `translate(-${interpolatedStyle.x}%, 0)`
            }}
          >
            <FilterSidebar
              componentsInfo={this.state.componentsInfo}
              currentComponent={this.state.currentComponent}
              onComponentChange={this.handleComponentSelection.bind(this, this.state.componentsInfo)}
              hideOnOutsideClick={this.props.isScreenSmall}
              onHide={() => this.handleToggleSidebar.call(this, false)}
            />

        }
      </Motion>
    );

    let toggleSidebarBtn = (
      <button
        className="demo-page__primary-btn"
        onClick={() => this.handleToggleSidebar.call(this)}
        type="button"
      >
        SIDEBAR
      </button>
    );

    let maxWidthSlider = !isMobileScreen ? (

          Max width:

        <Rcslider
          className="demo-page__max-container-width-slider"
          onChange={this.handleContainerWidthChange.bind(this)}
          defaultValue={parseInt(options.maxContainerWidth, 10)}
          tipFormatter={null}
        />

          {options.maxContainerWidth}

    ) : null;

    let componentPackage = find(
      packagesInfo,
      packageInfo => packageInfo.info.name === currentComponentInfo.package
    ) || {};

    let forceCenteringToggler = (

        Force Centering

    );

    let useScopeToggler = (

        Use scope

    );

    let repositoryUrl = null;
    if (componentPackage.info && componentPackage.info.repository) {
      if (componentPackage.info.repository.url) {
        repositoryUrl = componentPackage.info.repository.url;
      } else if(componentPackage.info.repository) {
        repositoryUrl = 'https://github.com' + componentPackage.info.repository;
      }
    };

    return (

        {sidebar}

              <ToolApplicationHeader
                applicationName="Showroom"
                repositoryUrl="https://github.com/OpusCapita/react-showroom-client"
                contacts={[
                  { name: 'alexey.sergeev@jcatalog.com', email: 'alexey.sergeev@jcatalog.com' },
                  { name: 'kirill.volkovich@jcatalog.com', email: 'kirill.volkovich@jcatalog.com' }
                ]}
              />

                {toggleSidebarBtn}

 this.setOption('isShowContainerBorders', true)}
                onMouseLeave={() => this.setOption('isShowContainerBorders', false)}
              >
                {maxWidthSlider}
                {forceCenteringToggler}
                {useScopeToggler}

            <DemoPageComponentShortInfo
              packageName={currentComponentInfo && currentComponentInfo.package}
              packageJson={componentPackage.info}
              componentName={currentComponentInfo && currentComponentInfo.name}
              version={currentComponentInfo && currentComponentInfo.version}
              repositoryUrl={repositoryUrl}
              gitHead={componentPackage.info && componentPackage.info.gitHead}
              isMobileScreen={isMobileScreen}
            />

            {componentRenderer}

    )
  }
}

DemoPage.propTypes = {
  loader: PropTypes.object.isRequired,
  isScreenSmall: PropTypes.bool
};
<|endoftext|>


<commit_before>"use strict";
const ircFormatting = require("../irc/formatting");
const log = require("../logging").get("MatrixAction");
const ContentRepo = require("matrix-appservice-bridge").ContentRepo;
const escapeStringRegexp = require('escape-string-regexp');

const ACTION_TYPES = ["message", "emote", "topic", "notice", "file", "image", "video", "audio"];
const EVENT_TO_TYPE = {
    "m.room.message": "message",
    "m.room.topic": "topic"
};
const MSGTYPE_TO_TYPE = {
    "m.emote": "emote",
    "m.notice": "notice",
    "m.image": "image",
    "m.video": "video",
    "m.audio": "audio",
    "m.file": "file"
};

const MIN_LENGTH_TO_MATCH = 4;
const MAX_MATCHES = 5;

function MatrixAction(type, text, htmlText, timestamp) {
    if (ACTION_TYPES.indexOf(type) === -1) {
        throw new Error("Unknown MatrixAction type: " + type);
    }
    this.type = type;
    this.text = text;
    this.htmlText = htmlText;
    this.ts = timestamp || 0;
}

MatrixAction.prototype.formatMentions = function(nickUserIdMap) {
    // Get people this message could be mentioning.
    const regexString = "(" +
        Object.keys(nickUserIdMap).map((value) => escapeStringRegexp(value)).join("|")
        + ")";
    const userRegex = new RegExp(regexString, "igm");
    const matched = new Set();
    let match;
    let i = 0;
    while ((match = userRegex.exec(this.text)) !== null && i < MAX_MATCHES) {
        i++;
        let matchName = match[1];
        if (matchName.length < MIN_LENGTH_TO_MATCH || matched.has(matchName.toLowerCase())) {
            continue;
        }
        log.debug(`Matched ${matchName} in ${this.text}`);
        let userId = nickUserIdMap[matchName];
        if (userId === undefined) {
            // Might be casing.
            const nicks = Object.keys(nickUserIdMap).filter((nick) =>
                nick.toLowerCase() === matchName.toLowerCase()
            );
            if (nicks.length === 0) {
                continue;
            }
            userId = nickUserIdMap[nicks[0]];
            matchName = nicks[0];
        }
        if (this.htmlText === undefined) {
            this.htmlText = this.text;
        }
        this.htmlText = this.htmlText.replace(
            new RegExp(escapeStringRegexp(matchName), "igm"),
            `<a href="https://matrix.to/#/${userId}">${matchName}</a>`
        );
        matched.add(matchName.toLowerCase());
    }
}

MatrixAction.fromEvent = function(client, event, mediaUrl) {
    event.content = event.content || {};
    let type = EVENT_TO_TYPE[event.type] || "message"; // mx event type to action type
    let text = event.content.body;
    let htmlText = null;

    if (event.type === "m.room.topic") {
        text = event.content.topic;
    }
    else if (event.type === "m.room.message") {
        if (event.content.format === "org.matrix.custom.html") {
            htmlText = event.content.formatted_body;
        }
        if (MSGTYPE_TO_TYPE[event.content.msgtype]) {
            type = MSGTYPE_TO_TYPE[event.content.msgtype];
        }
        if (["m.image", "m.file", "m.video", "m.audio"].indexOf(event.content.msgtype) !== -1) {
            var fileSize = "";
            if (event.content.info && event.content.info.size &&
                    typeof event.content.info.size === "number") {
                fileSize = " (" + Math.round(event.content.info.size / 1024) + "KB)";
            }

            // By default assume that the media server = client homeserver
            if (!mediaUrl) {
                mediaUrl = client.getHomeserverUrl();
            }

            const url = ContentRepo.getHttpUriForMxc(mediaUrl, event.content.url);
            text = `${event.content.body}${fileSize} < ${url} >`;
        }
    }
    return new MatrixAction(type, text, htmlText, event.origin_server_ts);
};
MatrixAction.fromIrcAction = function(ircAction) {
    switch (ircAction.type) {
        case "message":
        case "emote":
        case "notice":
            let htmlText = ircFormatting.ircToHtml(ircAction.text);
            return new MatrixAction(
                ircAction.type,
                ircFormatting.stripIrcFormatting(ircAction.text),
                // only set HTML text if we think there is HTML, else the bridge
                // will send everything as HTML and never text only.
                ircAction.text !== htmlText ? htmlText : undefined
            );
        case "topic":
            return new MatrixAction("topic", ircAction.text);
        default:
            log.error("MatrixAction.fromIrcAction: Unknown action: %s", ircAction.type);
            return null;
    }
};

module.exports = MatrixAction;
<commit_msg>Fixup comments<commit_after>"use strict";
const ircFormatting = require("../irc/formatting");
const log = require("../logging").get("MatrixAction");
const ContentRepo = require("matrix-appservice-bridge").ContentRepo;
const escapeStringRegexp = require('escape-string-regexp');

const ACTION_TYPES = ["message", "emote", "topic", "notice", "file", "image", "video", "audio"];
const EVENT_TO_TYPE = {
    "m.room.message": "message",
    "m.room.topic": "topic"
};
const MSGTYPE_TO_TYPE = {
    "m.emote": "emote",
    "m.notice": "notice",
    "m.image": "image",
    "m.video": "video",
    "m.audio": "audio",
    "m.file": "file"
};

const MIN_LENGTH_TO_MATCH = 4;
const MAX_MATCHES = 5;

function MatrixAction(type, text, htmlText, timestamp) {
    if (ACTION_TYPES.indexOf(type) === -1) {
        throw new Error("Unknown MatrixAction type: " + type);
    }
    this.type = type;
    this.text = text;
    this.htmlText = htmlText;
    this.ts = timestamp || 0;
}

MatrixAction.prototype.formatMentions = function(nickUserIdMap) {
    const regexString = "(" +
        Object.keys(nickUserIdMap).map((value) => escapeStringRegexp(value)).join("|")
        + ")";
    const userRegex = new RegExp(regexString, "igm");
    const matched = new Set(); // lowercased nicknames we have matched already.
    let match;
    let i = 0;
    while ((match = userRegex.exec(this.text)) !== null && i < MAX_MATCHES) {
        i++;
        let matchName = match[1];
        // Deliberately have a minimum length to match on, so we don't match smaller nicks accidentally.
        if (matchName.length < MIN_LENGTH_TO_MATCH || matched.has(matchName.toLowerCase())) {
            continue;
        }
        let userId = nickUserIdMap[matchName];
        if (userId === undefined) {
            // We might need to search case-insensitive.
            const nicks = Object.keys(nickUserIdMap).filter((nick) =>
                nick.toLowerCase() === matchName.toLowerCase()
            );
            if (nicks.length === 0) {
                continue;
            }
            userId = nickUserIdMap[nicks[0]];
            matchName = nicks[0];
        }
        // If this is not HTML text already, make it so.
        if (this.htmlText === undefined) {
            this.htmlText = this.text;
        }
        this.htmlText = this.htmlText.replace(
            new RegExp(escapeStringRegexp(matchName), "igm"),
            `<a href="https://matrix.to/#/${userId}">${matchName}</a>`
        );
        // Don't match this name twice, we've already replaced all entries.
        matched.add(matchName.toLowerCase());
    }
}

MatrixAction.fromEvent = function(client, event, mediaUrl) {
    event.content = event.content || {};
    let type = EVENT_TO_TYPE[event.type] || "message"; // mx event type to action type
    let text = event.content.body;
    let htmlText = null;

    if (event.type === "m.room.topic") {
        text = event.content.topic;
    }
    else if (event.type === "m.room.message") {
        if (event.content.format === "org.matrix.custom.html") {
            htmlText = event.content.formatted_body;
        }
        if (MSGTYPE_TO_TYPE[event.content.msgtype]) {
            type = MSGTYPE_TO_TYPE[event.content.msgtype];
        }
        if (["m.image", "m.file", "m.video", "m.audio"].indexOf(event.content.msgtype) !== -1) {
            var fileSize = "";
            if (event.content.info && event.content.info.size &&
                    typeof event.content.info.size === "number") {
                fileSize = " (" + Math.round(event.content.info.size / 1024) + "KB)";
            }

            // By default assume that the media server = client homeserver
            if (!mediaUrl) {
                mediaUrl = client.getHomeserverUrl();
            }

            const url = ContentRepo.getHttpUriForMxc(mediaUrl, event.content.url);
            text = `${event.content.body}${fileSize} < ${url} >`;
        }
    }
    return new MatrixAction(type, text, htmlText, event.origin_server_ts);
};
MatrixAction.fromIrcAction = function(ircAction) {
    switch (ircAction.type) {
        case "message":
        case "emote":
        case "notice":
            let htmlText = ircFormatting.ircToHtml(ircAction.text);
            return new MatrixAction(
                ircAction.type,
                ircFormatting.stripIrcFormatting(ircAction.text),
                // only set HTML text if we think there is HTML, else the bridge
                // will send everything as HTML and never text only.
                ircAction.text !== htmlText ? htmlText : undefined
            );
        case "topic":
            return new MatrixAction("topic", ircAction.text);
        default:
            log.error("MatrixAction.fromIrcAction: Unknown action: %s", ircAction.type);
            return null;
    }
};

module.exports = MatrixAction;
<|endoftext|>


<commit_before>/*
    genericadmin - Weston Nielson (wnielson@gmail.com)

    updated by Jan Schrewe (jschrewe@googlemail.com)

    updated by Troy Melhase (troy.melhase@gmail.com)

    updated by Jonathan Ellenberger (jon@respondcreate.com)

 */
 (function($) {
    var isChangeUrl = /\/change\/?/i.test(window.location.href),
        urlPrefix = isChangeUrl ? '../' : '';
    var GenericAdmin = {
        url_array: null,
        fields: null,
        obj_url: urlPrefix + "../obj-data/",
        admin_media_url: window.__admin_media_prefix__,
		popup: '_popup',

        prepareSelect: function(select) {
            var that = this,
                opt_keys = [],
                opt_dict = {},
                no_value,
                opt_group_css = 'style="font-style:normal; font-weight:bold; color:#999; padding-left: 2px;"';

            // polish the look of the select
            select.find('option').each(function() {
                var key, opt;

                if (this.value) {
                    if (that.url_array[this.value]) {
                        key = that.url_array[this.value][0].split('/')[0];

                        opt = $(this).clone();
                        opt.text(that.capFirst(opt.text()));
                        if ($.inArray(key, opt_keys) < 0) {
                            opt_keys.push(key);
                            // if it's the first time in array
                            // it's the first time in dict
                            opt_dict[key] = [opt];
                        } else {
                            opt_dict[key].push(opt);
                        }
                    }
                } else {
                    no_value = $(this).clone();
                }
            });
            select.empty().append(no_value);

            opt_keys = opt_keys.sort();

            $.each(opt_keys, function(index, key) {
                var opt_group = $('<optgroup label="' + that.capFirst(key) + '" ' + opt_group_css + '></optgroup>');
                $.each(opt_dict[key], function(index, value) {
                    opt_group.append(value).css('color', '#000');
                });
                select.append(opt_group);
            });

            return select;
        },

        getLookupUrlParams: function(cID) {
            var q = this.url_array[cID][1] || {},
                str = [];
            for(var p in q) {
                str.push(encodeURIComponent(p) + "=" + encodeURIComponent(q[p]));
            }
            x = str.join("&");
            url = x ? ("?" + x) : "";
            return url;
        },

        getLookupUrl: function(cID) {
            return urlPrefix + '../../../' + this.url_array[cID][0] + '/' + this.getLookupUrlParams(cID);
        },

        getFkId: function() {
            if (this.fields.inline === false) {
                return 'id_' + this.fields.fk_field;
            } else {
                return ['id_', this.fields.prefix, '-', this.fields.number, '-', this.fields.fk_field].join('');
            }
        },

        getCtId: function() {
            if (this.fields.inline === false) {
                return 'id_' + this.fields.ct_field;
            } else {
                return ['id_', this.fields.prefix, '-', this.fields.number, '-', this.fields.ct_field].join('');
            }
        },

        capFirst: function(string) {
            return string.charAt(0).toUpperCase() + string.slice(1);
        },

        hideLookupLink: function() {
            var this_id = this.getFkId();
            $('#lookup_' + this_id).unbind().remove();
            $('#lookup_text_' + this_id + ' a').remove();
            $('#lookup_text_' + this_id + ' span').remove();
        },

        showLookupLink: function() {
            var that = this,
                url = this.getLookupUrl(this.cID),
                id = 'lookup_' + this.getFkId(),
                link = '';
            // admin media is removed in django 1.9
            if (this.admin_media_url !== undefined) {
                link = link + '';
            }
            link += '';
            link += '';

            // insert link html after input element
            this.object_input.after(link);

            return id;
        },

        pollInputChange: function(window) {
            var that = this,
                interval_id = setInterval(function() {
                    if (window.closed === true) {
                        clearInterval(interval_id);
                        that.updateObjectData()();
                        return true;
                    }
                },
                150);
        },

        popRelatedObjectLookup: function(link) {
            var name = id_to_windowname(this.getFkId()),
				url_parts = [],
                href,
                win;

            if (link.href.search(/\?/) >= 0) {
				url_parts[0] = '&';
                //href = link.href + '&pop=1';
            } else {
				url_parts[0] = '?';
                //href = link.href + '?pop=1';
            }
			url_parts[1] = this.popup;
			url_parts[2] = '=1';
			href = link.href + url_parts.join('');
            win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');

            // wait for popup to be closed and load object data
            this.pollInputChange(win);

            win.focus();
            return false;
        },

        updateObjectData: function() {
            var that = this;
            return function() {
                var value = that.object_input.val();

                if (!value) {
                    return
                }
                //var this_id = that.getFkId();
                $('#lookup_text_' + that.getFkId() + ' span').text('loading...');
                $.ajax({
                    url: that.obj_url,
                    dataType: 'json',
                    data: {
                        object_id: value,
                        content_type: that.cID
                    },
                    success: function(item) {
                        if (item && item.content_type_text && item.object_text) {
                            var url = that.getLookupUrl(that.cID);
                            $('#lookup_text_' + that.getFkId() + ' a')
                                .text(item.content_type_text + ': ' + item.object_text)
                                .attr('href', url + item.object_id);

                            // run a callback to do other stuff like prepopulating url fields
                            // can't be done with normal django admin prepopulate
                            if (that.updateObjectDataCallback) {
                                that.updateObjectDataCallback(item);
                            }
                        }
                        $('#lookup_text_' + that.getFkId() + ' span').text('');
                    },
                    error: function(xhr, status, error) {
                        $('#lookup_text_' + that.getFkId() + ' span').text('')
                            .html('Error: ' + xhr.status + ' – ' + that.capFirst(xhr.statusText.toLowerCase()));
                        if (xhr.status === 404) {
                            that.object_input.val('');
                        } else {
                            $('#lookup_text_' + that.getFkId() + ' span').css('color', '#f00');
                        }
                    }
                });
            };
        },

        install: function(fields, url_array, popup_var) {
            var that = this;

            this.url_array = url_array;
            this.fields = fields;
			this.popup = popup_var || this.popup;

            // store the base element
            this.object_input = $("#" + this.getFkId());

            // find the select we need to change
            this.object_select = this.prepareSelect($("#" + this.getCtId()));

            // install event handler for select
            this.object_select.change(function() {
                // reset the object input to the associated select (this one)
                var link_id;

                //(this).css('color', 'red'); // uncomment for testing
                that.hideLookupLink();
                // Set our objectId when the content_type is changed
                if (this.value) {
                    that.cID = this.value;
                    link_id = that.showLookupLink();
                    $('#' + link_id).click(function(e) {
                        e.preventDefault();
                        that.popRelatedObjectLookup(this);
                    });
                }
            });

            // fire change event if something is already selected
            if (this.object_select.val()) {
                this.object_select.trigger('change');
            }

            // Bind to the onblur of the object_id input.
            this.object_input.blur(that.updateObjectData());

            // Fire once for initial link.
            this.updateObjectData()();
        }
    };

    var InlineAdmin = {
        sub_admins: null,
        url_array: null,
        fields: null,
		popup: '_popup',

        install: function(fields, url_array, popup_var) {
            var inline_count = $('#id_' + fields.prefix + '-TOTAL_FORMS').val(),
                admin;

            this.url_array = url_array;
            this.fields = fields;
            this.sub_admins = [];
			this.popup = popup_var || this.popup;

            for (var j = 0; j < inline_count; j++) {
                f = $.extend({}, this.fields);
                f.number = j;
                admin = $.extend({}, GenericAdmin);
                admin.install(f, this.url_array, popup_var);
                this.sub_admins.push(admin);
            }
            $('#' + this.fields.prefix + '-group .add-row a').click(this.addHandler());
        },
        addHandler: function() {
            var that = this;
            return function(e) {
                e.preventDefault();
                var added_fields = $.extend({}, that.fields),
                    admin = $.extend({}, GenericAdmin);
                added_fields.number = ($('#id_' + that.fields.prefix + '-TOTAL_FORMS').val() - 1);
                admin.install(added_fields, that.url_array, that.popup);
                that.sub_admins.push(admin);

                $('#' + that.fields.prefix + '-' + added_fields.number + ' .inline-deletelink').click(
                    that.removeHandler(that)
                );
            }
        },
        removeHandler: function(that) {
            return function(e) {
                var parent_id,
                    deleted_num,
                    sub_admin;

                e.preventDefault();
                parent_id = $(e.currentTarget).parents('.dynamic-' + that.fields.prefix).first().attr('id');
                deleted_num = parseInt(parent_id.charAt(parent_id.length - 1), 10);
                for (var i = (that.sub_admins.length - 1); i >= 0; i--) {
                    sub_admin = that.sub_admins[i];
                    if (sub_admin.fields.number === deleted_num) {
                        that.sub_admins.splice(i, 1);
                    } else if (sub_admin.fields.number > deleted_num) {
                        sub_admin.fields.number = sub_admin.fields.number - 1;
                    }
                }
            }
        }
    };

    $(document).ready(function() {
        $.ajax({
            url: urlPrefix + '../genericadmin-init/',
            dataType: 'json',
            success: function(data) {
                var url_array = data.url_array,
                    ct_fields = data.fields,
					popup_var = data.popup_var,
                    fields;

                for (var i = 0; i < ct_fields.length; i++) {
                    fields = ct_fields[i];
                    if (fields.inline === false) {
                        $.extend({}, GenericAdmin).install(fields, url_array, popup_var);
                    } else {
                        $.extend({}, InlineAdmin).install(fields, url_array, popup_var);
                    }
                }
            }
        });
    });
} (django.jQuery));
<commit_msg>fix js regex that detects new change url<commit_after>/*
    genericadmin - Weston Nielson (wnielson@gmail.com)

    updated by Jan Schrewe (jschrewe@googlemail.com)

    updated by Troy Melhase (troy.melhase@gmail.com)

    updated by Jonathan Ellenberger (jon@respondcreate.com)

 */
 (function($) {
    var isChangeUrl = /\/change\/?$/i.test(window.location.href),
        urlPrefix = isChangeUrl ? '../' : '';
    var GenericAdmin = {
        url_array: null,
        fields: null,
        obj_url: urlPrefix + "../obj-data/",
        admin_media_url: window.__admin_media_prefix__,
		popup: '_popup',

        prepareSelect: function(select) {
            var that = this,
                opt_keys = [],
                opt_dict = {},
                no_value,
                opt_group_css = 'style="font-style:normal; font-weight:bold; color:#999; padding-left: 2px;"';

            // polish the look of the select
            select.find('option').each(function() {
                var key, opt;

                if (this.value) {
                    if (that.url_array[this.value]) {
                        key = that.url_array[this.value][0].split('/')[0];

                        opt = $(this).clone();
                        opt.text(that.capFirst(opt.text()));
                        if ($.inArray(key, opt_keys) < 0) {
                            opt_keys.push(key);
                            // if it's the first time in array
                            // it's the first time in dict
                            opt_dict[key] = [opt];
                        } else {
                            opt_dict[key].push(opt);
                        }
                    }
                } else {
                    no_value = $(this).clone();
                }
            });
            select.empty().append(no_value);

            opt_keys = opt_keys.sort();

            $.each(opt_keys, function(index, key) {
                var opt_group = $('<optgroup label="' + that.capFirst(key) + '" ' + opt_group_css + '></optgroup>');
                $.each(opt_dict[key], function(index, value) {
                    opt_group.append(value).css('color', '#000');
                });
                select.append(opt_group);
            });

            return select;
        },

        getLookupUrlParams: function(cID) {
            var q = this.url_array[cID][1] || {},
                str = [];
            for(var p in q) {
                str.push(encodeURIComponent(p) + "=" + encodeURIComponent(q[p]));
            }
            x = str.join("&");
            url = x ? ("?" + x) : "";
            return url;
        },

        getLookupUrl: function(cID) {
            return urlPrefix + '../../../' + this.url_array[cID][0] + '/' + this.getLookupUrlParams(cID);
        },

        getFkId: function() {
            if (this.fields.inline === false) {
                return 'id_' + this.fields.fk_field;
            } else {
                return ['id_', this.fields.prefix, '-', this.fields.number, '-', this.fields.fk_field].join('');
            }
        },

        getCtId: function() {
            if (this.fields.inline === false) {
                return 'id_' + this.fields.ct_field;
            } else {
                return ['id_', this.fields.prefix, '-', this.fields.number, '-', this.fields.ct_field].join('');
            }
        },

        capFirst: function(string) {
            return string.charAt(0).toUpperCase() + string.slice(1);
        },

        hideLookupLink: function() {
            var this_id = this.getFkId();
            $('#lookup_' + this_id).unbind().remove();
            $('#lookup_text_' + this_id + ' a').remove();
            $('#lookup_text_' + this_id + ' span').remove();
        },

        showLookupLink: function() {
            var that = this,
                url = this.getLookupUrl(this.cID),
                id = 'lookup_' + this.getFkId(),
                link = '';
            // admin media is removed in django 1.9
            if (this.admin_media_url !== undefined) {
                link = link + '';
            }
            link += '';
            link += '';

            // insert link html after input element
            this.object_input.after(link);

            return id;
        },

        pollInputChange: function(window) {
            var that = this,
                interval_id = setInterval(function() {
                    if (window.closed === true) {
                        clearInterval(interval_id);
                        that.updateObjectData()();
                        return true;
                    }
                },
                150);
        },

        popRelatedObjectLookup: function(link) {
            var name = id_to_windowname(this.getFkId()),
				url_parts = [],
                href,
                win;

            if (link.href.search(/\?/) >= 0) {
				url_parts[0] = '&';
                //href = link.href + '&pop=1';
            } else {
				url_parts[0] = '?';
                //href = link.href + '?pop=1';
            }
			url_parts[1] = this.popup;
			url_parts[2] = '=1';
			href = link.href + url_parts.join('');
            win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');

            // wait for popup to be closed and load object data
            this.pollInputChange(win);

            win.focus();
            return false;
        },

        updateObjectData: function() {
            var that = this;
            return function() {
                var value = that.object_input.val();

                if (!value) {
                    return
                }
                //var this_id = that.getFkId();
                $('#lookup_text_' + that.getFkId() + ' span').text('loading...');
                $.ajax({
                    url: that.obj_url,
                    dataType: 'json',
                    data: {
                        object_id: value,
                        content_type: that.cID
                    },
                    success: function(item) {
                        if (item && item.content_type_text && item.object_text) {
                            var url = that.getLookupUrl(that.cID);
                            $('#lookup_text_' + that.getFkId() + ' a')
                                .text(item.content_type_text + ': ' + item.object_text)
                                .attr('href', url + item.object_id);

                            // run a callback to do other stuff like prepopulating url fields
                            // can't be done with normal django admin prepopulate
                            if (that.updateObjectDataCallback) {
                                that.updateObjectDataCallback(item);
                            }
                        }
                        $('#lookup_text_' + that.getFkId() + ' span').text('');
                    },
                    error: function(xhr, status, error) {
                        $('#lookup_text_' + that.getFkId() + ' span').text('')
                            .html('Error: ' + xhr.status + ' – ' + that.capFirst(xhr.statusText.toLowerCase()));
                        if (xhr.status === 404) {
                            that.object_input.val('');
                        } else {
                            $('#lookup_text_' + that.getFkId() + ' span').css('color', '#f00');
                        }
                    }
                });
            };
        },

        install: function(fields, url_array, popup_var) {
            var that = this;

            this.url_array = url_array;
            this.fields = fields;
			this.popup = popup_var || this.popup;

            // store the base element
            this.object_input = $("#" + this.getFkId());

            // find the select we need to change
            this.object_select = this.prepareSelect($("#" + this.getCtId()));

            // install event handler for select
            this.object_select.change(function() {
                // reset the object input to the associated select (this one)
                var link_id;

                //(this).css('color', 'red'); // uncomment for testing
                that.hideLookupLink();
                // Set our objectId when the content_type is changed
                if (this.value) {
                    that.cID = this.value;
                    link_id = that.showLookupLink();
                    $('#' + link_id).click(function(e) {
                        e.preventDefault();
                        that.popRelatedObjectLookup(this);
                    });
                }
            });

            // fire change event if something is already selected
            if (this.object_select.val()) {
                this.object_select.trigger('change');
            }

            // Bind to the onblur of the object_id input.
            this.object_input.blur(that.updateObjectData());

            // Fire once for initial link.
            this.updateObjectData()();
        }
    };

    var InlineAdmin = {
        sub_admins: null,
        url_array: null,
        fields: null,
		popup: '_popup',

        install: function(fields, url_array, popup_var) {
            var inline_count = $('#id_' + fields.prefix + '-TOTAL_FORMS').val(),
                admin;

            this.url_array = url_array;
            this.fields = fields;
            this.sub_admins = [];
			this.popup = popup_var || this.popup;

            for (var j = 0; j < inline_count; j++) {
                f = $.extend({}, this.fields);
                f.number = j;
                admin = $.extend({}, GenericAdmin);
                admin.install(f, this.url_array, popup_var);
                this.sub_admins.push(admin);
            }
            $('#' + this.fields.prefix + '-group .add-row a').click(this.addHandler());
        },
        addHandler: function() {
            var that = this;
            return function(e) {
                e.preventDefault();
                var added_fields = $.extend({}, that.fields),
                    admin = $.extend({}, GenericAdmin);
                added_fields.number = ($('#id_' + that.fields.prefix + '-TOTAL_FORMS').val() - 1);
                admin.install(added_fields, that.url_array, that.popup);
                that.sub_admins.push(admin);

                $('#' + that.fields.prefix + '-' + added_fields.number + ' .inline-deletelink').click(
                    that.removeHandler(that)
                );
            }
        },
        removeHandler: function(that) {
            return function(e) {
                var parent_id,
                    deleted_num,
                    sub_admin;

                e.preventDefault();
                parent_id = $(e.currentTarget).parents('.dynamic-' + that.fields.prefix).first().attr('id');
                deleted_num = parseInt(parent_id.charAt(parent_id.length - 1), 10);
                for (var i = (that.sub_admins.length - 1); i >= 0; i--) {
                    sub_admin = that.sub_admins[i];
                    if (sub_admin.fields.number === deleted_num) {
                        that.sub_admins.splice(i, 1);
                    } else if (sub_admin.fields.number > deleted_num) {
                        sub_admin.fields.number = sub_admin.fields.number - 1;
                    }
                }
            }
        }
    };

    $(document).ready(function() {
        $.ajax({
            url: urlPrefix + '../genericadmin-init/',
            dataType: 'json',
            success: function(data) {
                var url_array = data.url_array,
                    ct_fields = data.fields,
					popup_var = data.popup_var,
                    fields;

                for (var i = 0; i < ct_fields.length; i++) {
                    fields = ct_fields[i];
                    if (fields.inline === false) {
                        $.extend({}, GenericAdmin).install(fields, url_array, popup_var);
                    } else {
                        $.extend({}, InlineAdmin).install(fields, url_array, popup_var);
                    }
                }
            }
        });
    });
} (django.jQuery));
<|endoftext|>


<commit_before>var vui = vui || {};
vui.matchers = vui.matchers || {};

vui.matchers.jasmine = {
	toMatchRecordedObjectAt: function() {
		return {
			compare: function ( actual, recordedObjectPath, exceptions ) {

				var expectedResult;

				//@if !RECORDING
				expectedResult = vui.records.getRecord(recordedObjectPath);
				//@endif

				//@if RECORDING
				expectedResult = actual
				vui.records.setRecord(recordedObjectPath, expectedResult);
				//@endif

				var diff = vui.differs.json.diffLogs( actual, expectedResult, exceptions );

	       		var retStr = "";
				for( d in diff ) {
					retStr = "Expected " + d + " to be " + diff[d].expected + " but got " + diff[d].actual;
				}

				return {
					pass: retStr == "",
					message: retStr
				};

			}
		};
	}
};
<commit_msg>Fix an issue with the Jasmine log not outputting the full string.<commit_after>var vui = vui || {};
vui.matchers = vui.matchers || {};

vui.matchers.jasmine = {
	toMatchRecordedObjectAt: function() {
		return {
			compare: function ( actual, recordedObjectPath, exceptions ) {

				var expectedResult;

				//@if !RECORDING
				expectedResult = vui.records.getRecord(recordedObjectPath);
				//@endif

				//@if RECORDING
				expectedResult = actual
				vui.records.setRecord(recordedObjectPath, expectedResult);
				//@endif

				var diff = vui.differs.json.diffLogs( actual, expectedResult, exceptions );

	       		var retStr = "";
				for( d in diff ) {
					retStr = retStr + "Expected " + d + " to be " + diff[d].expected + " but got " + diff[d].actual + "\n";
				}

				return {
					pass: retStr == "",
					message: retStr
				};

			}
		};
	}
};
<|endoftext|>


<commit_before>var pj = require('./paper-core.js')
var asyncMap = require('slide').asyncMap
var drompii = require('./drompii.js')
var through = require('through2')
var D = require('./dombii.js')
var ddx = require('./dedex.js')
var fs = require('fs')
var _ = require('underscore')
var path = require('path')

var OMNI = fs.readFileSync(__dirname+'/omni.hogan', 'utf8')
var GRIFTER = fs.readFileSync(__dirname+'/grifter.hogan', 'utf8')
var LOGIN = fs.readFileSync(__dirname+'/login.hogan', 'utf8')

module.exports = function Omni (opts) {
  var blob
  var dx = {}
  dx.desc = 'login'

  var s = through.obj(function Interface (d, enc, next) {
    if (d.code === 1) {
      next()
      login.draw({err:true,msg:d.message})
      document.body.querySelector('#login').focus()
      return null
    } else if (!d.key) { next(); return null }

    var tkn = (d.key.split(':').length>1)
      ? d.key.split(':')[1]
      : d.key

    if (tkn && tkn === opts.id) {
      if (d.key.split(':')[0] === '@edit') {
        sessionStorage['edit'] = d.value
        login.erase()
        omni.draw(dx, initUI)
      } else {
        if (d.value === '-edit') omni.erase() // but it should also be unpiped

        // var val = d.value[0]
        // if (!val) { next(); return false }
        // dx.pkg = val
        // ui.readout(val.name)
        // pj.view.draw()

      }
    }
    next()
  })

 // UI

  var ui =  {}

  function initUI () {
    pj.setup(document.querySelector('#cvs'))

    ui.results = new pj.Group({ point:[0,0] })

    ui.label = new pj.PointText({
      point : [0,0],
      fontFamily : 'Monaco',
      fillColor : 'black',
      content : name,
      fontSize : 10
    })

    ui.makeBox = function (name,pos) {
      var label = new pj.PointText({
        point : [0,0],
        fontFamily : 'Monaco',
        fillColor : 'black',
        content : name,
        fontSize : 10
      })

      label.position.x = (label.bounds.width/2) + 4
      label.position.y = (label.bounds.height/2) + 4

      var frame = new pj.Shape.Rectangle({
        strokeWidth : 1,
        strokeColor : 'black',
        point : [0,0],
        size : [label.bounds.width+8, label.bounds.height+8]
      })

      var nb = new pj.Group({
        children : [frame,label]
      })
      nb.position.x = label.position.x + 2

      var y = (ui.results.children.length+1)*(frame.bounds.height+4)
      y += (label.position.y+1)

      nb.position.y = y

      return nb
    }

    ui.readout = function (str) {
      ui.label.content = str
      ui.label.position.y = (ui.label.bounds.height/2) + 4
      ui.label.position.x = ui.label.bounds.width/2
    }
  }

  // TEMPLATES

  var login = new D({
    template : LOGIN,
    parent : document.body,
    events : [['.login','submit',function (e) {
      e.preventDefault()
      s.push('+@edit '+e.target[0].value+'/'+opts.id)
      e.target[0].value = ''
    }]]
  })

  var omni = new D({
    id : opts.id,
    template : OMNI,
    parent : document.body,
    events : [
      [window,'contextmenu',grifter],
      ['.oz','keyup',keyInput]
    ]
  })

  var editor = new D({
    template : GRIFTER,
    parent : document.body,
    events : [
      ['.grifter','keyup',edit],
      ['.grifter','drop',upload],
      ['.grifter','dragenter',cancel],
      ['.grifter','dragleave',cancel],
      ['.grifter','dragover',cancel]
    ]
  })

  // EVENTS

  function keyInput (e) {
    var val = e.target.value.replace(' ','')

    if (e.keyCode === 8 || e.key === 'Backspace' && val === '')
      pj.view.draw()

    else if (e.keyCode === 13 || e.key === 'Enter') {
      e.preventDefault()
      // var b = ui.makeBox(dx.pkg.name,[0,10])
      // ui.results.addChild(b)
      // pj.view.draw()
      // e.target.value = ''
      s.push(val+'/'+opts.id)
    }
  }

  // MAKE PANELS DRAGGABLE

  var drag
  function ungrip (e) { window.removeEventListener('mousemove',drag) }
  function grip(e) {
    e.preventDefault()

    ungrip(e)

    var p = e.target.parentElement
    var offX = e.clientX - p.pageX
    var offY = e.clientY - p.pageY

    drag = function (e) {
      dx.x = e.clientX - offX
      dx.y = e.clientY - offY
      omni.draw(dx)
    }

    window.addEventListener('mousemove', drag, false)
  }

  // CONTEXT / EDIT

  function grifter (e) {
    e.preventDefault()
    blob = drompii(e)
    editor.erase()

    var dx = {
      x : e.pageX-10,
      y: e.pageY-10,
      body: _.values(blob.edit)[0].replace(/[\n\r]/g,'')
    }

    if (dx.body.length>140) { dx.w = 400; dx.h = 300 }

    switch (blob.type) {
      case 'SPAN' : editor.draw(dx);break;
      case 'IMG' : editor.draw(dx);break;
    }
  }

  function edit (e) {
    if (e.keyCode === 13) {
      e.preventDefault()
      var body = e.target.value.replace(/[\n\r]/g,'')
      blob.data[_.keys(blob.edit)[0]] = body
      s.push({key:'+$'+blob.id,value:blob.data})
      editor.erase()
      return false
    }
  }

  function upload (e) {
    cancel(e)
    var files = e.dataTransfer.files

    for (file in files) {
      if (file === 'length') return
      if (files[file] && files[file].type)
        var fileName =files[file].name.replace(/[^a-z0-9]/gi,'_').toLowerCase()

      var filepath
      var ndata = {}
      var formData = new FormData()
      formData.append('file', fileName)
      formData.append('token', 'test123')

      var xhr = new XMLHttpRequest()
      xhr.addEventListener('error', function (e) { console.error(e) }, false)
      xhr.addEventListener('load', function (e) {
        s.push({key:'+$'+ndata.id,value:ndata.data})
      }, false)
      xhr.addEventListener('progress', function (e) {
        editor.data.body = 'loaded : ' + (e.loaded/e.total) * 100 + '% '
        editor.draw()
        if (e.loaded === e.total) editor.erase()
        else if (e.total === 0) editor.erase()
      }, false)
      xhr.open('post', '/upload', true)

      var reader = new FileReader()
      reader.readAsDataURL(files[file])
      reader.addEventListener('load', function (data) {
        filePath = '/files/'+fileName
        formData.append('blob', data.target.result)
        editor.erase()
        if (data.target.result.split('/')[0]==='data:image') {
          var img = new Image()
          img.src = data.target.result
          img.addEventListener('load',function (e) {
            blob.edit.w = e.target.width
            blob.edit.h = e.target.height
            blob.edit.src = '/files/'+fileName
            _.each(blob.edit, function (v,k,l) {
              if (blob.data[k]) blob.data[k] = v
            })
            _.each(blob, function (v,k,l) { ndata[k] = v })
          },false)
        }
        xhr.send(formData)
      }, false)
    }
  }

  if (sessionStorage['edit'])
    s.push('+@edit '+sessionStorage['edit']+'/'+opts.id)

  if (!sessionStorage['edit']) {
    login.draw({err:false})
    document.body.querySelector('#login').focus()
  }

  return s
}

function cancel (e) {
  e.preventDefault()
  if (e.stopPropogation) e.stopPropogation()
}
<commit_msg>hack to drop body down when editing<commit_after>var pj = require('./paper-core.js')
var asyncMap = require('slide').asyncMap
var drompii = require('./drompii.js')
var through = require('through2')
var D = require('./dombii.js')
var ddx = require('./dedex.js')
var fs = require('fs')
var _ = require('underscore')
var path = require('path')

var OMNI = fs.readFileSync(__dirname+'/omni.hogan', 'utf8')
var GRIFTER = fs.readFileSync(__dirname+'/grifter.hogan', 'utf8')
var LOGIN = fs.readFileSync(__dirname+'/login.hogan', 'utf8')

module.exports = function Omni (opts) {
  var blob
  var dx = {}
  dx.desc = 'login'

  var s = through.obj(function Interface (d, enc, next) {
    if (d.code === 1) {
      next()
      login.draw({err:true,msg:d.message})
      document.body.querySelector('#login').focus()
      return null
    } else if (!d.key) { next(); return null }

    var tkn = (d.key.split(':').length>1)
      ? d.key.split(':')[1]
      : d.key

    if (tkn && tkn === opts.id) {
      if (d.key.split(':')[0] === '@edit') {
        sessionStorage['edit'] = d.value
        login.erase()
        omni.draw(dx, initUI)
        document.body.setAttribute('class','editing')
      } else {
        if (d.value === '-edit') {
          omni.erase() // but it should also be unpiped
          document.body.setAttribute('class',null)
        }
        // var val = d.value[0]
        // if (!val) { next(); return false }
        // dx.pkg = val
        // ui.readout(val.name)
        // pj.view.draw()

      }
    }
    next()
  })

 // UI

  var ui =  {}

  function initUI () {
    pj.setup(document.querySelector('#cvs'))

    ui.results = new pj.Group({ point:[0,0] })

    ui.label = new pj.PointText({
      point : [0,0],
      fontFamily : 'Monaco',
      fillColor : 'black',
      content : name,
      fontSize : 10
    })

    ui.makeBox = function (name,pos) {
      var label = new pj.PointText({
        point : [0,0],
        fontFamily : 'Monaco',
        fillColor : 'black',
        content : name,
        fontSize : 10
      })

      label.position.x = (label.bounds.width/2) + 4
      label.position.y = (label.bounds.height/2) + 4

      var frame = new pj.Shape.Rectangle({
        strokeWidth : 1,
        strokeColor : 'black',
        point : [0,0],
        size : [label.bounds.width+8, label.bounds.height+8]
      })

      var nb = new pj.Group({
        children : [frame,label]
      })
      nb.position.x = label.position.x + 2

      var y = (ui.results.children.length+1)*(frame.bounds.height+4)
      y += (label.position.y+1)

      nb.position.y = y

      return nb
    }

    ui.readout = function (str) {
      ui.label.content = str
      ui.label.position.y = (ui.label.bounds.height/2) + 4
      ui.label.position.x = ui.label.bounds.width/2
    }
  }

  // TEMPLATES

  var login = new D({
    template : LOGIN,
    parent : document.body,
    events : [['.login','submit',function (e) {
      e.preventDefault()
      s.push('+@edit '+e.target[0].value+'/'+opts.id)
      e.target[0].value = ''
    }]]
  })

  var omni = new D({
    id : opts.id,
    template : OMNI,
    parent : document.body,
    events : [
      [window,'contextmenu',grifter],
      ['.oz','keyup',keyInput]
    ]
  })

  var editor = new D({
    template : GRIFTER,
    parent : document.body,
    events : [
      ['.grifter','keyup',edit],
      ['.grifter','drop',upload],
      ['.grifter','dragenter',cancel],
      ['.grifter','dragleave',cancel],
      ['.grifter','dragover',cancel]
    ]
  })

  // EVENTS

  function keyInput (e) {
    var val = e.target.value.replace(' ','')

    if (e.keyCode === 8 || e.key === 'Backspace' && val === '')
      pj.view.draw()

    else if (e.keyCode === 13 || e.key === 'Enter') {
      e.preventDefault()
      // var b = ui.makeBox(dx.pkg.name,[0,10])
      // ui.results.addChild(b)
      // pj.view.draw()
      // e.target.value = ''
      s.push(val+'/'+opts.id)
    }
  }

  // MAKE PANELS DRAGGABLE

  var drag
  function ungrip (e) { window.removeEventListener('mousemove',drag) }
  function grip(e) {
    e.preventDefault()

    ungrip(e)

    var p = e.target.parentElement
    var offX = e.clientX - p.pageX
    var offY = e.clientY - p.pageY

    drag = function (e) {
      dx.x = e.clientX - offX
      dx.y = e.clientY - offY
      omni.draw(dx)
    }

    window.addEventListener('mousemove', drag, false)
  }

  // CONTEXT / EDIT

  function grifter (e) {
    e.preventDefault()
    blob = drompii(e)
    editor.erase()

    var dx = {
      x : e.pageX-10,
      y: e.pageY-10,
      body: _.values(blob.edit)[0].replace(/[\n\r]/g,'')
    }

    if (dx.body.length>140) { dx.w = 400; dx.h = 300 }

    switch (blob.type) {
      case 'SPAN' : editor.draw(dx);break;
      case 'IMG' : editor.draw(dx);break;
    }
  }

  function edit (e) {
    if (e.keyCode === 13) {
      e.preventDefault()
      var body = e.target.value.replace(/[\n\r]/g,'')
      blob.data[_.keys(blob.edit)[0]] = body
      s.push({key:'+$'+blob.id,value:blob.data})
      editor.erase()
      return false
    }
  }

  function upload (e) {
    cancel(e)
    var files = e.dataTransfer.files

    for (file in files) {
      if (file === 'length') return
      if (files[file] && files[file].type)
        var fileName =files[file].name.replace(/[^a-z0-9]/gi,'_').toLowerCase()

      var filepath
      var ndata = {}
      var formData = new FormData()
      formData.append('file', fileName)
      formData.append('token', 'test123')

      var xhr = new XMLHttpRequest()
      xhr.addEventListener('error', function (e) { console.error(e) }, false)
      xhr.addEventListener('load', function (e) {
        s.push({key:'+$'+ndata.id,value:ndata.data})
      }, false)
      xhr.addEventListener('progress', function (e) {
        editor.data.body = 'loaded : ' + (e.loaded/e.total) * 100 + '% '
        editor.draw()
        if (e.loaded === e.total) editor.erase()
        else if (e.total === 0) editor.erase()
      }, false)
      xhr.open('post', '/upload', true)

      var reader = new FileReader()
      reader.readAsDataURL(files[file])
      reader.addEventListener('load', function (data) {
        filePath = '/files/'+fileName
        formData.append('blob', data.target.result)
        editor.erase()
        if (data.target.result.split('/')[0]==='data:image') {
          var img = new Image()
          img.src = data.target.result
          img.addEventListener('load',function (e) {
            blob.edit.w = e.target.width
            blob.edit.h = e.target.height
            blob.edit.src = '/files/'+fileName
            _.each(blob.edit, function (v,k,l) {
              if (blob.data[k]) blob.data[k] = v
            })
            _.each(blob, function (v,k,l) { ndata[k] = v })
          },false)
        }
        xhr.send(formData)
      }, false)
    }
  }

  if (sessionStorage['edit'])
    s.push('+@edit '+sessionStorage['edit']+'/'+opts.id)

  if (!sessionStorage['edit']) {
    login.draw({err:false})
    document.body.querySelector('#login').focus()
  }

  return s
}

function cancel (e) {
  e.preventDefault()
  if (e.stopPropogation) e.stopPropogation()
}
<|endoftext|>