<commit_before>/**
 * Switcher.js allows native-like page switching with ajax.
 *
 * Server identifies Switcher.js requests by "X-Requested-With: SwitchPage" HTTP header.
 * When this header is detected, you can return only updated elements. Usually there is no point
 * to track which elements was updated, but you can return very simplified page with container elements only,
 * with all layout missing. To identify which elements to replace, this script uses id attribute. All container
 * elements you want to update on page switch should contain .switcher class.
 *
 * If script fails to switch link, it uses http redirect to change page.
 *
 * This script adds following events:
 * construct        fires after page change
 * destruct        fires before page change
 * switch        fires after destruct when script understands that page switch will be successful
 */

var switcher = {};

switcher.basePath = '/';
switcher.hashChanged = false;
switcher.noPush = false;
switcher.url = false;
switcher.referrer = false;

switcher.ajaxConfig = {
    async: true, cache: false, headers: {'X-Requested-With': 'SwitchPage'}, type: 'GET', beforeSend: function () {
        loading.show();
    }, success: function (data, status, xhr) {
        try {
            var newdata = $(data);
        } catch (ignore) {
            switcher.fallback();
            return;
        }
        var a = newdata.filter('.switcher').add(newdata.find('.switcher'));
        if (!a.length) {
            switcher.fallback();
            return;
        }
        $(document).triggerHandler('destruct');
        if (!switcher.noPush) {
            if (typeof history.pushState == 'function') {
                history.pushState({url: switcher.url}, '', switcher.url);
            } else { // browser does not support pushState, use hashes
                switcher.hashChanged = true;
                window.location = switcher.basePath + '#!' + switcher.url;
            }
        }
        $(document).triggerHandler('switch');

        a.each(function (k, v) {
            try {
                $('#' + $(v).attr('id')).replaceWith(v).remove();
            } catch (ignore) {
            }
        });
        $(window).scrollTop(0);

        var title = newdata.filter('title').text();
        if (title.length) {
            document.title = title;
        } else {
            title = newdata.find('title').text();
            if (title.length) {
                document.title = title;
            }
        }
        $(document).triggerHandler('construct');
        loading.hide();
    }, error: function (xhr) {
        switcher.fallback();
    }
};

/**
 * Page switch fall back
 */
switcher.fallback = function () {
    $(document).triggerHandler('destruct');
    loading.hide();
    document.location = switcher.url;
};

/**
 * Switch page
 * @param url
 * @param noPush
 * @param data
 */
switcher.page = function (url, noPush, data) {
    // cut protocol://host part if it matches current host
    var host = window.location.protocol + "//" + window.location.host + "/";
    if (host == url.substring(0, host.length)) {
        switcher.page(url.substring(host.length - 1));
        return;
    }
    if (typeof debug != 'undefined') {
        debug.addReq('Switching page: ' + url);
    }
    switcher.noPush = noPush ? true : false;
    switcher.referrer = switcher.url;
    switcher.url = url;
    if (typeof data == 'undefined') {
        if ($('.switcher').length) {
            $.ajax(url, switcher.ajaxConfig);
        } else {
            $(document).triggerHandler('destruct');
            loading.hide();
            window.location = switcher.url;
        }
    } else {
        var conf = switcher.ajaxConfig;
        conf.type = 'POST';
        conf.data = data;
        $.ajax(url, conf);
    }
};

/**
 * Support "Back" and "Forward" browser buttons for browsers without pushState
 */
window.onhashchange = function () {
    if (switcher.hashChanged) {
        switcher.hashChanged = false;
        return;
    }
    if (document.location.hash.substring(0, 2) == '#!') {
        switcher.page(document.location.hash.substring(2), true);
    } else {
        switcher.page(document.location.href, true);
    }
};

/**
 * Support "Back" and "Forward" browser buttons
 */
window.onpopstate = function () {
    if (switcher.url && switcher.url != decodeURI(document.location.pathname) &&
        switcher.url != document.location.hash.substring(2)) {
        switcher.page(document.location.href, true);
    }
};

/**
 * Init
 */
$(document).ready(function () {
    if (document.location.hash && document.location.hash.substring(0, 2) == '#!') {
        // redirect /#!/some/page to /some/page in smart browsers
        switcher.page(document.location.hash.substring(2), true);
        if (typeof history.replaceState == 'function') {
            switcher.hashChanged = true;
            history.replaceState({url: switcher.url}, '', switcher.url);
        }
    } else if (typeof history.pushState != 'function' && document.location.hash.substring(0, 2) != '#!' &&
        content.length) {
        // redirect /some/page to /#!/some/page in stupid browsers
        switcher.page(document.location.href);
    } else {
        if (!switcher.url) {
            // remember current URL on first page load
            switcher.url = decodeURI(document.location.pathname);
        }
    }
});

$(document).on('click dblclick', 'a', function (event) {
    if ($(this).hasClass('ajaxer') || $(this).hasClass('noAjaxer')) {
        // skip link if it has class .ajaxer or .noAjaxer
        return;
    }

    var href = $(this).attr('href');
    if (href == '#') {
        // do nothing on href="#" links
        event.preventDefault();
    } else if (href && href.substring(0, 11) != 'javascript:' && href.substr(0, 1) != '#') {
        // link is not javascript and not anchor, use ajax page switching
        event.preventDefault();
        switcher.page($(this).attr('href'));
    }
});
<commit_msg>Switcher clean up and refactoring<commit_after>/**
 * Switcher.js allows native-like page switching with ajax.
 *
 * Server identifies Switcher.js requests by "X-Requested-With: SwitchPage" HTTP header.
 * When this header is detected, you can return only updated elements. Usually there is no point
 * to track which elements was updated, but you can return very simplified page with container elements only,
 * with all layout missing. To identify which elements to replace, this script uses id attribute. All container
 * elements you want to update on page switch should contain .switcher class.
 *
 * If script fails to switch link, it uses http redirect to change page.
 *
 * This script adds following events:
 * construct        fires after page change
 * destruct        fires before page change
 * switch        fires after destruct when script understands that page switch will be successful
 */

var switcher = {};

switcher.noPush = false;
switcher.url = false;
switcher.referrer = false;

switcher.ajaxConfig = {
    async: true, cache: false, headers: {'X-Requested-With': 'SwitchPage'}, type: 'GET', beforeSend: function () {
        loading.show();
    }, success: function (data, status, xhr) {
        try {
            var newdata = $(data);
        } catch (ignore) {
            switcher.fallback();
            return;
        }
        var a = newdata.filter('.switcher').add(newdata.find('.switcher'));
        if (!a.length) {
            switcher.fallback();
            return;
        }
        $(document).triggerHandler('destruct');
        if (!switcher.noPush) {
            history.pushState({url: switcher.url}, '', switcher.url);
        }
        $(document).triggerHandler('switch');

        a.each(function (k, v) {
            try {
                $('#' + $(v).attr('id')).replaceWith(v).remove();
            } catch (ignore) {
            }
        });
        $(window).scrollTop(0);

        var title = newdata.filter('title').text();
        if (title.length) {
            document.title = title;
        } else {
            title = newdata.find('title').text();
            if (title.length) {
                document.title = title;
            }
        }
        $(document).triggerHandler('construct');
        loading.hide();
    }, error: function (xhr) {
        switcher.fallback();
    }
};

/**
 * Page switch fall back
 */
switcher.fallback = function () {
    $(document).triggerHandler('destruct');
    loading.hide();
    document.location = switcher.url;
};

/**
 * Switch page
 * @param url
 * @param noPush
 * @param data
 */
switcher.page = function (url, noPush, data) {
    // cut protocol://host part if it matches current host
    var host = window.location.protocol + "//" + window.location.host + "/";
    if (host == url.substring(0, host.length)) {
        switcher.page(url.substring(host.length - 1));
        return;
    }
    if (typeof debug != 'undefined') {
        debug.addReq('Switching page: ' + url);
    }
    switcher.noPush = noPush ? true : false;
    switcher.referrer = switcher.url;
    switcher.url = url;
    if (typeof data == 'undefined') {
        if ($('.switcher').length) {
            $.ajax(url, switcher.ajaxConfig);
        } else {
            $(document).triggerHandler('destruct');
            loading.hide();
            window.location = switcher.url;
        }
    } else {
        var conf = switcher.ajaxConfig;
        conf.type = 'POST';
        conf.data = data;
        $.ajax(url, conf);
    }
};

switcher.bind = function () {
    $(document).on('click dblclick', 'a', function (event) {

        // skip .ajaxer and .noAjaxer links
        if ($(this).hasClass('ajaxer') || $(this).hasClass('noAjaxer')) {
            return;
        }

        var href = $(this).attr('href');

        // skip empty links, anchors and javascript
        if (href == '' || href == '#') {
            event.preventDefault();
            return;
        }
        if (href.substr(0, 11) == 'javascript:' || href.substr(0, 1) == '#') {
            return;
        }

        event.preventDefault();
        switcher.page(href);
    });
    $(window).on('popstate', switcher.onpopstate);
};

/**
 * Support "Back" and "Forward" browser buttons
 */
switcher.onpopstate = function () {
    if (switcher.url && switcher.url != decodeURI(document.location.pathname)) {
        switcher.page(document.location.href, true);
    }
};

switcher.init = function () {
    // if there are no switcher elements, don't init
    if (!$('.switcher:not(#debug)').length) {
        return;
    }
    // remember current URL on first page load
    if (!switcher.url) {
        switcher.url = decodeURI(document.location.pathname);
    }
    // binds
    switcher.bind();
};

$(document).ready(switcher.init);
<|endoftext|>


<commit_before>/* global VERSION */
import React, {PropTypes} from 'react'

import Notifications from 'shared/components/Notifications'

const Login = ({authData: {auth}}) => {
  if (auth.isAuthLoading) {
    return

  }

  return (

      <Notifications />

Chronograf

{VERSION} / Time-Series Data Visualization

          {auth.links.map(({name, login, label}) => (

              <span className={`icon ${name}`}>
              Login with {label}

          ))}

Made by InfluxData

  )
}

const {
  array,
  bool,
  shape,
  string,
} = PropTypes

Login.propTypes = {
  authData: shape({
    me: shape(),
    links: array,
    isLoading: bool,
  }),
  location: shape({
    pathname: string,
  }),
}

export default Login
<commit_msg>Add guard against empty auth state in Login render<commit_after>/* global VERSION */
import React, {PropTypes} from 'react'

import Notifications from 'shared/components/Notifications'

const Login = ({authData: {auth}}) => {
  if (auth.isAuthLoading) {
    return

  }

  return (

      <Notifications />

Chronograf

{VERSION} / Time-Series Data Visualization

          {auth.links && auth.links.map(({name, login, label}) => (

              <span className={`icon ${name}`}>
              Login with {label}

          ))}

Made by InfluxData

  )
}

const {
  array,
  bool,
  shape,
  string,
} = PropTypes

Login.propTypes = {
  authData: shape({
    me: shape(),
    links: array,
    isLoading: bool,
  }),
  location: shape({
    pathname: string,
  }),
}

export default Login
<|endoftext|>


<commit_before>import React, {
    Component
} from 'react';

import Svg, {
    G,
    Circle,
    Line,
    Rect,
    Text,
    Use
} from 'react-native-svg';

class GExample extends Component{
    static title = 'G children props inherit';

    constructor() {
        super(...arguments);
        this.state = {
            fill: 'purple'
        };
    }

    componentDidMount = () => {
        setTimeout(() => {
            this.setState({
                fill: '#856'
            });
        }, 2000);
    };

    render() {
        return <Svg
            height="100"
            width="100"
        >
            <G
                fill={this.state.fill}
                stroke="pink"
                strokeWidth="3"
            >
                <G>
                    <Circle
                        cx="25"
                        cy="25"
                        r="11"
                    />
                </G>
                <Circle
                    cx="25"
                    cy="75"
                    r="11"
                    stroke="red"
                />
                <Circle
                    cx="50"
                    cy="50"
                    r="11"
                    fill="green"
                />
                <Circle
                    cx="75"
                    cy="25"
                    r="11"
                    stroke="red"
                />
                <Circle
                    cx="75"
                    cy="75"
                    r="11"
                />
            </G>
        </Svg>;
    }
}

class GTransform extends Component{
    static title = 'G transform';
    render() {
        return <Svg
            height="100"
            width="200"
        >
            <G
                rotate="50"
                origin="40, 30"
                id="group"
            >
                <Line
                    x1="60"
                    y1="10"
                    x2="140"
                    y2="10"
                    stroke="#060"
                />

                <Rect
                    x="60"
                    y="20"
                    height="50"
                    width="80"
                    stroke="#060"
                    fill="#060"
                />

                <Text
                    x="100"
                    y="75"
                    stroke="#600"
                    fill="#600"
                    textAnchor="middle"
                >
                    Text grouped with shapes</Text>
            </G>
            <Use href="#group" x="5" y="40" rotate="-50" scale="0.75" stroke="red" opacity="0.5" />
        </Svg>;
    }
}

const icon = <Svg
    height="20"
    width="20"
>
    <G
        fill="purple"
        stroke="pink"
        strokeWidth="1"
    >
        <Circle
            cx="5"
            cy="5"
            r="3"
        />
        <Circle
            cx="5"
            cy="15"
            r="3"
        />
        <Circle
            cx="10"
            cy="10"
            fill="green"
            r="3"
        />
        <Circle
            cx="15"
            cy="5"
            r="3"
        />
        <Circle
            cx="15"
            cy="15"
            r="3"
        />
    </G>
</Svg>;

const samples = [GExample, GTransform];

export {
    icon,
    samples
};
<commit_msg>never setState after component is unmounted<commit_after>import React, {
    Component
} from 'react';

import Svg, {
    G,
    Circle,
    Line,
    Rect,
    Text,
    Use
} from 'react-native-svg';

class GExample extends Component{
    static title = 'G children props inherit';

    constructor() {
        super(...arguments);
        this.state = {
            fill: 'purple'
        };
    }

    componentDidMount = () => {
        setTimeout(() => {
            if (!this._unmounted) {
                this.setState({
                    fill: '#856'
                });
            }
        }, 2000);
    };

    componentWillUnmount = () => {
        this._unmounted = true;
    };

    render() {
        return <Svg
            height="100"
            width="100"
        >
            <G
                fill={this.state.fill}
                stroke="pink"
                strokeWidth="3"
            >
                <G>
                    <Circle
                        cx="25"
                        cy="25"
                        r="11"
                    />
                </G>
                <Circle
                    cx="25"
                    cy="75"
                    r="11"
                    stroke="red"
                />
                <Circle
                    cx="50"
                    cy="50"
                    r="11"
                    fill="green"
                />
                <Circle
                    cx="75"
                    cy="25"
                    r="11"
                    stroke="red"
                />
                <Circle
                    cx="75"
                    cy="75"
                    r="11"
                />
            </G>
        </Svg>;
    }
}

class GTransform extends Component{
    static title = 'G transform';
    render() {
        return <Svg
            height="100"
            width="200"
        >
            <G
                rotate="50"
                origin="40, 30"
                id="group"
            >
                <Line
                    x1="60"
                    y1="10"
                    x2="140"
                    y2="10"
                    stroke="#060"
                />

                <Rect
                    x="60"
                    y="20"
                    height="50"
                    width="80"
                    stroke="#060"
                    fill="#060"
                />

                <Text
                    x="100"
                    y="75"
                    stroke="#600"
                    fill="#600"
                    textAnchor="middle"
                >
                    Text grouped with shapes</Text>
            </G>
            <Use href="#group" x="5" y="40" rotate="-50" scale="0.75" stroke="red" opacity="0.5" />
        </Svg>;
    }
}

const icon = <Svg
    height="20"
    width="20"
>
    <G
        fill="purple"
        stroke="pink"
        strokeWidth="1"
    >
        <Circle
            cx="5"
            cy="5"
            r="3"
        />
        <Circle
            cx="5"
            cy="15"
            r="3"
        />
        <Circle
            cx="10"
            cy="10"
            fill="green"
            r="3"
        />
        <Circle
            cx="15"
            cy="5"
            r="3"
        />
        <Circle
            cx="15"
            cy="15"
            r="3"
        />
    </G>
</Svg>;

const samples = [GExample, GTransform];

export {
    icon,
    samples
};
<|endoftext|>


<commit_before>require.config({
	paths: {
		"goo": "../../../src/goo"
	}
});

require([
	'goo/entities/GooRunner',
	'goo/entities/World',
	'goo/renderer/Material',
	'goo/renderer/shaders/ShaderLib',
	'goo/renderer/Camera',
	'goo/shapes/ShapeCreator',
	'goo/entities/components/CameraComponent',
	'goo/scripts/OrbitCamControlScript',
	'goo/entities/EntityUtils',
	'goo/entities/components/ScriptComponent',
	'goo/renderer/MeshData',
	'goo/entities/components/MeshRendererComponent',
	'goo/math/Vector3',
	'goo/renderer/light/PointLight',
	'goo/entities/components/LightComponent',
	'goo/entities/components/CameraDebugComponent',
	'goo/entities/EventHandler'
], function (
	GooRunner,
	World,
	Material,
	ShaderLib,
	Camera,
	ShapeCreator,
	CameraComponent,
	OrbitCamControlScript,
	EntityUtils,
	ScriptComponent,
	MeshData,
	MeshRendererComponent,
	Vector3,
	PointLight,
	LightComponent,
	CameraDebugComponent,
	EventHandler
	) {
	'use strict';

	var cameraState = {
		spin: true,
		angle: 0,
		mainCameraId: 1
	};

	function setMainCamera(id, cameraEntities) {
		var mainCamera = cameraEntities[id].getComponent('CameraComponent').camera;
		EventHandler.dispatch("setCurrentCamera", mainCamera);
	}

	function frustumViewerDemo(goo) {
		// add spheres to have the cameras view them
		var sphereMeshData = ShapeCreator.createSphere(32, 32);

		var nSpheres = 15;
		for(var i = 0; i < nSpheres; i++) {
			for(var j = 0; j < nSpheres; j++) {
				var sphereMaterial = Material.createMaterial(ShaderLib.simpleColored, 'SphereMaterial' + i + '_' + j);
				sphereMaterial.uniforms.color = [i / nSpheres, j / nSpheres, 0.3];
				var sphereEntity = EntityUtils.createTypicalEntity(goo.world, sphereMeshData, sphereMaterial);
				sphereEntity.transformComponent.transform.translation.set(i - nSpheres/2, j - nSpheres/2, 0);
				sphereEntity.addToWorld();
			}
		}

		// add light
		var light = new PointLight();
		var lightEntity = goo.world.createEntity('light');
		lightEntity.setComponent(new LightComponent(light));
		lightEntity.transformComponent.transform.translation.set(100, 100, 100);
		lightEntity.addToWorld();

		document.body.addEventListener('keypress', function(e) {
			switch(e.keyCode) {
				case 49:
					if(cameraState.mainCameraId === 1) {
						setMainCamera(0, [camera1Entity, camera2Entity]);
						cameraState.mainCameraId = 0;
					}
					break;
				case 50:
					if(cameraState.mainCameraId === 0) {
						setMainCamera(1, [camera1Entity, camera2Entity]);
						cameraState.mainCameraId = 1;
					}
					break;
				case 51:
					cameraState.spin = !cameraState.spin;
					break;
				default:
					console.log('Keys 1, 2 switch main camera; key 3 starts/stops the spinning of camera 1');
			}
		});

		// camera 1 - spinning
		var camera1 = new Camera(45, 1, 1, 1000);
		var camera1Entity = goo.world.createEntity("CameraEntity");
		camera1Entity.transformComponent.transform.translation.set(0, 0, 3);
		camera1Entity.transformComponent.transform.lookAt(new Vector3(0, 0, 0), Vector3.UNIT_Y);
		camera1Entity.setComponent(new CameraComponent(camera1));
		camera1Entity.addToWorld();

		camera1Entity.setComponent(new ScriptComponent({
			run: function (entity) {
				if(cameraState.spin) {
					cameraState.angle += 0.01;
					entity.transformComponent.transform.setRotationXYZ(
						cameraState.angle,
						0,
						0);
					entity.transformComponent.setUpdated();
					/*
					entity.cameraComponent.camera.setFrustumPerspective(
						(Math.cos(cameraState.angle) * 0.5 + 0.5) * 70 + 10,
						1,
						1,
						1000
					); */
				}
			}
		}));

		// camera 2 - main, with orbit cam control script
		var camera2 = new Camera(45, 1, 1, 1000);
		var camera2Entity = goo.world.createEntity("CameraEntity");
		camera2Entity.transformComponent.transform.translation.set(0, 0, 3);
		camera2Entity.transformComponent.transform.lookAt(new Vector3(0, 0, 0), Vector3.UNIT_Y);
		var camera2Component = new CameraComponent(camera2);
		camera2Component.isMain = true;
		camera2Entity.setComponent(camera2Component);
		camera2Entity.addToWorld();
		var scripts = new ScriptComponent();
		scripts.scripts.push(new OrbitCamControlScript({
			domElement : goo.renderer.domElement,
			spherical : new Vector3(25, Math.PI / 4, 0)
		}));
		camera2Entity.setComponent(scripts);

		// attach camera debug components
		camera1Entity.setComponent(new CameraDebugComponent());
		camera2Entity.setComponent(new CameraDebugComponent());
	}

	function init() {
		var goo = new GooRunner();
		goo.renderer.domElement.id = 'goo';
		document.body.appendChild(goo.renderer.domElement);

		frustumViewerDemo(goo);
	}

	init();
});
<commit_msg>#335 Added test for removal of CameraDebugComponent<commit_after>require.config({
	paths: {
		"goo": "../../../src/goo"
	}
});

require([
	'goo/entities/GooRunner',
	'goo/entities/World',
	'goo/renderer/Material',
	'goo/renderer/shaders/ShaderLib',
	'goo/renderer/Camera',
	'goo/shapes/ShapeCreator',
	'goo/entities/components/CameraComponent',
	'goo/scripts/OrbitCamControlScript',
	'goo/entities/EntityUtils',
	'goo/entities/components/ScriptComponent',
	'goo/renderer/MeshData',
	'goo/entities/components/MeshRendererComponent',
	'goo/math/Vector3',
	'goo/renderer/light/PointLight',
	'goo/entities/components/LightComponent',
	'goo/entities/components/CameraDebugComponent',
	'goo/entities/EventHandler'
], function (
	GooRunner,
	World,
	Material,
	ShaderLib,
	Camera,
	ShapeCreator,
	CameraComponent,
	OrbitCamControlScript,
	EntityUtils,
	ScriptComponent,
	MeshData,
	MeshRendererComponent,
	Vector3,
	PointLight,
	LightComponent,
	CameraDebugComponent,
	EventHandler
	) {
	'use strict';

	var cameraState = {
		spin: true,
		angle: 0,
		mainCameraId: 1
	};

	function setMainCamera(id, cameraEntities) {
		var mainCamera = cameraEntities[id].getComponent('CameraComponent').camera;
		EventHandler.dispatch("setCurrentCamera", mainCamera);
	}

	function frustumViewerDemo(goo) {
		// add spheres to have the cameras view them
		var sphereMeshData = ShapeCreator.createSphere(32, 32);

		var nSpheres = 15;
		for(var i = 0; i < nSpheres; i++) {
			for(var j = 0; j < nSpheres; j++) {
				var sphereMaterial = Material.createMaterial(ShaderLib.simpleColored, 'SphereMaterial' + i + '_' + j);
				sphereMaterial.uniforms.color = [i / nSpheres, j / nSpheres, 0.3];
				var sphereEntity = EntityUtils.createTypicalEntity(goo.world, sphereMeshData, sphereMaterial);
				sphereEntity.transformComponent.transform.translation.set(i - nSpheres/2, j - nSpheres/2, 0);
				sphereEntity.addToWorld();
			}
		}

		// add light
		var light = new PointLight();
		var lightEntity = goo.world.createEntity('light');
		lightEntity.setComponent(new LightComponent(light));
		lightEntity.transformComponent.transform.translation.set(100, 100, 100);
		lightEntity.addToWorld();

		document.body.addEventListener('keypress', function(e) {
			switch(e.keyCode) {
				case 49:
					if(cameraState.mainCameraId === 1) {
						setMainCamera(0, [camera1Entity, camera2Entity]);
						cameraState.mainCameraId = 0;
					}
					break;
				case 50:
					if(cameraState.mainCameraId === 0) {
						setMainCamera(1, [camera1Entity, camera2Entity]);
						cameraState.mainCameraId = 1;
					}
					break;
				case 51:
					cameraState.spin = !cameraState.spin;
					break;
				case 52:
					if(camera1Entity.hasComponent('CameraDebugComponent')) {
						camera1Entity.clearComponent('CameraDebugComponent');
					}
					else {
						camera1Entity.setComponent(new CameraDebugComponent());
					}
					break;
				default:
					console.log('Keys 1, 2 switch main camera\nkey 3 starts/stops the spinning of camera 1\nkey 4 adds/removes camera debug component on camera 1');
			}
		});

		// camera 1 - spinning
		var camera1 = new Camera(45, 1, 1, 1000);
		var camera1Entity = goo.world.createEntity("CameraEntity");
		camera1Entity.transformComponent.transform.translation.set(0, 0, 3);
		camera1Entity.transformComponent.transform.lookAt(new Vector3(0, 0, 0), Vector3.UNIT_Y);
		camera1Entity.setComponent(new CameraComponent(camera1));
		camera1Entity.addToWorld();

		camera1Entity.setComponent(new ScriptComponent({
			run: function (entity) {
				if(cameraState.spin) {
					cameraState.angle += 0.01;
					entity.transformComponent.transform.setRotationXYZ(
						cameraState.angle,
						0,
						0);
					entity.transformComponent.setUpdated();
					/*
					entity.cameraComponent.camera.setFrustumPerspective(
						(Math.cos(cameraState.angle) * 0.5 + 0.5) * 70 + 10,
						1,
						1,
						1000
					); */
				}
			}
		}));

		// camera 2 - main, with orbit cam control script
		var camera2 = new Camera(45, 1, 1, 1000);
		var camera2Entity = goo.world.createEntity("CameraEntity");
		camera2Entity.transformComponent.transform.translation.set(0, 0, 3);
		camera2Entity.transformComponent.transform.lookAt(new Vector3(0, 0, 0), Vector3.UNIT_Y);
		var camera2Component = new CameraComponent(camera2);
		camera2Component.isMain = true;
		camera2Entity.setComponent(camera2Component);
		camera2Entity.addToWorld();
		var scripts = new ScriptComponent();
		scripts.scripts.push(new OrbitCamControlScript({
			domElement : goo.renderer.domElement,
			spherical : new Vector3(25, Math.PI / 4, 0)
		}));
		camera2Entity.setComponent(scripts);

		// attach camera debug components
		camera1Entity.setComponent(new CameraDebugComponent());
		camera2Entity.setComponent(new CameraDebugComponent());
	}

	function init() {
		var goo = new GooRunner();
		goo.renderer.domElement.id = 'goo';
		document.body.appendChild(goo.renderer.domElement);

		frustumViewerDemo(goo);
	}

	init();
});
<|endoftext|>


<commit_before>/**
 * Created by ksinger on 24.08.2015.
 */
import angular from "angular";
import ngAnimate from "angular-animate";

import "ng-redux";
import labelledHrModule from "./labelled-hr.js";
import imageDropzoneModule from "./image-dropzone.js";
import matchingContextModule from "./details/matching-context-picker.js"; // TODO: should be renamed
import createIsseeksModule from "./create-isseeks.js";
import { postTitleCharacterLimit } from "config";
import {
  get,
  getIn,
  attach,
  //  deepFreeze,
  delay,
} from "../utils.js";
import { actionCreators } from "../actions/actions.js";
import won from "../won-es6.js";
import { connect2Redux } from "../won-utils.js";
import { selectIsConnected } from "../selectors.js";

// TODO: these should be replaced by importing defintions from config
import descriptionPickerModule from "./details/description-picker.js";
import locationPickerModule from "./details/location-picker.js";
import personPickerModule from "./details/person-picker.js";
import routePickerModule from "./details/route-picker.js";
import tagsPickerModule from "./details/tags-picker.js";
import ttlPickerModule from "./details/ttl-picker.js";

const postTypeTexts = [
  {
    type: won.WON.BasicNeedTypeDemand,
    text: "I'm looking for",
    helpText:
      "Select this if you are looking for things or services other people offer",
  },
  {
    type: won.WON.BasicNeedTypeSupply,
    text: "I'm offering",
    helpText:
      "Use this if you are offering an item or a service. You will find people who said" +
      " that they're looking for something.",
  },
  {
    type: won.WON.BasicNeedTypeDotogether,
    text: "I want to find someone to",
    helpText:
      "Select this if you are looking to find other people who share your interest. You will be matched" +
      " with other people who chose this option as well.",
  },
  {
    type: won.WON.BasicNeedTypeCombined,
    text: "I'm offering and looking for",
    helpText:
      "Select this if you are looking for things or services other people offer + Use this if you are offering an item or a service. You will find people who said" +
      " that they're looking for something.",
  },
];

//TODO can't inject $scope with the angular2-router, preventing redux-cleanup
const serviceDependencies = [
  "$ngRedux",
  "$scope",
  "$element" /*'$routeParams' /*injections as strings here*/,
];

//All deatils, except tags, because tags are saved in an array
// const keySet = deepFreeze(
//   new Set([
//     "description",
//     "location",
//     "matchingContext",
//     "thumbnail",
//     "travelAction",
//     "ttl",
//   ])
// );

function genComponentConf() {
  const template = `

                <svg style="--local-primary:var(--won-primary-color);"
                    class="cp__header__back__icon">
                    <use xlink:href="#ico36_backarrow" href="#ico36_backarrow"></use>
                </svg>

            Post
            Search

            <won-create-isseeks
                ng-if="self.isPost"
                is-or-seeks="::'Description'"
                on-update="::self.updateDraft(draft, 'is')"
                on-scroll="::self.scrollToBottom(element)">
            </won-create-isseeks>
            <won-create-isseeks
                ng-if="self.isSearch"
                is-or-seeks="::'Search'"
                on-update="::self.updateDraft(draft, 'seeks')"
                on-scroll="::self.scrollToBottom(element)">
            </won-create-isseeks>

                    Tune Matching Behaviour
                    <svg class="cp__content__tuning__title__carret" ng-show="!self.showTuningOptions">
                        <use xlink:href="#ico16_arrow_down" href="#ico16_arrow_down"></use>
                    </svg>
                    <svg class="cp__content__tuning__title__carret" ng-show="self.showTuningOptions">
                        <use xlink:href="#ico16_arrow_up" href="#ico16_arrow_up"></use>
                    </svg>

                    <won-matching-context-picker
                      ng-if="self.showTuningOptions"
                      default-matching-context="::self.defaultMatchingContext"
                      initial-matching-context="::self.draftObject.matchingContext"
                      on-matching-context-updated="::self.updateMatchingContext(matchingContext)">
                    </won-matching-context-picker>

            <won-labelled-hr label="::'done?'" class="cp__content__labelledhr show-in-responsive"></won-labelled-hr>
            <button type="submit" class="won-button--filled red cp__content__publish show-in-responsive"
                    ng-disabled="!self.isValid()"
                    ng-click="::self.publish()">

                    Publish

                    Publishing …

            </button>

            <won-labelled-hr label="::'done?'" class="cp__footer__labelledhr"></won-labelled-hr>
            <button type="submit" class="won-button--filled red cp__footer__publish"
                    ng-disabled="!self.isValid()"
                    ng-click="::self.publish()">

                    Publish

                    Publishing …

            </button>

    `;

  class Controller {
    constructor(/* arguments <- serviceDependencies */) {
      attach(this, serviceDependencies, arguments);

      this.SEARCH = "search";
      this.POST = "post";

      this.focusedElement = null;
      //TODO debug; deleteme
      window.cnc4dbg = this;

      this.postTypeTexts = postTypeTexts;
      this.characterLimit = postTitleCharacterLimit;
      this.draftIs = {
        title: undefined,
        type: postTypeTexts[3].type, // TODO: do we use this information anywhere?
        // description: undefined,
        // tags: undefined,
        // person: undefined,
        // location: undefined,
        // travelAction: undefined,
        // thumbnail: undefined,
      };
      this.draftSeeks = {
        title: undefined,
        type: postTypeTexts[3].type,
        // description: undefined,
        // tags: undefined,
        // person: undefined,
        // location: undefined,
        // travelAction: undefined,
        // thumbnail: undefined,
      };

      this.windowHeight = window.screen.height;
      this.scrollContainer().addEventListener("scroll", e => this.onResize(e));
      this.draftObject = {
        is: this.draftIs,
        seeks: this.draftSeeks,
        matchingContext: undefined,
      };

      this.showTuningOptions = false;

      this.pendingPublishing = false;
      this.details = { is: [], seeks: [] };
      this.isNew = true;

      const selectFromState = state => {
        const showCreateView = getIn(state, [
          "router",
          "currentParams",
          "showCreateView",
        ]);
        const isSearch = showCreateView === this.SEARCH;
        const isPost = showCreateView && !isSearch;

        // needed to be able to reset matching context to default
        // TODO: is there an easier way to do this?
        const defaultMatchingContextList = getIn(state, [
          "config",
          "theme",
          "defaultContext",
        ]);
        const defaultMatchingContext = defaultMatchingContextList
          ? defaultMatchingContextList.toJS()
          : [];

        return {
          connectionHasBeenLost: !selectIsConnected(state),
          showCreateView,
          isSearch,
          isPost,
          defaultMatchingContext: defaultMatchingContext,
        };
      };

      // TODO: think about how to deal with contexts predefined in usecases
      delay(0).then(() =>
        this.updateMatchingContext(this.defaultMatchingContext)
      );

      // Using actionCreators like this means that every action defined there is available in the template.
      connect2Redux(selectFromState, actionCreators, [], this);
    }

    onResize() {
      //TODO: delete
      //console.log("ResizeEvent: ", window.screen.height);
      if (this.focusedElement) {
        if (this.windowHeight < window.screen.height) {
          this.windowHeight < window.screen.height;
          this.scrollToBottom(this.focusedElement);
        } else {
          this.windowHeight = window.screen.height;
        }
      }
    }

    scrollToBottom(element) {
      this._programmaticallyScrolling = true;

      if (element) {
        let heightHeader =
          this.$element[0].querySelector(".cp__header").offsetHeight + 10;
        let scrollTop = this.$element[0].querySelector(element).offsetTop;
        this.scrollContainer().scrollTop = scrollTop - heightHeader;

        this.focusedElement = element;
        //TODO: debug: delete me
        //console.log("ScrollTop: ", this.scrollContainer().scrollTop);
      }
    }

    scrollContainer() {
      if (!this._scrollContainer) {
        this._scrollContainer = this.$element[0].querySelector(".cp__content");
      }
      return this._scrollContainer;
    }

    toggleTuningOptions() {
      // if (!this.showTuningOptions) {
      //   this.onScroll({ element: ".cis__addDetail__header.b" });
      // }
      this.showTuningOptions = !this.showTuningOptions;
    }

    isValid() {
      const draft = this.draftObject;
      const hasContent = get(draft, "is") || get(draft, "seeks");
      const title =
        getIn(draft, ["is", "title"]) || getIn(draft, ["seeks", "title"]);
      const hasValidTitle = title && title.length < this.characterLimit;
      const hasTTL =
        getIn(draft, ["is", "ttl"]) || getIn(draft, ["seeks", "ttl"]);
      return (
        !this.connectionHasBeenLost && hasContent && (hasValidTitle || hasTTL)
      );
    }

    updateMatchingContext(matchingContext) {
      // also accepts []!
      if (matchingContext) {
        this.draftObject.matchingContext = matchingContext;
      } else {
        this.draftObject.matchingContext = undefined;
      }
    }

    updateDraft(updatedDraft, isSeeks) {
      if (this.isNew) {
        this.isNew = false;
      }

      this.draftObject[isSeeks] = updatedDraft;
    }

    publish() {
      // Post both needs
      if (!this.pendingPublishing) {
        this.pendingPublishing = true;

        // TODO: This should be a usecase/done via a different component
        // Check if this is a search
        const searchString = this.checkForSearchString(this.draftObject);
        if (searchString) {
          this.draftObject.searchString = searchString;
          //delete this.draftObject.is;
        }

        const draft = this.getPublishObject(this.draftObject);

        this.needs__create(
          draft,
          this.$ngRedux.getState().getIn(["config", "defaultNodeUri"])
        );
      }
    }

    getPublishObject(draft) {
      if (!this.isOrSeeksIsValid(draft.is)) {
        delete draft.is;
      }
      if (!this.isOrSeeksIsValid(draft.seeks)) {
        delete draft.seeks;
      }
      return draft;
    }

    // returns true if the part has a valid title or any other detail
    isOrSeeksIsValid(isOrSeeks) {
      // TODO: title should be either in the root part of the need or in a detail-picker
      const title = get(isOrSeeks, "title");
      const hasValidTitle = title && title.length < this.characterLimit;

      let hasDetail = false;
      const details = Object.keys(isOrSeeks);
      for (let d of details) {
        if (details[d] && d !== "type") {
          hasDetail = true;
        }
      }
      //const hasTTL = get(isOrSeeks, "ttl");
      return !!(hasValidTitle || hasDetail);
    }

    checkForSearchString(draft) {
      // draft has an is part -> not a pure search
      if (this.isOrSeeksIsValid(draft.is)) {
        return undefined;
      }

      // draft has no valid seeks part -> not a pure search
      if (!draft.seeks || !draft.seeks.title) {
        return undefined;
      }

      for (let detail of Object.keys(draft.seeks)) {
        if (detail !== "title" && detail !== "type" && draft.seeks[detail]) {
          return undefined;
        }
      }

      return draft.seeks.title;
    }

    createWhatsNew() {
      if (!this.pendingPublishing) {
        this.pendingPublishing = true;
        this.needs__whatsNew();
      }
    }
  }

  Controller.$inject = serviceDependencies;

  return {
    restrict: "E",
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    scope: {
      /*scope-isolation*/
    },
    template: template,
  };
}

export default //.controller('CreateNeedController', [...serviceDependencies, CreateNeedController])
angular
  .module("won.owner.components.createPost", [
    labelledHrModule,
    imageDropzoneModule,
    descriptionPickerModule,
    locationPickerModule,
    personPickerModule,
    routePickerModule,
    tagsPickerModule,
    ttlPickerModule,
    createIsseeksModule,
    matchingContextModule,
    ngAnimate,
  ])
  .directive("wonCreatePost", genComponentConf).name;
<commit_msg>Enable Publish button when enough information was entered.<commit_after>/**
 * Created by ksinger on 24.08.2015.
 */
import angular from "angular";
import ngAnimate from "angular-animate";

import "ng-redux";
import labelledHrModule from "./labelled-hr.js";
import imageDropzoneModule from "./image-dropzone.js";
import matchingContextModule from "./details/matching-context-picker.js"; // TODO: should be renamed
import createIsseeksModule from "./create-isseeks.js";
import { postTitleCharacterLimit } from "config";
import {
  get,
  getIn,
  attach,
  //  deepFreeze,
  delay,
} from "../utils.js";
import { actionCreators } from "../actions/actions.js";
import won from "../won-es6.js";
import { connect2Redux } from "../won-utils.js";
import { selectIsConnected } from "../selectors.js";

// TODO: these should be replaced by importing defintions from config
import descriptionPickerModule from "./details/description-picker.js";
import locationPickerModule from "./details/location-picker.js";
import personPickerModule from "./details/person-picker.js";
import routePickerModule from "./details/route-picker.js";
import tagsPickerModule from "./details/tags-picker.js";
import ttlPickerModule from "./details/ttl-picker.js";

const postTypeTexts = [
  {
    type: won.WON.BasicNeedTypeDemand,
    text: "I'm looking for",
    helpText:
      "Select this if you are looking for things or services other people offer",
  },
  {
    type: won.WON.BasicNeedTypeSupply,
    text: "I'm offering",
    helpText:
      "Use this if you are offering an item or a service. You will find people who said" +
      " that they're looking for something.",
  },
  {
    type: won.WON.BasicNeedTypeDotogether,
    text: "I want to find someone to",
    helpText:
      "Select this if you are looking to find other people who share your interest. You will be matched" +
      " with other people who chose this option as well.",
  },
  {
    type: won.WON.BasicNeedTypeCombined,
    text: "I'm offering and looking for",
    helpText:
      "Select this if you are looking for things or services other people offer + Use this if you are offering an item or a service. You will find people who said" +
      " that they're looking for something.",
  },
];

//TODO can't inject $scope with the angular2-router, preventing redux-cleanup
const serviceDependencies = [
  "$ngRedux",
  "$scope",
  "$element" /*'$routeParams' /*injections as strings here*/,
];

//All deatils, except tags, because tags are saved in an array
// const keySet = deepFreeze(
//   new Set([
//     "description",
//     "location",
//     "matchingContext",
//     "thumbnail",
//     "travelAction",
//     "ttl",
//   ])
// );

function genComponentConf() {
  const template = `

                <svg style="--local-primary:var(--won-primary-color);"
                    class="cp__header__back__icon">
                    <use xlink:href="#ico36_backarrow" href="#ico36_backarrow"></use>
                </svg>

            Post
            Search

            <won-create-isseeks
                ng-if="self.isPost"
                is-or-seeks="::'Description'"
                on-update="::self.updateDraft(draft, 'is')"
                on-scroll="::self.scrollToBottom(element)">
            </won-create-isseeks>
            <won-create-isseeks
                ng-if="self.isSearch"
                is-or-seeks="::'Search'"
                on-update="::self.updateDraft(draft, 'seeks')"
                on-scroll="::self.scrollToBottom(element)">
            </won-create-isseeks>

                    Tune Matching Behaviour
                    <svg class="cp__content__tuning__title__carret" ng-show="!self.showTuningOptions">
                        <use xlink:href="#ico16_arrow_down" href="#ico16_arrow_down"></use>
                    </svg>
                    <svg class="cp__content__tuning__title__carret" ng-show="self.showTuningOptions">
                        <use xlink:href="#ico16_arrow_up" href="#ico16_arrow_up"></use>
                    </svg>

                    <won-matching-context-picker
                      ng-if="self.showTuningOptions"
                      default-matching-context="::self.defaultMatchingContext"
                      initial-matching-context="::self.draftObject.matchingContext"
                      on-matching-context-updated="::self.updateMatchingContext(matchingContext)">
                    </won-matching-context-picker>

            <won-labelled-hr label="::'done?'" class="cp__content__labelledhr show-in-responsive"></won-labelled-hr>
            <button type="submit" class="won-button--filled red cp__content__publish show-in-responsive"
                    ng-disabled="!self.isValid()"
                    ng-click="::self.publish()">

                    Publish

                    Publishing …

            </button>

            <won-labelled-hr label="::'done?'" class="cp__footer__labelledhr"></won-labelled-hr>
            <button type="submit" class="won-button--filled red cp__footer__publish"
                    ng-disabled="!self.isValid()"
                    ng-click="::self.publish()">

                    Publish

                    Publishing …

            </button>

    `;

  class Controller {
    constructor(/* arguments <- serviceDependencies */) {
      attach(this, serviceDependencies, arguments);

      this.SEARCH = "search";
      this.POST = "post";

      this.focusedElement = null;
      //TODO debug; deleteme
      window.cnc4dbg = this;

      this.postTypeTexts = postTypeTexts;
      this.characterLimit = postTitleCharacterLimit;
      this.draftIs = {
        title: undefined,
        type: postTypeTexts[3].type, // TODO: do we use this information anywhere?
        // description: undefined,
        // tags: undefined,
        // person: undefined,
        // location: undefined,
        // travelAction: undefined,
        // thumbnail: undefined,
      };
      this.draftSeeks = {
        title: undefined,
        type: postTypeTexts[3].type,
        // description: undefined,
        // tags: undefined,
        // person: undefined,
        // location: undefined,
        // travelAction: undefined,
        // thumbnail: undefined,
      };

      this.windowHeight = window.screen.height;
      this.scrollContainer().addEventListener("scroll", e => this.onResize(e));
      this.draftObject = {
        is: this.draftIs,
        seeks: this.draftSeeks,
        matchingContext: undefined,
      };

      this.showTuningOptions = false;

      this.pendingPublishing = false;
      this.details = { is: [], seeks: [] };
      this.isNew = true;

      const selectFromState = state => {
        const showCreateView = getIn(state, [
          "router",
          "currentParams",
          "showCreateView",
        ]);
        const isSearch = showCreateView === this.SEARCH;
        const isPost = showCreateView && !isSearch;

        // needed to be able to reset matching context to default
        // TODO: is there an easier way to do this?
        const defaultMatchingContextList = getIn(state, [
          "config",
          "theme",
          "defaultContext",
        ]);
        const defaultMatchingContext = defaultMatchingContextList
          ? defaultMatchingContextList.toJS()
          : [];

        return {
          connectionHasBeenLost: !selectIsConnected(state),
          showCreateView,
          isSearch,
          isPost,
          defaultMatchingContext: defaultMatchingContext,
        };
      };

      // TODO: think about how to deal with contexts predefined in usecases
      delay(0).then(() =>
        this.updateMatchingContext(this.defaultMatchingContext)
      );

      // Using actionCreators like this means that every action defined there is available in the template.
      connect2Redux(selectFromState, actionCreators, [], this);
    }

    onResize() {
      //TODO: delete
      //console.log("ResizeEvent: ", window.screen.height);
      if (this.focusedElement) {
        if (this.windowHeight < window.screen.height) {
          this.windowHeight < window.screen.height;
          this.scrollToBottom(this.focusedElement);
        } else {
          this.windowHeight = window.screen.height;
        }
      }
    }

    scrollToBottom(element) {
      this._programmaticallyScrolling = true;

      if (element) {
        let heightHeader =
          this.$element[0].querySelector(".cp__header").offsetHeight + 10;
        let scrollTop = this.$element[0].querySelector(element).offsetTop;
        this.scrollContainer().scrollTop = scrollTop - heightHeader;

        this.focusedElement = element;
        //TODO: debug: delete me
        //console.log("ScrollTop: ", this.scrollContainer().scrollTop);
      }
    }

    scrollContainer() {
      if (!this._scrollContainer) {
        this._scrollContainer = this.$element[0].querySelector(".cp__content");
      }
      return this._scrollContainer;
    }

    toggleTuningOptions() {
      // if (!this.showTuningOptions) {
      //   this.onScroll({ element: ".cis__addDetail__header.b" });
      // }
      this.showTuningOptions = !this.showTuningOptions;
    }

    isValid() {
      const draft = this.draftObject;
      const hasContent = get(draft, "is") || get(draft, "seeks");
      const hasValidIs = this.isOrSeeksIsValid(get(draft, "is"));
      const hasValidSeeks = this.isOrSeeksIsValid(get(draft, "seeks"));
      return (
        !this.connectionHasBeenLost &&
        hasContent &&
        (hasValidIs || hasValidSeeks)
      );
    }

    updateMatchingContext(matchingContext) {
      // also accepts []!
      if (matchingContext) {
        this.draftObject.matchingContext = matchingContext;
      } else {
        this.draftObject.matchingContext = undefined;
      }
    }

    updateDraft(updatedDraft, isSeeks) {
      if (this.isNew) {
        this.isNew = false;
      }

      this.draftObject[isSeeks] = updatedDraft;
    }

    publish() {
      // Post both needs
      if (!this.pendingPublishing) {
        this.pendingPublishing = true;

        // TODO: This should be a usecase/done via a different component
        // Check if this is a search
        const searchString = this.checkForSearchString(this.draftObject);
        if (searchString) {
          this.draftObject.searchString = searchString;
          //delete this.draftObject.is;
        }

        const draft = this.getPublishObject(this.draftObject);

        this.needs__create(
          draft,
          this.$ngRedux.getState().getIn(["config", "defaultNodeUri"])
        );
      }
    }

    getPublishObject(draft) {
      if (!this.isOrSeeksIsValid(draft.is)) {
        delete draft.is;
      }
      if (!this.isOrSeeksIsValid(draft.seeks)) {
        delete draft.seeks;
      }
      return draft;
    }

    // returns true if the part has a valid title or any other detail
    isOrSeeksIsValid(isOrSeeks) {
      if (!isOrSeeks) {
        return false;
      }

      const title = get(isOrSeeks, "title");
      const hasValidTitle = title && title.length < this.characterLimit;

      let hasDetail = false;
      const details = Object.keys(isOrSeeks);
      for (let d of details) {
        if (details[d] && d !== "type") {
          hasDetail = true;
        }
      }
      return !!(hasValidTitle || hasDetail);
    }

    checkForSearchString(draft) {
      // draft has an is part -> not a pure search
      if (this.isOrSeeksIsValid(draft.is)) {
        return undefined;
      }

      // draft has no valid seeks part -> not a pure search
      if (!draft.seeks || !draft.seeks.title) {
        return undefined;
      }

      for (let detail of Object.keys(draft.seeks)) {
        if (detail !== "title" && detail !== "type" && draft.seeks[detail]) {
          return undefined;
        }
      }

      return draft.seeks.title;
    }

    createWhatsNew() {
      if (!this.pendingPublishing) {
        this.pendingPublishing = true;
        this.needs__whatsNew();
      }
    }
  }

  Controller.$inject = serviceDependencies;

  return {
    restrict: "E",
    controller: Controller,
    controllerAs: "self",
    bindToController: true, //scope-bindings -> ctrl
    scope: {
      /*scope-isolation*/
    },
    template: template,
  };
}

export default //.controller('CreateNeedController', [...serviceDependencies, CreateNeedController])
angular
  .module("won.owner.components.createPost", [
    labelledHrModule,
    imageDropzoneModule,
    descriptionPickerModule,
    locationPickerModule,
    personPickerModule,
    routePickerModule,
    tagsPickerModule,
    ttlPickerModule,
    createIsseeksModule,
    matchingContextModule,
    ngAnimate,
  ])
  .directive("wonCreatePost", genComponentConf).name;
<|endoftext|>


<commit_before>Application.Controllers.controller("provWizardController",
                                   ["$scope", "$timeout", provWizardController]);

function provWizardController($scope, $timeout) {
    $scope.detailsActive = true;
    $scope.templatesActive = false;
    $scope.templates = [
        "template-a",
        "template-b",
        "template-c",
        "template-d"
    ];

    $scope.steps = [
        "Process Description",
        "Settings",
        "Input Files",
        "Output Files"
    ];

    var nodes = [
        {id: 1, label: "My Sample", level: 0, group: "sample"},
        {id: 2, label: "Section", level: 1, group: "process"},
        {id: 3, label: "SEM", level: 1, group: "process"},
        {id: 4, label: "My Sample Cut 1", level: 2, group: "sample"},
        {id: 5, label: "My Sample Cut 2", level: 2, group: "sample"},
        {id: 6, label: "SEM Analysis", level: 2, group: "process"}
    ];

    var lastNodeID = 6;
    var lastEdgeID = 6;

    var edges = [
        {id: 1, from: 1, to: 2},
        {id: 2, from: 1, to: 3},
        {id: 3, from: 2, to: 4},
        {id: 4, from: 2, to: 5},
        {id: 5, from: 3, to: 6},
        {id: 6, from: 2, to: 6}
    ];

    $scope.options = {
        stabilize: true,
        height: '700px',
        //width: '650px',
        dragNetwork: false,
        zoomable: true,
        hierarchicalLayout: {
            enabled: true,
            nodeSpacing: 500
        },
        groups: {
            sample: {
                color: "gray",
                shape: "box"
            },
            process: {
                shape: "box"
            }
        }
    };

    $scope.data = {
        nodes: nodes,
        edges: edges
    };

    $scope.selectedNode = null;
    $scope.selectedEdge = null;

    $scope.onSelect = function(props) {
        if (props.nodes.length !== 0 ) {
            var nodeID = props.nodes[0];
            var index = _.indexOf($scope.data.nodes, function(node) {
                return node.id+"" === nodeID;
            });
            $scope.selectedNode = $scope.data.nodes[index];
            $scope.selectedEdge = null;
        } else {
            $scope.selectedEdge = props.edges[0];
            $scope.selectedNode = null;
        }
    };

    $scope.addNode = function() {
        if (!$scope.selectedNode) {
            return;
        }

        var node = $scope.selectedNode;
        lastNodeID++;
        $timeout(function() {
            $scope.data.nodes.push({
                id: lastNodeID,
                label: "My new process " + lastNodeID,
                level: node.level+1,
                group: "process"
            });
            $scope.data.edges.push({
                from: node.id,
                to: lastNodeID
            });
        });
    };

    $scope.addBetween = function() {
        if (!$scope.selectedEdge) {
            return;
        }
        var index = _.indexOf($scope.data.edges, function(edge) {
            return edge.id+"" == $scope.selectedEdge;
        });
        var edge = $scope.data.edges[index];
        var indexFrom = _.indexOf($scope.data.nodes, function(node) {
            return node.id == edge.from;
        });
        var fromNode = $scope.data.nodes[indexFrom];

        var indexTo = _.indexOf($scope.data.nodes, function(node) {
            return node.id == edge.to;
        });
        var toNode = $scope.data.nodes[indexTo];
        $timeout(function() {
            lastNodeID++;
            $scope.data.nodes.push({
                id: lastNodeID,
                label: "Inbetween process " + lastNodeID,
                level: fromNode.level+1,
                group: "process"
            });
            toNode.level++;
            $scope.data.edges.splice(index, 1);
            lastEdgeID++;
            $scope.data.edges.push({
                id: lastEdgeID,
                from: fromNode.id,
                to: lastNodeID
            });

            lastEdgeID++;
            $scope.data.edges.push({
                id: lastEdgeID,
                from: lastNodeID,
                to: toNode.id
            });
        });
    };
}
<commit_msg>Add navigation.<commit_after>Application.Controllers.controller("provWizardController",
                                   ["$scope", "$timeout", provWizardController]);

function provWizardController($scope, $timeout) {
    $scope.detailsActive = true;
    $scope.templatesActive = false;
    $scope.templates = [
        "template-a",
        "template-b",
        "template-c",
        "template-d"
    ];

    $scope.steps = [
        "Process Description",
        "Settings",
        "Input Files",
        "Output Files"
    ];

    var nodes = [
        {id: 1, label: "My Sample", level: 0, group: "sample"},
        {id: 2, label: "Section", level: 1, group: "process"},
        {id: 3, label: "SEM", level: 1, group: "process"},
        {id: 4, label: "My Sample Cut 1", level: 2, group: "sample"},
        {id: 5, label: "My Sample Cut 2", level: 2, group: "sample"},
        {id: 6, label: "SEM Analysis", level: 2, group: "process"}
    ];

    var lastNodeID = 6;
    var lastEdgeID = 6;

    var edges = [
        {id: 1, from: 1, to: 2},
        {id: 2, from: 1, to: 3},
        {id: 3, from: 2, to: 4},
        {id: 4, from: 2, to: 5},
        {id: 5, from: 3, to: 6},
        {id: 6, from: 2, to: 6}
    ];

    $scope.options = {
        stabilize: true,
        height: '700px',
        //width: '650px',
        dragNetwork: false,
        navigation: true,
        zoomable: true,
        hierarchicalLayout: {
            enabled: true,
            nodeSpacing: 500
        },
        groups: {
            sample: {
                color: "gray",
                shape: "box"
            },
            process: {
                shape: "box"
            }
        }
    };

    $scope.data = {
        nodes: nodes,
        edges: edges
    };

    $scope.selectedNode = null;
    $scope.selectedEdge = null;

    $scope.onSelect = function(props) {
        if (props.nodes.length !== 0 ) {
            var nodeID = props.nodes[0];
            var index = _.indexOf($scope.data.nodes, function(node) {
                return node.id+"" === nodeID;
            });
            $scope.selectedNode = $scope.data.nodes[index];
            $scope.selectedEdge = null;
        } else {
            $scope.selectedEdge = props.edges[0];
            $scope.selectedNode = null;
        }
    };

    $scope.addNode = function() {
        if (!$scope.selectedNode) {
            return;
        }

        var node = $scope.selectedNode;
        lastNodeID++;
        $timeout(function() {
            $scope.data.nodes.push({
                id: lastNodeID,
                label: "My new process " + lastNodeID,
                level: node.level+1,
                group: "process"
            });
            $scope.data.edges.push({
                from: node.id,
                to: lastNodeID
            });
        });
    };

    $scope.addBetween = function() {
        if (!$scope.selectedEdge) {
            return;
        }
        var index = _.indexOf($scope.data.edges, function(edge) {
            return edge.id+"" == $scope.selectedEdge;
        });
        var edge = $scope.data.edges[index];
        var indexFrom = _.indexOf($scope.data.nodes, function(node) {
            return node.id == edge.from;
        });
        var fromNode = $scope.data.nodes[indexFrom];

        var indexTo = _.indexOf($scope.data.nodes, function(node) {
            return node.id == edge.to;
        });
        var toNode = $scope.data.nodes[indexTo];
        $timeout(function() {
            lastNodeID++;
            $scope.data.nodes.push({
                id: lastNodeID,
                label: "Inbetween process " + lastNodeID,
                level: fromNode.level+1,
                group: "process"
            });
            toNode.level++;
            $scope.data.edges.splice(index, 1);
            lastEdgeID++;
            $scope.data.edges.push({
                id: lastEdgeID,
                from: fromNode.id,
                to: lastNodeID
            });

            lastEdgeID++;
            $scope.data.edges.push({
                id: lastEdgeID,
                from: lastNodeID,
                to: toNode.id
            });
        });
    };
}
<|endoftext|>


<commit_before>/**
 * @class  	UIFactory.Select
 * @author  Flavio De Stefano <flavio.destefano@caffeinalab.com>
 */

var Moment = require('alloy/moment');
var Util = require('T/util');

var Data = {};

function fillPickerData($this, $picker) {
	if (OS_ANDROID) {
		_.each($picker.columns, function(col) {
			for (var i = col.rowCount; i >= 0; i--) {
				col.removeRow( col.rows[i] );
			}
		});
	}

	if ($this != null) {
		var pickerColumns = Data[ $this._uid ].values.map(function(rows, columnIndex) {
			var $col = Ti.UI.createPickerColumn();
			rows.forEach(function(value) {
				$col.addRow( Ti.UI.createPickerRow(value) );
			});
			return $col;
		});
		$picker.columns = pickerColumns;

		// Wait for visible custom event, 'cause "On iOS, this method must be called after the picker is rendered."
		$picker.addEventListener('visible', function(e) {
			Data[ $this._uid ].values.forEach(function(rows, columnIndex) {
				$picker.setSelectedRow(columnIndex, Data[ $this._uid ].indexes[columnIndex] || 0, false);
			});
		});
	}

	Data[ $this._uid ].eventsOnChange = [];
}

function onValueSelected($this, $picker) {
	if ($this.typeString === 'plain') {

		Data[ $this._uid ].eventsOnChange.forEach(function(e, columnIndex) {
			if (e != null) {
				Data[ $this._uid ].value[columnIndex] = e.value;
				Data[ $this._uid ].indexes[columnIndex] = e.index;
				Data[ $this._uid ].titles[columnIndex] = e.value ? e.title : null;
			}
		});

	} else if ($this.typeString === 'date') {
		Data[ $this._uid ].value = $picker.value;
	}

	if (OS_IOS) {
		if (_.isFunction($this.updateUI)) $this.updateUI();
	}
}

function createTiUIPicker($this) {
	var $picker = null;

	if ($this.typeString === 'plain') {

		if (OS_IOS) {
			$picker = Ti.UI.createPicker({
				width: Ti.UI.FILL,
			});
		} else if (OS_ANDROID) {
			$picker = Ti.UI.createPicker($this);
		}

		fillPickerData($this, $picker);

		$picker.addEventListener('change', function(e) {
			Data[ $this._uid ].eventsOnChange[e.columnIndex] = e.row;

			if (OS_ANDROID) {
				// This has been the root of all evils - is $picker, $picker (not $this, $picker)
				onValueSelected($picker, $picker);
			}
		});

	} else if ($this.typeString === 'date') {

		if (OS_IOS) {
			$picker = Ti.UI.createPicker({
				value: $this.getValue(),
				minDate: $this.minDate,
				maxDate: $this.maxDate,
				width: Ti.UI.FILL,
				type: Ti.UI.PICKER_TYPE_DATE,
			});
		} else if (OS_ANDROID) {
			// no case
		}

	}

	return $picker;
}

// Get the two buttons in the toolbar
function UIPickerButtons($this, $picker, callbacks) {
	var $doneBtn = Ti.UI.createButton({ title: L('done', 'Done') });
	$doneBtn.addEventListener('click', function() {
		onValueSelected($this, $picker);
		callbacks.done();
	});

	var $cancelBtn = Ti.UI.createButton({ title: L('cancel', 'Cancel') });
	$cancelBtn.addEventListener('click', function() {
		callbacks.cancel();
	});

	return {
		done: $doneBtn,
		cancel: $cancelBtn
	};
}

var UIPickers = {

	// Show the picker in a Window that slide in from the bottom
	iphone: function($this) {
		var $picker = createTiUIPicker($this);
		var buttons = UIPickerButtons($this, $picker, {
			cancel: function() {
				$this.fireEvent('cancelled');
				$pickerModal.close();
			},
			done: function() {
				$pickerModal.close();
			}
		});

		var $toolbar = Ti.UI.iOS.createToolbar({
			items: [
				buttons.cancel,
				Ti.UI.createButton({ systemButton: Ti.UI.iPhone.SystemButton.FLEXIBLE_SPACE }),
				buttons.done
			],
			borderTop: true,
			borderBottom: false
		});

		var $containerView = Ti.UI.createView({
			height: Ti.UI.SIZE,
			width: Ti.UI.FILL,
			layout: 'vertical',
			bottom: 0,
			transform: Ti.UI.create2DMatrix().translate(0, 300)
		});
		$containerView.add($toolbar);
		$containerView.add($picker);

		var $pickerModal = Ti.UI.createWindow({
			backgroundColor: '#4000',
		});
		$pickerModal.add($containerView);

		$pickerModal.addEventListener('open', function(e) {
			$picker.fireEvent('visible');
		});

		$pickerModal.open();

		$containerView.animate({
			transform: Ti.UI.create2DMatrix()
		});
	},

	// Show the picker in a Popover Window attached to the Label
	ipad: function($this) {
		var $picker = createTiUIPicker($this);
		var has_value = false;

		var buttons = UIPickerButtons($this, $picker, {
			cancel: function() {
				has_value = false;
				$popover.hide();
			},
			done: function() {
				has_value = true;
				$popover.hide();
			}
		});

		var $containerWindow = Ti.UI.createWindow({
			leftNavButton: buttons.cancel,
			rightNavButton: buttons.done,
			title: $this.hintText,
			navTintColor: $this.tintColor
		});
		$containerWindow.add($picker);

		$containerWindow.addEventListener('open', function(e) {
			$picker.fireEvent('visible');
		});

		$containerWindow.addEventListener('close', function(e) {
			if (!has_value) {
				$this.fireEvent('cancelled');
			}
		});

		var $navigator = Ti.UI.iOS.createNavigationWindow({
			window: $containerWindow,
			width: 320,
			height: 216 + 40, // 216 is the default iOS iPad picker height
		});

		var $popover = Ti.UI.iPad.createPopover({
			contentView: $navigator
		});

		$popover.show({
			view: $this
		});
	},

	android: function($this) {
		Ti.UI.createPicker(
			_.extend({}, _.pick($this, 'minDate', 'maxDate'), {
				typeString: Ti.UI.PICKER_TYPE_DATE,
			})
		).showDatePickerDialog({
			value: $this.getValue(),
			callback: function(e) {
				if (e.value == null || e.cancel !== false) return;
				$this.updateUI();
			}
		});
	}

};

function dataPickerInterface(type, opt) {
	var self = {};

	if (type === 'plain') {

		self.values = opt.columns.map(function(column, columnIndex) {
			return column.map(function(row, rowIndex) {
				var val = null;
				var current = opt.columnsValues != null ? opt.columnsValues[columnIndex] : null;
				if (_.isObject(row)) {
					val = _.extend({}, row, {
						index: rowIndex,
						selected: (current != null && _.isEqual(current, (_.isObject(val) ? val.value : val) ))
					});
				} else {
					val = {
						title: row.toString(),
						value: row,
						index: rowIndex,
						selected: (current != null && current == row)
					};
				}
				return val;
			});
		});

		self.value = [];
		self.indexes = [];
		self.titles = [];

		_.each(self.values, function(rows, columnIndex) {
			var row = _.findWhere(rows, { selected: true });

			if (row != null) {
				self.value[columnIndex] = row.value;
				self.indexes[columnIndex] = row.index;
				self.titles[columnIndex] = row.title;
			} else {
				self.value[columnIndex] = null;
				self.indexes[columnIndex] = null;
				self.titles[columnIndex] = null;
			}
		});

	} else if (type === 'date') {

		self.value = opt.value || new Date();

	}

	return self;
}

module.exports = function(args) {
	args = _.defaults(args || {}, {

		/**
		 * @property {String} [dateFormat='D MMMM YYYY']
		 */
		dateFormat: 'D MMMM YYYY',

		/**
		 * @property {Array} [columns=[]]
		 * An array containing arrays of values.
		 * For each entry you can specify an entry like `{ value: '1', title: 'One' }` to define different title/values.
		 * Alternatively, just declare an entry with a primitive value.
		 */
		columns: [],

		/**
		 * @property {Object} [value]
		 * Values of the columns
		 */
		columnsValues: null,

		/**
		 * @property {Array} [values=[]]
		 * Shorthand for a single-columns values
		 */
		values: null,

		/**
		 * @property {Object} [value]
		 * Shorthand for a single-columns columnsValues
		 */
		value: null,

		/**
		 * @property {String} [type="plain"]
		 * Type of the picker. Could be `plain`, `date`.
		 */
		type: 'plain'

	});

	if (args.values != null) {
		args.columns = [ args.values ];
		args.columnsValues = [ args.value ];
	}

	args._uid = _.uniqueId();

	// Create a unique interface
	Data[ args._uid ] = dataPickerInterface(args.type, {

		// For plain
		columnsValues: args.columnsValues,
		columns: args.columns,

		// For date
		value: args.value

	});

	delete args.columns;
	delete args.columnsValues;
	delete args.value;
	delete args.values;

	args.typeString = args.type;
	delete args.type;

	// Start UI

	var $this = null;

	if (OS_IOS) {

		// in iOS case, $this is a Label
		_.defaults(args, {
			height: 48,
			width: Ti.UI.FILL
		});

		$this = Ti.UI.createLabel(args);

		$this.addEventListener('click', function(){
			UIPickers[ Ti.Platform.osname ]($this);
		});

	} else if (OS_ANDROID) {

		if (args.typeString === 'plain') {

			// Android Ti.UI.Picker just work
			$this = createTiUIPicker(args);

		} else if (args.typeString === 'date') {

			// While Ti.UI.Picker Date is only modal
			$this = Ti.UI.createLabel(args);

			$this.addEventListener('click', function(){
				UIPickers.android($this);
			});

		}
	}

	$this.updateUI = function() {
		var val = $this.getValue();

		$this.fireEvent('change', {
			value: val,
			source: $this
		});

		if ($this.typeString === 'plain') {

			if (OS_IOS) {
				$this.text = Data[ $this._uid ].titles.join(' ') || $this.hintText || '';
			} else {
				Data[ $this._uid ].indexes.forEach(function(rowIndex, columnIndex) {
					this.setSelectedRow(columnIndex, rowIndex, false);
				});
			}

		} else if ($this.typeString === 'date') {

			$this.text = val ? Moment(val).format($this.dateFormat) : ($this.hintText || '');

		}
	};

	/**
	 * @method getValue
	 * Get the value
	 * @return {Object}
	 */
	$this.getValue = function() {
		var v = Data[ $this._uid ].value;
		if ($this.typeString === 'plain') {
			if (v != null && v.length === 1) return v[0];
		}
		return v;
	};

	/**
	 * @method  setValue
	 * Set the current value
	 */
	$this.setValue = function(values) {
		Data[ $this._uid ].value = value;

		if ($this.typeString === 'plain') {
			Data[ $this._uid ].values.forEach(function(rows, columnIndex) {
				var row = _.findWhere(rows, { value: values[columnIndex] });
				if (row != null) {
					Data[ $this._uid ].indexes[columnIndex] = row.index;
					Data[ $this._uid ].titles[columnIndex] = row.title;
				}
			});
		}

		$this.updateUI();
	};

	/**
	 * @method setValues
	 * @param {Array} values The values
	 * Set the values for the picker
	 */
	$this.setValues = function(values) {
		$this.setColumns([ values ]);
	};

	/**
	 * @method setColumns
	 * @param {Array} columns The columns
	 * Set the columns for the picker
	 */
	$this.setColumns = function(columns) {
		_.extend(Data[ args._uid ], dataPickerInterface($this.typeString, {
			columnsValues: $this.columnsValues,
			columns: columns
		}));

		if (OS_ANDROID) {
			fillPickerData($this, $this);
		}

		$this.updateUI();
	};

	/**
	 * @method open
	 * Open the picker
	 */
	$this.open = function() {
		UIPickers[ Ti.Platform.osname ]($this);
	};

	// Update the UI
	$this.updateUI();

	return $this;
};
<commit_msg>Fixed doc<commit_after>/**
 * @class  	UIFactory.Select
 * @author  Flavio De Stefano <flavio.destefano@caffeinalab.com>
 */

var Moment = require('alloy/moment');
var Util = require('T/util');

var Data = {};

function fillPickerData($this, $picker) {
	if (OS_ANDROID) {
		_.each($picker.columns, function(col) {
			for (var i = col.rowCount; i >= 0; i--) {
				col.removeRow( col.rows[i] );
			}
		});
	}

	if ($this != null) {
		var pickerColumns = Data[ $this._uid ].values.map(function(rows, columnIndex) {
			var $col = Ti.UI.createPickerColumn();
			rows.forEach(function(value) {
				$col.addRow( Ti.UI.createPickerRow(value) );
			});
			return $col;
		});
		$picker.columns = pickerColumns;

		// Wait for visible custom event, 'cause "On iOS, this method must be called after the picker is rendered."
		$picker.addEventListener('visible', function(e) {
			Data[ $this._uid ].values.forEach(function(rows, columnIndex) {
				$picker.setSelectedRow(columnIndex, Data[ $this._uid ].indexes[columnIndex] || 0, false);
			});
		});
	}

	Data[ $this._uid ].eventsOnChange = [];
}

function onValueSelected($this, $picker) {
	if ($this.typeString === 'plain') {

		Data[ $this._uid ].eventsOnChange.forEach(function(e, columnIndex) {
			if (e != null) {
				Data[ $this._uid ].value[columnIndex] = e.value;
				Data[ $this._uid ].indexes[columnIndex] = e.index;
				Data[ $this._uid ].titles[columnIndex] = e.value ? e.title : null;
			}
		});

	} else if ($this.typeString === 'date') {
		Data[ $this._uid ].value = $picker.value;
	}

	if (OS_IOS) {
		if (_.isFunction($this.updateUI)) $this.updateUI();
	}
}

function createTiUIPicker($this) {
	var $picker = null;

	if ($this.typeString === 'plain') {

		if (OS_IOS) {
			$picker = Ti.UI.createPicker({
				width: Ti.UI.FILL,
			});
		} else if (OS_ANDROID) {
			$picker = Ti.UI.createPicker($this);
		}

		fillPickerData($this, $picker);

		$picker.addEventListener('change', function(e) {
			Data[ $this._uid ].eventsOnChange[e.columnIndex] = e.row;

			if (OS_ANDROID) {
				// This has been the root of all evils - is $picker, $picker (not $this, $picker)
				onValueSelected($picker, $picker);
			}
		});

	} else if ($this.typeString === 'date') {

		if (OS_IOS) {
			$picker = Ti.UI.createPicker({
				value: $this.getValue(),
				minDate: $this.minDate,
				maxDate: $this.maxDate,
				width: Ti.UI.FILL,
				type: Ti.UI.PICKER_TYPE_DATE,
			});
		} else if (OS_ANDROID) {
			// no case
		}

	}

	return $picker;
}

// Get the two buttons in the toolbar
function UIPickerButtons($this, $picker, callbacks) {
	var $doneBtn = Ti.UI.createButton({ title: L('done', 'Done') });
	$doneBtn.addEventListener('click', function() {
		onValueSelected($this, $picker);
		callbacks.done();
	});

	var $cancelBtn = Ti.UI.createButton({ title: L('cancel', 'Cancel') });
	$cancelBtn.addEventListener('click', function() {
		callbacks.cancel();
	});

	return {
		done: $doneBtn,
		cancel: $cancelBtn
	};
}

var UIPickers = {

	// Show the picker in a Window that slide in from the bottom
	iphone: function($this) {
		var $picker = createTiUIPicker($this);
		var buttons = UIPickerButtons($this, $picker, {
			cancel: function() {
				$this.fireEvent('cancelled');
				$pickerModal.close();
			},
			done: function() {
				$pickerModal.close();
			}
		});

		var $toolbar = Ti.UI.iOS.createToolbar({
			items: [
				buttons.cancel,
				Ti.UI.createButton({ systemButton: Ti.UI.iPhone.SystemButton.FLEXIBLE_SPACE }),
				buttons.done
			],
			borderTop: true,
			borderBottom: false
		});

		var $containerView = Ti.UI.createView({
			height: Ti.UI.SIZE,
			width: Ti.UI.FILL,
			layout: 'vertical',
			bottom: 0,
			transform: Ti.UI.create2DMatrix().translate(0, 300)
		});
		$containerView.add($toolbar);
		$containerView.add($picker);

		var $pickerModal = Ti.UI.createWindow({
			backgroundColor: '#4000',
		});
		$pickerModal.add($containerView);

		$pickerModal.addEventListener('open', function(e) {
			$picker.fireEvent('visible');
		});

		$pickerModal.open();

		$containerView.animate({
			transform: Ti.UI.create2DMatrix()
		});
	},

	// Show the picker in a Popover Window attached to the Label
	ipad: function($this) {
		var $picker = createTiUIPicker($this);
		var has_value = false;

		var buttons = UIPickerButtons($this, $picker, {
			cancel: function() {
				has_value = false;
				$popover.hide();
			},
			done: function() {
				has_value = true;
				$popover.hide();
			}
		});

		var $containerWindow = Ti.UI.createWindow({
			leftNavButton: buttons.cancel,
			rightNavButton: buttons.done,
			title: $this.hintText,
			navTintColor: $this.tintColor
		});
		$containerWindow.add($picker);

		$containerWindow.addEventListener('open', function(e) {
			$picker.fireEvent('visible');
		});

		$containerWindow.addEventListener('close', function(e) {
			if (!has_value) {
				$this.fireEvent('cancelled');
			}
		});

		var $navigator = Ti.UI.iOS.createNavigationWindow({
			window: $containerWindow,
			width: 320,
			height: 216 + 40, // 216 is the default iOS iPad picker height
		});

		var $popover = Ti.UI.iPad.createPopover({
			contentView: $navigator
		});

		$popover.show({
			view: $this
		});
	},

	android: function($this) {
		Ti.UI.createPicker(
			_.extend({}, _.pick($this, 'minDate', 'maxDate'), {
				typeString: Ti.UI.PICKER_TYPE_DATE,
			})
		).showDatePickerDialog({
			value: $this.getValue(),
			callback: function(e) {
				if (e.value == null || e.cancel !== false) return;
				$this.updateUI();
			}
		});
	}

};

function dataPickerInterface(type, opt) {
	var self = {};

	if (type === 'plain') {

		self.values = opt.columns.map(function(column, columnIndex) {
			return column.map(function(row, rowIndex) {
				var val = null;
				var current = opt.columnsValues != null ? opt.columnsValues[columnIndex] : null;
				if (_.isObject(row)) {
					val = _.extend({}, row, {
						index: rowIndex,
						selected: (current != null && _.isEqual(current, (_.isObject(val) ? val.value : val) ))
					});
				} else {
					val = {
						title: row.toString(),
						value: row,
						index: rowIndex,
						selected: (current != null && current == row)
					};
				}
				return val;
			});
		});

		self.value = [];
		self.indexes = [];
		self.titles = [];

		_.each(self.values, function(rows, columnIndex) {
			var row = _.findWhere(rows, { selected: true });

			if (row != null) {
				self.value[columnIndex] = row.value;
				self.indexes[columnIndex] = row.index;
				self.titles[columnIndex] = row.title;
			} else {
				self.value[columnIndex] = null;
				self.indexes[columnIndex] = null;
				self.titles[columnIndex] = null;
			}
		});

	} else if (type === 'date') {

		self.value = opt.value || new Date();

	}

	return self;
}

module.exports = function(args) {
	args = _.defaults(args || {}, {

		/**
		 * @property {String} [dateFormat='D MMMM YYYY']
		 */
		dateFormat: 'D MMMM YYYY',

		/**
		 * @property {Array} [columns=[]]
		 * An array containing arrays of values.
		 * For each entry you can specify an entry like `{ value: '1', title: 'One' }` to define different title/values.
		 * Alternatively, just declare an entry with a primitive value.
		 */
		columns: [],

		/**
		 * @property {Object} [columnsValues=null]
		 * Values of the columns
		 */
		columnsValues: null,

		/**
		 * @property {Array} [values=null]
		 * @deprecated Use columns instead
		 * Shorthand for a single-columns values
		 */
		values: null,

		/**
		 * @property {Object} [value=null]
		 * @deprecated Use columnsValues instead
		 * Shorthand for a single-columns columnsValues
		 */
		value: null,

		/**
		 * @property {String} [type="plain"]
		 * Type of the picker. Could be `plain`, `date`.
		 */
		type: 'plain'

	});

	if (args.values != null) {
		args.columns = [ args.values ];
		args.columnsValues = [ args.value ];
	}

	args._uid = _.uniqueId();

	// Create a unique interface
	Data[ args._uid ] = dataPickerInterface(args.type, {

		// For plain
		columnsValues: args.columnsValues,
		columns: args.columns,

		// For date
		value: args.value

	});

	delete args.columns;
	delete args.columnsValues;
	delete args.value;
	delete args.values;

	args.typeString = args.type;
	delete args.type;

	// Start UI

	var $this = null;

	if (OS_IOS) {

		// in iOS case, $this is a Label
		_.defaults(args, {
			height: 48,
			width: Ti.UI.FILL
		});

		$this = Ti.UI.createLabel(args);

		$this.addEventListener('click', function(){
			UIPickers[ Ti.Platform.osname ]($this);
		});

	} else if (OS_ANDROID) {

		if (args.typeString === 'plain') {

			// Android Ti.UI.Picker just work
			$this = createTiUIPicker(args);

		} else if (args.typeString === 'date') {

			// While Ti.UI.Picker Date is only modal
			$this = Ti.UI.createLabel(args);

			$this.addEventListener('click', function(){
				UIPickers.android($this);
			});

		}
	}

	$this.updateUI = function() {
		var val = $this.getValue();

		$this.fireEvent('change', {
			value: val,
			source: $this
		});

		if ($this.typeString === 'plain') {

			if (OS_IOS) {
				$this.text = Data[ $this._uid ].titles.join(' ') || $this.hintText || '';
			} else {
				Data[ $this._uid ].indexes.forEach(function(rowIndex, columnIndex) {
					this.setSelectedRow(columnIndex, rowIndex, false);
				});
			}

		} else if ($this.typeString === 'date') {

			$this.text = val ? Moment(val).format($this.dateFormat) : ($this.hintText || '');

		}
	};

	/**
	 * @method getValue
	 * Get the value
	 * @return {Object}
	 */
	$this.getValue = function() {
		var v = Data[ $this._uid ].value;
		if ($this.typeString === 'plain') {
			if (v != null && v.length === 1) return v[0];
		}
		return v;
	};

	/**
	 * @method  setValue
	 * Set the current value
	 */
	$this.setValue = function(values) {
		Data[ $this._uid ].value = value;

		if ($this.typeString === 'plain') {
			Data[ $this._uid ].values.forEach(function(rows, columnIndex) {
				var row = _.findWhere(rows, { value: values[columnIndex] });
				if (row != null) {
					Data[ $this._uid ].indexes[columnIndex] = row.index;
					Data[ $this._uid ].titles[columnIndex] = row.title;
				}
			});
		}

		$this.updateUI();
	};

	/**
	 * @method setValues
	 * @param {Array} values The values
	 * Set the values for the picker
	 */
	$this.setValues = function(values) {
		$this.setColumns([ values ]);
	};

	/**
	 * @method setColumns
	 * @param {Array} columns The columns
	 * Set the columns for the picker
	 */
	$this.setColumns = function(columns) {
		_.extend(Data[ args._uid ], dataPickerInterface($this.typeString, {
			columnsValues: $this.columnsValues,
			columns: columns
		}));

		if (OS_ANDROID) {
			fillPickerData($this, $this);
		}

		$this.updateUI();
	};

	/**
	 * @method open
	 * Open the picker
	 */
	$this.open = function() {
		UIPickers[ Ti.Platform.osname ]($this);
	};

	// Update the UI
	$this.updateUI();

	return $this;
};
<|endoftext|>


<commit_before>(function() {
	Tc.tests = {};
// todo: handle modules that have no markup
	window.ModuleTest = function ModuleTest(app) {
		var i
			,tests = []
			,mod
			,modName
		;

		// look at the modules that exist on the page's Tc app and get the module names
		for (i = 0; i < app.modules.length, mod = app.modules[i]; i++) {
			modName = mod.$ctx[0].className.split(' ')[1]
			modName = Tc.Utils.String.toCamel(modName).replace('mod', '');

			// if the module has no test, goto next
			// if we already have the module/test, goto next
			if (!Tc.tests[modName] || Tc.tests[modName].isTesting) {
				continue;
			}

			Tc.tests[modName].isTesting = true;

			tests.push({
				 name: modName
				,$node: mod.$ctx.clone(true, true)
			});
		}
		this.tests = tests;
	};

	ModuleTest.prototype = {

		run: function() {
			var i, test, $node
				,testApp = new Tc.Application()
				,moduleInstance
			;

			for (i = 0; i < this.tests.length, test = this.tests[i]; i++) {
				$ctx = $(test.$node).wrap('<div/>').parent(); // Terrific needs this...
				//moduleInstance = testApp.sandbox.addModules($ctx)[0]
				// run the test
				Tc.tests[test.name]( test.name, $ctx, testApp );
				console.groupEnd();
			}
		}
	};

	QUnit.begin(function( details ) {
		console.groupCollapsed('Module Tests')
	});

	QUnit.moduleStart(function( details ) {
		console.group( 'Module: '+ details.name );
	});

	QUnit.moduleDone(function( details ) {
		console.groupEnd();
	});

	QUnit.log(function( details ) {
		!details.result &&
			console.warn( 'Module test failed: ' + details.message);
	});

	QUnit.done(function( details ) {
		console.groupEnd();
		var consoleFn = details.failed == 0 ? 'info' : 'warn';
		console[consoleFn]('Passed: '+ details.passed +'/'+ details.total + ' | ', 'Failed: '+ details.failed );
	});

})();
<commit_msg>cleanup test runner function<commit_after>(function() {
	Tc.tests = {};
// todo: handle modules that have no markup
	window.ModuleTest = function ModuleTest(app) {
		var i
			,tests = []
			,mod
			,modName
		;

		// look at the modules that exist on the page's Tc app and get the module names
		for (i = 0; i < app.modules.length, mod = app.modules[i]; i++) {
			modName = mod.$ctx[0].className.split(' ')[1]
			modName = Tc.Utils.String.toCamel(modName).replace('mod', '');

			// if the module has no test, goto next
			// if we already have the module/test, goto next
			if (!Tc.tests[modName] || Tc.tests[modName].isTesting) {
				continue;
			}

			Tc.tests[modName].isTesting = true;

			tests.push({
				 name: modName
				,$node: mod.$ctx.clone(true, true)
			});
		}
		this.tests = tests;
	};

	ModuleTest.prototype = {

		run: function() {
			var i, test
				,testApp = new Tc.Application()
			;

			for (i = 0; i < this.tests.length, test = this.tests[i]; i++) {
				$ctx = $(test.$node).wrap('<div/>').parent(); // Terrific needs this...

				// run the test
				Tc.tests[test.name]( test.name, $ctx, testApp );
				console.groupEnd();
			}
		}
	};

	QUnit.begin(function( details ) {
		console.groupCollapsed('Module Tests')
	});

	QUnit.moduleStart(function( details ) {
		console.group( 'Module: '+ details.name );
	});

	QUnit.moduleDone(function( details ) {
		console.groupEnd();
	});

	QUnit.log(function( details ) {
		!details.result &&
			console.warn( 'Module test failed: ' + details.message);
	});

	QUnit.done(function( details ) {
		console.groupEnd();
		var consoleFn = details.failed == 0 ? 'info' : 'warn';
		console[consoleFn]('Passed: '+ details.passed +'/'+ details.total + ' | ', 'Failed: '+ details.failed );
	});

})();
<|endoftext|>


<commit_before>'use strict';

angular.module('warehaus.users', []);

angular.module('warehaus.users').factory('users', function($rootScope, $http, $q, $log, getObjectNotifications) {
    var ready_promise = $q.defer();

    var self = {
        ready: false,
        whenReady: ready_promise.promise,
        count: 0,
        byUserId: {}
    };

    var update_user_count = function() {
        self.count = Object.keys(self.byUserId).length;
    };

    var annotate_user = function(user) {
        user.display_name = user.display_name;
        user.email = user.email || '';
        var avatar_base_url = 'https://gravatar.com/avatar/' + md5(user.email) + '?d=mm';
        user.avatar_32 = avatar_base_url + '&s=70';
        user.avatar_96 = avatar_base_url + '&s=192';
    };

    var load_all_users = function() {
        return $http.get('/api/auth/users').then(function(res) {
            for (var i = 0; i < res.data.objects.length; ++i) {
                var user = res.data.objects[i];
                annotate_user(user);
                self.byUserId[user.id] = user;
            }
            update_user_count();
            self.ready = true;
            ready_promise.resolve();
            $rootScope.$broadcast('warehaus.users.inventory_changed');
        });
    };

    self.update_user = function(user_id, update) {
        return $http.put('/api/auth/users/' + user_id, update);
    };

    var user_changed = function(notification) {
        $log.debug('Fetching changed user:', notification.id);
        return $http.get('/api/auth/users/' + notification.id).then(function(res) {
            var user = res.data;
            annotate_user(user);
            self.byUserId[user.id] = user;
            update_user_count();
            $rootScope.$broadcast('warehaus.users.user_changed', notification.id);
        });
    };

    var user_deleted = function(notification) {
        $log.debug('Discarding deleted user:', notification.id);
        delete self.byUserId[notification.id];
        update_user_count();
        $rootScope.$broadcast('warehaus.users.user_deleted', notification.id);
    };

    getObjectNotifications('user', load_all_users, user_changed, user_deleted);

    return self;
});

angular.module('warehaus.users').directive('userAvatar', function(users) {
    var link = function(scope, elem, attrs) {
        scope.users = users;
    };

    return {
        restrict: 'AE',
        template: '',
        link: link,
        scope: {
            'id': '=',
            'size': '@'
        }
    };
});

angular.module('warehaus.users').directive('userUsername', function(users) {
    var link = function(scope, elem, attrs) {
        scope.users = users;
    };

    return {
        restrict: 'AE',
        template: '{{ users.byUserId[id].username }} ',
        link: link,
        scope: {
            'id': '='
        }
    };
});

angular.module('warehaus.users').directive('userDisplayName', function(users) {
    var link = function(scope, elem, attrs) {
        scope.users = users;
    };

    return {
        restrict: 'AE',
        template: '{{ users.byUserId[id].display_name }} ',
        link: link,
        scope: {
            'id': '='
        }
    };
});

angular.module('warehaus.users').directive('userEmail', function(users) {
    var link = function(scope, elem, attrs) {
        scope.users = users;
    };

    return {
        restrict: 'AE',
        template: '{{ users.byUserId[id].email }} ',
        link: link,
        scope: {
            'id': '='
        }
    };
});

angular.module('warehaus.users').run(function($rootScope, users) {
    $rootScope.users = users;
});
<commit_msg>Unify simple user directives code<commit_after>'use strict';

angular.module('warehaus.users', []);

angular.module('warehaus.users').factory('users', function($rootScope, $http, $q, $log, getObjectNotifications) {
    var ready_promise = $q.defer();

    var self = {
        ready: false,
        whenReady: ready_promise.promise,
        count: 0,
        byUserId: {}
    };

    var update_user_count = function() {
        self.count = Object.keys(self.byUserId).length;
    };

    var annotate_user = function(user) {
        user.display_name = user.display_name;
        user.email = user.email || '';
        var avatar_base_url = 'https://gravatar.com/avatar/' + md5(user.email) + '?d=mm';
        user.avatar_32 = avatar_base_url + '&s=70';
        user.avatar_96 = avatar_base_url + '&s=192';
    };

    var load_all_users = function() {
        return $http.get('/api/auth/users').then(function(res) {
            for (var i = 0; i < res.data.objects.length; ++i) {
                var user = res.data.objects[i];
                annotate_user(user);
                self.byUserId[user.id] = user;
            }
            update_user_count();
            self.ready = true;
            ready_promise.resolve();
            $rootScope.$broadcast('warehaus.users.inventory_changed');
        });
    };

    self.update_user = function(user_id, update) {
        return $http.put('/api/auth/users/' + user_id, update);
    };

    var user_changed = function(notification) {
        $log.debug('Fetching changed user:', notification.id);
        return $http.get('/api/auth/users/' + notification.id).then(function(res) {
            var user = res.data;
            annotate_user(user);
            self.byUserId[user.id] = user;
            update_user_count();
            $rootScope.$broadcast('warehaus.users.user_changed', notification.id);
        });
    };

    var user_deleted = function(notification) {
        $log.debug('Discarding deleted user:', notification.id);
        delete self.byUserId[notification.id];
        update_user_count();
        $rootScope.$broadcast('warehaus.users.user_deleted', notification.id);
    };

    getObjectNotifications('user', load_all_users, user_changed, user_deleted);

    return self;
});

angular.module('warehaus.users').service('simpleUserDirective', function(users) {
    var link = function(scope, elem, attrs) {
        scope.users = users;
    };

    return function(options) {
        return {
            restrict: 'AE',
            template: options.template,
            link: link,
            scope: options.scope
        };
    };
});

angular.module('warehaus.users').directive('userAvatar', function(simpleUserDirective) {
    return simpleUserDirective({
        template: '',
        scope: {
            'id': '=',
            'size': '@'
        }
    });
});

angular.module('warehaus.users').directive('userUsername', function(simpleUserDirective) {
    return simpleUserDirective({
        template: '{{ users.byUserId[id].username }} ',
        scope: {
            'id': '='
        }
    });
});

angular.module('warehaus.users').directive('userDisplayName', function(simpleUserDirective) {
    return {
        template: '{{ users.byUserId[id].display_name }} ',
        scope: {
            'id': '='
        }
    };
});

angular.module('warehaus.users').directive('userEmail', function(simpleUserDirective) {
    return {
        template: '{{ users.byUserId[id].email }} ',
        scope: {
            'id': '='
        }
    };
});

angular.module('warehaus.users').run(function($rootScope, users) {
    $rootScope.users = users;
});
<|endoftext|>


<commit_before>'use strict';

module.exports = {
  normalizeEntityName: function() {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  },

  afterInstall: function() {
    return this.addBowerPackagesToProject([
      {name: 'pretender', target: '~0.6.0'},
      {name: 'ember-inflector', target: '~1.3.1'},
      {name: 'lodash', target: '~3.7.0'}
    ]);
  }
};
<commit_msg>Automatically add server to jshintrc files<commit_after>'use strict';

module.exports = {
  normalizeEntityName: function() {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  },

  afterInstall: function() {
    this.insertIntoFile('.jshintrc', '    "server",', {
      after: '"predef": [\n'
    });

    this.insertIntoFile('tests/.jshintrc', '    "server",', {
      after: '"predef": [\n'
    });

    return this.addBowerPackagesToProject([
      {name: 'pretender', target: '~0.6.0'},
      {name: 'ember-inflector', target: '~1.3.1'},
      {name: 'lodash', target: '~3.7.0'}
    ]);
  }
};
<|endoftext|>


<commit_before>/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * 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.
 */
importScripts('/__/firebase/8.2.10/firebase-app.js');
importScripts('/__/firebase/8.2.10/firebase-messaging.js');
importScripts('/__/firebase/init.js');

firebase.messaging();
<commit_msg>Auto-update dependencies.<commit_after>/**
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * 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.
 */
importScripts('/__/firebase/8.3.0/firebase-app.js');
importScripts('/__/firebase/8.3.0/firebase-messaging.js');
importScripts('/__/firebase/init.js');

firebase.messaging();
<|endoftext|>