<commit_before>var recordTreeViewController = function($scope, $element, $timeout, htmlHelpers, stylesheetService, treeService, recordTreeService, recordTreeElementService, nodeSelectionService, treeColumnService, contextMenuService, hotkeyService, hotkeyFactory, contextMenuFactory) {
    // link view to scope
    let data = $scope.$parent.tab.data;
    data.scope = $scope;

    // helper/scope variables
    let hotkeys = hotkeyFactory.recordTreeHotkeys();
    $scope.overrides = [];
    $scope.contextMenuItems = contextMenuFactory.recordTreeItems;
    $scope.focusedIndex = -1;

    // inherited functions
    treeService.buildFunctions($scope, $element);
    recordTreeService.buildFunctions($scope);
    recordTreeElementService.buildFunctions($scope);
    nodeSelectionService.buildFunctions($scope);
    treeColumnService.buildFunctions($scope, '.record-tree-view', false, true);
    hotkeyService.buildOnKeyDown($scope, 'onTreeKeyDown', hotkeys);

    // scope functions
    $scope.toggleAddressBar = function(visible) {
        $scope.showAddressBar = visible;
        visible ? $timeout($scope.focusAddressInput, 50) : $scope.treeElement.focus();
    };

    $scope.toggleEditModal = function(visible) {
        $scope.showEditModal = visible;
    };

    $scope.focusAddressInput = function () {
        let addressInput = htmlHelpers.resolveElement($scope.tabView, 'record-address-bar/input');
        if (addressInput) addressInput.focus();
    };

    $scope.onScroll = function(e) {
        $scope.columnsElement.scrollLeft = e.currentTarget.scrollLeft;
    };

    $scope.onNodeDoubleClick = function(e, node) {
        if (e.srcElement && e.srcElement.classList.contains('expand-node')) return;
        if (node.can_expand) $scope.toggleNode(null, node);
    };

    $scope.onCellDoubleClick = function(e, node, index) {
        if (!node.handles[index - 1]) {
            $scope.addElement(node, index);
            $timeout(() => $scope.editElement(node, index), 50);
        } else {
            $scope.editElement(node, index);
        }
        e.stopImmediatePropagation();
    };

    $scope.onCellMouseDown = function(index) {
        let oldIndex = $scope.focusedIndex;
        $scope.focusedIndex = index;
        if (oldIndex !== index) $scope.updateNodeLabels();
    };

    $scope.onDragOver = function() {
        let dragData = $scope.$root.dragData;
        if (dragData && dragData.source === 'mainTreeView') return true;
    };

    $scope.onDrop = function() {
        let dragData = $scope.$root.dragData;
        if (!dragData || dragData.source !== 'mainTreeView') return;
        let node = dragData.node,
            path = node.element_type === xelib.etFile ? 'File Header' : '';
        $scope.record = xelib.GetElement(node.handle, path);
    };

    $scope.showNodeContextMenu = function(e) {
        let offset = { top: e.clientY, left: e.clientX},
            items = contextMenuFactory.recordTreeItems,
            menuItems = contextMenuService.buildMenuItems($scope, items);
        $timeout(() => $scope.$emit('openContextMenu', offset, menuItems));
    };

    $scope.handleEnter = function(e) {
        $scope.onNodeDoubleClick(e, $scope.lastSelectedNode());
        e.stopImmediatePropagation();
    };

    $scope.releaseHandles = function(oldValue) {
        xelib.Release(oldValue);
        xelib.ReleaseNodes($scope.virtualNodes);
        $scope.overrides.forEach(xelib.Release);
        $scope.overrides = [];
    };

    // event handling
    $scope.$on('setRecord', function(e, record) {
        $scope.record = record;
        e.stopPropagation();
    });

    $scope.$on('nodeUpdated', $scope.reload);
    $scope.$on('nodeAdded', $scope.reload);

    // initialization
    $scope.$watch('record', function(newValue, oldValue) {
        if (oldValue == newValue) return;
        if (oldValue) $scope.releaseHandles(oldValue);
        if (!newValue) return;
        if (!xelib.IsMaster(newValue)) {
            $scope.record = xelib.GetMaster(newValue);
        } else {
            $scope.buildColumns();
            $scope.buildTree();
            $scope.$broadcast('recordChanged');
            $timeout($scope.resolveElements, 100);
        }
    });

    $scope.showAddressBar = true;
    $scope.autoExpand = true;
    $timeout($scope.linkToMainTreeView, 100);
};<commit_msg>fixed bug with not updating element names when record selection is changed and user refocuses the same index<commit_after>var recordTreeViewController = function($scope, $element, $timeout, htmlHelpers, stylesheetService, treeService, recordTreeService, recordTreeElementService, nodeSelectionService, treeColumnService, contextMenuService, hotkeyService, hotkeyFactory, contextMenuFactory) {
    // link view to scope
    let data = $scope.$parent.tab.data;
    data.scope = $scope;

    // helper/scope variables
    let hotkeys = hotkeyFactory.recordTreeHotkeys();
    $scope.overrides = [];
    $scope.contextMenuItems = contextMenuFactory.recordTreeItems;

    // inherited functions
    treeService.buildFunctions($scope, $element);
    recordTreeService.buildFunctions($scope);
    recordTreeElementService.buildFunctions($scope);
    nodeSelectionService.buildFunctions($scope);
    treeColumnService.buildFunctions($scope, '.record-tree-view', false, true);
    hotkeyService.buildOnKeyDown($scope, 'onTreeKeyDown', hotkeys);

    // scope functions
    $scope.toggleAddressBar = function(visible) {
        $scope.showAddressBar = visible;
        visible ? $timeout($scope.focusAddressInput, 50) : $scope.treeElement.focus();
    };

    $scope.toggleEditModal = function(visible) {
        $scope.showEditModal = visible;
    };

    $scope.focusAddressInput = function () {
        let addressInput = htmlHelpers.resolveElement($scope.tabView, 'record-address-bar/input');
        if (addressInput) addressInput.focus();
    };

    $scope.onScroll = function(e) {
        $scope.columnsElement.scrollLeft = e.currentTarget.scrollLeft;
    };

    $scope.onNodeDoubleClick = function(e, node) {
        if (e.srcElement && e.srcElement.classList.contains('expand-node')) return;
        if (node.can_expand) $scope.toggleNode(null, node);
    };

    $scope.onCellDoubleClick = function(e, node, index) {
        if (!node.handles[index - 1]) {
            $scope.addElement(node, index);
            $timeout(() => $scope.editElement(node, index), 50);
        } else {
            $scope.editElement(node, index);
        }
        e.stopImmediatePropagation();
    };

    $scope.onCellMouseDown = function(index) {
        let oldIndex = $scope.focusedIndex;
        $scope.focusedIndex = index;
        if (oldIndex !== index) $scope.updateNodeLabels();
    };

    $scope.onDragOver = function() {
        let dragData = $scope.$root.dragData;
        if (dragData && dragData.source === 'mainTreeView') return true;
    };

    $scope.onDrop = function() {
        let dragData = $scope.$root.dragData;
        if (!dragData || dragData.source !== 'mainTreeView') return;
        let node = dragData.node,
            path = node.element_type === xelib.etFile ? 'File Header' : '';
        $scope.record = xelib.GetElement(node.handle, path);
    };

    $scope.showNodeContextMenu = function(e) {
        let offset = { top: e.clientY, left: e.clientX},
            items = contextMenuFactory.recordTreeItems,
            menuItems = contextMenuService.buildMenuItems($scope, items);
        $timeout(() => $scope.$emit('openContextMenu', offset, menuItems));
    };

    $scope.handleEnter = function(e) {
        $scope.onNodeDoubleClick(e, $scope.lastSelectedNode());
        e.stopImmediatePropagation();
    };

    $scope.releaseHandles = function(oldValue) {
        xelib.Release(oldValue);
        xelib.ReleaseNodes($scope.virtualNodes);
        $scope.overrides.forEach(xelib.Release);
        $scope.overrides = [];
    };

    // event handling
    $scope.$on('setRecord', function(e, record) {
        $scope.record = record;
        e.stopPropagation();
    });

    $scope.$on('nodeUpdated', $scope.reload);
    $scope.$on('nodeAdded', $scope.reload);

    // initialization
    $scope.$watch('record', function(newValue, oldValue) {
        if (oldValue == newValue) return;
        if (oldValue) $scope.releaseHandles(oldValue);
        if (!newValue) return;
        if (!xelib.IsMaster(newValue)) {
            $scope.record = xelib.GetMaster(newValue);
        } else {
            $scope.focusedIndex = -1;
            $scope.buildColumns();
            $scope.buildTree();
            $scope.$broadcast('recordChanged');
            $timeout($scope.resolveElements, 100);
        }
    });

    $scope.showAddressBar = true;
    $scope.autoExpand = true;
    $timeout($scope.linkToMainTreeView, 100);
};<|endoftext|>


<commit_before>$(function() {
  var govUkWelcomeCopy = [
    "
",
    "
Beta

Close
",
    "
",
    "
Welcome to GOV.UK, an experimental trial (\u2018beta\u2019) of a home for government information ",
    "and services, and the first steps towards a single government website.
",
    "
PLEASE BE AWARE \u2013 this is a test website. It may contain ",
    "inaccuracies or be misleading. ",
    "Directgov and Businesslink remain the official ",
    "websites for government information and services.
",
    "
Your suggestions will help us make this site better, so if ",
    "you have any comments please leave us feedback.
",
    "
Thanks, I\u2019ve ",
    "read the warning
",
    "
N.B. This site uses \u2018cookies\u2019 and Google Analytics. Closing ",
    "this page sets a cookie so you don\u2019t see it again. There\u2019s more information on cookies at ",
    "AboutCookies.org.
",
    "

"
  ].join('');

  var dpWelcomeCopy = [
    "
",
    "
Alpha

Close
",
    "
",
    "
",
    "  Welcome to the first draft of the Design Principles for GOV.UK. This",
    "  is an \u2018alpha\u2019 draft \u2014 there\u2019s lots more work to be done and many more",
    "  resources to be added.",
    "
",
    "
These principles are intended to be \u2018carrot not stick\u2019. They\u2019re not a ",
    "list of bad things to be avoided, they\u2019re a set of principles to ",
    "inspire you, accompanied by examples which explain things further and ",
    "code and resources which will make the principles easier to follow.
",
    "
We\u2019d love to know what you think \u2014 will these principles and examples ",
    "be useful for you? Please let us know via govuk-feedback@digital.cabinet-office.gov.uk.
",
    "
Thanks, I\u2019ve ",
    "read the warning
",
    "
N.B. This site uses \u2018cookies\u2019 and Google Analytics. Closing ",
    "this page sets a cookie so you don\u2019t see it again. There\u2019s more information on cookies at ",
    "AboutCookies.org.
",
    "

"
  ].join('');

  function getUrlVars() {
    var vars = [], hash;
    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for(var i = 0, len = hashes.length; i < len; i++) {
      hash = hashes[i].split('=');
      vars.push(hash[0]);
      vars[hash[0]] = hash[1];
    }
    return vars;
  }

  function getUrlVar(name){
    return getUrlVars()[name];
  }

  function onDesignPrinciples() {
    var pathName = window.location.pathname,
        isDP = !! pathName.match(/^\/designprinciples/),
        isPF;

    if (isDP) {
      // performance framework is in beta so return false to force that popup
      isPF = !! pathName.match(/^\/designprinciples\/performanceframework/);
      if (isPF) {
        return false;
      }

      return true;
    }

    return false;
  }

  function activeCookieName() {
    if (onDesignPrinciples()){
      return 'dp-tour';
    } else {
      return 'govuk-tour';
    }
  }

  function popupCopy() {
    if (onDesignPrinciples()){
      return dpWelcomeCopy;
    } else {
      return govUkWelcomeCopy;
    }
  }

  function showPopup() {
    if (getUrlVar('nopopup') != "true") {
      if(getCookie(activeCookieName()) != "dismiss"){
        BetaPopup.popup(popupCopy(), "welcome-tour");
      }
    }
  }

  showPopup();

  function setCookie(name, value, days){
    var cookieString = name + "=" + value + "; path=/";
    if (days) {
      var date = new Date();
      date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
      cookieString = cookieString + "; expires=" + date.toGMTString();
    }
    if (document.location.protocol == 'https:'){
      cookieString = cookieString + "; Secure";
    }
    document.cookie = cookieString;
  }

  function getCookie(name){
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i = 0, len = ca.length; i < len; i++) {
      var c = ca[i];
      while (c.charAt(0) == ' ') {
        c = c.substring(1, c.length);
      }
      if (c.indexOf(nameEQ) === 0) {
        return c.substring(nameEQ.length, c.length);
      }
    }
    return null;
  }

  $(".welcome-tour .close").live("click", function(){
    setCookie(activeCookieName(), "dismiss", 7);
    return;
  });

  $(".thanks-dismiss").live("click", function(){
    setCookie(activeCookieName(), "dismiss", 7);
    closePopup();
    return false;
  });

  closePopup = function(){
    $("#popup").fadeOut(400, function(){
      $("#mask").slideUp('fast');
      $("#mask").remove();
      $("#popup").remove();
    });

    $(".header-global h1 a").focus();
  };

});
<commit_msg>Add javascript logic to show and hide the cookie message depending on whether the cookie has been set yet<commit_after>$(function() {
  var govUkWelcomeCopy = [
    "
",
    "
Beta

Close
",
    "
",
    "
Welcome to GOV.UK, an experimental trial (\u2018beta\u2019) of a home for government information ",
    "and services, and the first steps towards a single government website.
",
    "
PLEASE BE AWARE \u2013 this is a test website. It may contain ",
    "inaccuracies or be misleading. ",
    "Directgov and Businesslink remain the official ",
    "websites for government information and services.
",
    "
Your suggestions will help us make this site better, so if ",
    "you have any comments please leave us feedback.
",
    "
Thanks, I\u2019ve ",
    "read the warning
",
    "
N.B. This site uses \u2018cookies\u2019 and Google Analytics. Closing ",
    "this page sets a cookie so you don\u2019t see it again. There\u2019s more information on cookies at ",
    "AboutCookies.org.
",
    "

"
  ].join('');

  var dpWelcomeCopy = [
    "
",
    "
Alpha

Close
",
    "
",
    "
",
    "  Welcome to the first draft of the Design Principles for GOV.UK. This",
    "  is an \u2018alpha\u2019 draft \u2014 there\u2019s lots more work to be done and many more",
    "  resources to be added.",
    "
",
    "
These principles are intended to be \u2018carrot not stick\u2019. They\u2019re not a ",
    "list of bad things to be avoided, they\u2019re a set of principles to ",
    "inspire you, accompanied by examples which explain things further and ",
    "code and resources which will make the principles easier to follow.
",
    "
We\u2019d love to know what you think \u2014 will these principles and examples ",
    "be useful for you? Please let us know via govuk-feedback@digital.cabinet-office.gov.uk.
",
    "
Thanks, I\u2019ve ",
    "read the warning
",
    "
N.B. This site uses \u2018cookies\u2019 and Google Analytics. Closing ",
    "this page sets a cookie so you don\u2019t see it again. There\u2019s more information on cookies at ",
    "AboutCookies.org.
",
    "

"
  ].join('');

  function getUrlVars() {
    var vars = [], hash;
    var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
    for(var i = 0, len = hashes.length; i < len; i++) {
      hash = hashes[i].split('=');
      vars.push(hash[0]);
      vars[hash[0]] = hash[1];
    }
    return vars;
  }

  function getUrlVar(name){
    return getUrlVars()[name];
  }

  function onDesignPrinciples() {
    var pathName = window.location.pathname,
        isDP = !! pathName.match(/^\/designprinciples/),
        isPF;

    if (isDP) {
      // performance framework is in beta so return false to force that popup
      isPF = !! pathName.match(/^\/designprinciples\/performanceframework/);
      if (isPF) {
        return false;
      }

      return true;
    }

    return false;
  }

  function activeCookieName() {
    if (onDesignPrinciples()){
      return 'dp-tour';
    } else {
      return 'govuk-tour';
    }
  }

  function popupCopy() {
    if (onDesignPrinciples()){
      return dpWelcomeCopy;
    } else {
      return govUkWelcomeCopy;
    }
  }

  function showPopup() {
    if (getUrlVar('nopopup') != "true") {
      if(getCookie(activeCookieName()) != "dismiss"){
        BetaPopup.popup(popupCopy(), "welcome-tour");
      }
    }
  }

  showPopup();

  $(".welcome-tour .close").live("click", function(){
    setCookie(activeCookieName(), "dismiss", 7);
    return;
  });

  $(".thanks-dismiss").live("click", function(){
    setCookie(activeCookieName(), "dismiss", 7);
    closePopup();
    return false;
  });

  closePopup = function(){
    $("#popup").fadeOut(400, function(){
      $("#mask").slideUp('fast');
      $("#mask").remove();
      $("#popup").remove();
    });

    $(".header-global h1 a").focus();
  };

});

function setCookie(name, value, days){
  var cookieString = name + "=" + value + "; path=/";
  if (days) {
    var date = new Date();
    date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
    cookieString = cookieString + "; expires=" + date.toGMTString();
  }
  if (document.location.protocol == 'https:'){
    cookieString = cookieString + "; Secure";
  }
  document.cookie = cookieString;
}

function getCookie(name){
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i = 0, len = ca.length; i < len; i++) {
    var c = ca[i];
    while (c.charAt(0) == ' ') {
      c = c.substring(1, c.length);
    }
    if (c.indexOf(nameEQ) === 0) {
      return c.substring(nameEQ.length, c.length);
    }
  }
  return null;
}

$(function() {
  if (document.getElementById('global-cookie-message') && getCookie('seen_cookie_message') === null) {
    $('#global-cookie-message').show();
    setCookie('seen_cookie_message', 'yes', 365);
  }
});
<|endoftext|>


<commit_before>import {
  SHOW_MORE_ENTRIES,
} from '../constants/ActionTypes';

const initialState = 5;

export default (state = initialState, action) => {
    switch (action.type) {
        case SHOW_MORE_ENTRIES:
            return state + 5;

        default:
            return state;
    }
}
<commit_msg>applied initialState variable<commit_after>import {
  SHOW_MORE_ENTRIES,
} from '../constants/ActionTypes';

const initialState = 5;

export default (state = initialState, action) => {
    switch (action.type) {
        case SHOW_MORE_ENTRIES:
            return state + initialState;

        default:
            return state;
    }
}
<|endoftext|>


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

import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { Field } from 'redux-form';
import { format, file } from 'redux-form-validators';

import HorizontalInput from '../ui/reduxForm/HorizontalInput';
import HorizontalFileInput from '../ui/reduxForm/HorizontalFileInput';
import HorizontalDirectoryInput, {
  validateDirectoryInput
} from '../ui/reduxForm/HorizontalDirectoryInput';
import TabPane from '../ui/TabPane';
import PlanUploadTypeRadios from './PlanUploadTypeRadios';
import { GIT_URL_REGEX } from '../../constants/PlansConstants';

const messages = defineMessages({
  addPlanName: {
    id: 'PlanFormTabs.addPlanName',
    defaultMessage: 'Add a Plan Name',
    description: 'Tooltip for "Plan Name" form field'
  },
  planFiles: {
    id: 'PlanFormTabs.planFiles',
    defaultMessage: 'Plan Files'
  },
  planName: {
    id: 'PlanFormTabs.planName',
    defaultMessage: 'Plan Name'
  },
  planNameValidationError: {
    id: 'PlanFormTabs.planNameValidationError',
    defaultMessage:
      'Please use only lowercase alphanumeric characters and hyphens (-).'
  },
  planTarball: {
    id: 'PlanFormTabs.planTarball',
    defaultMessage: 'Plan Tarball'
  },
  tarballInputDescription: {
    id: 'PlanFieldsTab.tarballInputDescription',
    defaultMessage:
      'Provided tarball must not contain root directory, when creating the tarball use following command: {command}'
  },
  directoryInputDescription: {
    id: 'PlanFieldsTab.directoryInputDescription',
    defaultMessage:
      'Provide a directory of Heat templates which defines a deployment plan.'
  },
  gitUrl: {
    id: 'PlanFormTabs.gitUrl',
    defaultMessage: 'Git Repository URL'
  },
  gitUrlInputDescription: {
    id: 'PlanFieldsTab.gitUrlInputDescription',
    defaultMessage:
      'Provide a Git repository URL containing Heat templates which define a deployment plan.'
  },
  gitUrlValidationError: {
    id: 'PlanFormTabs.gitUrlValidationError',
    defaultMessage: 'Please provide a valid Git repository URL.'
  }
});

const PlanFieldsTab = ({ active, intl: { formatMessage }, planUploadType }) => (
  <TabPane isActive={active}>
    <Field
      id="planName"
      component={HorizontalInput}
      name="planName"
      label={formatMessage(messages.planName)}
      labelColumns={3}
      placeholder={formatMessage(messages.addPlanName)}
      validate={format({
        with: /^[a-z][a-z0-9-]+$/,
        message: formatMessage(messages.planNameValidationError)
      })}
      required
    />
    <PlanUploadTypeRadios />
    {planUploadType === 'directory' && (
      <Field
        id="files"
        name="files"
        component={HorizontalDirectoryInput}
        label={formatMessage(messages.planFiles)}
        labelColumns={3}
        validate={validateDirectoryInput}
        description={formatMessage(messages.directoryInputDescription)}
        required
      />
    )}
    {planUploadType === 'tarball' && (
      <Field
        id="tarball"
        name="tarball"
        component={HorizontalFileInput}
        type="file"
        label={formatMessage(messages.planTarball)}
        labelColumns={3}
        validate={file({ accept: 'application/x-gzip, application/gzip' })}
        description={
          <FormattedMessage
            {...messages.tarballInputDescription}
            values={{
              command: (

                  tar -czf heat-templates.tar.gz -C tripleo-heat-templates/ .

              )
            }}
          />
        }
        required
      />
    )}
    {planUploadType === 'git' && (
      <Field
        id="gitUrl"
        name="gitUrl"
        component={HorizontalInput}
        label={formatMessage(messages.gitUrl)}
        labelColumns={3}
        validate={format({
          with: GIT_URL_REGEX,
          message: formatMessage(messages.gitUrlValidationError)
        })}
        description={formatMessage(messages.gitUrlInputDescription)}
        required
      />
    )}
  </TabPane>
);
PlanFieldsTab.propTypes = {
  active: PropTypes.bool.isRequired,
  intl: PropTypes.object,
  planUploadType: PropTypes.string.isRequired
};
PlanFieldsTab.defaultProps = { active: false };

export default injectIntl(PlanFieldsTab);
<commit_msg>Fix tgz plan upload error on some OSes<commit_after>/**
 * Copyright 2018 Red Hat Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { Field } from 'redux-form';
import { format, file } from 'redux-form-validators';

import HorizontalInput from '../ui/reduxForm/HorizontalInput';
import HorizontalFileInput from '../ui/reduxForm/HorizontalFileInput';
import HorizontalDirectoryInput, {
  validateDirectoryInput
} from '../ui/reduxForm/HorizontalDirectoryInput';
import TabPane from '../ui/TabPane';
import PlanUploadTypeRadios from './PlanUploadTypeRadios';
import { GIT_URL_REGEX } from '../../constants/PlansConstants';

const messages = defineMessages({
  addPlanName: {
    id: 'PlanFormTabs.addPlanName',
    defaultMessage: 'Add a Plan Name',
    description: 'Tooltip for "Plan Name" form field'
  },
  planFiles: {
    id: 'PlanFormTabs.planFiles',
    defaultMessage: 'Plan Files'
  },
  planName: {
    id: 'PlanFormTabs.planName',
    defaultMessage: 'Plan Name'
  },
  planNameValidationError: {
    id: 'PlanFormTabs.planNameValidationError',
    defaultMessage:
      'Please use only lowercase alphanumeric characters and hyphens (-).'
  },
  planTarball: {
    id: 'PlanFormTabs.planTarball',
    defaultMessage: 'Plan Tarball'
  },
  tarballInputDescription: {
    id: 'PlanFieldsTab.tarballInputDescription',
    defaultMessage:
      'Provided tarball must not contain root directory, when creating the tarball use following command: {command}'
  },
  directoryInputDescription: {
    id: 'PlanFieldsTab.directoryInputDescription',
    defaultMessage:
      'Provide a directory of Heat templates which defines a deployment plan.'
  },
  gitUrl: {
    id: 'PlanFormTabs.gitUrl',
    defaultMessage: 'Git Repository URL'
  },
  gitUrlInputDescription: {
    id: 'PlanFieldsTab.gitUrlInputDescription',
    defaultMessage:
      'Provide a Git repository URL containing Heat templates which define a deployment plan.'
  },
  gitUrlValidationError: {
    id: 'PlanFormTabs.gitUrlValidationError',
    defaultMessage: 'Please provide a valid Git repository URL.'
  }
});

const PlanFieldsTab = ({ active, intl: { formatMessage }, planUploadType }) => (
  <TabPane isActive={active}>
    <Field
      id="planName"
      component={HorizontalInput}
      name="planName"
      label={formatMessage(messages.planName)}
      labelColumns={3}
      placeholder={formatMessage(messages.addPlanName)}
      validate={format({
        with: /^[a-z][a-z0-9-]+$/,
        message: formatMessage(messages.planNameValidationError)
      })}
      required
    />
    <PlanUploadTypeRadios />
    {planUploadType === 'directory' && (
      <Field
        id="files"
        name="files"
        component={HorizontalDirectoryInput}
        label={formatMessage(messages.planFiles)}
        labelColumns={3}
        validate={validateDirectoryInput}
        description={formatMessage(messages.directoryInputDescription)}
        required
      />
    )}
    {planUploadType === 'tarball' && (
      <Field
        id="tarball"
        name="tarball"
        component={HorizontalFileInput}
        type="file"
        label={formatMessage(messages.planTarball)}
        labelColumns={3}
        validate={file({
          accept: 'application/x-gzip, application/gzip, .tgz, .tar.gz'
        })}
        description={
          <FormattedMessage
            {...messages.tarballInputDescription}
            values={{
              command: (

                  tar -czf heat-templates.tar.gz -C tripleo-heat-templates/ .

              )
            }}
          />
        }
        required
      />
    )}
    {planUploadType === 'git' && (
      <Field
        id="gitUrl"
        name="gitUrl"
        component={HorizontalInput}
        label={formatMessage(messages.gitUrl)}
        labelColumns={3}
        validate={format({
          with: GIT_URL_REGEX,
          message: formatMessage(messages.gitUrlValidationError)
        })}
        description={formatMessage(messages.gitUrlInputDescription)}
        required
      />
    )}
  </TabPane>
);
PlanFieldsTab.propTypes = {
  active: PropTypes.bool.isRequired,
  intl: PropTypes.object,
  planUploadType: PropTypes.string.isRequired
};
PlanFieldsTab.defaultProps = { active: false };

export default injectIntl(PlanFieldsTab);
<|endoftext|>


<commit_before>import * as fs from 'fs'

import { createHash } from 'crypto'

import parse from './parse'
import resolve from './resolve'
import isIgnored from './ignore'

// map from settings sha1 => path => export map objects
const exportCaches = new Map()

export default class ExportMap {
  constructor(context) {
    this.context = context
    this.named = new Set()

    this.errors = []
  }

  get settings() { return this.context && this.context.settings }

  get hasDefault() { return this.named.has('default') }
  get hasNamed() { return this.named.size > (this.hasDefault ? 1 : 0) }

  static get(source, context) {

    var path = resolve(source, context)
    if (path == null) return null

    return ExportMap.for(path, context)
  }

  static for(path, context) {
    let exportMap

    const cacheKey = hashObject({
      settings: context.settings,
      parserPath: context.parserPath,
      parserOptions: context.parserOptions,
    })
    let exportCache = exportCaches.get(cacheKey)
    if (exportCache === undefined) {
      exportCache = new Map()
      exportCaches.set(cacheKey, exportCache)
    }

    exportMap = exportCache.get(path)
    // return cached ignore
    if (exportMap === null) return null

    const stats = fs.statSync(path)
    if (exportMap != null) {
      // date equality check
      if (exportMap.mtime - stats.mtime === 0) {
        return exportMap
      }
      // future: check content equality?
    }

    exportMap = ExportMap.parse(path, context)
    exportMap.mtime = stats.mtime

    // ignore empties, optionally
    if (exportMap.named.size === 0 && isIgnored(path, context)) {
      exportMap = null
    }

    exportCache.set(path, exportMap)

    return exportMap
  }

  static parse(path, context) {
    var m = new ExportMap(context)

    try {
      var ast = parse(path, context)
    } catch (err) {
      m.errors.push(err)
      return m // can't continue
    }

    ast.body.forEach(function (n) {
      m.captureDefault(n)
      m.captureAll(n, path)
      m.captureNamedDeclaration(n, path)
    })

    return m
  }

  resolveReExport(node, base) {
    var remotePath = resolve.relative(node.source.value, base, this.settings)
    if (remotePath == null) return null

    return ExportMap.for(remotePath, this.context)
  }

  captureDefault(n) {
    if (n.type !== 'ExportDefaultDeclaration') return
    this.named.add('default')
  }

  /**
   * capture all named exports from remote module.
   *
   * returns null if this node wasn't an ExportAllDeclaration
   * returns false if it was not resolved
   * returns true if it was resolved + parsed
   *
   * @param  {node} n
   * @param  {string} path - the path of the module currently parsing
   * @return {boolean?}
   */
  captureAll(n, path) {
    if (n.type !== 'ExportAllDeclaration') return null

    var remoteMap = this.resolveReExport(n, path)
    if (remoteMap == null) return false

    remoteMap.named.forEach(function (name) { this.named.add(name) }.bind(this))

    return true
  }

  captureNamedDeclaration(n, path) {
    if (n.type !== 'ExportNamedDeclaration') return

    // capture declaration
    if (n.declaration != null) {
      switch (n.declaration.type) {
        case 'FunctionDeclaration':
        case 'ClassDeclaration':
        case 'TypeAlias': // flowtype with babel-eslint parser
          this.named.add(n.declaration.id.name)
          break
        case 'VariableDeclaration':
          n.declaration.declarations.forEach((d) =>
            recursivePatternCapture(d.id, id => this.named.add(id.name)))
          break
      }
    }

    // capture specifiers
    let remoteMap
    if (n.source) remoteMap = this.resolveReExport(n, path)

    n.specifiers.forEach(function (s) {
      if (s.type === 'ExportDefaultSpecifier') {
        // don't add it if it is not present in the exported module
        if (!remoteMap || !remoteMap.hasDefault) return
      }

      this.named.add(s.exported.name)
    }.bind(this))
  }

  reportErrors(context, declaration) {
    context.report({
      node: declaration.source,
      message: `Parse errors in imported module '${declaration.source.value}': ` +
                  `${this.errors
                        .map(e => `${e.message} (${e.lineNumber}:${e.column})`)
                        .join(', ')}`,
    })
  }
}

/**
 * Traverse a patter/identifier node, calling 'callback'
 * for each leaf identifier.
 * @param  {node}   pattern
 * @param  {Function} callback
 * @return {void}
 */
export function recursivePatternCapture(pattern, callback) {
  switch (pattern.type) {
    case 'Identifier': // base case
      callback(pattern)
      break

    case 'ObjectPattern':
      pattern.properties.forEach(({ value }) => {
        recursivePatternCapture(value, callback)
      })
      break

    case 'ArrayPattern':
      pattern.elements.forEach((element) => {
        if (element == null) return
        recursivePatternCapture(element, callback)
      })
      break
  }
}

function hashObject(object) {
  const settingsShasum = createHash('sha1')
  settingsShasum.update(JSON.stringify(object))
  return settingsShasum.digest('hex')
}
<commit_msg>simplified export collection<commit_after>import * as fs from 'fs'

import { createHash } from 'crypto'

import parse from './parse'
import resolve from './resolve'
import isIgnored from './ignore'

// map from settings sha1 => path => export map objects
const exportCaches = new Map()

export default class ExportMap {
  constructor(context) {
    this.context = context
    this.named = new Set()

    this.errors = []
  }

  get settings() { return this.context && this.context.settings }

  get hasDefault() { return this.named.has('default') }
  get hasNamed() { return this.named.size > (this.hasDefault ? 1 : 0) }

  static get(source, context) {

    var path = resolve(source, context)
    if (path == null) return null

    return ExportMap.for(path, context)
  }

  static for(path, context) {
    let exportMap

    const cacheKey = hashObject({
      settings: context.settings,
      parserPath: context.parserPath,
      parserOptions: context.parserOptions,
    })
    let exportCache = exportCaches.get(cacheKey)
    if (exportCache === undefined) {
      exportCache = new Map()
      exportCaches.set(cacheKey, exportCache)
    }

    exportMap = exportCache.get(path)
    // return cached ignore
    if (exportMap === null) return null

    const stats = fs.statSync(path)
    if (exportMap != null) {
      // date equality check
      if (exportMap.mtime - stats.mtime === 0) {
        return exportMap
      }
      // future: check content equality?
    }

    exportMap = ExportMap.parse(path, context)
    exportMap.mtime = stats.mtime

    // ignore empties, optionally
    if (exportMap.named.size === 0 && isIgnored(path, context)) {
      exportMap = null
    }

    exportCache.set(path, exportMap)

    return exportMap
  }

  static parse(path, context) {
    var m = new ExportMap(context)

    try {
      var ast = parse(path, context)
    } catch (err) {
      m.errors.push(err)
      return m // can't continue
    }

    ast.body.forEach(function (n) {
      if (n.type === 'ExportDefaultDeclaration') {
        m.named.add('default')
        return
      }

      if (n.type === 'ExportAllDeclaration') {
        let remoteMap = m.resolveReExport(n, path)
        if (remoteMap == null) return

        remoteMap.named.forEach((name) => { m.named.add(name) })
        return
      }

      if (n.type === 'ExportNamedDeclaration'){

        // capture declaration
        if (n.declaration != null) {
          switch (n.declaration.type) {
            case 'FunctionDeclaration':
            case 'ClassDeclaration':
            case 'TypeAlias': // flowtype with babel-eslint parser
              m.named.add(n.declaration.id.name)
              break
            case 'VariableDeclaration':
              n.declaration.declarations.forEach((d) =>
                recursivePatternCapture(d.id, id => m.named.add(id.name)))
              break
          }
        }

        // capture specifiers
        let remoteMap
        if (n.source) remoteMap = m.resolveReExport(n, path)

        n.specifiers.forEach(function (s) {
          if (s.type === 'ExportDefaultSpecifier') {
            // don't add it if it is not present in the exported module
            if (!remoteMap || !remoteMap.hasDefault) return
          }

          m.named.add(s.exported.name)
        })
      }

    })

    return m
  }

  resolveReExport(node, base) {
    var remotePath = resolve.relative(node.source.value, base, this.settings)
    if (remotePath == null) return null

    return ExportMap.for(remotePath, this.context)
  }

  reportErrors(context, declaration) {
    context.report({
      node: declaration.source,
      message: `Parse errors in imported module '${declaration.source.value}': ` +
                  `${this.errors
                        .map(e => `${e.message} (${e.lineNumber}:${e.column})`)
                        .join(', ')}`,
    })
  }
}

/**
 * Traverse a patter/identifier node, calling 'callback'
 * for each leaf identifier.
 * @param  {node}   pattern
 * @param  {Function} callback
 * @return {void}
 */
export function recursivePatternCapture(pattern, callback) {
  switch (pattern.type) {
    case 'Identifier': // base case
      callback(pattern)
      break

    case 'ObjectPattern':
      pattern.properties.forEach(({ value }) => {
        recursivePatternCapture(value, callback)
      })
      break

    case 'ArrayPattern':
      pattern.elements.forEach((element) => {
        if (element == null) return
        recursivePatternCapture(element, callback)
      })
      break
  }
}

function hashObject(object) {
  const settingsShasum = createHash('sha1')
  settingsShasum.update(JSON.stringify(object))
  return settingsShasum.digest('hex')
}
<|endoftext|>


<commit_before>/*global web3*/
const fs = require('../../core/fs.js');
const utils = require('../../utils/utils.js');

class ENS {
  constructor(embark, _options) {
    this.logger = embark.logger;
    this.events = embark.events;
    this.namesConfig = embark.config.namesystemConfig;
    this.embark = embark;
    this.ensRegistry = null;
    this.ensResolver = null;

    this.addENSToEmbarkJS();
    this.addSetProvider();
  }

  addENSToEmbarkJS() {
    const self = this;
    // TODO: make this a shouldAdd condition
    if (this.namesConfig === {}) {
      return;
    }

    if ((this.namesConfig.available_providers.indexOf('ens') < 0) && (this.namesConfig.provider !== 'ens' || this.namesConfig.enabled !== true)) {
      return;
    }

    // get namehash, import it into file
    self.events.request("version:get:eth-ens-namehash", function(EnsNamehashVersion) {
      let currentEnsNamehashVersion = require('../../../package.json').dependencies["eth-ens-namehash"];
      if (EnsNamehashVersion !== currentEnsNamehashVersion) {
        self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function(err, location) {
          self.embark.registerImportFile("eth-ens-namehash", fs.dappPath(location));
        });
      }
    });

    let code = "";
    code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString();
    code += "\nEmbarkJS.Names.registerProvider('ens', __embarkENS);";

    this.embark.addCodeToEmbarkJS(code);
  }

  configureENSRegistry() {
    const self = this;
    self.embark.addContractFile('./contracts/ENSRegistry.sol');
    self.embark.registerContractConfiguration({
      "default": {
        "gas": "auto",
        "ENSRegistry": {
          "deploy": true,
        }
      },
      "ropsten": {
        "ENSRegistry": {
          "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010"
        }
      },
      "rinkeby": {
        "ENSRegistry": {
          "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
        }
      },
      "mainnet": {
        "ENSRegistry": {
          "address": "0x314159265dd8dbb310642f98f50c066173c1259b"
        }
      }
    });
    self.events.on("deploy:contract:deployed", (contract) => {
      if (contract.className === "ENSRegistry") {
        return web3.eth.Contract(contract.abiDefinition, contract.address);
      }
    })
  }

  addSetProvider() {
    const self = this;

    let config = JSON.stringify(self.configureENSRegistry());

    let code = "\nEmbarkJS.Names.setProvider('ens'," + config + ");";

    let shouldInit = (namesConfig) => {
      return (namesConfig.provider === 'ens' && namesConfig.enabled === true);
    };

    this.embark.addProviderInit('names', code, shouldInit);
  }
}

module.exports = ENS;
<commit_msg>lint is lyfe<commit_after>/*global web3*/
const fs = require('../../core/fs.js');
const utils = require('../../utils/utils.js');

class ENS {
  constructor(embark, _options) {
    this.logger = embark.logger;
    this.events = embark.events;
    this.namesConfig = embark.config.namesystemConfig;
    this.embark = embark;
    this.ensRegistry = null;
    this.ensResolver = null;

    this.addENSToEmbarkJS();
    this.addSetProvider();
  }

  addENSToEmbarkJS() {
    const self = this;
    // TODO: make this a shouldAdd condition
    if (this.namesConfig === {}) {
      return;
    }

    if ((this.namesConfig.available_providers.indexOf('ens') < 0) && (this.namesConfig.provider !== 'ens' || this.namesConfig.enabled !== true)) {
      return;
    }

    // get namehash, import it into file
    self.events.request("version:get:eth-ens-namehash", function(EnsNamehashVersion) {
      let currentEnsNamehashVersion = require('../../../package.json').dependencies["eth-ens-namehash"];
      if (EnsNamehashVersion !== currentEnsNamehashVersion) {
        self.events.request("version:getPackageLocation", "eth-ens-namehash", EnsNamehashVersion, function(err, location) {
          self.embark.registerImportFile("eth-ens-namehash", fs.dappPath(location));
        });
      }
    });

    let code = "";
    code += "\n" + fs.readFileSync(utils.joinPath(__dirname, 'embarkjs.js')).toString();
    code += "\nEmbarkJS.Names.registerProvider('ens', __embarkENS);";

    this.embark.addCodeToEmbarkJS(code);
  }

  configureENSRegistry() {
    const self = this;
    self.embark.addContractFile('./contracts/ENSRegistry.sol');
    self.embark.registerContractConfiguration({
      "default": {
        "gas": "auto",
        "ENSRegistry": {
          "deploy": true
        }
      },
      "ropsten": {
        "ENSRegistry": {
          "address": "0x112234455c3a32fd11230c42e7bccd4a84e02010"
        }
      },
      "rinkeby": {
        "ENSRegistry": {
          "address": "0xe7410170f87102DF0055eB195163A03B7F2Bff4A"
        }
      },
      "mainnet": {
        "ENSRegistry": {
          "address": "0x314159265dd8dbb310642f98f50c066173c1259b"
        }
      }
    });
    self.events.on("deploy:contract:deployed", (contract) => {
      if (contract.className === "ENSRegistry") {
        return web3.eth.Contract(contract.abiDefinition, contract.address);
      }
    });
  }

  addSetProvider() {
    const self = this;

    let config = JSON.stringify(self.configureENSRegistry());

    let code = "\nEmbarkJS.Names.setProvider('ens'," + config + ");";

    let shouldInit = (namesConfig) => {
      return (namesConfig.provider === 'ens' && namesConfig.enabled === true);
    };

    this.embark.addProviderInit('names', code, shouldInit);
  }
}

module.exports = ENS;
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/** @type {string}
 * @const
 */
var FEEDBACK_LANDING_PAGE =
    'https://www.google.com/support/chrome/go/feedback_confirmation';
/** @type {number}
 * @const
 */
var MAX_ATTACH_FILE_SIZE = 3 * 1024 * 1024;

var attachedFileBlob = null;
var lastReader = null;

var feedbackInfo = null;
var systemInfo = null;

var systemInfoWindowId = 0;

/**
 * Reads the selected file when the user selects a file.
 * @param {Event} fileSelectedEvent The onChanged event for the file input box.
 */
function onFileSelected(fileSelectedEvent) {
  $('attach-error').hidden = true;
  var file = fileSelectedEvent.target.files[0];
  if (!file) {
    // User canceled file selection.
    attachedFileBlob = null;
    return;
  }

  if (file.size > MAX_ATTACH_FILE_SIZE) {
    $('attach-error').hidden = false;

    // Clear our selected file.
    $('attach-file').value = '';
    attachedFileBlob = null;
    return;
  }

  attachedFileBlob = file.slice();
}

/**
 * Clears the file that was attached to the report with the initial request.
 * Instead we will now show the attach file button in case the user wants to
 * attach another file.
 */
function clearAttachedFile() {
  $('custom-file-container').hidden = true;
  attachedFileBlob = null;
  feedbackInfo.attachedFile = null;
  $('attach-file').hidden = false;
}

/**
 * Opens a new window with chrome://system, showing the current system info.
 */
function openSystemInfoWindow() {
  if (systemInfoWindowId == 0) {
    chrome.windows.create({url: 'chrome://system'}, function(win) {
      systemInfoWindowId = win.id;
      chrome.app.window.current().show();
    });
  } else {
    chrome.windows.update(systemInfoWindowId, {drawAttention: true});
  }
}

/**
 * Opens a new window with chrome://slow_trace, downloading performance data.
 */
function openSlowTraceWindow() {
  chrome.windows.create(
      {url: 'chrome://slow_trace/tracing.zip#' + feedbackInfo.traceId},
      function(win) {});
}

/**
 * Sends the report; after the report is sent, we need to be redirected to
 * the landing page, but we shouldn't be able to navigate back, hence
 * we open the landing page in a new tab and sendReport closes this tab.
 * @return {boolean} True if the report was sent.
 */
function sendReport() {
  if ($('description-text').value.length == 0) {
    var description = $('description-text');
    description.placeholder = loadTimeData.getString('no-description');
    description.focus();
    return false;
  }

  // Prevent double clicking from sending additional reports.
  $('send-report-button').disabled = true;
  console.log('Feedback: Sending report');
  if (!feedbackInfo.attachedFile && attachedFileBlob) {
    feedbackInfo.attachedFile = { name: $('attach-file').value,
                                  data: attachedFileBlob };
  }

  feedbackInfo.description = $('description-text').value;
  feedbackInfo.pageUrl = $('page-url-text').value;
  feedbackInfo.email = $('user-email-text').value;

  var useSystemInfo = false;
  // On ChromeOS, since we gather System info, check if the user has given his
  // permission for us to send system info.
<if expr="pp_ifdef('chromeos')">
  if ($('sys-info-checkbox') != null &&
      $('sys-info-checkbox').checked &&
      systemInfo != null) {
    useSystemInfo = true;
  }
  if ($('performance-info-checkbox') == null ||
      !($('performance-info-checkbox').checked)) {
    feedbackInfo.traceId = null;
  }
</if>

// On NonChromeOS, we don't have any system information gathered except the
// Chrome version and the OS version. Hence for Chrome, pass the system info
// through.
<if expr="not pp_ifdef('chromeos')">
  if (systemInfo != null)
    useSystemInfo = true;
</if>

  if (useSystemInfo) {
    if (feedbackInfo.systemInformation != null) {
      // Concatenate sysinfo if we had any initial system information
      // sent with the feedback request event.
      feedbackInfo.systemInformation =
          feedbackInfo.systemInformation.concat(systemInfo);
    } else {
      feedbackInfo.systemInformation = systemInfo;
    }
  }

  // If the user doesn't want to send the screenshot.
  if (!$('screenshot-checkbox').checked)
    feedbackInfo.screenshot = null;

  chrome.feedbackPrivate.sendFeedback(feedbackInfo, function(result) {
    window.open(FEEDBACK_LANDING_PAGE, '_blank');
    window.close();
  });

  return true;
}

/**
 * Click listener for the cancel button.
 * @param {Event} e The click event being handled.
 */
function cancel(e) {
  e.preventDefault();
  window.close();
}

/**
 * Converts a blob data URL to a blob object.
 * @param {string} url The data URL to convert.
 * @return {Blob} Blob object containing the data.
 */
function dataUrlToBlob(url) {
  var mimeString = url.split(',')[0].split(':')[1].split(';')[0];
  var data = atob(url.split(',')[1]);
  var dataArray = [];
  for (var i = 0; i < data.length; ++i)
    dataArray.push(data.charCodeAt(i));

  return new Blob([new Uint8Array(dataArray)], {type: mimeString});
}

<if expr="pp_ifdef('chromeos')">
/**
 * Update the page when performance feedback state is changed.
 */
function performanceFeedbackChanged() {
  if ($('performance-info-checkbox').checked) {
    $('attach-file').disabled = true;
    $('attach-file').checked = false;

    $('screenshot-checkbox').disabled = true;
    $('screenshot-checkbox').checked = false;

    $('sys-info-checkbox').disabled = true;
    $('sys-info-checkbox').checked = false;
  } else {
    $('attach-file').disabled = false;
    $('screenshot-checkbox').disabled = false;
    $('sys-info-checkbox').disabled = false;
  }
}
</if>

/**
 * Initializes our page.
 * Flow:
 * .) DOMContent Loaded        -> . Request feedbackInfo object
 *                                . Setup page event handlers
 * .) Feedback Object Received -> . take screenshot
 *                                . request email
 *                                . request System info
 *                                . request i18n strings
 * .) Screenshot taken         -> . Show Feedback window.
 */
function initialize() {
  // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
  console.log('FEEDBACK_DEBUG: feedback.js: initialize()');

  // Add listener to receive the feedback info object.
  chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.sentFromEventPage) {
      // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
      console.log('FEEDBACK_DEBUG: Received feedbackInfo.');
      feedbackInfo = request.data;
      $('description-text').textContent = feedbackInfo.description;
      if (feedbackInfo.pageUrl)
        $('page-url-text').value = feedbackInfo.pageUrl;

      takeScreenshot(function(screenshotDataUrl) {
        $('screenshot-image').src = screenshotDataUrl;
        feedbackInfo.screenshot = dataUrlToBlob(screenshotDataUrl);
        // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
        console.log('FEEDBACK_DEBUG: Taken screenshot. Showing window.');
        chrome.app.window.current().show();
      });

      chrome.feedbackPrivate.getUserEmail(function(email) {
        $('user-email-text').value = email;
      });

      chrome.feedbackPrivate.getSystemInformation(function(sysInfo) {
        systemInfo = sysInfo;
      });

      // An extension called us with an attached file.
      if (feedbackInfo.attachedFile) {
        $('attached-filename-text').textContent =
            feedbackInfo.attachedFile.name;
        attachedFileBlob = feedbackInfo.attachedFile.data;
        $('custom-file-container').hidden = false;
        $('attach-file').hidden = true;
      }

<if expr="pp_ifdef('chromeos')">
      if (feedbackInfo.traceId && ($('performance-info-area'))) {
        $('performance-info-area').hidden = false;
        $('performance-info-checkbox').checked = true;
        performanceFeedbackChanged();
        $('performance-info-link').onclick = openSlowTraceWindow;
      }
</if>

      chrome.feedbackPrivate.getStrings(function(strings) {
        loadTimeData.data = strings;
        i18nTemplate.process(document, loadTimeData);
      });
    }
  });

  window.addEventListener('DOMContentLoaded', function() {
    // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
    console.log('FEEDBACK_DEBUG: feedback.js: DOMContentLoaded');
    // Ready to receive the feedback object.
    chrome.runtime.sendMessage({ready: true});

    // Setup our event handlers.
    $('attach-file').addEventListener('change', onFileSelected);
    $('send-report-button').onclick = sendReport;
    $('cancel-button').onclick = cancel;
    $('remove-attached-file').onclick = clearAttachedFile;
<if expr="pp_ifdef('chromeos')">
    $('performance-info-checkbox').addEventListener(
        'change', performanceFeedbackChanged);
</if>

    chrome.windows.onRemoved.addListener(function(windowId, removeInfo) {
      if (windowId == systemInfoWindowId)
        systemInfoWindowId = 0;
    });
    if ($('sysinfo-url')) {
      $('sysinfo-url').onclick = openSystemInfoWindow;
    }
  });
}

initialize();
<commit_msg>Allow system info to be attached when submitting a feedback report with performance data<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/** @type {string}
 * @const
 */
var FEEDBACK_LANDING_PAGE =
    'https://www.google.com/support/chrome/go/feedback_confirmation';
/** @type {number}
 * @const
 */
var MAX_ATTACH_FILE_SIZE = 3 * 1024 * 1024;

var attachedFileBlob = null;
var lastReader = null;

var feedbackInfo = null;
var systemInfo = null;

var systemInfoWindowId = 0;

/**
 * Reads the selected file when the user selects a file.
 * @param {Event} fileSelectedEvent The onChanged event for the file input box.
 */
function onFileSelected(fileSelectedEvent) {
  $('attach-error').hidden = true;
  var file = fileSelectedEvent.target.files[0];
  if (!file) {
    // User canceled file selection.
    attachedFileBlob = null;
    return;
  }

  if (file.size > MAX_ATTACH_FILE_SIZE) {
    $('attach-error').hidden = false;

    // Clear our selected file.
    $('attach-file').value = '';
    attachedFileBlob = null;
    return;
  }

  attachedFileBlob = file.slice();
}

/**
 * Clears the file that was attached to the report with the initial request.
 * Instead we will now show the attach file button in case the user wants to
 * attach another file.
 */
function clearAttachedFile() {
  $('custom-file-container').hidden = true;
  attachedFileBlob = null;
  feedbackInfo.attachedFile = null;
  $('attach-file').hidden = false;
}

/**
 * Opens a new window with chrome://system, showing the current system info.
 */
function openSystemInfoWindow() {
  if (systemInfoWindowId == 0) {
    chrome.windows.create({url: 'chrome://system'}, function(win) {
      systemInfoWindowId = win.id;
      chrome.app.window.current().show();
    });
  } else {
    chrome.windows.update(systemInfoWindowId, {drawAttention: true});
  }
}

/**
 * Opens a new window with chrome://slow_trace, downloading performance data.
 */
function openSlowTraceWindow() {
  chrome.windows.create(
      {url: 'chrome://slow_trace/tracing.zip#' + feedbackInfo.traceId},
      function(win) {});
}

/**
 * Sends the report; after the report is sent, we need to be redirected to
 * the landing page, but we shouldn't be able to navigate back, hence
 * we open the landing page in a new tab and sendReport closes this tab.
 * @return {boolean} True if the report was sent.
 */
function sendReport() {
  if ($('description-text').value.length == 0) {
    var description = $('description-text');
    description.placeholder = loadTimeData.getString('no-description');
    description.focus();
    return false;
  }

  // Prevent double clicking from sending additional reports.
  $('send-report-button').disabled = true;
  console.log('Feedback: Sending report');
  if (!feedbackInfo.attachedFile && attachedFileBlob) {
    feedbackInfo.attachedFile = { name: $('attach-file').value,
                                  data: attachedFileBlob };
  }

  feedbackInfo.description = $('description-text').value;
  feedbackInfo.pageUrl = $('page-url-text').value;
  feedbackInfo.email = $('user-email-text').value;

  var useSystemInfo = false;
  // On ChromeOS, since we gather System info, check if the user has given his
  // permission for us to send system info.
<if expr="pp_ifdef('chromeos')">
  if ($('sys-info-checkbox') != null &&
      $('sys-info-checkbox').checked &&
      systemInfo != null) {
    useSystemInfo = true;
  }
  if ($('performance-info-checkbox') == null ||
      !($('performance-info-checkbox').checked)) {
    feedbackInfo.traceId = null;
  }
</if>

// On NonChromeOS, we don't have any system information gathered except the
// Chrome version and the OS version. Hence for Chrome, pass the system info
// through.
<if expr="not pp_ifdef('chromeos')">
  if (systemInfo != null)
    useSystemInfo = true;
</if>

  if (useSystemInfo) {
    if (feedbackInfo.systemInformation != null) {
      // Concatenate sysinfo if we had any initial system information
      // sent with the feedback request event.
      feedbackInfo.systemInformation =
          feedbackInfo.systemInformation.concat(systemInfo);
    } else {
      feedbackInfo.systemInformation = systemInfo;
    }
  }

  // If the user doesn't want to send the screenshot.
  if (!$('screenshot-checkbox').checked)
    feedbackInfo.screenshot = null;

  chrome.feedbackPrivate.sendFeedback(feedbackInfo, function(result) {
    window.open(FEEDBACK_LANDING_PAGE, '_blank');
    window.close();
  });

  return true;
}

/**
 * Click listener for the cancel button.
 * @param {Event} e The click event being handled.
 */
function cancel(e) {
  e.preventDefault();
  window.close();
}

/**
 * Converts a blob data URL to a blob object.
 * @param {string} url The data URL to convert.
 * @return {Blob} Blob object containing the data.
 */
function dataUrlToBlob(url) {
  var mimeString = url.split(',')[0].split(':')[1].split(';')[0];
  var data = atob(url.split(',')[1]);
  var dataArray = [];
  for (var i = 0; i < data.length; ++i)
    dataArray.push(data.charCodeAt(i));

  return new Blob([new Uint8Array(dataArray)], {type: mimeString});
}

<if expr="pp_ifdef('chromeos')">
/**
 * Update the page when performance feedback state is changed.
 */
function performanceFeedbackChanged() {
  if ($('performance-info-checkbox').checked) {
    $('attach-file').disabled = true;
    $('attach-file').checked = false;

    $('screenshot-checkbox').disabled = true;
    $('screenshot-checkbox').checked = false;
  } else {
    $('attach-file').disabled = false;
    $('screenshot-checkbox').disabled = false;
  }
}
</if>

/**
 * Initializes our page.
 * Flow:
 * .) DOMContent Loaded        -> . Request feedbackInfo object
 *                                . Setup page event handlers
 * .) Feedback Object Received -> . take screenshot
 *                                . request email
 *                                . request System info
 *                                . request i18n strings
 * .) Screenshot taken         -> . Show Feedback window.
 */
function initialize() {
  // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
  console.log('FEEDBACK_DEBUG: feedback.js: initialize()');

  // Add listener to receive the feedback info object.
  chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request.sentFromEventPage) {
      // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
      console.log('FEEDBACK_DEBUG: Received feedbackInfo.');
      feedbackInfo = request.data;
      $('description-text').textContent = feedbackInfo.description;
      if (feedbackInfo.pageUrl)
        $('page-url-text').value = feedbackInfo.pageUrl;

      takeScreenshot(function(screenshotDataUrl) {
        $('screenshot-image').src = screenshotDataUrl;
        feedbackInfo.screenshot = dataUrlToBlob(screenshotDataUrl);
        // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
        console.log('FEEDBACK_DEBUG: Taken screenshot. Showing window.');
        chrome.app.window.current().show();
      });

      chrome.feedbackPrivate.getUserEmail(function(email) {
        $('user-email-text').value = email;
      });

      chrome.feedbackPrivate.getSystemInformation(function(sysInfo) {
        systemInfo = sysInfo;
      });

      // An extension called us with an attached file.
      if (feedbackInfo.attachedFile) {
        $('attached-filename-text').textContent =
            feedbackInfo.attachedFile.name;
        attachedFileBlob = feedbackInfo.attachedFile.data;
        $('custom-file-container').hidden = false;
        $('attach-file').hidden = true;
      }

<if expr="pp_ifdef('chromeos')">
      if (feedbackInfo.traceId && ($('performance-info-area'))) {
        $('performance-info-area').hidden = false;
        $('performance-info-checkbox').checked = true;
        performanceFeedbackChanged();
        $('performance-info-link').onclick = openSlowTraceWindow;
      }
</if>

      chrome.feedbackPrivate.getStrings(function(strings) {
        loadTimeData.data = strings;
        i18nTemplate.process(document, loadTimeData);
      });
    }
  });

  window.addEventListener('DOMContentLoaded', function() {
    // TODO(rkc):  Remove logging once crbug.com/284662 is closed.
    console.log('FEEDBACK_DEBUG: feedback.js: DOMContentLoaded');
    // Ready to receive the feedback object.
    chrome.runtime.sendMessage({ready: true});

    // Setup our event handlers.
    $('attach-file').addEventListener('change', onFileSelected);
    $('send-report-button').onclick = sendReport;
    $('cancel-button').onclick = cancel;
    $('remove-attached-file').onclick = clearAttachedFile;
<if expr="pp_ifdef('chromeos')">
    $('performance-info-checkbox').addEventListener(
        'change', performanceFeedbackChanged);
</if>

    chrome.windows.onRemoved.addListener(function(windowId, removeInfo) {
      if (windowId == systemInfoWindowId)
        systemInfoWindowId = 0;
    });
    if ($('sysinfo-url')) {
      $('sysinfo-url').onclick = openSystemInfoWindow;
    }
  });
}

initialize();
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2012 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * Used as a shortcut. Moved to the top of the page due to race conditions.
 * @param {string} id is a case-sensitive string representing the unique ID of
 *     the element being sought.
 * @return {object} id returns the element object specified as a parameter
 */
$ = function(id) {
  return document.getElementById(id);
};

/**
 * Sets the global variable gUseRtpDataChannel in message_handling.js
 * based on the check box element 'data-channel-type-rtp' checked status on
 * peerconnection.html. Also prints a help text to inform the user.
 */
function setPcDataChannelType() {
  var useRtpDataChannels = $('data-channel-type-rtp').checked;
  useRtpDataChannelsForNewPeerConnections(useRtpDataChannels);
  if (useRtpDataChannels) {
    debug('Make sure to tick the RTP check box on both the calling and ' +
          'answering side to ensure a data channel can be setup properly as ' +
          'it has to use the same transport protocol (RTP to RTP and SCTP to ' +
          'SCTP).');
  }
}

// The *Here functions are called from peerconnection.html and will make calls
// into our underlying JavaScript library with the values from the page
// (have to be named differently to avoid name clashes with existing functions).

function getUserMediaFromHere() {
  var constraints = $('getusermedia-constraints').value;
  try {
    doGetUserMedia(constraints);
  } catch (exception) {
    print_('getUserMedia says: ' + exception);
  }
}

function connectFromHere() {
  var server = $('server').value;
  if ($('peer-id').value == '') {
    // Generate a random name to distinguish us from other tabs:
    $('peer-id').value = 'peer_' + Math.floor(Math.random() * 10000);
    debug('Our name from now on will be ' + $('peer-id').value);
  }
  connect(server, $('peer-id').value);
}

function negotiateCallFromHere() {
  // Set the global variables used in jsep01_call.js with values from our UI.
  setCreateOfferConstraints(getEvaluatedJavaScript_(
      $('pc-createoffer-constraints').value));
  setCreateAnswerConstraints(getEvaluatedJavaScript_(
      $('pc-createanswer-constraints').value));

  ensureHasPeerConnection_();
  negotiateCall();
}

function addLocalStreamFromHere() {
  ensureHasPeerConnection_();
  addLocalStream();
}

function removeLocalStreamFromHere() {
  removeLocalStream();
}

function hangUpFromHere() {
  hangUp();
  acceptIncomingCallsAgain();
}

function toggleRemoteVideoFromHere() {
  toggleRemoteStream(function(remoteStream) {
    return remoteStream.getVideoTracks()[0];
  }, 'video');
}

function toggleRemoteAudioFromHere() {
  toggleRemoteStream(function(remoteStream) {
    return remoteStream.getAudioTracks()[0];
  }, 'audio');
}

function toggleLocalVideoFromHere() {
  toggleLocalStream(function(localStream) {
    return localStream.getVideoTracks()[0];
  }, 'video');
}

function toggleLocalAudioFromHere() {
  toggleLocalStream(function(localStream) {
    return localStream.getAudioTracks()[0];
  }, 'audio');
}

function stopLocalFromHere() {
  stopLocalStream();
}

function createDataChannelFromHere() {
  ensureHasPeerConnection_();
  createDataChannelOnPeerConnection();
}

function closeDataChannelFromHere() {
  ensureHasPeerConnection_();
  closeDataChannelOnPeerConnection();
}

function sendDataFromHere() {
  var data = $('data-channel-send').value;
  sendDataOnChannel(data);
}

function createDtmfSenderFromHere() {
  ensureHasPeerConnection_();
  createDtmfSenderOnPeerConnection();
}

function insertDtmfFromHere() {
  var tones = $('dtmf-tones').value;
  var duration = $('dtmf-tones-duration').value;
  var gap = $('dtmf-tones-gap').value;
  insertDtmfOnSender(tones, duration, gap);
}

function forceIsacChanged() {
  var forceIsac = $('force-isac').checked;
  if (forceIsac) {
    forceIsac_();
  } else {
    dontTouchSdp_();
  }
}

/**
 * Updates the constraints in the getusermedia-constraints text box with a
 * MediaStreamConstraints string. This string is created based on the status of
 * the checkboxes for audio and video. If device enumeration is supported and
 * device source id's are not null they will be added to the constraints string.
 * Fetches the screen size using "screen" in Chrome as we need to pass a max
 * resolution else it defaults to 640x480 in the constraints for screen
 * capturing.
 */
function updateGetUserMediaConstraints() {
  var audio_selected = $('audiosrc');
  var video_selected = $('videosrc');
  var constraints = {
    audio: $('audio').checked,
    video: $('video').checked
  };
  if (audio_selected.disabled == false && video_selected.disabled == false) {
    var devices = getSourcesFromField(audio_selected, video_selected);
    if ($('audio').checked == true) {
      if (devices.audio_id != null) {
        constraints.audio = {optional: [{sourceId: devices.audio_id}]};
      }
      else {
        constraints.audio = true;
      }
    }
    if ($('video').checked == true) {
      // Default optional constraints placed here.
      constraints.video = {optional: [{minWidth: $('video-width').value},
                                      {minHeight: $('video-height').value},
                                      {googCpuOveruseDetection: true},
                                      {googLeakyBucket: true}]
      };
      if (devices.video_id != null) {
        constraints.video.optional.push({sourceId: devices.video_id});
      }
    }
  }
  if ($('screencapture').checked) {
    var constraints = {
      audio: $('audio').checked,
      video: {mandatory: {chromeMediaSource: 'screen',
                          maxWidth: screen.width,
                          maxHeight: screen.height}}
    };
    if ($('audio').checked == true)
      debug('Audio for screencapture is not implemented yet, please ' +
            'try to set audio = false prior requesting screencapture');
  }
  $('getusermedia-constraints').value =
      JSON.stringify(constraints, null, ' ');
}

function showServerHelp() {
  alert('You need to build and run a peerconnection_server on some ' +
        'suitable machine. To build it in chrome, just run make/ninja ' +
        'peerconnection_server. Otherwise, read in https://code.google' +
        '.com/searchframe#xSWYf0NTG_Q/trunk/peerconnection/README&q=REA' +
        'DME%20package:webrtc%5C.googlecode%5C.com.');
}

function toggleHelp() {
  var help = $('help');
  if (help.style.display == 'none')
    help.style.display = 'inline';
  else
    help.style.display = 'none';
}

function clearLog() {
  $('messages').innerHTML = '';
  $('debug').innerHTML = '';
}

/**
 * Prepopulate constraints from JS to the UI and setup callbacks in the scripts
 * shared with browser tests or automated tests. Enumerates devices available
 * via getUserMedia.
 */
window.onload = function() {
  $('pc-createoffer-constraints').value = JSON.stringify(
      gCreateOfferConstraints, null, ' ');
  $('pc-createanswer-constraints').value = JSON.stringify(
    gCreateAnswerConstraints, null, ' ');
  replaceReturnCallback(print_);
  replaceDebugCallback(debug_);
  doNotAutoAddLocalStreamWhenCalled();
  hookupDataChannelCallbacks_();
  hookupDtmfSenderCallback_();
  displayVideoSize_($('local-view'));
  displayVideoSize_($('remote-view'));
  getDevices();
  setPcDataChannelType();
  setupLocalStorageFieldValues();
};

/**
 * Checks if the 'audiosrc' and 'videosrc' drop down menu elements has had all
 * of its children appended in order to provide device ID's to the function
 * 'updateGetUserMediaConstraints()', used in turn to populate the getUserMedia
 * constraints text box when the page has loaded. If not the user is informed
 * and instructions on how to populate the field is provided.
 */
function checkIfDeviceDropdownsArePopulated() {
  if (document.addEventListener) {
    $('audiosrc').addEventListener('DOMNodeInserted',
         updateGetUserMediaConstraints, false);
    $('videosrc').addEventListener('DOMNodeInserted',
         updateGetUserMediaConstraints, false);
  }
  else {
    debug('addEventListener is not supported by your browser, cannot update ' +
          'device source ID\'s automatically. Select a device from the audio ' +
          'or video source drop down menu to update device source id\'s');
  }
}

/**
 * Disconnect before the tab is closed.
 */
window.onbeforeunload = function() {
  if (!isDisconnected())
    disconnect();
};

// Internals.

/**
 * Create the peer connection if none is up (this is just convenience to
 * avoid having a separate button for that).
 * @private
 */
function ensureHasPeerConnection_() {
  if (getReadyState() == 'no-peer-connection') {
    preparePeerConnection();
  }
}

/**
 * @private
 * @param {string} message Text to print.
 */
function print_(message) {
  // Filter out uninteresting noise.
  if (message == 'ok-no-errors')
    return;

  console.log(message);
  $('messages').innerHTML += message + '
';
}

/**
 * @private
 * @param {string} message Text to print.
 */
function debug_(message) {
  console.log(message);
  $('debug').innerHTML += message + '
';
}

/**
 * @private
 * @param {string} stringRepresentation JavaScript as a string.
 * @return {Object} The PeerConnection constraints as a JavaScript dictionary.
 */
function getEvaluatedJavaScript_(stringRepresentation) {
  try {
    var evaluatedJavaScript;
    eval('evaluatedJavaScript = ' + stringRepresentation);
  } catch (exception) {
    throw failTest('Not valid JavaScript expression: ' + stringRepresentation);
  }
  return evaluatedJavaScript;
}

/**
 * Swaps lines within a SDP message.
 * @private
 * @param {string} sdp The full SDP message.
 * @param {string} line The line to swap with swapWith.
 * @param {string} swapWith The other line.
 * @return {string} The altered SDP message.
 */
function swapSdpLines_(sdp, line, swapWith) {
  var lines = sdp.split('\r\n');
  var lineStart = lines.indexOf(line);
  var swapLineStart = lines.indexOf(swapWith);
  if (lineStart == -1 || swapLineStart == -1)
    return sdp;  // This generally happens on the first message.

  var tmp = lines[lineStart];
  lines[lineStart] = lines[swapLineStart];
  lines[swapLineStart] = tmp;

  return lines.join('\r\n');
}

// TODO(phoglund): Not currently used; delete once it clear we do not need to
// test opus prioritization.
/** @private */
function preferOpus_() {
  setOutgoingSdpTransform(function(sdp) {
    sdp = sdp.replace('103 104 111', '111 103 104');

    // TODO(phoglund): We need to swap the a= lines too. I don't think this
    // should be needed but it apparently is right now.
    return swapSdpLines_(sdp,
                         'a=rtpmap:103 ISAC/16000',
                         'a=rtpmap:111 opus/48000');
  });
}

/** @private */
function forceIsac_() {
  setOutgoingSdpTransform(function(sdp) {
    // Remove all other codecs (not the video codecs though).
    sdp = sdp.replace(/m=audio (\d+) RTP\/SAVPF.*\r\n/g,
                      'm=audio $1 RTP/SAVPF 104\r\n');
    sdp = sdp.replace('a=fmtp:111 minptime=10', 'a=fmtp:104 minptime=10');
    sdp = sdp.replace(/a=rtpmap:(?!104)\d{1,3} (?!VP8|red|ulpfec).*\r\n/g, '');
    return sdp;
  });
}

/** @private */
function dontTouchSdp_() {
  setOutgoingSdpTransform(function(sdp) { return sdp; });
}

/** @private */
function hookupDataChannelCallbacks_() {
  setDataCallbacks(function(status) {
    $('data-channel-status').value = status;
  },
  function(data_message) {
    debug('Received ' + data_message.data);
    $('data-channel-receive').value =
      data_message.data + '\n' + $('data-channel-receive').value;
  });
}

/** @private */
function hookupDtmfSenderCallback_() {
  setOnToneChange(function(tone) {
    debug('Sent DTMF tone: ' + tone.tone);
    $('dtmf-tones-sent').value =
      tone.tone + '\n' + $('dtmf-tones-sent').value;
  });
}

/**
 * A list of element id's to be registered for local storage.
 */
function setupLocalStorageFieldValues() {
  registerLocalStorage_('pc-server');
  registerLocalStorage_('pc-createanswer-constraints');
  registerLocalStorage_('pc-createoffer-constraints');
}

/**
 * Stores the value of the element_id parameter using local storage.
 * @private
 * @param {!string} element_id to be used as a key for local storage
 */
function registerLocalStorage_(element_id) {
  var element = $(element_id);
  element.onblur = function() { storeLocalStorageFieldValue_(this); };

  if (localStorage.getItem(element.id) === 'undefined') {
    storeLocalStorageFieldValue_(element);
  } else {
    element.value = localStorage.getItem(element.id);
  }
}

/**
 * Stores the string value of the element object using local storage.
 * @private
 * @param {!Object} element of which id is representing the key parameter for
 *     local storage.
 */
function storeLocalStorageFieldValue_(element) {
  localStorage.setItem(element.id, element.value);
}
<commit_msg>Fixed element id in the ConnectFromHere function.<commit_after>/**
 * Copyright (c) 2012 The Chromium Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * Used as a shortcut. Moved to the top of the page due to race conditions.
 * @param {string} id is a case-sensitive string representing the unique ID of
 *     the element being sought.
 * @return {object} id returns the element object specified as a parameter
 */
$ = function(id) {
  return document.getElementById(id);
};

/**
 * Sets the global variable gUseRtpDataChannel in message_handling.js
 * based on the check box element 'data-channel-type-rtp' checked status on
 * peerconnection.html. Also prints a help text to inform the user.
 */
function setPcDataChannelType() {
  var useRtpDataChannels = $('data-channel-type-rtp').checked;
  useRtpDataChannelsForNewPeerConnections(useRtpDataChannels);
  if (useRtpDataChannels) {
    debug('Make sure to tick the RTP check box on both the calling and ' +
          'answering side to ensure a data channel can be setup properly as ' +
          'it has to use the same transport protocol (RTP to RTP and SCTP to ' +
          'SCTP).');
  }
}

// The *Here functions are called from peerconnection.html and will make calls
// into our underlying JavaScript library with the values from the page
// (have to be named differently to avoid name clashes with existing functions).

function getUserMediaFromHere() {
  var constraints = $('getusermedia-constraints').value;
  try {
    doGetUserMedia(constraints);
  } catch (exception) {
    print_('getUserMedia says: ' + exception);
  }
}

function connectFromHere() {
  var server = $('pc-server').value;
  if ($('peer-id').value == '') {
    // Generate a random name to distinguish us from other tabs:
    $('peer-id').value = 'peer_' + Math.floor(Math.random() * 10000);
    debug('Our name from now on will be ' + $('peer-id').value);
  }
  connect(server, $('peer-id').value);
}

function negotiateCallFromHere() {
  // Set the global variables used in jsep01_call.js with values from our UI.
  setCreateOfferConstraints(getEvaluatedJavaScript_(
      $('pc-createoffer-constraints').value));
  setCreateAnswerConstraints(getEvaluatedJavaScript_(
      $('pc-createanswer-constraints').value));

  ensureHasPeerConnection_();
  negotiateCall();
}

function addLocalStreamFromHere() {
  ensureHasPeerConnection_();
  addLocalStream();
}

function removeLocalStreamFromHere() {
  removeLocalStream();
}

function hangUpFromHere() {
  hangUp();
  acceptIncomingCallsAgain();
}

function toggleRemoteVideoFromHere() {
  toggleRemoteStream(function(remoteStream) {
    return remoteStream.getVideoTracks()[0];
  }, 'video');
}

function toggleRemoteAudioFromHere() {
  toggleRemoteStream(function(remoteStream) {
    return remoteStream.getAudioTracks()[0];
  }, 'audio');
}

function toggleLocalVideoFromHere() {
  toggleLocalStream(function(localStream) {
    return localStream.getVideoTracks()[0];
  }, 'video');
}

function toggleLocalAudioFromHere() {
  toggleLocalStream(function(localStream) {
    return localStream.getAudioTracks()[0];
  }, 'audio');
}

function stopLocalFromHere() {
  stopLocalStream();
}

function createDataChannelFromHere() {
  ensureHasPeerConnection_();
  createDataChannelOnPeerConnection();
}

function closeDataChannelFromHere() {
  ensureHasPeerConnection_();
  closeDataChannelOnPeerConnection();
}

function sendDataFromHere() {
  var data = $('data-channel-send').value;
  sendDataOnChannel(data);
}

function createDtmfSenderFromHere() {
  ensureHasPeerConnection_();
  createDtmfSenderOnPeerConnection();
}

function insertDtmfFromHere() {
  var tones = $('dtmf-tones').value;
  var duration = $('dtmf-tones-duration').value;
  var gap = $('dtmf-tones-gap').value;
  insertDtmfOnSender(tones, duration, gap);
}

function forceIsacChanged() {
  var forceIsac = $('force-isac').checked;
  if (forceIsac) {
    forceIsac_();
  } else {
    dontTouchSdp_();
  }
}

/**
 * Updates the constraints in the getusermedia-constraints text box with a
 * MediaStreamConstraints string. This string is created based on the status of
 * the checkboxes for audio and video. If device enumeration is supported and
 * device source id's are not null they will be added to the constraints string.
 * Fetches the screen size using "screen" in Chrome as we need to pass a max
 * resolution else it defaults to 640x480 in the constraints for screen
 * capturing.
 */
function updateGetUserMediaConstraints() {
  var audio_selected = $('audiosrc');
  var video_selected = $('videosrc');
  var constraints = {
    audio: $('audio').checked,
    video: $('video').checked
  };
  if (audio_selected.disabled == false && video_selected.disabled == false) {
    var devices = getSourcesFromField(audio_selected, video_selected);
    if ($('audio').checked == true) {
      if (devices.audio_id != null) {
        constraints.audio = {optional: [{sourceId: devices.audio_id}]};
      }
      else {
        constraints.audio = true;
      }
    }
    if ($('video').checked == true) {
      // Default optional constraints placed here.
      constraints.video = {optional: [{minWidth: $('video-width').value},
                                      {minHeight: $('video-height').value},
                                      {googCpuOveruseDetection: true},
                                      {googLeakyBucket: true}]
      };
      if (devices.video_id != null) {
        constraints.video.optional.push({sourceId: devices.video_id});
      }
    }
  }
  if ($('screencapture').checked) {
    var constraints = {
      audio: $('audio').checked,
      video: {mandatory: {chromeMediaSource: 'screen',
                          maxWidth: screen.width,
                          maxHeight: screen.height}}
    };
    if ($('audio').checked == true)
      debug('Audio for screencapture is not implemented yet, please ' +
            'try to set audio = false prior requesting screencapture');
  }
  $('getusermedia-constraints').value =
      JSON.stringify(constraints, null, ' ');
}

function showServerHelp() {
  alert('You need to build and run a peerconnection_server on some ' +
        'suitable machine. To build it in chrome, just run make/ninja ' +
        'peerconnection_server. Otherwise, read in https://code.google' +
        '.com/searchframe#xSWYf0NTG_Q/trunk/peerconnection/README&q=REA' +
        'DME%20package:webrtc%5C.googlecode%5C.com.');
}

function toggleHelp() {
  var help = $('help');
  if (help.style.display == 'none')
    help.style.display = 'inline';
  else
    help.style.display = 'none';
}

function clearLog() {
  $('messages').innerHTML = '';
  $('debug').innerHTML = '';
}

/**
 * Prepopulate constraints from JS to the UI and setup callbacks in the scripts
 * shared with browser tests or automated tests. Enumerates devices available
 * via getUserMedia.
 */
window.onload = function() {
  $('pc-createoffer-constraints').value = JSON.stringify(
      gCreateOfferConstraints, null, ' ');
  $('pc-createanswer-constraints').value = JSON.stringify(
    gCreateAnswerConstraints, null, ' ');
  replaceReturnCallback(print_);
  replaceDebugCallback(debug_);
  doNotAutoAddLocalStreamWhenCalled();
  hookupDataChannelCallbacks_();
  hookupDtmfSenderCallback_();
  displayVideoSize_($('local-view'));
  displayVideoSize_($('remote-view'));
  getDevices();
  setPcDataChannelType();
  setupLocalStorageFieldValues();
};

/**
 * Checks if the 'audiosrc' and 'videosrc' drop down menu elements has had all
 * of its children appended in order to provide device ID's to the function
 * 'updateGetUserMediaConstraints()', used in turn to populate the getUserMedia
 * constraints text box when the page has loaded. If not the user is informed
 * and instructions on how to populate the field is provided.
 */
function checkIfDeviceDropdownsArePopulated() {
  if (document.addEventListener) {
    $('audiosrc').addEventListener('DOMNodeInserted',
         updateGetUserMediaConstraints, false);
    $('videosrc').addEventListener('DOMNodeInserted',
         updateGetUserMediaConstraints, false);
  }
  else {
    debug('addEventListener is not supported by your browser, cannot update ' +
          'device source ID\'s automatically. Select a device from the audio ' +
          'or video source drop down menu to update device source id\'s');
  }
}

/**
 * Disconnect before the tab is closed.
 */
window.onbeforeunload = function() {
  if (!isDisconnected())
    disconnect();
};

// Internals.

/**
 * Create the peer connection if none is up (this is just convenience to
 * avoid having a separate button for that).
 * @private
 */
function ensureHasPeerConnection_() {
  if (getReadyState() == 'no-peer-connection') {
    preparePeerConnection();
  }
}

/**
 * @private
 * @param {string} message Text to print.
 */
function print_(message) {
  // Filter out uninteresting noise.
  if (message == 'ok-no-errors')
    return;

  console.log(message);
  $('messages').innerHTML += message + '
';
}

/**
 * @private
 * @param {string} message Text to print.
 */
function debug_(message) {
  console.log(message);
  $('debug').innerHTML += message + '
';
}

/**
 * @private
 * @param {string} stringRepresentation JavaScript as a string.
 * @return {Object} The PeerConnection constraints as a JavaScript dictionary.
 */
function getEvaluatedJavaScript_(stringRepresentation) {
  try {
    var evaluatedJavaScript;
    eval('evaluatedJavaScript = ' + stringRepresentation);
  } catch (exception) {
    throw failTest('Not valid JavaScript expression: ' + stringRepresentation);
  }
  return evaluatedJavaScript;
}

/**
 * Swaps lines within a SDP message.
 * @private
 * @param {string} sdp The full SDP message.
 * @param {string} line The line to swap with swapWith.
 * @param {string} swapWith The other line.
 * @return {string} The altered SDP message.
 */
function swapSdpLines_(sdp, line, swapWith) {
  var lines = sdp.split('\r\n');
  var lineStart = lines.indexOf(line);
  var swapLineStart = lines.indexOf(swapWith);
  if (lineStart == -1 || swapLineStart == -1)
    return sdp;  // This generally happens on the first message.

  var tmp = lines[lineStart];
  lines[lineStart] = lines[swapLineStart];
  lines[swapLineStart] = tmp;

  return lines.join('\r\n');
}

// TODO(phoglund): Not currently used; delete once it clear we do not need to
// test opus prioritization.
/** @private */
function preferOpus_() {
  setOutgoingSdpTransform(function(sdp) {
    sdp = sdp.replace('103 104 111', '111 103 104');

    // TODO(phoglund): We need to swap the a= lines too. I don't think this
    // should be needed but it apparently is right now.
    return swapSdpLines_(sdp,
                         'a=rtpmap:103 ISAC/16000',
                         'a=rtpmap:111 opus/48000');
  });
}

/** @private */
function forceIsac_() {
  setOutgoingSdpTransform(function(sdp) {
    // Remove all other codecs (not the video codecs though).
    sdp = sdp.replace(/m=audio (\d+) RTP\/SAVPF.*\r\n/g,
                      'm=audio $1 RTP/SAVPF 104\r\n');
    sdp = sdp.replace('a=fmtp:111 minptime=10', 'a=fmtp:104 minptime=10');
    sdp = sdp.replace(/a=rtpmap:(?!104)\d{1,3} (?!VP8|red|ulpfec).*\r\n/g, '');
    return sdp;
  });
}

/** @private */
function dontTouchSdp_() {
  setOutgoingSdpTransform(function(sdp) { return sdp; });
}

/** @private */
function hookupDataChannelCallbacks_() {
  setDataCallbacks(function(status) {
    $('data-channel-status').value = status;
  },
  function(data_message) {
    debug('Received ' + data_message.data);
    $('data-channel-receive').value =
      data_message.data + '\n' + $('data-channel-receive').value;
  });
}

/** @private */
function hookupDtmfSenderCallback_() {
  setOnToneChange(function(tone) {
    debug('Sent DTMF tone: ' + tone.tone);
    $('dtmf-tones-sent').value =
      tone.tone + '\n' + $('dtmf-tones-sent').value;
  });
}

/**
 * A list of element id's to be registered for local storage.
 */
function setupLocalStorageFieldValues() {
  registerLocalStorage_('pc-server');
  registerLocalStorage_('pc-createanswer-constraints');
  registerLocalStorage_('pc-createoffer-constraints');
}

/**
 * Stores the value of the element_id parameter using local storage.
 * @private
 * @param {!string} element_id to be used as a key for local storage
 */
function registerLocalStorage_(element_id) {
  var element = $(element_id);
  element.onblur = function() { storeLocalStorageFieldValue_(this); };

  if (localStorage.getItem(element.id) === 'undefined') {
    storeLocalStorageFieldValue_(element);
  } else {
    element.value = localStorage.getItem(element.id);
  }
}

/**
 * Stores the string value of the element object using local storage.
 * @private
 * @param {!Object} element of which id is representing the key parameter for
 *     local storage.
 */
function storeLocalStorageFieldValue_(element) {
  localStorage.setItem(element.id, element.value);
}
<|endoftext|>


<commit_before>const functions = require('firebase-functions');

// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });
<commit_msg>feat(functions): add a search function<commit_after>'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);

exports.search = functions.https.onRequest(function search(req, res) {
  const searchTerm = req.query.q;
  admin.database().ref('/books').once('value').then(function data(snapshot) {
    const valAsArray = convertToArray(snapshot.val());
    const result = filterByName(searchTerm, valAsArray);
    res.json({ result: result });
  }).catch(function onError(error) {
    res.json(error);
  });
});

function convertToArray(val) {
  const array = [];
  for (const key in val) {
    array.push(Object.assign({ uid: key }, val[key]));
  }

  return array;
}

function filterByName(term = '', values = []) {
  const search = createSearchExp(term);
  return values.filter(n => search.test(n.title));
}

function createSearchExp(val = '') {
  const exp = val.replace(/ /g, '.*');
  return new RegExp(`.*${exp}.*`, 'gi')
}
<|endoftext|>