<commit_before>/*
 * Copyright 2020 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.
 */

/**
 * External dependencies
 */
import { useEffect, useRef } from 'react';
import propTypes from 'prop-types';
import styled from 'styled-components';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { TranslateWithMarkup } from '../../../../../i18n';
import { SettingForm, SettingHeading, FormLabel } from '../components';

const CheckBox = styled.input.attrs({
  type: 'checkbox',
  id: 'telemetry-opt-in',
})`
  height: 18px;
  width: 18px;
  margin: 0 12px 0 0;
  flex: 1 0 18px;
`;

const Label = styled.label.attrs({ htmlFor: 'telemetry-opt-in' })`
  display: flex;
  justify-content: flex-start;
`;

export default function TelemetrySettings({
  selected,
  onCheckboxSelected,
  disabled,
}) {
  const checkboxRef = useRef();
  const focusOnCheckbox = useRef(false);

  const checked = Boolean(selected);

  useEffect(() => {
    if (focusOnCheckbox.current) {
      checkboxRef.current.focus();
    }
  });

  return (
    <SettingForm>

        <SettingHeading>
          {__('Data Sharing Opt-in', 'web-stories')}
        </SettingHeading>

          <CheckBox
            ref={checkboxRef}
            data-testid="telemetry-settings-checkbox"
            disabled={disabled}
            onChange={() => {
              onCheckboxSelected();
              focusOnCheckbox.current = true;
            }}
            onBlur={() => {
              focusOnCheckbox.current = false;
            }}
            checked={checked}
          />
          <FormLabel aria-checked={checked}>
            <TranslateWithMarkup
              mapping={{
                a: (
                  //eslint-disable-next-line jsx-a11y/anchor-has-content

                ),
              }}
            >
              {__(
                'Check the box to help us improve the Web Stories plugin by allowing tracking of product usage stats. All data are treated in accordance with Google Privacy Policy.',
                'web-stories'
              )}
            </TranslateWithMarkup>
          </FormLabel>

    </SettingForm>
  );
}

TelemetrySettings.propTypes = {
  disabled: propTypes.bool.isRequired,
  selected: propTypes.bool.isRequired,
  onCheckboxSelected: propTypes.func.isRequired,
};
<commit_msg>restoring aria label post merge<commit_after>/*
 * Copyright 2020 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.
 */

/**
 * External dependencies
 */
import { useEffect, useRef } from 'react';
import propTypes from 'prop-types';
import styled from 'styled-components';

/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';

/**
 * Internal dependencies
 */
import { TranslateWithMarkup } from '../../../../../i18n';
import { SettingForm, SettingHeading, FormLabel } from '../components';

const CheckBox = styled.input.attrs({
  type: 'checkbox',
  id: 'telemetry-opt-in',
})`
  height: 18px;
  width: 18px;
  margin: 0 12px 0 0;
  flex: 1 0 18px;
`;

const Label = styled.label.attrs({ htmlFor: 'telemetry-opt-in' })`
  display: flex;
  justify-content: flex-start;
`;

export default function TelemetrySettings({
  selected,
  onCheckboxSelected,
  disabled,
}) {
  const checkboxRef = useRef();
  const focusOnCheckbox = useRef(false);

  const checked = Boolean(selected);

  useEffect(() => {
    if (focusOnCheckbox.current) {
      checkboxRef.current.focus();
    }
  });

  return (
    <SettingForm>

        <SettingHeading>
          {__('Data Sharing Opt-in', 'web-stories')}
        </SettingHeading>

          <CheckBox
            ref={checkboxRef}
            data-testid="telemetry-settings-checkbox"
            disabled={disabled}
            onChange={() => {
              onCheckboxSelected();
              focusOnCheckbox.current = true;
            }}
            onBlur={() => {
              focusOnCheckbox.current = false;
            }}
            checked={checked}
          />
          <FormLabel aria-checked={checked}>
            <TranslateWithMarkup
              mapping={{
                a: (
                  //eslint-disable-next-line jsx-a11y/anchor-has-content

                ),
              }}
            >
              {__(
                'Check the box to help us improve the Web Stories plugin by allowing tracking of product usage stats. All data are treated in accordance with Google Privacy Policy.',
                'web-stories'
              )}
            </TranslateWithMarkup>
          </FormLabel>

    </SettingForm>
  );
}

TelemetrySettings.propTypes = {
  disabled: propTypes.bool.isRequired,
  selected: propTypes.bool.isRequired,
  onCheckboxSelected: propTypes.func.isRequired,
};
<|endoftext|>


<commit_before>/* eslint-disable import/no-dynamic-require */

import React from 'react'
import path from 'path'
import chokidar from 'chokidar'

import { pathJoin } from '../utils/shared'
import { reloadRoutes } from './webpack'
import getDirname from '../utils/getDirname'

const REGEX_TO_CUT_TO_ROOT = /(\..+?)\/.*/g
const REGEX_TO_REMOVE_TRAILING_SLASH = /^\/{0,}/g
const REGEX_TO_REMOVE_LEADING_SLASH = /\/{0,}$/g

const DEFAULT_NAME_FOR_STATIC_CONFIG_FILE = 'static.config.js'
// the default static.config.js location
const DEFAULT_PATH_FOR_STATIC_CONFIG = path.resolve(
  path.join(process.cwd(), DEFAULT_NAME_FOR_STATIC_CONFIG_FILE)
)
const DEFAULT_ROUTES = [{ path: '/' }]
const DEFAULT_ENTRY = 'index.js'
const PATH_404 = '404'

export const cutPathToRoot = (string = '') => string.replace(REGEX_TO_CUT_TO_ROOT, '$1')

export const trimLeadingAndTrailingSlashes = (string = '') =>
  string.replace(REGEX_TO_REMOVE_TRAILING_SLASH, '').replace(REGEX_TO_REMOVE_LEADING_SLASH, '')

export const throwErrorIfRouteIsMissingPath = route => {
  const { path, is404 = false } = route

  if (!is404 && !path) {
    throw new Error(`No path defined for route: ${JSON.stringify(route)}`)
  }
}

const consoleWarningForRouteWithoutNoIndex = route =>
  route.noIndex &&
  console.warn(`=> Warning: Route ${route.path} is using 'noIndex'. Did you mean 'noindex'?`)

export const createNormalizedRoute = (route, parent = {}, config = {}) => {
  const { children, ...routeWithOutChildren } = route
  const { path: parentPath = '/' } = parent
  const { tree: keepRouteChildren = false } = config
  const { is404 = false } = route

  throwErrorIfRouteIsMissingPath(route)

  const originalRoutePath = is404 ? PATH_404 : pathJoin(route.path)
  const routePath = is404 ? PATH_404 : pathJoin(parentPath, route.path)

  consoleWarningForRouteWithoutNoIndex(route)

  const normalizedRoute = {
    ...(keepRouteChildren ? route : routeWithOutChildren),
    path: routePath,
    originalPath: originalRoutePath,
    noindex: route.noindex || parent.noindex || route.noIndex,
    hasGetProps: !!route.getData,
  }

  return normalizedRoute
}

export const consoleWarningForMutlipleRoutesWithTheSamePath = routes => {
  routes.forEach(route => {
    const found = routes.filter(r => r.path === route.path)
    if (found.length > 1) {
      console.warn('More than one route is defined for path:', route.path)
    }
  })
}

const recurseCreateNormalizedRoute = (routes = [], parent, config) => {
  if (config.tree) {
    return routes
      .map(route => {
        const normalizedRoute = createNormalizedRoute(route, parent, config)
        normalizedRoute.children = recurseCreateNormalizedRoute(
          normalizedRoute.children,
          normalizedRoute,
          config
        )
        return normalizedRoute
      })
      .filter(d => d !== null)
  }

  return routes.reduce((memo = [], route) => {
    const normalizedRoute = createNormalizedRoute(route, parent, config)
    const routeExists = memo.find(({ path }) => path === normalizedRoute.path)

    return [
      ...memo,
      ...recurseCreateNormalizedRoute(route.children, normalizedRoute, config),
      ...(routeExists ? [] : [normalizedRoute]),
    ]
  }, [])
}

// Normalize routes with parents, full paths, context, etc.
export const normalizeRoutes = (routes, config = {}) => {
  const { disableDuplicateRoutesWarning, force404 = true } = config
  const normalizedRoutes = recurseCreateNormalizedRoute(routes, {}, config)

  if (!disableDuplicateRoutesWarning) {
    consoleWarningForMutlipleRoutesWithTheSamePath(normalizedRoutes)
  }

  if (force404 && !normalizedRoutes.find(r => r.is404)) {
    normalizedRoutes.push(
      createNormalizedRoute({
        is404: true,
        path: PATH_404,
      }),
      config
    )
  }

  return normalizedRoutes
}

// At least ensure the index page is defined for export
export const makeGetRoutes = config => async (...args) => {
  const { getRoutes = async () => DEFAULT_ROUTES } = config
  const routes = await getRoutes(...args)
  return normalizeRoutes(routes, config)
}

export const buildConfigation = (config = {}) => {
  // path defaults
  config.paths = {
    root: path.resolve(process.cwd()),
    src: 'src',
    dist: 'dist',
    devDist: 'tmp/dev-server',
    public: 'public',
    ...(config.paths || {}),
  }

  // Use the root to resolve all other relative paths
  const resolvePath = relativePath => path.resolve(config.paths.root, relativePath)

  // Resolve all paths
  const distPath =
    process.env.REACT_STATIC_ENV === 'development'
      ? resolvePath(config.paths.devDist || config.paths.dist)
      : resolvePath(config.paths.dist)

  const paths = {
    ROOT: config.paths.root,
    LOCAL_NODE_MODULES: path.resolve(getDirname(), '../../node_modules'),
    SRC: resolvePath(config.paths.src),
    DIST: distPath,
    PUBLIC: resolvePath(config.paths.public),
    NODE_MODULES: resolvePath('node_modules'),
    PACKAGE: resolvePath('package.json'),
    HTML_TEMPLATE: path.join(distPath, 'index.html'),
    STATIC_DATA: path.join(distPath, 'staticData'),
  }

  // Defaults
  const finalConfig = {
    // Defaults
    entry: path.join(paths.SRC, DEFAULT_ENTRY),
    getSiteData: () => ({}),
    renderToHtml: (render, Comp) => render(<Comp />),
    prefetchRate: 3,
    disableRouteInfoWarning: false,
    disableRoutePrefixing: false,
    outputFileRate: 10,
    // Config Overrides
    ...config,
    // Materialized Overrides
    paths,
    siteRoot: cutPathToRoot(config.siteRoot, '$1'),
    stagingSiteRoot: cutPathToRoot(config.stagingSiteRoot, '$1'),
    basePath: trimLeadingAndTrailingSlashes(config.basePath),
    stagingBasePath: trimLeadingAndTrailingSlashes(config.stagingBasePath),
    devBasePath: trimLeadingAndTrailingSlashes(config.devBasePath),
    extractCssChunks: config.extractCssChunks || false,
    inlineCss: config.inlineCss || false,
    getRoutes: makeGetRoutes(config),
  }

  // Set env variables to be used client side
  process.env.REACT_STATIC_PREFETCH_RATE = finalConfig.prefetchRate
  process.env.REACT_STATIC_DISABLE_ROUTE_INFO_WARNING = finalConfig.disableRouteInfoWarning
  process.env.REACT_STATIC_DISABLE_ROUTE_PREFIXING = finalConfig.disableRoutePrefixing

  return finalConfig
}

const buildConfigFromPath = configPath => {
  const filename = path.resolve(configPath)
  delete require.cache[filename]
  try {
    const config = require(configPath).default
    return buildConfigation(config)
  } catch (err) {
    return {}
  }
}

const fromFile = (configPath = DEFAULT_PATH_FOR_STATIC_CONFIG, watch) => {
  const config = buildConfigFromPath(configPath)

  if (watch) {
    chokidar.watch(configPath).on('all', () => {
      Object.assign(config, buildConfigFromPath(configPath))
      reloadRoutes()
    })
  }

  return config
}

// Retrieves the static.config.js from the current project directory
export default function getConfig (customConfig, { watch } = {}) {
  if (typeof customConfig === 'object') {
    // return a custom config obj
    return buildConfigation(customConfig)
  }

  // return a custom config file location
  // defaults to constant paath for static config
  return fromFile(customConfig, watch)
}
<commit_msg>Report errors when building configuration (#619)<commit_after>/* eslint-disable import/no-dynamic-require */

import React from 'react'
import path from 'path'
import chokidar from 'chokidar'

import { pathJoin } from '../utils/shared'
import { reloadRoutes } from './webpack'
import getDirname from '../utils/getDirname'

const REGEX_TO_CUT_TO_ROOT = /(\..+?)\/.*/g
const REGEX_TO_REMOVE_TRAILING_SLASH = /^\/{0,}/g
const REGEX_TO_REMOVE_LEADING_SLASH = /\/{0,}$/g

const DEFAULT_NAME_FOR_STATIC_CONFIG_FILE = 'static.config.js'
// the default static.config.js location
const DEFAULT_PATH_FOR_STATIC_CONFIG = path.resolve(
  path.join(process.cwd(), DEFAULT_NAME_FOR_STATIC_CONFIG_FILE)
)
const DEFAULT_ROUTES = [{ path: '/' }]
const DEFAULT_ENTRY = 'index.js'
const PATH_404 = '404'

export const cutPathToRoot = (string = '') => string.replace(REGEX_TO_CUT_TO_ROOT, '$1')

export const trimLeadingAndTrailingSlashes = (string = '') =>
  string.replace(REGEX_TO_REMOVE_TRAILING_SLASH, '').replace(REGEX_TO_REMOVE_LEADING_SLASH, '')

export const throwErrorIfRouteIsMissingPath = route => {
  const { path, is404 = false } = route

  if (!is404 && !path) {
    throw new Error(`No path defined for route: ${JSON.stringify(route)}`)
  }
}

const consoleWarningForRouteWithoutNoIndex = route =>
  route.noIndex &&
  console.warn(`=> Warning: Route ${route.path} is using 'noIndex'. Did you mean 'noindex'?`)

export const createNormalizedRoute = (route, parent = {}, config = {}) => {
  const { children, ...routeWithOutChildren } = route
  const { path: parentPath = '/' } = parent
  const { tree: keepRouteChildren = false } = config
  const { is404 = false } = route

  throwErrorIfRouteIsMissingPath(route)

  const originalRoutePath = is404 ? PATH_404 : pathJoin(route.path)
  const routePath = is404 ? PATH_404 : pathJoin(parentPath, route.path)

  consoleWarningForRouteWithoutNoIndex(route)

  const normalizedRoute = {
    ...(keepRouteChildren ? route : routeWithOutChildren),
    path: routePath,
    originalPath: originalRoutePath,
    noindex: route.noindex || parent.noindex || route.noIndex,
    hasGetProps: !!route.getData,
  }

  return normalizedRoute
}

export const consoleWarningForMutlipleRoutesWithTheSamePath = routes => {
  routes.forEach(route => {
    const found = routes.filter(r => r.path === route.path)
    if (found.length > 1) {
      console.warn('More than one route is defined for path:', route.path)
    }
  })
}

const recurseCreateNormalizedRoute = (routes = [], parent, config) => {
  if (config.tree) {
    return routes
      .map(route => {
        const normalizedRoute = createNormalizedRoute(route, parent, config)
        normalizedRoute.children = recurseCreateNormalizedRoute(
          normalizedRoute.children,
          normalizedRoute,
          config
        )
        return normalizedRoute
      })
      .filter(d => d !== null)
  }

  return routes.reduce((memo = [], route) => {
    const normalizedRoute = createNormalizedRoute(route, parent, config)
    const routeExists = memo.find(({ path }) => path === normalizedRoute.path)

    return [
      ...memo,
      ...recurseCreateNormalizedRoute(route.children, normalizedRoute, config),
      ...(routeExists ? [] : [normalizedRoute]),
    ]
  }, [])
}

// Normalize routes with parents, full paths, context, etc.
export const normalizeRoutes = (routes, config = {}) => {
  const { disableDuplicateRoutesWarning, force404 = true } = config
  const normalizedRoutes = recurseCreateNormalizedRoute(routes, {}, config)

  if (!disableDuplicateRoutesWarning) {
    consoleWarningForMutlipleRoutesWithTheSamePath(normalizedRoutes)
  }

  if (force404 && !normalizedRoutes.find(r => r.is404)) {
    normalizedRoutes.push(
      createNormalizedRoute({
        is404: true,
        path: PATH_404,
      }),
      config
    )
  }

  return normalizedRoutes
}

// At least ensure the index page is defined for export
export const makeGetRoutes = config => async (...args) => {
  const { getRoutes = async () => DEFAULT_ROUTES } = config
  const routes = await getRoutes(...args)
  return normalizeRoutes(routes, config)
}

export const buildConfigation = (config = {}) => {
  // path defaults
  config.paths = {
    root: path.resolve(process.cwd()),
    src: 'src',
    dist: 'dist',
    devDist: 'tmp/dev-server',
    public: 'public',
    ...(config.paths || {}),
  }

  // Use the root to resolve all other relative paths
  const resolvePath = relativePath => path.resolve(config.paths.root, relativePath)

  // Resolve all paths
  const distPath =
    process.env.REACT_STATIC_ENV === 'development'
      ? resolvePath(config.paths.devDist || config.paths.dist)
      : resolvePath(config.paths.dist)

  const paths = {
    ROOT: config.paths.root,
    LOCAL_NODE_MODULES: path.resolve(getDirname(), '../../node_modules'),
    SRC: resolvePath(config.paths.src),
    DIST: distPath,
    PUBLIC: resolvePath(config.paths.public),
    NODE_MODULES: resolvePath('node_modules'),
    PACKAGE: resolvePath('package.json'),
    HTML_TEMPLATE: path.join(distPath, 'index.html'),
    STATIC_DATA: path.join(distPath, 'staticData'),
  }

  // Defaults
  const finalConfig = {
    // Defaults
    entry: path.join(paths.SRC, DEFAULT_ENTRY),
    getSiteData: () => ({}),
    renderToHtml: (render, Comp) => render(<Comp />),
    prefetchRate: 3,
    disableRouteInfoWarning: false,
    disableRoutePrefixing: false,
    outputFileRate: 10,
    // Config Overrides
    ...config,
    // Materialized Overrides
    paths,
    siteRoot: cutPathToRoot(config.siteRoot, '$1'),
    stagingSiteRoot: cutPathToRoot(config.stagingSiteRoot, '$1'),
    basePath: trimLeadingAndTrailingSlashes(config.basePath),
    stagingBasePath: trimLeadingAndTrailingSlashes(config.stagingBasePath),
    devBasePath: trimLeadingAndTrailingSlashes(config.devBasePath),
    extractCssChunks: config.extractCssChunks || false,
    inlineCss: config.inlineCss || false,
    getRoutes: makeGetRoutes(config),
  }

  // Set env variables to be used client side
  process.env.REACT_STATIC_PREFETCH_RATE = finalConfig.prefetchRate
  process.env.REACT_STATIC_DISABLE_ROUTE_INFO_WARNING = finalConfig.disableRouteInfoWarning
  process.env.REACT_STATIC_DISABLE_ROUTE_PREFIXING = finalConfig.disableRoutePrefixing

  return finalConfig
}

const buildConfigFromPath = configPath => {
  const filename = path.resolve(configPath)
  delete require.cache[filename]
  try {
    const config = require(configPath).default
    return buildConfigation(config)
  } catch (err) {
    console.error(err)
    return {}
  }
}

const fromFile = (configPath = DEFAULT_PATH_FOR_STATIC_CONFIG, watch) => {
  const config = buildConfigFromPath(configPath)

  if (watch) {
    chokidar.watch(configPath).on('all', () => {
      Object.assign(config, buildConfigFromPath(configPath))
      reloadRoutes()
    })
  }

  return config
}

// Retrieves the static.config.js from the current project directory
export default function getConfig (customConfig, { watch } = {}) {
  if (typeof customConfig === 'object') {
    // return a custom config obj
    return buildConfigation(customConfig)
  }

  // return a custom config file location
  // defaults to constant paath for static config
  return fromFile(customConfig, watch)
}
<|endoftext|>


<commit_before>const getWeatherInfo = () => {
  const sendRequest = (latitude, longitude, metricSystem) => {
    fetch(`https://stellar-photos.herokuapp.com/api/weather/${latitude},${longitude},${metricSystem}`)
      .then(response => response.json())
      .then((forecast) => {
        const f = Object.assign({
          timestamp: Date.now(),
        }, forecast);

        chrome.storage.local.set({ forecast: f });
      })
      .catch(error => console.log(error));
  };

  chrome.storage.sync.get('coords', (result) => {
    const { coords } = result;
    if (!coords) return;

    const { longitude, latitude } = coords;

    chrome.storage.sync.get('tempUnit', (data) => {
      const tempUnit = data.tempUnit || 'celsius';
      const metricSystem = (tempUnit === 'fahrenheit') ? 'imperial' : 'metric';
      sendRequest(longitude, latitude, metricSystem);
    });
  });
};

const fetchRandomPhoto = () => {
  const sendRequest = (collections) => {
    fetch(`https://stellar-photos.herokuapp.com/api/photos/random/${collections}`)
      .then(response => response.json())
      .then((data) => {
        chrome.storage.local.set({ nextImage: data });

        chrome.storage.local.get('history', (result) => {
          const history = result.history || [];

          if (history.length >= 10) {
            history.pop();
          }

          history.unshift(data);
          chrome.storage.local.set({ history });
        });
      });
  };

  chrome.storage.sync.get('collections', (result) => {
    let { collections } = result;

    if (!collections) collections = '998309';

    chrome.storage.sync.set({ collections });

    sendRequest(collections);
  });
};

const loadNewData = () => {
  fetchRandomPhoto();

  chrome.storage.local.get('forecast', (result) => {
    const { forecast } = result;

    chrome.storage.sync.get('coords', (d) => {
      const { coords } = d;

      if (!forecast && coords) {
        getWeatherInfo();
        return;
      }

      if (forecast) {
        const { timestamp } = forecast;
        if (timestamp) {
          const lessThanOneHourAgo = () => {
            const oneHour = 1000 * 60 * 60;
            const oneHourAgo = Date.now() - oneHour;
            return timestamp > oneHourAgo;
          };

          if (!lessThanOneHourAgo()) {
            getWeatherInfo();
          }
        }
      }
    });
  });
};

chrome.runtime.onInstalled.addListener(fetchRandomPhoto);
chrome.runtime.onMessage.addListener((request, sender) => {
  switch (request.command) {
    case 'set-dropbox-token': {
      chrome.storage.local.set({ dropboxToken: request.token });

      chrome.notifications.create('dropbox-notification', {
        type: 'basic',
        iconUrl: chrome.extension.getURL('icons/48.png'),
        title: 'Stellar Photos',
        message: 'Dropbox authenticated successfully',
      });

      chrome.runtime.sendMessage({ command: 'update-cloud-status' });
      break;
    }

    case 'close-tab': {
      chrome.tabs.remove(sender.tab.id);
      break;
    }

    case 'update-weather': {
      getWeatherInfo();
      break;
    }

    case 'load-data': {
      loadNewData();
    }
  }
});
<commit_msg>Catch errors when fetching random photo<commit_after>const getWeatherInfo = () => {
  const sendRequest = (latitude, longitude, metricSystem) => {
    fetch(`https://stellar-photos.herokuapp.com/api/weather/${latitude},${longitude},${metricSystem}`)
      .then(response => response.json())
      .then((forecast) => {
        const f = Object.assign({
          timestamp: Date.now(),
        }, forecast);

        chrome.storage.local.set({ forecast: f });
      })
      .catch(error => console.log(error));
  };

  chrome.storage.sync.get('coords', (result) => {
    const { coords } = result;
    if (!coords) return;

    const { longitude, latitude } = coords;

    chrome.storage.sync.get('tempUnit', (data) => {
      const tempUnit = data.tempUnit || 'celsius';
      const metricSystem = (tempUnit === 'fahrenheit') ? 'imperial' : 'metric';
      sendRequest(longitude, latitude, metricSystem);
    });
  });
};

const fetchRandomPhoto = () => {
  const sendRequest = (collections) => {
    fetch(`https://stellar-photos.herokuapp.com/api/photos/random/${collections}`)
      .then(response => response.json())
      .then((data) => {
        chrome.storage.local.set({ nextImage: data });

        chrome.storage.local.get('history', (result) => {
          const history = result.history || [];

          if (history.length >= 10) {
            history.pop();
          }

          history.unshift(data);
          chrome.storage.local.set({ history });
        });
      })
      .catch(error => console.log(error));
  };

  chrome.storage.sync.get('collections', (result) => {
    let { collections } = result;

    if (!collections) collections = '998309';

    chrome.storage.sync.set({ collections });

    sendRequest(collections);
  });
};

const loadNewData = () => {
  fetchRandomPhoto();

  chrome.storage.local.get('forecast', (result) => {
    const { forecast } = result;

    chrome.storage.sync.get('coords', (d) => {
      const { coords } = d;

      if (!forecast && coords) {
        getWeatherInfo();
        return;
      }

      if (forecast) {
        const { timestamp } = forecast;
        if (timestamp) {
          const lessThanOneHourAgo = () => {
            const oneHour = 1000 * 60 * 60;
            const oneHourAgo = Date.now() - oneHour;
            return timestamp > oneHourAgo;
          };

          if (!lessThanOneHourAgo()) {
            getWeatherInfo();
          }
        }
      }
    });
  });
};

chrome.runtime.onInstalled.addListener(fetchRandomPhoto);
chrome.runtime.onMessage.addListener((request, sender) => {
  switch (request.command) {
    case 'set-dropbox-token': {
      chrome.storage.local.set({ dropboxToken: request.token });

      chrome.notifications.create('dropbox-notification', {
        type: 'basic',
        iconUrl: chrome.extension.getURL('icons/48.png'),
        title: 'Stellar Photos',
        message: 'Dropbox authenticated successfully',
      });

      chrome.runtime.sendMessage({ command: 'update-cloud-status' });
      break;
    }

    case 'close-tab': {
      chrome.tabs.remove(sender.tab.id);
      break;
    }

    case 'update-weather': {
      getWeatherInfo();
      break;
    }

    case 'load-data': {
      loadNewData();
    }
  }
});
<|endoftext|>


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

const CHANNEL_NOT_READY = 'CHANNEL_NOT_READY';

class Seed extends Component {

  constructor(props) {
    super(props);
    this.useIframe = (this.props.seedUrl.startsWith('http:') || this.props.seedUrl.startsWith('https:'));
    this.iframeLoaded = this.iframeLoaded.bind(this);
  }

  componentWillUnmount() {
    this.destroyFrame();
  }

  componentWillUpdate() {
    this.destroyFrame();
  }

  destroyFrame() {
    if (this.useIframe) {
      if (this.iframe) {
        this.iframe.removeEventListener('load', this.iframeLoaded);
      }

      if (this.channel) {
        this.channel.destroy();
        this.channel = undefined;
      }
    }
  }

  componentDidMount() {
    if (!this.useIframe) {
      if (window.chrome && window.chrome.runtime && window.chrome.runtime.sendMessage) {
        window.chrome.runtime.sendMessage(this.props.seedUrl, { method: 'ping' }, (reply) => {
          if (reply && reply.pong) {
            this.ready = true;
            this.props.onReady && this.props.onReady();
          }
        });
      }
    }
  }

  sendMessage({method, params}) {
    const useIframe = this.useIframe;

    return new Promise((resolve, reject) => {
      if (!this.ready || this.ready !== true)
        return reject(new Error(CHANNEL_NOT_READY));

      if (useIframe) {
        this.channel.call({
          method,
          params,
          success: resolve,
          error: reject,
        });

      } else {
        window.chrome.runtime.sendMessage(this.props.seedUrl, { method, params }, (response) => {
          if (!response) {
            return reject(new Error('No response returned from Chrome extension'));
          }
          if (response.error)
            return reject(response.error);
          return resolve(response);
        });
      }
    });
  }

  request(requestOptions) {
    return this.sendMessage({
      method: 'httpRequest',
      params: requestOptions
    });
  }

  iframeLoaded() {
    this.channel = Channel.build({
      window: this.iframe.contentWindow,
      origin: this.props.origin,
      scope: this.props.scope,
      debugOutput: this.props.debugOutput,
      onReady: () => {
        this.ready = true;
        this.props.onReady && this.props.onReady();
      }
    });
  }

  render() {
    return (this.useIframe ?
      <iframe
        src={this.props.seedUrl}
        height="0"
        width="0"
        frameBorder="0"
        sandbox="allow-scripts allow-same-origin"
        ref={(iframe) => { if (iframe) { this.iframe = iframe; iframe.addEventListener('load', this.iframeLoaded, false); } } }
        >
      </iframe> : null
    );
  }
}

Seed.propTypes = {
  seedUrl: React.PropTypes.string.isRequired,
  origin: React.PropTypes.string,
  scope: React.PropTypes.string,
  debugOutput: React.PropTypes.bool,
  onReady: React.PropTypes.func
};

Seed.defaultProps = {
  origin: '*',
  debugOutput: false
}

export default Seed;
<commit_msg>Export the seed as objet as well<commit_after>import React, { Component } from 'react';
import Channel from 'jschannel';

const CHANNEL_NOT_READY = 'CHANNEL_NOT_READY';

class Seed extends Component {

  constructor(props) {
    super(props);
    this.useIframe = (this.props.seedUrl.startsWith('http:') || this.props.seedUrl.startsWith('https:'));
    this.iframeLoaded = this.iframeLoaded.bind(this);
  }

  componentWillUnmount() {
    this.destroyFrame();
  }

  componentWillUpdate() {
    this.destroyFrame();
  }

  destroyFrame() {
    if (this.useIframe) {
      if (this.iframe) {
        this.iframe.removeEventListener('load', this.iframeLoaded);
      }

      if (this.channel) {
        this.channel.destroy();
        this.channel = undefined;
      }
    }
  }

  componentDidMount() {
    if (!this.useIframe) {
      if (window.chrome && window.chrome.runtime && window.chrome.runtime.sendMessage) {
        window.chrome.runtime.sendMessage(this.props.seedUrl, { method: 'ping' }, (reply) => {
          if (reply && reply.pong) {
            this.ready = true;
            this.props.onReady && this.props.onReady();
          }
        });
      }
    }
  }

  sendMessage({method, params}) {
    const useIframe = this.useIframe;

    return new Promise((resolve, reject) => {
      if (!this.ready || this.ready !== true)
        return reject(new Error(CHANNEL_NOT_READY));

      if (useIframe) {
        this.channel.call({
          method,
          params,
          success: resolve,
          error: reject,
        });

      } else {
        window.chrome.runtime.sendMessage(this.props.seedUrl, { method, params }, (response) => {
          if (!response) {
            return reject(new Error('No response returned from Chrome extension'));
          }
          if (response.error)
            return reject(response.error);
          return resolve(response);
        });
      }
    });
  }

  request(requestOptions) {
    return this.sendMessage({
      method: 'httpRequest',
      params: requestOptions
    });
  }

  iframeLoaded() {
    this.channel = Channel.build({
      window: this.iframe.contentWindow,
      origin: this.props.origin,
      scope: this.props.scope,
      debugOutput: this.props.debugOutput,
      onReady: () => {
        this.ready = true;
        this.props.onReady && this.props.onReady();
      }
    });
  }

  render() {
    return (this.useIframe ?
      <iframe
        src={this.props.seedUrl}
        height="0"
        width="0"
        frameBorder="0"
        sandbox="allow-scripts allow-same-origin"
        ref={(iframe) => { if (iframe) { this.iframe = iframe; iframe.addEventListener('load', this.iframeLoaded, false); } } }
        >
      </iframe> : null
    );
  }
}

Seed.propTypes = {
  seedUrl: React.PropTypes.string.isRequired,
  origin: React.PropTypes.string,
  scope: React.PropTypes.string,
  debugOutput: React.PropTypes.bool,
  onReady: React.PropTypes.func
};

Seed.defaultProps = {
  origin: '*',
  debugOutput: false
}

export { Seed };
export default Seed;
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var nodemock = require('nodemock');
var net = require('net');
var msgpack = require('msgpack');
var http = require('http');
var Deferred = require('jsdeferred').Deferred;
var client = require('socket.io-client');

var socketIoAdaptor = require('../lib/frontend/socket.io-adaptor');

var testSendPort = exports.testSendPort = 3333;
var testReceivePort = exports.testReceivePort = 3334;
var testServerPort = exports.testServerPort = 3335;

function connectTo(port) {
  var deferred = new Deferred();
  var clientSocket = new net.Socket();
  clientSocket.on('error', function(error){
    clientSocket.destroy();
    deferred.fail(error);
  });
  clientSocket.connect(port, 'localhost', function(){
    deferred.call(clientSocket);
  });
  return deferred;
}
exports.connectTo = connectTo;
Deferred.register('connectTo', function() { return connectTo.apply(this, arguments); });

function sendPacketTo(packet, port) {
  var clientSocket;
  return connectTo(port)
    .next(function(newSocket) {
      clientSocket = newSocket;
      var packedPacket = msgpack.pack(packet);
      clientSocket.write(new Buffer(packedPacket));
    })
    .wait(0.01)
    .next(function() {
      clientSocket.destroy();
      clientSocket = undefined;
    })
    .error(function(error) {
      if (clientSocket) {
        clientSocket.destroy();
        clientSocket = undefined;
      }
      throw error;
    });
}
exports.sendPacketTo = sendPacketTo;
Deferred.register('sendPacketTo', function() { return sendPacketTo.apply(this, arguments); });

function setupServer(handlerOrServer) {
  var deferred = new Deferred();
  var server;
  if ('close' in handlerOrServer) { // it is a server
    server = handlerOrServer;
  } else { // it is a handler
    server = http.createServer(handlerOrServer);
  }
  server.listen(testServerPort, function() {
    deferred.call(server);
  });
  return deferred;
}
exports.setupServer = setupServer;

function sendRequest(method, path, postData, headers) {
  var deferred = new Deferred();

  var options = {
        host: 'localhost',
        port: testServerPort,
        path: path,
        method: method,
        headers: {}
      };

  if (headers) {
    for (var header in headers) {
      if (headers.hasOwnProperty(header))
        options.headers[header] = headers[header];
    }
  }

  Deferred.next(function() {
    var request = http.request(options, function(response) {
          var body = '';
          response.on('data', function(data) {
            body += data;
          });
          response.on('end', function() {
            deferred.call({
              statusCode: response.statusCode,
              body: body
            });
          });
        });
    request.on('error', function(error) {
      deferred.fail(error);
    });

    if (postData) request.write(postData);
    request.end();
  });

  return deferred;
}

function get(path, headers) {
  return sendRequest('GET', path, null, headers);
}
exports.get = get;
Deferred.register('get', function() { return get.apply(this, arguments); });

function post(path, body, headers) {
  return sendRequest('POST', path, body, headers);
}
exports.post = post;
Deferred.register('post', function() { return post.apply(this, arguments); });

function createClientSocket() {
  var deferred = new Deferred();
  var host = 'http://localhost:' + testServerPort;
  var options = { 'force new connection': true };
  var socket = client.connect(host, options);
  socket.on('connect', function() {
    deferred.call(socket);
  });
  return deferred;
}
exports.createClientSocket = createClientSocket;

function createMockedBackendConnection() {
  var connection = nodemock;
  var onMessageControllers = {};
  socketIoAdaptor.commands.forEach(function(command) {
    onMessageControllers[command] = {};
    connection = connection
      .mock('on')
        .takes('message', function() {})
        .ctrl(1, onMessageControllers[command]);
  });

  onMessageControllers.error = {};
  connection = connection
    .mock('on')
      .takes('error', function() {})
      .ctrl(1, onMessageControllers.error);

  connection.controllers = onMessageControllers;
  return connection;
}
exports.createMockedBackendConnection = createMockedBackendConnection;

function createStubbedBackendConnection() {
  return {
    emitMessage: function() {},
    emit: function() {},
    on: function() {},
    removeListener: function() {},
    removeAllListeners: function() {}
  };
}
exports.createStubbedBackendConnection = createStubbedBackendConnection;

function readyToDestroyMockedConnection(connection) {
  connection = connection
    .mock('removeListener')
      .takes('message', function() {})
      .times(socketIoAdaptor.commands.length)
    .mock('removeListener')
      .takes('error', function() {});
  return connection;
}
exports.readyToDestroyMockedConnection = readyToDestroyMockedConnection;

function createMockedHandlersFactory() {
  return nodemock
    .mock('search')
    .takes({})
    .returns(function() {});
}
exports.createMockedHandlersFactory = createMockedHandlersFactory;

function TypeOf(typeString) {
  if (!(this instanceof TypeOf))
    return new TypeOf(typeString);

  this.typeString = typeString;
  if (typeString == 'date') {
    return new InstanceOf(Date);
  }
}
exports.TypeOf = TypeOf;

function InstanceOf(constructor) {
  if (!(this instanceof InstanceOf))
    return new InstanceOf(constructor);

  this.constructorFunction = constructor;
}
exports.InstanceOf = InstanceOf;

function assertEnvelopeEqual(actual, expected) {
  var vs = JSON.stringify(actual) + ' vs ' + JSON.stringify(expected);
  Object.keys(expected).forEach(function(key) {
    var actualValue = actual[key];
    var expectedValue = expected[key];
    if (expectedValue instanceof InstanceOf) {
      if (typeof actualValue == 'string') {
        // Try fo parse the value and create new instance.
        // If this process is failed, it can be an invalid value.
        actualValue = new expectedValue.constructorFunction(actualValue);
      }
      assert.instanceOf(actualValue,
                        expectedValue.constructorFunction,
                        key + ' / ' + vs);
    } else if (expectedValue instanceof TypeOf) {
      assert.typeOf(typeof actualValue,
                    expectedValue.typeString,
                    key + ' / ' + vs);
    } else {
      assert.deepEqual(actualValue, expectedValue, key + ' / ' + vs);
    }
  });
}
assert.envelopeEqual = assertEnvelopeEqual;

function sortKeys(original) {
  if (!original || typeof original != 'object')
    return original;

  if (Array.isArray(original))
    return original.map(sortKeys);

  var sorted = {};
  Object.keys(original).sort().forEach(function(key) {
    sorted[key] = sortKeys(original[key]);
  });
  return sorted;
}

// assert.deepEqual fails when the order of hash keys are different,
// even if they are "eaual" as JSON objects.
function assertEqualJSON(actual, expected) {
  this.deepEqual(sortKeys(actual), sortKeys(expected));
}
assert.equalJSON = assertEqualJSON;

exports.outputAll = {
  startTime:   true,
  elapsedTime: true,
  count:       true,
  attributes:  true,
  recodes:     true
};
<commit_msg>Define "close" method for stubbed connections<commit_after>var assert = require('chai').assert;
var nodemock = require('nodemock');
var net = require('net');
var msgpack = require('msgpack');
var http = require('http');
var Deferred = require('jsdeferred').Deferred;
var client = require('socket.io-client');

var socketIoAdaptor = require('../lib/frontend/socket.io-adaptor');

var testSendPort = exports.testSendPort = 3333;
var testReceivePort = exports.testReceivePort = 3334;
var testServerPort = exports.testServerPort = 3335;

function connectTo(port) {
  var deferred = new Deferred();
  var clientSocket = new net.Socket();
  clientSocket.on('error', function(error){
    clientSocket.destroy();
    deferred.fail(error);
  });
  clientSocket.connect(port, 'localhost', function(){
    deferred.call(clientSocket);
  });
  return deferred;
}
exports.connectTo = connectTo;
Deferred.register('connectTo', function() { return connectTo.apply(this, arguments); });

function sendPacketTo(packet, port) {
  var clientSocket;
  return connectTo(port)
    .next(function(newSocket) {
      clientSocket = newSocket;
      var packedPacket = msgpack.pack(packet);
      clientSocket.write(new Buffer(packedPacket));
    })
    .wait(0.01)
    .next(function() {
      clientSocket.destroy();
      clientSocket = undefined;
    })
    .error(function(error) {
      if (clientSocket) {
        clientSocket.destroy();
        clientSocket = undefined;
      }
      throw error;
    });
}
exports.sendPacketTo = sendPacketTo;
Deferred.register('sendPacketTo', function() { return sendPacketTo.apply(this, arguments); });

function setupServer(handlerOrServer) {
  var deferred = new Deferred();
  var server;
  if ('close' in handlerOrServer) { // it is a server
    server = handlerOrServer;
  } else { // it is a handler
    server = http.createServer(handlerOrServer);
  }
  server.listen(testServerPort, function() {
    deferred.call(server);
  });
  return deferred;
}
exports.setupServer = setupServer;

function sendRequest(method, path, postData, headers) {
  var deferred = new Deferred();

  var options = {
        host: 'localhost',
        port: testServerPort,
        path: path,
        method: method,
        headers: {}
      };

  if (headers) {
    for (var header in headers) {
      if (headers.hasOwnProperty(header))
        options.headers[header] = headers[header];
    }
  }

  Deferred.next(function() {
    var request = http.request(options, function(response) {
          var body = '';
          response.on('data', function(data) {
            body += data;
          });
          response.on('end', function() {
            deferred.call({
              statusCode: response.statusCode,
              body: body
            });
          });
        });
    request.on('error', function(error) {
      deferred.fail(error);
    });

    if (postData) request.write(postData);
    request.end();
  });

  return deferred;
}

function get(path, headers) {
  return sendRequest('GET', path, null, headers);
}
exports.get = get;
Deferred.register('get', function() { return get.apply(this, arguments); });

function post(path, body, headers) {
  return sendRequest('POST', path, body, headers);
}
exports.post = post;
Deferred.register('post', function() { return post.apply(this, arguments); });

function createClientSocket() {
  var deferred = new Deferred();
  var host = 'http://localhost:' + testServerPort;
  var options = { 'force new connection': true };
  var socket = client.connect(host, options);
  socket.on('connect', function() {
    deferred.call(socket);
  });
  return deferred;
}
exports.createClientSocket = createClientSocket;

function createMockedBackendConnection() {
  var connection = nodemock;
  var onMessageControllers = {};
  socketIoAdaptor.commands.forEach(function(command) {
    onMessageControllers[command] = {};
    connection = connection
      .mock('on')
        .takes('message', function() {})
        .ctrl(1, onMessageControllers[command]);
  });

  onMessageControllers.error = {};
  connection = connection
    .mock('on')
      .takes('error', function() {})
      .ctrl(1, onMessageControllers.error);

  connection.controllers = onMessageControllers;
  return connection;
}
exports.createMockedBackendConnection = createMockedBackendConnection;

function createStubbedBackendConnection() {
  return {
    emitMessage: function() {},
    emit: function() {},
    on: function() {},
    removeListener: function() {},
    removeAllListeners: function() {},
    close: function() {}
  };
}
exports.createStubbedBackendConnection = createStubbedBackendConnection;

function readyToDestroyMockedConnection(connection) {
  connection = connection
    .mock('removeListener')
      .takes('message', function() {})
      .times(socketIoAdaptor.commands.length)
    .mock('removeListener')
      .takes('error', function() {});
  return connection;
}
exports.readyToDestroyMockedConnection = readyToDestroyMockedConnection;

function createMockedHandlersFactory() {
  return nodemock
    .mock('search')
    .takes({})
    .returns(function() {});
}
exports.createMockedHandlersFactory = createMockedHandlersFactory;

function TypeOf(typeString) {
  if (!(this instanceof TypeOf))
    return new TypeOf(typeString);

  this.typeString = typeString;
  if (typeString == 'date') {
    return new InstanceOf(Date);
  }
}
exports.TypeOf = TypeOf;

function InstanceOf(constructor) {
  if (!(this instanceof InstanceOf))
    return new InstanceOf(constructor);

  this.constructorFunction = constructor;
}
exports.InstanceOf = InstanceOf;

function assertEnvelopeEqual(actual, expected) {
  var vs = JSON.stringify(actual) + ' vs ' + JSON.stringify(expected);
  Object.keys(expected).forEach(function(key) {
    var actualValue = actual[key];
    var expectedValue = expected[key];
    if (expectedValue instanceof InstanceOf) {
      if (typeof actualValue == 'string') {
        // Try fo parse the value and create new instance.
        // If this process is failed, it can be an invalid value.
        actualValue = new expectedValue.constructorFunction(actualValue);
      }
      assert.instanceOf(actualValue,
                        expectedValue.constructorFunction,
                        key + ' / ' + vs);
    } else if (expectedValue instanceof TypeOf) {
      assert.typeOf(typeof actualValue,
                    expectedValue.typeString,
                    key + ' / ' + vs);
    } else {
      assert.deepEqual(actualValue, expectedValue, key + ' / ' + vs);
    }
  });
}
assert.envelopeEqual = assertEnvelopeEqual;

function sortKeys(original) {
  if (!original || typeof original != 'object')
    return original;

  if (Array.isArray(original))
    return original.map(sortKeys);

  var sorted = {};
  Object.keys(original).sort().forEach(function(key) {
    sorted[key] = sortKeys(original[key]);
  });
  return sorted;
}

// assert.deepEqual fails when the order of hash keys are different,
// even if they are "eaual" as JSON objects.
function assertEqualJSON(actual, expected) {
  this.deepEqual(sortKeys(actual), sortKeys(expected));
}
assert.equalJSON = assertEqualJSON;

exports.outputAll = {
  startTime:   true,
  elapsedTime: true,
  count:       true,
  attributes:  true,
  recodes:     true
};
<|endoftext|>


<commit_before>/*
 * Copyright 2020 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.
 */

/**
 * Internal dependencies
 */
/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
/**
 * External dependencies
 */
import React from 'react';
import styled from 'styled-components';
import { rgba } from 'polished';
import theme from '../../../theme';
import { ProviderType } from '../providerType';
import { ReactComponent as UnsplashLogoFull } from '../../../icons/unsplash_logo_full.svg';

const AttributionPill = styled.div`
  position: absolute;
  left: 24px;
  bottom: 10px;
  border-radius: 100px;
  padding: 5px 8px;
  line-height: 16px;
  display: flex;
  flex-wrap: nowrap;
  font-size: 12px;
  color: ${theme.colors.fg.v1};
  background-color: ${rgba(theme.colors.bg.v0, 0.7)};
  cursor: pointer;
`;

const ContentType = {
  IMAGE: 'image',
  VIDEO: 'video',
};

const LOGO_STYLE = {
  fill: theme.colors.fg.v1,
  marginLeft: '6px',
  height: '14px',
};

/**
 * @typedef ProviderConfiguration
 * @property {string} displayName The display name of the provider.
 * @property {ContentType[]} supportedContentTypes The supported content types by the provider.
 * @property {boolean} supportsCategories Whether this provider supports filtering media by category.
 * @property {boolean} requiresAuthorAttribution Whether this provider requires showing author
 * attribution on each media element.
 * @property {function(): React.Component} attributionBuilder A function that constructs an attribution
 * React Component for this provider.
 */

function UnsplashAttribution() {
  return (

      <AttributionPill>
        {__('Powered by', 'web-stories')}
        <UnsplashLogoFull style={LOGO_STYLE} />
      </AttributionPill>

  );
}

function CoverrAttribution() {
  return (

      <AttributionPill>
        {__('Powered by', 'web-stories')}
        {'COVERR'}
      </AttributionPill>

  );
}

/**
 *
 * @type {Object.<string, ProviderConfiguration>}
 */
export const Providers = {
  [ProviderType.UNSPLASH]: {
    displayName: 'Unsplash',
    supportedContentTypes: [ContentType.IMAGE],
    supportsCategories: true,
    requiresAuthorAttribution: true,
    attributionBuilder: UnsplashAttribution,
  },
  [ProviderType.COVERR]: {
    displayName: 'Coverr',
    supportedContentTypes: [ContentType.VIDEO],
    supportsCategories: false,
    requiresAuthorAttribution: false,
    attributionBuilder: CoverrAttribution,
  },
};
<commit_msg>Add an internal "flag" for the coverr subtab.<commit_after>/*
 * Copyright 2020 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.
 */

/**
 * Internal dependencies
 */
/**
 * WordPress dependencies
 */
import { __ } from '@wordpress/i18n';
/**
 * External dependencies
 */
import React from 'react';
import styled from 'styled-components';
import { rgba } from 'polished';
import theme from '../../../theme';
import { ProviderType } from '../providerType';
import { ReactComponent as UnsplashLogoFull } from '../../../icons/unsplash_logo_full.svg';

const AttributionPill = styled.div`
  position: absolute;
  left: 24px;
  bottom: 10px;
  border-radius: 100px;
  padding: 5px 8px;
  line-height: 16px;
  display: flex;
  flex-wrap: nowrap;
  font-size: 12px;
  color: ${theme.colors.fg.v1};
  background-color: ${rgba(theme.colors.bg.v0, 0.7)};
  cursor: pointer;
`;

const ContentType = {
  IMAGE: 'image',
  VIDEO: 'video',
};

const LOGO_STYLE = {
  fill: theme.colors.fg.v1,
  marginLeft: '6px',
  height: '14px',
};

/**
 * @typedef ProviderConfiguration
 * @property {string} displayName The display name of the provider.
 * @property {ContentType[]} supportedContentTypes The supported content types by the provider.
 * @property {boolean} supportsCategories Whether this provider supports filtering media by category.
 * @property {boolean} requiresAuthorAttribution Whether this provider requires showing author
 * attribution on each media element.
 * @property {function(): React.Component} attributionBuilder A function that constructs an attribution
 * React Component for this provider.
 */

function UnsplashAttribution() {
  return (

      <AttributionPill>
        {__('Powered by', 'web-stories')}
        <UnsplashLogoFull style={LOGO_STYLE} />
      </AttributionPill>

  );
}

function CoverrAttribution() {
  return (

      <AttributionPill>
        {__('Powered by', 'web-stories')}
        {'COVERR'}
      </AttributionPill>

  );
}

const showCoverrTab = false;

/**
 *
 * @type {Object.<string, ProviderConfiguration>}
 */
export const Providers = Object.fromEntries(
  new Map(
    [
      [
        ProviderType.UNSPLASH,
        {
          displayName: 'Unsplash',
          supportedContentTypes: [ContentType.IMAGE],
          supportsCategories: true,
          requiresAuthorAttribution: true,
          attributionBuilder: UnsplashAttribution,
        },
      ],
      showCoverrTab
        ? [
            ProviderType.COVERR,
            {
              displayName: 'Coverr',
              supportedContentTypes: [ContentType.VIDEO],
              supportsCategories: false,
              requiresAuthorAttribution: false,
              attributionBuilder: CoverrAttribution,
            },
          ]
        : null,
    ].filter((e) => e != null)
  )
);
<|endoftext|>


<commit_before>aurena = {

websocket_listener : function()
{
  if (aurena.ws != null)
    return;

  if (!("WebSocket" in window) && ("MozWebSocket" in window))
    window.WebSocket = window.MozWebSocket;

  if ("WebSocket" in window)
  {
     var url = document.URL.replace("http", "ws") + "../client/control_events";
     var ws = new WebSocket(url, "aurena");
     aurena.ws = ws;

     ws.onopen = function()
     {
        $("#connstatus").html("
Connected
");
     };
     ws.onmessage = function (evt)
     {
        var received_msg = evt.data;

        if (typeof received_msg == typeof("")) {
            aurena.handle_event(received_msg);
        }
     };
     ws.onclose = function()
     {
        $("#connstatus").html("
Disconnected
");
        aurena.ws = null;
        setTimeout(aurena.websocket_listener, 1000);
     };
  }
  else
  {
     $("#debug").prepend("
websocket connections not available!
");
  }
},
update_playstate : function() {
  if (aurena.paused) {
    $("#playstate").html("Paused");
  }
  else {
    $("#playstate").html("Playing");
  }
  if (aurena.cur_media != 0)
    $("#nowplaying").html("track " + aurena.cur_media);
  else
    $("#nowplaying").html("None");
},

set_vol_slider : function set_vol_slider(client_id, vol, anim) {
  var s;

  if (client_id == 0)
    s = $("#mastervolslider");
  else
    s = $("#volume-" + client_id);

  if (!aurena.sliding && vol != s.slider("value")) {
    // $("#debug").prepend("
Setting vol " + vol + "
");
    aurena.slide_update = true;
    s.slider("option", "animate", anim);
    s.slider("value", vol);
    s.slider("option", "animate", true);
    aurena.slide_update = false;
  }
},

set_client_enable : function f(client_id, enable) {
  if (client_id < 1)
    return;
  var s = $("#enable-" + client_id);
  s.attr('checked', enable);
},

handle_event : function handle_event(data) {
  json = $.parseJSON(data);
  switch (json["msg-type"]) {
    case "enrol":
      var vol = json["volume-level"];
      aurena.paused = json["paused"];
      aurena.cur_media = json["resource-id"];

      aurena.set_vol_slider (0, vol, false);
      aurena.update_playstate();
      break;
    case "volume":
      var vol = json["level"];
      aurena.set_vol_slider (0, vol, true);
      break;
    case "client-volume":
      var vol = json["level"];
      aurena.set_vol_slider (json["client-id"], vol, true);
      break;
    case "client-setting":
      var en = json["enabled"];
      aurena.set_client_enable (json["client-id"], en);
      break;
    case "pause":
      aurena.paused = true;
      aurena.update_playstate();
      break;
    case "play":
      aurena.paused = false;
      aurena.update_playstate();
      break;
    case "set-media":
      aurena.paused = json["paused"];
      aurena.cur_media = json["resource-id"];
      aurena.update_playstate();
      break;
    case "player-clients-changed":
      aurena.update_player_clients();
      break;
    default:
      $("#debug").prepend("
Received message of type " + json["msg-type"] + ": " + data + "
");
      break;
  }
},
update_player_clients : function () {
  function send_enable_val(client_id) {
    if (aurena.sendingEnable)
      return;
    var enabled = 0;

    if ($("#enable-" + client_id).attr('checked'))
      enabled = 1;

    aurena.sendingEnable = true;
    $.ajax({
      type: 'GET',
      url: "../control/setclient",
      data: { client_id: client_id, enable: enabled }
    }).complete(function() {
      aurena.sendingEnable = false;
    });
  }

  $.getJSON("../client/player_info", function(data) {
     var items = [];
     var clients = data['player-clients'];
     aurena.clients = clients;
     $.each(clients, function(key, val) {
       var enable_id = "enable-" + val["client-id"];
       var volume_id = "volume-" + val["client-id"];
       var info = '
';
       info += "<input type='checkbox' id='" + enable_id + "'/>";
       info += " Client " + val["host"];
       info += "
";
       info += "
";
       info += '
';
       items.push(info);
        console.log ("Client data " + JSON.stringify(val));
     });
     $("#cliententries").empty().prepend($('
', {
       html: items.join('')
     }));
     $.each(clients, function(key, val) {
       var client_id = val["client-id"];
       var enable_id = "enable-" + client_id;
       var volume_id = "volume-" + client_id;

       $("#" + volume_id).slider({
         animate: true,
         min : 0.0, max : 1.5, range : 'true', value : val["volume"], step : 0.01,
         start : function(event, ui) { aurena.sliding = true; },
         stop : function(event, ui) { setTimeout(function() { aurena.sliding = false; }, 100); },
         slide : function(cid) { return function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(cid); } }(client_id),
         change : function(cid) { return function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(cid); } }(client_id)
       });
       $('#volumeval-' + client_id).text(Math.round(val["volume"] * 100).toString() + '%');
       $("#" + enable_id).attr('checked', val["enabled"]).change(function(cid) { return function () { send_enable_val (cid) } }(client_id));
     });
  });
},

send_slider_volume : function send_slider_volume(client_id) {
  var s;

  if (client_id == 0)
    s= $("#mastervolslider");
  else
    s = $("#volume-" + client_id);

  var curVol = s.slider( "option", "value");
  if (client_id == 0)
    $('#mastervolval').text(Math.round(curVol * 100).toString() + '%');
  else
    $('#volumeval-' + client_id).text(Math.round(curVol * 100).toString() + '%');

  if (aurena.sendingVol || !aurena.volChange || aurena.slide_update) return;
  aurena.sendingVol = true; aurena.volChange = false;
  // $("#debug").prepend("
Sending volume " + curVol.toString() + "
");
  $.ajax({
    type: 'POST',
    url: "../control/volume",
    data: { level: curVol.toString(), client_id: client_id }
  }).complete(function() {
        aurena.sendingVol = false; aurena.send_slider_volume(client_id);
  });
},

init : function() {
  aurena.sendingVol = false;
  aurena.volChange = false;

  aurena.sliding = false;
  aurena.slide_update = false;
  aurena.paused = true;
  aurena.cur_media = 0;

  $("#mastervolslider").slider({
     animate: true,
     min : 0.0, max : 1.5, range : 'true', value : 1.0, step : 0.01,
     start : function(event, ui) { //$("#debug").prepend("
start");
                                   aurena.sliding = true; },
     stop : function(event, ui) { setTimeout(function() { aurena.sliding = false; }, 100); },
     slide : function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(0); },
     change : function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(0); }
  });
  $("#play").click(function() { $.ajax({ url: "../control/play", type: 'POST' }); });
  $("#pause").click(function() { $.ajax({ url: "../control/pause" , type: 'POST'}); });
  $("#next").click(function() { $.ajax({ url: "../control/next" , type: 'POST'}); });
  aurena.websocket_listener();
}

};

$(document).ready(function() {
  aurena.init();
});
<commit_msg>Add play/pause/next/previous JS functions<commit_after>aurena = {

websocket_listener : function()
{
  if (aurena.ws != null)
    return;

  if (!("WebSocket" in window) && ("MozWebSocket" in window))
    window.WebSocket = window.MozWebSocket;

  if ("WebSocket" in window)
  {
     var url = document.URL.replace("http", "ws") + "../client/control_events";
     var ws = new WebSocket(url, "aurena");
     aurena.ws = ws;

     ws.onopen = function()
     {
        $("#connstatus").html("
Connected
");
     };
     ws.onmessage = function (evt)
     {
        var received_msg = evt.data;

        if (typeof received_msg == typeof("")) {
            aurena.handle_event(received_msg);
        }
     };
     ws.onclose = function()
     {
        $("#connstatus").html("
Disconnected
");
        aurena.ws = null;
        setTimeout(aurena.websocket_listener, 1000);
     };
  }
  else
  {
     $("#debug").prepend("
websocket connections not available!
");
  }
},
update_playstate : function() {
  if (aurena.paused) {
    $("#playstate").html("Paused");
  }
  else {
    $("#playstate").html("Playing");
  }
  if (aurena.cur_media != 0)
    $("#nowplaying").html("track " + aurena.cur_media);
  else
    $("#nowplaying").html("None");
},

set_vol_slider : function set_vol_slider(client_id, vol, anim) {
  var s;

  if (client_id == 0)
    s = $("#mastervolslider");
  else
    s = $("#volume-" + client_id);

  if (!aurena.sliding && vol != s.slider("value")) {
    // $("#debug").prepend("
Setting vol " + vol + "
");
    aurena.slide_update = true;
    s.slider("option", "animate", anim);
    s.slider("value", vol);
    s.slider("option", "animate", true);
    aurena.slide_update = false;
  }
},

set_client_enable : function f(client_id, enable) {
  if (client_id < 1)
    return;
  var s = $("#enable-" + client_id);
  s.attr('checked', enable);
},

handle_event : function handle_event(data) {
  json = $.parseJSON(data);
  switch (json["msg-type"]) {
    case "enrol":
      var vol = json["volume-level"];
      aurena.paused = json["paused"];
      aurena.cur_media = json["resource-id"];

      aurena.set_vol_slider (0, vol, false);
      aurena.update_playstate();
      break;
    case "volume":
      var vol = json["level"];
      aurena.set_vol_slider (0, vol, true);
      break;
    case "client-volume":
      var vol = json["level"];
      aurena.set_vol_slider (json["client-id"], vol, true);
      break;
    case "client-setting":
      var en = json["enabled"];
      aurena.set_client_enable (json["client-id"], en);
      break;
    case "pause":
      aurena.paused = true;
      aurena.update_playstate();
      break;
    case "play":
      aurena.paused = false;
      aurena.update_playstate();
      break;
    case "set-media":
      aurena.paused = json["paused"];
      aurena.cur_media = json["resource-id"];
      aurena.update_playstate();
      break;
    case "player-clients-changed":
      aurena.update_player_clients();
      break;
    default:
      $("#debug").prepend("
Received message of type " + json["msg-type"] + ": " + data + "
");
      break;
  }
},
update_player_clients : function () {
  function send_enable_val(client_id) {
    if (aurena.sendingEnable)
      return;
    var enabled = 0;

    if ($("#enable-" + client_id).attr('checked'))
      enabled = 1;

    aurena.sendingEnable = true;
    $.ajax({
      type: 'GET',
      url: "../control/setclient",
      data: { client_id: client_id, enable: enabled }
    }).complete(function() {
      aurena.sendingEnable = false;
    });
  }

  $.getJSON("../client/player_info", function(data) {
     var items = [];
     var clients = data['player-clients'];
     aurena.clients = clients;
     $.each(clients, function(key, val) {
       var enable_id = "enable-" + val["client-id"];
       var volume_id = "volume-" + val["client-id"];
       var info = '
';
       info += "<input type='checkbox' id='" + enable_id + "'/>";
       info += " Client " + val["host"];
       info += "
";
       info += "
";
       info += '
';
       items.push(info);
        console.log ("Client data " + JSON.stringify(val));
     });
     $("#cliententries").empty().prepend($('
', {
       html: items.join('')
     }));
     $.each(clients, function(key, val) {
       var client_id = val["client-id"];
       var enable_id = "enable-" + client_id;
       var volume_id = "volume-" + client_id;

       $("#" + volume_id).slider({
         animate: true,
         min : 0.0, max : 1.5, range : 'true', value : val["volume"], step : 0.01,
         start : function(event, ui) { aurena.sliding = true; },
         stop : function(event, ui) { setTimeout(function() { aurena.sliding = false; }, 100); },
         slide : function(cid) { return function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(cid); } }(client_id),
         change : function(cid) { return function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(cid); } }(client_id)
       });
       $('#volumeval-' + client_id).text(Math.round(val["volume"] * 100).toString() + '%');
       $("#" + enable_id).attr('checked', val["enabled"]).change(function(cid) { return function () { send_enable_val (cid) } }(client_id));
     });
  });
},

send_slider_volume : function send_slider_volume(client_id) {
  var s;

  if (client_id == 0)
    s= $("#mastervolslider");
  else
    s = $("#volume-" + client_id);

  var curVol = s.slider( "option", "value");
  if (client_id == 0)
    $('#mastervolval').text(Math.round(curVol * 100).toString() + '%');
  else
    $('#volumeval-' + client_id).text(Math.round(curVol * 100).toString() + '%');

  if (aurena.sendingVol || !aurena.volChange || aurena.slide_update) return;
  aurena.sendingVol = true; aurena.volChange = false;
  // $("#debug").prepend("
Sending volume " + curVol.toString() + "
");
  $.ajax({
    type: 'POST',
    url: "../control/volume",
    data: { level: curVol.toString(), client_id: client_id }
  }).complete(function() {
        aurena.sendingVol = false; aurena.send_slider_volume(client_id);
  });
},
playPause : function() {
  if (aurena.paused)
    aurena.play();
  else
    aurena.pause();
  aurena.paused = !aurena.paused;
},
play : function() {
  $.ajax({ url: "../control/play" , type: 'POST'});
},
pause : function() {
  $.ajax({ url: "../control/pause" , type: 'POST'});
},
next : function() {
  $.ajax({ url: "../control/next" , type: 'POST'});
},
previous : function() {
  $.ajax({ url: "../control/previous" , type: 'POST'});
},
init : function() {
  aurena.sendingVol = false;
  aurena.volChange = false;

  aurena.sliding = false;
  aurena.slide_update = false;
  aurena.paused = true;
  aurena.cur_media = 0;

  $("#mastervolslider").slider({
     animate: true,
     min : 0.0, max : 1.5, range : 'true', value : 1.0, step : 0.01,
     start : function(event, ui) { //$("#debug").prepend("
start");
                                   aurena.sliding = true; },
     stop : function(event, ui) { setTimeout(function() { aurena.sliding = false; }, 100); },
     slide : function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(0); },
     change : function(event, ui) { aurena.volChange = true; aurena.send_slider_volume(0); }
  });
  $("#play").click(function() { aurena.play() });
  $("#pause").click(function() { aurena.pause() });
  $("#next").click(function() { aurena.next() });
  aurena.websocket_listener();
}

};

$(document).ready(function() {
  aurena.init();
});
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 William Malone (www.williammalone.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*global window, document */

var BLOCKS;

if (BLOCKS === undefined) {
	BLOCKS = {};
}

BLOCKS.controller = function (element) {

	"use strict";

	var controller = BLOCKS.eventDispatcher(),
		elementPos,

		getElementPos = function (element) {

			var parentOffset,
				pos = {
					x: element.offsetLeft,
					y: element.offsetTop
				};

           if (element.offsetParent) {
               parentOffset = getElementPos(element.offsetParent);
               pos.x += parentOffset.x;
               pos.y += parentOffset.y;
           }

           return pos;
        },

		init = function () {

			if (!element) {
				element = document.getElementById("BlocksGame");
			}

			element.addEventListener("orientationchange", onOrientationEvent, true);

			document.addEventListener("keydown", onKeyDownEvent, true);
			document.addEventListener("keyup", onKeyUpEvent, true);

			element.addEventListener("touchstart", onTouchEvent, true);
			element.addEventListener("touchmove", onTouchEvent, true);
			element.addEventListener("touchend", onTouchEvent, true);
			element.addEventListener("touchcancel", onTouchEvent, true);

			element.addEventListener("mousedown", onMouseEvent, true);
			element.addEventListener("mousemove", onMouseEvent, true);
			element.addEventListener("mouseup", onMouseEvent, true);
			element.addEventListener("mousecancel", onMouseEvent, true);

		},

        onOrientationEvent = function () {

			if (controller.listening) {

				switch (window.orientation) {

				case -90:
					controller.orientation = "landscape";
					break;

				case 0:
					controller.orientation = "portrait";
					break;

				case 90:
					controller.orientation = "landscape";
					break;

				case 180:
					controller.orientation = "portrait";
					break;
				}

				controller.dispatchEvent("orientationChange", {
					orientation: controller.orientation
				});
			}
		},

		onKeyDownEvent = function (e) {

			if (controller.listening) {
				controller.dispatchEvent("keyDown", e);
			}
		},

		onKeyUpEvent = function (e) {

			if (controller.listening) {
				controller.dispatchEvent("keyUp", e);
			}
		},

        dispatchTapEvent = function (e, eventType) {

			switch (eventType) {

			case "tap":

				controller.drag = true;
				controller.dispatchEvent("tap", e);

				break;

			case "drag":
				controller.drag = true;
				controller.dispatchEvent("drag", e);

				break;

			case "release":
				controller.drag = false;
				controller.dispatchEvent("release", e);
				break;

			case "cancel":
				controller.drag = false;
				controller.dispatchEvent("cancel", e);
				break;

			default:
				break;
			}
		},

		onTouchEvent = function (e) {

			var i, key, event, touch, eventType, firstFinger;

			if (controller.listening) {

				// Disable scrolling on mobile and prevent mouse event on touch
				if (e.preventDefault) {
					e.preventDefault();
				}

				// TODO: ElementPos does not have to be calculated every time?
				elementPos = getElementPos(element);

				// Select the first changed touch and assign it as the default touch
				firstFinger = e.changedTouches[0];

				// Make a copy of the touch event
				event = {};
				for (key in firstFinger) {
					if (firstFinger.hasOwnProperty(key)) {
						event[key] = firstFinger[key];
					}
				}

				event.x = (firstFinger.pageX - elementPos.x - controller.offsetX) * controller.scaleX;
				event.y = (firstFinger.pageY - elementPos.y - controller.offsetY) * controller.scaleY;
				event.type = e.type;

				event.touches = [];
				// For each touch currently on the screen
				for (i = 0; i < e.touches.length; i += 1) {

					event.touches[i] = {};
					for (key in e.touches[i]) {
						if (e.touches[i].hasOwnProperty(key)) {
							event.touches[i][key] = e.touches[i][key];
						}
					}

					event.touches[i].x = (event.touches[i].clientX - elementPos.x - controller.offsetX) * controller.scaleX;
					event.touches[i].y = (event.touches[i].clientY - elementPos.y - controller.offsetY) * controller.scaleY;

				}

				event.changedTouches = [];
				// For each touch invloved in this event on the screen
				for (i = 0; i < e.changedTouches.length; i += 1) {

					event.changedTouches[i] = {};
					for (key in e.changedTouches[i]) {
						if (e.changedTouches[i].hasOwnProperty(key)) {
							event.changedTouches[i][key] = e.changedTouches[i][key];
						}
					}

					event.changedTouches[i].x = (event.changedTouches[i].pageX - elementPos.x - controller.offsetX) * controller.scaleX;
					event.changedTouches[i].y = (event.changedTouches[i].pageY - elementPos.y - controller.offsetY) * controller.scaleY;
				}

				switch (event.type) {

				case "touchstart":

					eventType = "tap";
					controller.dispatchEvent("touchStart", event);

					break;

				case "touchmove":
					eventType = "drag";
					controller.dispatchEvent("touchMove", event);
					break;

				case "touchend":
					eventType = "release";
					controller.dispatchEvent("touchEnd", event);
					break;

				case "touchcancel":
					eventType = "cancel";
					controller.dispatchEvent("touchCancel", event);
					break;

				default:
					break;
				}

				dispatchTapEvent(event, eventType);
			}
		},

		onMouseEvent = function (e) {

			var i, key, eventType, event;

			if (controller.listening) {

				// Disable right click
				//if (e.button === 2) {
				//	return;
				//}

				event = {};
				for (key in e) {
					if (e.hasOwnProperty(key)) {
						event[key] = e[key];
					}
				}

				// TODO: ElementPos does not have to be calculated every time?
				elementPos = getElementPos(element);

				event.x = (event.pageX - elementPos.x - controller.offsetX) * controller.scaleX;
				event.y = (event.pageY - elementPos.y - controller.offsetY) * controller.scaleY;
				event.identifier = "mouse";
				event.touches = [event];
				event.changedTouches = [event];

				switch (event.type) {

				case "mousedown":
					eventType = "tap";
					controller.dispatchEvent("mouseDown", event);

					break;

				case "mousemove":
					eventType = "drag";
					controller.dispatchEvent("mouseMove", event);
					break;

				case "mouseup":
					eventType = "release";
					controller.dispatchEvent("mouseUp", event);
					break;

				case "mousecancel":
					eventType = "cancel";
					controller.dispatchEvent("mouseCancel", event);
					break;

				default:
					break;
				}

				dispatchTapEvent(event, eventType);
			}
		};

	controller.scaleX = 1;
	controller.scaleY = 1;
	controller.offsetX = 0;
	controller.offsetY = 0;
	controller.listening = true;

	controller.simulateKeyDownEvent = function (keyCode) {
		onKeyDownEvent({
			keyCode: keyCode
		});
	};

	controller.simulateKeyUpEvent = function (keyCode) {
		onKeyUpEvent({
			keyCode: keyCode
		});
	};

	init();

	return controller;
};<commit_msg>Fixed Firefox IE Controller Issue<commit_after>/*
Copyright (c) 2013 William Malone (www.williammalone.com)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*global window, document */

var BLOCKS;

if (BLOCKS === undefined) {
	BLOCKS = {};
}

BLOCKS.controller = function (element) {

	"use strict";

	var controller = BLOCKS.eventDispatcher(),
		elementPos,

		getElementPos = function (element) {

			var parentOffset,
				pos = {
					x: element.offsetLeft,
					y: element.offsetTop
				};

           if (element.offsetParent) {
               parentOffset = getElementPos(element.offsetParent);
               pos.x += parentOffset.x;
               pos.y += parentOffset.y;
           }

           return pos;
        },

		init = function () {

			if (!element) {
				element = document.getElementById("BlocksGame");
			}

			element.addEventListener("orientationchange", onOrientationEvent, true);

			document.addEventListener("keydown", onKeyDownEvent, true);
			document.addEventListener("keyup", onKeyUpEvent, true);

			element.addEventListener("touchstart", onTouchEvent, true);
			element.addEventListener("touchmove", onTouchEvent, true);
			element.addEventListener("touchend", onTouchEvent, true);
			element.addEventListener("touchcancel", onTouchEvent, true);

			element.addEventListener("mousedown", onMouseEvent, true);
			element.addEventListener("mousemove", onMouseEvent, true);
			element.addEventListener("mouseup", onMouseEvent, true);
			element.addEventListener("mousecancel", onMouseEvent, true);

		},

        onOrientationEvent = function () {

			if (controller.listening) {

				switch (window.orientation) {

				case -90:
					controller.orientation = "landscape";
					break;

				case 0:
					controller.orientation = "portrait";
					break;

				case 90:
					controller.orientation = "landscape";
					break;

				case 180:
					controller.orientation = "portrait";
					break;
				}

				controller.dispatchEvent("orientationChange", {
					orientation: controller.orientation
				});
			}
		},

		onKeyDownEvent = function (e) {

			if (controller.listening) {
				controller.dispatchEvent("keyDown", e);
			}
		},

		onKeyUpEvent = function (e) {

			if (controller.listening) {
				controller.dispatchEvent("keyUp", e);
			}
		},

        dispatchTapEvent = function (e, eventType) {

			switch (eventType) {

			case "tap":

				controller.drag = true;
				controller.dispatchEvent("tap", e);

				break;

			case "drag":
				controller.drag = true;
				controller.dispatchEvent("drag", e);

				break;

			case "release":
				controller.drag = false;
				controller.dispatchEvent("release", e);
				break;

			case "cancel":
				controller.drag = false;
				controller.dispatchEvent("cancel", e);
				break;

			default:
				break;
			}
		},

		onTouchEvent = function (e) {

			var i, key, event, touch, eventType, firstFinger;

			if (controller.listening) {

				// Disable scrolling on mobile and prevent mouse event on touch
				if (e.preventDefault) {
					e.preventDefault();
				}

				// TODO: ElementPos does not have to be calculated every time?
				elementPos = getElementPos(element);

				// Select the first changed touch and assign it as the default touch
				firstFinger = e.changedTouches[0];

				// Make a copy of the touch event
				event = {};
				for (key in firstFinger) {
					//if (firstFinger.hasOwnProperty(key)) { // Don't use due to Firefox and IE9
						event[key] = firstFinger[key];
					//}
				}

				event.x = (firstFinger.pageX - elementPos.x - controller.offsetX) * controller.scaleX;
				event.y = (firstFinger.pageY - elementPos.y - controller.offsetY) * controller.scaleY;
				event.type = e.type;

				event.touches = [];
				// For each touch currently on the screen
				for (i = 0; i < e.touches.length; i += 1) {

					event.touches[i] = {};
					for (key in e.touches[i]) {
						if (e.touches[i].hasOwnProperty(key)) {
							event.touches[i][key] = e.touches[i][key];
						}
					}

					event.touches[i].x = (event.touches[i].clientX - elementPos.x - controller.offsetX) * controller.scaleX;
					event.touches[i].y = (event.touches[i].clientY - elementPos.y - controller.offsetY) * controller.scaleY;

				}

				event.changedTouches = [];
				// For each touch invloved in this event on the screen
				for (i = 0; i < e.changedTouches.length; i += 1) {

					event.changedTouches[i] = {};
					for (key in e.changedTouches[i]) {
						if (e.changedTouches[i].hasOwnProperty(key)) {
							event.changedTouches[i][key] = e.changedTouches[i][key];
						}
					}

					event.changedTouches[i].x = (event.changedTouches[i].pageX - elementPos.x - controller.offsetX) * controller.scaleX;
					event.changedTouches[i].y = (event.changedTouches[i].pageY - elementPos.y - controller.offsetY) * controller.scaleY;
				}

				switch (event.type) {

				case "touchstart":

					eventType = "tap";
					controller.dispatchEvent("touchStart", event);

					break;

				case "touchmove":
					eventType = "drag";
					controller.dispatchEvent("touchMove", event);
					break;

				case "touchend":
					eventType = "release";
					controller.dispatchEvent("touchEnd", event);
					break;

				case "touchcancel":
					eventType = "cancel";
					controller.dispatchEvent("touchCancel", event);
					break;

				default:
					break;
				}

				dispatchTapEvent(event, eventType);
			}
		},

		onMouseEvent = function (e) {

			var i, key, eventType, event;

			if (controller.listening) {

				// Disable right click
				//if (e.button === 2) {
				//	return;
				//}

				event = {};
				for (key in e) {
					//if (e.hasOwnProperty(key)) { Don't use due to Firefox and IE9
						event[key] = e[key];
					//}
				}

				// TODO: ElementPos does not have to be calculated every time?
				elementPos = getElementPos(element);

				event.x = (event.pageX - elementPos.x - controller.offsetX) * controller.scaleX;
				event.y = (event.pageY - elementPos.y - controller.offsetY) * controller.scaleY;
				event.identifier = "mouse";
				event.touches = [event];
				event.changedTouches = [event];

				switch (event.type) {

				case "mousedown":
					eventType = "tap";
					controller.dispatchEvent("mouseDown", event);

					break;

				case "mousemove":
					eventType = "drag";
					controller.dispatchEvent("mouseMove", event);
					break;

				case "mouseup":
					eventType = "release";
					controller.dispatchEvent("mouseUp", event);
					break;

				case "mousecancel":
					eventType = "cancel";
					controller.dispatchEvent("mouseCancel", event);
					break;

				default:
					break;
				}

				dispatchTapEvent(event, eventType);
			}
		};

	controller.scaleX = 1;
	controller.scaleY = 1;
	controller.offsetX = 0;
	controller.offsetY = 0;
	controller.listening = true;

	controller.simulateKeyDownEvent = function (keyCode) {
		onKeyDownEvent({
			keyCode: keyCode
		});
	};

	controller.simulateKeyUpEvent = function (keyCode) {
		onKeyUpEvent({
			keyCode: keyCode
		});
	};

	init();

	return controller;
};<|endoftext|>


<commit_before>import app from 'app';
import _ from 'lodash';
import 'views/forms/edit/edit';
import 'views/forms/view/abs/view-abs-procedure.directive';

    export { default as template } from './edit-absProcedure.html';

  export default ["$scope", "realm", "$http", "$filter", "$q", "$routeParams", "$controller", "$location", function($scope, realm, $http, $filter, $q, $routeParams, $controller, $location) {
        $controller('editController', {
            $scope: $scope
        });

        $scope.path = $location.path();

        _.extend($scope.options, {
            jurisdictions: function() {
                return $q.all([
                    $http.get("/api/v2013/thesaurus/domains/D7BD5BDE-A6B9-4261-B788-16839CCC4F7E/terms", {
                        cache: true
                    }),
                    $http.get("/api/v2013/thesaurus/terms/5B6177DD-5E5E-434E-8CB7-D63D67D5EBED", {
                        cache: true
                    })
                ]).then(function(o) {
                    var jurisdictions = o[0].data;
                    jurisdictions.push(o[1].data);

                    _.forEach(jurisdictions, function(element) {
                        element.__value = element.name;
                    });

                    return jurisdictions;
                });
            },
            keywords   : function() {
                return $http.get("/api/v2013/thesaurus/domains/CA9BBEA9-AAA7-4F2F-B3A3-7ED180DE1924/terms", { cache: true }).then(function(o){return o.data;});
            }
        });

        $scope.ac_jurisdictions = function() {
            return $scope.options.jurisdictions().then(function(jurisdictions) {
                _.forEach(jurisdictions, function(element) {
                    element.__value = element.name;
                });
                return jurisdictions;
            });
        };

        $scope.onContactQuery = function(searchText){

            var queryOptions = {
                schemas	  : ['authority', 'contact'],
                realm     : realm.value,
                searchText: searchText
            }
            if ($scope.document && $scope.document.government)
                    queryOptions.government = $scope.document.government.identifier;

            return $scope.onBuildDocumentSelectorQuery(queryOptions);
        }

        $scope.onMeaureQuery = function(searchText){

            var queryOptions = {
                schemas	  : ['measure'],
                realm     : realm.value,
                searchText: searchText
            }
            if ($scope.document && $scope.document.government)
                queryOptions.government = $scope.document.government.identifier;

            return $scope.onBuildDocumentSelectorQuery(queryOptions);
        }
        //==================================
        //
        //==================================
        $scope.isSubNational = function(document) {

            document = document || $scope.document;

            return document &&
                document.jurisdiction &&
                document.jurisdiction.identifier == "DEBB019D-8647-40EC-8AE5-10CA88572F6E";
        };

        //==================================
        //
        //==================================
        $scope.isCommunity = function(document) {

            document = document || $scope.document;

            return document &&
                document.jurisdiction &&
                document.jurisdiction.identifier == "9627DF2B-FFAC-4F85-B075-AF783FF2A0B5";
        };
        //==================================
        //
        //==================================
        $scope.isOthers = function(document) {

            document = document || $scope.document;

            return document &&
                document.jurisdiction &&
                document.jurisdiction.identifier == "5B6177DD-5E5E-434E-8CB7-D63D67D5EBED";
        };
        //==================================
        //
        //==================================
        $scope.getCleanDocument = function(document) {

            document = document || $scope.document;

            if (!document)
                return undefined;

            //document = angular.fromJson(angular.toJson(document));

            if (document.jurisdiction && !$scope.isSubNational(document) && !$scope.isCommunity(document) && !$scope.isOthers(document)) {
                document.jurisdiction.customValue = undefined;
            }

            if (/^\s*$/g.test(document.notes))
                document.notes = undefined;

            return $scope.sanitizeDocument(document);
        };

        $scope.setDocument();
    }];

<commit_msg>ABS-PRO: update onContactQuery<commit_after>import app from 'app';
import _ from 'lodash';
import 'views/forms/edit/edit';
import 'views/forms/view/abs/view-abs-procedure.directive';

    export { default as template } from './edit-absProcedure.html';

  export default ["$scope", "realm", "$http", "$filter", "$q", "$routeParams", "$controller", "$location", function($scope, realm, $http, $filter, $q, $routeParams, $controller, $location) {
        $controller('editController', {
            $scope: $scope
        });

        $scope.path = $location.path();

        _.extend($scope.options, {
            jurisdictions: function() {
                return $q.all([
                    $http.get("/api/v2013/thesaurus/domains/D7BD5BDE-A6B9-4261-B788-16839CCC4F7E/terms", {
                        cache: true
                    }),
                    $http.get("/api/v2013/thesaurus/terms/5B6177DD-5E5E-434E-8CB7-D63D67D5EBED", {
                        cache: true
                    })
                ]).then(function(o) {
                    var jurisdictions = o[0].data;
                    jurisdictions.push(o[1].data);

                    _.forEach(jurisdictions, function(element) {
                        element.__value = element.name;
                    });

                    return jurisdictions;
                });
            },
            keywords   : function() {
                return $http.get("/api/v2013/thesaurus/domains/CA9BBEA9-AAA7-4F2F-B3A3-7ED180DE1924/terms", { cache: true }).then(function(o){return o.data;});
            }
        });

        $scope.ac_jurisdictions = function() {
            return $scope.options.jurisdictions().then(function(jurisdictions) {
                _.forEach(jurisdictions, function(element) {
                    element.__value = element.name;
                });
                return jurisdictions;
            });
        };

         $scope.onContactQuery = function(searchText){

                var queryOptions = {
                schemas : ['contact', 'authority'],
                realm : realm.value,
                searchText: searchText,
                query : `(schema_s:authority AND government_s:${$scope.document.government.identifier}) OR (schema_s:contact)`
                }
                return $scope.onBuildDocumentSelectorQuery(queryOptions);
            }

        $scope.onMeaureQuery = function(searchText){

            var queryOptions = {
                schemas	  : ['measure'],
                realm     : realm.value,
                searchText: searchText
            }
            if ($scope.document && $scope.document.government)
                queryOptions.government = $scope.document.government.identifier;

            return $scope.onBuildDocumentSelectorQuery(queryOptions);
        }
        //==================================
        //
        //==================================
        $scope.isSubNational = function(document) {

            document = document || $scope.document;

            return document &&
                document.jurisdiction &&
                document.jurisdiction.identifier == "DEBB019D-8647-40EC-8AE5-10CA88572F6E";
        };

        //==================================
        //
        //==================================
        $scope.isCommunity = function(document) {

            document = document || $scope.document;

            return document &&
                document.jurisdiction &&
                document.jurisdiction.identifier == "9627DF2B-FFAC-4F85-B075-AF783FF2A0B5";
        };
        //==================================
        //
        //==================================
        $scope.isOthers = function(document) {

            document = document || $scope.document;

            return document &&
                document.jurisdiction &&
                document.jurisdiction.identifier == "5B6177DD-5E5E-434E-8CB7-D63D67D5EBED";
        };
        //==================================
        //
        //==================================
        $scope.getCleanDocument = function(document) {

            document = document || $scope.document;

            if (!document)
                return undefined;

            //document = angular.fromJson(angular.toJson(document));

            if (document.jurisdiction && !$scope.isSubNational(document) && !$scope.isCommunity(document) && !$scope.isOthers(document)) {
                document.jurisdiction.customValue = undefined;
            }

            if (/^\s*$/g.test(document.notes))
                document.notes = undefined;

            return $scope.sanitizeDocument(document);
        };

        $scope.setDocument();
    }];

<|endoftext|>


<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

describe("media", function () {
    describe("MediaError object + error codes", function () {
        var MediaError = require('cordova/plugin/MediaError');
        it("should have no problem instantiating a MediaError object with the zero code", function () {
            var err = new MediaError(0);
            expect(err.code).toBe(0);
        });
    });
});
<commit_msg>removed invalid test, MediaError constructor is not defined by the spec, duck-typing testable only<commit_after><|endoftext|>