<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import DashboardPopover from '../Dashboard/DashboardPopover'
import RaisedButton from 'material-ui/RaisedButton'
import Divider from 'material-ui/Divider'
import Menu from 'material-ui/Menu'
import MenuItem from 'material-ui/MenuItem'
import IconButton from 'material-ui/IconButton'
import HeartIcon from 'material-ui/svg-icons/action/favorite'
import HeartBorderIcon from 'material-ui/svg-icons/action/favorite-border'
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
import SettingsIcon from 'material-ui/svg-icons/action/settings'
import HelpIcon from 'material-ui/svg-icons/action/help'
import PersonAddIcon from 'material-ui/svg-icons/social/person-add'
import ChartIcon from 'material-ui/svg-icons/editor/insert-chart'
import CheckmarkIcon from 'material-ui/svg-icons/action/done'
import ExitToAppIcon from 'material-ui/svg-icons/action/exit-to-app'
import {
  goToInviteFriends,
  goToDonate,
  goToLogin,
  goToSettings,
  goToStats
} from 'navigation/navigation'
import { logout } from 'authentication/user'
import appTheme, {
  dashboardIconActiveColor,
  dashboardIconInactiveColor,
  dividerColor
} from 'theme/default'
import { commaFormatted } from 'utils/utils'
import { MAX_DAILY_HEARTS_FROM_TABS } from '../../constants'

class UserMenu extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      heartsHover: false,
      heartsPopoverOpen: false,
      menuIconHover: false,
      menuOpen: false,
      // refs
      heartsPopoverAnchorElem: null,
      heartsHoverPopoverAnchorElem: null,
      menuPopoverAnchorElem: null
    }
  }

  async logout () {
    var logoutSuccess = false
    try {
      logoutSuccess = await logout()
    } catch (e) {
      console.error(e)
    }
    if (logoutSuccess) {
      goToLogin()
    }
  }

  onHeartsHover (hovering, event) {
    this.setState({
      heartsHover: hovering,
      heartsHoverPopoverAnchorElem: event.currentTarget
    })
  }

  onHeartsClick (event) {
    this.setState({
      heartsPopoverOpen: !this.state.open,
      heartsPopoverAnchorElem: event.currentTarget
    })
  }

  handleHeartsPopoverClose () {
    this.setState({
      heartsPopoverOpen: false
    })
  }

  onMenuClick (event) {
    this.setState({
      menuOpen: !this.state.open,
      menuPopoverAnchorElem: event.currentTarget
    })
  }

  handleMenuPopoverClose () {
    this.setState({
      menuOpen: false
    })
  }

  onMenuIconHover (hovering) {
    this.setState({
      menuIconHover: hovering
    })
  }

  onHover (hovering) {
    this.setState({
      hover: hovering
    })
  }

  render () {
    const { app, user } = this.props
    if (!user || !app) {
      return null
    }

    const userMenuStyle = {
      display: 'flex',
      alignItems: 'center'
    }

    // Hearts style
    const textStyle = Object.assign({}, {
      color: this.state.heartsHover
        ? dashboardIconActiveColor
        : dashboardIconInactiveColor,
      transition: 'color 300ms ease-in',
      fontSize: 18,
      fontWeight: 'normal',
      fontFamily: appTheme.fontFamily,
      userSelect: 'none',
      cursor: 'pointer'
    }, this.props.style)
    const heartsStyle = Object.assign({}, textStyle, {
      marginRight: 0,
      display: 'flex',
      alignItems: 'center'
    })

    // Hearts popover style
    const heartsPopoverStyle = {
      textAlign: 'center',
      width: 210
    }
    const heartsPopoverSectionStyle = {
    }
    const dividerStyle = {
      marginTop: 16,
      marginBottom: 12
    }
    const statTextStyle = {
      fontSize: 14,
      display: 'block',
      marginTop: 4,
      marginBottom: 4
    }
    const smallHeartIconStyle = {
      height: 16,
      marginLeft: -3
    }
    const statNumberStyle = {
      fontSize: 24,
      display: 'block'
    }
    const popoverButtonStyle = {
      marginTop: 6,
      marginBottom: 0
    }
    const popoverButtonLabelStyle = {
      fontSize: 13
    }

    // Popover section on how to earn Hearts.
    const rewardMethodContainerStyle = Object.assign({}, statTextStyle, {
      display: 'flex',
      textAlign: 'left',
      color: dividerColor,
      marginTop: 1,
      marginBottom: 1
    })
    const rewardAmountsSectionStyle = Object.assign({}, heartsPopoverSectionStyle, {
      paddingLeft: 22,
      paddingRight: 22
    })
    const rewardTextStyle = {
      textAlign: 'left',
      flex: 6
    }
    const rewardValueStyle = {
      flex: 3,
      textAlign: 'right'
    }

    // Menu style
    const menuWidth = 200
    const menuPopoverStyle = {
      padding: 0,
      width: menuWidth
    }
    const menuIconButtonStyle = {
      padding: 0,
      width: 40,
      height: 40
    }
    const menuIconStyle = {
      color: (
        this.state.menuIconHover
          ? dashboardIconActiveColor
          : dashboardIconInactiveColor
      ),
      transition: 'color 300ms ease-in',
      fontSize: 22
    }
    const menuStyle = {
      width: menuWidth,
      overflowX: 'hidden',
      backgroundColor: 'transparent',
      fontFamily: appTheme.fontFamily
    }
    const menuItemStyle = {
      fontSize: 14,
      color: appTheme.palette.alternateTextColor
    }
    const menuItemIconColor = '#FFFFFF'
    const menuItemSvgIconStyle = {
      color: menuItemIconColor,
      height: 22,
      width: 22
    }

    // Used to let the user know they aren't earning any more
    // Hearts from tabs today.
    const reachedMaxDailyHearts = user.tabsToday >= MAX_DAILY_HEARTS_FROM_TABS

    // TODO: add level bar
    return (

          {commaFormatted(user.vcCurrent)}
           { this.heartIconContainer = ref }}
          >
            <HeartBorderIcon
              style={{ marginLeft: 2, height: 24, width: 24, paddingBottom: 0 }}
              color={dashboardIconInactiveColor}
              hoverColor={dashboardIconActiveColor}
            />
            { reachedMaxDailyHearts
              ? (
                <CheckmarkIcon
                  style={{ height: 16, width: 16, position: 'absolute', paddingLeft: 4, paddingBottom: 2 }}
                  color={dashboardIconInactiveColor}
                  hoverColor={dashboardIconActiveColor}
                />
              )
              : null
            }
            { reachedMaxDailyHearts
              ? (
                <DashboardPopover
                  open={this.state.heartsHover && !this.state.heartsPopoverOpen}
                  anchorEl={this.state.heartsHoverPopoverAnchorElem}
                  style={heartsPopoverStyle}
                >

                    You've earned the maximum Hearts from opening tabs today! You'll
                    be able to earn more Hearts in a few hours.

                </DashboardPopover>
              )
              : null
            }

        <DashboardPopover
          open={this.state.heartsPopoverOpen}
          anchorEl={this.state.heartsPopoverAnchorElem}
          onRequestClose={this.handleHeartsPopoverClose.bind(this)}
          style={heartsPopoverStyle}
        >

              Level {user.level}

                {user.heartsUntilNextLevel}
                <HeartBorderIcon
                  style={smallHeartIconStyle}
                  color={dashboardIconActiveColor}
                />
                 until next level

            <Divider style={dividerStyle} />

                  {user.vcDonatedAllTime}
                  <HeartBorderIcon
                    style={{ marginLeft: 2, height: 24, width: 24, paddingBottom: 1 }}
                    color={dashboardIconActiveColor}
                  />

                Donated

                <RaisedButton
                  label='Donate Hearts'
                  style={popoverButtonStyle}
                  labelStyle={popoverButtonLabelStyle}
                  primary
                  onClick={goToDonate}
                />

            <Divider style={dividerStyle} />

                {user.numUsersRecruited} Tabbers Recruited

                <RaisedButton
                  label='Invite A Friend'
                  labelPosition='before'
                  style={popoverButtonStyle}
                  labelStyle={popoverButtonLabelStyle}
                  primary
                  onClick={goToInviteFriends}
                />

            <Divider style={dividerStyle} />

                Open a tab

                  1
                  <HeartBorderIcon
                    style={Object.assign({}, smallHeartIconStyle, { marginRight: -4 })}
                    color={dividerColor}
                  />

                Recruit a friend

                  {app.referralVcReward}
                  <HeartBorderIcon
                    style={Object.assign({}, smallHeartIconStyle, { marginRight: -4 })}
                    color={dividerColor}
                  />

        </DashboardPopover>
        <IconButton
          style={menuIconButtonStyle}
          iconStyle={menuIconStyle}
          onMouseEnter={this.onMenuIconHover.bind(this, true)}
          onMouseLeave={this.onMenuIconHover.bind(this, false)}
          onClick={this.onMenuClick.bind(this)}
          data-test-id={'app-menu-icon'}
          data-tour-id={'settings-button'}
        >
          <MoreVertIcon />
        </IconButton>
        <DashboardPopover
          style={menuPopoverStyle}
          open={this.state.menuOpen}
          anchorEl={this.state.menuPopoverAnchorElem}
          onRequestClose={this.handleMenuPopoverClose.bind(this)}
        >
          <Menu
            width={menuWidth}
            autoWidth={false}
            style={menuStyle}
            menuItemStyle={menuItemStyle}
          >
            <MenuItem primaryText='Settings' onClick={goToSettings}
              leftIcon={
                <SettingsIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <MenuItem primaryText='Donate Hearts' onClick={goToDonate}
              leftIcon={
                <HeartIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <MenuItem primaryText='Invite Friends' onClick={goToInviteFriends}
              leftIcon={
                <PersonAddIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <MenuItem primaryText='Your Stats' onClick={goToStats}
              leftIcon={
                <ChartIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <Divider style={{ marginBottom: 0, marginTop: 0 }} />

              <MenuItem primaryText='Help' onClick={goToStats}
                leftIcon={
                  <HelpIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
                }
                style={menuItemStyle}
              />

            <Divider style={{ marginBottom: 0, marginTop: 0 }} />
            <MenuItem
              primaryText='Sign Out'
              onClick={this.logout.bind(this)}
              data-test-id={'app-menu-sign-out'}
              leftIcon={
                <ExitToAppIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
          </Menu>
        </DashboardPopover>

    )
  }
}

UserMenu.propTypes = {
  app: PropTypes.shape({
    referralVcReward: PropTypes.number.isRequired
  }),
  user: PropTypes.shape({
    vcCurrent: PropTypes.number.isRequired,
    level: PropTypes.number.isRequired,
    heartsUntilNextLevel: PropTypes.number.isRequired,
    vcDonatedAllTime: PropTypes.number.isRequired,
    numUsersRecruited: PropTypes.number.isRequired,
    tabsToday: PropTypes.number.isRequired
  }),
  style: PropTypes.object
}

UserMenu.defaultProps = {
  style: {}
}

export default UserMenu
<commit_msg>Move refs out of state<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import DashboardPopover from '../Dashboard/DashboardPopover'
import RaisedButton from 'material-ui/RaisedButton'
import Divider from 'material-ui/Divider'
import Menu from 'material-ui/Menu'
import MenuItem from 'material-ui/MenuItem'
import IconButton from 'material-ui/IconButton'
import HeartIcon from 'material-ui/svg-icons/action/favorite'
import HeartBorderIcon from 'material-ui/svg-icons/action/favorite-border'
import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'
import SettingsIcon from 'material-ui/svg-icons/action/settings'
import HelpIcon from 'material-ui/svg-icons/action/help'
import PersonAddIcon from 'material-ui/svg-icons/social/person-add'
import ChartIcon from 'material-ui/svg-icons/editor/insert-chart'
import CheckmarkIcon from 'material-ui/svg-icons/action/done'
import ExitToAppIcon from 'material-ui/svg-icons/action/exit-to-app'
import {
  goToInviteFriends,
  goToDonate,
  goToLogin,
  goToSettings,
  goToStats
} from 'navigation/navigation'
import { logout } from 'authentication/user'
import appTheme, {
  dashboardIconActiveColor,
  dashboardIconInactiveColor,
  dividerColor
} from 'theme/default'
import { commaFormatted } from 'utils/utils'
import { MAX_DAILY_HEARTS_FROM_TABS } from '../../constants'

class UserMenu extends React.Component {
  constructor (props) {
    super(props)

    // refs
    this.heartsPopoverAnchorElem = null
    this.menuPopoverAnchorElem = null

    this.state = {
      heartsHover: false,
      heartsPopoverOpen: false,
      menuIconHover: false,
      menuOpen: false
    }
  }

  async logout () {
    var logoutSuccess = false
    try {
      logoutSuccess = await logout()
    } catch (e) {
      console.error(e)
    }
    if (logoutSuccess) {
      goToLogin()
    }
  }

  onHeartsHover (hovering, event) {
    this.setState({
      heartsHover: hovering
    })
  }

  onHeartsClick (event) {
    this.setState({
      heartsPopoverOpen: !this.state.open
    })
  }

  handleHeartsPopoverClose () {
    this.setState({
      heartsPopoverOpen: false
    })
  }

  onMenuClick (event) {
    this.setState({
      menuOpen: !this.state.open
    })
  }

  handleMenuPopoverClose () {
    this.setState({
      menuOpen: false
    })
  }

  onMenuIconHover (hovering) {
    this.setState({
      menuIconHover: hovering
    })
  }

  onHover (hovering) {
    this.setState({
      hover: hovering
    })
  }

  render () {
    const { app, user } = this.props
    if (!user || !app) {
      return null
    }

    const userMenuStyle = {
      display: 'flex',
      alignItems: 'center'
    }

    // Hearts style
    const textStyle = Object.assign({}, {
      color: this.state.heartsHover
        ? dashboardIconActiveColor
        : dashboardIconInactiveColor,
      transition: 'color 300ms ease-in',
      fontSize: 18,
      fontWeight: 'normal',
      fontFamily: appTheme.fontFamily,
      userSelect: 'none',
      cursor: 'pointer'
    }, this.props.style)
    const heartsStyle = Object.assign({}, textStyle, {
      marginRight: 0,
      display: 'flex',
      alignItems: 'center'
    })

    // Hearts popover style
    const heartsPopoverStyle = {
      textAlign: 'center',
      width: 210
    }
    const heartsPopoverSectionStyle = {
    }
    const dividerStyle = {
      marginTop: 16,
      marginBottom: 12
    }
    const statTextStyle = {
      fontSize: 14,
      display: 'block',
      marginTop: 4,
      marginBottom: 4
    }
    const smallHeartIconStyle = {
      height: 16,
      marginLeft: -3
    }
    const statNumberStyle = {
      fontSize: 24,
      display: 'block'
    }
    const popoverButtonStyle = {
      marginTop: 6,
      marginBottom: 0
    }
    const popoverButtonLabelStyle = {
      fontSize: 13
    }

    // Popover section on how to earn Hearts.
    const rewardMethodContainerStyle = Object.assign({}, statTextStyle, {
      display: 'flex',
      textAlign: 'left',
      color: dividerColor,
      marginTop: 1,
      marginBottom: 1
    })
    const rewardAmountsSectionStyle = Object.assign({}, heartsPopoverSectionStyle, {
      paddingLeft: 22,
      paddingRight: 22
    })
    const rewardTextStyle = {
      textAlign: 'left',
      flex: 6
    }
    const rewardValueStyle = {
      flex: 3,
      textAlign: 'right'
    }

    // Menu style
    const menuWidth = 200
    const menuPopoverStyle = {
      padding: 0,
      width: menuWidth
    }
    const menuIconButtonStyle = {
      padding: 0,
      width: 40,
      height: 40
    }
    const menuIconStyle = {
      color: (
        this.state.menuIconHover
          ? dashboardIconActiveColor
          : dashboardIconInactiveColor
      ),
      transition: 'color 300ms ease-in',
      fontSize: 22
    }
    const menuStyle = {
      width: menuWidth,
      overflowX: 'hidden',
      backgroundColor: 'transparent',
      fontFamily: appTheme.fontFamily
    }
    const menuItemStyle = {
      fontSize: 14,
      color: appTheme.palette.alternateTextColor
    }
    const menuItemIconColor = '#FFFFFF'
    const menuItemSvgIconStyle = {
      color: menuItemIconColor,
      height: 22,
      width: 22
    }

    // Used to let the user know they aren't earning any more
    // Hearts from tabs today.
    const reachedMaxDailyHearts = user.tabsToday >= MAX_DAILY_HEARTS_FROM_TABS

    // TODO: add level bar
    return (

 { this.heartsPopoverAnchorElem = elem }}
          data-tour-id={'hearts'}
        >
          {commaFormatted(user.vcCurrent)}
           { this.heartIconContainer = ref }}
          >
            <HeartBorderIcon
              style={{ marginLeft: 2, height: 24, width: 24, paddingBottom: 0 }}
              color={dashboardIconInactiveColor}
              hoverColor={dashboardIconActiveColor}
            />
            { reachedMaxDailyHearts
              ? (
                <CheckmarkIcon
                  style={{ height: 16, width: 16, position: 'absolute', paddingLeft: 4, paddingBottom: 2 }}
                  color={dashboardIconInactiveColor}
                  hoverColor={dashboardIconActiveColor}
                />
              )
              : null
            }
            { reachedMaxDailyHearts
              ? (
                <DashboardPopover
                  open={this.state.heartsHover && !this.state.heartsPopoverOpen}
                  anchorEl={this.heartsPopoverAnchorElem}
                  style={heartsPopoverStyle}
                >

                    You've earned the maximum Hearts from opening tabs today! You'll
                    be able to earn more Hearts in a few hours.

                </DashboardPopover>
              )
              : null
            }

        <DashboardPopover
          open={this.state.heartsPopoverOpen}
          anchorEl={this.heartsPopoverAnchorElem}
          onRequestClose={this.handleHeartsPopoverClose.bind(this)}
          style={heartsPopoverStyle}
        >

              Level {user.level}

                {user.heartsUntilNextLevel}
                <HeartBorderIcon
                  style={smallHeartIconStyle}
                  color={dashboardIconActiveColor}
                />
                 until next level

            <Divider style={dividerStyle} />

                  {user.vcDonatedAllTime}
                  <HeartBorderIcon
                    style={{ marginLeft: 2, height: 24, width: 24, paddingBottom: 1 }}
                    color={dashboardIconActiveColor}
                  />

                Donated

                <RaisedButton
                  label='Donate Hearts'
                  style={popoverButtonStyle}
                  labelStyle={popoverButtonLabelStyle}
                  primary
                  onClick={goToDonate}
                />

            <Divider style={dividerStyle} />

                {user.numUsersRecruited} Tabbers Recruited

                <RaisedButton
                  label='Invite A Friend'
                  labelPosition='before'
                  style={popoverButtonStyle}
                  labelStyle={popoverButtonLabelStyle}
                  primary
                  onClick={goToInviteFriends}
                />

            <Divider style={dividerStyle} />

                Open a tab

                  1
                  <HeartBorderIcon
                    style={Object.assign({}, smallHeartIconStyle, { marginRight: -4 })}
                    color={dividerColor}
                  />

                Recruit a friend

                  {app.referralVcReward}
                  <HeartBorderIcon
                    style={Object.assign({}, smallHeartIconStyle, { marginRight: -4 })}
                    color={dividerColor}
                  />

        </DashboardPopover>
        <IconButton
          style={menuIconButtonStyle}
          iconStyle={menuIconStyle}
          onMouseEnter={this.onMenuIconHover.bind(this, true)}
          onMouseLeave={this.onMenuIconHover.bind(this, false)}
          onClick={this.onMenuClick.bind(this)}
          ref={elem => { this.menuPopoverAnchorElem = elem }}
          data-test-id={'app-menu-icon'}
          data-tour-id={'settings-button'}
        >
          <MoreVertIcon />
        </IconButton>
        <DashboardPopover
          style={menuPopoverStyle}
          open={this.state.menuOpen}
          anchorEl={this.menuPopoverAnchorElem}
          onRequestClose={this.handleMenuPopoverClose.bind(this)}
        >
          <Menu
            width={menuWidth}
            autoWidth={false}
            style={menuStyle}
            menuItemStyle={menuItemStyle}
          >
            <MenuItem primaryText='Settings' onClick={goToSettings}
              leftIcon={
                <SettingsIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <MenuItem primaryText='Donate Hearts' onClick={goToDonate}
              leftIcon={
                <HeartIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <MenuItem primaryText='Invite Friends' onClick={goToInviteFriends}
              leftIcon={
                <PersonAddIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <MenuItem primaryText='Your Stats' onClick={goToStats}
              leftIcon={
                <ChartIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
            <Divider style={{ marginBottom: 0, marginTop: 0 }} />

              <MenuItem primaryText='Help' onClick={goToStats}
                leftIcon={
                  <HelpIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
                }
                style={menuItemStyle}
              />

            <Divider style={{ marginBottom: 0, marginTop: 0 }} />
            <MenuItem
              primaryText='Sign Out'
              onClick={this.logout.bind(this)}
              data-test-id={'app-menu-sign-out'}
              leftIcon={
                <ExitToAppIcon color={menuItemIconColor} style={menuItemSvgIconStyle} />
              }
            />
          </Menu>
        </DashboardPopover>

    )
  }
}

UserMenu.propTypes = {
  app: PropTypes.shape({
    referralVcReward: PropTypes.number.isRequired
  }),
  user: PropTypes.shape({
    vcCurrent: PropTypes.number.isRequired,
    level: PropTypes.number.isRequired,
    heartsUntilNextLevel: PropTypes.number.isRequired,
    vcDonatedAllTime: PropTypes.number.isRequired,
    numUsersRecruited: PropTypes.number.isRequired,
    tabsToday: PropTypes.number.isRequired
  }),
  style: PropTypes.object
}

UserMenu.defaultProps = {
  style: {}
}

export default UserMenu
<|endoftext|>


<commit_before>// Provides default renderer for control Time Picker
sap.ui.define(['sap/ui/commons/ComboBoxRenderer', 'sap/ui/core/Renderer'],
	function(ComboBoxRenderer, Renderer) {
	"use strict";

	/**
	 * Renderer for the Time Picker
	 */
	var TimePickerRenderer = Renderer.extend(ComboBoxRenderer);

	TimePickerRenderer.renderExpander = function(rm, oCmb){

		rm.write("
▼
");

	};

	return TimePickerRenderer;

}, true);
<commit_msg>Update TimePickerRenderer.js<commit_after>// Provides default renderer for control Time Picker
sap.ui.define([
        'sap/ui/commons/ComboBoxRenderer',
        'sap/ui/core/Renderer'], function (ComboBoxRenderer, Renderer) {
    "use strict";

    /**
     * Renderer for the Time Picker
     */
    var TimePickerRenderer = Renderer.extend(ComboBoxRenderer);

    TimePickerRenderer.renderExpander = function (rm, oCmb) {

        rm.write("
▼
");

    };

    return TimePickerRenderer;

}, true);
<|endoftext|>


<commit_before>/*
* Copyright 2017 the Isard-vdi project authors:
*      Josep Maria Viñolas Auquer
*      Alberto Larraz Dalmases
* License: AGPLv3
*/

$(document).ready(function() {
    $template = $(".template-storage-detail");
    var storage_ready=$('#storage').DataTable({
      "ajax": {
        "url": "/api/v3/admin/storage/ready",
        "contentType": "application/json",
        "type": 'GET',
      },
      "sAjaxDataProp": "",
      "language": {
        "loadingRecords": 'Loading...'
      },
      "rowId": "id",
      "deferRender": true,
        "columns": [
            {
                "className":      'details-control',
                "orderable":      false,
                "data":           null,
                "width": "10px",
                "defaultContent": '<button class="btn btn-xs btn-info" type="button"  data-placement="top" ></button>'
            },
            { "data": "directory_path",},
            { "data": "id",},
            { "data": "type",},
            { "data": null},
            { "data": null},
            { "data": "parent",},
            { "data": "user_name",},
            { "data": "category",},
            { "data": "domains",},
            { "data": "status_logs",}
        ],
        "columnDefs": [
            {
                "targets": 4,
                "render": function ( data, type, full, meta ) {
                    if( full['status'] == 'ready' && 'qemu-img-info' in full){
                        return Math.round(full["qemu-img-info"]["virtual-size"]/1000/1000/1000)+" GB"
                    }else{
                        return '-'
                    }
                }},
                {
                "targets": 5,
                "render": function ( data, type, full, meta ) {
                    if( full['status'] == 'ready' && 'qemu-img-info' in full){
                        return Math.round(full["qemu-img-info"]["actual-size"]/1000/1000/1000)+' GB ('+Math.round(full["qemu-img-info"]["actual-size"]*100/full["qemu-img-info"]["virtual-size"])+'%)'
                    }else{
                        return '-'
                    }
                }},
                {
                  "targets": 10,
                  "render": function ( data, type, full, meta ) {
                    if( "status_logs" in full ){
                      return moment.unix(full["status_logs"][full["status_logs"].length -1]["time"]).fromNow()
                    }
                    return "-"
                }
            }],
    });

    $('#storage tbody').on('click', 'td.details-control', function () {
        var tr = $(this).closest("tr");
        var row = storage_ready.row(tr);
        var rowData = row.data();

        if (row.child.isShown()) {
          // This row is already open - close it
          row.child.hide();
          tr.removeClass("shown");
        //   storage_ready.ajax.reload();

          // Destroy the Child Datatable
          $("#cl" + rowData.clientID)
            .DataTable()
            .destroy();
        } else {
            // Open this row
            row.child(format(rowData)).show();
            var id = rowData.id;

            childTable = $("#cl" + id).DataTable({
              dom: "t",
              ajax: {
                url: "/admin/storage/domains/" + id,
                contentType: "application/json",
                type: "GET",
              },
              sAjaxDataProp: "",
              language: {
                loadingRecords:
                  'Loading...',
              },
              columns: [
                { data: "kind" },
                { data: "name" },
              ],
              columnDefs: [
              ],
              select: false,
            });

            tr.addClass("shown");
          }
    } );

    $('.btn-tree').on('click', function(){
      $('form').each(function() {
        this.reset();
      })

      $('#modalTreeDisk').modal({
        backdrop: 'static',
        keyboard: false
      }).modal('show');

      populateDiskTree();
    });

    var storage_deleted=$('#storage_deleted').DataTable( {
        "ajax": {
        "url": "/api/v3/admin/storage/deleted",
                "contentType": "application/json",
                "type": 'GET',
        },
        "sAjaxDataProp": "",
      "language": {
        "loadingRecords": 'Loading...'
      },
      "rowId": "id",
      "deferRender": true,
        "columns": [
            { "data": "id",},
            { "data": "type",},
            { "data": null},
            { "data": null},
            { "data": "user_name",},
            { "data": "category",},
            { "data": "status_logs"}
        ],
        "columnDefs": [
          {
            "targets": 2,
            "render": function ( data, type, full, meta ) {
                if( 'qemu-img-info' in full){
                    return Math.round(full["qemu-img-info"]["virtual-size"]/1000/1000/1000)+" GB"
                }else{
                    return '-'
                }
            }},
            {
            "targets": 3,
            "render": function ( data, type, full, meta ) {
                if( 'qemu-img-info' in full){
                    return Math.round(full["qemu-img-info"]["actual-size"]/1000/1000/1000)+' GB ('+Math.round(full["qemu-img-info"]["actual-size"]*100/full["qemu-img-info"]["virtual-size"])+'%)'
                }else{
                    return '-'
                }
            }},
          {
            "targets": 6,
            "render": function ( data, type, full, meta ) {
              return moment.unix(full["status_logs"][full["status_logs"].length -1]["time"]).fromNow()
          }
        }],
    });

    if( $("#storage_physical").length != 0){
      var storage_physical=$('#storage_physical').DataTable( {
        "ajax": {
        "url": "/api/v3/admin/storage/physical/domains",
                "contentType": "application/json",
                "type": 'GET',
        },
        "sAjaxDataProp": "",
        "language": {
          "loadingRecords": 'Loading...'
        },
        "rowId": "id",
        "deferRender": true,
          "columns": [
            { "data": ""},
            { "data": "path",},
            { "data": "correct-chain",},
            { "data": "size"},
            { "data": "hyper"},
            { "data": "domains"},
            { "data": "tomigrate"},
            {
              "className": 'text-center',
              "data": null,
              "orderable": false,
              "defaultContent": '<input type="checkbox" class="form-check-input"></input>'
            }
        ],
        "columnDefs": [
          {
            "targets": 3,
            "render": function ( data, type, full, meta ) {
              return Math.round(data/1000/1000/1000)+" GB"
            }
          },
          {
            "targets": 0,
            "render": function ( data, type, full, meta ) {
              return '<button type="button" id="btn-info" class="btn btn-pill-right btn-success btn-xs"></button>';
            }
          }
        ],
      });

      $('#storage_physical tbody').on( 'click', 'button', function () {
        var data = storage_physical.row( $(this).parents('tr') ).data();
        switch($(this).attr('id')){
          case 'btn-info':
            $.ajax({
              type: "GET",
              url:
                "/api/v3/admin/storage/physical/toolbox_host",
              contentType: "application/json",
              success: function (toolbox_host) {
                $.ajax({
                  type: "POST",
                  url: toolbox_host+"/storage/disk/info",
                  headers: {"Authorization": "Bearer " +localStorage.getItem("token")},
                  data: JSON.stringify({
                    'path_id': data.path
                  }),
                  contentType: "application/json",
                  success: function (disk_info) {
                    new PNotify({
                      title: "Disk info.",
                        text: JSON.stringify(disk_info),
                        hide: true,
                        delay: 10000,
                        icon: 'fa fa-info',
                        opacity: 1,
                        type: 'info'
                    });
                  },
                });
              },
              error: function (xhr, ajaxOptions, thrownError) {
                console.log(xhr)
                if (xhr.status == 428) {
                  new PNotify({
                      title: "Unable to access storage",
                      text: xhr.responseJSON.description,
                      hide: true,
                      delay: 3000,
                      icon: 'fa fa-warning',
                      opacity: 1,
                      type: 'error'
                  });
                }
              }
            });
        break;
      }
      })

      storage_physical.on( 'click', 'tr[role="row"]', function (e) {
        toggleRow(this, e);
      });

      $(".btn-phy-update").on("click", function () {
        new PNotify({
          title: "Rescan physical disks on storage",
          text: "Do you really want to rescan all them?",
          hide: false,
          opacity: 0.9,
          confirm: { confirm: true },
          buttons: { closer: false, sticker: false },
          history: { history: false },
          addclass: "pnotify-center",
        })
          .get()
          .on("pnotify.confirm", function () {
            rescan_pnotify = new PNotify({
              title: "Waiting storage",
                text: "Storage is looking for files in storage. Please wait, it can take some minutes...",
                hide: false,
                icon: 'fa fa-alert-sign',
                opacity: 1,
                type: "warning",
            });
            $.ajax({
              type: "GET",
              url:
                "/api/v3/admin/storage/physical/toolbox_host",
              contentType: "application/json",
              success: function (toolbox_host) {
                $.ajax({
                  type: "PUT",
                  url: toolbox_host+"/storage/disks",
                  contentType: "application/json",
                  success: function (data) {
                    storage_physical.ajax.reload();
                    rescan_pnotify.update({
                      title: "Physical storage",
                      text:  "Updated "+data.templates+" templates and "+data.desktops+" desktop disksfrom "+toolbox_host,
                      hide: true,
                      delay: 5000,
                      opacity: 1,
                      type: 'success'
                  });
                  },
                });
              },
              error: function (xhr, ajaxOptions, thrownError) {
                console.log(xhr)
                if (xhr.status == 428) {
                  new PNotify({
                      title: "Unable to access storage",
                      text: xhr.responseJSON.description,
                      hide: true,
                      delay: 3000,
                      icon: 'fa fa-warning',
                      opacity: 1,
                      type: 'error'
                  });
                }
              }
            });
          })
          .on("pnotify.cancel", function () {});
      });

      $('#mactions').on('change', function () {
        action=$(this).val();
        names=''
        ids=[]

        if(storage_physical.rows('.active').data().length){
            $.each(storage_physical.rows('.active').data(),function(key, value){
                names+=value['path']+'\n';
                ids.push(value['path']);
            });
            var text = "You are about to\n- Activate maintenance mode\n- Stop all desktops\n while executing "+action+" these physical disks:\n\n "+names
        }else{
            $.each(storage_physical.rows({filter: 'applied'}).data(),function(key, value){
              ids.push(value['path']);
            });
            var text = "You are about to\n- Activate maintenance mode\n- Stop all desktops\n while executing "+action+" "+storage_physical.rows({filter: 'applied'}).data().length+" disks!\n All the disks in list!"
        }

        new PNotify({
            title: 'Warning!',
              text: text,
              hide: false,
              opacity: 0.9,
              confirm: {
                confirm: true
              },
              buttons: {
                closer: false,
                sticker: false
              },
              history: {
                history: false
              },
              addclass: 'pnotify-center'
            }).get().on('pnotify.confirm', function() {
              new PNotify({
                title: "Migrating disks.",
                  text: "Activating maintenance mode and stopping domains",
                  hide: true,
                  delay: 4250,
                  icon: 'fa fa-alert',
                  opacity: 1,
                  type: 'warning',
              });
              $.ajax({
                type: "POST",
                url:"/api/v3/admin/storage/physical/multiple_actions/"+action,
                data: JSON.stringify({'paths':ids}),
                contentType: 'application/json',
                success: function(data)
                {
                  storage_physical.ajax.reload()
                },
                always: function(data)
                {
                  $('#mactions option[value="none"]').prop("selected", true);
                  $('#domains tr.active').removeClass('active')
                  $('#mactions option[value="none"]').prop("selected",true);
                }
              });
            } )
      })
    }

    socket = io.connect(location.protocol+'//' + document.domain + ':' + location.port+'/administrators', {
        'query': {'jwt': localStorage.getItem("token")},
        'path': '/api/v3/socket.io/',
        'transports': ['websocket']
    });

    socket.on('connect', function() {
        connection_done();
        console.log('Listening aministrators namespace');
    });

    socket.on('connect_error', function(data) {
      connection_lost();
    });

    socket.on('user_quota', function(data) {
        console.log('Quota update')
        var data = JSON.parse(data);
        drawUserQuota(data);
    });

    var storage_migration_progress = null
    socket.on('storage_migration_progress', function(data) {
        var data = JSON.parse(data);
        if (storage_migration_progress == null){
          storage_migration_progress = new PNotify({
            title: "Migrating disks. Maintenance mode active.",
              text: data.description+ "\nProgress: "+data.current+"/"+data.total,
              hide: false,
              icon: 'fa fa-'+data.type,
              opacity: 1,
              type: data.type,
          });
        }else{
          storage_migration_progress.update({
            title: "Migrating disks. Maintenance mode active.",
              text: data.description+ "\nProgress: "+data.current+"/"+data.total+"\nPLEASE WAIT!",
              hide: false,
              icon: 'fa fa-'+data.type,
              opacity: 1,
              type: data.type,
          });
        }
        if ("id" in data){
          storage_physical.row('#'+data.id).remove().draw();
        }

        if(data.current >= data.total){
          PNotify.removeAll()
          storage_ready.ajax.reload()}
    });

  })

function format(rowData) {
    var childTable =
      '
' +
      "
";
    return $(childTable).toArray();
}

function populateDiskTree(){
  $(":ui-fancytree").fancytree("destroy")
  $("#modalTreeDisk .storage_disk_tree").fancytree({
    extensions: ["table"],
    table: {
      indentation: 20,      // indent 20px per node level
      nodeColumnIdx: 1,     // render the node title into the 2nd column
    },
    source: {
      url: "/api/v3/admin/storage/tree_list",
      cache: false
    },
    lazyLoad: function(event, data){
      data.result = $.ajax({
        url: "/api/v3/admin/storage/tree_list",
        dataType: "json"
      });
    },
    renderColumns: function(event, data) {
      var node = data.node,
      $tdList = $(node.tr).find(">td");
      $tdList.eq(0).text(node.getIndexHier());
      // Fancy tree populates id column (1) as title
      $tdList.eq(2).text(node.data.user_name);
      if (node.data.directory_path == "/isard/templates") {
        $tdList.eq(3).text("Template");
      } else if (node.data.directory_path == "/isard/groups") {
        $tdList.eq(3).text("Desktop");
      }
      $tdList.eq(4).text(node.data.category_name);
    }
  });
}
<commit_msg>fix(webapp): only migrate old disks<commit_after>/*
* Copyright 2017 the Isard-vdi project authors:
*      Josep Maria Viñolas Auquer
*      Alberto Larraz Dalmases
* License: AGPLv3
*/

$(document).ready(function() {
    $template = $(".template-storage-detail");
    var storage_ready=$('#storage').DataTable({
      "ajax": {
        "url": "/api/v3/admin/storage/ready",
        "contentType": "application/json",
        "type": 'GET',
      },
      "sAjaxDataProp": "",
      "language": {
        "loadingRecords": 'Loading...'
      },
      "rowId": "id",
      "deferRender": true,
        "columns": [
            {
                "className":      'details-control',
                "orderable":      false,
                "data":           null,
                "width": "10px",
                "defaultContent": '<button class="btn btn-xs btn-info" type="button"  data-placement="top" ></button>'
            },
            { "data": "directory_path",},
            { "data": "id",},
            { "data": "type",},
            { "data": null},
            { "data": null},
            { "data": "parent",},
            { "data": "user_name",},
            { "data": "category",},
            { "data": "domains",},
            { "data": "status_logs",}
        ],
        "columnDefs": [
            {
                "targets": 4,
                "render": function ( data, type, full, meta ) {
                    if( full['status'] == 'ready' && 'qemu-img-info' in full){
                        return Math.round(full["qemu-img-info"]["virtual-size"]/1000/1000/1000)+" GB"
                    }else{
                        return '-'
                    }
                }},
                {
                "targets": 5,
                "render": function ( data, type, full, meta ) {
                    if( full['status'] == 'ready' && 'qemu-img-info' in full){
                        return Math.round(full["qemu-img-info"]["actual-size"]/1000/1000/1000)+' GB ('+Math.round(full["qemu-img-info"]["actual-size"]*100/full["qemu-img-info"]["virtual-size"])+'%)'
                    }else{
                        return '-'
                    }
                }},
                {
                  "targets": 10,
                  "render": function ( data, type, full, meta ) {
                    if( "status_logs" in full ){
                      return moment.unix(full["status_logs"][full["status_logs"].length -1]["time"]).fromNow()
                    }
                    return "-"
                }
            }],
    });

    $('#storage tbody').on('click', 'td.details-control', function () {
        var tr = $(this).closest("tr");
        var row = storage_ready.row(tr);
        var rowData = row.data();

        if (row.child.isShown()) {
          // This row is already open - close it
          row.child.hide();
          tr.removeClass("shown");
        //   storage_ready.ajax.reload();

          // Destroy the Child Datatable
          $("#cl" + rowData.clientID)
            .DataTable()
            .destroy();
        } else {
            // Open this row
            row.child(format(rowData)).show();
            var id = rowData.id;

            childTable = $("#cl" + id).DataTable({
              dom: "t",
              ajax: {
                url: "/admin/storage/domains/" + id,
                contentType: "application/json",
                type: "GET",
              },
              sAjaxDataProp: "",
              language: {
                loadingRecords:
                  'Loading...',
              },
              columns: [
                { data: "kind" },
                { data: "name" },
              ],
              columnDefs: [
              ],
              select: false,
            });

            tr.addClass("shown");
          }
    } );

    $('.btn-tree').on('click', function(){
      $('form').each(function() {
        this.reset();
      })

      $('#modalTreeDisk').modal({
        backdrop: 'static',
        keyboard: false
      }).modal('show');

      populateDiskTree();
    });

    var storage_deleted=$('#storage_deleted').DataTable( {
        "ajax": {
        "url": "/api/v3/admin/storage/deleted",
                "contentType": "application/json",
                "type": 'GET',
        },
        "sAjaxDataProp": "",
      "language": {
        "loadingRecords": 'Loading...'
      },
      "rowId": "id",
      "deferRender": true,
        "columns": [
            { "data": "id",},
            { "data": "type",},
            { "data": null},
            { "data": null},
            { "data": "user_name",},
            { "data": "category",},
            { "data": "status_logs"}
        ],
        "columnDefs": [
          {
            "targets": 2,
            "render": function ( data, type, full, meta ) {
                if( 'qemu-img-info' in full){
                    return Math.round(full["qemu-img-info"]["virtual-size"]/1000/1000/1000)+" GB"
                }else{
                    return '-'
                }
            }},
            {
            "targets": 3,
            "render": function ( data, type, full, meta ) {
                if( 'qemu-img-info' in full){
                    return Math.round(full["qemu-img-info"]["actual-size"]/1000/1000/1000)+' GB ('+Math.round(full["qemu-img-info"]["actual-size"]*100/full["qemu-img-info"]["virtual-size"])+'%)'
                }else{
                    return '-'
                }
            }},
          {
            "targets": 6,
            "render": function ( data, type, full, meta ) {
              return moment.unix(full["status_logs"][full["status_logs"].length -1]["time"]).fromNow()
          }
        }],
    });

    if( $("#storage_physical").length != 0){
      var storage_physical=$('#storage_physical').DataTable( {
        "ajax": {
        "url": "/api/v3/admin/storage/physical/domains",
                "contentType": "application/json",
                "type": 'GET',
        },
        "sAjaxDataProp": "",
        "language": {
          "loadingRecords": 'Loading...'
        },
        "rowId": "id",
        "deferRender": true,
          "columns": [
            { "data": ""},
            { "data": "path",},
            { "data": "correct-chain",},
            { "data": "size"},
            { "data": "hyper"},
            { "data": "domains"},
            { "data": "tomigrate"},
            {
              "className": 'text-center',
              "data": null,
              "orderable": false,
              "defaultContent": '<input type="checkbox" class="form-check-input"></input>'
            }
        ],
        "columnDefs": [
          {
            "targets": 3,
            "render": function ( data, type, full, meta ) {
              return Math.round(data/1000/1000/1000)+" GB"
            }
          },
          {
            "targets": 0,
            "render": function ( data, type, full, meta ) {
              return '<button type="button" id="btn-info" class="btn btn-pill-right btn-success btn-xs"></button>';
            }
          }
        ],
      });

      $('#storage_physical tbody').on( 'click', 'button', function () {
        var data = storage_physical.row( $(this).parents('tr') ).data();
        switch($(this).attr('id')){
          case 'btn-info':
            $.ajax({
              type: "GET",
              url:
                "/api/v3/admin/storage/physical/toolbox_host",
              contentType: "application/json",
              success: function (toolbox_host) {
                $.ajax({
                  type: "POST",
                  url: toolbox_host+"/storage/disk/info",
                  headers: {"Authorization": "Bearer " +localStorage.getItem("token")},
                  data: JSON.stringify({
                    'path_id': data.path
                  }),
                  contentType: "application/json",
                  success: function (disk_info) {
                    new PNotify({
                      title: "Disk info.",
                        text: JSON.stringify(disk_info),
                        hide: true,
                        delay: 10000,
                        icon: 'fa fa-info',
                        opacity: 1,
                        type: 'info'
                    });
                  },
                });
              },
              error: function (xhr, ajaxOptions, thrownError) {
                console.log(xhr)
                if (xhr.status == 428) {
                  new PNotify({
                      title: "Unable to access storage",
                      text: xhr.responseJSON.description,
                      hide: true,
                      delay: 3000,
                      icon: 'fa fa-warning',
                      opacity: 1,
                      type: 'error'
                  });
                }
              }
            });
        break;
      }
      })

      storage_physical.on( 'click', 'tr[role="row"]', function (e) {
        toggleRow(this, e);
      });

      $(".btn-phy-update").on("click", function () {
        new PNotify({
          title: "Rescan physical disks on storage",
          text: "Do you really want to rescan all them?",
          hide: false,
          opacity: 0.9,
          confirm: { confirm: true },
          buttons: { closer: false, sticker: false },
          history: { history: false },
          addclass: "pnotify-center",
        })
          .get()
          .on("pnotify.confirm", function () {
            rescan_pnotify = new PNotify({
              title: "Waiting storage",
                text: "Storage is looking for files in storage. Please wait, it can take some minutes...",
                hide: false,
                icon: 'fa fa-alert-sign',
                opacity: 1,
                type: "warning",
            });
            $.ajax({
              type: "GET",
              url:
                "/api/v3/admin/storage/physical/toolbox_host",
              contentType: "application/json",
              success: function (toolbox_host) {
                $.ajax({
                  type: "PUT",
                  url: toolbox_host+"/storage/disks",
                  contentType: "application/json",
                  success: function (data) {
                    storage_physical.ajax.reload();
                    rescan_pnotify.update({
                      title: "Physical storage",
                      text:  "Updated "+data.templates+" templates and "+data.desktops+" desktop disksfrom "+toolbox_host,
                      hide: true,
                      delay: 5000,
                      opacity: 1,
                      type: 'success'
                  });
                  },
                });
              },
              error: function (xhr, ajaxOptions, thrownError) {
                console.log(xhr)
                if (xhr.status == 428) {
                  new PNotify({
                      title: "Unable to access storage",
                      text: xhr.responseJSON.description,
                      hide: true,
                      delay: 3000,
                      icon: 'fa fa-warning',
                      opacity: 1,
                      type: 'error'
                  });
                }
              }
            });
          })
          .on("pnotify.cancel", function () {});
      });

      $('#mactions').on('change', function () {
        action=$(this).val();
        names=''
        ids=[]

        if(storage_physical.rows('.active').data().length){
            $.each(storage_physical.rows('.active').data(),function(key, value){
                if(value["tomigrate"] == true){
                  names+=value['path']+'\n';
                  ids.push(value['path']);
                }
            });
            var text = "You are about to\n- Activate maintenance mode\n- Stop all desktops\n while executing "+action+" these 'To Migrate' physical disks:\n\n "+names
        }else{
            $.each(storage_physical.rows({filter: 'applied'}).data(),function(key, value){
              if(value["tomigrate"] == true){
                ids.push(value['path']);
              }
            });
            var text = "You are about to\n- Activate maintenance mode\n- Stop all desktops\n while executing "+action+" "+ids.length+" disks!\n All the 'To Migrate' disks in list!"
        }

        new PNotify({
            title: 'Warning!',
              text: text,
              hide: false,
              opacity: 0.9,
              confirm: {
                confirm: true
              },
              buttons: {
                closer: false,
                sticker: false
              },
              history: {
                history: false
              },
              addclass: 'pnotify-center'
            }).get().on('pnotify.confirm', function() {
              new PNotify({
                title: "Migrating disks.",
                  text: "Activating maintenance mode and stopping domains",
                  hide: true,
                  delay: 4250,
                  icon: 'fa fa-alert',
                  opacity: 1,
                  type: 'warning',
              });
              $.ajax({
                type: "POST",
                url:"/api/v3/admin/storage/physical/multiple_actions/"+action,
                data: JSON.stringify({'paths':ids}),
                contentType: 'application/json',
                success: function(data)
                {
                  storage_physical.ajax.reload()
                },
                always: function(data)
                {
                  $('#mactions option[value="none"]').prop("selected", true);
                  $('#domains tr.active').removeClass('active')
                  $('#mactions option[value="none"]').prop("selected",true);
                }
              });
            } )
      })
    }

    socket = io.connect(location.protocol+'//' + document.domain + ':' + location.port+'/administrators', {
        'query': {'jwt': localStorage.getItem("token")},
        'path': '/api/v3/socket.io/',
        'transports': ['websocket']
    });

    socket.on('connect', function() {
        connection_done();
        console.log('Listening aministrators namespace');
    });

    socket.on('connect_error', function(data) {
      connection_lost();
    });

    socket.on('user_quota', function(data) {
        console.log('Quota update')
        var data = JSON.parse(data);
        drawUserQuota(data);
    });

    var storage_migration_progress = null
    socket.on('storage_migration_progress', function(data) {
        var data = JSON.parse(data);
        if (storage_migration_progress == null){
          storage_migration_progress = new PNotify({
            title: "Migrating disks. Maintenance mode active.",
              text: data.description+ "\nProgress: "+data.current+"/"+data.total,
              hide: false,
              icon: 'fa fa-'+data.type,
              opacity: 1,
              type: data.type,
          });
        }else{
          storage_migration_progress.update({
            title: "Migrating disks. Maintenance mode active.",
              text: data.description+ "\nProgress: "+data.current+"/"+data.total+"\nPLEASE WAIT!",
              hide: false,
              icon: 'fa fa-'+data.type,
              opacity: 1,
              type: data.type,
          });
        }
        if ("id" in data){
          storage_physical.row('#'+data.id).remove().draw();
        }

        if(data.current >= data.total){
          PNotify.removeAll()
          storage_ready.ajax.reload()}
    });

  })

function format(rowData) {
    var childTable =
      '
' +
      "
";
    return $(childTable).toArray();
}

function populateDiskTree(){
  $(":ui-fancytree").fancytree("destroy")
  $("#modalTreeDisk .storage_disk_tree").fancytree({
    extensions: ["table"],
    table: {
      indentation: 20,      // indent 20px per node level
      nodeColumnIdx: 1,     // render the node title into the 2nd column
    },
    source: {
      url: "/api/v3/admin/storage/tree_list",
      cache: false
    },
    lazyLoad: function(event, data){
      data.result = $.ajax({
        url: "/api/v3/admin/storage/tree_list",
        dataType: "json"
      });
    },
    renderColumns: function(event, data) {
      var node = data.node,
      $tdList = $(node.tr).find(">td");
      $tdList.eq(0).text(node.getIndexHier());
      // Fancy tree populates id column (1) as title
      $tdList.eq(2).text(node.data.user_name);
      if (node.data.directory_path == "/isard/templates") {
        $tdList.eq(3).text("Template");
      } else if (node.data.directory_path == "/isard/groups") {
        $tdList.eq(3).text("Desktop");
      }
      $tdList.eq(4).text(node.data.category_name);
    }
  });
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

import type {LogLevel} from '../Data/LogBoxLog';

import * as React from 'react';
import SafeAreaView from '../../Components/SafeAreaView/SafeAreaView';
import StyleSheet from '../../StyleSheet/StyleSheet';
import Text from '../../Text/Text';
import View from '../../Components/View/View';
import LogBoxButton from './LogBoxButton';
import * as LogBoxStyle from './LogBoxStyle';

type Props = $ReadOnly<{|
  onDismiss: () => void,
  onMinimize: () => void,
  fatalType?: ?LogLevel,
|}>;

function LogBoxInspectorFooter(props: Props): React.Node {
  if (props.fatalType === 'fatal' || props.fatalType === 'syntax') {
    return (
      <View style={styles.root}>
        <LogBoxButton
          backgroundColor={{
            default: LogBoxStyle.getFatalColor(),
            pressed: LogBoxStyle.getFatalDarkColor(),
          }}
          onPress={() =>
            require('../../Utilities/DevSettings').reload('LogBox fatal')
          }
          style={fatalStyles.button}>
          <View style={[fatalStyles.content]}>
            <Text style={fatalStyles.label}>Reload</Text>
            <Text style={fatalStyles.subtextLabel}>
              {{fatal: 'Fatal', syntax: 'Syntax'}[props.fatalType]} errors
              require a full reload
            </Text>
          </View>
          <SafeAreaView />
        </LogBoxButton>
      </View>
    );
  }

  return (
    <View style={styles.root}>
      <FooterButton text="Minimize" onPress={props.onMinimize} />
      <FooterButton text="Dismiss" onPress={props.onDismiss} />
    </View>
  );
}

type ButtonProps = $ReadOnly<{|
  onPress: () => void,
  text: string,
|}>;

function FooterButton(props: ButtonProps): React.Node {
  return (
    <LogBoxButton
      backgroundColor={{
        default: 'transparent',
        pressed: LogBoxStyle.getBackgroundLightColor(),
      }}
      onPress={props.onPress}
      style={buttonStyles.button}>
      <View style={buttonStyles.content}>
        <Text style={buttonStyles.label}>{props.text}</Text>
      </View>
      <SafeAreaView />
    </LogBoxButton>
  );
}

const fatalStyles = StyleSheet.create({
  button: {
    flex: 1,
  },
  content: {
    alignItems: 'center',
    height: 60,
    justifyContent: 'center',
  },
  subtext: {
    height: 60,
  },
  label: {
    color: LogBoxStyle.getTextColor(1),
    fontSize: 14,
    fontWeight: '600',
    includeFontPadding: false,
    lineHeight: 20,
  },
  subtextLabel: {
    color: LogBoxStyle.getTextColor(0.8),
    fontSize: 11,
    includeFontPadding: false,
    lineHeight: 12,
  },
});

const buttonStyles = StyleSheet.create({
  button: {
    flex: 1,
  },
  content: {
    alignItems: 'center',
    height: 48,
    justifyContent: 'center',
  },
  label: {
    color: LogBoxStyle.getTextColor(1),
    fontSize: 14,
    includeFontPadding: false,
    lineHeight: 20,
  },
});

const styles = StyleSheet.create({
  root: {
    backgroundColor: LogBoxStyle.getBackgroundColor(1),
    shadowColor: '#000',
    shadowOffset: {width: 0, height: -2},
    shadowRadius: 2,
    shadowOpacity: 0.5,
    elevation: 1,
    flexDirection: 'row',
  },
});

export default LogBoxInspectorFooter;
<commit_msg>LogBox - Update press backfround for inspector footers<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

import type {LogLevel} from '../Data/LogBoxLog';

import * as React from 'react';
import SafeAreaView from '../../Components/SafeAreaView/SafeAreaView';
import StyleSheet from '../../StyleSheet/StyleSheet';
import Text from '../../Text/Text';
import View from '../../Components/View/View';
import LogBoxButton from './LogBoxButton';
import * as LogBoxStyle from './LogBoxStyle';

type Props = $ReadOnly<{|
  onDismiss: () => void,
  onMinimize: () => void,
  fatalType?: ?LogLevel,
|}>;

function LogBoxInspectorFooter(props: Props): React.Node {
  if (props.fatalType === 'fatal' || props.fatalType === 'syntax') {
    return (
      <View style={styles.root}>
        <LogBoxButton
          backgroundColor={{
            default: LogBoxStyle.getFatalColor(),
            pressed: LogBoxStyle.getFatalDarkColor(),
          }}
          onPress={() =>
            require('../../Utilities/DevSettings').reload('LogBox fatal')
          }
          style={fatalStyles.button}>
          <View style={[fatalStyles.content]}>
            <Text style={fatalStyles.label}>Reload</Text>
            <Text style={fatalStyles.subtextLabel}>
              {{fatal: 'Fatal', syntax: 'Syntax'}[props.fatalType]} errors
              require a full reload
            </Text>
          </View>
          <SafeAreaView />
        </LogBoxButton>
      </View>
    );
  }

  return (
    <View style={styles.root}>
      <FooterButton text="Minimize" onPress={props.onMinimize} />
      <FooterButton text="Dismiss" onPress={props.onDismiss} />
    </View>
  );
}

type ButtonProps = $ReadOnly<{|
  onPress: () => void,
  text: string,
|}>;

function FooterButton(props: ButtonProps): React.Node {
  return (
    <LogBoxButton
      backgroundColor={{
        default: 'transparent',
        pressed: LogBoxStyle.getBackgroundDarkColor(),
      }}
      onPress={props.onPress}
      style={buttonStyles.button}>
      <View style={buttonStyles.content}>
        <Text style={buttonStyles.label}>{props.text}</Text>
      </View>
      <SafeAreaView />
    </LogBoxButton>
  );
}

const fatalStyles = StyleSheet.create({
  button: {
    flex: 1,
  },
  content: {
    alignItems: 'center',
    height: 60,
    justifyContent: 'center',
  },
  subtext: {
    height: 60,
  },
  label: {
    color: LogBoxStyle.getTextColor(1),
    fontSize: 14,
    fontWeight: '600',
    includeFontPadding: false,
    lineHeight: 20,
  },
  subtextLabel: {
    color: LogBoxStyle.getTextColor(0.8),
    fontSize: 11,
    includeFontPadding: false,
    lineHeight: 12,
  },
});

const buttonStyles = StyleSheet.create({
  button: {
    flex: 1,
  },
  content: {
    alignItems: 'center',
    height: 48,
    justifyContent: 'center',
  },
  label: {
    color: LogBoxStyle.getTextColor(1),
    fontSize: 14,
    includeFontPadding: false,
    lineHeight: 20,
  },
});

const styles = StyleSheet.create({
  root: {
    backgroundColor: LogBoxStyle.getBackgroundColor(1),
    shadowColor: '#000',
    shadowOffset: {width: 0, height: -2},
    shadowRadius: 2,
    shadowOpacity: 0.5,
    elevation: 1,
    flexDirection: 'row',
  },
});

export default LogBoxInspectorFooter;
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Alibaba Group Holding Limited.
 * All rights reserved.
 *
 */
'use strict';

import getVendorPropertyName from 'domkit/getVendorPropertyName';
import CSSProperty from 'CSSProperty';

var shorthandProperties = {
  margin: true,
  padding: true,
  borderWidth: true,
  borderRadius: true,
};

// some number that react not auto add px
var numberProperties = {
  lineHeight: true
};

var boxProperties = {
  paddingHorizontal: true,
  paddingVertical: true,
  marginHorizontal: true,
  marginVertical: true,
};

var borderProperties = {
  borderColor: true,
  borderWidth: true,
  borderTopColor: true,
  borderRightColor: true,
  borderBottomColor: true,
  borderLeftColor: true,
  borderTopWidth: true,
  borderRightWidth: true,
  borderBottomWidth: true,
  borderLeftWidth: true,
};

// prefix 2009 spec
var flexboxProperties = {
  flex: 'WebkitBoxFlex',
  order: 'WebkitBoxOrdinalGroup',
  // https://github.com/postcss/autoprefixer/blob/master/lib/hacks/flex-direction.coffee
  flexDirection: 'WebkitBoxOrient',
  // https://github.com/postcss/autoprefixer/blob/master/lib/hacks/align-items.coffee
  alignItems: 'WebkitBoxAlign',
  // https://github.com/postcss/autoprefixer/blob/master/lib/hacks/justify-content.coffee
  justifyContent: 'WebkitBoxPack',
  flexWrap: null,
  alignSelf: null,
};

var oldFlexboxValues = {
  'flex-end': 'end',
  'flex-start': 'start',
  'space-between': 'justify',
  'space-around': 'distribute',
};

var builtinStyle = document.createElement('div').style;
var flexboxSpec;
if ('alignSelf' in builtinStyle) flexboxSpec = 'final';
else if ('webkitAlignSelf' in builtinStyle) flexboxSpec = 'finalVendor';
else flexboxSpec = '2009';

// FIXME: UCBrowser is cheat
var isUCBrowser = /UCBrowser/i.test(navigator.userAgent);
if (isUCBrowser) flexboxSpec = '2009';

// TODO: cache the result
function prefixOldFlexbox(property, value, result) {

  if (flexboxSpec === '2009') {
    var oldValue = oldFlexboxValues[value] || value;
    var oldProperty = flexboxProperties[property] || property;
    if (oldProperty === 'WebkitBoxOrient') {
      // boxOrient
      if (value.indexOf('row') != -1) {
        oldValue = 'horizontal';
      } else {
        oldValue = 'vertical';
      }
      // boxDirection
      var dir = '';
      if (value.indexOf('reverse') != -1) {
        dir = 'reverse';
      } else {
        dir = 'normal';
      }
      result.WebkitBoxDirection = dir;
    }
    return result[oldProperty] = oldValue;

  } else if (flexboxSpec === 'finalVendor') {
    return result[getVendorPropertyName(property)] = value;

  } else {
    return result[property] = value;

  }
}

function extendBoxProperties(property, value, result) {
  var padding = 'padding';
  var margin = 'margin';
  var horizontal = 'Horizontal';
  var vertical = 'Vertical';
  var type = property.indexOf(margin) == 0 ? margin : padding;
  var directionType = property.indexOf(vertical) !== -1 ? vertical : horizontal;

  if (directionType == horizontal) {
    result[type + 'Left'] = result[type + 'Right'] = value;
  } else if (directionType == vertical) {
    result[type + 'Top'] = result[type + 'Bottom'] = value;
  }
}

function isValidValue(value) {
  return value !== '' && value !== null && value !== undefined;
}

function processValueForProp(value, prop) {

  if (typeof value == 'number') {
    // transform less then 1px value to 1px, 0.5 to be 1
    if (!CSSProperty.isUnitlessNumber[prop] && value > 0 && value < 1) {
      value = 1;
    }

    // Add px to numeric values
    if (numberProperties[prop] && typeof value == 'number') {
      value += 'px';
    }
  }

  // [
  //   {scaleX: 2},
  //   {scaleY: 2}
  // ] => scaleX(2) scaleY(2)

  if (shorthandProperties[prop] && typeof value == 'string') {
    value = value.replace(/\d*\.?\d+(rem|em|in|cm|mm|pt|pc|px|vh|vw|vmin|vmax|%)*/g, function(val, unit) {
      return unit ? val : val + 'px';
    });
  }

  return value;
}

function defaultBorderStyle(style, result) {
  if (!style.borderStyle && !result.borderStyle) {
    result.borderStyle = 'solid';
  }

  if (!style.borderWidth && !result.borderWidth) {
    result.borderWidth = 0;
  }

  if (!style.borderColor && !result.borderColor) {
    result.borderColor = 'black';
  }
}

function extendProperties(style) {
  var result = {};

  for (var property in style) {
    var value = style[property];
    if (!isValidValue(value)) {
      continue;
    }
    // set a default border style if there has border about property
    if (borderProperties[property]) {
      defaultBorderStyle(style, result);
    }

    if (boxProperties[property]) {
      extendBoxProperties(property, value, result);
    } else if (flexboxProperties[property]) {
      prefixOldFlexbox(property, value, result);
    } else {
      value = processValueForProp(value, property);
      property = getVendorPropertyName(property);
      result[property] = value;
    }
  }

  return result;
}

module.exports = extendProperties;
<commit_msg>flex fix for IE11<commit_after>/**
 * Copyright (c) 2015-present, Alibaba Group Holding Limited.
 * All rights reserved.
 *
 */
'use strict';

import getVendorPropertyName from 'domkit/getVendorPropertyName';
import CSSProperty from 'CSSProperty';

var shorthandProperties = {
  margin: true,
  padding: true,
  borderWidth: true,
  borderRadius: true,
};

// some number that react not auto add px
var numberProperties = {
  lineHeight: true
};

var boxProperties = {
  paddingHorizontal: true,
  paddingVertical: true,
  marginHorizontal: true,
  marginVertical: true,
};

var borderProperties = {
  borderColor: true,
  borderWidth: true,
  borderTopColor: true,
  borderRightColor: true,
  borderBottomColor: true,
  borderLeftColor: true,
  borderTopWidth: true,
  borderRightWidth: true,
  borderBottomWidth: true,
  borderLeftWidth: true,
};

// prefix 2009 spec
var flexboxProperties = {
  flex: 'WebkitBoxFlex',
  order: 'WebkitBoxOrdinalGroup',
  // https://github.com/postcss/autoprefixer/blob/master/lib/hacks/flex-direction.coffee
  flexDirection: 'WebkitBoxOrient',
  // https://github.com/postcss/autoprefixer/blob/master/lib/hacks/align-items.coffee
  alignItems: 'WebkitBoxAlign',
  // https://github.com/postcss/autoprefixer/blob/master/lib/hacks/justify-content.coffee
  justifyContent: 'WebkitBoxPack',
  flexWrap: null,
  alignSelf: null,
};

var oldFlexboxValues = {
  'flex-end': 'end',
  'flex-start': 'start',
  'space-between': 'justify',
  'space-around': 'distribute',
};

var builtinStyle = document.createElement('div').style;
var flexboxSpec;
if ('alignSelf' in builtinStyle) flexboxSpec = 'final';
else if ('webkitAlignSelf' in builtinStyle) flexboxSpec = 'finalVendor';
else flexboxSpec = '2009';

// FIXME: UCBrowser is cheat
var isUCBrowser = /UCBrowser/i.test(navigator.userAgent);
if (isUCBrowser) flexboxSpec = '2009';

// TODO: cache the result
function prefixOldFlexbox(property, value, result) {

  if (flexboxSpec === '2009') {
    var oldValue = oldFlexboxValues[value] || value;
    var oldProperty = flexboxProperties[property] || property;
    if (oldProperty === 'WebkitBoxOrient') {
      // boxOrient
      if (value.indexOf('row') != -1) {
        oldValue = 'horizontal';
      } else {
        oldValue = 'vertical';
      }
      // boxDirection
      var dir = '';
      if (value.indexOf('reverse') != -1) {
        dir = 'reverse';
      } else {
        dir = 'normal';
      }
      result.WebkitBoxDirection = dir;
    }
    return result[oldProperty] = oldValue;

  } else if (flexboxSpec === 'finalVendor') {
    return result[getVendorPropertyName(property)] = value;

  } else {
    return result[property] = value;

  }
}

function defaultFlexExpansion (style, result) {
  const grow = style.flex
  const shrink = style.flexShrink != null ? style.flexShrink : 1
  const basis = style.flexBasis != null ? style.flexBasis : 'auto'
  result.flex = `${grow} ${shrink} ${basis}`
}

function extendBoxProperties(property, value, result) {
  var padding = 'padding';
  var margin = 'margin';
  var horizontal = 'Horizontal';
  var vertical = 'Vertical';
  var type = property.indexOf(margin) == 0 ? margin : padding;
  var directionType = property.indexOf(vertical) !== -1 ? vertical : horizontal;

  if (directionType == horizontal) {
    result[type + 'Left'] = result[type + 'Right'] = value;
  } else if (directionType == vertical) {
    result[type + 'Top'] = result[type + 'Bottom'] = value;
  }
}

function isValidValue(value) {
  return value !== '' && value !== null && value !== undefined;
}

function processValueForProp(value, prop) {

  if (typeof value == 'number') {
    // transform less then 1px value to 1px, 0.5 to be 1
    if (!CSSProperty.isUnitlessNumber[prop] && value > 0 && value < 1) {
      value = 1;
    }

    // Add px to numeric values
    if (numberProperties[prop] && typeof value == 'number') {
      value += 'px';
    }
  }

  // [
  //   {scaleX: 2},
  //   {scaleY: 2}
  // ] => scaleX(2) scaleY(2)

  if (shorthandProperties[prop] && typeof value == 'string') {
    value = value.replace(/\d*\.?\d+(rem|em|in|cm|mm|pt|pc|px|vh|vw|vmin|vmax|%)*/g, function(val, unit) {
      return unit ? val : val + 'px';
    });
  }

  return value;
}

function defaultBorderStyle(style, result) {
  if (!style.borderStyle && !result.borderStyle) {
    result.borderStyle = 'solid';
  }

  if (!style.borderWidth && !result.borderWidth) {
    result.borderWidth = 0;
  }

  if (!style.borderColor && !result.borderColor) {
    result.borderColor = 'black';
  }
}

function extendProperties(style) {
  var result = {};

  for (var property in style) {
    var value = style[property];
    if (!isValidValue(value)) {
      continue;
    }
    // set a default border style if there has border about property
    if (borderProperties[property]) {
      defaultBorderStyle(style, result);
    }

    if (boxProperties[property]) {
      extendBoxProperties(property, value, result);
    } else if (flexboxProperties[property]) {
      prefixOldFlexbox(property, value, result);
      if (property === 'flex') {
        defaultFlexExpansion(style, result);
      }
    } else {
      value = processValueForProp(value, property);
      property = getVendorPropertyName(property);
      result[property] = value;
    }
  }

  return result;
}

module.exports = extendProperties;
<|endoftext|>


<commit_before>// ---------------------------- //
//             Main             //
// ---------------------------- //
// This file is called after every other javascript files

// Modules

// Example:
// window.project.modules.exampleModule = $('.element').module();

$('.lightbox').lightbox();
<commit_msg>Remove test data<commit_after>// ---------------------------- //
//             Main             //
// ---------------------------- //
// This file is called after every other javascript files

// Modules

// Example:
// window.project.modules.exampleModule = $('.element').module();
<|endoftext|>


<commit_before>// ==UserScript==
// @name       LinkedIn hide email contacts from "People You May Know"
// @namespace  http://mathemaniac.org
// @version    1.1.0
// @description  Hides those annoying email contacts from PYMK
// @match      http://www.linkedin.com/people/pymk*
// @match      https://www.linkedin.com/people/pymk*
// @copyright  2015, Sebastian Paaske Tørholm
// @require    https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js
// ==/UserScript==

$(function () {
    $('ul.people-cards-list li[id*="@"]').remove();

    // Remove when autoloading new ones
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    var config = { childList: true, characterData: false, attributes: false, subtree: true };
    var observer = new MutationObserver( function (mutations) {
        mutations.forEach( function (mutation) {
            if (mutation.addedNodes) {
                $(mutation.addedNodes).each( function () {
                    if ($(this).attr('id').match(/card-.*@.*/)) {
                        console.log("removing ", $(this).attr('id'));
                        $(this).remove();
                    }
                } );
            }
        });
    });

    $('ul.people-cards-list').each( function () { observer.observe(this, config); } );
});
<commit_msg>Update LinkedIn PYMK script to work with new page<commit_after>// ==UserScript==
// @name       LinkedIn hide email contacts from "People You May Know"
// @namespace  http://mathemaniac.org
// @version    1.2.0
// @description  Hides those annoying email contacts from PYMK
// @match      https://www.linkedin.com/mynetwork*
// @copyright  2015-2017, Sebastian Paaske Tørholm
// @require    https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js
// ==/UserScript==

$(function () {
    $('.mn-pymk-list__card:has(.mn-person-info__guest-handle)').remove();

    // Remove when autoloading new ones
    var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
    var config = { childList: true, characterData: false, attributes: false, subtree: true };
    var observer = new MutationObserver( function (mutations) {
        mutations.forEach( function (mutation) {
            if (mutation.addedNodes) {
                $(mutation.addedNodes).each( function () {
                    if ($(this).hasClass('mn-person-info__guest-handle')) {
                        console.log("removing card for ", $(this).text());
                        $(this).parents('.mn-pymk-list__card').remove();
                    }
                } );
            }
        });
    });

    $('.mn-pymk-list__cards').each( function () { observer.observe(this, config); } );
});
<|endoftext|>


<commit_before>angular.module('fitness.game', [])

// directive for auto-focusing popup input when shown
.directive('focusMe', function($timeout) {
  return {
    link: function(scope, element, attrs) {
      $timeout(function() {
        element[0].focus();
      }, 150);
    }
  };
})
.controller('GameCtrl', function($ionicPopup, $timeout, $interval, gameService, $scope, $state) {

	console.log('Game Controller loaded');

	var self = this;
	var vowels = ['A', 'E', 'I', 'O', 'U'];
	var numVowels = 0;
	var numCons = 0;
	var vowelsRevealed = 0;
	var consRevealed = 0;
	var vowelStack, consStack;

	var data = "The rain in spain falls mainly on the plain";
	data = data.toUpperCase();

	// stole this from http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
	this.shuffleArray = function(array) {
	    for (var i = array.length - 1; i > 0; i--) {
	        var j = Math.floor(Math.random() * (i + 1));
	        var temp = array[i];
	        array[i] = array[j];
	        array[j] = temp;
	    }
	    return array;
	}

	// count vowels and consonants so we know the range for random numbers
	for(var i = 0; i < data.length; i++) {
		// don't care if it's a space
		if(data.charAt(i) === " ") {
			continue;
		}
		// increment vowel count
		else if(vowels.includes(data.charAt(i))) {
			numVowels++;
		}
		// increment consonant count
		else {
			numCons++;
		}
	}

	var orderVowels = [];
	for(var a = 0; a < numVowels; a++) {
		orderVowels[a] = a;
	}

	var orderCons = [];
	for(var b = 0; b < numCons; b++) {
		orderCons[b] = b;
	}

	orderVowels = self.shuffleArray(orderVowels);
	orderCons = self.shuffleArray(orderCons);

	vowelStack = new Array(numVowels);
	consStack = new Array(numCons);

	var parts = data.split(" ");
	self.phrase = [];
	parts.forEach(function(d) {
		var temp = [];
		for(var x = 0; x < d.length; x++) {
			var obj = {
				letter: d[x],
				revealed: false,
				model: "."
			};

			if(vowels.includes(d[x])) {
				obj.letterType = "V";
				obj.order = orderVowels.shift();
				vowelStack[obj.order] = obj;
			} else if(d === ' ') {
				obj.letterType = "S";
			} else {
				obj.letterType = "C";
				obj.order = orderCons.shift();
				consStack[obj.order] = obj;
			}
			temp.push(obj);
		}
		self.phrase.push(temp)
	});

	// button click handler, exhausts vowels first, then consonants
	this.reveal = function() {
		if(vowelStack.length == 0) {
			var curr = consStack.shift();
			if (curr) {
				curr.model = curr.letter;
				vowelsRevealed++;
			}
		} else {
			var curr = vowelStack.shift();
			if (curr) {
				curr.model = curr.letter;
				consRevealed++;
			}
		}
	};

	this.showPopup = function() {
		var guessPopup = $ionicPopup.show({
			template: '<input focus-me class="popup-input" ng-model="vm.guess">',
			title: 'Enter Phrase',
			scope: $scope,
			buttons: [
				{
					text: 'Cancel',
					type: 'button-dark'
				},
				{
					text: 'Guess',
					type: 'button-positive',
					onTap: function(e) {
						if(self.guess.toUpperCase() === data) {
							goodGuess();
						} else {
							badGuess();
						}
					}
				}
			]
		});
	};

	function goodGuess() {
		console.log("good guess!")
		revealAll();
	}

	function badGuess() {
		self.guess = "";
		console.log("bad guess!")
	}

	// this will replace the existing reveal function
	function reveal1(letterType) {
		var curr;
		if(letterType === "V" && vowelStack.length != 0) {
			curr = vowelStack.shift();
			if (curr) {
				curr.model = curr.letter;
				vowelsRevealed++;
			}
		} else if(letterType === "C" && consStack.length != 0) {
			curr = consStack.shift();
			if (curr) {
				curr.model = curr.letter;
				consRevealed++;
			}
		} else {
			// either we have a bad lettertype or both stacks are empty
		}
	}

	// reveals the entire phrase
	function revealAll() {
		vowelStack.forEach(function(d) {
			d.model = d.letter;
		});

		consStack.forEach(function(d) {
			d.model = d.letter;
		});
	}

	// takes the number of vowels and consonants that should be revealed and reveals them
	function catchUp(vowels, consonants) {
		if(vowels < 0 || consonants < 0) {
			return;
		}

		for(var a = 0; a < vowels; a++) {
			reveal1("V");
		}

		for(var b = 0; b < consonants; b++) {
			reveal1("C");
		}
	}

	function saveState() {
		console.log(data)
		console.log(self.phrase);
		console.log(vowelStack)
		console.log(consStack)
		// localforage.setItem("tbd_PHRASE", data);
		// localforage.setItem("tbd_VIEWMODEL", self.phrase);
		// localforage.setItem("tbd_VSTACK", vowelStack);
		// localforage.setItem("tbd_CSTACK", consStack);
	}

	function loadState() {
		return localforage.getItem("tbd_PHRASE").then(function(value1) {
			return localforage.getItem("tbd_PHRASE");
		}).then(function(value2) {

		});
	}

	this.drawFriendly = function() {

		console.log('goal steps ' + self.fitbitData.goals.steps);

		jQuery("#friend-progress").empty();

			self.friendlyProgress = jQuery("#friend-progress").radialMultiProgress("init", {
				'fill': 25,
				'font-size': 14,
				'size': 100,
				'data': [
					{'color': "#2DB1E4", 'range': [0, self.fitbitData.goals.steps]}, // steps
					{'color': "#9CCA13", 'range': [0, self.fitbitData.goals.floors]}, // floors
					{'color': "#cf2583", 'range': [0, 24]} // time
				]
			});

		var dh, dm, ds;
	//	setInterval(function() {
			console.log('in the draw circle func.');

			var date = new Date(),
	        h = date.getHours(),
	        m = date.getMinutes(),
	        s = date.getSeconds();

			self.fitbitData.time = gameService.updateTime(24-h);

			console.log('hours is ' + h);

	    if (dh !== h) {
	    	self.friendlyProgress.radialMultiProgress("to", {
	      		"index": 0, 'perc': self.fitbitData.steps, 'time': 10
	      	});
	    	dh = h;
	    }
	    if (dm !== m) {
	    	self.friendlyProgress.radialMultiProgress("to", {
	    		"index": 1, 'perc': self.fitbitData.floors, 'time': 10
	    	});
	    	dm = m;
	    }
	    if (ds !== s) {
	    	self.friendlyProgress.radialMultiProgress("to", {
	    		"index": 2, 'perc': h, 'time': 100
	    	});
	    	ds = s;
	    }
//	  }, 1000);
	};

	$scope.$on('$ionicView.enter', function(e) {

		self.fitbitData = {} ;
		self.fitbitData.goals = {} ;

		self.fitbitData = gameService.data ;

		console.log('steps in game.js: ' + self.fitbitData.steps);

		console.log('getting access token from storage');
		localforage.getItem('fitbitToken').then(function(token){
			if (!token)
				gameService.reload();

			gameService.fitbitToken = token;
			console.log('saving token to game service: ' + token);
			gameService.getFitbitData();
		});

		$interval.cancel(self.queryInterval);

		self.queryInterval = $interval( function(){ self.refreshData(); } , 120000);

		$timeout( self.drawFriendly, 750);
	});

	this.refreshData = function(){

		gameService.getFitbitData();
		$timeout( self.drawFriendly, 750);
		$scope.$broadcast('scroll.refreshComplete');
	}
});
<commit_msg>fixed time display<commit_after>angular.module('fitness.game', [])

// directive for auto-focusing popup input when shown
.directive('focusMe', function($timeout) {
  return {
    link: function(scope, element, attrs) {
      $timeout(function() {
        element[0].focus();
      }, 150);
    }
  };
})
.controller('GameCtrl', function($ionicPopup, $timeout, $interval, gameService, $scope, $state) {

	console.log('Game Controller loaded');

	var self = this;
	var vowels = ['A', 'E', 'I', 'O', 'U'];
	var numVowels = 0;
	var numCons = 0;
	var vowelsRevealed = 0;
	var consRevealed = 0;
	var vowelStack, consStack;

	var data = "The rain in spain falls mainly on the plain";
	data = data.toUpperCase();

	// stole this from http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
	this.shuffleArray = function(array) {
	    for (var i = array.length - 1; i > 0; i--) {
	        var j = Math.floor(Math.random() * (i + 1));
	        var temp = array[i];
	        array[i] = array[j];
	        array[j] = temp;
	    }
	    return array;
	}

	// count vowels and consonants so we know the range for random numbers
	for(var i = 0; i < data.length; i++) {
		// don't care if it's a space
		if(data.charAt(i) === " ") {
			continue;
		}
		// increment vowel count
		else if(vowels.includes(data.charAt(i))) {
			numVowels++;
		}
		// increment consonant count
		else {
			numCons++;
		}
	}

	var orderVowels = [];
	for(var a = 0; a < numVowels; a++) {
		orderVowels[a] = a;
	}

	var orderCons = [];
	for(var b = 0; b < numCons; b++) {
		orderCons[b] = b;
	}

	orderVowels = self.shuffleArray(orderVowels);
	orderCons = self.shuffleArray(orderCons);

	vowelStack = new Array(numVowels);
	consStack = new Array(numCons);

	var parts = data.split(" ");
	self.phrase = [];
	parts.forEach(function(d) {
		var temp = [];
		for(var x = 0; x < d.length; x++) {
			var obj = {
				letter: d[x],
				revealed: false,
				model: "."
			};

			if(vowels.includes(d[x])) {
				obj.letterType = "V";
				obj.order = orderVowels.shift();
				vowelStack[obj.order] = obj;
			} else if(d === ' ') {
				obj.letterType = "S";
			} else {
				obj.letterType = "C";
				obj.order = orderCons.shift();
				consStack[obj.order] = obj;
			}
			temp.push(obj);
		}
		self.phrase.push(temp)
	});

	// button click handler, exhausts vowels first, then consonants
	this.reveal = function() {
		if(vowelStack.length == 0) {
			var curr = consStack.shift();
			if (curr) {
				curr.model = curr.letter;
				vowelsRevealed++;
			}
		} else {
			var curr = vowelStack.shift();
			if (curr) {
				curr.model = curr.letter;
				consRevealed++;
			}
		}
	};

	this.showPopup = function() {
		var guessPopup = $ionicPopup.show({
			template: '<input focus-me class="popup-input" ng-model="vm.guess">',
			title: 'Enter Phrase',
			scope: $scope,
			buttons: [
				{
					text: 'Cancel',
					type: 'button-dark'
				},
				{
					text: 'Guess',
					type: 'button-positive',
					onTap: function(e) {
						if(self.guess.toUpperCase() === data) {
							goodGuess();
						} else {
							badGuess();
						}
					}
				}
			]
		});
	};

	function goodGuess() {
		console.log("good guess!")
		revealAll();
	}

	function badGuess() {
		self.guess = "";
		console.log("bad guess!")
	}

	// this will replace the existing reveal function
	function reveal1(letterType) {
		var curr;
		if(letterType === "V" && vowelStack.length != 0) {
			curr = vowelStack.shift();
			if (curr) {
				curr.model = curr.letter;
				vowelsRevealed++;
			}
		} else if(letterType === "C" && consStack.length != 0) {
			curr = consStack.shift();
			if (curr) {
				curr.model = curr.letter;
				consRevealed++;
			}
		} else {
			// either we have a bad lettertype or both stacks are empty
		}
	}

	// reveals the entire phrase
	function revealAll() {
		vowelStack.forEach(function(d) {
			d.model = d.letter;
		});

		consStack.forEach(function(d) {
			d.model = d.letter;
		});
	}

	// takes the number of vowels and consonants that should be revealed and reveals them
	function catchUp(vowels, consonants) {
		if(vowels < 0 || consonants < 0) {
			return;
		}

		for(var a = 0; a < vowels; a++) {
			reveal1("V");
		}

		for(var b = 0; b < consonants; b++) {
			reveal1("C");
		}
	}

	function saveState() {
		console.log(data)
		console.log(self.phrase);
		console.log(vowelStack)
		console.log(consStack)
		// localforage.setItem("tbd_PHRASE", data);
		// localforage.setItem("tbd_VIEWMODEL", self.phrase);
		// localforage.setItem("tbd_VSTACK", vowelStack);
		// localforage.setItem("tbd_CSTACK", consStack);
	}

	function loadState() {
		return localforage.getItem("tbd_PHRASE").then(function(value1) {
			return localforage.getItem("tbd_PHRASE");
		}).then(function(value2) {

		});
	}

	this.drawFriendly = function() {

		console.log('goal steps ' + self.fitbitData.goals.steps);

		jQuery("#friend-progress").empty();

			self.friendlyProgress = jQuery("#friend-progress").radialMultiProgress("init", {
				'fill': 25,
				'font-size': 14,
				'size': 100,
				'data': [
					{'color': "#2DB1E4", 'range': [0, self.fitbitData.goals.steps]}, // steps
					{'color': "#9CCA13", 'range': [0, self.fitbitData.goals.floors]}, // floors
					{'color': "#cf2583", 'range': [0, 24]} // time
				]
			});

		var dh, dm, ds;
	//	setInterval(function() {
			console.log('in the draw circle func.');

			var date = new Date(),
	        h = date.getHours(),
	        m = date.getMinutes(),
	        s = date.getSeconds();

			self.fitbitData.time = gameService.updateTime(24-h);

			console.log('hours is ' + h);

	    	self.friendlyProgress.radialMultiProgress("to", {
	      		"index": 0, 'perc': self.fitbitData.steps, 'time': 10
	      	});
	    	self.friendlyProgress.radialMultiProgress("to", {
	    		"index": 1, 'perc': self.fitbitData.floors, 'time': 10
	    	});
	    	self.friendlyProgress.radialMultiProgress("to", {
	    		"index": 2, 'perc': h, 'time': 10
	    	});
	  //  }
//	  }, 1000);
	};

	$scope.$on('$ionicView.enter', function(e) {

		self.fitbitData = {} ;
		self.fitbitData.goals = {} ;

		self.fitbitData = gameService.data ;

		console.log('steps in game.js: ' + self.fitbitData.steps);

		console.log('getting access token from storage');
		localforage.getItem('fitbitToken').then(function(token){
			if (!token)
				gameService.reload();

			gameService.fitbitToken = token;
			console.log('saving token to game service: ' + token);
			gameService.getFitbitData();
		});

		$interval.cancel(self.queryInterval);

		self.queryInterval = $interval( function(){ self.refreshData(); } , 120000);

		$timeout( self.drawFriendly, 750);
	});

	this.refreshData = function(){

		gameService.getFitbitData();
		$timeout( self.drawFriendly, 750);
		$scope.$broadcast('scroll.refreshComplete');
	}
});
<|endoftext|>