<commit_before>/*
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd

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

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

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

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {Resizable} from "re-resizable";

import AppTile from '../elements/AppTile';
import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
import * as ScalarMessaging from '../../../ScalarMessaging';
import WidgetUtils from '../../../utils/WidgetUtils';
import WidgetEchoStore from "../../../stores/WidgetEchoStore";
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import SettingsStore from "../../../settings/SettingsStore";
import {useLocalStorageState} from "../../../hooks/useLocalStorageState";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import WidgetStore from "../../../stores/WidgetStore";
import ResizeHandle from "../elements/ResizeHandle";
import Resizer from "../../../resizer/resizer";
import PercentageDistributor from "../../../resizer/distributors/percentage";

export default class AppsDrawer extends React.Component {
    static propTypes = {
        userId: PropTypes.string.isRequired,
        room: PropTypes.object.isRequired,
        resizeNotifier: PropTypes.instanceOf(ResizeNotifier).isRequired,
        showApps: PropTypes.bool, // Should apps be rendered
    };

    static defaultProps = {
        showApps: true,
    };

    constructor(props) {
        super(props);

        this.state = {
            apps: this._getApps(),
        };

        this._resizeContainer = null;
        this.resizer = this._createResizer();

        this.props.resizeNotifier.on("isResizing", this.onIsResizing);
    }

    componentDidMount() {
        ScalarMessaging.startListening();
        WidgetStore.instance.on(this.props.room.roomId, this._updateApps);
        this.dispatcherRef = dis.register(this.onAction);
    }

    componentWillUnmount() {
        ScalarMessaging.stopListening();
        WidgetStore.instance.off(this.props.room.roomId, this._updateApps);
        if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
        if (this._resizeContainer) {
            this.resizer.detach();
        }
        this.props.resizeNotifier.off("isResizing", this.onIsResizing);
    }

    // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
    // eslint-disable-next-line camelcase
    UNSAFE_componentWillReceiveProps(newProps) {
        // Room has changed probably, update apps
        this._updateApps();
    }

    onIsResizing = (resizing) => {
        this.setState({ resizing });
        if (!resizing) {
            this._relaxResizer();
        }
    };

    _createResizer() {
        const classNames = {
            handle: "mx_ResizeHandle",
            vertical: "mx_ResizeHandle_vertical",
            reverse: "mx_ResizeHandle_reverse",
        };
        const collapseConfig = {
            onResizeStart: () => {
                this._resizeContainer.classList.add("mx_AppsDrawer_resizing");
            },
            onResizeStop: () => {
                this._resizeContainer.classList.remove("mx_AppsDrawer_resizing");
                // persist to localStorage
                console.log("@@ _saveResizerPreferences");
                localStorage.setItem(this._getStorageKey(), JSON.stringify([
                    this.state.apps.map(app => app.id),
                    ...this.state.apps.slice(1).map((_, i) => this.resizer.forHandleAt(i).size),
                ]));
            },
        };
        // pass a truthy container for now, we won't call attach until we update it
        const resizer = new Resizer({}, PercentageDistributor, collapseConfig);
        resizer.setClassNames(classNames);
        return resizer;
    }

    _collectResizer = (ref) => {
        console.log("@@ _collectResizer");
        if (this._resizeContainer) {
            this.resizer.detach();
        }

        if (ref) {
            this.resizer.container = ref;
            this.resizer.attach();
        }
        this._resizeContainer = ref;
        this._loadResizerPreferences();
    };

    _getStorageKey = () => `mx_apps_drawer-${this.props.room.roomId}`;

    _getAppsHash = (apps) => apps.map(app => app.id).join("~");

    componentDidUpdate(prevProps, prevState) {
        if (this._getAppsHash(this.state.apps) !== this._getAppsHash(prevState.apps)) {
            this._loadResizerPreferences();
        }
    }

    _relaxResizer = () => {
        const distributors = this.resizer.getDistributors();

        // relax all items if they had any overconstrained flexboxes
        distributors.forEach(d => d.start());
        distributors.forEach(d => d.finish());
    };

    _loadResizerPreferences = () => {
        console.log("@@ _loadResizerPreferences");
        try {
            const [[...lastIds], ...sizes] = JSON.parse(localStorage.getItem(this._getStorageKey()));
            // Every app was included in the last split, reuse the last sizes
            if (this.state.apps.length <= lastIds.length && this.state.apps.every((app, i) => lastIds[i] === app.id)) {
                sizes.forEach((size, i) => {
                    const distributor = this.resizer.forHandleAt(i);
                    if (distributor) {
                        distributor.size = size;
                        distributor.finish();
                    }
                });
                return;
            }
        } catch (e) {
            // this is expected
        }

        if (this.state.apps) {
            console.log("@@ full relaxation");
            const distributors = this.resizer.getDistributors();
            distributors.forEach(d => d.item.clearSize());
            distributors.forEach(d => d.start());
            distributors.forEach(d => d.finish());
        }
    };

    onAction = (action) => {
        const hideWidgetKey = this.props.room.roomId + '_hide_widget_drawer';
        switch (action.action) {
            case 'appsDrawer':
                // Note: these booleans are awkward because localstorage is fundamentally
                // string-based. We also do exact equality on the strings later on.
                if (action.show) {
                    localStorage.setItem(hideWidgetKey, "false");
                } else {
                    // Store hidden state of widget
                    // Don't show if previously hidden
                    localStorage.setItem(hideWidgetKey, "true");
                }

                break;
        }
    };

    _getApps = () => WidgetStore.instance.getPinnedApps(this.props.room.roomId);

    _updateApps = () => {
        this.setState({
            apps: this._getApps(),
        });
    };

    _launchManageIntegrations() {
        if (SettingsStore.getValue("feature_many_integration_managers")) {
            IntegrationManagers.sharedInstance().openAll();
        } else {
            IntegrationManagers.sharedInstance().getPrimaryManager().open(this.props.room, 'add_integ');
        }
    }

    render() {
        if (!this.props.showApps) return
;

        const apps = this.state.apps.map((app, index, arr) => {
            const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, this.props.room.roomId);

            return (<AppTile
                key={app.id}
                app={app}
                fullWidth={arr.length < 2}
                room={this.props.room}
                userId={this.props.userId}
                creatorUserId={app.creatorUserId}
                widgetPageTitle={WidgetUtils.getWidgetDataTitle(app)}
                waitForIframeLoad={app.waitForIframeLoad}
                whitelistCapabilities={capWhitelist}
            />);
        });

        if (apps.length === 0) {
            return
;
        }

        let spinner;
        if (
            apps.length === 0 && WidgetEchoStore.roomHasPendingWidgets(
                this.props.room.roomId,
                WidgetUtils.getRoomWidgets(this.props.room),
            )
        ) {
            const Loader = sdk.getComponent("elements.Spinner");
            spinner = <Loader />;
        }

        const classes = classNames({
            mx_AppsDrawer: true,
            mx_AppsDrawer_fullWidth: apps.length < 2,
            mx_AppsDrawer_resizing: this.state.resizing,
            mx_AppsDrawer_has1: apps.length === 1,
            mx_AppsDrawer_has2: apps.length === 2,
            mx_AppsDrawer_has3: apps.length === 3,
        });

        return (

                <PersistentVResizer
                    id={"apps-drawer_" + this.props.room.roomId}
                    minHeight={100}
                    maxHeight={this.props.maxHeight ? this.props.maxHeight - 50 : undefined}
                    handleClass="mx_AppsContainer_resizerHandle"
                    className="mx_AppsContainer_resizer"
                    resizeNotifier={this.props.resizeNotifier}
                >

                        { apps.map((app, i) => {
                            if (i < 1) return app;
                            return <React.Fragment key={app.key}>
                                <ResizeHandle reverse={i > apps.length / 2} />
                                { app }
                            </React.Fragment>;
                        }) }

                </PersistentVResizer>
                { spinner }

        );
    }
}

const PersistentVResizer = ({
    id,
    minHeight,
    maxHeight,
    className,
    handleWrapperClass,
    handleClass,
    resizeNotifier,
    children,
}) => {
    const [height, setHeight] = useLocalStorageState("pvr_" + id, 280); // old fixed height was 273px

    return <Resizable
        size={{height: Math.min(height, maxHeight)}}
        minHeight={minHeight}
        maxHeight={maxHeight}
        onResizeStart={() => {
            resizeNotifier.startResizing();
        }}
        onResize={() => {
            resizeNotifier.notifyTimelineHeightChanged();
        }}
        onResizeStop={(e, dir, ref, d) => {
            setHeight(height + d.height);
            resizeNotifier.stopResizing();
        }}
        handleWrapperClass={handleWrapperClass}
        handleClasses={{bottom: handleClass}}
        className={className}
        enable={{bottom: true}}
    >
        { children }
    </Resizable>;
};
<commit_msg>remove debug lines<commit_after>/*
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd

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

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

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

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {Resizable} from "re-resizable";

import AppTile from '../elements/AppTile';
import dis from '../../../dispatcher/dispatcher';
import * as sdk from '../../../index';
import * as ScalarMessaging from '../../../ScalarMessaging';
import WidgetUtils from '../../../utils/WidgetUtils';
import WidgetEchoStore from "../../../stores/WidgetEchoStore";
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
import SettingsStore from "../../../settings/SettingsStore";
import {useLocalStorageState} from "../../../hooks/useLocalStorageState";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import WidgetStore from "../../../stores/WidgetStore";
import ResizeHandle from "../elements/ResizeHandle";
import Resizer from "../../../resizer/resizer";
import PercentageDistributor from "../../../resizer/distributors/percentage";

export default class AppsDrawer extends React.Component {
    static propTypes = {
        userId: PropTypes.string.isRequired,
        room: PropTypes.object.isRequired,
        resizeNotifier: PropTypes.instanceOf(ResizeNotifier).isRequired,
        showApps: PropTypes.bool, // Should apps be rendered
    };

    static defaultProps = {
        showApps: true,
    };

    constructor(props) {
        super(props);

        this.state = {
            apps: this._getApps(),
        };

        this._resizeContainer = null;
        this.resizer = this._createResizer();

        this.props.resizeNotifier.on("isResizing", this.onIsResizing);
    }

    componentDidMount() {
        ScalarMessaging.startListening();
        WidgetStore.instance.on(this.props.room.roomId, this._updateApps);
        this.dispatcherRef = dis.register(this.onAction);
    }

    componentWillUnmount() {
        ScalarMessaging.stopListening();
        WidgetStore.instance.off(this.props.room.roomId, this._updateApps);
        if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
        if (this._resizeContainer) {
            this.resizer.detach();
        }
        this.props.resizeNotifier.off("isResizing", this.onIsResizing);
    }

    // TODO: [REACT-WARNING] Replace with appropriate lifecycle event
    // eslint-disable-next-line camelcase
    UNSAFE_componentWillReceiveProps(newProps) {
        // Room has changed probably, update apps
        this._updateApps();
    }

    onIsResizing = (resizing) => {
        this.setState({ resizing });
        if (!resizing) {
            this._relaxResizer();
        }
    };

    _createResizer() {
        const classNames = {
            handle: "mx_ResizeHandle",
            vertical: "mx_ResizeHandle_vertical",
            reverse: "mx_ResizeHandle_reverse",
        };
        const collapseConfig = {
            onResizeStart: () => {
                this._resizeContainer.classList.add("mx_AppsDrawer_resizing");
            },
            onResizeStop: () => {
                this._resizeContainer.classList.remove("mx_AppsDrawer_resizing");
                // persist to localStorage
                localStorage.setItem(this._getStorageKey(), JSON.stringify([
                    this.state.apps.map(app => app.id),
                    ...this.state.apps.slice(1).map((_, i) => this.resizer.forHandleAt(i).size),
                ]));
            },
        };
        // pass a truthy container for now, we won't call attach until we update it
        const resizer = new Resizer({}, PercentageDistributor, collapseConfig);
        resizer.setClassNames(classNames);
        return resizer;
    }

    _collectResizer = (ref) => {
        if (this._resizeContainer) {
            this.resizer.detach();
        }

        if (ref) {
            this.resizer.container = ref;
            this.resizer.attach();
        }
        this._resizeContainer = ref;
        this._loadResizerPreferences();
    };

    _getStorageKey = () => `mx_apps_drawer-${this.props.room.roomId}`;

    _getAppsHash = (apps) => apps.map(app => app.id).join("~");

    componentDidUpdate(prevProps, prevState) {
        if (this._getAppsHash(this.state.apps) !== this._getAppsHash(prevState.apps)) {
            this._loadResizerPreferences();
        }
    }

    _relaxResizer = () => {
        const distributors = this.resizer.getDistributors();

        // relax all items if they had any overconstrained flexboxes
        distributors.forEach(d => d.start());
        distributors.forEach(d => d.finish());
    };

    _loadResizerPreferences = () => {
        try {
            const [[...lastIds], ...sizes] = JSON.parse(localStorage.getItem(this._getStorageKey()));
            // Every app was included in the last split, reuse the last sizes
            if (this.state.apps.length <= lastIds.length && this.state.apps.every((app, i) => lastIds[i] === app.id)) {
                sizes.forEach((size, i) => {
                    const distributor = this.resizer.forHandleAt(i);
                    if (distributor) {
                        distributor.size = size;
                        distributor.finish();
                    }
                });
                return;
            }
        } catch (e) {
            // this is expected
        }

        if (this.state.apps) {
            const distributors = this.resizer.getDistributors();
            distributors.forEach(d => d.item.clearSize());
            distributors.forEach(d => d.start());
            distributors.forEach(d => d.finish());
        }
    };

    onAction = (action) => {
        const hideWidgetKey = this.props.room.roomId + '_hide_widget_drawer';
        switch (action.action) {
            case 'appsDrawer':
                // Note: these booleans are awkward because localstorage is fundamentally
                // string-based. We also do exact equality on the strings later on.
                if (action.show) {
                    localStorage.setItem(hideWidgetKey, "false");
                } else {
                    // Store hidden state of widget
                    // Don't show if previously hidden
                    localStorage.setItem(hideWidgetKey, "true");
                }

                break;
        }
    };

    _getApps = () => WidgetStore.instance.getPinnedApps(this.props.room.roomId);

    _updateApps = () => {
        this.setState({
            apps: this._getApps(),
        });
    };

    _launchManageIntegrations() {
        if (SettingsStore.getValue("feature_many_integration_managers")) {
            IntegrationManagers.sharedInstance().openAll();
        } else {
            IntegrationManagers.sharedInstance().getPrimaryManager().open(this.props.room, 'add_integ');
        }
    }

    render() {
        if (!this.props.showApps) return
;

        const apps = this.state.apps.map((app, index, arr) => {
            const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, this.props.room.roomId);

            return (<AppTile
                key={app.id}
                app={app}
                fullWidth={arr.length < 2}
                room={this.props.room}
                userId={this.props.userId}
                creatorUserId={app.creatorUserId}
                widgetPageTitle={WidgetUtils.getWidgetDataTitle(app)}
                waitForIframeLoad={app.waitForIframeLoad}
                whitelistCapabilities={capWhitelist}
            />);
        });

        if (apps.length === 0) {
            return
;
        }

        let spinner;
        if (
            apps.length === 0 && WidgetEchoStore.roomHasPendingWidgets(
                this.props.room.roomId,
                WidgetUtils.getRoomWidgets(this.props.room),
            )
        ) {
            const Loader = sdk.getComponent("elements.Spinner");
            spinner = <Loader />;
        }

        const classes = classNames({
            mx_AppsDrawer: true,
            mx_AppsDrawer_fullWidth: apps.length < 2,
            mx_AppsDrawer_resizing: this.state.resizing,
            mx_AppsDrawer_has1: apps.length === 1,
            mx_AppsDrawer_has2: apps.length === 2,
            mx_AppsDrawer_has3: apps.length === 3,
        });

        return (

                <PersistentVResizer
                    id={"apps-drawer_" + this.props.room.roomId}
                    minHeight={100}
                    maxHeight={this.props.maxHeight ? this.props.maxHeight - 50 : undefined}
                    handleClass="mx_AppsContainer_resizerHandle"
                    className="mx_AppsContainer_resizer"
                    resizeNotifier={this.props.resizeNotifier}
                >

                        { apps.map((app, i) => {
                            if (i < 1) return app;
                            return <React.Fragment key={app.key}>
                                <ResizeHandle reverse={i > apps.length / 2} />
                                { app }
                            </React.Fragment>;
                        }) }

                </PersistentVResizer>
                { spinner }

        );
    }
}

const PersistentVResizer = ({
    id,
    minHeight,
    maxHeight,
    className,
    handleWrapperClass,
    handleClass,
    resizeNotifier,
    children,
}) => {
    const [height, setHeight] = useLocalStorageState("pvr_" + id, 280); // old fixed height was 273px

    return <Resizable
        size={{height: Math.min(height, maxHeight)}}
        minHeight={minHeight}
        maxHeight={maxHeight}
        onResizeStart={() => {
            resizeNotifier.startResizing();
        }}
        onResize={() => {
            resizeNotifier.notifyTimelineHeightChanged();
        }}
        onResizeStop={(e, dir, ref, d) => {
            setHeight(height + d.height);
            resizeNotifier.stopResizing();
        }}
        handleWrapperClass={handleWrapperClass}
        handleClasses={{bottom: handleClass}}
        className={className}
        enable={{bottom: true}}
    >
        { children }
    </Resizable>;
};
<|endoftext|>


<commit_before>/*
* Colorwheel
* Copyright (c) 2010 John Weir (http://famedriver.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*
* requires jQuery & Raphael
*   http://jquery.com http://raphaeljs.com
*
* see http://jweir.github.com/colorwheel for Usage
*
*/

Raphael.colorwheel = function(target, color_wheel_size, no_segments){
  var canvas,
      current_color,
      size,
      segments = no_segments || 60,
      bs_square = {},
      hue_ring = {},
      tri_size,
      cursor = {},
      drag_target,
      input_target,
      center,
      parent,
      change_callback,
      drag_callbacks = [function(){}, function(){}],
      offset,
      padding = 2,
      sdim; // holds the dimensions for the saturation square

  function point(x, y){ return {x:x, y:y};}
  function radians(a){ return a * (Math.PI/180);}

  function angle(x,y){
    var q = x > 0 ? 0 : 180;
    return q+Math.atan((0 - y)/(0 - x))*180/(Math.PI);
  }

  function create(target, color_wheel_size){
    size     = color_wheel_size;
    tri_size = size/20;
    center   = size/2;
    parent   = $(target);
    canvas   = Raphael(parent[0],size, size);
    canvas.safari();

    create_bs_square();
    create_hue_ring();
    hue_ring.cursor = cursor_create(tri_size);
    bs_square.cursor = cursor_create(tri_size*0.5);
    events_setup();
    parent.css({height:size+"px", width:size+"px"});
    disable_select(parent);
    return public_methods();
  }

  function disable_select(target){
    $(target).css({"unselectable": "on","-moz-user-select": "none","-webkit-user-select": "none"});
  }

  function public_methods(){
    return {
      input: input,
      onchange: onchange,
      ondrag : ondrag,
      color : public_set_color
    };
  }

  // Sets a textfield for user input of hex color values
  // TODO don't clear the change callback
  // TODO allow a null target to unbind the input
  function input(target){
    change_callback = null;
    input_target = target;
    $(target).keyup(function(){
      if(this.value.match(/^#([0-9A-F]){3}$|^#([0-9A-F]){6}$/img)){
        set_color(this.value);
        update_color(true);
		run_onchange_event();
      }
    });
    set_color(target.value);
    update_color(true);

    return public_methods();
  }

  function onchange(callback){
    change_callback = callback;
    update_color(false);
    return public_methods();
  }

  function ondrag(start_callback, end_callback){
    drag_callbacks = [start_callback || function(){}, end_callback || function(){}];
    return public_methods();
  }

  function drag(e){
    var x, y, page;

    e.preventDefault(); // prevents scrolling on touch

    page = e.originalEvent.touches ? e.originalEvent : e;

    x = page.pageX - (parent.offset().left + center);
    y = page.pageY - (parent.offset().top + center);

    if(drag_target == hue_ring){
      set_hue_cursor(x,y);
      update_color();
      run_onchange_event();
      return true;
    }
    if(drag_target == bs_square){
      set_bs_cursor(x,y);
      update_color();
      run_onchange_event();
      return true;
    }
  }

  function start_drag(event, target){
    $(document).on('mouseup touchend',stop_drag);
    $(document).on('mousemove touchmove',drag);
    drag_target = target;
    drag(event);
    drag_callbacks[0](current_color);
  }

  function stop_drag(){
    $(document).off("mouseup touchend",stop_drag);
    $(document).off("mousemove touchmove",drag);
    drag_callbacks[1](current_color);
    run_onchange_event();
  }

  function events_setup(){
    $([hue_ring.event.node,hue_ring.cursor[0].node]).on("mousedown touchstart",
                                                        function(e){start_drag(e,hue_ring);});
    $([bs_square.b.node, bs_square.cursor[0].node]).on("mousedown touchstart",
                                                       function(e){start_drag(e,bs_square);});
  }

  function cursor_create(size){
    var set = canvas.set().push(
        canvas.circle(0, 0, size).attr({"stroke-width":4, stroke:"#333"}),
        canvas.circle(0, 0, size+2).attr({"stroke-width":1, stroke:"#FFF", opacity:0.5})
    );

    set[0].node.style.cursor = "crosshair";

    return set;
  }

  function set_bs_cursor(x,y){
    x = x+center;
    y = y+center;
    if(x < sdim.x) x = sdim.x;
    if(x > sdim.x+sdim.l) x = sdim.x+sdim.l;
    if(y < sdim.y) y = sdim.y;
    if(y > sdim.y+sdim.l) y = sdim.y + sdim.l;

    bs_square.cursor.attr({cx:x, cy:y}).transform("t0,0");
  }

  function set_hue(color){
    var hex = Raphael.getRGB(color).hex;
    bs_square.h.attr("fill", hex);
  }

  function hue(){
    return Raphael.rgb2hsb(bs_square.h.attr("fill")).h;
  }

  function public_set_color(value){
    var ret = set_color(value);
    update_color(false);
    return ret;
  }

  function set_color(value){
    if(value === undefined){ return current_color; }

    var temp = canvas.rect(1,1,1,1).attr({fill:value}),
        hsb = canvas.raphael.rgb2hsb(temp.attr("fill"));

    set_bs_cursor(
      (0-sdim.l/2) + (sdim.l*hsb.s),
      sdim.l/2 - (sdim.l*hsb.b));
    set_hue_cursor((360*(hsb.h))-90);
    temp.remove();
    return public_methods();
  }

  // Could optimize this method
  function update_color(dont_replace_input_value){
    var x = bs_square.cursor.items[0].attr("cx"),
        y = bs_square.cursor.items[0].attr("cy"),
        hsb = {
          b: 1-(y-sdim.y)/sdim.l,
          s: (x-sdim.x)/sdim.l,
          h: hue()
        };

    current_color = Raphael.hsb2rgb(hsb.h, hsb.s,hsb.b);

    if(input_target){
      var c = current_color.hex;
      if(dont_replace_input_value != true) { input_target.value = c;}
       if(hsb.b < 0.5){
        $(input_target).css("color", "#FFF");
      } else {
        $(input_target).css("color", "#000");
      }
      input_target.style.background = c;
    }

  }

  // accepts either x,y or d (degrees)
  function set_hue_cursor(mixed_args){
    var d;
    if(arguments.length == 2){
      d = angle(arguments[0],arguments[1]);
    } else {
      d = arguments[0];
    }

    var x = Math.cos(radians(d)) * (center-tri_size-padding);
    var y = Math.sin(radians(d)) * (center-tri_size-padding);
    hue_ring.cursor.attr({cx:x+center, cy:y+center}).transform("t0,0");
    set_hue("hsb("+(d+90)/360+",1,1)");
  }

  function bs_square_dim(){
    if(sdim){ return sdim;}
    var s = size - (tri_size * 4);
    sdim = {
      x:(s/6)+tri_size*2+padding,
      y:(s/6)+tri_size*2+padding,
      l:(s * 2/3)-padding*2
    };
    return sdim;
  }

  function create_bs_square(){
    bs_square_dim();
    box = [sdim.x, sdim.y, sdim.l, sdim.l];

    bs_square.h = canvas.rect.apply(canvas, box).attr({
      stroke:"#EEE", gradient: "0-#FFF-#000", opacity:1});
    bs_square.s = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "0-#FFF-#FFF", opacity:0});
    bs_square.b = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "90-#000-#FFF", opacity:0});
    bs_square.b.node.style.cursor = "crosshair";
  }

  function hue_segement_shape(){
    var path = "M -@W 0 L @W 0 L @W @H L -@W @H z";
    return path.replace(/@H/img, tri_size*2).replace(/@W/img,tri_size);
  }

  function copy_segment(r, d, k){
    var n = r.clone();
    var hue = d*(255/k);

    var s = size/2,
      t = tri_size,
      p = padding;

    n.transform("t"+s+","+(s-t)+"r"+(360/k)*d+"t0,-"+(s-t-p)+"");

    n.attr({"stroke-width":0, fill:"hsb("+d*(1/k)+", 1, 0.85)"});
    hue_ring.hues.push(n);
  }

  function create_hue_ring(){
    var s = hue_segement_shape(),
        tri = canvas.path(s).attr({stroke:"rgba(0,0,0,0)"}).transform("t"+(size/2)+","+padding),
        k = segments; // # of segments to use to generate the hues

    hue_ring.hues = canvas.set();

    for(n=0; n<k; n++){ copy_segment(tri, n, k); }

    // IE needs a slight opacity to assign events
    hue_ring.event = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke-width":tri_size*2, opacity:0.01});

    hue_ring.outline = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke":"#000", "stroke-width":(tri_size*2)+3, opacity:0.1});
    hue_ring.outline.toBack();
    hue_ring.event.node.style.cursor = "crosshair";
  }

  function run_onchange_event(){
	if (change_callback != undefined){
      change_callback(current_color);
    }
  }

  return create(target, color_wheel_size);
};
<commit_msg>fix touches for Android<commit_after>/*
* Colorwheel
* Copyright (c) 2010 John Weir (http://famedriver.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
*
* requires jQuery & Raphael
*   http://jquery.com http://raphaeljs.com
*
* see http://jweir.github.com/colorwheel for Usage
*
*/

Raphael.colorwheel = function(target, color_wheel_size, no_segments){
  var canvas,
      current_color,
      size,
      segments = no_segments || 60,
      bs_square = {},
      hue_ring = {},
      tri_size,
      cursor = {},
      drag_target,
      input_target,
      center,
      parent,
      change_callback,
      drag_callbacks = [function(){}, function(){}],
      offset,
      padding = 2,
      sdim; // holds the dimensions for the saturation square

  function point(x, y){ return {x:x, y:y};}
  function radians(a){ return a * (Math.PI/180);}

  function angle(x,y){
    var q = x > 0 ? 0 : 180;
    return q+Math.atan((0 - y)/(0 - x))*180/(Math.PI);
  }

  function create(target, color_wheel_size){
    size     = color_wheel_size;
    tri_size = size/20;
    center   = size/2;
    parent   = $(target);
    canvas   = Raphael(parent[0],size, size);
    canvas.safari();

    create_bs_square();
    create_hue_ring();
    hue_ring.cursor = cursor_create(tri_size);
    bs_square.cursor = cursor_create(tri_size*0.5);
    events_setup();
    parent.css({height:size+"px", width:size+"px"});
    disable_select(parent);
    return public_methods();
  }

  function disable_select(target){
    $(target).css({"unselectable": "on","-moz-user-select": "none","-webkit-user-select": "none"});
  }

  function public_methods(){
    return {
      input: input,
      onchange: onchange,
      ondrag : ondrag,
      color : public_set_color
    };
  }

  // Sets a textfield for user input of hex color values
  // TODO don't clear the change callback
  // TODO allow a null target to unbind the input
  function input(target){
    change_callback = null;
    input_target = target;
    $(target).keyup(function(){
      if(this.value.match(/^#([0-9A-F]){3}$|^#([0-9A-F]){6}$/img)){
        set_color(this.value);
        update_color(true);
		run_onchange_event();
      }
    });
    set_color(target.value);
    update_color(true);

    return public_methods();
  }

  function onchange(callback){
    change_callback = callback;
    update_color(false);
    return public_methods();
  }

  function ondrag(start_callback, end_callback){
    drag_callbacks = [start_callback || function(){}, end_callback || function(){}];
    return public_methods();
  }

  function drag(e){
    var x, y, page;

    e.preventDefault(); // prevents scrolling on touch

    page = e.originalEvent.touches ? e.originalEvent.touches[0] : e;

    x = page.pageX - (parent.offset().left + center);
    y = page.pageY - (parent.offset().top + center);

    if(drag_target == hue_ring){
      set_hue_cursor(x,y);
      update_color();
      run_onchange_event();
      return true;
    }
    if(drag_target == bs_square){
      set_bs_cursor(x,y);
      update_color();
      run_onchange_event();
      return true;
    }
  }

  function start_drag(event, target){
    event.preventDefault(); // prevents scrolling on touch

    $(document).on('mouseup touchend',stop_drag);
    $(document).on('mousemove touchmove',drag);
    drag_target = target;
    drag(event);
    drag_callbacks[0](current_color);
  }

  function stop_drag(event){
    event.preventDefault(); // prevents scrolling on touch

    $(document).off("mouseup touchend",stop_drag);
    $(document).off("mousemove touchmove",drag);
    drag_callbacks[1](current_color);
    run_onchange_event();
  }

  function events_setup(){
    $([hue_ring.event.node,hue_ring.cursor[0].node]).on("mousedown touchstart",
                                                        function(e){start_drag(e,hue_ring);});
    $([bs_square.b.node, bs_square.cursor[0].node]).on("mousedown touchstart",
                                                       function(e){start_drag(e,bs_square);});
  }

  function cursor_create(size){
    var set = canvas.set().push(
        canvas.circle(0, 0, size).attr({"stroke-width":4, stroke:"#333"}),
        canvas.circle(0, 0, size+2).attr({"stroke-width":1, stroke:"#FFF", opacity:0.5})
    );

    set[0].node.style.cursor = "crosshair";

    return set;
  }

  function set_bs_cursor(x,y){
    x = x+center;
    y = y+center;
    if(x < sdim.x) x = sdim.x;
    if(x > sdim.x+sdim.l) x = sdim.x+sdim.l;
    if(y < sdim.y) y = sdim.y;
    if(y > sdim.y+sdim.l) y = sdim.y + sdim.l;

    bs_square.cursor.attr({cx:x, cy:y}).transform("t0,0");
  }

  function set_hue(color){
    var hex = Raphael.getRGB(color).hex;
    bs_square.h.attr("fill", hex);
  }

  function hue(){
    return Raphael.rgb2hsb(bs_square.h.attr("fill")).h;
  }

  function public_set_color(value){
    var ret = set_color(value);
    update_color(false);
    return ret;
  }

  function set_color(value){
    if(value === undefined){ return current_color; }

    var temp = canvas.rect(1,1,1,1).attr({fill:value}),
        hsb = canvas.raphael.rgb2hsb(temp.attr("fill"));

    set_bs_cursor(
      (0-sdim.l/2) + (sdim.l*hsb.s),
      sdim.l/2 - (sdim.l*hsb.b));
    set_hue_cursor((360*(hsb.h))-90);
    temp.remove();
    return public_methods();
  }

  // Could optimize this method
  function update_color(dont_replace_input_value){
    var x = bs_square.cursor.items[0].attr("cx"),
        y = bs_square.cursor.items[0].attr("cy"),
        hsb = {
          b: 1-(y-sdim.y)/sdim.l,
          s: (x-sdim.x)/sdim.l,
          h: hue()
        };

    current_color = Raphael.hsb2rgb(hsb.h, hsb.s,hsb.b);

    if(input_target){
      var c = current_color.hex;
      if(dont_replace_input_value != true) { input_target.value = c;}
       if(hsb.b < 0.5){
        $(input_target).css("color", "#FFF");
      } else {
        $(input_target).css("color", "#000");
      }
      input_target.style.background = c;
    }

  }

  // accepts either x,y or d (degrees)
  function set_hue_cursor(mixed_args){
    var d;
    if(arguments.length == 2){
      d = angle(arguments[0],arguments[1]);
    } else {
      d = arguments[0];
    }

    var x = Math.cos(radians(d)) * (center-tri_size-padding);
    var y = Math.sin(radians(d)) * (center-tri_size-padding);
    hue_ring.cursor.attr({cx:x+center, cy:y+center}).transform("t0,0");
    set_hue("hsb("+(d+90)/360+",1,1)");
  }

  function bs_square_dim(){
    if(sdim){ return sdim;}
    var s = size - (tri_size * 4);
    sdim = {
      x:(s/6)+tri_size*2+padding,
      y:(s/6)+tri_size*2+padding,
      l:(s * 2/3)-padding*2
    };
    return sdim;
  }

  function create_bs_square(){
    bs_square_dim();
    box = [sdim.x, sdim.y, sdim.l, sdim.l];

    bs_square.h = canvas.rect.apply(canvas, box).attr({
      stroke:"#EEE", gradient: "0-#FFF-#000", opacity:1});
    bs_square.s = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "0-#FFF-#FFF", opacity:0});
    bs_square.b = canvas.rect.apply(canvas, box).attr({
      stroke:null, gradient: "90-#000-#FFF", opacity:0});
    bs_square.b.node.style.cursor = "crosshair";
  }

  function hue_segement_shape(){
    var path = "M -@W 0 L @W 0 L @W @H L -@W @H z";
    return path.replace(/@H/img, tri_size*2).replace(/@W/img,tri_size);
  }

  function copy_segment(r, d, k){
    var n = r.clone();
    var hue = d*(255/k);

    var s = size/2,
      t = tri_size,
      p = padding;

    n.transform("t"+s+","+(s-t)+"r"+(360/k)*d+"t0,-"+(s-t-p)+"");

    n.attr({"stroke-width":0, fill:"hsb("+d*(1/k)+", 1, 0.85)"});
    hue_ring.hues.push(n);
  }

  function create_hue_ring(){
    var s = hue_segement_shape(),
        tri = canvas.path(s).attr({stroke:"rgba(0,0,0,0)"}).transform("t"+(size/2)+","+padding),
        k = segments; // # of segments to use to generate the hues

    hue_ring.hues = canvas.set();

    for(n=0; n<k; n++){ copy_segment(tri, n, k); }

    // IE needs a slight opacity to assign events
    hue_ring.event = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke-width":tri_size*2, opacity:0.01});

    hue_ring.outline = canvas.circle(
      center,
      center,
      center-tri_size-padding).attr({"stroke":"#000", "stroke-width":(tri_size*2)+3, opacity:0.1});
    hue_ring.outline.toBack();
    hue_ring.event.node.style.cursor = "crosshair";
  }

  function run_onchange_event(){
	if (change_callback != undefined){
      change_callback(current_color);
    }
  }

  return create(target, color_wheel_size);
};
<|endoftext|>


<commit_before>/**
 * Grid canvas
 *
 * Component hierarchy diagram:
 *
 *  +––––––––––––––––––––––––––––––––+
 *  | Canvas                         |
 *  | +––––––––––––––––––––––––––––+ |
 *  | | Row                        | |
 *  | | +––––––+ +––––––+ +––––––+ | |
 *  | | | Cell | | Cell | | Cell | | |
 *  | | +––––––+ +––––––+ +––––––+ | |
 *  | +––––––––––––––––––––––––––––+ |
 *  | ...                            |
 *  +––––––––––––––––––––––––––––––––+
 *
 * @jsx React.DOM
 */
"use strict";

var React          = require('react/addons');
var shallowEqual   = require('./utils').shallowEqual;
var cx             = React.addons.classSet;
var cloneWithProps = React.addons.cloneWithProps;
var ScrollShim     = require('./ScrollShim');
var Row            = require('./Row');

var Canvas = React.createClass({
  mixins: [ScrollShim],

  propTypes: {
    header: React.PropTypes.component,
    cellRenderer: React.PropTypes.component,
    rowRenderer: React.PropTypes.component,
    rowHeight: React.PropTypes.number.isRequired,
    displayStart: React.PropTypes.number.isRequired,
    displayEnd: React.PropTypes.number.isRequired,
    length: React.PropTypes.number.isRequired,
    ActiveCell: React.PropTypes.object.isRequired,
    rows: React.PropTypes.oneOfType([
      React.PropTypes.func.isRequired,
      React.PropTypes.array.isRequired
    ])
  },

  render: function() {
    var displayStart = this.state.displayStart;
    var displayEnd = this.state.displayEnd;
    var rowHeight = this.props.rowHeight;
    var length = this.props.length;

    var rows = this
        .getRows(displayStart, displayEnd)
        .map((row, idx) => this.renderRow({
          key: displayStart + idx,
          idx: displayStart + idx,
          row: row,
          Active: this.props.ActiveCell.row == idx,
          ActiveCell: this.props.ActiveCell.cell,
          height: rowHeight,
          columns: this.props.columns,
          cellRenderer: this.props.cellRenderer
        }));

    if (displayStart > 0) {
      rows.unshift(this.renderPlaceholder('top', displayStart * rowHeight));
    }

    if (length - displayEnd > 0) {
      rows.push(
        this.renderPlaceholder('bottom', (length - displayEnd) * rowHeight));
    }

    return this.transferPropsTo(

          {rows}

    );
  },

  renderRow: function(props) {
    // if (React.isValidComponent(this.props.rowRenderer)) {
    //   return cloneWithProps(this.props.rowRenderer(props), props);
    // } else {
      return this.props.rowRenderer(props);
    //}
  },

  renderPlaceholder: function(key, height) {
    return (

        {this.props.columns.map(
          (column, idx) =>
)}

    );
  },

  getDefaultProps: function() {
    return {rowRenderer: Row};
  },

  getInitialState: function() {
    return {
      shouldUpdate: true,
      displayStart: this.props.displayStart,
      displayEnd: this.props.displayEnd
    };
  },

  componentWillReceiveProps: function(nextProps) {
    var shouldUpdate = !(nextProps.visibleStart > this.state.displayStart
                        && nextProps.visibleEnd < this.state.displayEnd)
                        || nextProps.length !== this.props.length
                        || nextProps.rowHeight !== this.props.rowHeight
                        || nextProps.columns !== this.props.columns
                        || nextProps.width !== this.props.width
                        || !shallowEqual(nextProps.style, this.props.style);

    if (shouldUpdate) {
      this.setState({
        shouldUpdate: true,
        displayStart: nextProps.displayStart,
        displayEnd: nextProps.displayEnd
      });
    } else {
      this.setState({shouldUpdate: false});
    }
  },

  shouldComponentUpdate: function(nextProps, nextState) {
    return nextState.shouldUpdate;
  },

  onScroll: function(e) {
    this.appendScrollShim();
    if (this.props.onScroll) {
      this.props.onScroll(e);
    }
  },

  setScrollTop: function(scrollTop) {
    this.getDOMNode().scrollTop = scrollTop;
  },

  getRows: function(displayStart, displayEnd) {
    if (Array.isArray(this.props.rows)) {
      return this.props.rows.slice(displayStart, displayEnd);
    } else {
      return this.props.rows(displayStart, displayEnd);
    }
  }
});

module.exports = Canvas;
<commit_msg>fix cloneWithProps on rowRenderer - we were passing a func, not an obj<commit_after>/**
 * Grid canvas
 *
 * Component hierarchy diagram:
 *
 *  +––––––––––––––––––––––––––––––––+
 *  | Canvas                         |
 *  | +––––––––––––––––––––––––––––+ |
 *  | | Row                        | |
 *  | | +––––––+ +––––––+ +––––––+ | |
 *  | | | Cell | | Cell | | Cell | | |
 *  | | +––––––+ +––––––+ +––––––+ | |
 *  | +––––––––––––––––––––––––––––+ |
 *  | ...                            |
 *  +––––––––––––––––––––––––––––––––+
 *
 * @jsx React.DOM
 */
"use strict";

var React          = require('react/addons');
var shallowEqual   = require('./utils').shallowEqual;
var cx             = React.addons.classSet;
var cloneWithProps = React.addons.cloneWithProps;
var ScrollShim     = require('./ScrollShim');
var Row            = require('./Row');

var Canvas = React.createClass({
  mixins: [ScrollShim],

  propTypes: {
    header: React.PropTypes.component,
    cellRenderer: React.PropTypes.component,
    rowRenderer: React.PropTypes.component,
    rowHeight: React.PropTypes.number.isRequired,
    displayStart: React.PropTypes.number.isRequired,
    displayEnd: React.PropTypes.number.isRequired,
    length: React.PropTypes.number.isRequired,
    ActiveCell: React.PropTypes.object.isRequired,
    rows: React.PropTypes.oneOfType([
      React.PropTypes.func.isRequired,
      React.PropTypes.array.isRequired
    ])
  },

  render: function() {
    var displayStart = this.state.displayStart;
    var displayEnd = this.state.displayEnd;
    var rowHeight = this.props.rowHeight;
    var length = this.props.length;

    var rows = this
        .getRows(displayStart, displayEnd)
        .map((row, idx) => this.renderRow({
          key: displayStart + idx,
          idx: displayStart + idx,
          row: row,
          Active: this.props.ActiveCell.row == idx,
          ActiveCell: this.props.ActiveCell.cell,
          height: rowHeight,
          columns: this.props.columns,
          cellRenderer: this.props.cellRenderer
        }));

    if (displayStart > 0) {
      rows.unshift(this.renderPlaceholder('top', displayStart * rowHeight));
    }

    if (length - displayEnd > 0) {
      rows.push(
        this.renderPlaceholder('bottom', (length - displayEnd) * rowHeight));
    }

    return this.transferPropsTo(

          {rows}

    );
  },

  renderRow: function(props) {
    if (React.isValidComponent(this.props.rowRenderer)) {
      return cloneWithProps(this.props.rowRenderer(props), props);
    } else {
      return this.props.rowRenderer(props);
    }
  },

  renderPlaceholder: function(key, height) {
    return (

        {this.props.columns.map(
          (column, idx) =>
)}

    );
  },

  getDefaultProps: function() {
    return {rowRenderer: Row};
  },

  getInitialState: function() {
    return {
      shouldUpdate: true,
      displayStart: this.props.displayStart,
      displayEnd: this.props.displayEnd
    };
  },

  componentWillReceiveProps: function(nextProps) {
    var shouldUpdate = !(nextProps.visibleStart > this.state.displayStart
                        && nextProps.visibleEnd < this.state.displayEnd)
                        || nextProps.length !== this.props.length
                        || nextProps.rowHeight !== this.props.rowHeight
                        || nextProps.columns !== this.props.columns
                        || nextProps.width !== this.props.width
                        || !shallowEqual(nextProps.style, this.props.style);

    if (shouldUpdate) {
      this.setState({
        shouldUpdate: true,
        displayStart: nextProps.displayStart,
        displayEnd: nextProps.displayEnd
      });
    } else {
      this.setState({shouldUpdate: false});
    }
  },

  shouldComponentUpdate: function(nextProps, nextState) {
    return nextState.shouldUpdate;
  },

  onScroll: function(e) {
    this.appendScrollShim();
    if (this.props.onScroll) {
      this.props.onScroll(e);
    }
  },

  setScrollTop: function(scrollTop) {
    this.getDOMNode().scrollTop = scrollTop;
  },

  getRows: function(displayStart, displayEnd) {
    if (Array.isArray(this.props.rows)) {
      return this.props.rows.slice(displayStart, displayEnd);
    } else {
      return this.props.rows(displayStart, displayEnd);
    }
  }
});

module.exports = Canvas;
<|endoftext|>


<commit_before>/* @flow */

import type { ComposeFieldConfigMap } from 'graphql-compose';
import {
  EnumTypeComposer,
  graphql,
  schemaComposer,
  SchemaComposer,
  TypeComposer,
} from 'graphql-compose';
import type { GraphQLFieldConfigMap } from 'graphql-compose/lib/graphql';
import type {
  ComposePartialFieldConfigAsObject,
  RelationOpts,
} from 'graphql-compose/lib/TypeComposer';
import { Model } from 'mongoose';
import type { TypeConverterOpts } from './composeWithMongoose';
import { composeWithMongoose } from './composeWithMongoose';
import { composeChildTC } from './discriminators';
import { mergeCustomizationOptions } from './discriminators/merge-customization-options';
import { prepareBaseResolvers } from './discriminators/prepare-resolvers/prepareBaseResolvers';
import { reorderFields } from './discriminators/utils';

const { GraphQLInterfaceType } = graphql;

export type Options = {
  test_disTypes?: boolean,
  reorderFields?: boolean | string[], // true order: _id, DKey, DInterfaceFields, DiscriminatorFields
  customizationOptions?: TypeConverterOpts,
};

type Discriminators = {
  [DName: string]: any,
};

// sets the values on DKey enum TC
function setDKeyETCValues(discriminators: Discriminators): any {
  const values: { [propName: string]: { value: string } } = {};

  for (const DName in discriminators) {
    if (discriminators.hasOwnProperty(DName)) {
      values[DName] = {
        value: DName,
      };
    }
  }

  return values;
}

// creates an enum from discriminator names
// then sets this enum type as the discriminator key field type
function createAndSetDKeyETC(dTC: DiscriminatorTypeComposer, discriminators: Discriminators) {
  const DKeyETC = EnumTypeComposer.create({
    name: `EnumDKey${dTC.getDBaseName()}${dTC.getDKey()[0].toUpperCase() +
      dTC.getDKey().substr(1)}`,
    values: setDKeyETCValues(discriminators),
  });

  // set on Output
  dTC.extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  // set on Input
  dTC.getInputTypeComposer().extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  return DKeyETC;
}

function getBaseTCFieldsWithTypes(baseTC: TypeComposer) {
  const baseFields = baseTC.getFieldNames();
  const baseFieldsWithTypes: GraphQLFieldConfigMap<any, any> = {};

  for (const field of baseFields) {
    baseFieldsWithTypes[field] = baseTC.getFieldConfig(field);
  }

  return baseFieldsWithTypes;
}

function createDInterface(baseModelTC: DiscriminatorTypeComposer): GraphQLInterfaceType {
  return new GraphQLInterfaceType({
    name: `${baseModelTC.getDBaseName()}Interface`,

    resolveType: (value: any) => {
      const childDName = value[baseModelTC.getDKey()];
      const sComposer = baseModelTC.getGQC(); // get schemaComposer

      if (childDName) {
        return sComposer.getTC(childDName).getType();
      }

      // as fallback return BaseModelTC
      return sComposer.getTC(baseModelTC.getTypeName()).getType();
    },
    // hoisting issue solved, get at time :)
    fields: () => getBaseTCFieldsWithTypes(baseModelTC),
  });
}

export class DiscriminatorTypeComposer extends TypeComposer {
  modelName: string;

  discriminatorKey: string;

  DKeyETC: EnumTypeComposer;

  GQC: SchemaComposer<any>;

  opts: Options;

  DInterface: GraphQLInterfaceType;

  discriminators: Discriminators;

  childTCs: TypeComposer[];

  constructor(baseModel: Model, opts?: any) {
    if (!baseModel || !(baseModel: any).discriminators) {
      throw Error('Discriminator Key not Set, Use composeWithMongoose for Normal Collections');
    }

    opts = {  // eslint-disable-line
      reorderFields: true,
      customizationOptions: {
        schemaComposer,
      },
      ...opts,
    };

    super(composeWithMongoose(baseModel, opts.customizationOptions).gqType);

    // !ORDER MATTERS
    this.opts = opts;
    this.modelName = (baseModel: any).modelName;
    this.discriminatorKey = (baseModel: any).schema.get('discriminatorKey') || '__t';

    // discriminants and object containing all discriminants with key
    // key being their DNames
    this.discriminators = (baseModel: any).discriminators;

    this.childTCs = [];
    this.GQC =
      opts.customizationOptions && opts.customizationOptions.schemaComposer
        ? opts.customizationOptions.schemaComposer
        : schemaComposer;
    this.setTypeName(this.modelName);
    this.DKeyETC = createAndSetDKeyETC(this, this.discriminators);

    reorderFields(this, (this.opts: any).reorderFields, this.discriminatorKey);

    this.DInterface = createDInterface(this);
    this.setInterfaces([this.DInterface]);

    // Hoist on _disTypes
    if (opts.test_disTypes) {
      if (!this.GQC.rootQuery().hasField('_disTypes')) {
        this.GQC.rootQuery().addFields({
          _disTypes: TypeComposer.create({
            name: '_disTypes',
            description: 'Hoisting for Discriminator Types',
          }),
        });
      }

      this.GQC.rootQuery()
        .getFieldTC('_disTypes')
        .addFields({
          [this.getTypeName()]: this,
        });
    }

    // prepare Base Resolvers
    prepareBaseResolvers(this);
  }

  getGQC(): SchemaComposer<any> {
    return this.GQC;
  }

  getDKey(): string {
    return this.discriminatorKey;
  }

  getDKeyETC(): EnumTypeComposer {
    return this.DKeyETC;
  }

  getDBaseName(): string {
    return this.modelName;
  }

  getDInterface(): GraphQLInterfaceType {
    return this.DInterface;
  }

  hasChildTC(DName: string): boolean {
    return !!this.childTCs.find(ch => ch.getTypeName() === DName);
  }

  // add fields only to DInterface, baseTC, childTC
  addDFields(newDFields: ComposeFieldConfigMap<any, any>): this {
    super.addFields(newDFields);

    for (const childTC of this.childTCs) {
      childTC.addFields(newDFields);
    }

    return this;
  }

  extendDField(
    fieldName: string,
    partialFieldConfig: ComposePartialFieldConfigAsObject<any, any>
  ): this {
    super.extendField(fieldName, partialFieldConfig);

    for (const childTC of this.childTCs) {
      childTC.extendField(fieldName, partialFieldConfig);
    }

    return this;
  }

  // relations with args are a bit hard to manage as interfaces i believe as of now do not
  // support field args. Well if one wants to have use args, you setType for resolver as this
  // this = this DiscriminantTypeComposer
  // NOTE, those relations will be propagated to the childTypeComposers and you can use normally.
  // FixMe: Note, You must use this function after creating all discriminators
  addDRelation(fieldName: string, relationOpts: RelationOpts<any, any>): this {
    this.addRelation(fieldName, relationOpts);

    for (const childTC of this.childTCs) {
      childTC.addRelation(fieldName, relationOpts);
    }

    return this;
  }

  /* eslint no-use-before-define: 0 */
  discriminator(childModel: Model, opts?: TypeConverterOpts): TypeComposer {
    const customizationOpts = mergeCustomizationOptions(
      (this.opts: any).customizationOptions,
      opts
    );

    let childTC = composeWithMongoose(childModel, customizationOpts);

    childTC = composeChildTC(this, childTC, this.opts);

    this.childTCs.push(childTC);

    return childTC;
  }
}

export function composeWithMongooseDiscriminators(
  baseModel: Model,
  opts?: Options
): DiscriminatorTypeComposer {
  return new DiscriminatorTypeComposer(baseModel, opts);
}
<commit_msg>fix: remove YAGNI method getGQC(), rename GQC to schemaComposer<commit_after>/* @flow */

import type { ComposeFieldConfigMap } from 'graphql-compose';
import {
  EnumTypeComposer,
  graphql,
  schemaComposer,
  SchemaComposer,
  TypeComposer,
} from 'graphql-compose';
import type { GraphQLFieldConfigMap } from 'graphql-compose/lib/graphql';
import type {
  ComposePartialFieldConfigAsObject,
  RelationOpts,
} from 'graphql-compose/lib/TypeComposer';
import { Model } from 'mongoose';
import type { TypeConverterOpts } from './composeWithMongoose';
import { composeWithMongoose } from './composeWithMongoose';
import { composeChildTC } from './discriminators';
import { mergeCustomizationOptions } from './discriminators/merge-customization-options';
import { prepareBaseResolvers } from './discriminators/prepare-resolvers/prepareBaseResolvers';
import { reorderFields } from './discriminators/utils';

const { GraphQLInterfaceType } = graphql;

export type Options = {
  test_disTypes?: boolean,
  reorderFields?: boolean | string[], // true order: _id, DKey, DInterfaceFields, DiscriminatorFields
  customizationOptions?: TypeConverterOpts,
};

type Discriminators = {
  [DName: string]: any,
};

// sets the values on DKey enum TC
function setDKeyETCValues(discriminators: Discriminators): any {
  const values: { [propName: string]: { value: string } } = {};

  for (const DName in discriminators) {
    if (discriminators.hasOwnProperty(DName)) {
      values[DName] = {
        value: DName,
      };
    }
  }

  return values;
}

// creates an enum from discriminator names
// then sets this enum type as the discriminator key field type
function createAndSetDKeyETC(dTC: DiscriminatorTypeComposer, discriminators: Discriminators) {
  const DKeyETC = EnumTypeComposer.create({
    name: `EnumDKey${dTC.getDBaseName()}${dTC.getDKey()[0].toUpperCase() +
      dTC.getDKey().substr(1)}`,
    values: setDKeyETCValues(discriminators),
  });

  // set on Output
  dTC.extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  // set on Input
  dTC.getInputTypeComposer().extendField(dTC.getDKey(), {
    type: () => DKeyETC,
  });

  return DKeyETC;
}

function getBaseTCFieldsWithTypes(baseTC: TypeComposer) {
  const baseFields = baseTC.getFieldNames();
  const baseFieldsWithTypes: GraphQLFieldConfigMap<any, any> = {};

  for (const field of baseFields) {
    baseFieldsWithTypes[field] = baseTC.getFieldConfig(field);
  }

  return baseFieldsWithTypes;
}

function createDInterface(baseModelTC: DiscriminatorTypeComposer): GraphQLInterfaceType {
  return new GraphQLInterfaceType({
    name: `${baseModelTC.getDBaseName()}Interface`,

    resolveType: (value: any) => {
      const childDName = value[baseModelTC.getDKey()];

      if (childDName) {
        return baseModelTC.schemaComposer.getTC(childDName).getType();
      }

      // as fallback return BaseModelTC
      return baseModelTC.schemaComposer.getTC(baseModelTC.getTypeName()).getType();
    },
    // hoisting issue solved, get at time :)
    fields: () => getBaseTCFieldsWithTypes(baseModelTC),
  });
}

export class DiscriminatorTypeComposer extends TypeComposer {
  modelName: string;

  discriminatorKey: string;

  DKeyETC: EnumTypeComposer;

  schemaComposer: SchemaComposer<any>;

  opts: Options;

  DInterface: GraphQLInterfaceType;

  discriminators: Discriminators;

  childTCs: TypeComposer[];

  constructor(baseModel: Model, opts?: any) {
    if (!baseModel || !(baseModel: any).discriminators) {
      throw Error('Discriminator Key not Set, Use composeWithMongoose for Normal Collections');
    }

    opts = {  // eslint-disable-line
      reorderFields: true,
      customizationOptions: {
        schemaComposer,
      },
      ...opts,
    };

    super(composeWithMongoose(baseModel, opts.customizationOptions).gqType);

    // !ORDER MATTERS
    this.opts = opts;
    this.modelName = (baseModel: any).modelName;
    this.discriminatorKey = (baseModel: any).schema.get('discriminatorKey') || '__t';

    // discriminants and object containing all discriminants with key
    // key being their DNames
    this.discriminators = (baseModel: any).discriminators;

    this.childTCs = [];
    this.schemaComposer =
      opts.customizationOptions && opts.customizationOptions.schemaComposer
        ? opts.customizationOptions.schemaComposer
        : schemaComposer;
    this.setTypeName(this.modelName);
    this.DKeyETC = createAndSetDKeyETC(this, this.discriminators);

    reorderFields(this, (this.opts: any).reorderFields, this.discriminatorKey);

    this.DInterface = createDInterface(this);
    this.setInterfaces([this.DInterface]);

    // Hoist on _disTypes
    if (opts.test_disTypes) {
      if (!this.GQC.rootQuery().hasField('_disTypes')) {
        this.GQC.rootQuery().addFields({
          _disTypes: TypeComposer.create({
            name: '_disTypes',
            description: 'Hoisting for Discriminator Types',
          }),
        });
      }

      this.GQC.rootQuery()
        .getFieldTC('_disTypes')
        .addFields({
          [this.getTypeName()]: this,
        });
    }

    // prepare Base Resolvers
    prepareBaseResolvers(this);
  }

  getDKey(): string {
    return this.discriminatorKey;
  }

  getDKeyETC(): EnumTypeComposer {
    return this.DKeyETC;
  }

  getDBaseName(): string {
    return this.modelName;
  }

  getDInterface(): GraphQLInterfaceType {
    return this.DInterface;
  }

  hasChildTC(DName: string): boolean {
    return !!this.childTCs.find(ch => ch.getTypeName() === DName);
  }

  // add fields only to DInterface, baseTC, childTC
  addDFields(newDFields: ComposeFieldConfigMap<any, any>): this {
    super.addFields(newDFields);

    for (const childTC of this.childTCs) {
      childTC.addFields(newDFields);
    }

    return this;
  }

  extendDField(
    fieldName: string,
    partialFieldConfig: ComposePartialFieldConfigAsObject<any, any>
  ): this {
    super.extendField(fieldName, partialFieldConfig);

    for (const childTC of this.childTCs) {
      childTC.extendField(fieldName, partialFieldConfig);
    }

    return this;
  }

  // relations with args are a bit hard to manage as interfaces i believe as of now do not
  // support field args. Well if one wants to have use args, you setType for resolver as this
  // this = this DiscriminantTypeComposer
  // NOTE, those relations will be propagated to the childTypeComposers and you can use normally.
  // FixMe: Note, You must use this function after creating all discriminators
  addDRelation(fieldName: string, relationOpts: RelationOpts<any, any>): this {
    this.addRelation(fieldName, relationOpts);

    for (const childTC of this.childTCs) {
      childTC.addRelation(fieldName, relationOpts);
    }

    return this;
  }

  /* eslint no-use-before-define: 0 */
  discriminator(childModel: Model, opts?: TypeConverterOpts): TypeComposer {
    const customizationOpts = mergeCustomizationOptions(
      (this.opts: any).customizationOptions,
      opts
    );

    let childTC = composeWithMongoose(childModel, customizationOpts);

    childTC = composeChildTC(this, childTC, this.opts);

    this.childTCs.push(childTC);

    return childTC;
  }
}

export function composeWithMongooseDiscriminators(
  baseModel: Model,
  opts?: Options
): DiscriminatorTypeComposer {
  return new DiscriminatorTypeComposer(baseModel, opts);
}
<|endoftext|>


<commit_before>
function $(element) {
	if (typeof element == "string") {
		element=document.getElementById(element);
	}
	if (element)
		extend_instance(element,Element);
	return element;
}

function extend_instance(instance,hash) {
	for (var name in hash) {
		instance[name] = hash[name];
	}
}

var Element = {
	"hide": function () {
		this.setStyle("display","none")
	},
	"show": function () {
		this.setStyle("display","block")
	},
	"visible": function () {
		return (this.getStyle("display") != "none");
	},
	"toggle": function () {
		if (this.visible) {
			this.hide();
		} else {
			this.show();
		}
	}
};

function encodeURIComponent(str) {
	if (typeof(str) == "string") {
		return str.replace(/=/g,'%3D').replace(/&/g,'%26');
	}
	//checkboxes and radio buttons return objects instead of a string
	else if(typeof(str) == "object"){
		for (prop in str)
		{
			return str[prop].replace(/=/g,'%3D').replace(/&/g,'%26');
		}
	}
};

var Form = {};
Form.serialize = function(form_element) {
	elements=$(form_element).serialize();
	param_string="";
	for (var name in elements) {
		if (param_string)
			param_string += "&";
		param_string += encodeURIComponent(name)+"="+encodeURIComponent(elements[name]);
	}
	return param_string;
};

Ajax.Updater = function (container,url,options) {
  this.container = container;
	this.url=url;
	this.ajax = new Ajax();
	this.ajax.requireLogin = 1;
	if (options["onSuccess"]) {
		this.ajax.responseType = Ajax.JSON;
		this.ajax.ondone = options["onSuccess"];
	} else {
		this.ajax.responseType = Ajax.FBML;
		this.ajax.ondone = function(data) {
		  $(container).setInnerFBML(data);
		}
	}
	if (options["onFailure"]) {
		this.ajax.onerror = options["onFailure"];
	}

	// Yes, this is an excercise in undoing what we just did
	// FB doesn't provide encodeURI, but they will encode things passed as a hash
	// so we turn it into a string, esaping & and =
	// then we split it all back out here
	// this could be killed if encodeURIComponent was available
	parameters={};
	pairs=options['parameters'].split('&');
	for (var i=0; i<pairs.length; i++) {
		kv=pairs[i].split('=');
		key=kv[0].replace(/%3D/g,'=').replace(/%26/g,'&');
		val=kv[1].replace(/%3D/g,'=').replace(/%26/g,'&');
		parameters[key]=val;
	}
  this.ajax.post(url,parameters);
	if (options["onLoading"]) {
     options["onLoading"].call()
  }
};
Ajax.Request = function(url,options) {
	Ajax.Updater('unused',url,options);
};

PeriodicalExecuter = function (callback, frequency) {
        setTimeout(callback, frequency *1000);
        setTimeout(function() { new PeriodicalExecuter(callback,frequency); }, frequency*1000);
};
<commit_msg>Slight fix to Ajax.Updater so remote_function_for works (for me).<commit_after>
function $(element) {
	if (typeof element == "string") {
		element=document.getElementById(element);
	}
	if (element)
		extend_instance(element,Element);
	return element;
}

function extend_instance(instance,hash) {
	for (var name in hash) {
		instance[name] = hash[name];
	}
}

var Element = {
	"hide": function () {
		this.setStyle("display","none")
	},
	"show": function () {
		this.setStyle("display","block")
	},
	"visible": function () {
		return (this.getStyle("display") != "none");
	},
	"toggle": function () {
		if (this.visible) {
			this.hide();
		} else {
			this.show();
		}
	}
};

function encodeURIComponent(str) {
	if (typeof(str) == "string") {
		return str.replace(/=/g,'%3D').replace(/&/g,'%26');
	}
	//checkboxes and radio buttons return objects instead of a string
	else if(typeof(str) == "object"){
		for (prop in str)
		{
			return str[prop].replace(/=/g,'%3D').replace(/&/g,'%26');
		}
	}
};

var Form = {};
Form.serialize = function(form_element) {
	elements=$(form_element).serialize();
	param_string="";
	for (var name in elements) {
		if (param_string)
			param_string += "&";
		param_string += encodeURIComponent(name)+"="+encodeURIComponent(elements[name]);
	}
	return param_string;
};

Ajax.Updater = function (container,url,options) {
  this.container = container;
	this.url=url;
	this.ajax = new Ajax();
	this.ajax.requireLogin = 1;
	if (options["onSuccess"]) {
		this.ajax.responseType = Ajax.JSON;
		this.ajax.ondone = options["onSuccess"];
	} else {
		this.ajax.responseType = Ajax.FBML;
		this.ajax.ondone = function(data) {
		  $(container).setInnerFBML(data);
		}
	}
	if (options["onFailure"]) {
		this.ajax.onerror = options["onFailure"];
	}

	// Yes, this is an excercise in undoing what we just did
	// FB doesn't provide encodeURI, but they will encode things passed as a hash
	// so we turn it into a string, esaping & and =
	// then we split it all back out here
	// this could be killed if encodeURIComponent was available
	parameters={};
  if (options['parameters']) {
		pairs=options['parameters'].split('&');
		for (var i=0; i<pairs.length; i++) {
			kv=pairs[i].split('=');
			key=kv[0].replace(/%3D/g,'=').replace(/%26/g,'&');
			val=kv[1].replace(/%3D/g,'=').replace(/%26/g,'&');
			parameters[key]=val;
		}
	}
  this.ajax.post(url,parameters);
	if (options["onLoading"]) {
     options["onLoading"].call()
  }
};
Ajax.Request = function(url,options) {
	Ajax.Updater('unused',url,options);
};

PeriodicalExecuter = function (callback, frequency) {
        setTimeout(callback, frequency *1000);
        setTimeout(function() { new PeriodicalExecuter(callback,frequency); }, frequency*1000);
};
<|endoftext|>


<commit_before>import Bootstrap from './Bootstrap'
import ErrorPage from './ErrorPage'
import FrozenHead from 'react-frozenhead'
import React from 'react'
import SupportStore from '../stores/SupportStore'
import { RouteHandler } from 'react-router'
import ga from 'react-google-analytics'

ga('create', 'UA-62785624-1', 'auto');
ga('send', 'pageview');

export default class App extends React.Component {

  constructor() {
    super()
    this.state = SupportStore.getState()

    this._onChange = () => {
      this.setState(SupportStore.getState())
    }
  }

  componentDidMount() {
    SupportStore.listen(this._onChange)
  }

  componentDidUnmount() {
    SupportStore.unlisten(this._onChange)
  }

  render() {
    return
      <FrozenHead>

        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta property="og:url" content="http://file.pizza" />
        <meta property="og:title" content="FilePizza - Your files, delivered." />
        <meta property="og:description" content="Peer-to-peer file transfers in your web browser." />
        <meta property="og:image" content="http://file.pizza/images/fb.png" />
        <title>FilePizza - Your files, delivered.</title>

        <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Quicksand:300,400,700|Lobster+Two" />
        <link rel="stylesheet" href="/css" />

        <Bootstrap data={this.props.data} />

        <ga.Initializer />

  }

}
<commit_msg>Use same scheme as hosted site<commit_after>import Bootstrap from './Bootstrap'
import ErrorPage from './ErrorPage'
import FrozenHead from 'react-frozenhead'
import React from 'react'
import SupportStore from '../stores/SupportStore'
import { RouteHandler } from 'react-router'
import ga from 'react-google-analytics'

ga('create', 'UA-62785624-1', 'auto');
ga('send', 'pageview');

export default class App extends React.Component {

  constructor() {
    super()
    this.state = SupportStore.getState()

    this._onChange = () => {
      this.setState(SupportStore.getState())
    }
  }

  componentDidMount() {
    SupportStore.listen(this._onChange)
  }

  componentDidUnmount() {
    SupportStore.unlisten(this._onChange)
  }

  render() {
    return
      <FrozenHead>

        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta property="og:url" content="http://file.pizza" />
        <meta property="og:title" content="FilePizza - Your files, delivered." />
        <meta property="og:description" content="Peer-to-peer file transfers in your web browser." />
        <meta property="og:image" content="http://file.pizza/images/fb.png" />
        <title>FilePizza - Your files, delivered.</title>

        <link rel="stylesheet" href="//fonts.googleapis.com/css?family=Quicksand:300,400,700|Lobster+Two" />
        <link rel="stylesheet" href="/css" />

        <Bootstrap data={this.props.data} />

        <ga.Initializer />

  }

}
<|endoftext|>


<commit_before>import React from 'react';
import BaseGuide from '../components/BaseGuide';
import { InlineJS as IJS, PrismBlock } from '../components/PrismBlocks';
import { Link } from '@curi/react';
import { Section, Subsection } from '../components/Sections';

export default ({ name }) => (
  <BaseGuide>

{name}

      Curi aims to be easy to setup. To get started, you just need to create a Hickory
      history object and an array of route objects. Pass those as arguments to the{' '}
      <IJS>createConfig</IJS> function to create your configuration object. Then,
      use the Promise returned by <IJS>config.ready()</IJS> to wait for your
      first response to be generated and you're ready to render.

        Curi's navigation is powered by the Hickory
        {' '}package. You just need to pick which type of Hickory history object is right
        for your application.

      <PrismBlock lang='javascript'>
      {
`import Browser from '@hickory/browser';
import Hash from '@hickory/hash';
import InMemory from '@hickory/in-memory';

// Use Browser when your website has a dynamic server
const browserHistory = Browser();

// Use Hash when your website uses a static file server
const hashHistory = Hash();

// Use InMemory when your application doesn't run in a browser
const memoryHistory = InMemory();`
      }
      </PrismBlock>

        Each history object has essentially the same API (InMemory has a few extra properties).
        The most important properties to know are the location object as well as the update, push, and
        replace methods.

      <PrismBlock lang='javascript'>
        {
`// the location property is the current location object
browserHistory.location === {
  pathname: '/guides/getting-started',
  ...
};

// the push method will navigate to a new location
browserHistory.push({ pathname: '/guides/installation' });

// the replace method will replace the current location
// with the provided one
browserHistory.push({ pathname: '/guides/confirming-navigation' });

// the update method will choose whether to push or replace for you
browserHistory.update({ pathname: '/guides/getting-started' });
`
        }
      </PrismBlock>

        Routes are objects with two required properties: name and path.

        Paths can be any valid path-to-regexp
        {' '}string. It is just important that you do not begin the string with a forward slash (/).
        Forward slashes are fine anywhere else in the path. (<IJS>this/is/fine</IJS>, but {' '}
        <IJS>/this/is/not</IJS>).

        The names are used to generate URIs for you. With Curi, you never have to write a
        URI's pathname string yourself. It is required that all of your routes have unique names. This
        is because Curi generates location pathnames using route names (and params for non-static paths).

      <PrismBlock lang='javascript'>
      {
`const routes = [
  {
    name: 'Home',
    path: '', // matches the pathname /
    ...
  },
  ...
]`
        }
      </PrismBlock>

        How route matching works and the other route properties are explained more in-depth in
        the <Link to='Guide' params={{ slug: 'routes' }}>All About Routes</Link> guide.

        Once you have your Hickory history object and your routes array, you just need to
        pass them to the default export from the Curi package (which we will name{' '}
        <IJS>createConfig</IJS> here).

      <PrismBlock lang='javascript'>
        {
`import createConfig from 'curi';
import Browser from '@hickory/browser';
import routes from './routes';

const history = Browser();
const config = createConfig(history, routes);
`
        }
      </PrismBlock>

      <Subsection
        title='Other configuration options'
        id='other-configuration-options'
      >

          The <IJS>createConfig</IJS> function
          can also take an optional third argument, which is an options object. You can use this
          to pass <Link to='Guide' params={{ slug: 'addons' }}>addons</Link>,{' '}
          <Link to='Guide' params={{ slug: 'side-effects' }}>side effects</Link>, and a{' '}
          <Link to='Guide' params={{ slug: 'response-caching' }}>cache</Link> to your configuration object.

        <PrismBlock lang='javascript'>
          {
`const config = createConfig(history, routes, {
  addons: [...],
  sideEffects: [...],
  cache: cacheObject
});`
          }
        </PrismBlock>
      </Subsection>

        Whenever navigation happens, a new location object is created by Hickory. Curi uses
        that location object's pathname property to match against all of your routes. When
        it finds one that matches, it uses that route object to create a response object. You
        can subscribe to a Curi configuration object, and when a new response is created, your
        subscriber function will be called with the response.

      <PrismBlock lang='javascript'>
        {
`const config = createConfig(history, routes);
config.subscribe(response => {
  // whenever the location changes, this function is called
  // you can use this function to re-render your application
  // using the new response object
});
`
        }
      </PrismBlock>

        Responses are generated asynchronously. A Curi configuration object has a{' '}
        <IJS>ready</IJS> function that returns a Promise and will resolve once
        the initial response has been generated. You do not have to use this, but it allows
        you to delay rendering until after the first response has been generated. If you want
        to render immediately, then you will need to handle how to render when there is no
        response.

      <PrismBlock lang='javascript'>
        {
`const config = createConfig(history, routes);
// wait to render until the first response is generated
config.ready().then(response => {
  // now we can render using the first response.
});`
        }
      </PrismBlock>

        Your location-based rendering will be centered around these response objects,
        so you should be familiar with the different properties that will be available
        to you. We will get into more details about responses in the{' '}
        <Link to='Guide' params={{ slug: 'responses' }}>Rendering with Responses</Link> guide,
        but for now we will just go over how a route maps to a response.

      <PrismBlock lang='javascript'>
      {
`// if you have the following routes
const routes = [
  ...,
  {
    name: 'Album',
    path: 'photos/:albumID',
    ...,
    children: [
      {
        name: 'Photo',
        path: ':photoID',
        body: () => Photo
      }
    ]
  }
];
// when the user visits the URI /photos/6789/12345
// the following response object would be created:

{
  // The location key
  key: '1.0',

  // The location object used to generate the response.
  location: { pathname: '/photos/6789/12345', ... },

  // The value returned by the route's body function
  body: Photo,

  // The name of the best matching route
  name: 'Photo',

  // The name of ancestor routes that matched
  // part of the location's pathname
  partials: ['Album'],

  // An object containing the values parsed
  // from the pathname by path-to-regexp.
  params: { photoID: 12345, albumID: 6789 },

  // There are a few more properties as well. Please read
  // the Rendering with Responses guide to see those
}`
       }
      </PrismBlock>

Next

      Now that you know the core of how Curi works, let's take a closer look at routes with
      the <Link to='Guide' params={{ slug: 'routes' }}>All About Routes</Link> guide.

  </BaseGuide>
);
<commit_msg>(Docs) Tweak Getting started guide [ci skip]<commit_after>import React from 'react';
import BaseGuide from '../components/BaseGuide';
import { InlineJS as IJS, PrismBlock } from '../components/PrismBlocks';
import { Link } from '@curi/react';
import { Section, Subsection } from '../components/Sections';

export default ({ name }) => (
  <BaseGuide>

{name}

      Curi aims to be easy to setup. To get started, you just need to create a Hickory
      history object and an array of route objects. Pass those as arguments to the{' '}
      <IJS>createConfig</IJS> function to create your configuration object. Then,
      use the Promise returned by <IJS>config.ready()</IJS> to wait for your
      first response to be generated and you're ready to render.

        Curi's navigation is powered by the Hickory
        {' '}package. You just need to pick which type of Hickory history object is right
        for your application.

      <PrismBlock lang='javascript'>
      {
`// Use Browser when your website has a dynamic server
import Browser from '@hickory/browser';
const browserHistory = Browser();

// Use Hash when your website uses a static file server
import Hash from '@hickory/hash';
const hashHistory = Hash();

// Use InMemory when your application doesn't run in a browser
import InMemory from '@hickory/in-memory';
const memoryHistory = InMemory();`
      }
      </PrismBlock>

        Each history object has essentially the same API (InMemory has a few extra properties).
        The most important properties to know are the location object as well as the update, push, and
        replace methods.

      <PrismBlock lang='javascript'>
        {
`// the location property is the current location object
browserHistory.location === {
  pathname: '/guides/getting-started',
  ...
};

// the push method will navigate to a new location
browserHistory.push({ pathname: '/guides/installation' });

// the replace method will replace the current location
// with the provided one
browserHistory.push({ pathname: '/guides/confirming-navigation' });

// the update method will choose whether to push or replace for you
browserHistory.update({ pathname: '/guides/getting-started' });
`
        }
      </PrismBlock>

        Routes are objects with two required properties: name and path.

        Paths can be any valid path-to-regexp
        {' '}string. It is just important that you do not begin the string with a forward slash (/).
        Forward slashes are fine anywhere else in the path. (<IJS>this/is/fine</IJS>, but {' '}
        <IJS>/this/is/not</IJS>).

        The names are used to generate URIs for you. With Curi, you never have to write a
        URI's pathname string yourself. It is required that all of your routes have unique names. This
        is because Curi generates location pathnames using route names (and params for non-static paths).

      <PrismBlock lang='javascript'>
      {
`const routes = [
  {
    name: 'Home',
    path: '', // matches the pathname /
    ...
  },
  ...
]`
        }
      </PrismBlock>

        How route matching works and the other route properties are explained more in-depth in
        the <Link to='Guide' params={{ slug: 'routes' }}>All About Routes</Link> guide.

        Once you have your Hickory history object and your routes array, you just need to
        pass them to the default export from the Curi package (which we will name{' '}
        <IJS>createConfig</IJS> here).

      <PrismBlock lang='javascript'>
        {
`import createConfig from 'curi';
import Browser from '@hickory/browser';
import routes from './routes';

const history = Browser();
const config = createConfig(history, routes);
`
        }
      </PrismBlock>

      <Subsection
        title='Other configuration options'
        id='other-configuration-options'
      >

          The <IJS>createConfig</IJS> function
          can also take an optional third argument, which is an options object. You can use this
          to pass <Link to='Guide' params={{ slug: 'addons' }}>addons</Link>,{' '}
          <Link to='Guide' params={{ slug: 'side-effects' }}>side effects</Link>, and a{' '}
          <Link to='Guide' params={{ slug: 'response-caching' }}>cache</Link> to your configuration object.

        <PrismBlock lang='javascript'>
          {
`const config = createConfig(history, routes, {
  addons: [...],
  sideEffects: [...],
  cache: cacheObject
});`
          }
        </PrismBlock>
      </Subsection>

        Whenever navigation happens, a new location object is created by Hickory. Curi uses
        that location object's pathname property to match against all of your routes. When
        it finds one that matches, it uses that route object to create a response object. You
        can subscribe to a Curi configuration object, and when a new response is created, your
        subscriber function will be called with the response.

      <PrismBlock lang='javascript'>
        {
`const config = createConfig(history, routes);
config.subscribe(response => {
  // whenever the location changes, this function is called
  // you can use this function to re-render your application
  // using the new response object
});
`
        }
      </PrismBlock>

        Responses are generated asynchronously. A Curi configuration object has a{' '}
        <IJS>ready</IJS> function that returns a Promise and will resolve once
        the initial response has been generated. You do not have to use this, but it allows
        you to delay rendering until after the first response has been generated. If you want
        to render immediately, then you will need to handle how to render when there is no
        response.

      <PrismBlock lang='javascript'>
        {
`const config = createConfig(history, routes);
// wait to render until the first response is generated
config.ready().then(response => {
  // now we can render using the first response.
});`
        }
      </PrismBlock>

        Your location-based rendering will be centered around these response objects,
        so you should be familiar with the different properties that will be available
        to you. We will get into more details about responses in the{' '}
        <Link to='Guide' params={{ slug: 'responses' }}>Rendering with Responses</Link> guide,
        but for now we will just go over how a route maps to a response.

      <PrismBlock lang='javascript'>
      {
`// if you have the following routes
const routes = [
  ...,
  {
    name: 'Album',
    path: 'photos/:albumID',
    ...,
    children: [
      {
        name: 'Photo',
        path: ':photoID',
        body: () => Photo
      }
    ]
  }
];
// when the user visits the URI /photos/6789/12345
// the following response object would be created:

{
  // The location key
  key: '1.0',

  // The location object used to generate the response.
  location: { pathname: '/photos/6789/12345', ... },

  // The value returned by the route's body function
  body: Photo,

  // The name of the best matching route
  name: 'Photo',

  // The name of ancestor routes that matched
  // part of the location's pathname
  partials: ['Album'],

  // An object containing the values parsed
  // from the pathname by path-to-regexp.
  params: { photoID: 12345, albumID: 6789 },

  // There are a few more properties as well. Please read
  // the Rendering with Responses guide to see those
}`
       }
      </PrismBlock>

Next

      Now that you know the core of how Curi works, let's take a closer look at routes with
      the <Link to='Guide' params={{ slug: 'routes' }}>All About Routes</Link> guide.

  </BaseGuide>
);
<|endoftext|>


<commit_before>'use strict';

angular.module('classBrowserUHApp.offeredclass', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/offeredclass', {
        templateUrl: 'views/offeredclass/offeredclass.html',
        controller: 'OfferedClassCtrl'
    });
}])

.controller('OfferedClassCtrl', ['$scope', '$http', '$q', '$rootScope', function ($scope, $http, $q, $rootScope) {
    $scope.format = [
        'Online',
        'Face to Face',
        'Hybrid'
    ];

    $rootScope.httpService.getData('resources/terms.json').then(function(result) {
        $scope.terms = result;
    });

}]);<commit_msg>Added options for format.<commit_after>'use strict';

angular.module('classBrowserUHApp.offeredclass', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/offeredclass', {
        templateUrl: 'views/offeredclass/offeredclass.html',
        controller: 'OfferedClassCtrl'
    });
}])

.controller('OfferedClassCtrl', ['$scope', '$http', '$q', '$rootScope', function ($scope, $http, $q, $rootScope) {

    $scope.format = {
        availableOptions: [
        {formatType: 'Online', isOrNot: 'Is'},
        {formatType: 'Not Online', isOrNot: 'Not'},
        {formatType: 'Not Face to Face', isOrNot: 'Not'},
        {formatType: 'Face to Face', isOrNot: 'Is'},
        {formatType: 'Not Hybrid', isOrNot: 'Not'},
        {formatType: 'Hybrid', isOrNot: 'Is'}
    ]
    };

    $rootScope.httpService.getData('resources/terms.json').then(function(result) {
        $scope.terms = result;
    });

}]);<|endoftext|>


<commit_before>// Import
var repeat    = require('underscore.string').repeat;

// Export
module.exports = Column

/**
 * A table column description
 *
 * @param {String|null} align Alignement (see class constants)
 * @param {Integer} size  Column width (char count)
 */
function Column(align, size) {
  this.align = align
  this.size  = size
}

Column.ALIGN_LEFT    = 'left'
Column.ALIGN_RIGHT   = 'right'
Column.ALIGN_CENTER  = 'center'
Column.ALIGN_DEFAULT = 'default'

/**
 * Generate a markdown formated column
 */
Column.prototype.toMarkdown = function () {
  var out = [];
  var size = this.getSize();
  switch(this.align) {
  case 'left':
    out.push(':' + repeat('-', size + 1))
    break;
  case 'right':
    out.push(repeat('-', size + 1) + ':')
    break;
  case 'center':
    out.push(':' + repeat('-', size) + ':')
    break;
  default:
    out.push(repeat('-',size+2))
  }
  return out.join('')
}

/**
 * Set how many chars this column could contain
 *
 * @param {integer} size
 */
Column.prototype.setSize = function (size) {
  this.size = size;
}

/**
 * Set how many chars this column could contain only if size is greater than
 * current size
 *
 * @param {integer} size
 */
Column.prototype.upSizeTo = function (size) {
  this.size = this.size || 1;
  this.size = size > this.size ? size : this.size;
}

/**
 * Get the column size (always >= 1)
 */
Column.prototype.getSize = function () {
  return (!this.size || (this.size < 1)) ? 1 : this.size
}
<commit_msg>feat: Add Column.getInfos()<commit_after>// Import
var repeat    = require('underscore.string').repeat;

// Export
module.exports = Column

/**
 * A table column description
 *
 * @param {String|null} align Alignement (see class constants)
 * @param {Integer} size  Column width (char count)
 */
function Column(align, size) {
  this.align = align
  this.size  = size
}

Column.ALIGN_LEFT    = 'left'
Column.ALIGN_RIGHT   = 'right'
Column.ALIGN_CENTER  = 'center'
Column.ALIGN_DEFAULT = 'default'

/**
 * Generate a markdown formated column
 */
Column.prototype.toMarkdown = function () {
  var out = [];
  var size = this.getSize();
  switch(this.align) {
  case 'left':
    out.push(':' + repeat('-', size + 1))
    break;
  case 'right':
    out.push(repeat('-', size + 1) + ':')
    break;
  case 'center':
    out.push(':' + repeat('-', size) + ':')
    break;
  default:
    out.push(repeat('-',size+2))
  }
  return out.join('')
}

/**
 * Set how many chars this column could contain
 *
 * @param {integer} size
 */
Column.prototype.setSize = function (size) {
  this.size = size;
}

/**
 * Set how many chars this column could contain only if size is greater than
 * current size
 *
 * @param {integer} size
 */
Column.prototype.upSizeTo = function (size) {
  this.size = this.size || 1;
  this.size = size > this.size ? size : this.size;
}

/**
 * Get the column size (always >= 1)
 */
Column.prototype.getSize = function () {
  return (!this.size || (this.size < 1)) ? 1 : this.size
}

Column.prototype.getInfos = function () {
  return {
    size: this.size,
    align: this.align
  }
};
<|endoftext|>