<commit_before>import Link from "next/link";
import SingleColumn from "./SingleColumn";
import Section from "./Section";
import { contact } from "../lib/constants";

export default function Footer() {
  return (

      <SingleColumn>

Use Urbit

            <Link href="/getting-started">

                Getting Started

            </Link>
            <Link href="/using">

                User's Manual

            </Link>
            <Link href="https://github.com/urbit/port/releases">

                Urbit Client

            </Link>
            <Link href="https://github.com/urbit/urbit/releases">

                Urbit Binaries

            </Link>
            {
              //   <Link href="">
              //

              //     Urbit Apps
              //

              // </Link>
            }
            <Link href="/getting-started/planet/#hosting-providers">

                  Hosting Providers

            </Link>

About

            <Link href="/understanding-urbit">

                What's Urbit?

            </Link>
            <Link href="/understanding-urbit/urbit-id">

                Urbit ID

            </Link>
            <Link href="/understanding-urbit/urbit-os">

                Urbit OS

            </Link>
            <Link href="/audits">

                Security Audits

            </Link>
            <Link href="/faq">

                FAQ

            </Link>
            <Link href="//media.urbit.org/whitepaper.pdf">

                Whitepaper

            </Link>

News

            <Link href="/blog">

                Blog

            </Link>
            <Link href="/events">

                Events

            </Link>
            <Link href="/updates">

                Updates

            </Link>

Develop

            <Link href="/docs">

                Documentation

            </Link>
            <Link href="https://github.com/urbit">

                Github

            </Link>
            <Link href="https://github.com/urbit/awesome-urbit#http-apis-airlock">

                Airlock APIs

            </Link>

Contribute

            <Link href="https://github.com/urbit/urbit/issues">

                Issue Tracker

            </Link>
            <Link href="/grants">

                Urbit Grants

            </Link>

Community

            <Link href="https://groups.google.com/a/urbit.org/g/dev?pli=1">

                Dev Mailing List

            </Link>
            <Link href="https://github.com/urbit/azimuth">

                Governance

            </Link>
            <Link href="https://twitter.com/urbit">

                Twitter

            </Link>

            <Link href="/privacy">

                Privacy Policy

            </Link>

            <Link href="/terms-of-service">

                Terms of Service

            </Link>

                {contact.email}

      </SingleColumn>

  );
}
<commit_msg>footer: fix link error during build<commit_after>import Link from "next/link";
import SingleColumn from "./SingleColumn";
import Section from "./Section";
import { contact } from "../lib/constants";

export default function Footer() {
  return (

      <SingleColumn>

Use Urbit

            <Link href="/getting-started">

                Getting Started

            </Link>
            <Link href="/using">

                User's Manual

            </Link>
            <Link href="https://github.com/urbit/port/releases">

                Urbit Client

            </Link>
            <Link href="https://github.com/urbit/urbit/releases">

                Urbit Binaries

            </Link>
            {
              //   <Link href="">
              //

              //     Urbit Apps
              //

              // </Link>
            }
            <Link href="/getting-started/planet/#hosting-providers">

                  Hosting Providers

            </Link>

About

            <Link href="/understanding-urbit">

                What's Urbit?

            </Link>
            <Link href="/understanding-urbit/urbit-id">

                Urbit ID

            </Link>
            <Link href="/understanding-urbit/urbit-os">

                Urbit OS

            </Link>
            <Link href="/audits">

                Security Audits

            </Link>
            <Link href="/faq">

                FAQ

            </Link>
            <Link href="https://media.urbit.org/whitepaper.pdf">

                Whitepaper

            </Link>

News

            <Link href="/blog">

                Blog

            </Link>
            <Link href="/events">

                Events

            </Link>
            <Link href="/updates">

                Updates

            </Link>

Develop

            <Link href="/docs">

                Documentation

            </Link>
            <Link href="https://github.com/urbit">

                Github

            </Link>
            <Link href="https://github.com/urbit/awesome-urbit#http-apis-airlock">

                Airlock APIs

            </Link>

Contribute

            <Link href="https://github.com/urbit/urbit/issues">

                Issue Tracker

            </Link>
            <Link href="/grants">

                Urbit Grants

            </Link>

Community

            <Link href="https://groups.google.com/a/urbit.org/g/dev?pli=1">

                Dev Mailing List

            </Link>
            <Link href="https://github.com/urbit/azimuth">

                Governance

            </Link>
            <Link href="https://twitter.com/urbit">

                Twitter

            </Link>

            <Link href="/privacy">

                Privacy Policy

            </Link>

            <Link href="/terms-of-service">

                Terms of Service

            </Link>

                {contact.email}

      </SingleColumn>

  );
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import format from 'date-fns/format';
import findPost from '../lib/findPost';
import Button from './Button';
import webp from '../lib/webp';

const Header = props => {
  const post = findPost(props.id);
  const { title, date, image: { imageUrl } } = post;
  return (

{props.title || title}

        {!props.link && date &&
{format(date, 'MMMM DD, YYYY')}
}
        {props.link && <Button text="Read More" link={props.id} />}

  );
};

Header.defaultProps = {
  link: null,
  id: null,
  title: null
};

Header.propTypes = {
  title: PropTypes.string,
  link: PropTypes.string,
  id: PropTypes.string
};

export default Header;
<commit_msg>show `posted x ago` with the title on hover being the date posted<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import format from 'date-fns/format';
import formatDistance from 'date-fns/formatDistance';
import findPost from '../lib/findPost';
import Button from './Button';
import webp from '../lib/webp';

const PostDate = ({ date }) => {
  const distance = formatDistance(date, new Date(), { addSuffix: true });
  const dateString = format(date, 'MMMM D, YYYY');
  return (

      Posted {distance}

  );
};

PostDate.propTypes = {
  date: PropTypes.number.isRequired
};

const Header = props => {
  const post = findPost(props.id);
  const { title, date, image: { imageUrl } } = post;
  return (

{props.title || title}

        {!props.link && date && <PostDate date={date} />}
        {props.link && <Button text="Read More" link={props.id} />}

  );
};

Header.defaultProps = {
  link: null,
  id: null,
  title: null
};

Header.propTypes = {
  title: PropTypes.string,
  link: PropTypes.string,
  id: PropTypes.string
};

export default Header;
<|endoftext|>


<commit_before>import { Component, Fragment } from 'react'

export default class extends Component {
  render () {
    const phrase = this.props.phrase
    return (
      <Fragment>

Søk: {phrase}

          <a href={`/sok?phrase=${phrase}`}>Alt innhold
          <a href={`/sok?phrase=${phrase}&faset=employees`}>Ansatte
          <a href={`/sok?phrase=${phrase}&faset=wwwtelemark`}>wwww.telemark.no
          <a href={`/sok?phrase=${phrase}&faset=portaleninfo`}>Infosider

0 treff på søkeordet "{phrase}", viser side 1 av 1.

      </Fragment>
    )
  }
}
<commit_msg>Search fix<commit_after>import { Component, Fragment } from 'react'

export default class extends Component {
  render () {
    const phrase = this.props.phrase
    return (
      <Fragment>
        { !phrase
          ? <Fragment>
Søkeside

Du har ennå ikke søkt etter noe
</Fragment>
          : <Fragment>

Søk: {phrase}

              <a href={`/search?phrase=${phrase}`}>Alt innhold
              <a href={`/search?phrase=${phrase}&faset=employees`}>Ansatte
              <a href={`/search?phrase=${phrase}&faset=wwwtelemark`}>wwww.telemark.no
              <a href={`/search?phrase=${phrase}&faset=portaleninfo`}>Infosider

0 treff på søkeordet "{phrase}", viser side 1 av 1.

          </Fragment>
        }

      </Fragment>
    )
  }
}
<|endoftext|>


<commit_before>import { useCallback, useRef, useState } from "react";
import { glossary } from "../lib/glossary";
import Link from "next/link";

const glossarySearch = (query) => {
  return glossary.filter((entry) => {
    return query.toLowerCase() === entry.name || entry.symbol === query;
  });
};

export default function Search(props) {
  const searchRef = useRef(null);
  const [query, SetQuery] = useState("");
  const [active, setActive] = useState(false);
  const [results, setResults] = useState([]);
  const searchEndpoint = (query) => `/api/search?q=${query}`;

  const onChange = useCallback((event) => {
    const query = event.target.value;

    SetQuery(query);
    if (query.length) {
      fetch(searchEndpoint(query))
        .then((res) => res.json())
        .then((res) => {
          setResults(res.results);
        });
    } else {
      setResults([]);
    }
  }, []);

  const onFocus = useCallback(() => {
    setActive(true);
    window.addEventListener("click", onClick);
  }, []);

  const onClick = useCallback((event) => {
    if (searchRef.current && !searchRef.current.contains(event.target)) {
      setActive(false);
      window.removeEventListener("click", onClick);
      props.toggleSearch();
    }
  }, []);

  let glossaryResults = [];
  if (query.length) {
    glossaryResults = glossarySearch(query);
  }

  const clear = useCallback((e) => {
    e.stopPropagation();
    SetQuery("");
  }, []);

  // Locks document scrolling when search is open
  if (typeof document !== "undefined") {
    if (props.showSearch) {
      document.body.style.overflow = "hidden";
    } else {
      document.body.style.overflow = "visible";
    }
  }

  if (props.showSearch) {
    return (

            <input
              className="text-2xl font-medium text-green bg-transparent py-2 px-4 outline-none relative w-full"
              onChange={onChange}
              onFocus={onFocus}
              placeholder="Search..."
              type="text"
              value={query}
              autoFocus={true}
            />

                ESC

 0 ? "" : "hidden")
            }
          >
            {active &&
            results.length === 0 &&
            glossaryResults.length === 0 &&
            query !== "" ? (

No Results found for

"{query}"

            ) : null}
            {active && glossaryResults.length > 0 ? (

Glossary

                {glossaryResults.map(({ name, link, desc, symbol }) => {
                  return (
                    <Link href={link} as={link} key={link}>

                          {symbol.length > 0 && (

                              {symbol}

                          )}
                          {name}

{desc}

                    </Link>
                  );
                })}

            ) : null}
            {active && results.length > 0 && (

                    {results.length} results for "{query}"

                {results
                  .filter((e) => e.parent !== "Glossary")
                  .map(({ title, slug, content, parent }) => {
                    return (

                        <Link href={slug} as={slug}>

                              {parent} / {title}

                              {content}

                        </Link>

                    );
                  })}

            )}

    );
  }
  return null;
}
<commit_msg>search: flex the container for scrolling<commit_after>import { useCallback, useRef, useState } from "react";
import { glossary } from "../lib/glossary";
import Link from "next/link";

const glossarySearch = (query) => {
  return glossary.filter((entry) => {
    return query.toLowerCase() === entry.name || entry.symbol === query;
  });
};

export default function Search(props) {
  const searchRef = useRef(null);
  const [query, SetQuery] = useState("");
  const [active, setActive] = useState(false);
  const [results, setResults] = useState([]);
  const searchEndpoint = (query) => `/api/search?q=${query}`;

  const onChange = useCallback((event) => {
    const query = event.target.value;

    SetQuery(query);
    if (query.length) {
      fetch(searchEndpoint(query))
        .then((res) => res.json())
        .then((res) => {
          setResults(res.results);
        });
    } else {
      setResults([]);
    }
  }, []);

  const onFocus = useCallback(() => {
    setActive(true);
    window.addEventListener("click", onClick);
  }, []);

  const onClick = useCallback((event) => {
    if (searchRef.current && !searchRef.current.contains(event.target)) {
      setActive(false);
      window.removeEventListener("click", onClick);
      props.toggleSearch();
    }
  }, []);

  let glossaryResults = [];
  if (query.length) {
    glossaryResults = glossarySearch(query);
  }

  const clear = useCallback((e) => {
    e.stopPropagation();
    SetQuery("");
  }, []);

  // Locks document scrolling when search is open
  if (typeof document !== "undefined") {
    if (props.showSearch) {
      document.body.style.overflow = "hidden";
    } else {
      document.body.style.overflow = "visible";
    }
  }

  if (props.showSearch) {
    return (

            <input
              className="text-2xl font-medium text-green bg-transparent py-2 px-4 outline-none relative w-full"
              onChange={onChange}
              onFocus={onFocus}
              placeholder="Search..."
              type="text"
              value={query}
              autoFocus={true}
            />

                ESC

 0 ? "" : "hidden")
            }
          >
            {active &&
            results.length === 0 &&
            glossaryResults.length === 0 &&
            query !== "" ? (

No Results found for

"{query}"

            ) : null}
            {active && glossaryResults.length > 0 ? (

Glossary

                {glossaryResults.map(({ name, link, desc, symbol }) => {
                  return (
                    <Link href={link} as={link} key={link}>

                          {symbol.length > 0 && (

                              {symbol}

                          )}
                          {name}

{desc}

                    </Link>
                  );
                })}

            ) : null}
            {active && results.length > 0 && (

                    {results.length} results for "{query}"

                {results
                  .filter((e) => e.parent !== "Glossary")
                  .map(({ title, slug, content, parent }) => {
                    return (

                        <Link href={slug} as={slug}>

                              {parent} / {title}

                              {content}

                        </Link>

                    );
                  })}

            )}

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


<commit_before>import React from 'react'
import filter from 'lodash/filter'
import classNames from 'classnames'
import { config } from '../config'
const { sponsors } = config

const SponsorBox = ({ website, name, image, imagePadding }) => (

      <img
        src={require(`../images/sponsors/${image}`)}
        alt={name}
        title={name}
        className="Sponsors-image"
      />

)

SponsorBox.propTypes = {
  website: React.PropTypes.string,
  name: React.PropTypes.string,
  image: React.PropTypes.string,
  imagePadding: React.PropTypes.bool,
}

export default () => (

Sponsors

            The great companies below are supporting us in 2016 – Thank you!

            {filter(sponsors, ['level', 'platinum']).map(sponsor => <SponsorBox key={sponsor.name} {...sponsor} />)}

            {filter(sponsors, ['level', 'silver']).map(sponsor => <SponsorBox key={sponsor.name} {...sponsor} />)}

            {filter(sponsors, ['level', 'bronze']).map(sponsor => <SponsorBox key={sponsor.name} {...sponsor} />)}

            Travel sponsors: DigitalOcean, Hudl, Spotify, appear.in, Capital One Financial Corporation, Amazon, Originate, Mozilla – Thank you!

            We are currently offering sponsorship opportunities for JSConf Iceland.{' '}
            Contact us for details.

            Github
            Twitter

          JSConf Iceland welcomes everyone and defends you from harassment.{' '}

            Code of conduct
            {' | '}
            Mailing list
            {' | '}
            Sponsor interest
            {' | '}
            team@jsconf.is

)
<commit_msg>Update footer.js<commit_after>import React from 'react'
import filter from 'lodash/filter'
import classNames from 'classnames'
import { config } from '../config'
const { sponsors } = config

const SponsorBox = ({ website, name, image, imagePadding }) => (

      <img
        src={require(`../images/sponsors/${image}`)}
        alt={name}
        title={name}
        className="Sponsors-image"
      />

)

SponsorBox.propTypes = {
  website: React.PropTypes.string,
  name: React.PropTypes.string,
  image: React.PropTypes.string,
  imagePadding: React.PropTypes.bool,
}

export default () => (

Sponsors

            The great companies below are supporting us in 2016 – Thank you!

            {filter(sponsors, ['level', 'platinum']).map(sponsor => <SponsorBox key={sponsor.name} {...sponsor} />)}

            {filter(sponsors, ['level', 'silver']).map(sponsor => <SponsorBox key={sponsor.name} {...sponsor} />)}

            {filter(sponsors, ['level', 'bronze']).map(sponsor => <SponsorBox key={sponsor.name} {...sponsor} />)}

            Travel sponsors: DigitalOcean, Hudl, Spotify, appear.in, Capital One Financial Corporation, Amazon, Originate, Mozilla – Thank you!

            Github
            Twitter

          JSConf Iceland welcomes everyone and defends you from harassment.{' '}

            Code of conduct
            {' | '}
            Mailing list
            {' | '}
            Sponsor interest
            {' | '}
            team@jsconf.is

)
<|endoftext|>


<commit_before>import T from 'template-binding';

import xin from '../';

const FILTER_ALL = () => true;

class RepeatRow extends T {
  constructor (repeat, item, index) {
    super();

    // override T constructor
    this.__templateInitialize(repeat, repeat.__templateModel, repeat);

    this.is = '$repeat-row';
    this.__id = this.__templateId;

    this.__repeat = repeat;
    this.__repeatAs = repeat.as;
    this.__repeatIndexAs = repeat.indexAs;

    this.__templateChildNodes.forEach(node => {
      if (node.nodeType === window.Node.ELEMENT_NODE) {
        node.__repeatModel = this;
      }
    });

    this.update(item, index);

    this.__templateRender();
  }

  update (item, index) {
    this[this.__repeatAs] = item;
    this[this.__repeatIndexAs] = index;
    this.notify(this.__repeatAs, item);
    this.notify(this.__repeatIndexAs, index);
  }

  set (path, value) {
    path = this.__templateGetPathAsArray(path);

    if (path[0] === this.__repeatAs || path[0] === this.__repeatIndexAs) {
      return super.set(path, value);
    }

    return this.__templateHost.set(path, value);
  }

  get (path) {
    path = this.__templateGetPathAsArray(path);

    if (path[0] === this.__repeatAs || path[0] === this.__repeatIndexAs) {
      return super.get(path);
    }

    return this.__templateHost.get(path);
  }

  notify (path, value) {
    path = this.__templateGetPathAsArray(path);

    if (path[0] === this.__repeatAs || path[0] === this.__repeatIndexAs) {
      return super.notify(path, value);
    }

    return this.__templateHost.notify(path, value);
  }
};

class Repeat extends xin.base('HTMLTemplateElement') {
  get props () {
    return {
      items: {
        type: Array,
        observer: '_itemsChanged(items, filter)',
      },

      as: {
        type: String,
        value: 'item',
      },

      indexAs: {
        type: String,
        value: 'index',
      },

      filter: {
        type: Function,
        observer: '_itemsChanged(items, filter)',
      },
    };
  }

  created () {
    super.created();

    this.rows = [];
  }

  __initTemplate () {
    T.prototype.__templateInitialize.call(this, null, this);
  }

  _itemsChanged (items, filter) {
    let len = 0;

    if (items && items.length) {
      let filter = this.filter || FILTER_ALL;
      items.filter(filter).forEach((item, index) => {
        if (this.rows[index]) {
          this.rows[index].update(item, index);
        } else {
          this.rows.push(new RepeatRow(this, item, index));
        }

        len++;
      });
    }

    // move to detach
    this.rows.splice(len).forEach(row => {
      row.__templateUninitialize();
    });
  }

  itemForElement (element) {
    while (element && !element.__repeatModel) {
      element = element.parentElement;
    }
    return element.__repeatModel.get(this.as);
  }

  indexForElement (element) {
    while (element && !element.__repeatModel) {
      element = element.parentElement;
    }
    return element.__repeatModel.get(this.indexAs);
  }

  modelForElement (element) {
    while (element && !element.__repeatModel) {
      element = element.parentElement;
    }
    return element.__repeatModel;
  }
}

xin.define('xin-repeat', Repeat, { extends: 'template' });

export default Repeat;
<commit_msg>debouncing repeat<commit_after>import T from 'template-binding';

import xin from '../';

const FILTER_ALL = () => true;

class RepeatRow extends T {
  constructor (repeat, item, index) {
    super();

    // override T constructor
    this.__templateInitialize(repeat, repeat.__templateModel, repeat);

    this.is = '$repeat-row';
    this.__id = this.__templateId;

    this.__repeat = repeat;
    this.__repeatAs = repeat.as;
    this.__repeatIndexAs = repeat.indexAs;

    this.__templateChildNodes.forEach(node => {
      if (node.nodeType === window.Node.ELEMENT_NODE) {
        node.__repeatModel = this;
      }
    });

    this.update(item, index);

    this.__templateRender();
  }

  update (item, index) {
    this[this.__repeatAs] = item;
    this[this.__repeatIndexAs] = index;
    this.notify(this.__repeatAs, item);
    this.notify(this.__repeatIndexAs, index);
  }

  set (path, value) {
    path = this.__templateGetPathAsArray(path);

    if (path[0] === this.__repeatAs || path[0] === this.__repeatIndexAs) {
      return super.set(path, value);
    }

    return this.__templateHost.set(path, value);
  }

  get (path) {
    path = this.__templateGetPathAsArray(path);

    if (path[0] === this.__repeatAs || path[0] === this.__repeatIndexAs) {
      return super.get(path);
    }

    return this.__templateHost.get(path);
  }

  notify (path, value) {
    path = this.__templateGetPathAsArray(path);

    if (path[0] === this.__repeatAs || path[0] === this.__repeatIndexAs) {
      return super.notify(path, value);
    }

    return this.__templateHost.notify(path, value);
  }
};

class Repeat extends xin.base('HTMLTemplateElement') {
  get props () {
    return {
      items: {
        type: Array,
        observer: '_itemsChanged(items, filter)',
      },

      as: {
        type: String,
        value: 'item',
      },

      indexAs: {
        type: String,
        value: 'index',
      },

      filter: {
        type: Function,
        observer: '_itemsChanged(items, filter)',
      },
    };
  }

  created () {
    super.created();

    this.rows = [];
  }

  __initTemplate () {
    T.prototype.__templateInitialize.call(this, null, this);
  }

  _itemsChanged (items, filter) {
    this.debounce('_itemsChanged', () => {
      let len = 0;

      if (items && items.length) {
        let filter = this.filter || FILTER_ALL;
        items.filter(filter).forEach((item, index) => {
          if (this.rows[index]) {
            this.rows[index].update(item, index);
          } else {
            this.rows.push(new RepeatRow(this, item, index));
          }

          len++;
        });
      }

      // move to detach
      this.rows.splice(len).forEach(row => {
        row.__templateUninitialize();
      });
    });
  }

  itemForElement (element) {
    while (element && !element.__repeatModel) {
      element = element.parentElement;
    }
    return element.__repeatModel.get(this.as);
  }

  indexForElement (element) {
    while (element && !element.__repeatModel) {
      element = element.parentElement;
    }
    return element.__repeatModel.get(this.indexAs);
  }

  modelForElement (element) {
    while (element && !element.__repeatModel) {
      element = element.parentElement;
    }
    return element.__repeatModel;
  }
}

xin.define('xin-repeat', Repeat, { extends: 'template' });

export default Repeat;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import IdyllComponent from 'idyll-component';
import { RemountOnResize } from './remount';

// A helper component, wrapping retina and zoom logic and
// auto-resizing the sketch to fill its parent container.
// To determine size/layout, we just use CSS on the div containing
// the Sketch component (we might use this with flexbox, for example).
class SketchComponent extends IdyllComponent {

  constructor(props) {
    super(props);
    this.mountedContainer = this.mountedContainer.bind(this);
    this.state = {};
  }

  // The way canvas interacts with CSS layouting is a bit buggy
  // and inconsistent across browsers. To make it dependent on
  // the layout of the parent container, we only render it after
  // mounting view, that is: after CSS layouting is done.
  mountedContainer(div) {
    const p5 = require('p5');
    this.p5 = p5;
    if (div) {
      this.div = div;
      let { sketch, sketchProps, webGL, noCanvas, ratio, updateProps } = this.props;
      let width = div.clientWidth | 0;
      let height = div.clientHeight | 0;
      if (ratio) {
        if (this.props.width || !this.props.height) {
          height = (div.clientWidth / ratio) | 0;
        } else {
          width = (div.clientHeight * ratio) | 0;
        }
      } else if (!this.props.width && !this.props.height){
        // default to 2:1 ratio
        height = (div.clientWidth * 0.5) | 0;
      }
      let newState = { div, width, height, ratio };

      if (sketch) {
        const _sketch = (p5) => {
          sketch(p5, { width, height, devicePixelRatio: window.devicePixelRatio, updateProps: updateProps});

          // handle creation of canvas
          const _setup = p5.setup || (() => { });
          if (noCanvas) {
            p5.setup = () => {
              p5.noCanvas();
              _setup();
            };
          } else {
            p5.setup = () => {
              p5.createCanvas(width, height, webGL? p5.WEBGL : p5.P2D);
            };
          }

          // handle removing the sketch if the component unmounts
          const _unmount = p5.unmount;
          p5.unmount = () => {
            if (_unmount) {
              _unmount();
            }
            p5.remove();
          }
        }
        newState.sketch = new p5(_sketch, div);
      }
      this.setState(newState);
    }
  }

  componentWillReceiveProps(nextProps) {
    // pass relevant props to sketch
    const { sketch, width, height } = this.state;
    let { webGL, noCanvas, ratio, updateProps } = nextProps;
    nextProps.sketch(sketch, { width, height, devicePixelRatio: window.devicePixelRatio, updateProps: updateProps});
  }

  componentWillUnmount() {
    if (this.state.sketch) {
      this.state.sketch.unmount();
    }
  }

  render() {
    const { props } = this;
    let style = Object.assign({}, props.style);
    let { width, height, ratio } = props;
    switch (typeof width) {
      case 'number':
        width = width | 0;
        style['minWidth'] = width;
        style['maxWidth'] = width;
        break;
      case 'string':
        style.width = width;
        break;
      case 'undefined':
        style.width = style.width ? style.width :
          ratio && (typeof height) === 'number' ? height / ratio : '100%';
      default:
    }
    if (!(ratio && width)) {
      switch (typeof height) {
        case 'number':
          height = height | 0;
          style['minHeight'] = height;
          style['maxHeight'] = height;
          break;
        case 'string':
          style.height = height;
          break;
        case 'undefined':
          style.height = style.height ? style.height : '100%';
          break;
        default:
      }
    }

    style.margin = style.margin ? style.margin : '1em auto';

    return (
      <div
        // The way canvas interacts with CSS layouting is a bit buggy
        // and inconsistent across browsers. To make it dependent on
        // the layout of the parent container, we only render it after
        // mounting div, that is: after CSS layouting is done.
        ref={this.mountedContainer}
        className={props.className}
        style={style}
      />
    );
  }
}

class Sketch extends Component {
  render() {
    const { props } = this;
    return (
      <RemountOnResize
        /* Since canvas interferes with CSS layouting,
        we unmount and remount it on resize events */
        watchedVal={props.watchedVal}
      >
        <SketchComponent
          {...props}
          updateProps={this.updateProps}
        />
      </RemountOnResize>
    );
  }
}

module.exports = Sketch;<commit_msg>Component -> IdyllComponent<commit_after>import React from 'react';
import IdyllComponent from 'idyll-component';
import { RemountOnResize } from './remount';

// A helper component, wrapping retina and zoom logic and
// auto-resizing the sketch to fill its parent container.
// To determine size/layout, we just use CSS on the div containing
// the Sketch component (we might use this with flexbox, for example).
class SketchComponent extends IdyllComponent {

  constructor(props) {
    super(props);
    this.mountedContainer = this.mountedContainer.bind(this);
    this.state = {};
  }

  // The way canvas interacts with CSS layouting is a bit buggy
  // and inconsistent across browsers. To make it dependent on
  // the layout of the parent container, we only render it after
  // mounting view, that is: after CSS layouting is done.
  mountedContainer(div) {
    const p5 = require('p5');
    this.p5 = p5;
    if (div) {
      this.div = div;
      let { sketch, sketchProps, webGL, noCanvas, ratio, updateProps } = this.props;
      let width = div.clientWidth | 0;
      let height = div.clientHeight | 0;
      if (ratio) {
        if (this.props.width || !this.props.height) {
          height = (div.clientWidth / ratio) | 0;
        } else {
          width = (div.clientHeight * ratio) | 0;
        }
      } else if (!this.props.width && !this.props.height){
        // default to 2:1 ratio
        height = (div.clientWidth * 0.5) | 0;
      }
      let newState = { div, width, height, ratio };

      if (sketch) {
        const _sketch = (p5) => {
          sketch(p5, { width, height, devicePixelRatio: window.devicePixelRatio, updateProps: updateProps});

          // handle creation of canvas
          const _setup = p5.setup || (() => { });
          if (noCanvas) {
            p5.setup = () => {
              p5.noCanvas();
              _setup();
            };
          } else {
            p5.setup = () => {
              p5.createCanvas(width, height, webGL? p5.WEBGL : p5.P2D);
            };
          }

          // handle removing the sketch if the component unmounts
          const _unmount = p5.unmount;
          p5.unmount = () => {
            if (_unmount) {
              _unmount();
            }
            p5.remove();
          }
        }
        newState.sketch = new p5(_sketch, div);
      }
      this.setState(newState);
    }
  }

  componentWillReceiveProps(nextProps) {
    // pass relevant props to sketch
    const { sketch, width, height } = this.state;
    let { webGL, noCanvas, ratio, updateProps } = nextProps;
    nextProps.sketch(sketch, { width, height, devicePixelRatio: window.devicePixelRatio, updateProps: updateProps});
  }

  componentWillUnmount() {
    if (this.state.sketch) {
      this.state.sketch.unmount();
    }
  }

  render() {
    const { props } = this;
    let style = Object.assign({}, props.style);
    let { width, height, ratio } = props;
    switch (typeof width) {
      case 'number':
        width = width | 0;
        style['minWidth'] = width;
        style['maxWidth'] = width;
        break;
      case 'string':
        style.width = width;
        break;
      case 'undefined':
        style.width = style.width ? style.width :
          ratio && (typeof height) === 'number' ? height / ratio : '100%';
      default:
    }
    if (!(ratio && width)) {
      switch (typeof height) {
        case 'number':
          height = height | 0;
          style['minHeight'] = height;
          style['maxHeight'] = height;
          break;
        case 'string':
          style.height = height;
          break;
        case 'undefined':
          style.height = style.height ? style.height : '100%';
          break;
        default:
      }
    }

    style.margin = style.margin ? style.margin : '1em auto';

    return (
      <div
        // The way canvas interacts with CSS layouting is a bit buggy
        // and inconsistent across browsers. To make it dependent on
        // the layout of the parent container, we only render it after
        // mounting div, that is: after CSS layouting is done.
        ref={this.mountedContainer}
        className={props.className}
        style={style}
      />
    );
  }
}

class Sketch extends IdyllComponent {
  render() {
    const { props } = this;
    return (
      <RemountOnResize
        /* Since canvas interferes with CSS layouting,
        we unmount and remount it on resize events */
        watchedVal={props.watchedVal}
      >
        <SketchComponent
          {...props}
          updateProps={this.updateProps}
        />
      </RemountOnResize>
    );
  }
}

module.exports = Sketch;<|endoftext|>


<commit_before>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.

(function() {
	"use strict";
	mocha.setup({ignoreLeaks: true});

	describe("ObjectNode", function() {
		function newNode(name, object) {
			return new jdls.ObjectNode(name, object);
		}

		describe("id", function() {
			it("is unique for each node object regardless of contents", function() {
				var object = {};
				var node1 = newNode("name", object);
				var node2 = newNode("name", object);
				expect(node1.id()).to.not.equal(node2.id());
			});
		});

		describe("name", function() {
			it("is based on provided name for most objects", function() {
				var node = newNode("name", {});
				expect(node.name()).to.equal("name");
			});

			it("doesn't crash when object has no prototype", function() {
				var node = newNode("name", Object.create(null));
				expect(node.name()).to.equal("name");
			});

			it("uses function name for functions", function() {
				var node = newNode("name", function aFunction() {});
				expect(node.name()).to.equal("aFunction()");
			});

			it("is anonymous for unnamed functions", function() {
				var node = newNode("name", function() {});
				expect(node.name()).to.equal("<anon>()");
			});

			it("handles 'Function' special case", function() {
				var node = newNode("name", Function.prototype);
				expect(node.name()).to.equal("Function.prototype");
			});

			it("uses constructor name when present", function() {
				function TheConstructor() {}
				var node = newNode("name", TheConstructor.prototype);
				expect(node.name()).to.equal("TheConstructor.prototype");
			});

			it("does not use inherited constructor name", function() {
				var proto = {
					constructor: function TheConstructor() {}
				};
				var object = Object.create(proto);
				var node = newNode("name", object);
				expect(node.name()).to.equal("name");
			});

			it("does not use constructor name when constructor's prototype property points elsewhere", function() {
				var object = {
					constructor: function TheConstructor() {}
				};
				var node = newNode("name", object);
				expect(node.name()).to.equal("name");
			});
		});

		describe("type", function() {
			it("is based on prototype's constructor name", function() {
				var proto = {
					constructor: function TheConstructor() {}
				};

				var object = Object.create(proto);
				object.constructor = function NotThisOne() {};

				var node = newNode("name", object);
				expect(node.type()).to.equal("TheConstructor");
			});

			it("works even when prototype's constructor is inherited", function() {
				var grandfather = {
					constructor: function TheConstructor() {}
				};
				var proto = Object.create(grandfather);
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("TheConstructor");
			});

			it("is root when object has no prototype", function() {
				var node = newNode("name", Object.create(null));
				expect(node.type()).to.equal("<root>");
			});

			it("is anonymous when constructor has no name", function() {
				var proto = {
					constructor: function() {}
				};
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});

			it("is anonymous when prototype has no constructor", function() {
				var proto = Object.create(null);
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});

			it("is anonymous when prototype constructor is not a function", function() {
				var proto = {
					constructor: "malformed constructor"
				};
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});

			it("is anonymous when prototype constructor is null", function() {
				var proto = {
					constructor: null
				};
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});
		});

		describe("equals", function() {
			it("is equal when objects have same identity, regardless of name", function() {
				var object = {};
				var node1 = newNode("name", object);
				var node2 = newNode("different name", object);
				expect(node1.equals(node2)).to.be(true);
			});

			it("is not equal when objects have different identify, even if they have same contents", function() {
				var node1 = newNode("name", {});
				var node2 = newNode("name", {});
				expect(node1.equals(node2)).to.be(false);
			});
		});

		describe("fields", function() {
			function fields(object) {
				var node = newNode("name", object);
				var result = node.properties();
				result.push(node.prototype());
				return result;
			}

			function conversionOf(variable) {
				var object = { name: variable };
				return fields(object)[0].value;
			}

			it("provides each field and the prototype", function() {
				var object = {
					a: 1,
					b: 2,
					c: 3
				};
				expect(fields(object)).to.eql([
					{ name: "a", value: "1", id: "f0" },
					{ name: "b", value: "2", id: "f1" },
					{ name: "c", value: "3", id: "f2" },
					{ name: "<prototype>", value: "Object.prototype", id: "proto" }
				]);
			});

			it("converts primitives", function() {
				expect(conversionOf(undefined)).to.equal("undefined");
				expect(conversionOf(null)).to.equal("null");

				expect(conversionOf(true)).to.equal("true");
				expect(conversionOf(false)).to.equal("false");

				expect(conversionOf(0)).to.equal("0");
				expect(conversionOf(1)).to.equal("1");

				expect(conversionOf("string")).to.equal('"string"');
			});

			it("converts functions", function() {
				expect(conversionOf(function aFunction() {})).to.equal("aFunction()");
				expect(conversionOf(function () {})).to.equal("<anon>()");
			});

			it("converts objects to their names when they have one", function() {
				function MyClass() {}
				expect(conversionOf(MyClass.prototype)).to.equal("MyClass.prototype");
			});

			it("converts objects to their types when they don't have a name", function() {
				expect(conversionOf({})).to.equal("{Object}");
			});

			it("handles 'Function' special case", function() {
				expect(conversionOf(Function.prototype)).to.equal("Function");
			});

			it("converts the prototype in the same way as other fields", function() {
				function MyClass() {}
				expect(fields(new MyClass())).to.eql([
					{ name: "<prototype>", value: "MyClass.prototype", id: "proto" }
				]);
			});
		});

		describe("sub-nodes", function() {
			function subNodes(object) {
				var result = [];
				var node = newNode("name", object);
				node.forEachSubNode(function(subnode) {
					result.push(subnode.name());
				});
				return result;
			}

			it("provides each function and object, and the prototype", function() {
				function MyClass() {}
				var object = new MyClass();
				object.a = function aFunction() {};
				object.b = Array.prototype;

				expect(subNodes(object)).to.eql([
					"aFunction()",
					"Array.prototype",
					"MyClass.prototype"
				]);
			});

			it("skips null, undefined, and primitives", function() {
				var object = {
					a: true,
					b: "string",
					c: 10,
					d: undefined,
					e: null
				};
				expect(subNodes(object)).to.eql([
					"Object.prototype"
				]);
			});

			it("skips prototype if it's null", function() {
				expect(subNodes(Object.create(null))).to.eql([]);
			});

			it("provides fallback name based on property name", function() {
				var proto = Object.create(null);
				var object = Object.create(proto);
				object.a = {
					b: {}
				};
				expect(subNodes(object)).to.eql([
					"name.a",
					"name.<prototype>"
				]);
			});

			it("provides id and name that matches field id and name", function() {
				var object = {
					a: 1,
					b: {}
				};
				var indexes = [];
				newNode("name", object).forEachSubNode(function(subnode, index, name) {
					indexes.push({ index: index, name: name });
				});
				expect(indexes).to.eql([
					{ index: "f1", name: "b" },
					{ index: "proto", name: "<prototype>" }
				]);
			});

		});

	});
}());<commit_msg>Separated ObjectNode.prototype() test from ObjectNode.properties() tests<commit_after>// Copyright (c) 2012 Titanium I.T. LLC. All rights reserved. See LICENSE.txt for details.

(function() {
	"use strict";
	mocha.setup({ignoreLeaks: true});

	describe("ObjectNode", function() {
		function newNode(name, object) {
			return new jdls.ObjectNode(name, object);
		}

		describe("id", function() {
			it("is unique for each node object regardless of contents", function() {
				var object = {};
				var node1 = newNode("name", object);
				var node2 = newNode("name", object);
				expect(node1.id()).to.not.equal(node2.id());
			});
		});

		describe("name", function() {
			it("is based on provided name for most objects", function() {
				var node = newNode("name", {});
				expect(node.name()).to.equal("name");
			});

			it("doesn't crash when object has no prototype", function() {
				var node = newNode("name", Object.create(null));
				expect(node.name()).to.equal("name");
			});

			it("uses function name for functions", function() {
				var node = newNode("name", function aFunction() {});
				expect(node.name()).to.equal("aFunction()");
			});

			it("is anonymous for unnamed functions", function() {
				var node = newNode("name", function() {});
				expect(node.name()).to.equal("<anon>()");
			});

			it("handles 'Function' special case", function() {
				var node = newNode("name", Function.prototype);
				expect(node.name()).to.equal("Function.prototype");
			});

			it("uses constructor name when present", function() {
				function TheConstructor() {}
				var node = newNode("name", TheConstructor.prototype);
				expect(node.name()).to.equal("TheConstructor.prototype");
			});

			it("does not use inherited constructor name", function() {
				var proto = {
					constructor: function TheConstructor() {}
				};
				var object = Object.create(proto);
				var node = newNode("name", object);
				expect(node.name()).to.equal("name");
			});

			it("does not use constructor name when constructor's prototype property points elsewhere", function() {
				var object = {
					constructor: function TheConstructor() {}
				};
				var node = newNode("name", object);
				expect(node.name()).to.equal("name");
			});
		});

		describe("type", function() {
			it("is based on prototype's constructor name", function() {
				var proto = {
					constructor: function TheConstructor() {}
				};

				var object = Object.create(proto);
				object.constructor = function NotThisOne() {};

				var node = newNode("name", object);
				expect(node.type()).to.equal("TheConstructor");
			});

			it("works even when prototype's constructor is inherited", function() {
				var grandfather = {
					constructor: function TheConstructor() {}
				};
				var proto = Object.create(grandfather);
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("TheConstructor");
			});

			it("is root when object has no prototype", function() {
				var node = newNode("name", Object.create(null));
				expect(node.type()).to.equal("<root>");
			});

			it("is anonymous when constructor has no name", function() {
				var proto = {
					constructor: function() {}
				};
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});

			it("is anonymous when prototype has no constructor", function() {
				var proto = Object.create(null);
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});

			it("is anonymous when prototype constructor is not a function", function() {
				var proto = {
					constructor: "malformed constructor"
				};
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});

			it("is anonymous when prototype constructor is null", function() {
				var proto = {
					constructor: null
				};
				var node = newNode("name", Object.create(proto));
				expect(node.type()).to.equal("<anon>");
			});
		});

		describe("equals", function() {
			it("is equal when objects have same identity, regardless of name", function() {
				var object = {};
				var node1 = newNode("name", object);
				var node2 = newNode("different name", object);
				expect(node1.equals(node2)).to.be(true);
			});

			it("is not equal when objects have different identify, even if they have same contents", function() {
				var node1 = newNode("name", {});
				var node2 = newNode("name", {});
				expect(node1.equals(node2)).to.be(false);
			});
		});

		describe("properties", function() {
			function properties(object) {
				var node = newNode("name", object);
				return node.properties();
			}

			function conversionOf(variable) {
				var object = { name: variable };
				return properties(object)[0].value;
			}

			it("provides each property", function() {
				var object = {
					a: 1,
					b: 2,
					c: 3
				};
				expect(properties(object)).to.eql([
					{ name: "a", value: "1", id: "f0" },
					{ name: "b", value: "2", id: "f1" },
					{ name: "c", value: "3", id: "f2" }
				]);
			});

			it("converts primitives", function() {
				expect(conversionOf(undefined)).to.equal("undefined");
				expect(conversionOf(null)).to.equal("null");

				expect(conversionOf(true)).to.equal("true");
				expect(conversionOf(false)).to.equal("false");

				expect(conversionOf(0)).to.equal("0");
				expect(conversionOf(1)).to.equal("1");

				expect(conversionOf("string")).to.equal('"string"');
			});

			it("converts functions", function() {
				expect(conversionOf(function aFunction() {})).to.equal("aFunction()");
				expect(conversionOf(function () {})).to.equal("<anon>()");
			});

			it("converts objects to their names when they have one", function() {
				function MyClass() {}
				expect(conversionOf(MyClass.prototype)).to.equal("MyClass.prototype");
			});

			it("converts objects to their types when they don't have a name", function() {
				expect(conversionOf({})).to.equal("{Object}");
			});

			it("handles 'Function' special case", function() {
				expect(conversionOf(Function.prototype)).to.equal("Function");
			});
		});

		describe("prototype", function() {
			function prototype(object) {
				var node = newNode("name", object);
				return node.prototype();
			}

			it("converts the same way as fields", function() {
				function MyClass() {}
				expect(prototype(new MyClass())).to.eql({ name: "<prototype>", value: "MyClass.prototype", id: "proto" });
			});
		});

		describe("sub-nodes", function() {
			function subNodes(object) {
				var result = [];
				var node = newNode("name", object);
				node.forEachSubNode(function(subnode) {
					result.push(subnode.name());
				});
				return result;
			}

			it("provides each function and object, and the prototype", function() {
				function MyClass() {}
				var object = new MyClass();
				object.a = function aFunction() {};
				object.b = Array.prototype;

				expect(subNodes(object)).to.eql([
					"aFunction()",
					"Array.prototype",
					"MyClass.prototype"
				]);
			});

			it("skips null, undefined, and primitives", function() {
				var object = {
					a: true,
					b: "string",
					c: 10,
					d: undefined,
					e: null
				};
				expect(subNodes(object)).to.eql([
					"Object.prototype"
				]);
			});

			it("skips prototype if it's null", function() {
				expect(subNodes(Object.create(null))).to.eql([]);
			});

			it("provides fallback name based on property name", function() {
				var proto = Object.create(null);
				var object = Object.create(proto);
				object.a = {
					b: {}
				};
				expect(subNodes(object)).to.eql([
					"name.a",
					"name.<prototype>"
				]);
			});

			it("provides id and name that matches field id and name", function() {
				var object = {
					a: 1,
					b: {}
				};
				var indexes = [];
				newNode("name", object).forEachSubNode(function(subnode, index, name) {
					indexes.push({ index: index, name: name });
				});
				expect(indexes).to.eql([
					{ index: "f1", name: "b" },
					{ index: "proto", name: "<prototype>" }
				]);
			});

		});

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


<commit_before>var { URL } = window;
var defaultScope = {
    hasInstance: false,
    btn: button,
};
var choose = function () {
    var elem = this;
    var { uploadto } = this;
    chooseFile('image/*').then(function ([file]) {

        if (URL) {
            var url = URL.createObjectURL(file);
            elem.value = url;
            dispatch(elem, 'change');
            if (uploadto) {
                uploadto = uploadto.replace(/\/+$/, '') + "/";
                var serverUrl = uploadto + url.replace(/^[\s\S]*?([\w\-]+)$/, "$1");
                cross("put", serverUrl).send(file).done(function (resposne) {
                    elem.value = serverUrl;
                    dispatch(elem, 'change');
                });
            }
        }
        elem.hasInstance = true;
    });
};

var build = function () {
    var elem = this;
    var { $scope = {} } = elem;
    elem.choose = choose;
    extendIfNeeded($scope, defaultScope);
    render(elem, $scope);
};

function main(elem = div()) {
    var { uploadto } = elem;
    elem.innerHTML = image;
    if (!uploadto) {
        uploadto = elem.getAttribute("uploadto");
    }
    care(elem, function (src) {
        css(elem, {
            backgroundImage: `url('${src}')`
        });
        this.$scope.hasInstance = !!src;
        render.refresh();
    }, false);
    build.call(elem);
    return elem;
}<commit_msg>解决选择图片后不显示的问题<commit_after>var { URL } = window;
var defaultScope = {
    hasInstance: false,
    btn: button,
    setValue(src) {
        if (this.value === src) return;
        this.value = src;
        cast(this, src);
    },
};
var choose = function () {
    var elem = this;
    var { uploadto } = this;
    chooseFile('image/*').then(function ([file]) {

        if (URL) {
            var url = URL.createObjectURL(file);
            elem.value = url;
            cast(elem, url);
            dispatch(elem, 'change');
            if (uploadto) {
                uploadto = uploadto.replace(/\/+$/, '') + "/";
                var serverUrl = uploadto + url.replace(/^[\s\S]*?([\w\-]+)$/, "$1");
                cross("put", serverUrl).send(file).done(function (resposne) {
                    elem.value = serverUrl;
                    cast(elem, serverUrl);
                    dispatch(elem, 'change');
                });
            }
        }
        elem.hasInstance = true;
    });
};

var build = function () {
    var elem = this;
    var { $scope = {} } = elem;
    elem.choose = choose;
    extendIfNeeded($scope, defaultScope);
    render(elem, $scope);
};

function main(elem = div()) {
    var { uploadto } = elem;
    elem.innerHTML = image;
    if (!uploadto) {
        uploadto = elem.getAttribute("uploadto");
    }
    care(elem, function (src) {
        css(elem, {
            backgroundImage: `url('${src}')`
        });
        this.$scope.hasInstance = !!src;
        render.refresh();
    }, false);
    build.call(elem);
    return elem;
}<|endoftext|>


<commit_before>import * as ActionTypes from '../constants/actionTypes';
import _ from 'underscore';
import { validationError } from './utils';
import { get, put, del } from '../utils/fetch';
import { validator } from '../utils/validation';
import {
  getParserErrorMessage,
  getContentRequiredMessage,
  getFilenameRequiredMessage
} from '../constants/lang';
import {
  datafilesAPIUrl,
  datafileAPIUrl
} from '../constants/api';

export function fetchDataFiles() {
  return (dispatch) => {
    dispatch({ type: ActionTypes.FETCH_DATAFILES_REQUEST});
    return get(
      datafilesAPIUrl(),
      { type: ActionTypes.FETCH_DATAFILES_SUCCESS, name: "files"},
      { type: ActionTypes.FETCH_DATAFILES_FAILURE, name: "error"},
      dispatch
    );
  };
}

export function fetchDataFile(filename) {
  return (dispatch) => {
    dispatch({ type: ActionTypes.FETCH_DATAFILE_REQUEST});
    return get(
      datafileAPIUrl(filename),
      { type: ActionTypes.FETCH_DATAFILE_SUCCESS, name: "file"},
      { type: ActionTypes.FETCH_DATAFILE_FAILURE, name: "error"},
      dispatch
    );
  };
}

export function putDataFile(filename, data) {
  return (dispatch, getState) => {
    const errors = validateDatafile(filename, data);
    if (errors.length) {
      return dispatch(validationError(errors));
    }
    // clear errors
    dispatch({type: ActionTypes.CLEAR_ERRORS});
    return put(
      datafileAPIUrl(filename),
      JSON.stringify({ raw_content: data }),
      { type: ActionTypes.PUT_DATAFILE_SUCCESS, name: "file"},
      { type: ActionTypes.PUT_DATAFILE_FAILURE, name: "error"},
      dispatch
    );
  };
}

function validateDatafile(filename, data) {
  return validator(
    { filename, data },
    { 'filename': 'required', 'data': 'required' },
    {
      'filename.required': getFilenameRequiredMessage(),
      'data.required': getContentRequiredMessage()
    }
  );
}

export function deleteDataFile(filename) {
  return (dispatch) => {
    return fetch(datafileAPIUrl(filename), {
      method: 'DELETE'
    })
    .then(data => {
      dispatch({ type: ActionTypes.DELETE_DATAFILE_SUCCESS });
      dispatch(fetchDataFiles());
    })
    .catch(error => dispatch({
      type: ActionTypes.DELETE_DATAFILE_FAILURE,
      error
    }));
  };
}

export function onDataFileChanged() {
  return {
    type: ActionTypes.DATAFILE_CHANGED
  };
}
<commit_msg>update datafiles action to support multiple views<commit_after>import * as ActionTypes from '../constants/actionTypes';
import _ from 'underscore';
import { validationError } from './utils';
import { get, put, del } from '../utils/fetch';
import { toYAML } from '../utils/helpers';
import { validator } from '../utils/validation';
import {
  getParserErrorMessage,
  getContentRequiredMessage,
  getFilenameRequiredMessage
} from '../constants/lang';
import {
  datafilesAPIUrl,
  datafileAPIUrl
} from '../constants/api';

export function fetchDataFiles() {
  return (dispatch) => {
    dispatch({ type: ActionTypes.FETCH_DATAFILES_REQUEST});
    return get(
      datafilesAPIUrl(),
      { type: ActionTypes.FETCH_DATAFILES_SUCCESS, name: "files"},
      { type: ActionTypes.FETCH_DATAFILES_FAILURE, name: "error"},
      dispatch
    );
  };
}

export function fetchDataFile(filename) {
  return (dispatch) => {
    dispatch({ type: ActionTypes.FETCH_DATAFILE_REQUEST});
    return get(
      datafileAPIUrl(filename),
      { type: ActionTypes.FETCH_DATAFILE_SUCCESS, name: "file"},
      { type: ActionTypes.FETCH_DATAFILE_FAILURE, name: "error"},
      dispatch
    );
  };
}

export function putDataFile(filename, data, source) {
  return (dispatch, getState) => {
    let payload = {};
    if (source == "editor") {
      const errors = validateDatafile(filename, data);
      if (errors.length) {
        return dispatch(validationError(errors));
      }
      // clear errors
      dispatch({type: ActionTypes.CLEAR_ERRORS});
      payload = { raw_content: data };
    } else if (source == "gui") {
      const metadata = getState().metadata.metadata;
      const yaml_string = toYAML(metadata);
      payload = { raw_content: yaml_string };
    }
    return put(
      datafileAPIUrl(filename),
      JSON.stringify(payload),
      { type: ActionTypes.PUT_DATAFILE_SUCCESS, name: "file"},
      { type: ActionTypes.PUT_DATAFILE_FAILURE, name: "error"},
      dispatch
    );
  };
}

function validateDatafile(filename, data) {
  return validator(
    { filename, data },
    { 'filename': 'required', 'data': 'required' },
    {
      'filename.required': getFilenameRequiredMessage(),
      'data.required': getContentRequiredMessage()
    }
  );
}

export function deleteDataFile(filename) {
  return (dispatch) => {
    return fetch(datafileAPIUrl(filename), {
      method: 'DELETE'
    })
    .then(data => {
      dispatch({ type: ActionTypes.DELETE_DATAFILE_SUCCESS });
      dispatch(fetchDataFiles());
    })
    .catch(error => dispatch({
      type: ActionTypes.DELETE_DATAFILE_FAILURE,
      error
    }));
  };
}

export function onDataFileChanged() {
  return {
    type: ActionTypes.DATAFILE_CHANGED
  };
}
<|endoftext|>


<commit_before>module.exports = {
    name: "military",
    title: "Military",
    description: "Single Tribes count as 2 Tribes during Attacks",
    points: 8,
    cost: { 'tribes': 4, 'gold': 3 },
    resources: [ 'stone', 'food' ],
    requires: [ 'government' ],
    required_by: [ 'centralized_government' ],
    events: {
        'attack': {
            'steps': {
                '3.1': "+ If you have {{ adv:military }}, \
                Reduce 2 Attacking Force by reducing 1 Tribe. {% tribe_reduce = 2; has_mm = false; %}",
                '3.3': "+ If you have both {{ adv:military }} and {{ adv:metal_working }}, \
                Reduce 3 Attacking Force by reducing 1 Tribe. \
                {% if (has_mm) tribe_reduce = 3 %}"
            }
        },
        'civil_war': {
            'steps': {
                '2.1': "- If you have {{ adv:military }}, Reduce City AV in \
                        Neighboring Regions by 3 instead of 2.\
                        {% neighbourCityReduce = -3 %}"
            }
        },
    },
    acquired: function() { },
    phases: { },
    actions: { }
}<commit_msg>Uprising and Military (fixes #4)<commit_after>var reducer = require("../core/reducer");

module.exports = {
    name: "military",
    title: "Military",
    description: "Single Tribes count as 2 Tribes during Attacks",
    points: 8,
    cost: { 'tribes': 4, 'gold': 3 },
    resources: [ 'stone', 'food' ],
    requires: [ 'government' ],
    required_by: [ 'centralized_government' ],
    events: {
        'attack': {
            'steps': {
                '3.1': "+ If you have {{ adv:military }}, \
                Reduce 2 Attacking Force by reducing 1 Tribe. {% tribe_reduce = 2; has_mm = false; %}",
                '3.3': "+ If you have both {{ adv:military }} and {{ adv:metal_working }}, \
                Reduce 3 Attacking Force by reducing 1 Tribe. \
                {% if (has_mm) tribe_reduce = 3 %}"
            }
        },
        'civil_war': {
            'steps': {
                '2.1': "- If you have {{ adv:military }}, Reduce City AV in \
                        Neighboring Regions by 3 instead of 2.\
                        {% neighbourCityReduce = -3 %}"
            }
        },
        'uprising': {
            'steps': {
                '4': "- If you have {{ adv:military }}, Select a Neighboring \
Region with a City. Reduce Neighboring City \
AV by 1. Decimate Tribes in selected \
Neighboring Region, unless you have \
Organized Religion, then reduce Neighboring Tribes by 2.\
{%; reduceNeighbour() %}"
            },
            reduceNeighbour: function() {
                var ctx = this;
                var engine = this.engine;
                var initial = _.pick(engine.map.areas, function(area, ak) {
                    ak = parseInt(ak);
                    return (_.contains(this.active_region.neighbours, ak) &&
                        area.city > 0);

                },this);
                var opts = reducer.Templates.basic(ctx, ['city']);
                opts.initial = initial;
                opts.tribeChange = tribeChange;
                opts.amount = 1;
                opts.edits = [];
                opts.shows = ['city', 'tribes'];
                opts.reduce = function(key) {
                    this.amount--;
                    var ret = { 'city': this.initial[key].city-1 };
                    if (this.opts.tribeChange == "0")
                        ret.tribes = 0;
                    else
                        ret.tribes = this.initial[key].tribes + parseInt(this.opts.tribeChange);
                    return ret;
                }
                engine.reducer(new reducer.Reducer(opts), function(chg) {
                    ctx.merge(chg);
                    ctx.done && ctx.done();
                });
            }
        }
    },
    acquired: function() { },
    phases: { },
    actions: { }
}<|endoftext|>


<commit_before>define(function() {
    return {
        'search-menu-free'  : gettext('Free text search'),
        'search-term-prefix': gettext('Search for')
    };

});
<commit_msg>Fixed text for previous search terms prefix<commit_after>define(function() {
    return {
        'search-menu-free'  : gettext('Free text search'),
        'search-term-prefix': gettext('Search for "')
    };

});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Bands = require('../../impl/bands.js').Bands;
var formatComputedObject =
    require('../helpers/format-computed-object.js').formatComputedObject;

var createImage = function(values, startDate) {
  var image = ee.Dictionary(values).toImage().int64();
  if (startDate) {
    image = image.set('system:time_start', ee.Date(startDate).millis());
  }
  return image;
};

withEarthEngineStub('Bands', function() {
  it('getSpectralIndices()', function() {
    var testImage = ee.Image([0]);
    var testIndices = ['ndvi', 'evi'];
    var result = Bands.getSpectralIndices(testImage, testIndices);
    expect(result.length).toEqual(2);
    expect(result[0].name()).toEqual('Image');
    expect(result[1].name()).toEqual('Image');
  });

  it('getSpectralIndices() fails on bad index name', function() {
    var testImage = ee.Image([0]);
    var testIndices = ['ndvi', 'foo'];
    expect(function() {
      Bands.getSpectralIndices(testImage, testIndices);
    }).toThrow();
  });

  fit('getSpectralIndices() fails on bad index name', function() {
    var testImage = ee.Image([0]);
    var testIndices = ee.Array(['ndvi', 'foo']);
    // expect(function() {
      Bands.getSpectralIndices(testImage, testIndices);
    // }).toThrow();
  });
});<commit_msg>Fix minimal unit tests<commit_after>/**
 * @license
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var Bands = require('../../impl/bands.js').Bands;
var formatComputedObject =
    require('../helpers/format-computed-object.js').formatComputedObject;

var createImage = function(values, startDate) {
  var image = ee.Dictionary(values).toImage().int64();
  if (startDate) {
    image = image.set('system:time_start', ee.Date(startDate).millis());
  }
  return image;
};

withEarthEngineStub('Bands', function() {
  it('getSpectralIndices()', function() {
    var testImage = ee.Image([0]);
    var testIndices = ['ndvi', 'evi'];
    var result = Bands.getSpectralIndices(testImage, testIndices);
    expect(result.name()).toEqual('Image');
  });

  it('getSpectralIndices() fails on bad index name', function() {
    var testImage = ee.Image([0]);
    var testIndices = ['ndvi', 'foo'];
    expect(function() {
      Bands.getSpectralIndices(testImage, testIndices);
    }).toThrow();
  });

  it('getSpectralIndices() with ee.List', function() {
    var testImage = ee.Image([0]);
    var testIndices = ee.List(['ndvi', 'evi']);
    var result = Bands.getSpectralIndices(testImage, testIndices);
    expect(result.name()).toEqual('Image');
  });
});<|endoftext|>